09-03-2025, 09:27 AM (This post was last modified: 09-03-2025, 09:39 AM by 1micha.elok.)
Thanks ! I think 3D animation with md2 will look way more lively. By the way, how do I make the character punch and kick ? ....
I've known how to punch
anim = AnimationLoop([198,199,200,201,202,203,204,205,206,207]) 'punch
Here's a better animation example. This is pretty much how I do it in Neon Breath and Robowack 3.
I got a weird runtime error related to the % operator when testing this. Because of it, I relased a new n7 version without posting about it (https://naalaa.com/n7/N7_250906.zip). If you get a runtime error when testing this example, you can download the new n7 version and see if it helps.
Put this code in the same folder as the original example. Basicly, in a game, you would let every object (like enemies) have an "AnimationController" to help you with its animations.
' Display settings.
constant RES = 480 ' Vertical resolution.
constant SCALE = 1 ' Window scale.
constant FULLSCREEN = 0 ' Fullscreen if 1
constant DISPLAY_FPS = 1 ' Display fps if 1.
constant FOV = 45 ' Vertical field of view in degrees.
constant MOUSE_SENS = 1 ' Mouse sensitivity.
' For delta time.
visible vLastTick = 0
' Some animations. You can look for other animations in the output when the program starts.
visible vPlayerWalkAnim = [40, 41, 42, 43, 44, 45]
visible vPlayerPunchAnim = [198, 199, 200, 201, 202, 203, 204, 205, 206, 207]
visible vPlayerCrouchPunchAnim = [208, 209, 210, 211, 212]
visible vPlayerWaveAnim = [112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122]
visible vSaluteAnim = [84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94]
' Create window.
set window "MD2", RES*screenw()/screenh(), RES, FULLSCREEN, SCALE
set redraw off
' Load md2 model.
info = []
scale = 0.04
model = LoadMD2("assets/doomguy/tris.md2", true, scale, -scale, scale, false, info)
texture = loadimage("assets/doomguy/texture.png")
' Print list of available frames.
for i = 0 to sizeof(info.frames) - 1
pln i + ": " + info.frames[i]
next
' Create an AnimationController, with some functions that help us manage animations for an object.
anim = AnimationController()
' Start playing the looped walk animation.
anim.Play(vPlayerWalkAnim, 5, true)
' Flag player walking. If player is walking we can press keys to do other stuff.
walking = true
' Init s3d with the window as render target, a field of view of FOV degrees, near clip plane at
' distance 0.1 and far clip plane at 10.
S3D_SetView(primary, rad(FOV), 0.1, 10)
' Loop until user presses esc.
while not keydown(KEY_ESCAPE, true)
' Get time passed since last frame.
dt = DeltaTime()
' Update mesh animation.
' AnimationController.Update returns false if a non-looped animation has finished playing. In
' that case, restart the walk animation.
if not anim.Update(dt)
anim.Play(vPlayerWalkAnim, 5, true)
walking = true
endif
' Write information and instructions.
set color 255, 255, 255
set caret 0, 0
wln "Rotate and zoom by moving the mouse while holding down left mouse button"
wln "Press 1 to punch, 2 to crouch punch, 3 to wave and 4 to salute"
wln
wln "Press Esc to quit"
' DeltaTime
' ---------
' Return delta time in seconds since last call.
function DeltaTime()
t = clock()
dt = (min(t - vLastTick, 100))/1000
vLastTick = t
return dt
endfunc
' DisplayFps
' ----------
' Display number of frames per second in bottom right corner based on delta time in seconds.
function DisplayFps(dt)
if DISPLAY_FPS
set caret width(primary) - fwidth(" "), height(primary) - fheight()
set justification right
set color 0, 255, 0
write "FPS: " + str(round(1/dt), 3)
set justification left
endif
endfunc
' LoadMdD2
' --------
' Create a mesh, possibly with multiple frames, from MD2 file.
function LoadMD2(filename, swapYZ, scaleX, scaleY, scaleZ, invertFaces, info)
assert typeof(info) = TYPE_UNSET or typeof(info) = TYPE_TABLE, "LoadMD2: info parameter must be unset or a table"
' Load all data from file.
f = openfile(filename, true)
if not file(f) return unset
ident = fread(f, 32, true)
if ident <> 844121161 return unset
version = fread(f, 32, true)
if version <> 8 return unset
skinWidth = fread(f, 32, true)
skinHeight = fread(f, 32, true)
frameSize = fread(f, 32, true)
numSkins = fread(f, 32, true)
numVertices = fread(f, 32, true)
numSt = fread(f, 32, true)
numTris = fread(f, 32, true)
numGlCmds = fread(f, 32, true)
numFrames = fread(f, 32, true)
offsetSkins = fread(f, 32, true)
offsetSt = fread(f, 32, true)
offsetTris = fread(f, 32, true)
offsetFrames = fread(f, 32, true)
offsetGlCmds = fread(f, 32, true)
offsetEnd = fread(f, 32, true)
uvs = []
if numSt
file seek f, offsetSt, SEEK_SET
for i = 0 to numSt - 1
uvs[sizeof(uvs)] = [fread(f, 16, true)/skinWidth, fread(f, 16, true)/skinHeight]
next
endif
tris = []
if numTris
file seek f, offsetTris, SEEK_SET
for i = 0 to numTris - 1
v0 = fread(f, 16, true); v1 = fread(f, 16, true); v2 = fread(f, 16, true)
uv0 = fread(f, 16, true); uv1 = fread(f, 16, true); uv2 = fread(f, 16, true)
if invertFaces tris[sizeof(tris)] = [v2, v1, v0, uv2, uv1, uv0, unset]
else tris[sizeof(tris)] = [v0, v1, v2, uv0, uv1, uv2, unset]
next
endif
frames = []
if typeof(info) info.frames = []
if numFrames
file seek f, offsetFrames, SEEK_SET
for i = 0 to numFrames - 1
frame = []
frames[sizeof(frames)] = frame
sx = fread(f, 64, false); sy = fread(f, 64, false); sz = fread(f, 64, false)
tx = fread(f, 64, false); ty = fread(f, 64, false); tz = fread(f, 64, false)
name = ""
done = false
for j = 0 to 15
c = fread(f, 8, true)
if c = 0 done = true
if not done name = name + chr(c)
next
if typeof(info) info.frames[sizeof(info.frames)] = name
frame.verts = []
for j = 0 to numVertices - 1
x = tx + fread(f, 8, false)*sx
y = ty + fread(f, 8, false)*sy
z = tz + fread(f, 8, false)*sz
if swapYZ frame.verts[sizeof(frame.verts)] = [scaleX*x, scaleY*z, scaleZ*y]
else frame.verts[sizeof(frame.verts)] = [scaleX*x, scaleY*y, scaleZ*z]
tmp = fread(f, 8, false) ' Not interested in normal index.
next
next
endif
free file f
' Build mesh.
mesh = S3D_CreateMesh(frames[0].verts, uvs, unset, tris)
if numFrames > 1
for i = 1 to numFrames - 1
S3D_AddMeshFrame(mesh, frames[i].verts)
next
endif