Hey guys I cannot figure out how to add collision detection can someone explain how I just want my tank to stop moving when it hits the other tank. Can anyone help? Thanks.

Recommended Answers

All 8 Replies

and IF statement would remedy this !

commented: simply BS -3

pygame has collision detection. Google is your friend. Even it you can't find an answer for your specific object, you can see how it is done with other objects.

pseudocode:

simulation_loop:
  new_time = old_time + time_step
  new_tank_pos = ComputeTankPos(tank_velocity, new_time)
  if new_tank_pos is too close to wall, other tank, whatever else:
    new_tank_pos = old_tank_pos
    tank_velocity = (0, 0)  # if you have velocity separated into x and y components

I have spent the last week and a half trying to get this to work; I get no errors when I run this, but the tanks still go through each other.

Here is the code for the entire game:

import pygame
import math
                                          
class Tank(pygame.sprite.Sprite):

        def __init__(self, init_pos, is_npc=True):

                pygame.sprite.Sprite.__init__(self)
                self.Tank = pygame.image.load("tank.png")       
                self.x = -200
                self.y = 20
                self.firecountdown=0

                self.center = init_pos
                self.rect = self.Tank.get_rect()

                self.velocity = [0, 0]
                
                self.is_npc = bool(is_npc)

        def _can_move_to(self, new_rect):
                for sprite in self.groups()[0]:
                        if sprite is not self:
                                return not sprite.rect.colliderect(new_rect)
        
        def draw(self, surface):
                surface.blit(self.Tank, (self.x, self.y))
        
        def update(self, dt,):
                keys = pygame.key.get_pressed()
                
                if not self.is_npc:
                        if keys[pygame.K_RIGHT]:
                                self.velocity[0] = 250
                        elif keys[pygame.K_LEFT]:
                                self.velocity[0] = -250
                        else:
                                self.velocity[0] = 0

                velocity = [v * t_passed for v in self.velocity]

                if self._can_move_to(self.rect.move(*velocity)):
                        self.rect.move_ip(*velocity)
        
                if(self.firecountdown > 0):
                        self.firecountdown-= dt
        def fire(self, bullet):
                if(self.firecountdown <=0) :
                        bullet.x = self.x
                        bullet.y = self.y
                        bullet.fired = True     
                        bullet.speed = 10
                        self.firecountdown = 1000
                        

class Bullet(pygame.sprite.Sprite):
        def __init__(self):
                self.bullet = pygame.image.load("tank_bullet.png")
                self.y = 0
                self.x = 0
                self.speed = 0
                self.forwardx = 1
                self.forwardy = 0
                self.fired = False      
        def draw(self, surface):
                surface.blit(self.bullet, (self.x, self.y))
        def update(self, dt):
                self.x += self.forwardx * self.speed 
                self.y += self.forwardy * self.speed 
                if self.x > 640:        
                        self.fired = False
                        
class Lvl_1:
        def __init__(self):
                self.floor = pygame.image.load("floor.png")
        def draw(self, surface):
                surface.blit(self.floor, (0, 0))

class Enemy_tank(pygame.sprite.Sprite):
        
        def __init__(self):
                pygame.sprite.Sprite.__init__(self)
                self.x = 200
                self.y = -40
                self.enemy_tank = pygame.image.load("enemy_tank.png")
                self.rect = self.enemy_tank.get_rect()
        def draw(self, surface):
                surface.blit(self.enemy_tank, (self.x, self.y))
        def update(self, dt):
                pass
        
class Enemy_bullet(pygame.sprite.Sprite):
        pass

tanks = pygame.sprite.Group()
tanks.add (Tank((100, 150), False))
tanks.add (Tank((300, 150)))
                
