3 Replies - 4357 Views - Last Post: 12 October 2011 - 09:25 AM Rate Topic: -----

#1 Airi-n  Icon User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 7
  • Joined: 24-September 11

Collision Detection Between Rectangles

Posted 11 October 2011 - 03:53 PM

I'm working on a program where a cannonball is shot from a cannon and that part works, but I now had to put in a target (which I did), but I'm having problems with getting the reaction I want for when the ball collides with the target. For now, I just made the collision method take in a few extra parameters such as the window to just draw a blue square somewhere on the screen for now before implementing what it needs to do, which is make the target disappear (I'm not sure how to do that either, and that's why I just went for something I do know how to do just for testing).

I've implemented code for it in the Target and Gui classes, but I'm posting the code for the other classes (minus the game_controller file that just runs the game) since the cannonball and the target have to interact with each other in some way.

from cannonball import Cannonball
import math    
        
class Cannon():
    '''
    Makes a cannon for the active cannonball
    '''
    
    def __init__(self, x_pos, y_pos, velocity, angle_degrees):
        '''
        Initializes the x position, y position, launch velocity, and launch angle in degrees
        '''
        self.x_pos = x_pos
        self.y_pos = y_pos
        self.velocity = velocity
        self.angle = (math.pi * angle_degrees) / 180.0
        
        self.active_cannonball = None
        
    def fire(self, time_interval):
        '''
        Shoots the cannon, initializes the active cannonball with the x position, y position,
        angle, velocity, and time interval so that it can move on its path
        '''
        self.active_cannonball = Cannonball(self.x_pos, self.y_pos, self.angle, self.velocity, time_interval)


import math

        
class Cannonball(object):
    '''
    Represents the cannonball that will be shot out of the cannon
    '''
    
    def __init__(self, x_pos, y_pos, angle, velocity, time_interval):
        '''
        Initializes the instance variables, calculates the horizontal distance that the ball travels at,
        and sets the ball's status to 'flying'
        '''
    
        self.x_pos = x_pos
        self.y_pos = y_pos
        self.x_velocity = velocity * math.cos(angle)
        self.y_velocity = velocity * math.sin(angle)
        self.time_interval = time_interval
        self.x_delta = self.time_interval * self.x_velocity
        self.is_flying = True
        
    def move(self):
        '''
        Changes the ball's x and y location using the formulas for ballistic trajectory.
        '''
        
        prev_y_velocity = self.y_velocity
        self.y_velocity = self.y_velocity - (9.8 * self.time_interval)
        self.y_pos = (self.y_pos + (self.time_interval * ((prev_y_velocity + self.y_velocity)/2)))
        self.y_pos = max(self.y_pos, 0)
        self.x_pos += (self.x_delta)
        self.is_flying = (self.y_pos > 0)
    


import pygame
from cannonball import Cannonball

'''
Created on Oct 10, 2011

@author: Ilene Peguero
'''

class Target(object):
    '''
    Represents the target to be hit by the cannonball
    '''
    
    BLUE = (0, 0, 255)


    def __init__(self, height, width, x_pos, y_pos):
        '''
        Constructor
        '''
        self.height = height
        self.width = width
        self.x_pos = x_pos
        self.y_pos = y_pos
    
    
    def collision_detect(self, cannonball, cannonball_rect, target_rect, window):
        if cannonball_rect.colliderect(target_rect):
            pygame.draw.rect(self.window, Target.BLUE, 100, 100, 30, 30)
        


class FireController(object):
    '''
    Controller for the method fire in cannon, which shoots the cannon and moves the cannonball
    through its trajectory
    '''
    
    def __init__(self, cannon, time_interval):
        '''
        Initializes the cannon with specified values
        '''
        self.cannon = cannon
        self.time_interval = time_interval
        
    def fire_cannon(self):
        '''
        Tells the cannon to shoot and sets active cannonball to the one being shot by the cannon
        '''
        self.cannon.fire(self.time_interval)
        self.active_cannonball = self.cannon.active_cannonball
        
    def move_cannonball(self):
        '''
        Tells the cannonball to move to the next position in its trajectory
        '''
        self.active_cannonball.move()


