Hello and thank you for taking the time to read my first ever tutorial.
This tutorial will teach the intermediate user how to make an easy collision system
using sparky’s dll, with jumping, movement, including first and third person viewing.
Perfect for starting any 3d game, and very easy to build upon.
Before any confusion, I will make this clear. This is an excerpt, condensed form, snippet,
call it what you like ; from the “Sliding collision” sparky’s dll demo. The instructions on top,
code at bottom. If any part needs more explaining in detail, ask.
If an algorithm looks weird to you, keep in mind that all this is in a loop.
Step 1
Ok, to start us off, this is the generic code you usually see at the start of many programs,
and if you don’t know what this does, read a few more tutorials before you try collision =P.
Heres a quick reminder of ‘autocam off’.
Autocam off : when you create a new object, the camera is automatically centered on it.
We don’t want this auto reaction, so we obviously turn it off.
sync on
sync rate 60
hide mouse
autocam off
Step 2
Just a few variable declarations, we use the radius for convenience, as the player is a sphere.
The rest is pretty self explanatory, if you don’t understand it don’t worry, you will later.
radius# = 7.0
gravity# = -0.1
slope# = 0.5
ground = 1
jumptimer = 0
gosub makeLevel
gosub makePlayer
Step 3
makeLevel: load object is the loading of the actual 3d world you want to test
(swap ‘world.x’ with yours) and sc_setupcomplexobject is just setting up collision for this
3d model, and the reason its ‘complex’ is because if your model only contains less than 30-40 polys,
you would only use the sc_setupobject command but if it has more, the ‘complex’ one is a lot better
(makes it faster!).
The parameters for sc_setupcomplexobject are [object number, group(just leave this at one for the
moment),faces per node(I don’t pretend to know what this means, but the recommendation is that I
leave this at two, and that’s perfectly fine by me)]
makePlayer: This just gives us a sphere as a player, positions him at the center and slightly above
ground, and sets him up for collision. Note we use only sc_setupobject here, as its sufficient for the
amount of polys the sphere has.
Parameters for sc_setupobject – (objectnumber, group, type of collision(0-polygon 1-sphere 2-box –
Ok, usually you would leave this at 0 but since we are only setting up a sphere, we don’t need more
than a sphere collision)
A quick rundown use sc_setupobject or sc_setupcomplexobject for any objects you want to have
collision with.
makeLevel:
load object "world.x",1
sc_setupComplexObject 1,1,2
return
makePlayer:
make object sphere 2,radius#*2
position object 2,0,50,0
sc_setupObject 2,0,1
return
Step 4
Ok, this is the big one. Get ready.
Here is the whole code of the moveplayer sequence, we will break it up into chunks.
movePlayer:
rem rotate player with mouse
yrotate object 2,object angle y(2)+mousemovex()/3.0
xrotate object 2,object angle x(2)+mousemovey()/3.0
oldx# = object position x(2)
oldy# = object position y(2)
oldz# = object position z(2)
rem apply gravity, and user changes to movement
angy# = object angle y(2)
vx# = 0
vz# = 0
if vy#=0 and jumptimer=0 then vy# = vy# + 10*gravity# else vy# = vy# + gravity#
if keystate(32)=1 then vx# = vx# + cos(angy#) : vz# = vz# - sin(angy#)
if keystate(30)=1 then vx# = vx# - cos(angy#) : vz# = vz# + sin(angy#)
if keystate(31)=1 then vx# = vx# - sin(angy#) : vz# = vz# - cos(angy#)
if keystate(17)=1 then vx# = vx# + sin(angy#) : vz# = vz# + cos(angy#)
rem only jump if on ground, and a certain time after last jump
if ground=1
if spacekey()=1 and jumptimer=0 then vy# = vy# + 3.0 : jumptimer = 20
endif
x# = oldx#+vx#
y# = oldy#+vy#
z# = oldz#+vz#
collide = sc_SphereCastGroup(1,oldx#,oldy#,oldz#,oldx#,oldy#+vy#,oldz#,radius#,0)
if collide>0
ny# = sc_getCollisionNormalY()
if abs(ny#)>slope#
rem FLAT, stick
oldy# = sc_getStaticCollisionY()
else
rem STEEP, slide
x# = x# - oldx# : z# = z# - oldz#
oldx# = sc_getCollisionSlideX()
oldy# = sc_getCollisionSlideY()
oldz# = sc_getCollisionSlideZ()
x# = x# + oldx# : z# = z# + oldz#
endif
if ny#>slope#
rem only on ground if standing on flat ground
ground = 1
vy# = 0
else
ground = 0
rem if player has hit a flat ceiling then stop vy# movement
if ny#<-slope# then vy# = gravity#
endif
else
rem nothing below player, not on ground, add vertical speed to player
oldy# = oldy# + vy#
ground = 0
endif
if ground = 1 and jumptimer>0 then dec jumptimer
collide = sc_SphereSlideGroup(1,oldx#,oldy#,oldz#,x#,oldy#,z#,radius#,0)
if collide>0
rem if hit, reposition player, halt movement vector
x# = sc_getCollisionSlideX()
oldy# = sc_getCollisionSlideY()
z# = sc_getCollisionSlideZ()
vx# = 0
vz# = 0
endif
rem position the player
position object 2,x#,oldy#,z#
sc_updateObject 2
return
This is pretty self explanatory, it just rotates the camera, fps style, using the mouse.
Look at it for a while if you don’t get it, its just basic math.
rem rotate player with mouse
yrotate object 2,object angle y(2)+mousemovex()/3.0
xrotate object 2,object angle x(2)+mousemovey()/3.0
Heres a big chunk, the movement part.
Keep the variable declarations in mind, they will become important later on.
Don’t bother trying to understand how the trig movement works if you cant be bothered, I opened
up a whole thread about it.
I will explain one crucial line of the code:
if vy#=0 and jumptimer=0 then vy# = vy# + 10*gravity# else vy# = vy# + gravity#
This means that if your jump has finished (y position returned to previous) and the timer between
jumps is zero, then stick player to ground (apply heavy gravity), or if youre still jumping apply normal
gravity.
The rest of the code is pretty self explanatory.
So this is pretty much movement before collision.
oldx# = object position x(2)
oldy# = object position y(2)
oldz# = object position z(2)
angy# = object angle y(2)
vx# = 0
vz# = 0
if vy#=0 and jumptimer=0 then vy# = vy# + 10*gravity# else vy# = vy# + gravity#
if keystate(32)=1 then vx# = vx# + cos(angy#) : vz# = vz# - sin(angy#)
if keystate(30)=1 then vx# = vx# - cos(angy#) : vz# = vz# + sin(angy#)
if keystate(31)=1 then vx# = vx# - sin(angy#) : vz# = vz# - cos(angy#)
if keystate(17)=1 then vx# = vx# + sin(angy#) : vz# = vz# + cos(angy#)
rem only jump if on ground, and a certain time after last jump
if ground=1
if spacekey()=1 and jumptimer=0 then vy# = vy# + 3.0 : jumptimer = 20
endif
x# = oldx#+vx#
y# = oldy#+vy#
z# = oldz#+vz#
Ok this is the headache.
Ill explain it line by line.
The first line checks collision by casting a sphere down from the first position (oldx#,oldy#,oldz#)
to the second position (oldx#,oldy#+vy#).
An exact definition:
SC_sphereCastGroup
SYNTAX
return integer=SC_sphereCastGroup ( groupNum, oldx, oldy, oldz, x, y, z, radius, excludeObj )
-groupNum: the object you want to check for collision use 0 for all objects
-oldx...z: the start and end points of the sphere to check.
-radius: the radius of the sphere you want to cast.
-excludeObj: an object to exclude from the collision check.
returns: the object number collided with first is returned
returns 0 if no collision occured.
Similar to SC_sphereCast, except it checks groups of objects. see SC_sphereCast
Objects assigned group 0 during setup have no group and are ignored in group checks.
As you can see here, were only checking y collisions for now. Sliding comes a little later on.
Theres a few things you need to understand here. I have put it in a diagram.
So if our player collides against something, we first check the normal(rotation) of the polygon we
have collided against using sc_getcollisionnormalY(), assigning it the float ny#.
So if the positive ( abs() < the reason its positive is so you also slide when you jump against a
‘slopey’ roof.) rotation of the polygon is more than our slope (which at 0.5 is pretty steep), we set
oldy# to where sparky says we should place our object using sc_getStaticcollisionY(). This simulates
walking around on contoured hills etc.
But if the polygon we hit’s y rotation is more than our designated slope, we slide.
This part is easy, the ‘x# = x# - oldx# : z# = z# - oldz#’ nullifies the previous movement we made,
as the only thing we can currently do is slide. Sparky tells us where to put our object with
sc_getCollisionSlideX() ,Y, and Z. Then we fix up the variables again with
‘x# = x# + oldx# : z# = z# + oldz#’
The next little bit is self explanatory, so the ‘ground’ variable (used for jumping) is only activated if
youre on flat (not really flat, just above your slope) ground. Note, the value is not calculated as a positive,
as we cant really stand on anything below a vertical polygon (not that we can even stand on a
vertical polygon!), as it would be a ceiling. The vy# is set to zero, as we don’t need gravity to pull us
down when were already on flat ground. Whereas if what we collide on is less that negative slope (-0.5 in this case),
it would be treated as a ceiling and all upward movement is stopped. So what would happen if the
normal was within our negative slope? Well then we would be sliding up, as mentioned before
(think about it). Lastly, if we are not colliding against anything, we add downward speed and nullify
the ground variable.
collide = sc_SphereCastGroup(1,oldx#,oldy#,oldz#,oldx#,oldy#+vy#,oldz#,radius#,0)
if collide>0
ny# = sc_getCollisionNormalY()
if abs(ny#)>slope#
rem FLAT, stick
oldy# = sc_getStaticCollisionY()
else
rem STEEP, slide
x# = x# - oldx# : z# = z# - oldz#
oldx# = sc_getCollisionSlideX()
oldy# = sc_getCollisionSlideY()
oldz# = sc_getCollisionSlideZ()
x# = x# + oldx# : z# = z# + oldz#
endif
if ny#>slope#
rem only on ground if standing on flat ground
ground = 1
vy# = 0
else
ground = 0
rem if player has hit a flat ceiling then stop vy# movement
if ny#<-slope# then vy# = gravity#
endif
else
rem nothing below player, not on ground, add vertical speed to player
oldy# = oldy# + vy#
ground = 0
endif
if ground = 1 and jumptimer>0 then dec jumptimer
This is your generic, but essential, sliding collision code,
It checks the X and Y variables. As you can see, sparky does all the work for you by giving you the new
sliding collision coordinates.
SC_sphereSlideGroup
SYNTAX
return integer=SC_sphereSlideGroup ( groupNum, oldx, oldy, oldz, x, y, z, radius, excludeObj )
-groupNum: the group you want to check for collision use 0 for all groups
-oldx...z: the start and end points of the sphere to check.
-radius: the radius of the sphere you want to cast.
-excludeObj: an object to exclude from the collision check.
returns: the object number collided with is returned
returns 0 if no collision occured.
Similar to SC_sphereSlide except it checks a group of objects
or all groups if group=0.
Objects assigned group 0 during setup have no group and are ignored in group collision.
collide = sc_SphereSlideGroup(1,oldx#,oldy#,oldz#,x#,oldy#,z#,radius#,0)
if collide>0
rem if hit, reposition player, halt movement vector
x# = sc_getCollisionSlideX()
oldy# = sc_getCollisionSlideY()
z# = sc_getCollisionSlideZ()
vx# = 0
vz# = 0
endif
rem position the player
position object 2,x#,oldy#,z#
sc_updateObject 2
return
Step 5
This is a pretty handy chunk of code to control the camera.
If you want to limit how far down you can look,
Put this just below the
`note, this is in the movePlayer subroutine
yrotate object 2,object angle y(2)+mousemovex()/3.0
xrotate object 2,object angle x(2)+mousemovey()/3.0
part.
if object angle x(2)>90 then xrotate object 2,90
function positionCameraToObject(obj,thirdPerson)
position camera object position x(2),object position y(2),object position z(2)
rotate camera object angle x(2),object angle y(2),object angle z(2)
if thirdPerson=1
pitch camera down 10
move camera -30
endif
endfunction
Step 6
And here we have our main loop.
The change view section with the times just mean this : instead of changing the variable at the
keypress using “if inkey$() = “whatever” then view = 1-view”, we use a timer, as in a fast loop the
variable will keep changing which will cause much inconvenience.
So if you take a quick look at it again, you will see that the timer (which decreases by itself) is reset
with each change.
The rest is pretty self explanatory….text for convenience….camera control….’q’ to quit…. And shift
to reset your position.
do
gosub MovePlayer
rem change view
if inkey$()="v" and vtimer<timer() then vtimer = timer()+300 : view = 1-view
positionCameraToObject(2,view)
text 0,20,"x rot: "+str$(object angle x(2))
text 0,40,"y rot: "+str$(object angle y(2))
text 0,60,"z rot: "+str$(object angle z(2))
text 0,80,"FPS: "+str$(screen fps())
text 0,100,"Touching Ground: "+str$(ground)
text 0,120,"x = "+str$(object position x(2))
text 0,140,"y = "+str$(object position y(2))
text 0,160,"z = "+str$(object position z(2))
if inkey$() = "q" then end
if shiftkey() = 1 then position object 2,0,50,0
sync
loop
Step 6
And here we have the entire piece of code.
sync on
sync rate 60
hide mouse
autocam off
radius# = 7.0
gravity# = -0.1
slope# = 0.5
ground = 1
jumptimer = 0
gosub makeLevel
gosub makePlayer
do
gosub MovePlayer
rem change view
if inkey$()="v" and vtimer<timer() then vtimer = timer()+300 : view = 1-view
positionCameraToObject(2,view)
text 0,20,"x rot: "+str$(object angle x(2))
text 0,40,"y rot: "+str$(object angle y(2))
text 0,60,"z rot: "+str$(object angle z(2))
text 0,80,"FPS: "+str$(screen fps())
text 0,100,"Touching Ground: "+str$(ground)
text 0,120,"x = "+str$(object position x(2))
text 0,140,"y = "+str$(object position y(2))
text 0,160,"z = "+str$(object position z(2))
if inkey$() = "q" then end
if shiftkey() = 1 then position object 2,0,50,0
sync
loop
makeLevel:
load object "orbitalrelay.x",1
sc_setupComplexObject 1,1,2
return
makePlayer:
make object sphere 2,radius#*2
position object 2,0,50,0
sc_setupObject 2,0,1
return
movePlayer:
rem rotate player with mouse
yrotate object 2,object angle y(2)+mousemovex()/3.0
xrotate object 2,object angle x(2)+mousemovey()/3.0
oldx# = object position x(2)
oldy# = object position y(2)
oldz# = object position z(2)
rem apply gravity, and user changes to movement
angy# = object angle y(2)
vx# = 0
vz# = 0
if vy#=0 and jumptimer=0 then vy# = vy# + 10*gravity# else vy# = vy# + gravity#
if keystate(32)=1 then vx# = vx# + cos(angy#) : vz# = vz# - sin(angy#)
if keystate(30)=1 then vx# = vx# - cos(angy#) : vz# = vz# + sin(angy#)
if keystate(31)=1 then vx# = vx# - sin(angy#) : vz# = vz# - cos(angy#)
if keystate(17)=1 then vx# = vx# + sin(angy#) : vz# = vz# + cos(angy#)
rem only jump if on ground, and a certain time after last jump
if ground=1
if spacekey()=1 and jumptimer=0 then vy# = vy# + 3.0 : jumptimer = 20
endif
x# = oldx#+vx#
y# = oldy#+vy#
z# = oldz#+vz#
collide = sc_SphereCastGroup(1,oldx#,oldy#,oldz#,oldx#,oldy#+vy#,oldz#,radius#,0)
if collide>0
ny# = sc_getCollisionNormalY()
if abs(ny#)>slope#
rem FLAT, stick
oldy# = sc_getStaticCollisionY()
else
rem STEEP, slide
x# = x# - oldx# : z# = z# - oldz#
oldx# = sc_getCollisionSlideX()
oldy# = sc_getCollisionSlideY()
oldz# = sc_getCollisionSlideZ()
x# = x# + oldx# : z# = z# + oldz#
endif
if ny#>slope#
rem only on ground if standing on flat ground
ground = 1
vy# = 0
else
ground = 0
rem if player has hit a flat ceiling then stop vy# movement
if ny#<-slope# then vy# = gravity#
endif
else
rem nothing below player, not on ground, add vertical speed to player
oldy# = oldy# + vy#
ground = 0
endif
if ground = 1 and jumptimer>0 then dec jumptimer
collide = sc_SphereSlideGroup(1,oldx#,oldy#,oldz#,x#,oldy#,z#,radius#,0)
if collide>0
rem if hit, reposition player, halt movement vector
x# = sc_getCollisionSlideX()
oldy# = sc_getCollisionSlideY()
z# = sc_getCollisionSlideZ()
vx# = 0
vz# = 0
endif
rem position the player
position object 2,x#,oldy#,z#
sc_updateObject 2
return
function positionCameraToObject(obj,thirdPerson)
position camera object position x(2),object position y(2),object position z(2)
rotate camera object angle x(2),object angle y(2),object angle z(2)
if thirdPerson=1
pitch camera down 10
move camera -30
endif
endfunction
if memblock exist(1) then delete memblock 1
Give yourself a pat on the back if you managed to read the whole thing without getting hopelessly
confused.
Forgive me if this tutorial was incomprehensible, as it was my first tutorial. =)
Thank you once again!
Low poly fractal terrain
This will create some good looking low poly fractal terrain using this dll by
el Goorf, and will convert it into
an object using
this function by Lost in Thought, then set it up with sparky for collision.
Just put in the code in these sections-
Makelevel:
makeLevel:
mapsize = 64
FT set seed 1000
FT set fallout 0.5
FT generate heightmap rnd(255),rnd(255),rnd(255),rnd(255),mapsize
make matrix 1,1000,1000,mapsize,mapsize
for s=0 to mapsize
for t = 0 to mapsize
set matrix height 1,s,t,FT get height(s,t)/3
next t
next s
update matrix 1
Matrix_to_Object(10,1,1000,1000,mapsize,mapsize,mapsize,mapsize,mapsize,mapsize,mapsize,mapsize^2)
delete matrix 1
sc_setupcomplexobject 10,1,2
load image "grass.png",10 : texture object 10,10
return
End of code:
function Matrix_to_Object( object, matrixnum, matxsize#, matzsize#, matxsegs, matzsegs, tilex, tilez, limbx, limbz, begtexnum, endtexnum )
`safety in case matxsegs and matzsegs is not evenly divisible by tilex and tilez
if matxsegs mod tilex > 0
EXIT PROMPT "Number of matrix xsegs not evenly divisible by tilex", "Texture tilex error"
end
endif
if matzsegs mod tilez > 0
EXIT PROMPT "Number of matrix zsegs not evenly divisible by tilez", "Texture tilez error"
end
endif
`safety in case limbx and limbz is smaller than the texture x and z
a = 0
if limbx < tilex then limbx = tilex : a = 1
if limbz < tilez then limbz = tilez : a = 1
if a > 0
sync
print "limbx or limbz was less than tilex or tilez : Error corrected"
sync
wait key
endif
`calc the number of polys in the matrix
num_mat_polys = (matxsegs*matzsegs)*2
`make array to store vert info
`storage indexs = poly number, vert number, x/y/z vert pos/norm/uv
`polys are numbered starting from left to right, front to
`back, one row at a time (with 2 polys per tile)
dim vert_store#(num_mat_polys,2,7)
`calc the width and depth of each tile on the matrix
`formula size#/number
mat_x_wide# = matxsize#/matxsegs
mat_z_deep# = matzsize#/matzsegs
`******************************************************************************
`get vert position data
`placeholder variable for poly numbers
a = 1
`one row at a time (front to back)
for j = 0 to matzsegs - 1
`one tile at a time (left to right)
for i = 0 to matxsegs - 1
`tile top left poly info
`bottom left vert (x,y,z)
vert_store#(a,0,0) = i*mat_x_wide#
vert_store#(a,0,1) = GET MATRIX HEIGHT(matrixnum, i, j)
vert_store#(a,0,2) = j*mat_z_deep#
`top left vert (x,y,z)
vert_store#(a,1,0) = i*mat_x_wide#
vert_store#(a,1,1) = GET MATRIX HEIGHT(matrixnum, i, j+1)
vert_store#(a,1,2) = (j+1)*mat_z_deep#
`top right vert (x,y,z)
vert_store#(a,2,0) = (i+1)*mat_x_wide#
vert_store#(a,2,1) = GET MATRIX HEIGHT(matrixnum, i+1, j+1)
vert_store#(a,2,2) = (j+1)*mat_z_deep#
inc a, 1
`tile bottom right poly info
`bottom left vert (x,y,z)
vert_store#(a,0,0) = i*mat_x_wide#
vert_store#(a,0,1) = GET MATRIX HEIGHT(matrixnum, i, j)
vert_store#(a,0,2) = j*mat_z_deep#
`top right vert (x,y,z)
vert_store#(a,1,0) = (i+1)*mat_x_wide#
vert_store#(a,1,1) = GET MATRIX HEIGHT(matrixnum, i+1, j+1)
vert_store#(a,1,2) = (j+1)*mat_z_deep#
`bottom right vert (x,y,z)
vert_store#(a,2,0) = (i+1)*mat_x_wide#
vert_store#(a,2,1) = GET MATRIX HEIGHT(matrixnum, i+1, j)
vert_store#(a,2,2) = j*mat_z_deep#
inc a, 1
next i
next j
`******************************************************************************
`******************************************************************************
`calc normals for polys
`Thanks to ADR for posting this code on the DBP forums :)
for i = 1 to num_mat_polys
`acuire vert positions
P1X# = vert_store#(i,0,0)
P1Y# = vert_store#(i,0,1)
P1Z# = vert_store#(i,0,2)
P2X# = vert_store#(i,1,0)
P2Y# = vert_store#(i,1,1)
P2Z# = vert_store#(i,1,2)
P3X# = vert_store#(i,2,0)
P3Y# = vert_store#(i,2,1)
P3Z# = vert_store#(i,2,2)
null = make vector3(1)
null = make vector3(2)
null = make vector3(3)
` -- calculate the two directional vectors for the adj and opp edges...
set vector3 1, P1X#, P1Y#, P1Z#
set vector3 2, P2X#, P2Y#, P2Z#
set vector3 3, P3X#, P3Y#, P3Z#
subtract vector3 2, 2, 1
subtract vector3 3, 3, 1 ` -- vector 3 and 1 are now directional vectors
normalize vector3 2,2 ` -- normalize em
normalize vector3 3,3
cross product vector3 1, 2,3 ` -- use the origin vector (1) to store the face normal
normalize vector3 1,1
`save normals (all 3 verts have same normals)
vert_store#(i,0,3) = x vector3(1)
vert_store#(i,0,4) = y vector3(1)
vert_store#(i,0,5) = z vector3(1)
vert_store#(i,1,3) = vert_store#(i,0,3)
vert_store#(i,1,4) = vert_store#(i,0,4)
vert_store#(i,1,5) = vert_store#(i,0,5)
vert_store#(i,2,3) = vert_store#(i,0,3)
vert_store#(i,2,4) = vert_store#(i,0,4)
vert_store#(i,2,5) = vert_store#(i,0,5)
null = delete vector3(1)
null = delete vector3(2)
null = delete vector3(3)
next i
`******************************************************************************
`******************************************************************************
`calc UV data for polys
`save current x tile number
xtiles = 1
`save current z tile number
ztiles = 1
`calc how much to step each u data per tile
stepu# = (1.0/tilex)
`calc how much to step each v data per tile
stepv# = (1.0/tilez)
`set base u data for new set of tiles
baseu# = 0
`set base v data for new set of tiles
basev# = 1-stepv#
`poly number placeholder variable
i = 1
`from front to back
for k = 1 to matzsegs
`reset the number of x tiles to 1 and the u base to 0
`at the beginning of each row
xtiles = 1
baseu# = 0
`from left to right
for l = 1 to matxsegs
`2 polys per tile
for m = 1 to 2
`write all 3 verts of each matrix poly
for j = 0 to 2
`select which formula to apply depending on polygon side
`and vert number (0 to 2)
`j selects the vert number
`m selects the polygon side (back/left or front right : 1 or 2)
select j
case 0
if m = 1
testu# = baseu#
testv# = basev#+stepv#
else
testu# = baseu#
testv# = basev#+stepv#
endif
endcase
case 1
if m = 1
testu# = baseu#
testv# = basev#
else
testu# = baseu#+stepu#
testv# = basev#
endif
endcase
case 2
if m = 1
testu# = baseu#+stepu#
testv# = basev#
else
testu# = baseu#+stepu#
testv# = basev#+stepv#
endif
endcase
endselect
`store calculated data for each vert of each poly
`u data
vert_store#(i,j,6) = testu#
`v data
vert_store#(i,j,7) = testv#
next j
inc i, 1
`next polygon side of this tile
next m
`update u data and xtiles place holder
inc baseu#, stepu#
inc xtiles, 1
`reset data when texture tile width has been reached
if xtiles > tilex
baseu# = 0
xtiles = 1
endif
`next x tile
next l
`update v data and ztiles place holder
dec basev#, stepv#
inc ztiles, 1
`reset data when texture depth has been reached
if ztiles > tilez
basev# = 1-stepv#
ztiles = 1
endif
`next z tile
next k
`******************************************************************************
`******************************************************************************
`make object from matrix verts
`calc number of memblocks needed
tempx = matxsegs/limbx
tempz = matzsegs/limbz
tempmem = tempx * tempz
`make arrays to store memblock positions and memblock numbers
dim membhold(tempx, tempz)
dim mempos(tempmem)
`enter memblock numbers for each texture tile based on the x and z limbs to use
a = 1
for i = 1 to tempz
for j = 1 to tempx
membhold(j, i) = a
inc a, 1
next j
next i
`calc the memblock size
`formula is 12 byte header + ((( 32 bytes per vert * limb x segs)*(limb z segs * 2 polys))* 3 verts per poly)
mat_mem_size = 12+(((32*limbx)*(limbz*2))*3)
`make memblocks and write headers for each memblock and set the beginning
`position for vert data to 12
for i = 1 to tempmem
make memblock i, mat_mem_size
`write objects fvf format as 274
write memblock dword i, 0, 274
`write bytes per vert as 32 (8 floats xpos#,ypos#,zpos#,xnorm#,ynorm#,znorm#,u#,v#)
write memblock dword i, 4, 32
`write number of verts in matrix (polys*3)
write memblock dword i, 8, ((limbx*limbz)*2)*3
`set beginning position for vert data after header(0-8)+4 = 12
mempos(i) = 12
next i
`image tile, row, and memblock placeholders
xtile = 1
ztile = 1
xrow = 1
xmem = 1
zmem = 1
`polygon placeholders (b=2 is 1 tile complete)
b = 1
`enter all polys' verts to memblock
for i = 1 to num_mat_polys
`select memblock number to write to use current x and z limb tile to pick
tempmemnum = membhold(xmem, zmem)
`write all 3 verts of each matrix poly
for j = 0 to 2
`xpos
write memblock float tempmemnum, mempos(tempmemnum), vert_store#(i,j,0)
`increment the current memblock position
inc mempos(tempmemnum), 4
`ypos
write memblock float tempmemnum, mempos(tempmemnum), vert_store#(i,j,1)
inc mempos(tempmemnum), 4
`zpos
write memblock float tempmemnum, mempos(tempmemnum), vert_store#(i,j,2)
inc mempos(tempmemnum), 4
`xnorm
write memblock float tempmemnum, mempos(tempmemnum), vert_store#(i,j,3)
inc mempos(tempmemnum), 4
`ynorm
write memblock float tempmemnum, mempos(tempmemnum), vert_store#(i,j,4)
inc mempos(tempmemnum), 4
`znorm
write memblock float tempmemnum, mempos(tempmemnum), vert_store#(i,j,5)
inc mempos(tempmemnum), 4
`u data
write memblock float tempmemnum, mempos(tempmemnum), vert_store#(i,j,6)
inc mempos(tempmemnum), 4
`v data
write memblock float tempmemnum, mempos(tempmemnum), vert_store#(i,j,7)
inc mempos(tempmemnum), 4
next j
`after each poly increase b by 1
inc b, 1
`after 2 polys have been completed 1 tile has been entered
if b > 2
`reset poly count to 1
b = 1
`move to next x tile
inc xtile, 1
`if at the next limb
if xtile > limbx
`reseet the x tile to 1
xtile = 1
`update the tile count to know when to move to the next row
inc xrow, limbx
`inc the xmem selector placeholder
inc xmem, 1
`if at the last xmem wide then start back at the begining
if xmem > tempx
xmem = 1
endif
endif
`when at the end of the row
if xrow > matxsegs
`go back to the far left
xrow = 1
`update the number of rows done
inc ztile, 1
`when the number of rows done is > the preset depth
if ztile > limbz
`reset row count back to 1
ztile = 1
`move to the next zmem selector placeholder
inc zmem, 1
`if row count overlaps predetermined number
if zmem > tempz
`wrap to 1
zmem = 1
endif
endif
endif
endif
next i
`undim arrays when done with them
undim vert_store#(0,0,0)
undim membhold(0, 0)
undim mempos(0)
`set the mesh number to use (can be replaced with a findfreemesh function)
mesh = 1
`make object and limbs from data setup
for i = 1 to tempmem
`make temp mesh from info
make mesh from memblock mesh, i
`delete temp memblock
delete memblock i
`if it is the first memblock mesh, use it as the base object
if i = 1
`make temp object for NGC
make object object, mesh, begtexnum
`else turn each memblock mesh into limbs
else
add limb object, i-1, mesh
endif
`delete temp mesh
delete mesh mesh
next i
`texture limbs
j = begtexnum + 1
for i = 2 to tempmem
texture limb object, i-1, j
inc j, 1
if j > endtexnum then j = begtexnum
next i
`unrem this to make the lighting look exactly like a matrix
`set object light object, 0
`******************************************************************************
endfunction
Timer Based Movement
This is in relation to this code snippet
This is from jeffhuys.
replace the
if keystate(32)=1 then vx# = vx# + cos(angy#) : vz# = vz# - sin(angy#)
if keystate(30)=1 then vx# = vx# - cos(angy#) : vz# = vz# + sin(angy#)
if keystate(31)=1 then vx# = vx# - sin(angy#) : vz# = vz# - cos(angy#)
if keystate(17)=1 then vx# = vx# + sin(angy#) : vz# = vz# + cos(angy#)
With
if keystate(32)=1 then vx# = vx# + (t#/30)*cos(angy#) : vz# = vz# - (t#/30)*sin(angy#)
if keystate(30)=1 then vx# = vx# - (t#/30)*cos(angy#) : vz# = vz# + (t#/30)*sin(angy#)
if keystate(31)=1 then vx# = vx# - (t#/30)*sin(angy#) : vz# = vz# - (t#/30)*cos(angy#)
if keystate(17)=1 then vx# = vx# + (t#/30)*sin(angy#) : vz# = vz# + (t#/30)*cos(angy#)
(after doing "tm_init()" in the start of code and "t# = tm_update()" every cycle!
To move slower, change the 30 into 40.
Examples
This excellent one from jeffhuys also includes a cool effect called
adrenaline - press 'x' ingame an youll see.
http://forumfiles.thegamecreators.com/?i=1303047