Collision detection problem that shouldn't be


GrumpyOgre

Still Fresh
Joined
May 3, 2012
Messages
5
Good evening fellow pygame enthusiasts. I've been working on a Ball class script. Its a fairly simple thing I think but boy o boy am I ever not seeing why my collision isn't working. I've made a constructor member function which seems to work fine. I've made an update function which also works. Then in the main game loop I create an empty array (list in python speak) of balls and when the keydown even detects a letter 'a' it calls the constructor and creates a new ball. That all works as planned.


The issue I have is when detecting collision between the balls. I simply use the distance formula to detect the distance between each ball and all the other balls in the list and if that value is ever less than the diameter of the ball then it calls up the member function that should change the direction of the two colliding balls. Seems simple enough and my distance formula is working fine but I can't get the balls to change direction. They change direction fine enough when they contact the "walls" but they don't change direction when they bump each other. After 24 hrs of trying various different things I am now out of ideas. What the heck am I doing wrong?


import pygame, sys, glob, random, math


from pygame import *


from random import *


h=600


w=800


screen = pygame.display.set_mode((w,h))


clock = pygame.time.Clock()


class ball:


def __init__(self):


# sets the x and y values of the start position for our sprite


self.size = 10


self.x = randrange(20, 780)


self.y = randrange(20, 580)


self.xDirection = 1


self.yDirection = 1


self.color = (randrange(0, 255),randrange(0, 255),randrange(0, 255))


self.nextx = self.x+self.xDirection


self.nexty = self.y+self.yDirection


self.bounce()


self.update()


self.collision()


def collision(self):


self.xDirection *=-1


self.yDirection *=-1


self.update()


def update(self):


self.x += self.xDirection


self.y += self.yDirection


pygame.draw.circle(screen, (self.color), (self.x, self.y), self.size)


def bounce(self):


if self.x > 779 or self.x < 21:


self.xDirection *=-1


#print BallList[0].x, BallList[0].xDirection


if self.y > 579 or self.y < 21:


self.yDirection *=-1


#print BallList[0].x, BallList[0].xDirection


def distance(obj1, obj2):


# dist formula sqrt((x2-x1)^2+(y2-y1)^2)


return math.sqrt(math.pow((obj1.nextx-obj2.nextx), 2) + math.pow((obj1.nexty-obj2.nexty),2))


BallList=[]


rungame = 1


while rungame:


screen.fill((0,0,0))


clock.tick(900)


for event in pygame.event.get():


if event.type == pygame.QUIT:


RunGame = False


elif event.type == KEYDOWN and event.key==pygame.K_a:


BallList.append(ball())


for a in range(0,len(BallList)):


for b in range(0,len(BallList)):


if BallList[a]==BallList or len(BallList)<1: continue


if distance(BallList[a],BallList
)<20 :


print "boom ", BallList[0].x, BallList[0].xDirection



BallList[a].collision()



BallList
.collision()








for x in range(0,len(BallList)):



BallList[x].update()



for x in range(0,len(BallList)):



BallList[x].bounce()



pygame.display.update()






pygame.quit()
 
Oh my. Sorry. Pygame.org doesn't have a dev forum so I Googled "pygame forum" and it took me here. My apologies. However, that Pandora device looks like fun. I may have to pick one up.
 
also using the [ code ] [/ code ] would help lisibility as python without indent...


EDIT: I dont grok python very well but we do have some members here that will probably see what's wrong
 
Last edited by a moderator:
repost



Code:
import pygame, sys, glob, random, math

from pygame import *

from random import *


h=600

w=800


screen = pygame.display.set_mode((w,h))


clock = pygame.time.Clock()


class ball:

def __init__(self):

  # sets the x and y values of the start position for our sprite

  self.size = 10

  self.x = randrange(20, 780)

  self.y = randrange(20, 580)

  self.xDirection = 1

  self.yDirection = 1

  self.color = (randrange(0, 255),randrange(0, 255),randrange(0, 255))

  self.nextx = self.x+self.xDirection

  self.nexty =  self.y+self.yDirection

  self.bounce()

  self.update()

  self.collision()


