kovels
kovels

Reputation: 57

Shooting tank bullet in python/pygame

I'm working on python project right now using pygame library and I need help with this project I make. I want my tank to shoot bullets and so those bullets ricochet from the walls. What is the best way possible to do this?

I'm sorry that my code looks so messy, I've been watching different youtube tutorials and they all do differently.

Here is my code

import pygame

pygame.init()

# ======================= Variables =======================

# ------------------------ Screen -------------------------

screenWidth = 1060
screenHeight = 798
screenSize = (screenWidth, screenHeight)
display = pygame.display.set_mode((screenWidth, screenHeight))
pygame.display.set_caption("Tank game")

bg = pygame.image.load("sprites/background/background1.png")
bg = pygame.transform.scale(bg, (screenWidth, screenHeight))

# ------------------------ Player -------------------------


# ------------------------ Enemy -------------------------


# ----------------------- Other ---------------------------

red = (155, 0, 0)

clock = pygame.time.Clock()
fps = 60


# ========================= Clases ========================


class player(pygame.sprite.Sprite):
    def __init__(self, location, angle, vel, x, y):
        pygame.sprite.Sprite.__init__(self)
        self.image = pygame.image.load("sprites/player/player_tank.png")

        self.x = x
        self.y = y
        self.vel = vel
        self.angle = angle
        self.rect = self.image.get_rect()
        self.rect.left, self.rect.top = location

        if self.angle == 360:
            self.angle = 0

    def rotate(self):
        rot_image = pygame.transform.rotate(self.image, self.angle)
        rot_rect = rot_image.get_rect(center=self.rect.center)
        return rot_image, rot_rect

    def moving_after_angle_change(self):
        x = round(math.cos(math.radians(self.angle + 90)), 1) * self.vel
        y = round(math.sin(math.radians(self.angle - 90)), 1) * self.vel
        return x, y


class enemy(pygame.sprite.Sprite):
    def __init__(self, x, y, width, height, end):
        pygame.sprite.Sprite.__init__(self)
        self.image = pygame.image.load("sprites/enemy/enemy_tank.png")

        self.x = x
        self.y = y
        self.width = width
        self.height = height
        self.end = end
        self.path = [self.x, self.y, self.end]
        self.vel = 5

    def draw(self, display):
        self.move()
        display.blit(self.image, (self.x, self.y))

    def move(self):
        if self.vel > 0:
            pass


# Bullet
bullet = pygame.image.load("sprites/bullet/bullet.png")
bullet = pygame.transform.scale(bullet, (16, 16))
bullet_x = 0
bullet_y = 480
bullet_x_change = 0
bullet_y_change = 10
bullet_state = 'ready'


# ======================= Functions =======================

def redrawGameWindow():
    display.blit(bg, (0, 0))
    display.blit(player_tank.image, player_tank.rect)
    display.blit(enemy_tank.image, (enemy_tank.x, enemy_tank.y))
    #display.blit(bullet, (player_tank.x + 160, player_tank.y + 100))

    pygame.display.flip()


def fireBullet(x, y):
    global bullet_state
    bullet_state = 'fire'
    display.blit(bullet, (x + 16, y + 10))


player_location = [70, 570]
player_angle = 270
player_angle_change = 0
player_vel = 0
player_x_change = 0
player_y_change = 0
player_tank_x_change_store = 0
player_tank_y_change_store = 0

run = True

while run:
    clock.tick(fps)

    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            run = False

        if event.type == pygame.KEYDOWN:
            if event.key == pygame.K_UP:
                player_vel = 2
            elif event.key == pygame.K_DOWN:
                player_vel = -2
            elif event.key == pygame.K_LEFT:
                player_angle_change = 2
            elif event.key == pygame.K_RIGHT:
                player_angle_change = -2

            if event.key == pygame.K_SPACE:
                display.blit(bullet, (player_tank.x + 160, player_tank.y + 100))

        if event.type == pygame.KEYUP:
            if event.key == pygame.K_UP:
                player_vel = 0
            elif event.key == pygame.K_DOWN:
                player_vel = 0
            elif event.key == pygame.K_LEFT:
                player_angle_change = 0
            elif event.key == pygame.K_RIGHT:
                player_angle_change = 0

    player_angle += player_angle_change

    player_tank = player(player_location, player_angle, player_vel, player_x_change, player_y_change)

    enemy_tank = enemy(800, 170, 64, 64, 700)

    player_tank.image, player_tank.rect = player_tank.rotate()

    player_tank.x_change, player_tank.y_change = player_tank.moving_after_angle_change()

    player_tank_x_change_store += player_tank.x_change
    player_tank_y_change_store += player_tank.y_change
    player_tank.rect.centerx += player_tank_x_change_store
    player_tank.rect.centery += player_tank_y_change_store

    # Bullet movement
    if bullet_state == "fire":
        fireBullet(player_tank.x, bullet_y)
        bullet_y -= bullet_y_change

    redrawGameWindow()

