问题描述
嘿,谁能告诉我为什么我没有看到物体从顶部掉下来?在这种情况下,“Münzen、Scheine 和 Sack”。我是 pygame 的新手,也许有一个简单的方法。我的游戏应该是这样的:
行走的人应该抓住掉下来的钱并获得积分。
https://gyazo.com/d2ce52cb54e8658e92ae9e5f3d1e7cca
import random
from pygame.sprite import Sprite
pygame.init()
#display
win = pygame.display.set_mode((900,780))
pygame.display.set_caption("The Collector")
#Laufanimation
walkRight = [pygame.image.load('Assets/R1.png'),pygame.image.load('Assets/R2.png'),pygame.image.load('Assets/R3.png'),pygame.image.load('Assets/R4.png'),pygame.image.load('Assets/R5.png'),pygame.image.load('Assets/R6.png'),pygame.image.load('Assets/R7.png'),pygame.image.load('Assets/R8.png'),pygame.image.load('Assets/R9.png')]
walkLeft = [pygame.image.load('Assets/L1.png'),pygame.image.load('Assets/L2.png'),pygame.image.load('Assets/L3.png'),pygame.image.load('Assets/L4.png'),pygame.image.load('Assets/L5.png'),pygame.image.load('Assets/L6.png'),pygame.image.load('Assets/L7.png'),pygame.image.load('Assets/L8.png'),pygame.image.load('Assets/L9.png')]
#Hintergrund
bg = pygame.image.load('City.jpg')
bg = pygame.transform.scale(bg,(900,780))
#Charakter
char = pygame.image.load('Assets/R1.png')
# Geld
Münzen2 = pygame.image.load("Assets/coin.png")
Schein2 = pygame.image.load("Assets/schein.png")
Sack2 = pygame.image.load("Assets/sack.png")
# Geld
Münzen = pygame.image.load("Assets/coin.png")
Schein = pygame.image.load("Assets/schein.png")
Sack = pygame.image.load("Assets/sack.png")
clock = pygame.time.Clock()
class player():
def __init__(self,x,y,width,height):
self.x = x
self.y = y
self.width = width
self.height = height
self.vel = 20
self.left = False
self.right = False
self.walkCount = 0
self.hitBox = (self.x + 20,self.y,28,60)
def draw(self,win):
if self.walkCount + 1 >= 27:
self.walkCount = 0
if self.left:
win.blit(walkLeft[self.walkCount//3],(self.x,self.y))
self.walkCount += 1
elif self.right:
win.blit(walkRight[self.walkCount//3],self.y))
self.walkCount +=1
else:
win.blit(char,self.y))
self.hitBox = (self.x + 215,self.y + 230,220,70) # NEW
pygame.draw.rect(win,(255,0),self.hitBox,2)
class Laser:
def __init__(self,img):
self.x = x
self.y = y
self.img = img
def draw(self,window):
window.blit(self.img,self.y))
def move(self,vel):
self.y += vel
def off_screen(self,height):
return not(self.y <= height and self.y >= 0)
def collision(self,obj):
return collide(self,obj)
def redrawGameWindow():
win.blit(bg,(0,0))
collector.draw(win)
pygame.display.update()
class Ship:
COOLDOWN = 30
def __init__(self,health=100):
self.x = x
self.y = y
self.health = health
self.ship_img = None
self.laser_img = None
self.lasers = []
self.cool_down_counter = 0
def draw(self,window):
window.blit(self.ship_img,self.y))
for laser in self.lasers:
laser.draw(window)
def move_lasers(self,vel,obj):
self.cooldown()
for laser in self.lasers:
laser.move(vel)
if laser.off_screen(HEIGHT):
self.lasers.remove(laser)
elif laser.collision(obj):
obj.health -= 10
self.lasers.remove(laser)
def cooldown(self):
if self.cool_down_counter >= self.COOLDOWN:
self.cool_down_counter = 0
elif self.cool_down_counter > 0:
self.cool_down_counter += 1
def shoot(self):
if self.cool_down_counter == 0:
laser = Laser(self.x,self.laser_img)
self.lasers.append(laser)
self.cool_down_counter = 1
def get_width(self):
return self.ship_img.get_width()
def get_height(self):
return self.ship_img.get_height()
class Enemy(Ship):
COLOR_MAP = {
"red": (Münzen,Münzen2),"green": (Schein,Schein2),"blue": (Sack,Sack2)
}
def __init__(self,color,health=100):
super().__init__(x,health)
self.ship_img,self.laser_img = self.COLOR_MAP[color]
self.mask = pygame.mask.from_surface(self.ship_img)
def move(self,vel):
self.y += vel
def shoot(self):
if self.cool_down_counter == 0:
laser = Laser(self.x-20,self.laser_img)
self.lasers.append(laser)
self.cool_down_counter = 1
def collide(obj1,obj2):
offset_x = obj2.x - obj1.x
offset_y = obj2.y - obj1.y
return obj1.mask.overlap(obj2.mask,(offset_x,offset_y)) != None
#mainloop
collector = player(200,410,64,64)
run = True
while run:
clock.tick(27)
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
keys = pygame.key.get_pressed()
if keys[pygame.K_LEFT] and collector.x > -180 -collector.width -collector.vel:
collector.x -= collector.vel
collector.left = True
collector.right = False
elif keys[pygame.K_RIGHT] and collector.x < 550 - collector.width - collector.vel:
collector.x += collector.vel
collector.right = True
collector.left = False
else:
collector.right = False
collector.left = False
collector.walkCount = 0
redrawGameWindow()
pygame.quit()````
[1]: https://i.stack.imgur.com/FYFkB.png
解决方法
您似乎将代码复制/粘贴到了一起,所以让我们放弃它并从头开始吧。在我们继续的过程中,请随时查看 documentation 中的一些内容。
首先,我们需要一个主循环来保持我们的游戏运行。我通常从这样的事情开始:
import pygame
RESOLUTION = 800,600
FPS = 60
def main():
pygame.init()
screen = pygame.display.set_mode(RESOLUTION)
dt,clock = 0,pygame.time.Clock()
sprites = pygame.sprite.Group()
while True:
events = pygame.event.get()
for e in events:
if e.type == pygame.QUIT:
return
screen.fill('black')
sprites.update(dt,events)
sprites.draw(screen)
pygame.display.flip()
dt = clock.tick(FPS) / 1000
if __name__ == "__main__":
main()
这将创建一个窗口并管理我们稍后将创建并添加到 sprites
容器的精灵。目前这里没什么可看的:
现在,我们想要一个可以左右移动的玩家。下面是我将如何做到这一点,利用一些 pygame 功能,如 Rect
和 Sprite
类。不涉及魔法。 Sprite
基本上只是一个具有 image
属性(您已经猜到这是要使用的图像)和一个 rect
属性的类,其中包含我们要绘制图像的位置。
这是 Player
类:
TILESIZE = 32
PLAYER_SPEED = 600
class Player(pygame.sprite.Sprite):
def __init__(self,pos,*grps):
super().__init__(*grps)
self.image = pygame.Surface((TILESIZE,TILESIZE))
self.image.fill('dodgerblue')
self.rect = self.image.get_rect(topleft=pos)
def update(self,dt,events):
d = 0
pressed = pygame.key.get_pressed()
if pressed[pygame.K_a]: d -= 1
if pressed[pygame.K_d]: d += 1
self.rect.move_ip(d * dt * PLAYER_SPEED,0)
display_rect = pygame.display.get_surface().get_rect()
self.rect.clamp_ip(display_rect)
现在让我们在游戏中添加一个 Player
:
...
sprites = pygame.sprite.Group()
Player((300,500),sprites)
while True:
...
请注意,您不必手动绘制/blit 任何内容。给我们的类一个 image
和 rect
属性,子类 Sprite
,将实例添加到 Group
,并在这个组上调用 draw
。
现在是掉落的硬币和其他东西。我们应该为他们创建一个类,像这样:
from random import choice
FALLING_SPEED = 400
class FallingStuff(pygame.sprite.Sprite):
def __init__(self,TILESIZE))
self.image.fill(choice(['red','yellow','green']))
self.rect = self.image.get_rect(topleft=pos)
def update(self,events):
self.rect.move_ip(0,FALLING_SPEED * dt)
display_rect = pygame.display.get_surface().get_rect()
if self.rect.top > display_rect.bottom:
self.kill()
在您的最终游戏中,您可以轻松地将单色 image
替换为您从文件加载的图像。在这里,我只是随机选择红色、黄色或绿色。
正如您已经猜到的,我们游戏对象的所有行为都在精灵类的 update
方法中。 FallingStuff
只是向下移动它的 rect
并在它离开屏幕时杀死自己。 'killing' 作为 sprite 只是意味着它将自己从它的所有 Group
容器中移除。使用这些而不是普通列表的另一个原因。
当然,我们要生成多个下落物体。有很多方法可以做到这一点,但让我们使用 pygame 的 time
模块来创建一个事件,因为为什么不:
from random import randint
...
CREATE_STUFF = pygame.USEREVENT + 1
pygame.time.set_timer(CREATE_STUFF,randint(1000,2000),True)
while True:
events = pygame.event.get()
for e in events:
if e.type == pygame.QUIT:
return
if e.type == CREATE_STUFF:
pygame.time.set_timer(CREATE_STUFF,True)
FallingStuff((randint(50,550),-TILESIZE),sprites)
screen.fill('black')
sprites.update(dt,events)
sprites.draw(screen)
pygame.display.flip()
dt = clock.tick(FPS) / 1000
剩下的唯一事情就是检查我们是否能抓住其中一个坠落的物体。
完整代码如下:
import pygame
import pygame.freetype
from random import choice,randint
RESOLUTION = 800,600
FPS = 60
TILESIZE = 32
PLAYER_SPEED = 600
FALLING_SPEED = 400
class Player(pygame.sprite.Sprite):
def __init__(self,falling_stuff,TILESIZE))
self.image.fill('dodgerblue')
self.rect = self.image.get_rect(topleft=pos)
self.falling_stuff = falling_stuff
self.score = 0
def update(self,0)
display_rect = pygame.display.get_surface().get_rect()
self.rect.clamp_ip(display_rect)
for stuff in pygame.sprite.spritecollide(self,self.falling_stuff,True):
self.score += 1
class FallingStuff(pygame.sprite.Sprite):
def __init__(self,FALLING_SPEED * dt)
display_rect = pygame.display.get_surface().get_rect()
if self.rect.top > display_rect.bottom:
self.kill()
def main():
pygame.init()
screen = pygame.display.set_mode(RESOLUTION)
dt,pygame.time.Clock()
sprites = pygame.sprite.Group()
falling_stuff = pygame.sprite.Group()
player = Player((300,sprites)
font = pygame.freetype.SysFont('Arial',54)
CREATE_STUFF = pygame.USEREVENT + 1
pygame.time.set_timer(CREATE_STUFF,True)
while True:
events = pygame.event.get()
for e in events:
if e.type == pygame.QUIT:
return
if e.type == CREATE_STUFF:
pygame.time.set_timer(CREATE_STUFF,True)
FallingStuff((randint(50,sprites)
screen.fill('black')
font.render_to(screen,(20,20),f'Score: {player.score}','white')
sprites.update(dt,events)
sprites.draw(screen)
pygame.display.flip()
dt = clock.tick(FPS) / 1000
if __name__ == "__main__":
main()
动画和命中框也是如此:
import pygame
import pygame.freetype
import os
from random import choice,randint
from itertools import cycle
RESOLUTION = 800,600
FPS = 60
TILESIZE = 32
PLAYER_SPEED = 300
FALLING_SPEED = 400
ANIM_THRESHOLD = 0.05
def load_images(dir):
path = os.path.dirname(os.path.realpath(__file__))
path = os.path.join(path,dir)
for f in os.listdir(path):
yield pygame.image.load(os.path.join(path,f)).convert_alpha()
class Player(pygame.sprite.Sprite):
def __init__(self,*grps):
super().__init__(*grps)
idle_images = list(load_images('1-Idle'))
run_images = list(load_images('2-Run'))
self.images = {
'IDLE': {
'RIGHT': cycle(idle_images),'LEFT': cycle(pygame.transform.flip(s,True,False) for s in idle_images)
},'RUN': {
'RIGHT': cycle(run_images),False) for s in run_images)
}
}
self.state = 'IDLE'
self.direction = 'RIGHT'
self.image = next(self.images['IDLE']['RIGHT'])
self.animation_counter = 0
self.rect = self.image.get_rect(topleft=pos)
self.falling_stuff = falling_stuff
self.score = 0
self.hitbox = pygame.Rect(0,30,20)
self.hitbox.center = self.rect.center
self.hitbox.move_ip(-10,-10)
def update_image(self,new_state):
self.animation_counter += dt
if self.animation_counter > ANIM_THRESHOLD or self.state != new_state:
self.image = next(self.images[new_state][self.direction])
self.animation_counter = 0
def update(self,0)
display_rect = pygame.display.get_surface().get_rect()
self.rect.clamp_ip(display_rect)
if d == 1:
new_state = 'RUN'
self.direction = 'RIGHT'
if d == -1:
new_state = 'RUN'
self.direction = 'LEFT'
if d == 0:
new_state = 'IDLE'
for stuff in self.falling_stuff:
if self.hitbox.colliderect(stuff.rect):
stuff.kill()
self.score += 1
self.update_image(dt,new_state)
self.state = new_state
self.hitbox.center = self.rect.center
self.hitbox.move_ip(10 if self.direction == 'LEFT' else -10,-10)
pygame.draw.rect(pygame.display.get_surface(),'red',self.hitbox,2)
class FallingStuff(pygame.sprite.Sprite):
def __init__(self,'white')
sprites.draw(screen)
sprites.update(dt,events)
pygame.display.flip()
dt = clock.tick(FPS) / 1000
if __name__ == "__main__":
main()
,
首先,您应该考虑使用“ae、oe、ue”或仅使用英文翻译而不是“ä、ö、ü”,这可能会导致一些问题。另外,你为什么不包括pygame? 其次,尽量不要对窗口大小使用固定值,如果以后要更改它,则必须更改几个值,并且忘记一个值时很容易遇到问题。我建议您使用宽度和高度变量,您可以稍后更改。
但是对于您的具体问题: 我认为你没有看到任何物体坠落的原因是没有物体。实际运行的代码部分在 while 循环中,只要我没有遗漏任何东西,就不会出现任何关于掉落物体的信息,也不会关于它们掉落的信息(任何类型的加速度或速度)。 此外,我强烈建议(如“oskros”的评论已经说过)在询问之前测试您的代码。这也是编程的一个重要部分,可以像这样完成,例如: 你进入每个函数并在那里写一个“打印”语句,所以你知道这个函数已经运行(通过控制台上的输出)。如果没有运行,请尝试查看它应该运行的点并从该点继续修复。 您基本上可以将这种技术应用于任何调试,stackoverflow 主要用于询问更具体的问题,而不是“为什么这不起作用,您能修复我的代码吗?” (至少对于整个程序而言)
,import pygame.freetype
from random import choice,randint
pygame.init()
RESOLUTION = 900,780
FPS = 60
TILESIZE = 32
PLAYER_SPEED = 600
FALLING_SPEED = 400
coin = pygame.image.load('coin.png')
coin = pygame.transform.scale(coin,(60,60))
sack = pygame.image.load('sack.png')
sack = pygame.transform.scale(sack,60))
money = pygame.image.load('schein.png')
money = pygame.transform.scale(money,60))
char = pygame.image.load ("L1.png")
walkRight = [pygame.image.load('Assets/R1.png'),pygame.image.load('Assets/R2.png'),pygame.image.load('Assets/R3.png')]
bg = pygame.image.load('City.jpg')
bg = pygame.transform.scale(bg,(900,780))
pygame.mixer.music.load('Music/Titel.mp3')
pygame.mixer.music.play(0)
class Player(pygame.sprite.Sprite):
def __init__(self,*grps):
super().__init__(*grps)
self.image = char
self.rect = self.image.get_rect(topleft=pos)
self.falling_stuff = falling_stuff
self.score = 0
def update(self,events):
d = 0
pressed = pygame.key.get_pressed()
if pressed[pygame.K_LEFT]: d -= 1
if pressed[pygame.K_RIGHT]: d += 1
self.rect.move_ip(d * dt * PLAYER_SPEED,*grps):
super().__init__(*grps)
self.image = choice([coin,sack,money])
self.rect = self.image.get_rect(topleft=pos)
def update(self,pygame.time.Clock()
sprites = pygame.sprite.Group()
falling_stuff = pygame.sprite.Group()
player = Player((400,700),sprites)
font = pygame.freetype.SysFont('ComicSans',70)
CREATE_STUFF = pygame.USEREVENT + 1
pygame.time.set_timer(CREATE_STUFF,sprites)
screen.blit(bg,(0,0))
font.render_to(screen,(30,30),events)
sprites.draw(screen)
pygame.display.flip()
dt = clock.tick(FPS) / 1000
if __name__ == "__main__":
main()