Can someone explain Collision?

Blitz3D Forums/Blitz3D Beginners Area/Can someone explain Collision?

Sorry but my collision code isn't working, and because I haven't done anything using true UpdateWorld collision yet I was wondering if someone could explain it to me.

Here is what I think I know already. Please correct me if I am wrong.

1) Entities have collision types stored on them to indicate what classification of collision they fall under.

2) Collision responses are set up with the Collisions command. In it I specify my collision type variables for the two objects I want to act upon and what method/response to use.

3) Collision properties are assigned via EntityRadius and EntityBox commands.

4) The Update world enacts on all of my choices and will move objects accordingly.

5) If I use Position commands rather than transpose/move commands for controlling entities I will need to run through all of my objects positional variables and adjust them after Update world like:
...
Enemy\X# = EntityX#(Enemy\ObjectNum)
...

But my code doesn't work. So if I am missing a key step or my understanding is faulty please tell me what I need to do.

Here is my code:
;Include the vector mathematics library
Include "vector.bb"
;Include the general maths library
Include "math.bb"
;Include the blitz basic demo start code
Include "start.bb"


;Setup all non-type global variables
Global CameraHandle = 0
Global ScreenWidth = 640
Global ScreenHeight = 480
;Friction will be used to slow the ship.  1 is no friction, 0 is absolute friction
Global Friction# = .5
;Default Sync
Global SyncRate# = 100

;Collision Variables
Global TYPE_BOX = 1
Global TYPE_PLAYER = 2
Global TYPE_BULLET = 3
Collisions TYPE_PLAYER, TYPE_BOX, 3, 1