def collision(self):

  self.xDirection *=-1

  self.yDirection *=-1

  self.update()


def update(self):

  self.x += self.xDirection

  self.y += self.yDirection

  pygame.draw.circle(screen, (self.color), (self.x, self.y), self.size)


def bounce(self):

  if self.x > 779 or self.x < 21:

	self.xDirection *=-1

  if self.y > 579 or self.y < 21:

	self.yDirection *=-1





def distance(obj1, obj2):

  # dist formula sqrt((x2-x1)^2+(y2-y1)^2)

  return math.sqrt(math.pow((obj1.nextx-obj2.nextx), 2) + math.pow((obj1.nexty-obj2.nexty),2))



BallList=[]


rungame = 1


while rungame:

  screen.fill((0,0,0))

  clock.tick(60)

  for event in pygame.event.get():

	if event.type == pygame.QUIT:

	  RunGame = False

	elif event.type == KEYDOWN and event.key==pygame.K_a:

	  BallList.append(ball())


  #problem seems to be in the collision() bit below

  for a in range(0,len(BallList)):

    for b in range(0,len(BallList)):

      if BallList[a]==BallList[b] or len(BallList)<1: continue

      if distance(BallList[a],BallList[b])<20 :

        BallList[a].collision()

        BallList[b].collision()



  BallList.append(ball())



  for x in range(0,len(BallList)):

    BallList[x].update()

  for x in range(0,len(BallList)):

    BallList[x].bounce()

  pygame.display.update()


pygame.quit()
 
Last edited by a moderator:
The re-post of your code isn't particularly useful due to loss of important indentation. ;)


What exactly is the behavior you experience? Do they just fail to reverse direction (move through each other), or do they sort of stick together? If I'm correct to assume they're sticking together, the problem is simple: when they collide, you're multiplying the speed variables by -1. The problem with this is both of them are moving, so if the corresponding speed variables are directly opposite of one another, they get too far in, and as a result get stuck in an infinite pattern of reversing direction every frame, keeping them in the same spot. I can mock up an image tomorrow if you don't understand.


The simple solution to this problem is to move the first object to the previous position when a collision happens, then call the bounce method on the other object. I can think of a slightly more complicated solution that would do just a tiny bit better (will post that tomorrow if you want), but the simple method's imperfection (difference of movement of the two objects) would likely go unnoticed.


As an aside, Pygame doesn't have a forum, but it does have a mailing list: http://pygame.org/wiki/info. :)
 
No need onpon4 for a mockup as I understand what you are saying. However, the balls dont stick together. They dont bounce at all. Well they bounce just fine off the walls (similar code) but they dont bounce off each other. They simply pass by/over/under each other.


Its odd about the repost as I can see the indentation on my screen.
 
You're checking the collision and reversing direction twice, that's why nothing happens.


Change the lines:



Code:
  for a in range(0,len(BallList)):

	for b in range(0,len(BallList)):

to:



Code:
  for a in range(0,len(BallList)):

	for b in range(a,len(BallList)):
 
BAH! I found it! First off thanks for your input to all of you. M-HT thank you, that makes total sense and it may have caused me problems eventually. I've implemented your suggestion to make my code more efficient as I didn't need to recheck collisions that had already been checked so I changed it to:


for a in range(0,len(BallList)-1):


for b in range(a+1,len(BallList)):


So now I've a lot less checks than I had previously. However, that wasn't my problem. I can't believe I did this actually but it happens. If you look up in the ball class section you will see I had a self.x and self.y values and also self.nextx and self.nexty values. I used those 'next' values to check for collision on what would be my next move. As onpon4 suggested, they might get stuck if I move them first then check for collision so I used those values to check for collision instead. But I noticed I never updated them in my code BAHAHAHA. What a dummy! Wow!


Again thanks all. I cant wait to see this pandora device in action. It looks very cool. My students would love to start developing on that platform I am sure.
 
Back
Top