import pygame
from cannon import Cannon 
from target import Target
from fire_controller import FireController
                    
                    
class Gui():
    '''
    Gui defines the GUI for the cannon shooting game
    '''
    
    BLACK = (0, 0, 0)
    GRAY = (105, 105, 105)
    GRASS_COLOR = (77, 189, 51)
    SKY_BLUE = (0, 191, 255)
    RED = (255, 0, 0)
        
    
    def __init__(self, width, height, velocity, angle, time_interval):
        '''
        Creates the display surface, the window title, and the instance variables
        '''
        
        self.width = width
        self.height = height
        self.velocity = velocity
        self.angle = angle
        self.time_interval = time_interval
        self.ground_y = self.height - 50
        
        self.window = pygame.display.set_mode((self.width, self.height))
        pygame.display.set_caption("Cannonball Shooting Game")
        
        self.cannon = Cannon(x_pos=50, y_pos=0, velocity=self.velocity, angle_degrees=self.angle)
        self.active_cannonball = None
        
        self.fire_controller = FireController(self.cannon, self.time_interval)
        
        self.target = Target(30, 30, 1050, self.ground_y - 25)
        
        self.cannonball_rect = None
        self.target_rect = None
        
        
    def display_grass(self):
        '''
        Draws the grass
        '''
        ground_start_pos = (0, self.ground_y + 50)
        ground_end_pos = (self.width, self.ground_y + 50)
        pygame.draw.line(self.window, Gui.GRASS_COLOR, ground_start_pos, ground_end_pos, 100)

                
    def display_cannon(self):
        '''
        Draws the cannon as a thick gray line with a black circle as its wheel
        '''
        barrel_start_pos = (round(self.cannon.x_pos), round(self.cannon.y_pos + self.ground_y))
        barrel_end_pos = (round(self.cannon.x_pos + 20), round(self.cannon.y_pos + self.ground_y - 20))
        
        pygame.draw.line(self.window, Gui.GRAY, barrel_start_pos, barrel_end_pos, 10)
        
        wheel_pos = (self.cannon.x_pos + 4, self.cannon.y_pos + self.ground_y)
        
        pygame.draw.circle(self.window, Gui.BLACK, wheel_pos, 7)
        
        
    def display_cannonball(self):
        '''
        Draws the cannonball as a black circle
        '''
        ball_pos = (round(self.active_cannonball.x_pos), round(self.ground_y - self.active_cannonball.y_pos))
        
        pygame.draw.circle(self.window, Gui.BLACK, ball_pos, 4)
        
        rect_pos = (round(self.active_cannonball.x_pos), round(self.ground_y - self.active_cannonball.y_pos),
                    5, 5)
        self.cannonball_rect = pygame.draw.rect(self.window, Gui.BLACK, rect_pos)
        
    
    def display_target(self):
        '''
        Draws the target as a red square
        '''
        target_pos = (self.target.x_pos, self.target.y_pos, self.target.height, self.target.width)
        self.target_rect = pygame.draw.rect(self.window, Gui.RED, target_pos)
    
    def display(self):
        '''
        Draws the grass, cannon, and if it has been initialized, the cannonball
        '''
        self.window.fill(Gui.SKY_BLUE)
        self.display_grass()
        self.display_cannon()
        self.display_target()
        if self.active_cannonball:
            self.display_cannonball()
        pygame.display.flip()
            
            
    def handle_move_cannonball_event(self):
        '''
        Tells the controller to move the cannonball until it is not flying
        '''
        while self.active_cannonball.is_flying:
            self.fire_controller.move_cannonball()
            self.display()
            
            
    def handle_fire_event(self):
        '''
        Tells the controller to fire the cannon, which creates the active cannonball
        '''
        self.fire_controller.fire_cannon()
        self.active_cannonball = self.cannon.active_cannonball
        
    
    def handle_target_collision_event(self):
        while self.active_cannonball.is_flying == False:
            self.target.collision_detect(self.active_cannonball, self.cannonball_rect, self.target_rect, self.window)
            
        
    def run(self):  
        '''
        Executes the animation loop, handling the "fire cannon" and "move
        active cannonball" events. Exits when the user clicks the quit button.
        '''      
        self.display()
        
        keepPlaying = True
        
        while keepPlaying:  
            for event in pygame.event.get():
                if event.type == pygame.QUIT:
                    keepPlaying = False  
                elif event.type == pygame.KEYDOWN and event.key == pygame.K_f:
                    self.handle_fire_event()
                    self.handle_move_cannonball_event()
                    
                    
                    