pygame.quit()
quit()

Upvotes: 2

Views: 1118

Answers (2)

sloth
sloth

Reputation: 101042

Here's a full example, based on an old answer:

import pygame

class Player(pygame.sprite.Sprite):
    def __init__(self):
        super().__init__()
        self.image = pygame.Surface((32, 32))
        self.image.fill((0, 0, 0))
        self.image.set_colorkey((0, 0, 0))
        pygame.draw.polygon(self.image, pygame.Color('dodgerblue'), ((0, 0), (32, 16), (0, 32)))
        self.org_image = self.image.copy()
        self.angle = 0
        self.direction = pygame.Vector2(1, 0)
        self.rect = self.image.get_rect(center=(200, 200))
        self.pos = pygame.Vector2(self.rect.center)

    def update(self, events, dt):
        for e in events:
            if e.type == pygame.KEYDOWN:
                if e.key == pygame.K_SPACE:
                    self.groups()[0].add(Projectile(self.rect.center, self.direction.normalize()))
        pressed = pygame.key.get_pressed()
        if pressed[pygame.K_a]:
            self.angle += 3
        if pressed[pygame.K_d]:
            self.angle -= 3

        self.direction = pygame.Vector2(1, 0).rotate(-self.angle)
        self.image = pygame.transform.rotate(self.org_image, self.angle)
        self.rect = self.image.get_rect(center=self.rect.center)

class Projectile(pygame.sprite.Sprite):
    def __init__(self, pos, direction):
        super().__init__()
        self.image = pygame.Surface((8, 8))
        self.image.fill((0, 0, 0))
        self.image.set_colorkey((0, 0, 0))
        pygame.draw.circle(self.image, pygame.Color('orange'), (4, 4), 4)
        self.rect = self.image.get_rect(center=pos)
        self.direction = direction
        self.pos = pygame.Vector2(self.rect.center)
        self.lives = 15

    def update(self, events, dt):
        # Bounding box of the screen
        screen_r = pygame.display.get_surface().get_rect()

        # where we would move next
        next_pos = self.pos + self.direction * dt

        # we hit a hall
        if not screen_r.contains(self.rect):

            # after 15 hits, destroy self
            self.lives -= 1
            if self.lives == 0:
                return self.kill()

            # horizontal reflection
            if next_pos.x > screen_r.right or next_pos.x < screen_r.left:
                self.direction.x *= -1

            # vertical reflection
            if next_pos.y > screen_r.bottom or next_pos.y < screen_r.top:
                self.direction.y *= -1

            # move after applying reflection
            next_pos = self.pos + self.direction * dt

        # set the new position
        self.pos = next_pos
        self.rect.center = self.pos

def main():
    pygame.init()
    screen = pygame.display.set_mode((500, 500))
    sprites = pygame.sprite.Group(Player())
    clock = pygame.time.Clock()
    dt = 0

    while True:
        events = pygame.event.get()
        for e in events:
            if e.type == pygame.QUIT:
                return
        sprites.update(events, dt)
        screen.fill((30, 30, 30))
        sprites.draw(screen)
        pygame.display.update()
        dt = clock.tick(60)

if __name__ == '__main__':
    main()

enter image description here

See how using the Vector2 class makes this kind of tasks very easy to solve.

Also, look at the proper usage of the Sprite class. Each Sprite minds its own business: the Player class handles rotating the player and creating projectiles, Projectile handles moving the projectiles and bouncing of the wall.

Upvotes: 1

The Big Kahuna
The Big Kahuna

Reputation: 2110

One way to do this is to make the bullets velocity flip when it hits a wall. Now I'm assuming the walls are the edge of the screen so what you need to do is in the loop, check if the bullet is about to hit a wall (the edge of the screen) and if it is, flip its x_change and y_change. So something like this:

if bullet_y <= 0:
    bullet_y_change *= -1
    bullet_y = 0
if bullet_y >= screenHeight:
    bullet_y_change *= -1
    bullet_y = screenHeight
if bullet_x <= 0:
    bullet_x_change *= -1
    bullet_x = 0
if bullet_x >= screenWidth:
    bullet_x_change *= 1
    bullet_x = screenWidth

Upvotes: 2

Related Questions