`--------------------------------------------------
` NEWTON PHYSICS SDK WRAPPER
` DEMO PROJECT 5 - first person shooter example
`
`--------------------------------------------------
`standard DBPro startup code...
sync on
sync rate 60
autocam off
hide mouse
set ambient light 100
`set point light 0, 50, 100, 20
`set light range 0, 5000
randomize timer()
`load images
load image "..\media\fps\farm.jpg",1
load image "..\media\fps\bullethole.png", 2
`set camera start point
position camera 0.0, 5.0, -20.0
`this is just an array so I can write onscreen if the simulation is running or not.
`it has nothing to do with Newton at all.
dim GOSTR$(2)
GOSTR$(1) = "SIMULATION PAUSED"
GOSTR$(2) = "SIMULATION RUNNING"
`global variables used for the first-person camera
global Player = 0
global Player_Mass# = 12.0
global Player_Speed# = 10.0
global Player_Yangle# = 0.0
global Player_Xangle# = 0.0
global Player_ShootPower# = 5000.0
global Player_JumpSpeed# = 35.0
global Door = 0
global DoorSlider = 0
global go = 0
global Sphere = 0
global UpVector = 0
global Default = 0
global PlayerID = 0
global MoveX# = 0.0
global MoveZ# = 0.0
global dx# = 0.0
global dy# = 0.0
global dy2# = 0.0
global dz# = 0.0
global length# = 0.0
global CurrentVel_X# = 0.0
global CurrentVel_Y# = 0.0
global CurrentVel_Z# = 0.0
global GoalVel_X# = 0.0
global GoalVel_y# = 0.0
global GoalVel_Z# = 0.0
global AccelX# = 0.0
global AccelY# = 0.0
global AccelZ# = 0.0
global px# = 0.0
global py# = 0.0
global pz# = 0.0
global dist# = 0.0
global time# = 0.0
global SPACEPRESSED = 0
global distShotfuncion# = 0.0
global MOUSE = 0
global x1# = 0.0
global y1# = 0.0
global z1# = 0.0
global x2# = 0.0
global y2# = 0.0
global z2# = 0.0
global HitBody = 0
global castdist# = 0.0
global cast_x# = 0.0
global cast_y# = 0.0
global cast_z# = 0.0
global hitmass# = 0.0
global obj = 0
global x# = 0.0
global nx# = 0.0
global nx2# = 0.0
global y# = 0.0
global ny# = 0.0
global z# = 0.0
global nz# = 0.0
global x#
global y#
global z#
global sx#
global sy#
global sz#
global rx#
global ry#
global rz#
global mass#
global col
global body
global obj
global color
TOP()
`I am using GOTO in these demos to keep them simple, in a real game situation you
`would probably want to avoid this programming style.
`------------------------------------------------
`------------------------------------------------
` -----------------------------------
` MAIN LOOP
` -----------------------------------
do
`get the elapsed time since last frame and save into time# variable.
time# = NDB_GetElapsedTimeInSec()
` Here's the big command that updates the Physics system.
` Objects are moved and positioned automatically.
` the if GO=1 part is just a variable check so we can pause and unpause the system.
if GO = 1 then NDB_NewtonUpdate time#
`if user presses "q" key, quit the program!
if lower$(inkey$()) = "q" then exit
`if user presses "r", we need to reset. so first destroy the Newton World, which will in turn
`delete all of the DBpro objects for us. then goto TOP, and start over!
if lower$(inkey$()) = "r"
for x = 105 to 109
Delete object x
delete image x
next x
for x = 1 to 2
delete sound x
next x
NDB_NewtonDestroy
TOP()
endif
` this part is for pausing/unpausing. basically it sets the GO variable to 1 or 0.
if keystate(25) and P_PRESSED = 0 then P_PRESSED = 1
if P_PRESSED = 1
P_PRESSED = 2
inc GO, 1
if GO > 1 then GO = 0
endif
if keystate(25) = 0 then P_PRESSED = 0
`draw the text in the upper left part of the screen.
DrawOnscreenData()
`handle player movement and jumping!!
HandleCamera()
`handle shooting objects!
Shooting()
`handle the automatic door!
` DoorCheck()
`NEWTON DEBUGGING SYSTEM:
` This may be a bit confusing to some users... if you don't understand it, ignore it for now.
` the DebugMakeNewtonObject command is really cool. it takes the entire Newton world, and makes
` it into a single DBpro object, so you can see the "world according to Newton" onscreen. you can
` use this to make sure that your visual objects and your rigid bodies are lined up, and also see the
` actual shape of the object according to Newton. Here I check if the control key is down, and if
` so I make the newton object, and save it into the "obj" variable. then I update the screen with
` te sync command, and then delete the "obj" right after syncing.
` there is also another debug command called DebugDrawNewtonLines, which draws the lines in 2D. it's
` slower than this command, but you don't have to fiddle with making and deleting objects. see the docs.
if controlkey()
obj = NDB_DebugMakeNewtonObject()
set object light obj, 0
else
obj = 0
endif
`update the screen
sync
if obj <> 0
delete object obj
endif
loop
` -----------------------------------
` -----------------------------------
` Destory the Newton world, clearing up any memory that was allocated.
NDB_NewtonDestroy
end
function top()
`Initialize Newton, and create the Newton World.
NDB_NewtonCreate
`Set the temp vector to our gravity constant (acceleration due to gravity)
`then set as our standard gravity force.
NDB_SetVector 0.0, -50.0, 0.0
NDB_SetStandardGravity
`make the test room!
MakeRoom()
`make the player (camera) body used for player movement!
MakePlayer()
`make the sky cube
Load_SkyCube()
` the first time you call this command, you may get a very large time#,
` so I call it twice at the start, to make sure we're getting a nice small time# value.
time# = NDB_GetElapsedTimeInSec()
time# = NDB_GetElapsedTimeInSec()
`this variable is used for pausing/unpausing the simulation.
GO = 1
endfunction
function Load_Skycube()
REM Load Images for Cube Environmental map
Load Image "..\Media\skymap\terrain0003.jpg",105
Load Image "..\Media\skymap\terrain0004.jpg",106
Load Image "..\Media\skymap\terrain0005.jpg",107
Load Image "..\Media\skymap\terrain0002.jpg",108
Load Image "..\Media\skymap\terrain0001.jpg",109
WallSizeX = 1500
WallSizeY = 1500
SkyMapHeight = 50
REM Sky Cube (using number range 5-9 for textures and objects)3
FOR WallBox = 105 TO 109
Make object plain WallBox ,WallSizeX, WallSizeY
texture object WallBox, WallBox
`SET OBJECT TEXTURE WallBox,2,0
Next Wallbox
position object 105,750, SkyMapHeight, 1500
Rotate Object 105,0,180,0
Position object 106,0,SkyMapHeight,750
rotate object 106,0,90,0
Position Object 107,750,SkyMapHeight,0
Rotate Object 107,0,0,0
Position Object 108,1500,SkyMapHeight,750
Rotate Object 108,0,270,0
Position Object 109,750,799,750
Rotate Object 109,90,90,0
EndFunction
function MakeRoom()
`this example uses TreeCollision objects for the level. Tree Collisio objects are just another way of
`describing collision shapes to Newton... but instead of using a primitive shape, it uses the polygon data
`from a 3D model. in Newton TreeCollision objects can only have a mass of 0, so they cannot be dynamic objects.
`this is fine for background pieces, which should never move anyway.
`Step 1- load the model to make the collision from. In this case it's also out visual model, but you might
` want to use another model specifically for collision. Also see the docs for info about the Serialization
` system, which can make loading TreeCollision objects MUCH faster for large, complex models.
obj = FreeObject()
load object "..\media\fps\farm.x", obj
`load sounds
load 3dsound "..\media\sounds\wind.wav",1
`load music
load sound "..\media\Music\music misty room loop.wav",2
for x = 1 to 2
play sound x
loop sound x
next x
`Step 2- make the TreeCollision data from the object, and save into variable "Col"
Col = NDB_NewtonCreateTreeCollision( obj )
`Step 3- make the rigid body from the collision data
Room = NDB_NewtonCreateBody( Col )
`next you would position the object + rigid body, but we're leaving them at 0,0,0 for this demo.
`Step 4- finally, attach the object to the Rigid Body
NDB_BodySetDBProData Room, obj
NDB_NewtonBodySetDestructorCallback Room
NDB_NewtonReleaseCollision Col
`that's it! the TreeCollision body is ready, so our level will have collision!
REMSTART
`next we want to add a sliding door to our level. we will make the door from a simple Box rigid body,
`and connect it to the level body via a SLIDER joint, as we want a sliding door.
Door = MakeBox( 18.5, 0.0, -11.0, 13.0, 14.0, 1.0, 0.0, 0.0, 0.0, 25.0 )
NDB_BodySetGravity Door, 0
`When making a joint, you generally set vector 1 to the location of the joint, and vector 2 to a unit vector
`describing the direction of the joints`s "pin". see the docs for more information on all joints.
NDB_SetVector 1, 18.5, 0.0, -11.0
NDB_SetVector 2, 0.0, 1.0, 0.0
DoorSlider = NDB_NewtonConstraintCreateSlider( Door, Room )
NDB_SetSliderLimits DoorSlider, -3.0, 20.0
NDB_SetSliderMotorAccel DoorSlider, -50.0
REMEND
`finally, add a few crates around to shoot at!
x# = 170.0
y# = 33.0
z# = 175.0
level = 1
boxes = 3
repeat
startz# = z# + -((boxes*5.0) / 2.0)
for i=1 to boxes
Body = MakeBox( x#, y#, startz#+(i*6.0), 5.0, 5.0, 5.0, 0.0, 0.0, 0.0, 25.0 )
next i
inc y#, 6.0
dec boxes
inc level
until boxes = 0
x# = 110.0
y# = 10.0
z# = 110.0
level = 1
boxes = 3
repeat
startz# = z# + -((boxes*5.0) / 2.0)
for i=1 to boxes
Body = MakeBox( x#, y#, startz#+(i*6.0), 5.0, 5.0, 5.0, 0.0, 0.0, 0.0, 5.0 )
next i
inc y#, 6.0
dec boxes
inc level
until boxes = 0
endfunction
`This function makes the rigid body that represents the player
function MakePlayer()
`for the player (camera), we're going to use an ellipsoid shape. this is a sphere that is "streched"
`on one or two axis'. in this case, we'll make it much taller than it is around, to mimick a human.
Sphere = NDB_NewtonCreateSphere( 2.5, 6.0, 2.5 )
Player = NDB_NewtonCreateBody( Sphere )
`setting the initial starting position.
NDB_BuildMatrix 0.0, 0.0, 0.0, 100.0, 10.0, 100.0
NDB_NewtonBodySetMatrix Player
`setting the mass...
NDB_SetVector 6.0, 8.0, 6.0
NDB_CalculateMIBoxSolid Player_Mass#
NDB_NewtonBodySetMassMatrix Player, Player_Mass#
`Newton automatically "freezes" objects which have come to rest, which means they are no longer calculated
`each time you call NDB_NewtonUpdate. they start calculating agani when another object hits them and sets
`them in motion again. However with our Player rigid body, we want it to be moved by the user's keyboard input.
`if the body freezes, Newton will not let the user move the body, because it's not in the active body list.
`To make a long story short, we need to tell Newton NOT to freeze this body, EVER. This will make Newton
`calculate this body every call to NewtonUpdate. this of course takes processor power, so it's best not to
`call this for too many bodies.
NDB_NewtonBodySetAutoFreeze Player, 0
NDB_BodySetGravity Player, 1
`Here's the meat and potatoes of the character system: the UpVector joint. this joint allows the character to
`move in 3 dimensions, but won't allow it to "fall over" when it hits other objects. which is exactly what we want
`here. for more info, have a look at the joint example and the documentation.
NDB_SetVector 0.0, 1.0, 0.0
UpVector = NDB_NewtonConstraintCreateUpVector( Player )
`Finally, because we want to control the player manually, we don't want friction getting in our way and causing
`problems... so I remove all friction between the Player material, and the Default material (aka everything else).
`this makes it MUCH easier to calculate the forces needed to move the player later.
Default = NDB_NewtonMaterialGetDefaultGroupID()
PlayerID = NDB_NewtonMaterialCreateGroupID()
NDB_NewtonMaterialSetDefaultFriction Default, PlayerID, 0.01, 0.01
NDB_NewtonMaterialSetDefaultElasticity Default, PlayerID, 0.01
`after setting the materials, we need to apply the Player material to the Player rigid body.
NDB_NewtonBodySetMaterialGroupID Player, PlayerID
endfunction
`this subroutine makes the simple in-screen display, which explains how to use the demo.
function DrawOnscreenData()
box 5,5,515,122,rgb(0,0,0),rgb(100,100,100),rgb(0,0,0),rgb(100,100,100)
line 5,5,515,5
line 5,5,5,122
line 515,5,515,122
line 5,122,515,122
text 10,10,"Aeons Tales BETA Ver.02
WWW.ENYGMASOFT.COM"
text 10,20,"Pre Aylana Model. Third Person will be implemented"
text 10,40," Move with W,S,A,D Keys || Look with mouse"
text 10,50," Left Mouse Button to shoot || Hold CTRL for debug data"
text 10,60," SHIFT to run || SPACE to jump || "p" to (un)pause"
text 10,70," Press "r" to reset || press "q" to quit"
text 10,80," FPS:"+str$(screen fps()) + " Body Count:"+str$(NDB_DebugRigidBodyCount())
text 10,90," Physics powered by Newton Dynamics "+str$(NDB_GetVersion())
text 10,105," "+GOSTR$(GO+1)
text 10, 120,"nx#: "+str$(nx#)
text 10, 130,"nx2# : "+str$(nx2#)
text 10, 140,"cast_x# :"+str$(cast_x#)
text 10, 150," cast_y# :"+str$(cast_y#)
text 10 ,160," cast_z# :"+str$(cast_z#)
ink rgb(255,0,0), rgb(0,0,0)
line 320, 220, 320, 260
line 300, 240, 340, 240
ink rgb(255,255,255), rgb(0,0,0)
endfunction
`This is the important subroutine that controls the Player movement. I will try to explain it in some detail.
`Basically the setup is like this: I have the Player rigid body I made in the MakePlayer subroutine, which is
`an elipsoid object that always stands up. Each game loop, I place the camera in same position as that Rigid
`Body. I also have 2 variables that represent the camera's orientation: Player_Yangle# and Player_Xangle#.
`these are linked to the mouse, to allow the user to look around. Then, when the user wants to move, I
`use the camera to deterime which way the player is facing, and then apply a force to the body in the direction
`of movement. The force is calculated in such a way that the player moves at a constant speed when walking.
`
`Here's how we calculate the movement force:
`
` In physics there is the formula F = m * a, where F is the force, m is the mass, and a is the acceleration.
`
` we also know that a (acceleration) is a CHANGE in velocity. so we can write "a" as (v2-v1)/time.
` this is basically (goal_velocity - current_velocity) / time.
`
` so in this part, after I calculate the direction I want to go, I get the current velocity, and use that
` to find the necessary acceleration to achieve that velocity. then I simlply plug that into Newton, and it
` takes care of the rest! I'll write more comments as I go to hopefully make it understandable.
function HandleCamera()
`-------------------------
`CAMERA
`-------------------------
`these variables rotate the camera.
inc Player_Xangle#, mousemovey() * 0.25
inc Player_Yangle#, mousemovex() * 0.25
position mouse 320, 240
`put a limit on how much the player can loop up/down.
if Player_Xangle# > 80.0 then Player_Xangle# = 80.0
if Player_Xangle# < -80.0 then Player_Xangle# = -80.0
rotate camera Player_Xangle#, Player_Yangle#, 0.0
`here we get the position of the Player rigid body, and place the camera there.
NDB_BodyGetPosition Player
position camera NDB_GetVector_X(), NDB_GetVector_Y(), NDB_GetVector_Z()
position sound 1,NDB_GetVector_X(), NDB_GetVector_Y(), NDB_GetVector_Z()
`next we set the movement variables to zero. the will stay at zero unless the user pressed a movement key.
`player movement defaults to zero each loop.
MoveX# = 0.0
MoveZ# = 0.0
if keystate(17) or keystate(31)
`player is pressing "w" or "s" key, we need to move forward or backward!
`find direction vector my moving the camera...
`i use some trig to find the direction the player wants to move.
dx# = sin(Player_Yangle#)
dz# = cos(Player_Yangle#)
`then I add this to the move vector, making it positive for forward, negative for backward.
inc MoveX#, dx# * (keystate(17)-keystate(31)) :`makes a positive vector with "w", negative with "s"
inc MoveZ#, dz# * (keystate(17)-keystate(31))
endif
if keystate(30) or keystate(32)
`same thing here, but this is for strafing, so I add 90 degrees to the current angle!
dx# = sin(Player_Yangle#+90.0)
dz# = cos(Player_Yangle#+90.0)
inc MoveX#, dx# * (keystate(32)-keystate(30)) :`makes a positive vector with "d", negative with "a"
inc MoveZ#, dz# * (keystate(32)-keystate(30))
endif
`Now we need ouy direction vector the be a unit vector, so we divide by the length of the vector.
`if you are confused here, please do a little research on vector math, it's VERY important for any 3D
`application!
`finally, re-normalize the move vector
length# = sqrt( (MoveX#^2)+(MoveZ#^2) )
MoveX# = MoveX# / length#
MoveZ# = MoveZ# / length#
`okay, new let's find the current velocity of the player. that's easy through newton...
NDB_NewtonBodyGetVelocity Player
CurrentVel_X# = NDB_GetVector_X()
CurrentVel_Y# = NDB_GetVector_Y()
CurrentVel_Z# = NDB_GetVector_Z()
`and our goal velocity is simply our move direction multiplied by the player's walking speed. (or 2x if running)
GoalVel_X# = MoveX# * (Player_Speed# * ((shiftkey()+1)*2) )
GoalVel_Z# = MoveZ# * (Player_Speed# * ((shiftkey()+1)*2) )
`here we calculate the actual acceleration needed to reach our Goal_Velocity. note that I multiply by 0.3, which
`is just a damper to keep the forces from getting too large too quickly.
AccelX# = 0.3 * ((GoalVel_X# - CurrentVel_X#) / time#)
AccelZ# = 0.3 * ((GoalVel_Z# - CurrentVel_Z#) / time#)
`also we want to limit how big the acceleration can be. this keeps the player from being able to push
`really heavy objects, etc.
if AccelX# > 200.0 then AccelX# = 200.0
if AccelX# < -200.0 then AccelX# = -200.0
if AccelZ# > 200.0 then AccelZ# = 200.0
if AccelZ# < -200.0 then AccelZ# = -200.0
`finally, we just need to apply this force to the Player! we'll use the AddForceGlobal command.
`NOTE- in the forumla above, I said F = m * a. we calculated "a", but we never multiplied by the mass!
` this is because my wrapper does this for you. it automatically multiples the force by the body
` mass inside the function.
`set temp vector 1 to force location
NDB_BodyGetPosition Player
`set temp vector 2 to force direction
NDB_SetVector 2, AccelX#, 0.0, AccelZ#
NDB_BodyAddForceGlobal Player
`we also want jumping to be available. for this we will use a simple ray cast to determine if we're
`standing on the ground or not.
AccelY# = 0.0
if spacekey() and SPACEPRESSED = 0
SPACEPRESSED = 1
`user has pressed the space bar, apparently they would like to jump
`cast a ray from the player location straight down, see if we hit something.
NDB_BodyGetPosition Player
px# = NDB_GetVector_X() : py# = NDB_GetVector_Y() : pz# = NDB_GetVector_Z()
NDB_SetVector 1, px#, py#, pz#
NDB_SetVector 2, px#, py# - 6.05, pz#
dist# = NDB_NewtonWorldRayCast()
if dist# < 1.15
`something has been found! in this case, we don't care what, just let the player jump!
`the jump part is just a simple upward force..
AccelY# = ((Player_JumpSpeed# - CurrentVel_Y#) / time#)
`add another force to the player, the jumping force! this is just like above, using the
`new AddForceGlobal command! easy, huh?
NDB_BodyGetPosition Player
NDB_SetVector 2, 0.0, AccelY#, 0.0
NDB_BodyAddForceGlobal Player
endif
endif
if spacekey() = 0 then SPACEPRESSED = 0
`and there you go!! FPS character controlling in remarkably few lines
endfunction
function Shooting()
if mouseclick() = 1 and MOUSE = 0
MOUSE = 1
`user wants to shoot! let's cast a ray with Newton and see if we've hit something!
x1# = camera position x() : y1# = camera position y() : z1# = camera position z()
`get a unit vector in the direction the player is facing, by moving the camera 1 unit!
move camera 1.0
x2# = camera position x()
y2# = camera position y()
z2# = camera position z()
move camera -1.0
`we will cast a ray 500 units long.
`dx# = sin(Player_Yangle#)
dx# = x2# - x1#
`dy# = ((sin(Player_Xangle#))* -1)
dy# = y2# - y1#
dz# = z2# - z1#
`dz# = cos(Player_Yangle#)
x2# = x1# + (dx# * 1500.0)
y2# = y1# + (dy# * 1500.0)
z2# = z1# + (dz# * 1500.0)
`cast the ray. put start point in vector 1, end point in vector 2
NDB_SetVector 1, x1#, y1#, z1#
NDB_SetVector 2, x2#, y2#, z2#
distShotfuncion# = NDB_NewtonWorldrayCast()
if distShotfuncion# < 1.0
`something hit!
HitBody = NDB_RayCastGetBody()
castdist# = distShotfuncion# * 1500.0
cast_x# = x1# + (dx# * castdist#)
cast_y# = y1# + (dy# * castdist#)
cast_z# = z1# + (dz# * castdist#)
hitmass# = NDB_NewtonBodyGetMassMatrix( HitBody )
if hitmass# > 0.0
`this is a live object, give it a kick!
NDB_SetVector 1, cast_x#, cast_y#, cast_z#
NDB_SetVector 2, dx# * Player_ShootPower#, dy# * dz# * Player_ShootPower#, 0.0
NDB_BodyAddForceGlobal HitBody
NDB_NewtonWorldUnfreezeBody HitBody
else
`this is the background (mass=0), add a bullethole!
obj = FreeObject()
make object plain obj, 0.5, 0.5
position object obj, cast_x#-(dx#*0.01), cast_y#-(dy#*0.01), cast_z#-(dz#*0.01)
NDB_RayCastGetNormal
nx# = NDB_GetVector_X() : ny# = NDB_GetVector_Y() : nz# = NDB_GetVector_Z()
nx2#= sin(Player_Yangle#)
x# = cast_x# + nx# : y# = cast_y# + ny# : z# = cast_z# + nz#
point object obj, x#, y#, z#
texture object obj, 2
set object transparency obj, 1
endif
endif
endif
if mouseclick() = 0 then MOUSE = 0
text 10,300,"HitBody:"+str$(HitBody)
text 10,310,"HitMass:"+str$(hitmass#)
endfunction
`this subroutine simply checks the distance (on the XZ plane) between the Player and the Door. if it's within
`15 units, it sets the door to open. if it's not, it sets the door to close. simple.
REMSTART
function DoorCheck()
NDB_BodyGetPosition Player
x1# = NDB_GetVector_X() : z1# = NDB_GetVector_Z()
NDB_BodyGetPosition Door
x2# = NDB_GetVector_X() : z2# = NDB_GetVector_Z()
dx# = x2# - x1#
dz# = z2# - z1#
dist# = sqrt( (dx#^2)+(dz#^2) )
if dist# < 15.0
`player is close to the door, open it!
NDB_SetSliderMotorAccel DoorSlider, 50.0
`the door may have fallen asleep, so let's un-freeze it!"
if NDB_BodyActive(Door) = 0 then NDB_NewtonWorldUnfreezeBody Door
NEARDOOR = 1
else
if NEARDOOR = 1
`we have just walked away from being under the door,
`so make sure the door isn't frozen, or it won't shut!
if NDB_BodyActive(Door) = 0 then NDB_NewtonWorldUnfreezeBody Door
NEARDOOR = 0
endif
`player is away from door, turn motor off!
NDB_SetSliderMotorAccel DoorSlider, -50.0
endif
endfunction
REMEND
`all of these functions are pretty similar, they just make different collision
`primitives. I'll explain the BOX in detail, and the others are all basically the same,
`except for the Convex Hulls, which I'll explain in detail as well.
function MakeBox(x#,y#,z#,sx#,sy#,sz#,rx#,ry#,rz#,mass#)
Col = NDB_NewtonCreateBox(sx#, sy#, sz#)
Body = NDB_NewtonCreateBody(Col)
NDB_BuildMatrix rx#, ry#, rz#, x#, y#, z#
NDB_NewtonBodySetMatrix Body
NDB_CalculateMIBoxSolid mass#, sx#, sy#, sz#
NDB_NewtonBodySetMassMatrix Body, mass#
NDB_NewtonReleaseCollision Col
obj = FreeObject()
load object "..\media\box.x", obj
scale object obj, sx#*100.0, sy#*100.0, sz#*100.0
position object obj, x#, y#, z#
rotate object obj, rx#, ry#, rz#
color = GetColor()
color object obj, color
set object ambience obj, 50
NDB_BodySetDBProData Body, obj
NDB_NewtonBodySetDestructorCallback Body
NDB_BodySetGravity Body, 1
endfunction Body
function FreeObject()
repeat
inc i
if object exist(i)=0 then found=1
until found
endfunction i
function GetColor()
repeat
r = rnd(1)*255
g = rnd(1)*255
b = rnd(1)*255
until r<>0 or g<>0 or b<> 0
color = rgb(r,g,b)
endfunction color
`must force DBPro to include the memblock command set, because the wrapper uses these commands internally
`to make TreeCollision objects! it's also necessary for Convex Hull primitives as well.
function NeverCalled()
if memblock exist(1) then delete memblock 1
endfunction