pygame.init()                                                           
background_color = (0,0,0)                                              
(width, height) = (640, 480)                                    
screen = pygame.display.set_mode((width, height))                       
pygame.display.set_caption('Game Window')                       
clock = pygame.time.Clock()
t_passed = clock.tick(30)
Tank = Tank(pygame.sprite.Sprite)
lvl_1 = Lvl_1()
bullet = Bullet()
enemy_tank = Enemy_tank()
enemy_bullet = Enemy_bullet()
pygame.key.set_repeat(1,50)                                     
running = True
speed = 100
t_accumalator = 0.0
t_step = 0.01




while running:

        t_accumalator += clock.tick() / 1000.0          

        for t in tanks:
                t.update(t_passed)

        bullet.update(t_passed)

        screen.fill (background_color)
        Tank.draw(screen)
        lvl_1.draw(screen)
        if bullet.fired == True:        
                bullet.draw(screen)
        enemy_tank.draw(screen)
        pygame.display.flip()                                   
        clock.tick(30)

        pygame.event.pump()
        
        for event in pygame.event.get():

                if event.type == pygame.QUIT:                           
                        running = False
                        exit()
                elif event.type == pygame.KEYDOWN:
                        if event.key == pygame.K_RIGHT:
                                Tank.x += 5
                        if event.key == pygame.K_LEFT:
                                Tank.x -= 5                             
                        if event.key == pygame.K_SPACE:
                                Tank.fire(bullet)

while t_accumalator >= t_step:
        for tank in tanks:
                tank.update(t_step, keys)

        t_accumalator -= t_step
        pygame.display.flip()

There's so much weird stuff in your code now, I'm not sure where to begin. But I'll start with line 106 above, where you assign a new Tank instance with the same name as the class, making the class inaccessible from that point forward. You also create new tanks by passing a position tuple and assigning it to center , and then using x and y everywhere else. Maybe the pygame.sprite.Sprite class uses center ? If so, save yourself a lot of headache and use it also. Finally it looks like you're using the right and left arrow keys to change the driection of the non-npc tank starting at line 32, and also to tweak the position of your poorly-named Tank instance starting at line 145. One or the other is presumably in a debugging state, but consider commenting out or removing code you're not testing, until you get basics working, and then add it back in when you're ready to proceed to the next step.

I watched the Python tutorials at thenewboston.com and made some changes in the code, I got an error with the tank.center but I put a self.center in the tank class? Can anyone give me some hints?

import pygame
import math
                                          
class tank(pygame.sprite.Sprite):

        def __init__(self, init_pos, is_npc=True):

                pygame.sprite.Sprite.__init__(self)
                self.Tank = pygame.image.load("tank.png")       
                self.x = -200
                self.y = 20
                self.firecountdown=0

                self.center = init_pos
                self.rect = self.Tank.get_rect()

                self.velocity = [0, 0]
                
                self.is_npc = bool(is_npc)

        def _can_move_to(self, new_rect):
                for sprite in self.groups()[0]:
                        if sprite is not self:
                                return not sprite.rect.colliderect(new_rect)
        
        def draw(self, surface):
                surface.blit(self.Tank, (self.x, self.y))
        
        def update(self, dt,):
                #keys = pygame.key.get_pressed()
                
                #if not self.is_npc:
                 #       if keys[pygame.K_RIGHT]:
                 #               self.velocity[0] = 250
                 #      elif keys[pygame.K_LEFT]:
                 #               self.velocity[0] = -250
                 #      else:
                 #               self.velocity[0] = 0

                velocity = [v * t_passed for v in self.velocity]

                if self._can_move_to(self.rect.move(*velocity)):
                        self.rect.move_ip(*velocity)
        
                if(self.firecountdown > 0):
                        self.firecountdown-= dt
        def fire(self, bullet):
                if(self.firecountdown <=0) :
                        bullet.x = self.x
                        bullet.y = self.y
                        bullet.fired = True     
                        bullet.speed = 10
                        self.firecountdown = 1000
                        

