Here is the nasty workaround mentioned above. Maybe someone can think of better methods to get around some of the limitations, it all gets a bit messy though.
; colliding with rotating block
; Following rotation of block stops ball as expected
; Going against rotation allows ball to pass through *
; * How do I prevent this and get the block to 'push' the ball?
; (Syntax Error)
; One possible approach. Not very satisfactory. Lots of issues.
; ( must separate blocks from other blocks and so on )
; Credit Shawn Swift for the ball bouncing/rotating code.
; Note: Transfer of block momentum is incorrectly implemented, but thats the
; least of your worries when using this method so hey... :-)
; (D. Woodgate)
; display
Graphics3D 640,480,0,2
HidePointer
SeedRnd MilliSecs()
; entitys
campiv=CreatePivot()
camera=CreateCamera(campiv)
PositionEntity camera,0,50,0
PointEntity camera,campiv
light=CreateLight(1,campiv)
TurnEntity light,60,-60,0
texture=CreateTexture(128,128)
SetBuffer TextureBuffer(texture)
Color 128,128,128
Rect 0,0,128,128
Color 128,0,0
Rect 0,0,64,64 Rect 64,64,64,64
SetBuffer BackBuffer()
ScaleTexture texture,0.25,0.25
Color 255,255,255
plane=CreatePlane()
EntityColor plane,50,100,50
PositionEntity plane,0,-1,0
; collisions
Const cBALL=1 , cBLOCK=2, cWALL=3
Collisions cBALL,cBLOCK,2,2
Collisions cBALL,cWALL,2,2
Dim block(50)
Dim rotspd#(50)
; create arena
Nwall=CreateCube()
EntityColor Nwall,200,0,0
EntityType Nwall,cWALL
FitMesh Nwall,-35,-1,-0.5, 70,2,0.5
PositionEntity nwall,0,0,35
Swall=CopyEntity(Nwall)
PositionEntity Swall,0,0,-35
Ewall=CopyEntity(Nwall)
RotateEntity EWall,0,90,0
PositionEntity Ewall,-35,0,0
Wwall=CopyEntity(Nwall)
RotateEntity Wwall,0,-90,0
PositionEntity Wwall,35,0,0
; The blocks
accel#=1
For x=-24 To 24 Step 15
For z=-24 To 24 Step 15
numblock=numblock+1
block(numblock)=CreateCube()
PositionEntity block(numblock),x,0,z
EntityColor block(numblock),200,100,100
ScaleMesh block(numblock),0.4,1,3.5
EntityType block(numblock),cBLOCK
rotspd(numblock)=Rnd(2,15)
If Rand(1,2)=1 Then rotspd(numblock)=-rotspd(numblock)
Next
Next
; the ball
ballrad# = 1.5
maxballspd# = 3
Drag#=0.98
ball=CreatePivot() ; Collision proxy
PositionEntity ball,0,0,0
EntityRadius ball,ballrad
EntityType ball,cBALL
orb=CreateSphere(12) ; The visible ball
ScaleEntity orb,ballrad,ballrad,ballrad
EntityTexture orb,texture
; init
MoveMouse 320,240 : FlushMouse
vx#=0 : vz#=0
; MAINLOOP
Repeat
; mouse control
MXSpd# = Float(MouseXSpeed())/255
MySpd# = Float(MouseYSpeed())/255
MoveMouse 320,240
; parent ball collision proxy to block collision candidate
; rotate all blocks and calculate ball translation due to block rotation
Gosub updateblocks
; Reset block state
UpdateWorld
; unparent ball from block
EntityParent ball,0
; update ball motion with drag and user input. Limit ball speed
Gosub updateball
; translate ball taking into account relative movement
; get ball position before applying collisions.
Gosub moveball
; Second update world to capture ball collisions
UpdateWorld
Gosub checkcollisions
; rotate ball according to motion vector
Gosub rotateball
Gosub movecamera
RenderWorld
Text 320,450,"MOVE BALL WITH MOUSE",1
Flip
Until KeyHit(1)
End
.checkcollisions
If CountCollisions(ball)>0 Then
; Swifty bounce code:
; Get the normal of the surface which the entity collided with.
Nx# = CollisionNX(ball, 1)
Nz# = CollisionNZ(ball, 1)
; Compute the dot product of the entity's motion vector and the normal of the surface collided with.
; Adding Rx and Rz is my lame attempt to factor in block rotational momentum
VdotN# = (Vx# + Rx#) * Nx# + (Vz# + Rz# ) * Nz#
; Calculate the normal force.
NFx# = -2.0 * Nx# * VdotN#
NFz# = -2.0 * Nz# * VdotN#
; Add the normal force to the direction vector.
Vx# = Vx# + NFx#
Vz# = Vz# + NFz#
EndIf
Return
.updateball
; apply drag
Vx# = Vx# * Drag# : Vz# = Vz# * Drag#
; transform mouse input so we move the ball with respect to the camera pivot
TFormVector MxSpd,0,-Myspd,campiv,0
Vx# = Vx# + TFormedX()
Vz# = Vz# + TFormedZ()
; limit ball speed, things break down if its going too fast
ballspd# = Sqr(Vx# * Vx# + Vz# * Vz#)
If ballspd# > maxballspd# Then
Vx# = Vx# / ballspd# * maxballspd#
Vz# = Vz# / ballspd# * maxballspd#
; keep the ball rolling if it stops
ElseIf ballspd<0.01 Then
vx#=Rnd(-1,1) vz#=Rnd(-1,1)
EndIf
Return
.updateblocks
; get global ball position
Gx#=EntityX(ball,1)
Gz#=EntityZ(ball,1)
accel# = 1+(KeyDown(52)-KeyDown(51))*0.01
; parent ball to nearest rotating block. This means of course that blocks
; cannot be too close together or too close to any other colliding object.
For i=1 To numblock
If EntityDistance(ball,block(i))<6.5 Then
EntityParent ball,block(i)
EntityColor block(i),200,200,100
Else
EntityColor block(i),200,100,100
EndIf
rotspd(i) = rotspd(i) * accel#
TurnEntity block(i),0,rotspd(i),0
Next
; the distance the ball has moved due to block rotation
; if there is no collision candidate then this will be zero
Rx# = Gx# - EntityX(ball,1)
Rz# = Gz# - EntityZ(ball,1)
Return
.moveball
; correct for relative movement
TranslateEntity ball,Rx,0,Rz,True
; get ball position before movement
OldX# = EntityX(ball,1)
OldZ# = EntityZ(ball,1)
; move ball globally
TranslateEntity ball,Vx#,0,Vz#,True
Return
.rotateball
; get distance ball has moved
NewX# = EntityX(ball,1)
NewZ# = EntityZ(ball,1)
Mx# = (NewX# - OldX#)
Mz# = (NewZ# - OldZ#)
; Swifty rotation code:
; Rotate the entity the right amount for it's radius and the distance it has moved along the X and Z axis.
; This is kinda a hack and only designed for rolling on planes but you won't notice the difference.
XAngleAdjust# = (Mx# / ballrad) * (180.0/Pi)
ZAngleAdjust# = (Mz# / ballrad) * (180.0/Pi)
PositionEntity orb,EntityX(ball,1),EntityY(ball,1),EntityZ(ball,1),True
TurnEntity orb,ZAngleAdjust#,0,-XAngleAdjust#,True
Return
.movecamera
; move the camera
TurnEntity campiv,0,KeyDown(203)-KeyDown(205),0
TurnEntity camera,KeyDown(200)-KeyDown(208),0,0
MoveEntity camera,KeyDown(32)-KeyDown(46),KeyDown(31)-KeyDown(45),KeyDown(30)-KeyDown(44)
Return
[Edit] Changed the bounce routine a bit. Seems to give better results as does using sliding collisions, though I am not quite sure why (I suspect it has to do with the fact I am doing two translations ) I am now wondering if more flexibility might be gained by using multiple collision proxies, though I am not sure yet how that would pan out in practice.
|