<Update: code updated 3rd April 07.>
Most recent code here:-
`Sliding box collision by Ric.
`Makes use of Sparky's collision dll.
color backdrop rgb(200,200,255)
sync on
sync rate 0
autocam off
position camera 0,0,-600
fov#=60.0
set camera fov fov#
sw#=screen width()
sh#=screen height()
screenaspect#=sh#/sw#
screenx#=(0-camera position z())*tan(fov#/2.0)/screenaspect#
screeny#=(0-camera position z())*tan(fov#/2.0)
global pick
global loopnumber
global maxangv#=2.0 `maximum angular velocity
type objecttype
mass as float
velocityx as float
velocityy as float
angv as float
radius as float
endtype
type nodetype
x as float
y as float
objectnumber as integer
ang as float
endtype
`make a plane for the ground
make object plain 10000,1000,1000
create bitmap 1,50,50
ink rgb(100,100,100),0
box 0,0,50,50
ink -1,0
for n=1 to 200
dot rnd(50),rnd(50)
next n
blur bitmap 1,3
get image 10000,0,0,50,50
delete bitmap 1
texture object 10000,10000
ghost object on 10000
position object 10000,0,0,25
`make some objects
`set the seed number here
lowestobjectnumber=1
`set the number of boxes here
highestobjectnumber=100
global dim node(highestobjectnumber,4) as nodetype
global dim object(highestobjectnumber) as objecttype
randomize timer()
for object=lowestobjectnumber to highestobjectnumber
`set the box sizes here
make object box object,10+rnd(40),10+rnd(40),50
create bitmap 1,10,10
ink rgb(rnd(255),rnd(255),rnd(255)),0
box 0,0,10,10
if image exist(1)=1 then delete image 1
get image object,0,0,10,10,1
delete bitmap 1
sc_setupobject object,0,0
texture object object,object
create_nodes(object)
`position the boxes
position object object,rnd(200)-100,rnd(200)-100,0
`set the mass of the boxes
object(object).mass=object size x(object)*object size y(object)*0.01
`just some reflections - nothing to do with the physics
clone object object+500,object
texture object object+500,object
set alpha mapping on object+500,10
glue object to limb object+500,object,0
position object object+500,0,0,50
next test
ink 0,0
do
inc loopnumber
gosub drag_and_rotate
apply_physics(lowestobjectnumber,highestobjectnumber)
text 0,0,"fps: "+str$(screen fps())
sync
loop
function apply_physics(lowestobjectnumber,highestobjectnumber)
for object=lowestobjectnumber to highestobjectnumber
sc_updateobject object
for node=1 to 4
`store current position of nodes and update
node(object,node).x=object position x(object)+object(object).radius*cos(90+object angle z(object)+node(object,node).ang)
node(object,node).y=object position y(object)+object(object).radius*sin(90+object angle z(object)+node(object,node).ang)
for target=lowestobjectnumber to highestobjectnumber
if target<>object
collision=sc_sphereslide(target,object position x(object),object position y(object),object position z(object),node(object,node).x,node(object,node).y,object position z(object),1,object)
if collision>0 and collision<>node(object,node).objectnumber
`get collision normals on target
cx#=sc_getcollisionnormalx()
cy#=sc_getcollisionnormaly()
`get new node position based on sliding data
sx#=sc_getcollisionslidex()
sy#=sc_getcollisionslidey()
`get x and y adjustments from original node position to new node position
adjustx#=(sx#-node(object,node).x)/2.0
adjusty#=(sy#-node(object,node).y)/2.0
if object<>pick
`apply force equal to the adjustment value
ax#=adjustx#/object(object).mass
inc object(object).velocityx,ax#
ay#=adjusty#/object(object).mass
inc object(object).velocityy,ay#
position object object,object position x(object)+adjustx#,object position y(object)+adjusty#,object position z(object)
endif
if target<>pick
`adjust the target position by the negative adjustment value
position object target,object position x(target)-adjustx#,object position y(target)-adjusty#,object position z(target)
`apply force equal to the adjustment value
ax#=-adjustx#/object(target).mass
inc object(target).velocityx,ax#
ay#=-adjusty#/object(target).mass
inc object(target).velocityy,ay#
`rotate target
`calculate moment
forcex#=node(object,node).x
forcey#=node(object,node).y
forceangle#=atanfull(cx#,cy#)+180
pivotx#=object position x(target)
pivoty#=object position y(target)
forcesize#=sqrt(adjustx#^2+adjusty#^2)/2.0
moment#=moment(forcesize#,forcex#,forcey#,forceangle#,pivotx#,pivoty#)
angularacc#=moment#/object(target).mass
inc object(target).angv,angularacc#
endif
endif
endif
next target
next node
next object
`update positions
for object=lowestobjectnumber to highestobjectnumber
if loopnumber=1
object(object).velocityx=0
object(object).velocityy=0
object(object).angv=0
endif
position object object,object position x(object)+object(object).velocityx,object position y(object)+object(object).velocityy,object position z(object)
if object position x(object)>400 then position object object,400,object position y(object),0
if object position x(object)<-400 then position object object,-400,object position y(object),0
if object position y(object)>300 then position object object,object position x(object),300,0
if object position y(object)<-300 then position object object,object position x(object),-300,0
object(object).velocityx=object(object).velocityx*0.98
object(object).velocityy=object(object).velocityy*0.98
rotate object object,0,0,object angle z(object)+object(object).angv
object(object).angv=object(object).angv*0.95
if object(object).angv>maxangv# then object(object).angv=maxangv#
next object
endfunction
drag_and_rotate:
if mouseclick()>0 and picked=0
pick=pick object(mousex(),mousey(),object1,highestobjectnumber)
if pick>0
picked=1
`store offsets
x#=((2*screenx#*mousex()/sw#)-screenx#+camera position x())
y#=-((2*screeny#*mousey()/sh#)-screeny#)+camera position y()
dx#=-x#+object position x(pick)
dy#=-y#+object position y(pick)
endif
endif
if picked=1 and mouseclick()=1
x#=((2*screenx#*mousex()/sw#)-screenx#+camera position x())
y#=-((2*screeny#*mousey()/sh#)-screeny#)+camera position y()
position object pick,x#+dx#,y#+dy#,0
object(pick).velocityx=0
object(pick).velocityy=0
endif
if picked=1 and mouseclick()=2 and rotate=0
mx=mousex()
ang#=object angle z(pick)
rotate=1
endif
if rotate=1
rotate object pick,0,0,ang#-(mousex()-mx)
object(pick).angv=0
endif
if picked=1 and mouseclick()=0 then picked=0:rotate=0
return
function free_object()
repeat
inc n
until object exist(n)=0
endfunction n
function free_node()
n=1000
repeat
inc n
until object exist(n)=0
endfunction n
function create_nodes(object)
object(object).radius=sqrt((object size x(object)/2.0)^2+(object size y(object)/2.0)^2)
node(object,1).ang=atanfull(object size x(object)/2.0,object size y(object)/2.0)
node(object,2).ang=atanfull(object size x(object)/2.0,-object size y(object)/2.0)
node(object,3).ang=atanfull(-object size x(object)/2.0,-object size y(object)/2.0)
node(object,4).ang=atanfull(-object size x(object)/2.0,object size y(object)/2.0)
endfunction
delete memblock 1
function moment(forcesize#,forcex#,forcey#,forceangle#,pivotx#,pivoty#)
`distance from point of application of force to pivot
distance#=distance(forcex#,forcey#,pivotx#,pivoty#)
`angle of the line joining point of application of force to pivot
bearing#=bearing(forcex#,forcey#,pivotx#,pivoty#)
`angle between force and perpendicular to line joining point of application of force to pivot
theta#=90-(forceangle#-bearing#)
moment#=forcesize#*distance#*cos(theta#)
endfunction moment#
function distance(x1#,y1#,x2#,y2#)
x#=x2#-x1#
y#=y2#-y1#
distance#=sqrt(x#*x#+y#*y#)
endfunction distance#
function bearing(x1#,y1#,x2#,y2#)
x#=x2#-x1#
y#=y2#-y1#
bearing#=atanfull(x#,y#)
endfunction bearing#
This code snippet demonstrates how to perform accurate collision between 3d boxes in a plane, with reasonably realistic linear and angular motion. No media needed, but you must have Sparky's sc_collision.dll in your user plugins folder.
Left mouse click - drag the boxes around
Right mouse click - rotate the boxes
For those who are interested, this method uses raycasting from the centre of each box to each of its four corners (in the plane of motion). The advantage of this method over spherical or elipsoid raycasting is that you get more realistic interactions between the corners of the boxes, and less calculations are required. The code also calculates the moment (or torque) applied to each box, so that objects posess angular as well as linear momentum.