class Bullet(pygame.sprite.Sprite):
        def __init__(self):
                self.bullet = pygame.image.load("tank_bullet.png")
                self.y = 0
                self.x = 0
                self.speed = 0
                self.forwardx = 1
                self.forwardy = 0
                self.fired = False      
        def draw(self, surface):
                surface.blit(self.bullet, (self.x, self.y))
        def update(self, dt):
                self.x += self.forwardx * self.speed 
                self.y += self.forwardy * self.speed 
                if self.x > 640:        
                        self.fired = False
                        
class Lvl_1:
        def __init__(self):
                self.floor = pygame.image.load("floor.png")
        def draw(self, surface):
                surface.blit(self.floor, (0, 0))

class Enemy_tank(pygame.sprite.Sprite):
        
        def __init__(self):
                pygame.sprite.Sprite.__init__(self)
                self.x = 200
                self.y = -40
                self.enemy_tank = pygame.image.load("enemy_tank.png")
                self.rect = self.enemy_tank.get_rect()
        def draw(self, surface):
                surface.blit(self.enemy_tank, (self.x, self.y))
        def update(self, dt):
                pass
        
class Enemy_bullet(pygame.sprite.Sprite):
        pass
                
pygame.init()                                                           
background_color = (0,0,0)                                              
(width, height) = (640, 480)                                    
screen = pygame.display.set_mode((width, height))                       
pygame.display.set_caption('Game Window')                       
clock = pygame.time.Clock()
t_passed = clock.tick(30)
Tank = tank(pygame.sprite.Sprite)
lvl_1 = Lvl_1()
bullet = Bullet()
enemy_tank = Enemy_tank()
enemy_bullet = Enemy_bullet()
pygame.key.set_repeat(1,50)                                     
running = True
speed = 100
t_accumalator = 0.0
t_step = 0.01

tanks = pygame.sprite.Group()
tanks.add (tank(((tank.center)), False))


while running:

        t_accumalator += clock.tick() / 1000.0          

        for t in tanks:
                t.update(t_passed)

        bullet.update(t_passed)

        screen.fill (background_color)
        Tank.draw(screen)
        lvl_1.draw(screen)
        if bullet.fired == True:        
                bullet.draw(screen)
        enemy_tank.draw(screen)
        pygame.display.flip()                                   
        clock.tick(30)

        pygame.event.pump()
        
        for event in pygame.event.get():

                if event.type == pygame.QUIT:                           
                        running = False
                        exit()
                elif event.type == pygame.KEYDOWN:
                        if event.key == pygame.K_RIGHT:
                                Tank.x += 5
                                Tank.velocity[0] = 250
                        if event.key == pygame.K_LEFT:
                                Tank.x -= 5
                                Tank.velocity[0] = -250
                        if event.key == pygame.K_SPACE:
                                Tank.fire(bullet)

while t_accumalator >= t_step:
        for tank in tanks:
                tank.update(t_step, keys)

        t_accumalator -= t_step
        pygame.display.flip()

Now your tank.update() method apparently moves the rect of the sprite, but the tank.draw() method blits the image at (self.x, self.y), which aren't updated except for the player's tank (via keystroke). If you're going to maintain these values separately, you have to keep them synchronized: whenever you move the rect, update x and y; and vice versa.

You can save yourself most of the confusion by writing smaller programs first: one that allows you to use the keyboard to move your own tank the way you want, and a second one that demonstrates automatic movement of [enemy] tanks. Then when you have both programs working correctly separately, then you can look at merging the main loop into one that takes user input for the player-tank and automates enemy-tanks.

For starters, just have two separate classes: PlayerTank and EnemyTank. Then when you're more comfortable, you can put all the common repeated functionality (like the draw() method, for instance) into a BaseTank class, derive PlayerTank and EnemyTank from BaseTank, and add only the new unique members and methods to each of the derived classes.

If anything can move diagonally, there are some good comments under rect.move() and rect.move_ip() at http://www.pygame.org/docs/ref/rect.html#Rect.move

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.