;--------------------------------
;---------MAIN PROGRAM-----------
;--------------------------------
GameEnds = 0
User.Player = SetupGame()
 Repeat 
  StartSync# = MilliSecs()
  ;===========
  
  ControlPlayer(User)
  ;Do a quick mouse reset if they aren't pressing the '-' key to debug-stop this
  If Not KeyDown(74) Then MoveMouse ScreenWidth/2, ScreenHeight/2
  UpdateCamera()
  ;===========

  ;Use a counter as AI modifications aren't necessary every loop  
  AICounter = AICounter+1
  If AICounter > 5 
   AICounter = 0
   RunAllAI()
  EndIf
  ;The AI is modified every 5 loops.  Enemies are controlled every loop, however. 
  RunAllEnemies()

  ;===========
  
  RunAllMissles(User)
  RunAllExplosions()

  ;===========

  GameEnds = Triggers()

  ;===========
  UpdateWorld
  UpdateVariables(User)
  RenderWorld 
  Flip
  ;===========
  SetSync(StartSync#)
 Until GameEnds Or KeyHit(1)
End 
;--------------------------------
;================================
;--------------------------------

;TYPES
;Player Type
Type Player
 Field X# ;x position
 Field Y# ;y position
 Field Z# ;z position
 Field Move.Vector ;vector controlling movement
 Field Rotation.Vector ;vector controlling current rotation
 Field Thrust.Vector ;vector controlling the thrusting
 Field Manuever# ;regulates the factor by which the object can pivot
 Field Speed# ;regulates speed by using this as a maximum value
 Field Health    ;the players health
 Field ObjectNum ;the object handle
 Field CameraNum ;the camera's handle
 Field CameraPivot ;the entity number of the pivot controlling camera movement
 Field BrushNum  ;the brush number holding texture and data
 Field AttackReflex ;controls time since last attacking
 Field StunReflex ;controls time since recovering from an attack
 Field Lasers.Missle 
End Type

;Enemy Type
Type Enemy
 Field X# ;x position
 Field Y# ;y position
 Field Z# ;z position
 Field Move.Vector ;vector controlling movement
 Field Rotation.Vector ;vector controlling current rotation
 Field Impulse.Vector ;vector controlling AI impulse behavior
 Field Speed# ;regulates speed by using this as a maximum value
 Field Manuever# ;regulates the factor by which the object can pivot
 Field Health    ;the enemy's health
 Field ObjectNum ;the object number
 Field BrushNum  ;the brush number holding texture and data
 Field AttackReflex ;controls time since last attacking
 Field StunReflex ;controls time since recovering from an attack
 Field Species ;used to regulate what type of AI actions to take
 ; 0 = Red (swarming) :: 1 = Blue (sneaker) :: 2 = Green (missler)
 Field Projectile.Missle ;stores the type of projectile the object uses
 Field AI ;This value is used to determine what action the enemy performed
End Type 

;Missle Type
;A type used to represent projectile fire
Type Missle
 Field X# ;x position
 Field Y# ;y position
 Field Z# ;z position 
 Field Move.Vector ;vector controlling movement
 Field Rotation.Vector ;vector controlling rotation (arcing projectile)
 Field Speed# ;controls the speed of the missle
 Field Maneuverability# ;controls the pivoting capabilities of arcing projectiles
 Field ObjectNum ;stores the object number of the projectile
 Field BrushNum ;stores the brush number (or texture number) of the projectile
 Field Detonate.Explosion ;stores the explosion type of the projectile on impact
 Field Damage ;controls the power of the missle
 Field Effect ;controls the effect of the missle 
 Field Reflex ;controls the time since firing the missle
 Field Species ;used to regulate what type of movement the missle follows
 Field Initialized ;Flag storing whether the missle has been initialized or not
End Type 

;Explosion Type
Type Explosion
 Field X# ;x position
 Field Y# ;y position
 Field Z# ;z position 
 Field Damage ;controls the damage of the explosion
 Field Size# ;controls the maximum size of the explosion,speed and duration
 Field ObjectNum ;stores the object number of the explosion
 Field BrushNum ;stores the brush number of the explosion
 Field SoundHandle ;stores the sound handle of the explosion
 Field Effect ;controls the effect of the explosion
End Type
  
;Functions
Function ControlPlayer(User.Player)
 ;This function acts upon the user input and applies the appropriate
 ;action
 ;INPUT
 Firing = 0
 Thrusting = 0
 Strafe = 0
 If KeyDown(57) Then Firing = 1
 If MouseDown(1) Then Thrusting = 1
 If MouseDown(2) Then Strafe = 1
 ;Position the camera pivot
 PositionEntity User\CameraPivot, User\X#, User\Y#, User\Z#
 ;Fire lasers
 If Firing = 1 And MilliSecs()-User\AttackReflex > 100
  User\AttackReflex = MilliSecs()
  ;Set up the basic missle.  It will be run in RunAllMissles()
  ;Add more code if the missle has explosions, arcing, ect.
  Laser.Missle = New Missle
  Laser\X# = User\X#
  Laser\Y# = User\Y#
  Laser\Z# = User\Z#
  Laser\Speed# = User\Lasers\Speed#
  Laser\ObjectNum = CopyEntity(User\Lasers\ObjectNum)
  PositionEntity Laser\ObjectNum, Laser\X#, Laser\Y#, Laser\Z#
  Laser\Move = New Vector
  Laser\Rotation = New Vector  
  Laser\Move = CopyVect(Laser\Move, User\Rotation)
  Laser\Move = ScaleVect(Laser\Move, Sync(Laser\Speed#))
  Laser\Initialized = 1
  EntityType Laser\ObjectNum, TYPE_BULLET
  EntityRadius Laser\ObjectNum, .5
 EndIf
 ;Apply Rotation
 If Not Strafe
  M# = User\Manuever
  ;Movement style using mouse speed rather than position 
  YAng# = WrapAngle(EntityYaw(User\ObjectNum)-M#*MouseXSpeed())
  XAng# = WrapAngle(EntityPitch(User\ObjectNum)+M#*MouseYSpeed())
  If XAng# > 70 And XAng# < 180 Then XAng# = 70
  If XAng# < 290 And XAng# > 180 Then XAng# = 290
  RotateEntity User\ObjectNum, XAng#, YAng#, 0
  ;-------
  ;If KeyHit(2) Then DebugLog "XAng# = "+XAng#+"   EntityPitch = "+EntityPitch(User\ObjectNum)
  ;-------
  ;Set the rotation vector to the current orientation
  User\Rotation = AngToVect(WrapAngle(YAng#-90), XAng#, User\Rotation)
 EndIf 
 ;Position and rotate the camera 
 ;First calculate Yaw Smoothness as this is on a full set of angles, rather than 1/2 circle
 ;of angles that is used for pitch
 CameraYaw# = WrapAngle(EntityYaw(User\CameraPivot))
 ObjectYaw# = WrapAngle(EntityYaw(User\ObjectNum))
 NewYaw# = SmoothAngle(ObjectYaw#, CameraYaw#, Sync(10))
 CameraPitch# = EntityPitch(User\CameraPivot)+90
 ObjectPitch# = EntityPitch(User\ObjectNum)+90
 NewPitch# = SmoothAngle(ObjectPitch#, CameraPitch#, Sync(10))-90
 RotateEntity User\CameraPivot, NewPitch#, NewYaw#, 0
 ;Add to Thrust Vectors
 If Thrusting 
  If Strafe
   ;If the player has strafing engines on the thrust vectors will lie perpendicular to the rotation 
   
  Else
   ;For normal movement the thrust vector is simply a magnitude of the rotation vector
   User\Thrust = CopyVect(User\Thrust, User\Rotation)
   User\Thrust = ScaleVect(User\Thrust, (Sync(User\Speed#)-VectLength(User\Move))*.025)   
  EndIf
 EndIf
 
 ;Calculate and reposition movement
 User\Move = ScaleVect(User\Move, 1.0-Sync(Friction#))
 ;Stop ship if it is moving too slowly
 If VectLength(User\Move) < 3*Sync(Friction#) Then User\Move = ScaleVect(User\Move, 0) 
 User\Move = AddVect(User\Move, User\Thrust, User\Move)
 User\Thrust\X# = 0
 User\Thrust\Y# = 0
 User\Thrust\Z# = 0
 User\X# = User\X# + User\Move\X#
 User\Y# = User\Y# + User\Move\Y#
 User\Z# = User\Z# + User\Move\Z#
 PositionEntity User\ObjectNum, User\X#, User\Y#, User\Z# 
 ;Update Camera 
 PointEntity CameraHandle, User\ObjectNum
End Function

Function UpdateCamera()
 ;This function updates the camera
 
 
End Function

Function EnemyAI(AI.Enemy)
 ;This function will be run to determine what the enemies will do
 ;It will send the result to the ControlEnemy() function

End Function

Function ControlEnemy(Num.Enemy)
 ;This will control physics for the enemy based on their AI reaction

End Function

Function ControlExplosion(Num.Explosion)
 ;This will run a specified explosion

End Function

Function RunAllAI()
 ;This will run all of the specified AI's

End Function

Function RunAllEnemies()
 ;This will run all of the enemies

End Function

Function RunAllMissles(User.Player)
 ;This will run every missle
  
 For Missles.Missle = Each Missle
  If Missles\ObjectNum > 0 And Missles\Initialized = 1
   If EntityDistance(Missles\ObjectNum, User\ObjectNum) < 500
    ;If the missle is still active then run it
    X# = Missles\X# + Missles\Move\X#
    Y# = Missles\Y# + Missles\Move\Y#
    Z# = Missles\Z# + Missles\Move\Z#
    PositionEntity Missles\ObjectNum, X#, Y#, Z#
    Missles\X# = X#
    Missles\Y# = Y#
    Missles\Z# = Z#
   If EntityCollided(Missles\ObjectNum, TYPE_BOX)
    DestructEntity = CollisionEntity(Missles\ObjectNum, 1)
    FreeEntity Missles\ObjectNum    
    Delete Missles
    FreeEntity DestructEntity
    DebugLog "A cube has been destroyed!"
   EndIf 
   Else
    FreeEntity Missles\ObjectNum
    Delete Missles
   EndIf
  EndIf
 Next
End Function

Function RunAllExplosions()
 ;This will run every explosion  

End Function

Function Triggers()
 ;This function basically checks to see whether the player has reached the goal
 ;and to see whether the player has died.
 ;It may serve as a simple template for other triggers in the full version

End Function

Function SetupGame.Player()
 ;This function sets up the game it is used as a more primitive function which
 ;will later be used for more advanced world loading commands
 ;Set up the player object
 SeedRnd(MilliSecs())
 User.Player = New Player
 User\Move = New Vector
 User\Thrust = New Vector
 User\Rotation = New Vector
 User\Health = 6
 User\ObjectNum = LoadMesh("spaceship.x")
 User\BrushNum = LoadBrush("spaceship.bmp")
 User\CameraPivot = CreatePivot()
 EntityType User\ObjectNum, TYPE_PLAYER
 EntityRadius User\ObjectNum, 2.0
 PaintEntity User\ObjectNum, User\BrushNum
 User\AttackReflex = MilliSecs()
 User\StunReflex = MilliSecs()
 User\Speed# = 60.0
 User\Manuever# = .5
 User\Lasers = New Missle
 User\Lasers\ObjectNum = LoadSprite("big_spark.bmp")
 HideEntity User\Lasers\ObjectNum
 User\Lasers\Speed# = 100.0
 ;Setup Camera stuff
 CameraHandle = CreateCamera(User\CameraPivot)
 PositionEntity CameraHandle, 0, 0, -30
 PointEntity CameraHandle, User\ObjectNum
 ;Set up some cubes for spacial orientation
 For Counter = 1 To 100
  Num = CreateCube()
  X# = Rnd(-150, 150)
  Y# = Rnd(-150, 150)
  Z# = Rnd(-150, 150)
  PositionEntity Num, X#, Y#, Z#
  EntityBox Num, X#, Y#, Z#, 5.0, 5.0, 5.0
  EntityType Num, TYPE_BOX
 Next 
 Return User
End Function

Function UpdateVariables(User.Player)
 ;This will refresh all the variables for positions after collisions
 ;Refresh the player
 User\X# = EntityX(User\ObjectNum)
 User\Y# = EntityY(User\ObjectNum)
 User\Z# = EntityZ(User\ObjectNum)
 ;Refresh the missles
 For Missle.Missle = Each Missle
  Missle\X# = EntityX(Missle\ObjectNum) 
  Missle\Y# = EntityY(Missle\ObjectNum)
  Missle\Z# = EntityZ(Missle\ObjectNum)
 Next 
End Function

;////////Sync Functions/////////

Function Sync#(Value#)
 ;This function will sync a value based on the syncrate
 Return Value#/SyncRate#
End Function

Function SetSync(StartSync)
 ;This will set up the SyncRate values and smooth them with the last sync value
 ;to prevent jerkiness
 If MilliSecs()-StartSync > 1
  SyncRate# = (SyncRate#*.5)+((1000.0/(MilliSecs()-StartSync))*.5)
 Else
  SyncRate# = 1000.0
 EndIf
End Function


But my code doesn't work.
Yeah, but WHAT doesn't work? player to box, bullet to player, bullet to box?

1-4 are correct. What you are talking about on statement 5, I have no idea.

By the way, use a [codebox]

Nothing works. The player simply glides through everything.

What I meant by number 5 is that I use variables to track my objects positions and use Position Entity commands. This means that if the Update World command would move the entity as a result of a collision I would also need to manually readjust the variables aswell.

Entitybox coords are local to the object. ie, -1,-1,-1,2,2,2 would form a 2x2x2 box around an object centred on its origin. So your boxes for your cubes are way off.

So collision boxes will conform to your entities translation and rotation, but they are not effected by entity scale. So if you scale your entity up you will need to make the box bigger. Oh, and they do not work very well with sprites and last time I tried it they were not too hot interfacing with proper elipsoids either, but as you have only set a spherical radius for the other collision type that should be ok.

The docs do not explain any of this very well. (if at all).

Oh and just FYI only elipsiod to elipsiod collisions work when both entities are moving - last time I tried it anyway. (If this has changed it has not been documented either). In short you can never be sure of anything so the best thing to do is suck it and see.

As to 5, Yes, though you might consider moving using translateentity and referencing an entities position using EntityX() etc. Up to you though, whichever you feel is easier.

You have to think about Blitz collisions as the moving object is the ellipsoid ... only non-moving entities can successfully use Box or Poly collision. So if you set EntityBox for an object ... it is only for other objects to collide with it ... not for it to collide with other objects. You can get a lot out of the collisions when you think about it like this.

Okay I understand that whole -1, -1, -1, 1, 1, 1 thing now. You see, in the help document it lists the things as Positions and Dimensions not coordinates for the rectangular solid.

I wasn't intending on doing any collisions with moving polygons or boxes but that is good to know. I guess I might have to buy NGC if I want to do anything more complicated that this.

So your saying what I need to do is fix my box coordinates? So assuming I haven't made any goofy mistakes with my code that should fix it?

As for the translate entity as opposed to position entity, this is only a prototype so when I actually do my game I will probably use your method, however, as for now I am more interested in finishing this as a gameplay testing tool than as an actual proffessionally coded game.

I feel like such a noob now after navigating here from DBPro... Ah well, it was definitely worth it.


So your saying what I need to do is fix my box coordinates? So assuming I haven't made any goofy mistakes with my code that should fix it?



Should do, although it could be I have missed something else. I have not done any collision stuff for a while.


Okay I understand that whole -1, -1, -1, 1, 1, 1 thing now. You see, in the help document it lists the things as Positions and Dimensions not coordinates for the rectangular solid.



Just remember the last three parameters of the entitybox command define the extent of the box on each axis, not the end coordinates, so -1,-1,-1,1,1,1 is not what you want here, it is -1,-1,-1,2,2,2.

BTW you do not actually need to define a box at all for those cubes. Why? I think blitz defines a default box of -1,-1,-1,2,2,2 and a default radius of 2 for each entity. It is probably good practice to define them anyway though as that behaviour may change.

Okay, I've switched to using radius's as I've imported a new enemy model I made.

However, now I am having another problem. It doesn't seem to matter what size I set the radius with it always acts the same size.

Here is the code:

 For Counter = 1 To 20
  Num = LoadAnimMesh("MediaS/Glagar.x")
  TextureNum = LoadBrush("MediaS/Glagar.bmp")
  PaintEntity Num, TextureNum
  ScaleEntity Num, 5.0, 5.0, 5.0
  X# = Rnd(-150, 150)
  Y# = Rnd(-150, 150)
  Z# = Rnd(-150, 150)
  PositionEntity Num, X#, Y#, Z#
  EntityRadius Num, 5.0
  EntityType Num, TYPE_BOX
 Next 


I know it is slightly erroneous of me to be using the TYPE_BOX even though it isn't a box and I'm using spherical collision, but that isn't the problem.

While I am at it (and to prevent creating a new thread):

I am using Milkshape3D to make the object and when I exported it the animation instead of stretching the object where the faces are the faces simply pull apart. It doesn't look like this in Milkshape which means I assume either I exported it incorrectly or the loading of animation files works differently than expected. Any ideas.

Thanks for all your help guys.

Can't tell by the code you've posted, but (just in case you're confused) ScaleEntity 5.0 and EntityRadius 5.0 are not the same thing.

For instance, if your mesh is originally 2 units high, scaling it 5 times will make it 10 units high, which would be 5 units higher than the collision sphere.

Aside from that, your code looks OK. It must be how you are using it???