有了下面的代码,什么是实现游戏状态以控制级别的最简单和最简单的方法?如果我想从标题屏幕开始,然后加载一个级别,并在完成后继续下一个级别?如果有人能解释最简单的方法,那就太好了!
import pygame
from pygame import *
WIN_WIDTH = 1120 - 320
WIN_HEIGHT = 960 - 320
HALF_WIDTH = int(WIN_WIDTH / 2)
HALF_HEIGHT = int(WIN_HEIGHT / 2)
DISPLAY = (WIN_WIDTH, WIN_HEIGHT)
DEPTH = 0
FLAGS = 0
CAMERA_SLACK = 30
def main():
global level
pygame.init()
screen = pygame.display.set_mode(DISPLAY, FLAGS, DEPTH)
pygame.display.set_caption("ABCDEFGHIJKLMNOPQRSTUVWXYZ")
timer = pygame.time.Clock()
level = 0
bg = Surface((32,32))
bg.convert()
bg.fill(Color("#0094FF"))
up = left = right = False
entities = pygame.sprite.Group()
player = Player(32, 32)
enemy = Enemy(32,32)
platforms = []
x = 0
y = 0
if level == 0:
level = [
" ",
" ",
" ",
" ",
" ",
" ",
" ",
" ",
" ",
" ",
" ",
" ",
" ",
" ",
" ",
" E ",
" PPPPPPPPPPPPPPPP",
" PPPPPPPPPPPPPPPP",
" PPPPPPPPPPPPPPPP",
" PPPPP PPPPPPPPPPPPPPPP",
" PPPPPPPPPPPPPPPP",
" PPPP P",
" PPPP P",
" PPPP PPPPPPP",
" PPPPPPPPPP PPPPPPP",
" PPPP PPPPPPP",
" PPPP PPPP PPPPPPP",
" PPPP PPPPPPP",
" PPPP PPPPPPP",
" PPPP PPPPPPP",
"PPPPP PPPP PPPPPPP",
"PPP PPPP PPPPPPP",
"PPP PPPP PPPPPPP",
"PPP PPPP PPPPPPP",
"PPP PPPPP PPPP PPPPPPP",
"PPP PPPP",
"PPP PPPP",
"PPP PPPP",
"PPP PPPPPPPPPPPPPPPPPP",
"PPP PPPPPPPPPPPPPPPPPP",
"PPPPPPPPPPPPPPP PPPPPPPPPPPPPPPPPP",
"PPPPPPPPPPPPPPP PPPPPPPPPPPPPPPPPP",
"PPPPPPPPPPPPPPP PPPPPPPPPPPPPPPPPP",
"PPPPPPPPPPPPPPP PPPPPPPPPPPPPPPPPP",
"PPPPPPPPPPPPPPP PPPPPPPPPPPPPPPPPP",]
#background = pygame.image.load("Untitled.png")
total_level_width = len(level[0]) * 32
total_level_height = len(level) * 32
# build the level
for row in level:
for col in row:
if col == "P":
p = Platform(x, y)
platforms.append(p)
entities.add(p)
if col == "E":
e = ExitBlock(x, y)
platforms.append(e)
entities.add(e)
x += 32
y += 32
x = 0
camera = Camera(complex_camera, total_level_width, total_level_height)
entities.add(player)
entities.add(enemy)
while 1:
timer.tick(60)
for e in pygame.event.get():
if e.type == QUIT: raise SystemExit, "QUIT"
if e.type == KEYDOWN and e.key == K_ESCAPE:
raise SystemExit, "ESCAPE"
if e.type == KEYDOWN and e.key == K_UP:
up = True
if e.type == KEYDOWN and e.key == K_LEFT:
left = True
if e.type == KEYDOWN and e.key == K_RIGHT:
right = True
if e.type == KEYUP and e.key == K_UP:
up = False
if e.type == KEYUP and e.key == K_LEFT:
left = False
if e.type == KEYUP and e.key == K_RIGHT:
right = False
# draw background
for y in range(20):
for x in range(25):
screen.blit(bg, (x * 32, y * 32))
# draw background
#screen.blit(background, camera.apply((0,0)))
#draw entities
for e in entities:
screen.blit(e.image, camera.apply(e))
# update player, update camera, and refresh
player.update(up, left, right, platforms)
enemy.update(platforms)
camera.update(player)
pygame.display.flip()
class Camera(object):
def __init__(self, camera_func, width, height):
self.camera_func = camera_func
self.state = Rect(0, 0, width, height)
def apply(self, target):
try:
return target.rect.move(self.state.topleft)
except AttributeError:
return map(sum, zip(target, self.state.topleft))
def update(self, target):
self.state = self.camera_func(self.state, target.rect)
def complex_camera(camera, target_rect):
l, t, _, _ = target_rect
_, _, w, h = camera
l, t, _, _ = -l + HALF_WIDTH, -t +HALF_HEIGHT, w, h
l = min(0, l) # stop scrolling left
l = max(-(camera.width - WIN_WIDTH), l) # stop scrolling right
t = max(-(camera.height-WIN_HEIGHT), t) # stop scrolling bottom
return Rect(l, t, w, h)
class Entity(pygame.sprite.Sprite):
def __init__(self):
pygame.sprite.Sprite.__init__(self)
class Player(Entity):
def __init__(self, x, y):
Entity.__init__(self)
self.xvel = 0
self.yvel = 0
self.onGround = False
self.image = Surface((32,32))
self.image.fill(Color("#0000FF"))
self.image.convert()
self.rect = Rect(200, 1200, 32, 32)
def update(self, up, left, right, platforms):
if self.rect.top > 1440 or self.rect.top < 0:
main()
if self.rect.left > 1408 or self.rect.right < 0:
main()
if up:
if self.onGround:
self.yvel = 0
self.yvel -= 10 # only jump if on the ground
if left:
self.xvel = -10
if right:
self.xvel = 10
if not self.onGround:
self.yvel += 0.3 # only accelerate with gravity if in the air
if self.yvel > 80: self.yvel = 80 # max falling speed
if not(left or right):
self.xvel = 0
self.rect.left += self.xvel # increment in x direction
self.collide(self.xvel, 0, platforms) # do x-axis collisions
self.rect.top += self.yvel # increment in y direction
self.onGround = False; # assuming we're in the air
self.collide(0, self.yvel, platforms) # do y-axis collisions
def collide(self, xvel, yvel, platforms):
for p in platforms:
if pygame.sprite.collide_rect(self, p):
if isinstance(p, ExitBlock):
pygame.event.post(pygame.event.Event(QUIT))
if xvel > 0: self.rect.right = p.rect.left
if xvel < 0: self.rect.left = p.rect.right
if yvel > 0:
self.rect.bottom = p.rect.top
self.onGround = True
if yvel < 0:
self.rect.top = p.rect.bottom
class Enemy(Entity):
def __init__(self, x, y):
Entity.__init__(self)
self.yVel = 0
self.xVel = 0
self.image = Surface((32,32))
self.image.fill(Color("#00FF00"))
self.image.convert()
self.rect = Rect(300, 1200, 32, 32)
self.onGround = False
self.right_dis = False
def update(self, platforms):
if not self.onGround:
self.yVel += 0.3
if self.rect.left == 96:
self.right_dis = False
if self.rect.right == 480:
self.right_dis = True
if not self.right_dis:
self.xVel = 2
if self.right_dis:
self.xVel = -2
self.rect.left += self.xVel # increment in x direction
self.collide(self.xVel, 0, platforms) # do x-axis collisions
self.rect.top += self.yVel # increment in y direction
self.onGround = False; # assuming we're in the air
self.collide(0, self.yVel, platforms) # do y-axis collisions
def collide(self, xVel, yVel, platforms):
for p in platforms:
if pygame.sprite.collide_rect(self, p):
if xVel > 0: self.rect.right = p.rect.left
if xVel < 0: self.rect.left = p.rect.right
if yVel > 0:
self.rect.bottom = p.rect.top
self.onGround = True
if yVel < 0:
self.rect.top = p.rect.bottom
class Platform(Entity):
def __init__(self, x, y):
Entity.__init__(self)
#self.image = Surface([32, 32], pygame.SRCALPHA, 32) #makes blocks invisible for much better artwork
self.image = Surface((32,32)) #makes blocks visible for building levels
self.image.convert()
self.rect = Rect(x, y, 32, 32)
def update(self):
pass
class ExitBlock(Platform):
def __init__(self, x, y):
Platform.__init__(self, x, y)
self.image = pygame.image.load("end.png")
if __name__ == "__main__":
main()
首先,让我们摆脱这些丑陋的if块:
我们可以重写为:
这个稍后会派上用场的。
回到主题:我们想要的是一堆不同的场景。每个场景都必须负责自己的屏幕渲染和事件处理。
让我们尝试将现有代码提取到游戏场景中,以便以后可以添加其他场景。我们首先创建一个空的
Scene
类,它将是场景的基类:我们的计划是覆盖每个子类中的每个方法,因此我们在基类中提升
NotImplementedError
s,这样我们很容易发现是否忘记这样做(我们也可以使用ABCs,但让它保持简单)。现在让我们将与运行游戏状态相关的所有内容(基本上是所有内容)放入一个新的
GameScene
类中。还不是完美的,但是一个好的开始。与实际游戏性相关的所有内容都被提取到自己的类中。有些变量必须是实例变量,因此必须通过
self
访问它们。现在我们需要改变
main
-函数来实际使用这个类:注意,我改变了两个小东西:我首先使用
pygame.event.get(QUIT)
来获得可能的QUIT
-事件,因为这是我们在主循环中唯一感兴趣的事件。所有其他事件都直接传递到当前场景:scene.handle_events(pygame.event.get())
。在这一点上,我们可以考虑将一些类解压到自己的文件中,但是让我们继续。
让我们创建一个标题菜单:
这只是显示一个绿色背景和一些文字。如果玩家按空格,我们希望开始第一个关卡。注意这一行:
在这里,我将参数
0
传递给GameScene
类,因此让我们对其进行更改,使其接受此参数:行
level = 0
可以删除,正如您已经猜到的。那是什么
self.manager
?它只是一个小助手类,为我们管理场景。它从标题scene开始,并将每个scenes
manager
字段设置为自身,以允许更改当前场景。如何实现这样的场景管理器有很多可能性,这是最简单的方法。缺点是每一个场景都必须知道它后面是哪一个场景,但这现在不应该打扰我们。让我们使用新的
SceneMananger
:直截了当。让我们快速添加第二个级别和一个胜负屏幕,我们就完成了。
下面是完整的代码。注意对
Player
类的更改:它不再调用main
函数,而是调用场景中的方法,以指示播放机到达出口或死亡。同时,我改变了玩家和敌人的位置。现在,指定实体在级别中的显示位置。E、 g.
Player(5, 40)
将在关卡第5列第40行创建播放器。作为奖励,敌人要进行正确的碰撞检测。我将级别的描述提取到一个名为
levels
的字典中,因此可以根据需要轻松地更改和添加级别(稍后,您可能希望每个级别有一个文件,因此这是一个好的开始)。它可以被扩展以保持玩家的起始位置,但是你也可以创建一个特殊的平铺,比如*
用于起始位置,以及E
用于级别描述中的敌人。我还制作了一个游戏,其中有游戏菜单、关卡菜单、加载部件和播放部件。
我的做法是在主游戏循环中,
我通过一系列elif语句来确定游戏的“模式”,并执行相应的操作。
看起来效果很好,我建议你也试试。
我意识到我的代码很长,但是如果你转到它所说的
#game loop
(使用ctrl+f来找到它),你可以看到elif来确定模式。希望这有帮助。相关问题 更多 >
编程相关推荐