Python3.13实战:手把手教你造pygame游戏2、游戏内容_python3.13游戏
参考文献
Pygame教程07:键盘常量+键盘事件的2种捕捉方式:Pygame教程07:键盘常量+键盘事件的2种捕捉方式-CSDN博客
(建议结合pygame教程来看)
(别问为什么3.11变3.13了)
(正文:
在Python3.13实战:手把手教你造pygame游戏1、游戏框架中,我们写出了我们游戏的框架,而这次,游戏内容也将被我们编写出来!
1、设计坦克类
首先,我们需要设计一个坦克类。这是一个精灵(Sprite)类。
使用Sprite类派生新类时需要分配Sprite.image和Sprite.rect属性并添加Sprite.update()方法。初始设定项可以添加任何数量的组(Group)实例。当派生Sprite类的子类时,我们要确保在将Sprite类添加到组之前已调用基础初始设定项。(如果你想要提升画质,可以用self.image = pygame.Surface([width, height],flags=pygame.HWSURFACE))
class Tank(pygame.sprite.Sprite) def __init__(self, color, width, height): # 调用父类 (Sprite) 构造函数 pygame.sprite.Sprite.__init__(self) self.image = pygame.Surface([width, height]) self.image.fill(color) self.rect = self.image.get_rect()
同时,我们定义一个玩家和2个敌人1个队友
player = Tank(\"green\", 20, 20)player2 = Tank(\"red\", 20, 20)player3 = Tank(\"blue\", 20, 20)player4 = Tank(\"white\", 20, 20)
然后转到while循环
sn.blit(player.image, (0, 0))sn.blit(player2.image, (20, 0))sn.blit(player3.image, (0, 20))sn.blit(player4.image, (20, 20))#第二个参数是坐标可以改

2、分组
但是我们设计完后,如何判断哪些是敌人,哪些是队友呢?
我们需要组,来干一些事情。
第一件,也是最重要的事情,是快速简单地分类精灵。这可以让我们快速的操作大部分符合条件的精灵们。
添加和删除组内地精灵是一个非常快速的操作,比使用列表存储所有内容要快。因此,您可以非常有效地更改组内成员关系。组可以快速地让游戏对象工作。你可以将精灵们添加到一个单独的组中,而不是跟踪一些属性。
我们可以创建一个组如“enemy”,当我们需要访问所有敌人时,我们已经有了一个敌人组,而不是遍历所有敌人们。之后游戏可以添加多个敌人,而不是添加更多的“sn.blit……”,我们可以轻松地将他们添加到不同的组或每个玩家。
同样,需要记住的是,从组中添加和删除精灵是一种非常快速的操作。最好添加许多组来包含和组织你的游戏对象。
首先我们可以用pygame.sprite.Group()创建组,如全体游戏对象,来更好操作sn.bilt操作。
themall = pygame.sprite.Group(player, player2, player3, player4)
但是,我们的sn.blit操作怎么运行呢?
答案很简单,组有一个方法叫做update,可以调用成员update,而且不限参数,于是我们就可以传进一个sn,进行blit操作。
重写Tank:
class Tank(pygame.sprite.Sprite): pos = [] # 加入位置来绘制 def __init__(self, color, width, height, posi): # 调用父类 (Sprite) 构造函数 pygame.sprite.Sprite.__init__(self) self.image = pygame.Surface([width, height],flags=pygame.HWSURFACE) self.image.fill(color) self.rect = self.image.get_rect() self.pos = posi def update(self, screen): screen.blit(self.image, self.pos)
由于构造函数更改,初始化代码也要更改。(这里调整了位置)
player = Tank(\"green\", 20, 20, [0,0])player2 = Tank(\"red\", 20, 20, [0,20])player3 = Tank(\"blue\", 20, 20, [20,0])player4 = Tank(\"white\", 20, 20, [20,20])
回到主循环,把刚刚一大串sn.blit改为themall.update(sn) 。
w = Truewhile w: for event in pygame.event.get(): if event.type == pygame.QUIT: w = False break themall.update(sn) pygame.display.flip()pygame.quit()

3、人机移动以及按键移动
1、人机移动
人机移动,我们仔细想一想,是不是可以依靠random?
其实,如果用random会抖来抖去,还要加修正(如sin,cos)使得它更加平滑。
但是首先先下载numpy。
pip install numpy
接着把它导入进去。
# 放在首行import numpy as n # 我们定义n是numpy的别名
然后,自己搞一个修正函数,我这里用的是,你可以用自己的。但是,为了保证方向随机,可以再次使用随机数。
x是1~10的随机数。
好了,那怎么让敌人移动呢?
我们回到Tank类的update,将它修改一下,加入一个参数叫flag,这样可以区分是要绘制还是移动。
由于以后会有多个类型的flag,我们用3.10的新关键字match...case...。
def update(self, screen, flag): match flag: case \"show\": screen.blit(self.image, self.pos) case \"move\": x = random.random() * 10 dx = n.sin(x * 1.14514)*1.14514 dy = n.cos(x * 1.14514)*1.14514 self.pos[0] += round((random.random()- 0.5) * dx) self.pos[1] += round((random.random()- 0.5) * dy)
也要把while循环中的调用改一下
然后,添加一个组表示人机。
computer = pygame.sprite.Group(player2, player3, player4)
在while循环中,加入这行代码:
computer.update(sn, \"move\")
这时,人机就会移动了。
为了方便分组,我又调整了位置。
player = Tank(\"green\", 20, 20, [0,100])player2 = Tank(\"red\", 20, 20, [0,360])player3 = Tank(\"blue\", 20, 20, [360,100])player4 = Tank(\"white\", 20, 20, [360,360])
诶?不是,你怎么跑出地图了?快回来!
神马惊天比优季!!!!!!
哎呀,精灵跑出地图了。不过我们并不用担心,有了numpy,什么都不是难题。我们需要用到n.clip函数,它需要传递一个ndarray、最小值和最大值。我们地图是400×400大小,于是,我们可以写下如下代码:
temp = n.array(self.pos)self.pos = n.clip(temp,0,380).tolist()
这里,我们定义了temp变量,并将它的每个元素都钳制在了的区间,使得精灵跑不出地图。
将其添加到update的控制移动代码中。
2、玩家按下按键时移动
在此之前,我们做个小小的改动。
在while循环中,再加入一个事件处理。
if event.type == pygame.KEYDOWN: match event.key: case pygame.K_ESCAPE: w = False break
这样就可以按下escape键时退出。
不过,我们的按键处理,用的可不是这种方法。
pygame.key.get_pressed是一个用于检测按键是否按下的函数,检测的不是刚刚点下而是长按,所以,拿它做,刚好合适。
定义变量:
kb = pygame.key.get_pressed()
检测:
if kb[pygame.K_w]: player.move(0,-0.05)if kb[pygame.K_s]: player.move(0,0.05)if kb[pygame.K_a]: player.move(-0.05,0)if kb[pygame.K_d]: player.move(0.05,0)
对了,还得加个move方法:
def move(self,x,y): self.pos[0] += x self.pos[1] += y
我们来试试:
神马惊天比优季!!!!!!
算了,抄代码。
temp = n.array(self.pos)self.pos = n.clip(temp,0,380).tolist()
制作完成!
终于做完了!!!!!!!!
现在移动正常,就来看源代码和效果图吧!!!
import pygameimport randomimport numpy as npygame.init()class Tank(pygame.sprite.Sprite): pos = [] def __init__(self, color, width, height, posi): # 调用父类 (Sprite) 构造函数 pygame.sprite.Sprite.__init__(self) self.image = pygame.Surface([width, height],flags=pygame.HWSURFACE) self.image.fill(color) self.rect = self.image.get_rect() self.pos = posi def move(self,x,y): self.pos[0] += x self.pos[1] += y temp = n.array(self.pos) self.pos = n.clip(temp,0,380).tolist() def update(self, screen, flag): match flag: case \"show\": screen.blit(self.image, self.pos) case \"move\": x = random.random() * 10 dx = n.sin(x * 1.14514)*1.14514 dy = n.cos(x * 1.14514)*1.14514 self.pos[0] += round((random.random()- 0.5) * dx) self.pos[1] += round((random.random()- 0.5) * dy) temp = n.array(self.pos) self.pos = n.clip(temp,0,380).tolist()sn = pygame.display.set_mode((400,400))sn.fill((127,127,127))player = Tank(\"green\", 20, 20, [0,100])player2 = Tank(\"red\", 20, 20, [0,360])player3 = Tank(\"blue\", 20, 20, [360,100])player4 = Tank(\"white\", 20, 20, [360,360])themall = pygame.sprite.Group(player, player2, player3, player4)computer = pygame.sprite.Group(player2, player3, player4)pygame.display.set_caption(\'坦克乱世\')w = Truewhile w: sn.fill((127,127,127)) for event in pygame.event.get(): if event.type == pygame.QUIT: w = False break if event.type == pygame.KEYDOWN: match event.key: case pygame.K_ESCAPE: w = False break themall.update(sn, \"show\") computer.update(sn, \"move\") kb = pygame.key.get_pressed() if kb[pygame.K_w]: player.move(0,-0.05) if kb[pygame.K_s]: player.move(0,0.05) if kb[pygame.K_a]: player.move(-0.05,0) if kb[pygame.K_d]: player.move(0.05,0) pygame.display.flip()pygame.quit()

在此之后,我们还会更新很多内容。
@dilongzuyj