> 技术文档 > Python3.13实战:手把手教你造pygame游戏2、游戏内容_python3.13游戏

Python3.13实战:手把手教你造pygame游戏2、游戏内容_python3.13游戏

参考文献

1、 pygame教程(非常详细):Pygame教程(非常详细)-CSDN博客 2、 pygame教程----Sprite精灵模块介绍:pygame教程----Sprite精灵模块介绍-CSDN博客 3、 【pygame】Sprite类:【pygame】Sprite类-CSDN博客 4、

Pygame教程07:键盘常量+键盘事件的2种捕捉方式:Pygame教程07:键盘常量+键盘事件的2种捕捉方式-CSDN博客

(建议结合pygame教程来看) 

(别问为什么3.11变3.13了)

(正文:

在​​​​​​Python3.13实战:手把手教你造pygame游戏1、游戏框架​​​​​中,我们写出了我们游戏的框架,而这次,游戏内容也将被我们编写出来!

1、设计坦克类

首先,我们需要设计一个坦克类。这是一个精灵Sprite)类。

使用Sprite派生新类时需要分配Sprite.imageSprite.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的别名

然后,自己搞一个修正函数,我这里用的是dx=sin(x*1.14514)*1.14514\\;\\; dy=\\cos(x\\cdot 1.14514)*1.14514,你可以用自己的。但是,为了保证方向随机,可以再次使用随机数。

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变量,并将它的每个元素都钳制在了[0, 380]的区间,使得精灵跑不出地图。

将其添加到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 x^{\\log_xa}=a