If anyone can help me out with this problem, I'd really appreciate it, as I have no idea what other angle to take on this.

Is This A Good Question/Topic? 0
  • +

Replies To: Collision Detection Between Rectangles

#2 Martyr2  Icon User is offline

  • Programming Theoretician
  • member icon

Reputation: 4334
  • View blog
  • Posts: 12,128
  • Joined: 18-April 07

Re: Collision Detection Between Rectangles

Posted 11 October 2011 - 04:19 PM

So you now have a move method that moves your cannonball through its trajectory. Great! Now for each movement through the air we have to detect if the cannonball has come into contact with any targets. Right now we have one, but the idea would be to allow a given cannonball to detect if it has run into any one of a number of targets.

One way you might approach this is simply store a list of target rectangles. Then as the ball moves, you give the current cannonball instance to a function which will run a colliderect against it and each target in the list. If any of them come back true, a collision has been detected and you can have it fire off a function which will set off the animation of the target being destroyed (passing the function the actual target instance so it knows which one to destroy).

In short....

1) Move cannonball one space
2) Give cannonball instance to function which loops through targets looking for a collision between the ball and one of the targets.
3) If collision found, give target to some animation function to destroy that target. (And stop or destroy the cannonball)
4) If collision was not found, function returns false. Return to step 1.

So the idea here is that for a thousand points in the trajectory you are checking "Did I hit something?" If you didn't, you continue on your merry way.

Targets in the list of targets may include the ground, other balls, enemy ship, wall etc.

Since you focus on one target, put that single target in a list, pass the cannonball object in motion to it, check with colliderect to see if the two hit one another and if they do, call your animation to destroy target. Stop cannonball's motion.

:)

This post has been edited by Martyr2: 11 October 2011 - 04:20 PM

Was This Post Helpful? 0
  • +
  • -

#3 Airi-n  Icon User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 7
  • Joined: 24-September 11

Re: Collision Detection Between Rectangles

Posted 11 October 2011 - 06:21 PM

Thank you for your post :D After reading what you had said, I changed a bit of my code. I changed the Terget class a bit, changed the display_target and handle_target_collision_event methods from my Gui class, and I'm glad there are no errors, but it still doesn't seem to be doing what it should be doing. I'm still working on it, but I wanted to go ahead and post this update.

import pygame
from cannonball import Cannonball

class Target(object):
    '''
    Represents the target to be hit by the cannonball
    '''
    
    BLUE = (0, 0, 255)
    target_list = []


    def __init__(self, height, width, x_pos, y_pos):
        '''
        Constructor
        '''
        self.height = height
        self.width = width
        self.x_pos = x_pos
        self.y_pos = y_pos
    
    
    def collision_detect(self, cannonball, cannonball_rect, window):
        '''
        if cannonball_rect.colliderect(target_rect):
            pygame.draw.rect(self.window, Target.BLUE, 100, 100, 50, 50)
            pygame.display()
        '''
        
        while cannonball.is_flying:
            for target in self.target_list:
                if target.colliderect(cannonball_rect) == True:
                    pygame.draw.rect(self.window, Target.BLUE, 100, 100, 50, 50)
                    pygame.display()
                else:
                    return False


def display_target(self):
        '''
        Draws the target as a red square
        '''
        target_pos = (self.target.x_pos, self.target.y_pos, self.target.height, self.target.width)
        self.target_rect = pygame.draw.rect(self.window, Gui.RED, target_pos)
        self.target.target_list.append(self.target_rect)        
    
    def handle_target_collision_event(self):
            self.target.collision_detect(self.active_cannonball, self.cannonball_rect, self.window)

Was This Post Helpful? 0
  • +
  • -

#4 Martyr2  Icon User is offline

  • Programming Theoretician
  • member icon

Reputation: 4334
  • View blog
  • Posts: 12,128
  • Joined: 18-April 07

Re: Collision Detection Between Rectangles

Posted 12 October 2011 - 09:25 AM

Honestly I would have probably put the detect on the cannonball class itself (so you can do something like cannonball.collision_detect() to find out if it hit anything), but that code is looking much more promising and I think you will get much more mileage out of it for the future.

:)
Was This Post Helpful? 0
  • +
  • -

Page 1 of 1