在 pygame 中未检测到碰撞
我不知道为什么,但在我的游戏中没有检测到碰撞.这是一个小行星风格的游戏,我希望子弹摧毁小行星,当飞船被一颗子弹击中时游戏结束,但它们相互穿过而没有做任何事情.
I don't know why but collisions aren't being detected in my game. Its an asteroids style game and I want the bullets to destroy the asteroids, and the game to end when the ship gets hit by one, but they're passing through each other without doing any of that.
这是我的代码:
import pygame
from math import sin, cos, pi
from random import randint
scr_width = 800
scr_height = 600
window = pygame.display.set_mode((scr_width, scr_height))
pygame.display.set_caption("Asteroids")
clock = pygame.time.Clock()
space_img = pygame.image.load("sprites/space.jpg")
red = (255, 0, 0)
class Ship:
def __init__(self, x, y):
self.x = x
self.y = y
self.width = 0
self.vel = 0
self.vel_max = 12
self.angle = 0
self.hitbox = (self.x, self.y, 10, 10)
self.ship_img = pygame.image.load("sprites/ship_off.png")
self.ship_img_copy = pygame.transform.rotate(self.ship_img, self.angle)
def draw(self):
self.ship_img = pygame.image.load("sprites/ship_off.png")
self.ship_img_copy = pygame.transform.rotate(self.ship_img, self.angle)
window.blit(self.ship_img_copy,
(self.x - (self.ship_img_copy.get_width()) / 2, self.y - (self.ship_img_copy.get_height()) / 2))
keys = pygame.key.get_pressed()
if keys[pygame.K_w]:
self.ship_img = pygame.image.load("sprites/ship_on.png")
self.ship_img_copy = pygame.transform.rotate(self.ship_img, self.angle)
window.blit(self.ship_img_copy,
(self.x - (self.ship_img_copy.get_width()) / 2, self.y - (self.ship_img_copy.get_height()) / 2))
# collision stuff
self.mask = pygame.mask.from_surface(self.ship_img_copy)
self.rect = pygame.Rect(self.x - (self.ship_img_copy.get_width()) / 2,
self.y - (self.ship_img_copy.get_height()) / 2,
self.ship_img_copy.get_width(), self.ship_img_copy.get_height())
def move(self):
keys = pygame.key.get_pressed()
# todo acceleration and thrust mechanics
if keys[pygame.K_w]:
self.vel = min(self.vel + 1, self.vel_max)
elif self.vel > 0:
self.vel = self.vel - 0.4
if keys[pygame.K_a]:
self.angle += 7
if keys[pygame.K_d]:
self.angle -= 7
self.x += self.vel * cos(self.angle * (pi / 180) + (90 * pi / 180))
self.y -= self.vel * sin(self.angle * (pi / 180) + 90 * (pi / 180))
# So that if it leaves one side it comes from the other
if self.y < 0:
self.y = (self.y - self.vel) % 600
elif self.y > 600:
self.y = (self.y + self.vel) % 600
elif self.x < 0:
self.x = (self.x - self.vel) % 800
elif self.x > 800:
self.x = (self.x + self.vel) % 800
class Asteroid:
def __init__(self):
self.ang_change = randint(1, 5)
self.ang = randint(0, 90) * (pi / 180)
y_values = [1, 599]
self.sx = randint(0, 800)
self.sy = y_values[randint(0, 1)]
# If object spawns from the top, it moves down instead of moving up and de-spawning immediately
if self.sy == y_values[0]:
self.neg = -1
else:
self.neg = 1
self.speed = randint(5, 10)
self.ang += self.ang_change
self.asteroid_angle = randint(0, 80)
self.asteroid_img = pygame.image.load("sprites/asteroid.png")
self.asteroid_copy = pygame.transform.rotate(self.asteroid_img, self.ang)
def generate(self):
self.ang += self.ang_change
self.asteroid_img = pygame.image.load("sprites/asteroid.png")
self.asteroid_copy = pygame.transform.rotate(self.asteroid_img, self.ang)
window.blit(self.asteroid_copy,
(self.sx - (self.asteroid_copy.get_width()) / 2, self.sy - (self.asteroid_copy.get_height()) / 2))
# collision stuff
self.mask = pygame.mask.from_surface(self.asteroid_copy)
self.rect = pygame.Rect(self.sx - (self.asteroid_copy.get_width()) / 2,
self.sy - (self.asteroid_copy.get_height()) / 2,
self.asteroid_copy.get_width(), self.asteroid_copy.get_height())
class Projectiles:
def __init__(self, x, y, angle):
self.x = x
self.y = y
self.angle = angle
self.vel = 20
self.bullet_body = pygame.image.load("sprites/bullet.png")
def draw(self):
self.bullet_body = pygame.image.load("sprites/bullet.png")
# collision stuff
self.rect = pygame.Rect(self.x - (self.bullet_body.get_width()) / 2,
self.y - (self.bullet_body.get_height()) / 2, 5, 5)
window.blit(self.bullet_body, (self.x - 2, self.y))
self.mask = pygame.mask.from_surface(self.bullet_body)
def redraw():
window.blit(space_img, (0, 0))
ship.draw()
for asteroid in asteroids:
asteroid.generate()
for bullet in bullets:
bullet.draw()
pygame.display.update()
# collision stuff
def collisions():
asteroids = pygame.sprite.Group()
bullets = pygame.sprite.Group()
if pygame.sprite.spritecollide(ship, asteroids, True, pygame.sprite.collide_mask):
print("hit")
pygame.quit()
pygame.sprite.groupcollide(asteroids, bullets, True, True, pygame.sprite.collide_mask)
# main loop
run = True
ship = Ship(400, 300)
next_fire = pygame.time.get_ticks() + 400
bullets = []
asteroids = []
while run:
clock.tick(60)
keys = pygame.key.get_pressed()
pygame.time.delay(35)
# collision stuff
collisions()
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
if keys[pygame.K_SPACE]:
if len(bullets) < 11 and pygame.time.get_ticks() >= next_fire:
bullets.append(
Projectiles(round(ship.x + ship.width - 6.5 // 2), round(ship.y + ship.width - 6.5 // 2), ship.angle))
next_fire = pygame.time.get_ticks() + 400
for bullet in bullets:
if 800 > bullet.x > 0 and 600 > bullet.y > 0:
bullet.x += bullet.vel * cos(bullet.angle * (pi / 180) + 90 * (pi / 180))
bullet.y -= bullet.vel * sin(bullet.angle * (pi / 180) + 90 * (pi / 180))
else:
bullets.pop(bullets.index(bullet))
# To limit the number of asteroids on screen
if len(asteroids) < 5:
asteroids.append(Asteroid())
for asteroid in asteroids:
if 805 > asteroid.sx > 0 and 605 > asteroid.sy > 0:
asteroid.sx += asteroid.speed * cos(asteroid.asteroid_angle * (pi / 180) + 90 * (pi / 180))
asteroid.sy -= asteroid.speed * sin(asteroid.asteroid_angle * (pi / 180) + 90 * (pi / 180)) * asteroid.neg
if asteroid.sx < 0:
asteroid.sx = (asteroid.sx - asteroid.speed) % 805
elif asteroid.sx > 805:
asteroid.sx = (asteroid.sx + asteroid.speed) % 805
else:
asteroids.pop(asteroids.index(asteroid))
window.fill((0, 0, 0))
ship.move()
redraw()
pygame.quit()
是我无法为碰撞制作单独的函数,还是我错过了其他东西?
Is it that I can't make a seperate function for collisions, or have I missed something else?
我无法测试代码,但通常问题是碰撞的函数使用来自 self.rect
的值,但您不使用它们但是 self.x
和 self.y
保持位置.
I couldn't test code but usually problem is that collision's function use values from self.rect
but you don't use them but self.x
and self.y
to keep position.
你应该在 __init__
self.rect = self.image.get_rect()
self.rect.center = (x, y)
以后你可以添加到self.rect.x
和self.rect.y
,它会自动计算
and later you can add to self.rect.x
and self.rect.y
and it will automatically calculate position for
blit(self.image, self.rect)
以及与其他物体碰撞
self.rect.colliderect(other.rect)
或在 event.MOUSEBUTTONDOWN
self.rect.collidepoint(event.pos)
测试对象是否被点击(即按钮).
to test if object was clicked (ie. button).
如果你想使用pygame Group
If you want to use pygame Group
asteroids = pygame.sprite.Group()
bullets = pygame.sprite.Group()
那么你不应该在 collisions()
中创建它们,而是在开始而不是列表
then you shouldn't create them inside collisions()
but at start instead of lists
asteroids = []
bullets = []
并且您应该将对象添加到组而不是附加到列表中.
and you should add objects to groups instead of appending to lists.
asteroids.add(Asteroid())
你甚至可以在不使用for
-loop
and you can even run function for all objects without using for
-loop
asteroids.draw()