Collision problem (Blitz3D v1.98)

Archives Forums/Blitz3D Bug Reports/Collision problem (Blitz3D v1.98)

PowerPC603(Posted 2009) [#1]
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

	; 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

	; Move the ball
	MoveEntity ball, 0, 0.5, 0

	; Process collisions

	; If the ball gets above a certain point, turn it downwards
	If EntityY(ball) > 8 Then
		TurnEntity ball, 0, 0, 180

	; 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

	; Render the world

	; 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


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.

PowerPC603(Posted 2009) [#2]
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).