Collision problem (Blitz3D v1.98)
Archives Forums/Blitz3D Bug Reports/Collision problem (Blitz3D v1.98)
| ||
Graphics3D 800, 600, 0, 2 SetBuffer BackBuffer() ; Setup frametimer (2 frames per second) Global frametimer = CreateTimer(2) ; Setup collision types Const colball = 1 Const colpaddle = 2 ; Create camera and position it camera = CreateCamera() PositionEntity camera, 0, 0, -100 ; Create a ball and give it a collision type ball = CreateSphere() PositionEntity ball, 0, 5, 0 EntityType ball, colball ; Create the paddle and give it a collision type paddle = CreateCube() ScaleMesh paddle, 10, 1, 1 EntityType paddle, colpaddle ; Setup collisions (ball -> paddle) Collisions colball, colpaddle, 2, 0 Collisions colpaddle, colball, 2, 0 ; Do until "ESC" is hit While Not KeyHit(1) ; Wait until timer runs out WaitTimer(frametimer) ; If "Spacebar" is hit, recreate the ball If KeyHit(57) Then ; Get the current position and rotation of the existing ball entity x = EntityX(ball) y = EntityY(ball) rotation = EntityRoll(ball) ; Free the existing ball (which was created before the paddle was created) FreeEntity ball ; Create a new ball entity (to make sure this new ball is created after the paddle was created) ball = CreateSphere() ; position the new ball at the same location and rotation as the first ball PositionEntity ball, x, y, 0 TurnEntity ball, 0, 0, rotation ; Set collision type EntityType ball, colball ; Indicate that the ball has been replaced by a new one ballrecreated = True EndIf ; Move the ball MoveEntity ball, 0, 0.5, 0 ; Process collisions UpdateWorld ; If the ball gets above a certain point, turn it downwards If EntityY(ball) > 8 Then TurnEntity ball, 0, 0, 180 EndIf ; Check if the paddle got hit paddlehit = EntityCollided(ball, colpaddle) ; If the paddle got hit If paddlehit Then ; turn the ball upwards again TurnEntity ball, 0, 0, 180 EndIf ; Render the world RenderWorld ; Debuginfo Text 0, 0, "Ball: " + ball Text 0, 10, "Paddle: " + paddle Text 0, 30, "PaddleHit: " + paddlehit Text 0, 40, "CountCollisions ball: " + CountCollisions(ball) Text 0, 50, "Countcollisions paddle: " + CountCollisions(paddle) If ballrecreated = True Then Text 0, 70, "Ball recreated" ; Flip frontbuffer and backbuffer Flip Wend End This code will show that the order in which entities are created, really matters when it comes to collisions. First, the ball is created. Then the paddle is created (which is stationary). The ball moves up and down slowly (2 frames per second) so you can see the debugdata properly. When the ball hits the paddle, the ball sees that it hit the paddle (EntityCollided(ball, colpaddle) returns the handle of the paddle properly). But only the ball has registered a collision, while the paddle hasn't. Now the ball will move up. If you press spacebar now, the existing ball is freed and replaced by a new ball. So the new ball is created after the paddle was created. When the new ball hits the paddle, both the ball and the paddle register a collision. Exactly the same situation (ball hits paddle), but collisions on both objects are very different. The order in which entities are created shouldn't make any difference in how collisions are registered. You can also create the paddle before the ball (at the start of the program), instead of using the spacebar. Try these: In the first codebox, the ball is created first, then the paddle. You'll see that the paddle won't register any collision when the ball hits the paddle, but the ball will register it perfectly. In the second codebox, the paddle is created first, then the ball. The rest of the program is exactly the same. Now both objects will register 1 collision when the ball hits the paddle. |
| ||
This problem may not be significant in small games, but if anyone uses streaming or progressive loading or anything else, where the environment loads when the player is closeby, then it will become a problem. Let's say you're driving a car on a terrain (terrain loaded first, car loaded after the terrain). Collisions are computed fine as long as the car is on the starting terrain. You can access collision normals on the terrain because the terrain has registered collisions from the car. The car drives along and comes to a place where new terrain data needs to be loaded. As soon as your car comes into contact with that terrain and you access the collision-data on the new terrain, your program will crash ("collision index out of bounds") or you don't get any data at all. So in fact, you need to load every bit of the world first, then your car, in order to process collisions. Or you can, like I'm doing now in my game, reload your car every time some new terrain is loaded/created. In my game (Arkanoid3D), the ball entities are recreated (freed and created again) everytime the paddle is recreated (to make it larger/smaller/equip it with guns). |