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.
[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.
; 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.