Условие столкновения в pygame (некорректно срабатывает условие)
В игре должно работать условие:
- Если вражеский корабль достиг нижней границы экрана, то игра завершается, но условие работает некорректно (в функции
enemy_chek()). - Если сделать проверку на нахождение точки
bottomвражеского корабля за пределами экрана, то это условие срабатывает даже тогда, когда этого не случается.
Могу предположить, что это из-за того, что координата y уничтоженных противников продолжает отслеживаться.
import pygame
import sys
from pygame.sprite import Group
pygame.init()
#параметры экрана
height, width = 800, 650 # высота # ширина
screen = pygame.display.set_mode((width, height))
# игрок
class Ship:
def __init__(self, screen):
self.screen = screen
self.screen_rect = screen.get_rect()
self.rect = pygame.Rect(300, 710, 80, 80)
self.color = (255, 255, 255)
self.move_left = False
self.move_right = False
def move(self):
if self.move_left == True:
self.rect.centerx -= 1
elif self.move_right == True:
self.rect.centerx += 1
if self.rect.right >= 650:
self.rect.right = 650
elif self.rect.left <= 0:
self.rect.left = 0
def output_s(self):
pygame.draw.rect(self.screen, self.color, self.rect)
#пули
class Bullet(pygame.sprite.Sprite):
def __init__(self, screen, my_ship):
super(Bullet, self).__init__()
self.screen = screen
self.rect = pygame.Rect(0, 0, 100, 10)
self.speed = 5
self.rect.centerx = my_ship.rect.centerx
self.rect.top = my_ship.rect.top
self.y = self.rect.y
def update(self):
"""перемещение пули вверх"""
self.y -= self.speed
self.rect.y = self.y
def draw_bullet(self):
pygame.draw.rect(self.screen, (255, 255, 255), self.rect)
#враги
class Enemy(pygame.sprite.Sprite): # класс enemy наследник класса sprite
def __init__(self, screen):
super(Enemy, self).__init__()
self.screen = screen
self.screen_rect = screen.get_rect()
self.rect = pygame.Rect(0, 0, 70, 70)
self.rect.top = self.screen_rect.top
self.rect.centerx = self.screen_rect.centerx
self.x = float(self.rect.x)
self.y = float(self.rect.y)
def output_e(self):
pygame.draw.rect(self.screen, (255, 255, 255), self.rect)
def update(self):
self.y += 0.1
self.rect.y = self.y
# объекты классов и группы
my_ship = Ship(screen)
bullets = Group()
enemys = Group()
# создания ряда врагов
def create_enemy(screen, enemys, width=600, current_row_y=25):
enemy_width = Enemy(screen).rect.width
e_numbers = (width - 50) // enemy_width
for i in range(e_numbers):
enemy = Enemy(screen)
enemy.x = 25 + (enemy_width + 25) * i
enemy.rect.x = enemy.x
enemy.y = current_row_y
enemy.rect.y = enemy.y
enemys.add(enemy)
#движение пуль и их столконовение с врагами
def update_bullets(screen, bullets, enemys, width=600):
bullets.update()
for bullet in bullets.copy():
if bullet.rect.bottom <= 0:
bullets.remove(bullet)
collision = pygame.sprite.groupcollide(bullets, enemys, True, True)
#отрисовка пуль. игрока и врагов на экране
def screen_update(screen, enemys, bullets):
screen.fill((0, 0, 0))
for enemy in enemys:
enemy.output_e()
for bullet in bullets:
bullet.draw_bullet()
my_ship.output_s()
my_ship.move()
pygame.display.flip()
#проигрыш
def gun_kill( screen, enemys, width=600):
enemys.empty()
bullets.empty()
create_enemy(screen, enemys, width)
#неправильно работающая функция
def enemy_check(screen, enemys, width=600):
# добралась ли армия до конца экрана
screen_rect = screen.get_rect()
for enemy in enemys:
if enemy.rect.bottom >= screen_rect.bottom:
gun_kill(screen, enemys)
break
def main():
create_enemy(screen, enemys) # Создаем врагов при старте
while True:
for event in pygame.event.get():
if event.type == pygame.QUIT:
sys.exit()
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_a:
my_ship.move_left = True
elif event.key == pygame.K_d:
my_ship.move_right = True
# стрельба
elif event.key == pygame.K_SPACE:
new_bullet = Bullet(screen, my_ship)
bullets.add(new_bullet)
elif event.type == pygame.KEYUP:
if event.key == pygame.K_a:
my_ship.move_left = False
elif event.key == pygame.K_d:
my_ship.move_right = False
#создание рядов, следующих друг за другом
#возможно, этот способ их создания - причина некорректной работы
last_enemy = enemys.sprites()[-1]
if enemys and last_enemy.rect.y >= 100:
create_enemy(screen, enemys, width, 0)
enemys.update()
enemy_check(screen, enemys)
update_bullets(screen, bullets, enemys, width=600)
screen_update(screen, enemys, bullets)
if __name__ == "__main__":
main()
Ответы (1 шт):
Автор решения: S. Nick
→ Ссылка
Я не обнаружил в приведенном вами примере того что вы пишите, т.е. у меня при достижении нижней границы экрана, начинается новая игра и вверху рисуется новый ряд врагов. Может я чего-то не так понял.
Я вам предложу проверить другой вариант похожей и более продвинутой игры.
Обратите внимание:
- движение игрока реализовано под левую и под правую руку;
- в игре реализован подсчет баллов и уровни игры;
- игра заканчивается при столкновении игрока с врагом;
- ...
Надеюсь пример будет полезет для вас.
import random
import time
import pygame
import pygame.mixer
from pygame.locals import *
class Player(pygame.sprite.Sprite):
def __init__(self):
pygame.sprite.Sprite.__init__(self)
# --------------------------------------> vvvvvvvvvvvvvvv <------- установите свое
self.images = [pygame.image.load("img/player1.png").convert_alpha(),
pygame.image.load("img/player2.png").convert_alpha()]
self.current_image = 0
self.speed = 20
# ------------------------------------> vvvvvvvvvvvvvvv <------- установите свое
self.image = pygame.image.load("img/player1.png").convert_alpha()
self.image = pygame.transform.scale(self.image, (68, 78))
self.rect = self.image.get_rect()
self.rect[0] = 600
self.rect[1] = 510
self.points = 0
def update(self):
self.animation()
def animation(self):
self.current_image = (self.current_image + 1) % 2
self.image = self.images[self.current_image]
self.image = pygame.transform.scale(self.image, (68, 78))
class Shot(pygame.sprite.Sprite):
def __init__(self):
pygame.sprite.Sprite.__init__(self)
# ------------------------------------> vvvvvvvvvvvv <--------------- установите свое
self.image = pygame.image.load("img/shot.png").convert_alpha()
self.rect = self.image.get_rect()
self.speed = 30
def update(self):
self.rect[1] -= self.speed
class Enemy (pygame.sprite.Sprite):
def __init__(self):
pygame.sprite.Sprite.__init__(self)
# -----------------------------------------> vvvvvvvvvvvvvvv <------- установите свое
self.animation = [pygame.image.load("img/meteor1.png").convert_alpha(),
pygame.image.load("img/meteor2.png").convert_alpha(),
pygame.image.load("img/meteor3.png").convert_alpha()]
# ------------------------------------> vvvvvvvvvvvvvvv <------------- установите свое
self.image = pygame.image.load("img/meteor1.png").convert_alpha()
self.image = pygame.transform.scale(self.image, (68, 78))
self.rect = self.image.get_rect()
self.rect[0] = random.randint(10, 1100)
self.rect[1] = random.randint(10, 30)
self.speed = 1
self.current_image = 0
self.current_explosion = 0
def update(self):
self.current_image = (self.current_image + 1) % 3
self.image = self.animation[self.current_image]
self.image = pygame.transform.scale(self.image, (68, 78))
self.rect[1] += self.speed
class Game():
def __init__(self):
pygame.init() # инициализировать pygame
# переменная, которая контролирует, запускается игра или нет
self.game_start = True
self.window_width = 1200 # ширина окна
self.window_height = 600 # высота окна
# создает окно, передавая ширину и высоту в качестве параметров
self.window = pygame.display.set_mode((self.window_width, self.window_height))
# -----------------------------------------> vvvvvvvvvvvvvvvvvv <------ установите свое
self.background = pygame.image.load("img/background.jpg") # фоновое изображение
# определил ширину и высоту фонового изображения.
self.background = pygame.transform.scale(
self.background, (self.window_width, self.window_height))
# Игрок
self.player_group = pygame.sprite.Group() # создает группу для игрока
self.player = Player() # создать игрока
self.player_group.add(self.player) # добавить игрока в группу
self.player_right = False # инициализирует переменную движения FALSE
self.player_left = False # инициализирует переменную движения FALSE
# Выстрелил
self.shoot_group = pygame.sprite.Group() # создать группу выстрелов
# Враг
self.create_enemy = True
self.enemy_group = pygame.sprite.Group()
# !!! ОЧКИ И ИНФОРМАЦИЯ ОБ УРОВНЕ
self.player_points = self.player.points
# ----------------------------------> vvvvvvvvvvvvv <--------------- установите свое
self.font = pygame.font.Font("font/8bit.ttf", 30)
self.points_text = self.font.render("SCORE: " + str(self.player_points),
1, (255,255,255))
self.level = 0
self.enemy_in_window = 5
self.level_text = self.font.render("LEVEL: "+ str(self.level),
1, (255, 255, 255))
# ФОНОВАЯ МУЗЫКА
pygame.mixer.init()
pygame.mixer.set_reserved(0)
# ------------------------------------------> vvvvvvvvvvvvvvvvvvvvv <--- установите свое
self.game_music = pygame.mixer.Sound("sounds/game_music.wav")
pygame.mixer.Channel(0).play(self.game_music, -1)
# FPS
self.fps = pygame.time.Clock() # добавить часы в переменную для управления fps
# ГЛАВНЫЙ ЦИКЛ
self.game_init = True
while self.game_init:
self.fps.tick(30) # установите частоту кадров в игре
for event in pygame.event.get(): # событие для игровых команд
if event.type == QUIT:
pygame.quit()
if event.type == KEYDOWN: # когда клавиша нажата
if event.key == K_d or event.key == K_RIGHT:
self.player_right = True
if event.key == K_a or event.key == K_LEFT:
self.player_left = True
if event.key == K_SPACE: # кнопка для стрельбы
self.player_shot = Shot() #
self.player_shot.rect[0] = self.player.rect[0]+23 # передает начальную позицию по x
self.player_shot.rect[1] = self.player.rect[1] # передает начальную позицию в y
self.shoot_group.add(self.player_shot) # добавить кадр в группу кадров
pygame.mixer.Channel(1).play(pygame.mixer.Sound("sounds/shot.wav")) # огнестрельная музыка
if event.type == KEYUP: # когда отпустишь клавишу
if event.key == K_d or event.key == K_RIGHT:
self.player_right = False
if event.key == K_a or event.key == K_LEFT:
self.player_left = False
if self.player_right: # если условие истинно, игрок движется вправо
self.player.rect[0] += self.player.speed
if self.player_left: # если условие истинно, игрок движется влево
self.player.rect[0] -= self.player.speed
self.window.blit(self.background, (0, 0)) # нарисовать фон
self.window.blit(self.points_text, (850, 10)) # счет
self.window.blit(self.level_text, (650, 10))
self.shoot_group.update() # вызывает функцию обновления для всех в группе снимков
self.player_group.update() # вызывает функцию обновления для всех в группе игрока
self.player_group.draw(self.window) # рисует всю группу игроков на экране
self.enemy_group.update() # Вызов обновления группы противника
self.enemy_group.draw(self.window) # рисовать врагов на экране
if len(self.enemy_group) < 5: # Если у вас меньше 5 врагов, добавьте больше врагов.
for i in range(5):
self.enemy = Enemy()
self.enemy_group.add(self.enemy)
print("Добавил еще одного врага")
# !!!
if self.enemy.rect[1] > 600: # Когда враги достигают 700 пикселей экрана, они уничтожаются.
self.enemy_group.remove(self.enemy)
print("\nВраг покинул экран\n")
# !!!
# ПРОВЕРКА СЧЕТА И УРОВНЯ
if self.player_points > 500:
self.enemy.speed = 2
self.level = 1
self.level_text = self.font.render(
"LEVEL: "+ str(self.level), 1, (255, 255, 255))
if self.player_points > 2000:
self.enemy.speed = 3
self.level = 2
self.level_text = self.font.render("LEVEL: "+ str(self.level),1,(255,255,255))
if self.player_points > 4000:
self.enemy.speed = 4
self.level = 3
self.level_text = self.font.render("LEVEL: "+ str(self.level),1,(255,255,255))
if self.player_points > 8000:
self.enemy.speed = 6
self.level = 4
self.level_text = self.font.render("LEVEL: "+ str(self.level),1,(255,255,255))
if self.player_points > 10000:
self.enemy.speed = 8
self.level = 5
self.level_text = self.font.render("LEVEL: "+ str(self.level),1,(255,255,255))
if self.player_points > 20000:
self.enemy.speed = 9
self.level = 6
self.level_text = self.font.render("LEVEL: "+ str(self.level),1,(255,255,255))
if self.player_points > 50000:
self.enemy.speed = 12
self.level = "FINAL LEVEL"
self.level_text = self.font.render("LEVEL: "+ str(self.level),1,(255,255,255))
for bullet in self.shoot_group: # для каждого кадра, находящегося в группе выстрелов
self.shoot_group.draw(self.window) # нарисуй кадр на экране
if self.player_shot.rect[1] < -20: # проверяет, меньше ли y-позиция кадра - 20 и в этом случае он уже покинул экран
self.shoot_group.remove(self.player_shot) # если проверка верна, то этот выстрел исключается из группы снимков
# !!!
# ПРОВЕРКА СТОЛКНОВЕНИЙ
if (pygame.sprite.groupcollide(self.shoot_group, self.enemy_group, True, True)):
self.player_points += random.randint(1, 10)
self.points_text = self.font.render("SCORE: " + str(self.player_points), 1, (255,255,255))
# --- установите свое ---------------------------------------> vvvvvvvvvvvvvvvvvvvvv <---
pygame.mixer.Channel(2).play(pygame.mixer.Sound("sounds/enemy_death.wav")) # музыка смерти врага
if (pygame.sprite.groupcollide(self.player_group, self.enemy_group, True, False)):
print(f'\nСтолкновение, новая игра \n') #
Game()
self.game_init = False
pygame.display.update()
Game()
background.jpg
shot.png
player1.png
meteor1.png





