09-11-2025, 06:13 PM
Here's an attempt of capturing the controls of Star Fox. The SNES had no analogue stick, yet the controls of Star Fox felt awesome. We'll see what happens when obstacles and enemies are added.
Code:
' flight_test.n7
' --------------
' Move with arrow keys, shoot with space bar. Change y-axis inversion below if you need to.
include "s3d.n7"
constant RES = 480
' Set to 1 for non-inverted y-axis. I can only play inverted ...
ctrlYScale = -1
winAspect = min(screenw()/screenh(), 2)
set window "flight test", RES*winAspect, RES, false
set redraw off
S3D_SetView(primary, rad(60), 0.1, 100)
' Create player ship model.
shipMesh = S3D_BeginMesh()
hw = 0.5
S3D_Begin(S3D_TRIANGLES)
S3D_Color(208, 208, 208)
' right side.
S3D_Vertex(0, 0, 2, 0, 0)
S3D_Vertex(0.5, 0.125, -1.25, 0, 0)
S3D_Vertex(0, -0.25, -1, 0, 0)
' left side.
S3D_Vertex(0, 0, 2, 0, 0)
S3D_Vertex(0, -0.25, -1, 0, 0)
S3D_Vertex(-0.5, 0.125, -1.25, 0, 0)
' back.
S3D_Color(255, 160, 0)
S3D_Vertex(0, -0.25, -1, 0, 0)
S3D_Vertex(0.5, 0.125, -1.25, 0, 0)
S3D_Vertex(-0.5, 0.125, -1.25, 0, 0)
' bottom.
S3D_Color(128, 128, 128)
S3D_Vertex(0, 0, 2, 0, 0)
S3D_Vertex(-0.5, 0.125, -1.25, 0, 0)
S3D_Vertex(0.5, 0.125, -1.25, 0, 0)
' right wing.
S3D_Color(64, 128, 208)
S3D_Vertex(0.5, 0, 0.25, 0, 0)
S3D_Vertex(2.0, 0.25, -2, 0, 0)
S3D_Vertex(0.5, 0, -1.5, 0, 0)
S3D_Vertex(0.5, 0, 0.25, 0, 0)
S3D_Vertex(0.5, 0, -1.5, 0, 0)
S3D_Vertex(2.0, 0.25, -2, 0, 0)
' left wing.
S3D_Color(64, 128, 208)
S3D_Vertex(-0.5, 0, 0.25, 0, 0)
S3D_Vertex(-2.0, 0.25, -2, 0, 0)
S3D_Vertex(-0.5, 0, -1.5, 0, 0)
S3D_Vertex(-0.5, 0, 0.25, 0, 0)
S3D_Vertex(-0.5, 0, -1.5, 0, 0)
S3D_Vertex(-2.0, 0.25, -2, 0, 0)
S3D_End()
S3D_EndMesh()
' Player bullet model, probably needs volume ...
bulletMesh = S3D_BeginMesh()
S3D_Color(255, 208, 96)
S3D_Begin(S3D_QUADS)
S3D_Vertex(0, 0, 0.5, 0, 0)
S3D_Vertex(0.5, 0, 0, 0, 0)
S3D_Vertex(0, 0, -1.5, 0, 0)
S3D_Vertex(-0.5, 0, 0, 0, 0)
S3D_Vertex(-0.5, 0, 0, 0, 0)
S3D_Vertex(0, 0, -1.5, 0, 0)
S3D_Vertex(0.5, 0, 0, 0, 0)
S3D_Vertex(0, 0, 0.5, 0, 0)
S3D_End()
S3D_EndMesh()
' Player.
ship = []
ship.mesh = shipMesh
ship.pos = []
ship.pos[0] = 0
ship.pos[1] = -2
ship.pos[2] = 0
ship.rot = []
ship.rot.yaw = 0
ship.rot.pitch = 0
ship.rot.roll = 0
ship.dir = [0, 0, 0, 0]
ship.shootTimer = 0
' Player bullets.
bullets = []
' Camera.
cam = []
cam.pos = []
cam.pos[0] = 0
cam.pos[1] = 0
cam.pos[2] = 0
cam.rot = []
cam.rot.yaw = 0
cam.rot.pitch = 0
cam.rot.roll = 0
cam.followX = 0.125
' X and y limitations of player.
xMin = -8
xMax = 8
yMin = -15
yMax = -1
' Forward vector.
fwdVec = [0, 0, 1, 0]
' For computations using s3d.
srcVec = [0, 0, 0, 0]
dstVec = [0, 0, 0, 0]
while not keydown(KEY_ESCAPE, true)
' Change direction.
dYaw = 0
dPitch = 0
if keydown(KEY_LEFT) dYaw = dYaw - 45
if keydown(KEY_RIGHT) dYaw = dYaw + 45
if keydown(KEY_UP) dPitch = dPitch + 30*ctrlYScale
if keydown(KEY_DOWN) dPitch = dPitch - 30*ctrlYScale
ship.rot.yaw = 0.95*ship.rot.yaw + 0.05*dYaw
ship.rot.pitch = 0.95*ship.rot.pitch + 0.05*dPitch
ship.rot.roll = 0.95*ship.rot.roll + 0.05*dYaw*0.5
' Get ships direction as a vector.
S3D_ClearTransformation()
' A window aspect effect is applied in ClearTransformation, so we have to revert it to get
' proper coordinates from TransformVector. I have ... NO idea of why I did it like that. I'll
' fix that in the next n7 release.
S3D_Scale(winAspect, 1, 1)
S3D_RotateY(rad(ship.rot.yaw))
S3D_RotateX(rad(ship.rot.pitch))
S3D_RotateZ(rad(ship.rot.roll))
S3D_TransformVector(ship.dir, fwdVec)
VectorNormalize(ship.dir)
' Uhm, slow down when close to x and y limits.
dxMul = 1; dyMul =1
if ship.dir[0] < 0 dxMul = min(ship.pos[0] - xMin, 4)*0.25
elseif ship.dir[0] > 0 dxMul = min(xMax - ship.pos[0], 4)*0.25
if ship.dir[1] < 0 dyMul = min(ship.pos[1] - yMin, 4)*0.25
elseif ship.dir[1] > 0 dyMul = min(yMax - ship.pos[1], 4)*0.25
' Move.
ship.pos[0] = max(min(ship.pos[0] + ship.dir[0]*0.25*dxMul, xMax), xMin)
ship.pos[1] = max(min(ship.pos[1] + ship.dir[1]*0.5*dyMul, yMax), yMin)
' Shoot.
ship.shootTimer = max(ship.shootTimer - 1, 0)
if keydown(KEY_SPACE) and ship.shootTimer <= 0
ship.shootTimer = 15
spd = 1
' Add two bullets with positions relative to the player ship.
S3D_ClearTransformation()
S3D_Scale(winAspect, 1, 1)
S3D_Translate(ship.pos[0], ship.pos[1], ship.pos[2])
S3D_RotateY(rad(ship.rot.yaw))
S3D_RotateX(rad(ship.rot.pitch))
S3D_RotateZ(rad(ship.rot.roll))
for x = -0.75 to 0.75 step 1.5
srcVec[0] = x; srcVec[1] = 0; srcVec[2] = 1; srcVec[3] = 1
bullet = [
mesh: bulletMesh,
pos: dim(3),
rot: [yaw: ship.rot.yaw, pitch: ship.rot.pitch, roll: ship.rot.roll],
mvec: [ship.dir[0]*spd, ship.dir[1]*spd, ship.dir[2]*spd]]
S3D_TransformVector(bullet.pos, srcVec)
bullets[sizeof(bullets)] = bullet
next
endif
' Position camera.
cam.pos[0] = cam.followX*ship.pos[0]
cam.pos[1] = 0.5*ship.pos[1] - 3
cam.pos[2] = ship.pos[2] - 10
' Update bullets.
i = 0
while i < sizeof(bullets)
b = bullets[i]
VectorAdd(b.pos, b.mvec)
if b.pos[1] >= 0 or b.pos[2] > cam.pos[2] + 50 free key bullets, i
else i = i + 1
wend
' Draw.
set color 48, 48, 48
cls
S3D_Clear()
S3D_Translate(-cam.pos[0], -cam.pos[1], -cam.pos[2])
DrawObject(ship)
foreach b in bullets DrawObject(b)
set color 255, 255, 255
set caret 4, 4
wln "dx: " + str(ship.dir[0], 0, 2)
wln "dy: " + str(ship.dir[1], 0, 2)
wln "dz: " + str(ship.dir[2], 0, 2)
wln
wln "bullets: " + sizeof(bullets)
redraw
fwait 60
wend
' DrawObject
' ----------
function DrawObject(o)
' Object.
S3D_Push()
S3D_Color(255, 255, 255)
S3D_Translate(o.pos[0], o.pos[1], o.pos[2])
S3D_RotateY(rad(o.rot.yaw))
S3D_RotateX(rad(o.rot.pitch))
S3D_RotateZ(rad(o.rot.roll))
S3D_Mesh(o.mesh, 0)
S3D_Pop()
' Shadow.
S3D_SetDepthBuffer(S3D_Z_BUFFER_READ)
S3D_Push()
S3D_Translate(o.pos[0], 0, o.pos[2])
S3D_Scale(1, 0, 1)
S3D_RotateY(rad(o.rot.yaw))
S3D_RotateX(rad(o.rot.pitch))
S3D_RotateZ(rad(o.rot.roll))
S3D_Color(0, 0, 0)
S3D_Mesh(o.mesh, 0)
S3D_Pop()
S3D_SetDepthBuffer(S3D_Z_BUFFER)
endfunc
' VectorNormalize
' ---------------
function VectorNormalize(v)
k = 1/sqr(v[0]*v[0] + v[1]*v[1] + v[2]*v[2])
v[0] = v[0]*k; v[1] = v[1]*k; v[2] = v[2]*k
endfunc
' VectorAdd
' ---------
function VectorAdd(dst, src)
dst[0] = dst[0] + src[0]
dst[1] = dst[1] + src[1]
dst[2] = dst[2] + src[2]
endfunc

I believe it was Top Gun on NES that made me an inverted player for life. I have bought games that I've never been able to play because there's been no option to invert the controls.