Just though I'd share this - it was my winning entry for a recent DBPro coding challenge. It has some useful features if your interested in seeing how this sort of game can be accomplished without using external physics or rotation plugins, and could be used as a foundation for something more. It's also quite fun to play - but be warned, it's quite hard!
Thanks to Lower Logic for his excellent global rotation functions.
____________________________________________________________________
Aim: Get the ball onto the purple platform
Controls:
Arrowkeys to tilt the table
Spacekey to nudge, just incase the ball gets stuck.
Hint: Start at the bottom left, and follow the green path!
If anyone wants to use this as the basis for their own game, then feel free.
`Marble rolling game by Ric, 2007.
`Global rotation functions by Lower Logic
gosub display
`udt's
type balltype
x as float
y as float
z as float
vx as float
vy as float
vz as float
omega as float `angular velocity
endtype
myball as balltype
type boardtype
omega as float `angular velocity
endtype
board as boardtype
gosub make_ball
gosub make_background
gosub make_textures
gosub make_board
gosub set_ball_properties
gosub set_ground_properties
gosub make_vectors
gosub make_spirit_levels
do
gosub control_board
gosub collision
gosub move_ball
gosub move_camera
gosub apply_friction
gosub update_spirit_levels
gosub nudge
gosub replace
sync
loop
nudge:
if spacekey()=1 then position object ball,object position x(ball)+5,object position y(ball),object position z(ball)
return
replace:
if object position y(ball)<-100
position object ball,0,20,0.1
myball.vx=0
myball.vy=0
myball.vz=0
endif
return
make_spirit_levels:
pitchback=free_image()
create bitmap 1,100,100
word$="PITCH"
ink rgb(180,180,255),0
text 50-text width(word$)/2.0,0,word$
box 0,50,100,100
get image pitchback,0,0,100,100,1
delete bitmap 1
sprite pitchback,100,668,pitchback
set sprite alpha pitchback,130
pitch=free_image()
create bitmap 1,100,100
ink -1,0
box 0,49,100,51
get image pitch,0,0,100,100,1
delete bitmap 1
sprite pitch,150,718,pitch
offset sprite pitch,50,50
rollback=free_image()
create bitmap 1,100,100
word$="ROLL"
ink rgb(180,180,255),0
text 50-text width(word$)/2.0,0,word$
box 0,50,100,100
get image rollback,0,0,100,100,1
delete bitmap 1
sprite rollback,824,668,rollback
set sprite alpha rollback,130
roll=free_image()
create bitmap 1,100,100
ink -1,0
box 0,49,100,51
get image roll,0,0,100,100,1
delete bitmap 1
sprite roll,874,718,roll
offset sprite roll,50,50
return
update_spirit_levels:
rotate sprite pitch,-anglex#
rotate sprite roll,anglez#
return
apply_friction:
dec myball.vx,myball.vx*friction#
dec myball.vz,myball.vz*friction#
return
move_camera:
position object cameradummy,object position x(ball),object position y(ball),object position z(ball)
rotate object cameradummy,0,0,0
rotate_gx(cameradummy,anglex#)
move object cameradummy,-100
move object up cameradummy,100
point object cameradummy,object position x(ball),object position y(ball),object position z(ball)
roll object left cameradummy,anglez#
position camera object position x(cameradummy),object position y(cameradummy),object position z(cameradummy)
set camera to object orientation cameradummy
set object to camera orientation cube
pitch object up cube,45
return
make_background:
background=free_image()
create bitmap 1,500,500
ink rgb(0,255,0),0
for n=0 to 499 step 10
line n,0,n,500
line 0,n,500,n
next n
get image background,0,0,500,500,1
delete bitmap 1
cube=free_object()
make object cube cube,-500
texture object cube,background
return
make_vectors:
vleft=1
vright=2
vahead=3
vbehind=4
vabove=5
vbelow=6
null=make vector3(vleft)
null=make vector3(vright)
null=make vector3(vahead)
null=make vector3(vbehind)
null=make vector3(vabove)
null=make vector3(vbelow)
set vector3 vleft,-10,0,0
set vector3 vright,10,0,0
set vector3 vahead,0,0,10
set vector3 vbehind,0,0,-10
set vector3 vabove,0,10,0
set vector3 vbelow,0,-10,0
return
collision:
`repeat for each vector 1 to 6
for n=1 to 6
`store xyz coordinates around ball
x#=object position x(ball)+x vector3(n)
y#=object position y(ball)+y vector3(n)
z#=object position z(ball)+z vector3(n)
dist#=intersect object(ground,object position x(ball),object position y(ball),object position z(ball),x#,y#,z#)
if dist#=0 then dist#=1000
if dist#<=2.5
`if collision in a certain direction is detected, then reverse the velocity in that direction, and multiply by dampening amount
overlap#=2.5-dist#
if n=1
myball.vx=-myball.vx*damp#
position object ball,object position x(ball)+overlap#,object position y(ball),object position z(ball)
endif
if n=2
myball.vx=-myball.vx*damp#
position object ball,object position x(ball)-overlap#,object position y(ball),object position z(ball)
endif
if n=3
myball.vz=-myball.vz*damp#
position object ball,object position x(ball),object position y(ball),object position z(ball)-overlap#
endif
if n=4
myball.vz=-myball.vz*damp#
position object ball,object position x(ball),object position y(ball),object position z(ball)+overlap#
endif
if n=5
myball.vy=-myball.vy*damp#
position object ball,object position x(ball),object position y(ball)-overlap#,object position z(ball)
endif
if n=6
myball.vy=-myball.vy*damp#
position object ball,object position x(ball),object position y(ball)+overlap#,object position z(ball)
endif
endif
next n
return
move_ball:
dec myball.vy,gravity#
inc myball.vx,sin(anglez#)/mass#
inc myball.vz,sin(-anglex#)/mass#
if myball.vx>2.5 then myball.vx=2.5
if myball.vx<-2.5 then myball.vx=-2.5
if myball.vz>2.5 then myball.vz=2.5
if myball.vz<-2.5 then myball.vz=-2.5
if abs(myball.vx)<0.005 then myball.vx=0
if abs(myball.vz)<0.005 then myball.vz=0
position object ball,object position x(ball)+myball.vx,object position y(ball)+myball.vy,object position z(ball)+myball.vz
rotate_gz(ball,(-17*myball.vx))
rotate_gx(ball,(17*myball.vz))
`set light to follow ball
position light 1,object position x(ball),object position y(ball)+40,object position z(ball)
`update ball reflection
position object ball2,object position x(ball),-object position y(ball)+1,object position z(ball)
rotate_gz(ball2,(17*myball.vx))
rotate_gx(ball2,(-17*myball.vz))
return
control_board:
if leftkey()=1 and anglez#>-25 then dec anglez#,board.omega
if rightkey()=1 and anglez#<25 then inc anglez#,board.omega
if upkey()=1 and anglex#>-25 then dec anglex#,board.omega
if downkey()=1 and anglex#<25 then inc anglex#,board.omega
return
set_ball_properties:
gravity#=0.05
damp#=0.4
mass#=6.0
friction#=0.004
return
set_ground_properties:
board.omega=0.4
return
make_textures:
blue=free_image()
create bitmap 1,10,10
ink rgb(180,180,255),0
box 0,0,10,10
get image blue,0,0,10,10
delete bitmap 1
red=free_image()
create bitmap 1,10,10
ink rgb(255,0,0),0
box 0,0,10,10
get image red,0,0,10,10
delete bitmap 1
green=free_image()
create bitmap 1,10,10
ink rgb(0,255,0),0
box 0,0,10,10
get image green,0,0,10,10
delete bitmap 1
magenta=free_image()
create bitmap 1,10,10
ink rgb(255,0,255),0
box 0,0,10,10
get image magenta,0,0,10,10
delete bitmap 1
return
make_board:
`dummy
cameradummy=free_object()
make object cube cameradummy,1
hide object cameradummy
`ground
ground=free_object()
make object box ground,200,2,200
texture object ground,blue
set object transparency ground,5
set alpha mapping on ground,50
`all other board objects attached as limbs for simplicity with collision
`back
temp=free_object()
make object box temp,200,10,5
make mesh from object 1,temp
delete object temp
add limb ground,1,1
delete mesh 1
offset limb ground,1,0,0,100
texture limb ground,1,red
`front
temp=free_object()
make object box temp,200,10,5
make mesh from object 1,temp
delete object temp
add limb ground,2,1
delete mesh 1
offset limb ground,2,0,0,-100
texture limb ground,2,red
`left
temp=free_object()
make object box temp,5,10,200
make mesh from object 1,temp
delete object temp
add limb ground,3,1
delete mesh 1
offset limb ground,3,-100,0,0
texture limb ground,3,red
`right
temp=free_object()
make object box temp,5,10,200
make mesh from object 1,temp
delete object temp
add limb ground,4,1
delete mesh 1
offset limb ground,4,100,0,0
texture limb ground,4,red
limb=4
for z=1 to 20
for x=1 to 20
read data$
if data$<>"000"
inc limb
temp=free_object()
if data$="0xr"
make object box temp,10,4,10
data$="02r"
else
make object box temp,10,2,10
endif
make mesh from object 1,temp
delete object temp
add limb ground,limb,1
delete mesh 1
offset limb ground,limb,-105+x*10,val(left$(data$,2))*2-1,105-z*10
if mid$(data$,3)="r" then texture limb ground,limb,red
if mid$(data$,3)="g" then texture limb ground,limb,green
if mid$(data$,3)="b" then texture limb ground,limb,blue
if mid$(data$,3)="m" then texture limb ground,limb,magenta
`reflection
temp=free_object()
make object box temp,10,2,10
position object temp,-105+x*10,-val(left$(data$,2))*2-1,105-z*10
if mid$(data$,3)="r" then texture object temp,red
if mid$(data$,3)="g" then texture object temp,green
if mid$(data$,3)="b" then texture object temp,blue
if mid$(data$,3)="m" then texture object temp,magenta
set object transparency temp,1
set alpha mapping on temp,20
endif
next x
next z
return
make_ball:
`make ball
create bitmap 1,256,256
ink -1,0
box 0,0,128,128
box 128,128,256,256
ballimage=free_image()
get image ballimage,0,0,256,256,1
delete bitmap 1
ball=free_object()
make object sphere ball,5,20,20
texture object ball,ballimage
scale object texture ball,2,2
position object ball,0,20,0.1
`ball reflection
ball2=free_object()
make object sphere ball2,5,20,20
texture object ball2,ballimage
scale object texture ball2,2,2
set object transparency ball2,5
set alpha mapping on ball2,20
return
display:
set display mode 1024,768,32
hide mouse
sync on
sync rate 60
autocam off
color backdrop 0
position camera 0,20,-100
make light 1
set light range 1,200
hide light 0
set ambient light 50
return
function free_object()
repeat
inc n
until object exist(n)=0
endfunction n
function free_image()
repeat
inc n
until image exist(n)=0
endfunction n
remstart Rotate_GX
This function rotates the given object around the global (world) x axis by
the given amount.
Param obj The object to rotate
Param amount# The angle to rotate the object by
remend
function rotate_GX(obj as integer,amount# as float)
rem get normal vectors for X, Y, and Z axes of the object
x#=object position x(obj):y#=object position y(obj):z#=object position z(obj)
move object right obj,1
xx#=object position x(obj)-x#:xy#=object position y(obj)-y#:xz#=object position z(obj)-z#
move object left obj,1:move object up obj,1
yx#=object position x(obj)-x#:yy#=object position y(obj)-y#:yz#=object position z(obj)-z#
move object down obj,1:move object obj,1
zx#=object position x(obj)-x#:zy#=object position y(obj)-y#:zz#=object position z(obj)-z#
move object obj,-1
rem rotate the vectors
xx1#=xx#
xy1#=xy#*cos(amount#)-xz#*sin(amount#)
xz1#=xz#*cos(amount#)+xy#*sin(amount#)
zx1#=zx#
zy1#=zy#*cos(amount#)-zz#*sin(amount#)
zz1#=zz#*cos(amount#)+zy#*sin(amount#)
rem calculate angle z
zr#=atanfull(xy1#,xx1#)
rem calculate angle y
xx2#=xx1#*cos(zr#)+xy1#*sin(zr#)
xy2#=xy1#*cos(zr#)-xx1#*sin(zr#)
xz2#=xz1#
zx2#=zx1#*cos(zr#)+zy1#*sin(zr#)
zy2#=zy1#*cos(zr#)-zx1#*sin(zr#)
zz2#=zz1#
yr#=atanfull(xx2#,xz2#)-90
rem calculate angle x
zx3#=zx2#*cos(yr#+90)-zz2#*sin(yr#+90)
zy3#=zy2#
xr#=atanfull(zy3#,zx3#)+180
if xr#+1>xr# and yr#+1>yr# and zr#+1>zr#
rotate object obj,xr#,yr#,zr#
endif
endfunction
remstart Rotate_GY
This function rotates the given object around the global (world) y axis by
the given amount.
Param obj The object to rotate
Param amount# The angle to rotate the object by
remend
function rotate_GY(obj,amount#)
rem get normal vectors for X, Y, and Z axes of the object
x#=object position x(obj):y#=object position y(obj):z#=object position z(obj)
move object right obj,1
xx#=object position x(obj)-x#:xy#=object position y(obj)-y#:xz#=object position z(obj)-z#
move object left obj,1:move object up obj,1
yx#=object position x(obj)-x#:yy#=object position y(obj)-y#:yz#=object position z(obj)-z#
move object down obj,1:move object obj,1
zx#=object position x(obj)-x#:zy#=object position y(obj)-y#:zz#=object position z(obj)-z#
move object obj,-1
rem rotate the vectors
xx1#=xx#*cos(amount#)+xz#*sin(amount#)
xy1#=xy#
xz1#=xz#*cos(amount#)-xx#*sin(amount#)
zx1#=zx#*cos(amount#)+zz#*sin(amount#)
zy1#=zy#
zz1#=zz#*cos(amount#)-zx#*sin(amount#)
rem calculate angle z
zr#=atanfull(xy1#,xx1#)
rem calculate angle y
xx2#=xx1#*cos(zr#)+xy1#*sin(zr#)
xy2#=xy1#*cos(zr#)-xx1#*sin(zr#)
xz2#=xz1#
zx2#=zx1#*cos(zr#)+zy1#*sin(zr#)
zy2#=zy1#*cos(zr#)-zx1#*sin(zr#)
zz2#=zz1#
yr#=atanfull(xx2#,xz2#)-90
rem calculate angle x
zx3#=zx2#*cos(yr#+90)-zz2#*sin(yr#+90)
zy3#=zy2#
xr#=atanfull(zy3#,zx3#)+180
if xr#+1>xr# and yr#+1>yr# and zr#+1>zr#
rotate object obj,xr#,yr#,zr#
endif
endfunction
remstart Rotate_GZ
This function rotates the given object around the global (world) z axis by
the given amount.
Param obj The object to rotate
Param amount# The angle to rotate the object by
remend
function rotate_GZ(obj,amount#)
rem Rotating around the global Z axis is trivial
rem as it is the first rotation anyway in the default ZYX rotation order
rotate object obj,object angle x(obj),object angle y(obj),object angle z(obj)+amount#
endfunction
data "000","11g","12g","13g","14g","15g","16g","17g","18g","19g","000","11g","12g","13g","14g","15g","16g","17g","000","000"
data "000","11g","000","000","000","000","000","000","000","20g","000","10g","000","000","000","000","000","18g","19g","20g"
data "000","11g","000","02g","02g","02g","02g","000","000","21g","000","09g","000","000","000","000","000","000","000","21g"
data "000","11g","000","02g","02g","02g","02g","000","000","22g","000","08g","000","000","000","000","000","000","000","22g"
data "000","11g","000","02g","02g","02g","02g","000","000","23g","000","07g","06g","05g","04g","000","000","000","000","23g"
data "000","11g","000","03g","000","02g","02g","000","000","24g","000","000","000","000","03g","000","000","000","000","24g"
data "000","11g","000","04g","000","02g","02g","000","000","25g","000","000","000","000","02g","000","000","000","000","25g"
data "000","11g","000","05g","000","02g","02g","000","000","000","000","000","000","02r","01g","02r","000","000","000","26g"
data "000","11g","000","06g","000","02r","01g","02r","000","20r","20r","02r","02r","02r","000","02r","000","000","000","27g"
data "000","11g","000","07g","000","02r","000","02r","20r","18g","08g","08g","02g","000","000","02r","000","000","000","28g"
data "000","11g","000","08g","000","02r","000","02r","20r","18g","08g","08g","02g","000","000","02r","000","000","000","29g"
data "000","11g","000","09g","000","02r","000","02r","000","20r","20r","02r","02r","02r","02r","02r","000","000","000","30g"
data "000","11g","000","10g","000","02r","000","02r","000","000","000","000","000","000","000","000","000","000","000","31g"
data "13r","11g","11g","11g","13r","02r","000","02r","000","06r","06r","000","000","000","000","000","000","000","000","000"
data "13r","13r","000","13r","13r","04r","02g","02g","03g","04g","04g","000","000","000","000","000","000","000","000","000"
data "000","000","000","000","000","04r","03r","000","000","04g","04g","000","04b","04b","04b","000","000","000","000","10g"
data "02r","02r","02r","02r","02r","0xr","04r","05r","06r","04g","04g","000","04b","02m","04b","000","10g","10g","10g","10g"
data "000","000","000","000","000","01g","02g","03g","04g","04g","04g","000","04b","04b","04b","000","000","000","000","10g"
data "000","000","02r","02r","02r","02r","000","000","000","000","000","000","000","000","000","000","000","000","000","10g"
data "000","000","000","000","000","000","000","000","000","000","000","000","000","000","000","000","000","000","000","10g"