Стрельба из танковой пули в python / pygame - PullRequest
2 голосов
/ 08 апреля 2020

Я сейчас работаю над проектом python, используя библиотеку pygame, и мне нужна помощь с этим проектом, который я создаю. Я хочу, чтобы мой танк стрелял из пуль, и поэтому эти пули рикошетят со стен. Каков наилучший способ сделать это?

Мне жаль, что мой код выглядит таким грязным, я смотрел различные учебники YouTube, и все они делают по-разному.

Вот мой код

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()

Ответы [ 2 ]

2 голосов
/ 08 апреля 2020

Один из способов сделать это - сделать так, чтобы скорость пуль изменялась при попадании в стену. Теперь я предполагаю, что стены - это край экрана, поэтому вам нужно в l oop проверить, не собирается ли пуля попасть в стену (край экрана), и, если это так, перевернуть его x_change и y_change. Вот как то так:

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
1 голос
/ 08 апреля 2020

Вот полный пример, основанный на старом ответе :

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

Посмотрите, как использовать Vector2 класс делает такие задачи очень легко решаемыми.

Также обратите внимание на правильное использование класса Sprite. Каждый Sprite занимается своим делом: класс Player управляет вращением игрока и созданием снарядов, Projectile управляет перемещением снарядов и подпрыгиванием стены.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...