problems with collisions in pong - aliensoldier - 01-24-2024
I'm trying to create the pong game and I'm having problems when the ball collides with the top and bottom of the moving player, the ball doesn't bounce, it just goes into the player's graph.
This happens when the player is moving, standing still it does not happen, the problem is in the ball.collision_player method of the ball.
I show all the code I have for now:
Code: 'pong
include "player.n7"
include "player-cpu.n7"
include "ball.n7"
set window "example pong",640,480,false
set redraw off
'objeto-----------------------------------
player = Player()
player_cpu = Player_Cpu()
ball = Ball()
while not keydown(KEY_ESCAPE,true)
set color 0,0,0
cls
'objetos-----------------------------
player.update()
player.Draw()
player_cpu.update()
player_cpu.Draw()
ball.update()
ball.Draw()
'lineas para el fondo------------------
'draw rect 320,32,2,60,true
'draw rect 320,120,2,60,true
'draw rect 320,210,2,60,true
'draw rect 320,300,2,60,true
'draw rect 320,390,2,60,true
'draw line 320,32,320,460
'draw line 330,32,330,460
redraw
fwait 60
wend
Code: 'player
visible player = []
function Player()
player.Width = 20
player.Height = 100
player.x = 32 - player.Width/2
player.y = 240 - player.Height/2
player.speed = 5
player.live = true
player.update = function()
if this.live = true
this.move()
endif
endfunc
player.Draw = function()
if this.live = true
set color 255,0,205
draw rect this.x,this.y,this.Width,this.Height,true
endif
endfunc
player.move = function()
if keydown(KEY_UP,false) and this.y > 16
this.y = this.y - this.speed
elseif keydown(KEY_DOWN,false) and this.y < 370
this.y = this.y + this.speed
endif
endfunc
return player
endfunc
function get_player()
return player
endfunc
Code: 'player-cpu
include "ball.n7"
visible ball = get_ball()
visible player_cpu = []
function Player_Cpu()
player_cpu.Width = 20
player_cpu.Height = 100
player_cpu.x = 608 - player_cpu.Width/2
player_cpu.y = 240 - player_cpu.Height/2
player_cpu.speed = 5
player_cpu.live = true
player_cpu.update = function()
endfunc
player_cpu.Draw = function()
if this.live
set color 255,204,0
draw rect this.x,this.y,this.Width,this.Height,true
endif
endfunc
return player_cpu
endfunc
function get_player_cpu()
return player_cpu
endfunc
Code: 'ball
include "player.n7"
include "miscellaneous.n7"
include "player-cpu.n7"
visible player = get_player()
visible player_cpu = get_player_cpu()
visible ball = []
function Ball()
ball.Width = 16
ball.Height = 16
ball.x = 320 - ball.Width / 2
ball.y = 240 - ball.Height / 2
ball.speedX = 2
ball.speedY = 2
ball.live = true
ball.update = function()
if this.live = true
this.move()
this.bounce()
this.collision_player()
endif
endfunc
ball.Draw = function()
if this.live = true
set color 200,200,200
draw rect this.x,this.y,this.Width,this.Height,true
'draw ellipse this.x,this.y,9,9,true
endif
endfunc
ball.move = function()
this.x = this.x + this.speedX
this.y = this.y + this.speedY
endfunc
ball.bounce = function()
if this.x <= 0 or this.x >= 640
this.speedX = this.speedX * -1
endif
if this.y <= 0 or this.y >= 480
this.speedY = this.speedY * -1
endif
endfunc
ball.collision_player = function()
'colision con la x
if collision_rect(this.x+this.speedX,this.y,this.Width,this.Height,player.x,player.y,player.Width,player.Height)
this.speedX = this.speedX * -1
endif
'colision con la y
if collision_rect(this.x,this.y+this.speedY,this.Width,this.Height,player.x,player.y,player.Width,player.Height)
this.speedY = this.speedY * -1
endif
endfunc
return ball
endfunc
function get_ball()
return ball
endfunc
Code: 'Miscellaneous
'variables y funciones para manejar los puntos
visible score_player = 0
visible score_player_cpu = 0
function get_score_player()
return score_player
endfunc
function get_score_player_cpu()
return score_player_cpu
endfunc
'funcion de colision--------------------------------
function collision_rect(x1,y1,w1,h1,x2,y2,w2,h2)
return x1 + w1 > x2 and x1 < x2 + w2 and
y1 + h1 > y2 and y1 < y2 + h2
endfunc
RE: problems with collisions in pong - Marcus - 01-24-2024
I promise to get back to you when I've looked at your code (and the code you posted in another thread)! I'll try and get the time tomorrow, been so busy lately
RE: problems with collisions in pong - Marcus - 01-25-2024
These things can become quite tricky, and I'm not sure if my solution works well in all cases.
If the ball and the paddle overlap, I decide wether the ball should bounce vertically or horizontally by looking at along which axis they overlap the least. If they overlap the least along the x-axis, it's a horizontal bounce, else a vertical.
ball.n7
Code: ...
ball.collision_player = function()
'colision con la x
'if collision_rect(this.x+this.speedX,this.y,this.Width,this.Height,player.x,player.y,player.Width,player.Height)
' this.speedX = this.speedX * -1
'endif
'colision con la y
'if collision_rect(this.x,this.y+this.speedY,this.Width,this.Height,player.x,player.y,player.Width,player.Height)
' this.speedY = this.speedY * -1
'endif
' Marcus.
' Check if they overlap.
if collision_rect(this.x,this.y,this.Width,this.Height,player.x,player.y,player.Width,player.Height)
' Calculate delta x and delta y, between the center of the ball and the center of the
' paddle. Divide the delta x value width the width of the paddle and delta y with the
' height of the paddle to normalize them (make comparison valid).
dx = (this.x + this.Width/2 - (player.x + player.Width/2))/player.Width
dy = (this.y + this.Height/2 - (player.y + player.Height/2))/player.Height
' If dx is higher, it means that there's less overlapping along the x-axis. In that
' case bounce left or right.
if |dx| >= |dy|
' dx < 0, ball should bounce to the left, and we also move the ball to the left so
' that there's no longer any collision.
if dx < 0
this.speedX = -|this.speedX|
this.x = player.x - this.Width
' dx > 0, ball should bounce to the right, and move the ball to the right of the
' paddle.
else
this.speedX = |this.speedX|
this.x = player.x + player.Width
endif
' dy is higher, same principle as for dx :)
else
if dy < 0
this.speedY = -|this.speedY|
this.y = player.y - this.Height
else
this.speedY = |this.speedY|
this.y = player.y + player.Height
endif
endif
endif
endfunc
...
Hope this helps! There are probably much better ways of doing it.
Edit: By the way, the code looks nice! I see now that you're already using "getters" and "setters" to share variables between files. In my opinion that makes the code way more readable than it would be if you could make variables visible across files - but that's just my opinion
RE: problems with collisions in pong - aliensoldier - 01-25-2024
Thank you very much, it works very well.
I have found a problem in naalaa that may be a bug or maybe it works like this.
For example, I am calling the ball from player cpu to access the "y" of the ball and make the player cpu move following the ball, but if I call the player cpu from ball to make the collision with the cpu I get fails.
If I access the data of the ball from the player cpu I cannot access the data of the player cpu from the ball. I don't know if it is a naalaa bug or it works this way, I have had to make some changes so that everything works from the ball but the code is growing a lot.
RE: problems with collisions in pong - Marcus - 01-25-2024
(01-25-2024, 08:24 PM)aliensoldier Wrote: Thank you very much, it works very well.
I have found a problem in naalaa that may be a bug or maybe it works like this.
For example, I am calling the ball from player cpu to access the "y" of the ball and make the player cpu move following the ball, but if I call the player cpu from ball to make the collision with the cpu I get fails.
If I access the data of the ball from the player cpu I cannot access the data of the player cpu from the ball. I don't know if it is a naalaa bug or it works this way, I have had to make some changes so that everything works from the ball but the code is growing a lot.
That sounds strange. Could you write a simple example that shows the bug or just add something to your game that makes the bug appear?
RE: problems with collisions in pong - aliensoldier - 01-25-2024
I have updated the code of the ball and the player cpu, in the ball we have get_player_cpu(), and in the cpu we have get_ball(). With this I have recreated the error that I get with a more complete code
RE: problems with collisions in pong - Marcus - 01-25-2024
(01-25-2024, 08:59 PM)aliensoldier Wrote: I have updated the code of the ball and the player cpu, in the ball we have get_player_cpu(), and in the cpu we have get_ball(). With this I have recreated the error that I get with a more complete code
I have to make it short, because I gotta go to bed
player.n7, ball.n7 and player-cpu.n7 is not where you should implement get_player, get_ball and get_player_cpu. Nor should you in these file store any objects that are used in the game. For example, player.n7 should only look like this:
Code: 'player
function Player()
player = []
player.Width = 20
player.Height = 100
player.x = 32 - player.Width/2
player.y = 240 - player.Height/2
player.speed = 5
player.live = true
player.update = function()
if this.live = true
this.move()
endif
endfunc
player.Draw = function()
if this.live = true
set color 255,0,205
draw rect this.x,this.y,this.Width,this.Height,true
endif
endfunc
player.move = function()
if keydown(KEY_UP,false) and this.y > 16
this.y = this.y - this.speed
elseif keydown(KEY_DOWN,false) and this.y < 370
this.y = this.y + this.speed
endif
endfunc
return player
endfunc
ball.n7 should look like this:
Code: 'ball
include "player.n7"
include "miscellaneous.n7"
' Marcus, use the getter when needed instead. ball.n7 should just be the implementation for a ball.
'visible player = get_player()
function Ball()
ball = []
ball.Width = 16
ball.Height = 16
ball.x = 320 - ball.Width / 2
ball.y = 240 - ball.Height / 2
ball.speedX = 2
ball.speedY = 2
ball.live = true
ball.update = function()
if this.live = true
this.move()
this.bounce()
this.collision_player()
endif
endfunc
ball.Draw = function()
if this.live = true
set color 200,200,200
draw rect this.x,this.y,this.Width,this.Height,true
'draw ellipse this.x,this.y,9,9,true
endif
endfunc
ball.move = function()
this.x = this.x + this.speedX
this.y = this.y + this.speedY
endfunc
ball.bounce = function()
if this.x <= 0 or this.x >= 640
this.speedX = this.speedX * -1
endif
if this.y <= 0 or this.y >= 480
this.speedY = this.speedY * -1
endif
endfunc
ball.collision_player = function()
'colision con la x
'if collision_rect(this.x+this.speedX,this.y,this.Width,this.Height,player.x,player.y,player.Width,player.Height)
' this.speedX = this.speedX * -1
'endif
'colision con la y
'if collision_rect(this.x,this.y+this.speedY,this.Width,this.Height,player.x,player.y,player.Width,player.Height)
' this.speedY = this.speedY * -1
'endif
' Marcus.
player = get_player()
' Check if they overlap.
if collision_rect(this.x,this.y,this.Width,this.Height,player.x,player.y,player.Width,player.Height)
' Calculate delta x and delta y, between the center of the ball and the center of the
' paddle. Divide the delta x value width the width of the paddle and delta y with the
' height of the paddle to normalize them (make comparison valid).
dx = (this.x + this.Width/2 - (player.x + player.Width/2))/player.Width
dy = (this.y + this.Height/2 - (player.y + player.Height/2))/player.Height
' If dx is higher, it means that there's less overlapping along the x-axis. In that
' case bounce left or right.
if |dx| >= |dy|
' dx < 0, ball should bounce to the left, and we also move the ball to the left so
' that there's no longer any collision.
if dx < 0
this.speedX = -|this.speedX|
this.x = player.x - this.Width
' dx > 0, ball should bounce to the right, and move the ball to the right of the
' paddle.
else
this.speedX = |this.speedX|
this.x = player.x + player.Width
endif
' dy is higher, same principle as for dx :)
else
if dy < 0
this.speedY = -|this.speedY|
this.y = player.y - this.Height
else
this.speedY = |this.speedY|
this.y = player.y + player.Height
endif
endif
endif
endfunc
return ball
endfunc
It is in pong.n7 that you call Player(), Ball() etc to create the actual game objects. Therefor it is in pong.n7 that you should implement get_player, get_ball and get_player_cpu, because it is pong.n7 that owns and manages these objects.
Code: 'pong
include "player.n7"
include "player-cpu.n7"
include "ball.n7"
' Marcus, objects and getters. This file is the owner of the sprites, so this is where the getters
' belong.
visible player, player_cpu, ball
function get_player(); return player; endfunc
function get_player_cpu(); return player_cpu; endfunc
function get_ball(); return ball; endfunc
set window "example pong",640,480,false
set redraw off
'objeto-----------------------------------
player = Player()
player_cpu = Player_Cpu()
ball = Ball()
while not keydown(KEY_ESCAPE,true)
set color 0,0,0
cls
'objetos-----------------------------
player.update()
player.Draw()
player_cpu.update()
player_cpu.Draw()
ball.update()
ball.Draw()
'lineas para el fondo------------------
'draw rect 320,32,2,60,true
'draw rect 320,120,2,60,true
'draw rect 320,210,2,60,true
'draw rect 320,300,2,60,true
'draw rect 320,390,2,60,true
'draw line 320,32,320,460
'draw line 330,32,330,460
redraw
fwait 60
wend
The error you see should disappear if you do it like this. The problem in your code now is that when this line executes in player-cpu.n7:
Code: visible ball = get_ball()
the ball hasn't even been created yet. So when you use that visible ball variable in your cpu update function things go very wrong. You shouldn't store the ball as a visible variable in player-cpu.n7 at all. Rather call get_ball() (implemented in pong.n7) in the player cpu update function.
Or why not just pass the ball as a parameter to player.update and player_cpu.update?
RE: problems with collisions in pong - aliensoldier - 01-26-2024
Passing the instance in the update method is the only one that has worked well.
|