学习 Python 之 Pygame 开发魂斗罗(十一)
学习 Python 之 Pygame 开发魂斗罗(十一)
- 继续编写魂斗罗
- 1. 改写主类函数中的代码顺序
- 2. 修改玩家初始化
- 3. 显示玩家生命值
- 4. 设置玩家碰到敌人死亡
- 5. 设置敌人子弹击中玩家
- 6. 修改updatePlayerPosition()函数逻辑
继续编写魂斗罗
在上次的博客学习 Python 之 Pygame 开发魂斗罗(十)中,我们实现了敌人死亡的爆炸效果,这次咱们实现一下玩家被敌人击中或者碰到敌人死亡的效果
下面是图片的素材
链接:https://pan.baidu.com/s/1X7tESkes_O6nbPxfpHD6hQ?pwd=hdly
提取码:hdly
1. 改写主类函数中的代码顺序
首先,我们改写一下update()函数中的代码顺序
def update(self, window, player1BulletList):# 加载背景window.blit(self.background, self.backRect)# 敌人更新enemyUpdate(MainGame.enemyList, MainGame.enemyBulletList)drawExplode(MainGame.explodeList)drawPlayerOneBullet(MainGame.player1BulletList)drawEnemyBullet(MainGame.enemyBulletList)# 更新人物currentTime = pygame.time.get_ticks()MainGame.allSprites.update(self.keys, currentTime, player1BulletList)self.updatePlayerPosition()updateEnemyPosition()# 摄像机移动self.camera()# 显示物体MainGame.allSprites.draw(window)# 加载敌人if -1503 < self.backRect.x < -1500:self.generateEnemy(MainGame.player1.rect.x + 600, POSITION_1, Direction.LEFT, pygame.time.get_ticks())self.generateEnemy(MainGame.player1.rect.x - 360, POSITION_1, Direction.RIGHT, pygame.time.get_ticks())if -1703 < self.backRect.x < -1700:self.generateEnemy(MainGame.player1.rect.x - 360, POSITION_1, Direction.RIGHT, pygame.time.get_ticks())self.generateEnemy(MainGame.player1.rect.x - 400, POSITION_1, Direction.RIGHT,pygame.time.get_ticks())for collider in MainGame.playerLandGroup:r = collider.draw(window, self.player1.rect.y)# 如果没有画出来,表示玩家高度低于直线,所有把直线从组中删除if not r:# 删除前先检查一下是不是在组中if collider in MainGame.playerColliderGroup:# 删除并加入栈MainGame.colliderStack.insert(0, collider)MainGame.playerColliderGroup.remove(collider)else:# 如果画出来了,判断一下玩家距离是否高于线的距离if collider.rect.y > self.player1.rect.bottom:# 如果是的话,且冲突栈不为空,那么从栈中取出一个元素放入冲突组,最前面的元素一定是先如队列的if len(MainGame.colliderStack) > 0:f = MainGame.colliderStack.pop()MainGame.playerColliderGroup.add(f)MainGame.playerRiverGroup.draw(window)
其次,把camera()函数中的下面框出的代码,提出来写成一个函数

def mapObjectMove(self):for sprite in MainGame.allSprites:sprite.rect.x -= self.cameraAdaptionfor collider in MainGame.playerColliderGroup:collider.rect.x -= self.cameraAdaptionfor collider in MainGame.colliderStack:collider.rect.x -= self.cameraAdaptionfor collider in MainGame.enemyColliderGroup:collider.rect.x -= self.cameraAdaption

最后,我们把加载背景图片的代码也单独写成一个函数
先找到加载背景图片代码的地方,在主类的构造函数里

把红框圈出的代码提出来,写成一个函数,并且调用

def initBackground(self):# 读取背景图片self.background = pygame.image.load('../Image/Map/1/Background/First(No Bridge).png')self.backRect = self.background.get_rect()self.background = pygame.transform.scale(self.background,(int(self.backRect.width * MAP_SCALE),int(self.backRect.height * MAP_SCALE)))self.backRect.x = -1280
把使用到的两个成员变量在构造函数中创建一下

好,现在运行一下游戏,看看有没有问题
运行后发现,一切正常
2. 修改玩家初始化
现在我们给玩家加入生命值,当玩家生命值为0时,游戏结束
首先,在玩家类中的构造函数里,增加一个参数

用来指定玩家初始的生命值
其次,在玩家类的构造函数中加入一个成员变量

之后,在主类中,加入一个全局函数,用来初始化玩家
def initPlayer1(life):if life == 0:passMainGame.allSprites.remove(MainGame.player1)MainGame.player1 = PlayerOne(pygame.time.get_ticks(), life)MainGame.player1.rect.x = 80MainGame.player1.rect.bottom = 0# 把角色放入组中,方便统一管理MainGame.allSprites.add(MainGame.player1)
这个函数的作用是:先把之前的玩家从组中删除,之后再创建一个新的玩家,新的玩家的生命值比上次的减少1,如果生命值为0,那么就游戏结束,现在先不着急写出游戏结束的函数
最后,把原来的玩家初始化代码改成调用这个函数


运行一下游戏,看看有没有问题

出现了问题
分析一下原因:第一次调用这个函数的时候,allSprites是None,如下图

我们把None改一下

这样就可以啦,再运行一下游戏,看看还有没有问题

这次就没有问题啦
3. 显示玩家生命值
在原版的魂斗罗中,玩家的生命值在左上角显示,我们来实现一下
首先,在构造函数中把生命值的图片加载进来
# 显示玩家生命值
self.lifeImage = loadImage('../Image/Player/Player1/Life/life.png')

在主类中加入成员函数
def drawLifeImage(self, window):# 如果玩家的生命值大于3,那么生命值图标就显示3个if MainGame.player1.life > 3:number = 3# 否则,有几个显示几个,肯定不超过三个else:number = MainGame.player1.liferect = self.lifeImage.get_rect()# 设置生命值图标的显示位置rect.y = 5for i in range(number):# 每个图标之间的距离为25像素rect.x = 5 + i * 20window.blit(self.lifeImage, rect)

之后我们调用一下这个函数,在update()中调用

好,现在运行一下游戏,看看效果

可以看到,左上角就显示玩家生命值啦
不过现在敌人的子弹击中我们,还有敌人碰到我们,我们都不会死亡,接下来我们来实现一下
4. 设置玩家碰到敌人死亡
我们找到主类中的updatePlayerPosition()函数,在其中加入下面这段代码
# 与敌人碰撞
if pygame.sprite.spritecollideany(MainGame.player1, MainGame.enemyGroup):MainGame.player1.life -= 1initPlayer1(MainGame.player1.life)
这段代码就是检测玩家和敌人是否发生碰撞,如果发生了,玩家生命值减少1,重新初始化玩家

def updatePlayerPosition(self):# 在index的循环次数中,不进行碰撞检测,用来让玩家向下跳跃if self.index > 0:self.index -= 1self.player1.rect.x += self.player1.xSpeedself.player1.rect.y += self.player1.ySpeedself.player1.isDown = Falseelse:# 首先更新y的位置self.player1.rect.y += self.player1.ySpeed# 玩家向下跳跃,35次循环内不进行碰撞检测if self.player1.state == State.JUMP and self.player1.isDown:self.index = 35# 玩家向上跳跃,15次循环内不进行碰撞检测elif self.player1.state == State.JUMP and self.player1.isUp:self.index = 15else:# 检测碰撞# 这里是玩家和所有碰撞组中的碰撞体检测碰撞,如果发生了碰撞,就会返回碰撞到的碰撞体对象collider = pygame.sprite.spritecollideany(self.player1, MainGame.playerColliderGroup)# 如果发生碰撞,判断是不是在河里if collider in MainGame.playerRiverGroup:# 在河里设置isInWaterself.player1.isInWater = True# 设置玩家在河里不能跳跃self.player1.isJumping = False# 默认落下去是站在河里的self.player1.isStanding = True# 玩家方向不能向下self.player1.isDown = False# 根据玩家方向,加载落入河中的一瞬间的图片if self.player1.direction == Direction.RIGHT:self.player1.image = self.player1.rightInWaterImageelse:self.player1.image = self.player1.leftInWaterImage# 判断是不是在陆地上elif collider in MainGame.playerLandGroup:self.player1.isInWater = False# 如果发生碰撞if collider:# 判断一下人物的y速度,如果大于0,则说明玩家已经接触到了碰撞体表面,需要让玩家站在表面,不掉下去if self.player1.ySpeed > 0:self.player1.ySpeed = 0self.player1.state = State.WALKself.player1.rect.bottom = collider.rect.topelse:# 否则的话,我们创建一个玩家的复制tempPlayer = copy.copy(self.player1)# 让玩家的纵坐标—+1,看看有没有发生碰撞tempPlayer.rect.y += 1# 如果没有发生碰撞,就说明玩家下面不是碰撞体,是空的if not pygame.sprite.spritecollideany(tempPlayer, MainGame.playerColliderGroup):# 如果此时不是跳跃状态,那么就让玩家变成下落状态,因为玩家在跳跃时,是向上跳跃,不需要对下面的物体进行碰撞检测if tempPlayer.state != State.JUMP:self.player1.state = State.FALLtempPlayer.rect.y -= 1# 与敌人碰撞if pygame.sprite.spritecollideany(MainGame.player1, MainGame.enemyGroup):MainGame.player1.life -= 1initPlayer1(MainGame.player1.life)# 更新x的位置self.player1.rect.x += self.player1.xSpeed# 同样的检查碰撞collider = pygame.sprite.spritecollideany(self.player1, MainGame.playerColliderGroup)# 如果发生了碰撞if collider:# 判断玩家的x方向速度,如果大于0,表示右边有碰撞体if self.player1.xSpeed > 0:# 设置玩家的右边等于碰撞体的左边self.player1.rect.right = collider.rect.leftelse:# 左边有碰撞体self.player1.rect.left = collider.rect.rightself.player1.xSpeed = 0tempPlayer = copy.copy(self.player1)tempPlayer.rect.y += 1if c := pygame.sprite.spritecollideany(tempPlayer, MainGame.playerColliderGroup):if c in MainGame.playerLandGroup:self.player1.isInWater = Falseelif c in MainGame.playerRiverGroup:self.player1.isInWater = TruetempPlayer.rect.y -= 1
好,现在运行一下游戏,看看效果

可以看到,玩家碰到敌人后就直接重新复活了,并且生命值减少了1
不过现在并没有实现敌人子弹击中玩家,玩家死亡,下面我们来实现
5. 设置敌人子弹击中玩家
首先,玩家死亡时,会有死亡的图片,我们要加入进去
修改Constants.py代码,加入爆炸种类

class ExplodeVariety(Enum):CIRCLE = 1BRIDGE = 2PLAYER1 = 3
其次,在爆炸类中根据爆炸种类加载不同的图片

图片素材我已经更新了,在网盘里就可以下载到
完整的爆炸效果类代码
class Explode:def __init__(self, object, variety = ExplodeVariety.CIRCLE, isUseTime = False):# 获取爆炸对象的位置self.rect = object.rectif variety == ExplodeVariety.CIRCLE:self.images = [loadImage('../Image/Explode/circleExplode1.png'),loadImage('../Image/Explode/circleExplode1.png'),loadImage('../Image/Explode/circleExplode1.png'),loadImage('../Image/Explode/circleExplode1.png'),loadImage('../Image/Explode/circleExplode2.png'),loadImage('../Image/Explode/circleExplode2.png'),loadImage('../Image/Explode/circleExplode2.png'),loadImage('../Image/Explode/circleExplode2.png'),loadImage('../Image/Explode/circleExplode3.png'),loadImage('../Image/Explode/circleExplode3.png'),loadImage('../Image/Explode/circleExplode3.png'),loadImage('../Image/Explode/circleExplode3.png'),]elif variety == ExplodeVariety.BRIDGE:self.images = [loadImage('../Image/Explode/bridgeExplode1.png'),loadImage('../Image/Explode/bridgeExplode2.png'),loadImage('../Image/Explode/bridgeExplode3.png'),]elif variety == ExplodeVariety.PLAYER1:self.images = [loadImage('../Image/Player/Player1/Death/death.png'),loadImage('../Image/Player/Player1/Death/death.png'),loadImage('../Image/Player/Player1/Death/death.png'),loadImage('../Image/Player/Player1/Death/death.png'),loadImage('../Image/Player/Player1/Death/death.png'),]self.index = 0self.image = self.images[self.index]self.isDestroy = Falseself.isUseTime = isUseTimeself.lastTime = Nonedef draw(self, window, currentTime = None):if self.isUseTime:if currentTime - self.lastTime > 115:# 根据索引获取爆炸对象, 添加到主窗口# 让图像加载五次,这里可以换成五张大小不一样的爆炸图片,可以实现让爆炸效果从小变大的效果if self.index < len(self.images):self.image = self.images[self.index]self.index += 1window.blit(self.image, self.rect)else:self.isDestroy = Trueself.index = 0self.lastTime = currentTimeelse:window.blit(self.image, self.rect)else:# 根据索引获取爆炸对象, 添加到主窗口# 让图像加载五次,这里可以换成五张大小不一样的爆炸图片,可以实现让爆炸效果从小变大的效果if self.index < len(self.images):self.image = self.images[self.index]self.index += 1window.blit(self.image, self.rect)else:self.isDestroy = Trueself.index = 0
最后,我们就可以在子弹类中加入代码,让子弹击中玩家时,玩家死亡
def collidePlayer(self, player, explodeList):# 函数的返回值用来表示是否要重新初始化玩家# 如果当前子弹和玩家发生碰撞if pygame.sprite.collide_rect(self, player):self.isDestroy = True# 玩家生命值减少1player.life -= 1# 加入玩家的死亡效果explodeList.append(Explode(player, ExplodeVariety.PLAYER1))# 返回Truereturn Truereturn False
函数的返回值用来表示是否要重新初始化玩家

接下来,在主类中调用这个函数,找到drawEnemyBullet()函数,在其中加入代码

之前敌人碰到玩家,玩家死亡,但是没有显示玩家死亡的图片,这里我们加入以下
来到updatePlayerPosition()函数,加入代码

好,下面我们运行一下,看看效果

可以看到子弹击中玩家后,玩家就出现死亡效果啦
但是目前玩家会无限复活,即使左上角的生命值没了,也会复活,这是因为玩家生命值归0后的代码我们并没有写,所以会出现这样的情况,后面我们再加上
6. 修改updatePlayerPosition()函数逻辑
接下来,我们把主类中的有些代码提出来,单独形成新的函数
来到updatePlayerPosition()函数,把下面框出的代码提出来,形成新的函数

def riverCollide(self):# 在河里设置isInWaterself.player1.isInWater = True# 设置玩家在河里不能跳跃self.player1.isJumping = False# 默认落下去是站在河里的self.player1.isStanding = True# 玩家方向不能向下self.player1.isDown = False# 根据玩家方向,加载落入河中的一瞬间的图片if self.player1.direction == Direction.RIGHT:self.player1.image = self.player1.rightInWaterImageelse:self.player1.image = self.player1.leftInWaterImage
原来的代码修改一下

运行一下游戏,看看有没有什么问题
并没有发现什么问题
完整的主类代码
import copy
import sys
import pygame
from Constants import *
from PlayerOne import PlayerOne
from Collider import Collider
from Enemy1 import Enemy1
from Explode import Explodedef drawPlayerOneBullet(player1BulletList):for bullet in player1BulletList:if bullet.isDestroy:player1BulletList.remove(bullet)else:bullet.draw(MainGame.window)bullet.move()bullet.collideEnemy(MainGame.enemyList, MainGame.explodeList)def enemyUpdate(enemyList, enemyBulletList):# 遍历整个敌人列表for enemy in enemyList:# 如果敌人已经被摧毁了if enemy.isDestroy:# 删除它的相关信息enemyList.remove(enemy)MainGame.allSprites.remove(enemy)MainGame.enemyGroup.remove(enemy)# 否则else:# 检查位置enemy.checkPosition(MainGame.player1.rect.x, MainGame.player1.rect.y)# 显示敌人enemy.draw(pygame.time.get_ticks())# 敌人移动enemy.move(pygame.time.get_ticks())# 敌人开火enemy.fire(enemyBulletList)def updateEnemyPosition():# 遍历全部敌人列表for enemy in MainGame.enemyList:# 创建一个复制t = copy.copy(enemy)t.rect.y += 1# 让复制的y加1,看看有没有发生碰撞,这里看的碰撞是enemyColliderGroup中的碰撞collide = pygame.sprite.spritecollideany(t, MainGame.enemyColliderGroup)# 没有发生碰撞,让敌人下落if not collide:enemy.rect.y += 4enemy.isFalling = True# 改变下落时的图片enemy.image = enemy.rightFallImage if enemy.direction == Direction.RIGHT else enemy.leftFallImageelse:enemy.isFalling = False# 如果与河发生碰撞,表示敌人落到了水中,那么敌人直接死亡if collide in MainGame.enemyRiverGroup:enemy.isDestroy = TrueMainGame.explodeList.append(Explode(enemy))t.rect.y -= 1def drawEnemyBullet(enemyBulletList):for bullet in enemyBulletList:if bullet.isDestroy:enemyBulletList.remove(bullet)else:bullet.draw(MainGame.window)bullet.move()if bullet.collidePlayer(MainGame.player1, MainGame.explodeList):initPlayer1(MainGame.player1.life)def initLand():land1 = Collider(81, 119 * MAP_SCALE, 737 * MAP_SCALE, LAND_THICKNESS * MAP_SCALE)land2 = Collider(400, 151 * MAP_SCALE, 96 * MAP_SCALE, LAND_THICKNESS * MAP_SCALE)land3 = Collider(640, 183 * MAP_SCALE, 33 * MAP_SCALE, LAND_THICKNESS * MAP_SCALE)land4 = Collider(880, 183 * MAP_SCALE, 33 * MAP_SCALE, LAND_THICKNESS * MAP_SCALE)land5 = Collider(720, 215 * MAP_SCALE, 2 * LAND_LENGTH * MAP_SCALE, LAND_THICKNESS * MAP_SCALE)land6 = Collider(1040, 154 * MAP_SCALE, 2 * LAND_LENGTH * MAP_SCALE, LAND_THICKNESS * MAP_SCALE)land7 = Collider(1600, 166 * MAP_SCALE, 3 * LAND_LENGTH * MAP_SCALE, LAND_THICKNESS * MAP_SCALE)land8 = Collider(1120 * RATIO, 215 * MAP_SCALE, 2 * LAND_LENGTH * MAP_SCALE, LAND_THICKNESS * MAP_SCALE)land9 = Collider(1650 * RATIO, 119 * MAP_SCALE, 5 * LAND_LENGTH * MAP_SCALE, LAND_THICKNESS * MAP_SCALE)land10 = Collider(2185 * RATIO, 119 * MAP_SCALE, 8 * LAND_LENGTH * MAP_SCALE, LAND_THICKNESS * MAP_SCALE)land11 = Collider(2595 * RATIO, 215 * MAP_SCALE, 3 * LAND_LENGTH * MAP_SCALE, LAND_THICKNESS * MAP_SCALE)land12 = Collider(2770 * RATIO, 167 * MAP_SCALE, 2 * LAND_LENGTH * MAP_SCALE, LAND_THICKNESS * MAP_SCALE)land13 = Collider(2535 * RATIO, 87 * MAP_SCALE, 16 * LAND_LENGTH * MAP_SCALE, LAND_THICKNESS * MAP_SCALE)land14 = Collider(2950 * RATIO, 151 * MAP_SCALE, 7 * LAND_LENGTH * MAP_SCALE, LAND_THICKNESS * MAP_SCALE)land15 = Collider(3185 * RATIO, 215 * MAP_SCALE, 6 * LAND_LENGTH * MAP_SCALE, LAND_THICKNESS * MAP_SCALE)MainGame.playerLandGroup = pygame.sprite.Group(land1, land2, land3, land4, land5, land6, land7, land8, land9, land10,land11, land12, land13, land14, land15)eland1 = Collider(81, 119 * MAP_SCALE, 737 * MAP_SCALE, LAND_THICKNESS * MAP_SCALE)eland9 = Collider(1650 * RATIO, 119 * MAP_SCALE, 5 * LAND_LENGTH * MAP_SCALE, LAND_THICKNESS * MAP_SCALE)MainGame.enemyLandGroup = pygame.sprite.Group(eland1, eland9)MainGame.playerColliderGroup.add(MainGame.playerLandGroup)MainGame.enemyColliderGroup.add(MainGame.enemyLandGroup)def initRiver():river1 = Collider(0, 215 * MAP_SCALE, 289 * MAP_SCALE, LAND_THICKNESS * MAP_SCALE, (0, 0, 255))river2 = Collider(880, 215 * MAP_SCALE, 255 * MAP_SCALE, LAND_THICKNESS * MAP_SCALE, (0, 0, 255))river3 = Collider(1680, 215 * MAP_SCALE, 737 * MAP_SCALE, LAND_THICKNESS * MAP_SCALE, (0, 0, 255))eRiver1 = Collider(0, 215 * MAP_SCALE, 289 * MAP_SCALE, LAND_THICKNESS * MAP_SCALE, (0, 0, 255))eRiver3 = Collider(1680, 215 * MAP_SCALE, 737 * MAP_SCALE, LAND_THICKNESS * MAP_SCALE, (0, 0, 255))MainGame.playerRiverGroup = pygame.sprite.Group(river1, river2, river3)MainGame.enemyRiverGroup = pygame.sprite.Group(eRiver1, eRiver3)MainGame.playerColliderGroup.add(MainGame.playerRiverGroup)MainGame.enemyColliderGroup.add(MainGame.enemyRiverGroup)def drawExplode(explodeList):for explode in explodeList:if explode.isDestroy:explodeList.remove(explode)else:if explode.isUseTime:explode.draw(MainGame.window, pygame.time.get_ticks())else:explode.draw(MainGame.window)def initPlayer1(life):if life == 0:passMainGame.allSprites.remove(MainGame.player1)MainGame.player1 = PlayerOne(pygame.time.get_ticks(), life)MainGame.player1.rect.x = 80MainGame.player1.rect.bottom = 0# 把角色放入组中,方便统一管理MainGame.allSprites.add(MainGame.player1)class MainGame:player1 = NoneallSprites = pygame.sprite.Group()# 敌人enemyList = []window = None# 子弹player1BulletList = []enemyBulletList = []# 爆炸效果explodeList = []# 冲突playerLandGroup = pygame.sprite.Group()playerRiverGroup = pygame.sprite.Group()enemyLandGroup = pygame.sprite.Group()enemyRiverGroup = pygame.sprite.Group()playerColliderGroup = pygame.sprite.Group()enemyColliderGroup = pygame.sprite.Group()enemyGroup = pygame.sprite.Group()bridgeGroup = pygame.sprite.Group()# 冲突栈colliderStack = []def __init__(self):# 设置成员变量self.background = Noneself.backRect = None# 初始化展示模块pygame.display.init()SCREEN_SIZE = (SCREEN_WIDTH, SCREEN_HEIGHT)# 初始化窗口MainGame.window = pygame.display.set_mode(SCREEN_SIZE)# 设置窗口标题pygame.display.set_caption('魂斗罗角色')# 是否结束游戏self.isEnd = False# 获取按键self.keys = pygame.key.get_pressed()# 帧率self.fps = 60self.clock = pygame.time.Clock()# 角色initPlayer1(3)# 加载背景self.initBackground()# 摄像头调整self.cameraAdaption = 0# 加载场景景物initLand()initRiver()# 碰撞失效间隔self.index = 0# 显示玩家生命值self.lifeImage = loadImage('../Image/Player/Player1/Life/life.png')def run(self):while not self.isEnd:# 设置背景颜色pygame.display.get_surface().fill((0, 0, 0))# 游戏场景和景物更新函数self.update(MainGame.window, MainGame.player1BulletList)# 获取窗口中的事件self.getPlayingModeEvent()# 更新窗口pygame.display.update()# 设置帧率self.clock.tick(self.fps)fps = self.clock.get_fps()caption = '魂斗罗 - {:.2f}'.format(fps)pygame.display.set_caption(caption)else:sys.exit()def getPlayingModeEvent(self):# 获取事件列表for event in pygame.event.get():# 点击窗口关闭按钮if event.type == pygame.QUIT:self.isEnd = True# 键盘按键按下elif event.type == pygame.KEYDOWN:self.keys = pygame.key.get_pressed()# 键盘按键抬起elif event.type == pygame.KEYUP:self.keys = pygame.key.get_pressed()def update(self, window, player1BulletList):# 加载背景window.blit(self.background, self.backRect)# 显示生命图标self.drawLifeImage(MainGame.window)# 敌人更新enemyUpdate(MainGame.enemyList, MainGame.enemyBulletList)drawExplode(MainGame.explodeList)drawPlayerOneBullet(MainGame.player1BulletList)drawEnemyBullet(MainGame.enemyBulletList)# 更新人物currentTime = pygame.time.get_ticks()MainGame.allSprites.update(self.keys, currentTime, player1BulletList)self.updatePlayerPosition()updateEnemyPosition()# 摄像机移动self.camera()# 显示物体MainGame.allSprites.draw(window)# 加载敌人if -1503 < self.backRect.x < -1500:self.generateEnemy(MainGame.player1.rect.x + 600, POSITION_1, Direction.LEFT, pygame.time.get_ticks())self.generateEnemy(MainGame.player1.rect.x - 360, POSITION_1, Direction.RIGHT, pygame.time.get_ticks())if -1703 < self.backRect.x < -1700:self.generateEnemy(MainGame.player1.rect.x - 360, POSITION_1, Direction.RIGHT, pygame.time.get_ticks())self.generateEnemy(MainGame.player1.rect.x - 400, POSITION_1, Direction.RIGHT,pygame.time.get_ticks())for collider in MainGame.playerLandGroup:r = collider.draw(window, self.player1.rect.y)# 如果没有画出来,表示玩家高度低于直线,所有把直线从组中删除if not r:# 删除前先检查一下是不是在组中if collider in MainGame.playerColliderGroup:# 删除并加入栈MainGame.colliderStack.insert(0, collider)MainGame.playerColliderGroup.remove(collider)else:# 如果画出来了,判断一下玩家距离是否高于线的距离if collider.rect.y > self.player1.rect.bottom:# 如果是的话,且冲突栈不为空,那么从栈中取出一个元素放入冲突组,最前面的元素一定是先如队列的if len(MainGame.colliderStack) > 0:f = MainGame.colliderStack.pop()MainGame.playerColliderGroup.add(f)MainGame.playerRiverGroup.draw(window)def camera(self):# 如果玩家的右边到达了屏幕的一半if self.player1.rect.right > SCREEN_WIDTH / 2:if not (self.backRect.x <= -3500 * MAP_SCALE):# 计算出超过的距离self.cameraAdaption = self.player1.rect.right - SCREEN_WIDTH / 2# 让背景向右走这么多距离self.backRect.x -= self.cameraAdaption# 场景中的物体都走这么多距离self.mapObjectMove()def mapObjectMove(self):for sprite in MainGame.allSprites:sprite.rect.x -= self.cameraAdaptionfor collider in MainGame.playerColliderGroup:collider.rect.x -= self.cameraAdaptionfor collider in MainGame.colliderStack:collider.rect.x -= self.cameraAdaptionfor collider in MainGame.enemyColliderGroup:collider.rect.x -= self.cameraAdaptiondef updatePlayerPosition(self):# 在index的循环次数中,不进行碰撞检测,用来让玩家向下跳跃if self.index > 0:self.index -= 1self.player1.rect.x += self.player1.xSpeedself.player1.rect.y += self.player1.ySpeedself.player1.isDown = Falseelse:# 首先更新y的位置self.player1.rect.y += self.player1.ySpeed# 玩家向下跳跃,35次循环内不进行碰撞检测if self.player1.state == State.JUMP and self.player1.isDown:self.index = 35# 玩家向上跳跃,15次循环内不进行碰撞检测elif self.player1.state == State.JUMP and self.player1.isUp:self.index = 15else:# 检测碰撞# 这里是玩家和所有碰撞组中的碰撞体检测碰撞,如果发生了碰撞,就会返回碰撞到的碰撞体对象collider = pygame.sprite.spritecollideany(self.player1, MainGame.playerColliderGroup)# 如果发生碰撞,判断是不是在河里if collider in MainGame.playerRiverGroup:self.riverCollide()# 判断是不是在陆地上elif collider in MainGame.playerLandGroup:self.player1.isInWater = False# 如果发生碰撞if collider:# 判断一下人物的y速度,如果大于0,则说明玩家已经接触到了碰撞体表面,需要让玩家站在表面,不掉下去if self.player1.ySpeed > 0:self.player1.ySpeed = 0self.player1.state = State.WALKself.player1.rect.bottom = collider.rect.topelse:# 否则的话,我们创建一个玩家的复制tempPlayer = copy.copy(self.player1)# 让玩家的纵坐标—+1,看看有没有发生碰撞tempPlayer.rect.y += 1# 如果没有发生碰撞,就说明玩家下面不是碰撞体,是空的if not pygame.sprite.spritecollideany(tempPlayer, MainGame.playerColliderGroup):# 如果此时不是跳跃状态,那么就让玩家变成下落状态,因为玩家在跳跃时,是向上跳跃,不需要对下面的物体进行碰撞检测if tempPlayer.state != State.JUMP:self.player1.state = State.FALLtempPlayer.rect.y -= 1# 与敌人碰撞if pygame.sprite.spritecollideany(MainGame.player1, MainGame.enemyGroup):MainGame.player1.life -= 1MainGame.explodeList.append(Explode(MainGame.player1, ExplodeVariety.PLAYER1))initPlayer1(MainGame.player1.life)# 更新x的位置self.player1.rect.x += self.player1.xSpeed# 同样的检查碰撞collider = pygame.sprite.spritecollideany(self.player1, MainGame.playerColliderGroup)# 如果发生了碰撞if collider:# 判断玩家的x方向速度,如果大于0,表示右边有碰撞体if self.player1.xSpeed > 0:# 设置玩家的右边等于碰撞体的左边self.player1.rect.right = collider.rect.leftelse:# 左边有碰撞体self.player1.rect.left = collider.rect.rightself.player1.xSpeed = 0tempPlayer = copy.copy(self.player1)tempPlayer.rect.y += 1if c := pygame.sprite.spritecollideany(tempPlayer, MainGame.playerColliderGroup):if c in MainGame.playerLandGroup:self.player1.isInWater = Falseelif c in MainGame.playerRiverGroup:self.player1.isInWater = TruetempPlayer.rect.y -= 1def riverCollide(self):# 在河里设置isInWaterself.player1.isInWater = True# 设置玩家在河里不能跳跃self.player1.isJumping = False# 默认落下去是站在河里的self.player1.isStanding = True# 玩家方向不能向下self.player1.isDown = False# 根据玩家方向,加载落入河中的一瞬间的图片if self.player1.direction == Direction.RIGHT:self.player1.image = self.player1.rightInWaterImageelse:self.player1.image = self.player1.leftInWaterImagedef generateEnemy(self, x, y, direction, currentTime):# 根据玩家的当前位置和方向产生一个敌人enemy = Enemy1(x, y, direction, currentTime)# 分别加入敌人列表,所有角色组,敌人碰撞组MainGame.enemyList.append(enemy)MainGame.allSprites.add(enemy)MainGame.enemyGroup.add(enemy)def initBackground(self):# 读取背景图片self.background = pygame.image.load('../Image/Map/1/Background/First(No Bridge).png')self.backRect = self.background.get_rect()self.background = pygame.transform.scale(self.background,(int(self.backRect.width * MAP_SCALE),int(self.backRect.height * MAP_SCALE)))self.backRect.x = -1280def drawLifeImage(self, window):# 如果玩家的生命值大于3,那么生命值图标就显示3个if MainGame.player1.life > 3:number = 3# 否则,有几个显示几个,肯定不超过三个else:number = MainGame.player1.liferect = self.lifeImage.get_rect()# 设置生命值图标的显示位置rect.y = 5for i in range(number):# 每个图标之间的距离为25像素rect.x = 5 + i * 20window.blit(self.lifeImage, rect)if __name__ == '__main__':MainGame().run()
完整的子弹类代码
import pygame
from Constants import *
from Explode import Explodeclass Bullet(pygame.sprite.Sprite):def __init__(self, person, isEnemy = False):pygame.sprite.Sprite.__init__(self)self.images = [loadImage('../Image/Bullet/bullet1.png')]self.index = 0self.image = self.images[self.index]# 速度self.xSpeed = 1self.ySpeed = 1self.rect = pygame.Rect(person.rect)if not isEnemy:if person.isInWater:self.waterPosition(person)else:self.landPosition(person)else:if person.direction == Direction.RIGHT:self.rect.x += 27 * PLAYER_SCALEself.rect.y += 7 * PLAYER_SCALEself.ySpeed = 0self.xSpeed = 7else:self.rect.x += -1 * PLAYER_SCALEself.rect.y += 7 * PLAYER_SCALEself.ySpeed = 0self.xSpeed = -7# 销毁开关self.isDestroy = Falsedef landPosition(self, person):if person.isStanding:if person.direction == Direction.RIGHT:if person.isUp:self.rect.x += 10 * PLAYER_SCALEself.rect.y += -1 * PLAYER_SCALEself.ySpeed = -7self.xSpeed = 0else:self.rect.x += 24 * PLAYER_SCALEself.rect.y += 11 * PLAYER_SCALEself.ySpeed = 0self.xSpeed = 7else:if person.isUp:self.rect.x += 10 * PLAYER_SCALEself.rect.y += -1 * PLAYER_SCALEself.ySpeed = -7self.xSpeed = 0else:self.rect.y += 11 * PLAYER_SCALEself.ySpeed = 0self.xSpeed = -7elif person.isSquating and not person.isWalking:if person.direction == Direction.RIGHT:self.rect.x += 34 * PLAYER_SCALEself.rect.y += 25 * PLAYER_SCALEself.ySpeed = 0self.xSpeed = 7else:self.rect.y += 25 * PLAYER_SCALEself.ySpeed = 0self.xSpeed = -7elif person.isWalking:if person.direction == Direction.RIGHT:if person.isUp:self.rect.x += 20 * PLAYER_SCALEself.rect.y += -1 * PLAYER_SCALEself.ySpeed = -7self.xSpeed = 7elif person.isDown:self.rect.x += 21 * PLAYER_SCALEself.rect.y += 20 * PLAYER_SCALEself.ySpeed = 7self.xSpeed = 7else:self.rect.x += 24 * PLAYER_SCALEself.rect.y += 11 * PLAYER_SCALEself.ySpeed = 0self.xSpeed = 7else:if person.isUp:self.rect.x += -3 * PLAYER_SCALEself.rect.y += -1 * PLAYER_SCALEself.ySpeed = -7self.xSpeed = -7elif person.isDown:self.rect.x += -3 * PLAYER_SCALEself.rect.y += 20 * PLAYER_SCALEself.ySpeed = 7self.xSpeed = -7else:self.rect.y += 11 * PLAYER_SCALEself.ySpeed = 0self.xSpeed = -7elif person.isJumping or person.state == State.FALL:if person.direction == Direction.RIGHT:self.rect.x += 16 * PLAYER_SCALEself.rect.y += 8 * PLAYER_SCALEself.ySpeed = 0self.xSpeed = 7else:self.rect.x += -2 * PLAYER_SCALEself.rect.y += 8 * PLAYER_SCALEself.ySpeed = 0self.xSpeed = -7def waterPosition(self, person):if person.isStanding:if person.direction == Direction.RIGHT:if person.isUp:self.rect.x += 14 * PLAYER_SCALEself.rect.y += 7 * PLAYER_SCALEself.ySpeed = -7self.xSpeed = 0else:self.rect.x += 27 * PLAYER_SCALEself.rect.y += 29 * PLAYER_SCALEself.ySpeed = 0self.xSpeed = 7else:if person.isUp:self.rect.x += 7 * PLAYER_SCALEself.rect.y += 3 * PLAYER_SCALEself.ySpeed = -7self.xSpeed = 0else:self.rect.x += -1 * PLAYER_SCALEself.rect.y += 29 * PLAYER_SCALEself.ySpeed = 0self.xSpeed = -7elif person.isWalking:if person.direction == Direction.RIGHT:if person.isUp:self.rect.x += 23 * PLAYER_SCALEself.rect.y += 17 * PLAYER_SCALEself.ySpeed = -7self.xSpeed = 7else:self.rect.x += 27 * PLAYER_SCALEself.rect.y += 29 * PLAYER_SCALEself.ySpeed = 0self.xSpeed = 7else:if person.isUp:self.rect.x += -3 * PLAYER_SCALEself.rect.y += -1 * PLAYER_SCALEself.ySpeed = -7self.xSpeed = -7else:self.rect.x += -1 * PLAYER_SCALEself.rect.y += 29 * PLAYER_SCALEself.ySpeed = 0self.xSpeed = -7def move(self):self.rect.x += self.xSpeedself.rect.y += self.ySpeedself.checkBullet()def draw(self, window):window.blit(self.image, self.rect)def checkBullet(self):toDestroy = Falseif self.rect.top < 0 or self.rect.top > 600:toDestroy = Trueif self.rect.left < 0 or self.rect.right > 900:toDestroy = Trueif toDestroy:self.isDestroy = Truedef collideEnemy(self, enemyList, explodeList):for enemy in enemyList:if pygame.sprite.collide_rect(self, enemy):self.isDestroy = Trueenemy.isDestroy = TrueexplodeList.append(Explode(enemy))def collidePlayer(self, player, explodeList):# 函数的返回值用来表示是否要重新初始化玩家# 如果当前子弹和玩家发生碰撞if pygame.sprite.collide_rect(self, player):self.isDestroy = True# 玩家生命值减少1player.life -= 1# 加入玩家的死亡效果explodeList.append(Explode(player, ExplodeVariety.PLAYER1))# 返回Truereturn Truereturn False
完整的玩家类代码
import pygame
from Constants import *
from Bullet import Bulletclass PlayerOne(pygame.sprite.Sprite):def __init__(self, currentTime, life):pygame.sprite.Sprite.__init__(self)# 加载角色图片self.standRightImage = loadImage('../Image/Player/Player1/Right/stand.png')self.standLeftImage = loadImage('../Image/Player/Player1/Left/stand.png')self.upRightImage = loadImage('../Image/Player/Player1/Up/upRight(small).png')self.upLeftImage = loadImage('../Image/Player/Player1/Up/upLeft(small).png')self.downRightImage = loadImage('../Image/Player/Player1/Down/down.png')self.downLeftImage = loadImage('../Image/Player/Player1/Down/down.png', True)self.obliqueUpRightImages = [loadImage('../Image/Player/Player1/Up/rightUp1.png'),loadImage('../Image/Player/Player1/Up/rightUp2.png'),loadImage('../Image/Player/Player1/Up/rightUp3.png'),]self.obliqueUpLeftImages = [loadImage('../Image/Player/Player1/Up/rightUp1.png', True),loadImage('../Image/Player/Player1/Up/rightUp2.png', True),loadImage('../Image/Player/Player1/Up/rightUp3.png', True),]self.obliqueDownRightImages = [loadImage('../Image/Player/Player1/ObliqueDown/1.png'),loadImage('../Image/Player/Player1/ObliqueDown/2.png'),loadImage('../Image/Player/Player1/ObliqueDown/3.png'),]self.obliqueDownLeftImages = [loadImage('../Image/Player/Player1/ObliqueDown/1.png', True),loadImage('../Image/Player/Player1/ObliqueDown/2.png', True),loadImage('../Image/Player/Player1/ObliqueDown/3.png', True),]# 角色向右的全部图片self.rightImages = [loadImage('../Image/Player/Player1/Right/run1.png'),loadImage('../Image/Player/Player1/Right/run2.png'),loadImage('../Image/Player/Player1/Right/run3.png')]# 角色向左的全部图片self.leftImages = [loadImage('../Image/Player/Player1/Left/run1.png'),loadImage('../Image/Player/Player1/Left/run2.png'),loadImage('../Image/Player/Player1/Left/run3.png')]# 角色跳跃的全部图片self.upRightImages = [loadImage('../Image/Player/Player1/Jump/jump1.png'),loadImage('../Image/Player/Player1/Jump/jump2.png'),loadImage('../Image/Player/Player1/Jump/jump3.png'),loadImage('../Image/Player/Player1/Jump/jump4.png'),]self.upLeftImages = [loadImage('../Image/Player/Player1/Jump/jump1.png', True),loadImage('../Image/Player/Player1/Jump/jump2.png', True),loadImage('../Image/Player/Player1/Jump/jump3.png', True),loadImage('../Image/Player/Player1/Jump/jump4.png', True),]self.rightFireImages = [loadImage('../Image/Player/Player1/Right/fire1.png'),loadImage('../Image/Player/Player1/Right/fire2.png'),loadImage('../Image/Player/Player1/Right/fire3.png'),]self.leftFireImages = [loadImage('../Image/Player/Player1/Right/fire1.png', True),loadImage('../Image/Player/Player1/Right/fire2.png', True),loadImage('../Image/Player/Player1/Right/fire3.png', True),]# 加载玩家在水中的图片self.upRightImageInWater = loadImage('../Image/Player/Player1/Water/up.png')self.upLeftImageInWater = loadImage('../Image/Player/Player1/Water/up.png', True)self.diveRightImageInWater = loadImage('../Image/Player/Player1/Water/dive.png')self.diveLeftImageInWater = loadImage('../Image/Player/Player1/Water/dive.png', True)self.standRightImageInWater = loadImage('../Image/Player/Player1/Water/stand.png')self.standLeftImageInWater = loadImage('../Image/Player/Player1/Water/stand.png', True)self.fireRightInWater = loadImage('../Image/Player/Player1/Water/standFire.png')self.fireLeftInWater = loadImage('../Image/Player/Player1/Water/standFire.png', True)self.obliqueRightInWater = loadImage('../Image/Player/Player1/Water/obliqueRight.png')self.obliqueLeftInWater = loadImage('../Image/Player/Player1/Water/obliqueRight.png', True)self.rightInWaterImage = loadImage('../Image/Player/Player1/Water/inWater.png')self.leftInWaterImage = loadImage('../Image/Player/Player1/Water/inWater.png', True)# 角色左右移动下标self.imageIndex = 0# 角色跳跃下标self.upImageIndex = 0# 角色斜射下标self.obliqueImageIndex = 0# 上一次显示图片的时间self.runLastTimer = currentTimeself.fireLastTimer = currentTime# 选择当前要显示的图片self.image = self.standRightImage# 获取图片的rectself.rect = self.image.get_rect()# 设置角色的状态self.state = State.FALL# 角色的方向self.direction = Direction.RIGHT# 速度self.xSpeed = PLAYER_X_SPEEDself.ySpeed = 0self.jumpSpeed = -11# 人物当前的状态标志self.isStanding = Falseself.isWalking = Falseself.isJumping = Trueself.isSquating = Falseself.isFiring = Falseself.isInWater = False# 重力加速度self.gravity = 0.8# 玩家上下方向self.isUp = Falseself.isDown = Falseself.life = lifedef update(self, keys, currentTime, playerBulletList):# 更新站或者走的状态# 根据状态响应按键if self.state == State.STAND:self.standing(keys, currentTime, playerBulletList)elif self.state == State.WALK:self.walking(keys, currentTime, playerBulletList)elif self.state == State.JUMP:self.jumping(keys, currentTime, playerBulletList)elif self.state == State.FALL:self.falling(keys, currentTime, playerBulletList)# 更新动画if self.isInWater:self.waterUpdate()else:self.landUpdate()def landUpdate(self):# 跳跃状态if self.isJumping:# 根据方向if self.direction == Direction.RIGHT:# 方向向右,角色加载向右跳起的图片self.image = self.upRightImages[self.upImageIndex]else:# 否则,方向向左,角色加载向左跳起的图片self.image = self.upLeftImages[self.upImageIndex]# 角色蹲下if self.isSquating:if self.direction == Direction.RIGHT:# 加载向右蹲下的图片self.image = self.downRightImageelse:# 加载向左蹲下的图片self.image = self.downLeftImage# 角色站着if self.isStanding:if self.direction == Direction.RIGHT:if self.isUp:# 加载向右朝上的图片self.image = self.upRightImageelif self.isDown:# 加载向右蹲下的图片self.image = self.downRightImageelse:# 加载向右站着的图片self.image = self.standRightImageelse:# 向左也是同样的效果if self.isUp:self.image = self.upLeftImageelif self.isDown:self.image = self.downLeftImageelse:self.image = self.standLeftImage# 角色移动if self.isWalking:if self.direction == Direction.RIGHT:if self.isUp:# 加载斜右上的图片self.image = self.obliqueUpRightImages[self.obliqueImageIndex]elif self.isDown:# 加载斜右下的图片self.image = self.obliqueDownRightImages[self.obliqueImageIndex]else:# 加载向右移动的图片,根据开火状态是否加载向右开火移动的图片if self.isFiring:self.image = self.rightFireImages[self.imageIndex]else:self.image = self.rightImages[self.imageIndex]else:if self.isUp:self.image = self.obliqueUpLeftImages[self.obliqueImageIndex]elif self.isDown:self.image = self.obliqueDownLeftImages[self.obliqueImageIndex]else:if self.isFiring:self.image = self.leftFireImages[self.imageIndex]else:self.image = self.leftImages[self.imageIndex]def waterUpdate(self):if self.isSquating:if self.direction == Direction.RIGHT:self.image = self.diveRightImageInWaterelse:self.image = self.diveLeftImageInWaterif self.isStanding:if self.direction == Direction.RIGHT:if self.isFiring:if self.isUp:self.image = self.upRightImageInWaterelse:self.image = self.fireRightInWaterelse:if self.isUp:self.image = self.upRightImageInWaterelse:self.image = self.standRightImageInWaterelse:if self.isFiring:if self.isUp:self.image = self.upLeftImageInWaterelse:self.image = self.fireLeftInWaterelse:if self.isUp:self.image = self.upLeftImageInWaterelse:self.image = self.standLeftImageInWaterif self.isWalking:if self.direction == Direction.RIGHT:if self.isUp:self.image = self.obliqueRightInWaterelse:if self.isFiring:self.image = self.fireRightInWaterelse:self.image = self.standRightImageInWaterelse:if self.isUp:self.image = self.obliqueLeftInWaterelse:if self.isFiring:self.image = self.fireLeftInWaterelse:self.image = self.standLeftImageInWaterdef standing(self, keys, currentTime, playerBulletList):"""角色站立"""# 设置角色状态self.isStanding = Trueself.isWalking = Falseself.isJumping = Falseself.isSquating = Falseself.isUp = Falseself.isDown = Falseself.isFiring = False# 设置速度self.ySpeed = 0self.xSpeed = 0# 按下A键if keys[pygame.K_a]:# A按下,角色方向向左self.direction = Direction.LEFT# 改变角色的状态,角色进入移动状态self.state = State.WALK# 设置站立状态为False,移动状态为Trueself.isStanding = Falseself.isWalking = True# 向左移动,速度为负数,这样玩家的x坐标是减小的self.xSpeed = -PLAYER_X_SPEED# 按下D键elif keys[pygame.K_d]:# D按下,角色方向向右self.direction = Direction.RIGHT# 改变角色的状态,角色进入移动状态self.state = State.WALK# 设置站立状态为False,移动状态为Trueself.isStanding = Falseself.isWalking = True# 向右移动,速度为正数self.xSpeed = PLAYER_X_SPEED# 按下k键elif keys[pygame.K_k]:if not self.isInWater:# K按下,角色进入跳跃状态,但是不会改变方向self.state = State.JUMP# 设置站立状态为False,跳跃状态为True# 不改变移动状态,因为移动的时候也可以跳跃self.isStanding = Falseself.isJumping = True# 设置速度,速度为负数,因为角色跳起后,要下落self.isUp = Trueself.ySpeed = self.jumpSpeed# 没有按下按键else:# 没有按下按键,角色依然是站立状态self.state = State.STANDself.isStanding = True# 按下w键if keys[pygame.K_w]:# W按下,角色向上,改变方向状态self.isUp = Trueself.isStanding = Trueself.isDown = Falseself.isSquating = False# 按下s键elif keys[pygame.K_s]:# S按下,角色蹲下,改变方向状态,并且蹲下状态设置为Trueself.isUp = Falseself.isStanding = Falseself.isDown = Trueself.isSquating = Trueif keys[pygame.K_j]:self.fire(currentTime, playerBulletList)def walking(self, keys, currentTime, playerBulletList):"""角色行走,每10帧变换一次图片"""self.isStanding = Falseself.isWalking = Trueself.isJumping = Falseself.isSquating = Falseself.isFiring = Falseself.ySpeed = 0self.xSpeed = PLAYER_X_SPEEDif self.isInWater:self.walkingInWater(currentTime)else:self.walkingInLand(currentTime)# 按下D键if keys[pygame.K_d]:self.direction = Direction.RIGHTself.xSpeed = PLAYER_X_SPEED# 按下A键elif keys[pygame.K_a]:self.direction = Direction.LEFTself.xSpeed = -PLAYER_X_SPEED# 按下S键elif keys[pygame.K_s]:self.isStanding = Falseself.isDown = Trueself.isUp = False# 按下W键if keys[pygame.K_w]:self.isUp = Trueself.isDown = False# 没有按键按下else:self.state = State.STAND# 移动时按下K键if keys[pygame.K_k]:# 角色状态变为跳跃if not self.isInWater:self.state = State.JUMPself.ySpeed = self.jumpSpeedself.isJumping = Trueself.isStanding = Falseself.isUp = Trueif keys[pygame.K_j]:self.fire(currentTime, playerBulletList)def walkingInLand(self, currentTime):# 如果当前是站立的图片if self.isStanding:# 方向向右,方向向上if self.direction == Direction.RIGHT and self.isUp:# 设置为向右朝上的图片self.image = self.upRightImage# 方向向右elif self.direction == Direction.RIGHT and not self.isUp:# 设置为向右站立的图片self.image = self.standRightImageelif self.direction == Direction.LEFT and self.isUp:self.image = self.upLeftImageelif self.direction == Direction.LEFT and not self.isUp:self.image = self.standLeftImage# 记下当前时间self.runLastTimer = currentTimeelse:# 如果是走动的图片,先判断方向if self.direction == Direction.RIGHT:# 设置速度self.xSpeed = PLAYER_X_SPEED# 根据上下方向觉得是否角色要加载斜射的图片if self.isUp or self.isDown:# isUp == True表示向上斜射# isDown == True表示向下斜射# 计算上一次加载图片到这次的时间,如果大于115,即11.5帧,即上次加载图片到这次加载图片之间,已经加载了11张图片if currentTime - self.runLastTimer > 115:# 那么就可以加载斜着奔跑的图片# 如果角色加载的图片不是第三张,则加载下一张就行if self.obliqueImageIndex < 2:self.obliqueImageIndex += 1# 否则就加载第一张图片else:self.obliqueImageIndex = 0# 记录变换图片的时间,为下次变换图片做准备self.runLastTimer = currentTime# 不是斜射else:# 加载正常向右奔跑的图片if currentTime - self.runLastTimer > 115:if self.imageIndex < 2:self.imageIndex += 1else:self.imageIndex = 0self.runLastTimer = currentTimeelse:self.xSpeed = -PLAYER_X_SPEEDif self.isUp or self.isDown:if currentTime - self.runLastTimer > 115:if self.obliqueImageIndex < 2:self.obliqueImageIndex += 1else:self.obliqueImageIndex = 0self.runLastTimer = currentTimeelse:if currentTime - self.runLastTimer > 115:if self.imageIndex < 2:self.imageIndex += 1else:self.imageIndex = 0self.runLastTimer = currentTimedef walkingInWater(self, currentTime):if self.isStanding:# 设置为斜射if self.direction == Direction.RIGHT and self.isUp:self.image = self.upRightImageInWaterelif self.direction == Direction.RIGHT and not self.isUp:self.image = self.standRightImageInWaterelif self.direction == Direction.LEFT and self.isUp:self.image = self.upLeftImageInWaterelif self.direction == Direction.LEFT and not self.isUp:self.image = self.standLeftImageInWaterself.runLastTimer = currentTimeelse:# 如果是走动的图片if self.direction == Direction.RIGHT:self.xSpeed = PLAYER_X_SPEEDif self.isUp:self.image = self.obliqueRightInWaterself.runLastTimer = currentTimeelse:self.image = self.standRightImageInWaterself.runLastTimer = currentTimeelse:self.xSpeed = PLAYER_X_SPEEDif self.isUp:self.image = self.obliqueLeftInWaterself.runLastTimer = currentTimeelse:self.image = self.standLeftImageInWaterself.runLastTimer = currentTimedef jumping(self, keys, currentTime, playerBulletList):"""跳跃"""# 设置标志self.isJumping = Trueself.isStanding = Falseself.isDown = Falseself.isSquating = Falseself.isFiring = False# 更新速度self.ySpeed += self.gravityif currentTime - self.runLastTimer > 115:if self.upImageIndex < 3:self.upImageIndex += 1else:self.upImageIndex = 0# 记录变换图片的时间,为下次变换图片做准备self.runLastTimer = currentTimeif keys[pygame.K_d]:self.direction = Direction.RIGHTelif keys[pygame.K_a]:self.direction = Direction.LEFT# 按下W键if keys[pygame.K_w]:self.isUp = Trueself.isDown = Falseelif keys[pygame.K_s]:self.isUp = Falseself.isDown = Trueif self.ySpeed >= 0:self.state = State.FALLif not keys[pygame.K_k]:self.state = State.FALLif keys[pygame.K_j]:self.fire(currentTime, playerBulletList)def falling(self, keys, currentTime, playerBulletList):# 下落时速度越来越快,所以速度需要一直增加self.ySpeed += self.gravityif currentTime - self.runLastTimer > 115:if self.upImageIndex < 3:self.upImageIndex += 1else:self.upImageIndex = 0self.runLastTimer = currentTimeif keys[pygame.K_d]:self.direction = Direction.RIGHTself.isWalking = Falseelif keys[pygame.K_a]:self.direction = Direction.LEFTself.isWalking = Falseif keys[pygame.K_j]:self.fire(currentTime, playerBulletList)def fire(self, currentTime, playerBulletList):self.isFiring = True# 潜水状态下不能开火if not (self.isInWater and self.isSquating):if len(playerBulletList) < PLAYER_BULLET_NUMBER:if currentTime - self.fireLastTimer > 150:playerBulletList.append(Bullet(self))self.fireLastTimer = currentTime
相关文章:
学习 Python 之 Pygame 开发魂斗罗(十一)
学习 Python 之 Pygame 开发魂斗罗(十一)继续编写魂斗罗1. 改写主类函数中的代码顺序2. 修改玩家初始化3. 显示玩家生命值4. 设置玩家碰到敌人死亡5. 设置敌人子弹击中玩家6. 修改updatePlayerPosition()函数逻辑继续编写魂斗罗 在上次的博客学习 Pytho…...
Linux驱动开发
一、驱动分类Linux中包含三大类驱动:字符设备驱动、块设备驱动和网络设备驱动。其中字符设备驱动是最大的一类驱动,因为字符设备最多,从led到I2C、SPI、音频等都属于字符设备驱动。块设备驱动和网络设备驱动都要比字符设备驱动复杂。因为其比…...
32--Vue-前端开发-Vue语法之组件化开发
一、vue语法回顾 购物车的例子 eg1:计算商品价格(掌握对象的迭代方法) <!DOCTYPE html> <html lang="en"> <head>...
打怪升级之CFileDialog类介绍
CFileDialog类 CFileDialog封装用于文件打开操作或文件保存操作的常见对话框。信息来源自Windows官方文档:https://learn.microsoft.com/zh-cn/cpp/mfc/reference/cfiledialog-class?viewmsvc-170 这里重点介绍几个常用的函数功能: 构造函数 explic…...
配天智造自主原创数字工厂:百余名员工人均创收122万
配天智造(832223)2022年度报告显示,报告期内公司实现营业收入1.3亿元,同比增长52%,归属于挂牌公司股东的净利润3867万元,同比增长28.11%。而这家公司全部在职员工仅有107人,人均创收约为122万。…...
COLMAP
简介:在使用instant-ngp过程中需要使用COLMAP得到模型的必要输入,比如模型需要的相机外参我们就可以通过COLMAP中的sparse reconstruction稀疏重建得到;而对于depth map深度图我们则需要dense reconstruction稠密重建得到,下面我们…...
2023-3-8 刷题情况
礼盒的最大甜蜜度 题目描述 给你一个正整数数组 price ,其中 price[i] 表示第 i 类糖果的价格,另给你一个正整数 k 。 商店组合 k 类 不同 糖果打包成礼盒出售。礼盒的 甜蜜度 是礼盒中任意两种糖果 价格 绝对差的最小值。 返回礼盒的 最大 甜蜜度。…...
关于长连接服务器和客户端之间要加入心跳的一些讨论
在之前的章节里深入浅出TCPIP之深入浅出TCPIP之TCP重传机制 我们都知道了TCPIP协议栈有个默认的TCP心跳机制,这个心跳机制是和socket绑定的,可以对指定的套接字开启协议栈的心跳检测机制。默认情况下,协议栈的心跳机制对socket套接字是关闭的,如果要使用需要人为开启的。 比…...
LeetCode——1590. 使数组和能被 P 整除
一、题目 给你一个正整数数组 nums,请你移除 最短 子数组(可以为 空),使得剩余元素的 和 能被 p 整除。 不允许 将整个数组都移除。 请你返回你需要移除的最短子数组的长度,如果无法满足题目要求,返回 -1…...
12N65-ASEMI高压MOS管12N65
编辑-Z 12N65在TO-220封装里的静态漏极源导通电阻(RDS(ON))为0.68Ω,是一款N沟道高压MOS管。12N65的最大脉冲正向电流ISM为48A,零栅极电压漏极电流(IDSS)为10uA,其工作时耐温度范围为-55~150摄氏度。12N65功耗&#x…...
cushy-serial 一个轻量级Python serial库
本文自笔者博客: https://www.blog.zeeland.cn/archives/rgoihgxcoci3 简介 cushy-serial是一个轻量级的Serial框架,初衷是希望使Serial编程变得更加简单、快捷,因此,相较于传统的pyserial,该框架可以更加快速地构建起一个serial…...
音视频开发系列(7)——Opengl常用Api介绍part1
GLES20.glTexParameteri GLES20.glTexParameteri是OpenGL ES 2.0用于设置纹理过滤器和纹理包装模式的函数。它有三个参数: target参数 target参数指定要设置纹理参数的纹理目标,根据不同的target值,glTexParameteri函数的行为也会有所不同…...
linux时间的特殊用法
今天介绍linux下Date时间命令相关的特殊用法 date (当前的时间) 修改系统当前时间: date -s "2022-6-20 9:33:50" 昨天的时间是我们比较常用的: date -d "yesterday" %Y%m%d ( 昨天的时间) date -d "1 day ago" %Y%m%d …...
axios 封装,API接口统一管理
分享一个自己封装的 axios 网络请求 主要的功能及其优点: 将所有的接口放在一个文件夹中管理(api.js)。并且可以支持动态接口,就是 api.js 文件中定义的接口可以使用 :xx 占位,根据需要动态的改变。动态接口用法模仿…...
SpringBoot使用Redis实现缓存
目录 实现步骤 1. 在 pom.xml 配置文件中添加如下依赖 2. 在 application.properties 中添加如下配置 3. 新建 RedisConfig.class,继承 CachingConfigurerSupport,添加如下方法 4. 新建 RedisService.class 添加如下方法 注意:cacheKey…...
[失业前端恶补算法]JavaScript leetcode刷题top100(三)
专栏声明:只求用最简单的,容易理解的方法通过,不求优化,不喜勿喷 今天更新五个 easy 难度题目: 相交链表 题面 给你两个单链表的头节点 headA 和 headB ,请你找出并返回两个单链表相交的起始节点。如果两个…...
Spark RDD的设计与运行原理
一、Spark RDD概念 一个RDD就是一个分布式对象集合,本质上是一个只读的分区记录集合,每个RDD可以分成多个分区,每个分区就是一个数据集片段,并且一个RDD的不同分区可以被保存到集群中不同的节点上,从而可以在集群中的…...
Golang的下载与安装
Windows系统 进入golang官方下载网站:所有版本 - Go 编程语言如图所示 下载后打开您下载的 MSI 文件,然后按照提示安装 Go。 验证是否已安装 Go。...
广州蓝景分享—8大Web前端开发的趋势
2023 年 1 月 11 日,2022 年度 StateOfJS 调查结果正式公布!StateOfJS 是前端生态圈中比较有影响力的且规模较大的数据调查。本文就来解读一下 2022 年 StateOfJS 的调查结果! JavaScript 发展很快,但似乎 JavaScript 开发人员的…...
Java学习-MySQL-创建数据库表
Java学习-MySQL-创建数据库表 SHOW DATABASESUSE school CREATE TABLE IF NOT EXISTS student( id INT(10) NOT NULL AUTO_INCREMENT COMMENT 学号, name VARCHAR(30) NOT NULL DEFAULT 匿名 COMMENT 姓名, pws VARCHAR(20) NOT NULL DEFAULT 123456 COMMENT 密码, sex VARCHA…...
基于距离变化能量开销动态调整的WSN低功耗拓扑控制开销算法matlab仿真
目录 1.程序功能描述 2.测试软件版本以及运行结果展示 3.核心程序 4.算法仿真参数 5.算法理论概述 6.参考文献 7.完整程序 1.程序功能描述 通过动态调整节点通信的能量开销,平衡网络负载,延长WSN生命周期。具体通过建立基于距离的能量消耗模型&am…...
工业安全零事故的智能守护者:一体化AI智能安防平台
前言: 通过AI视觉技术,为船厂提供全面的安全监控解决方案,涵盖交通违规检测、起重机轨道安全、非法入侵检测、盗窃防范、安全规范执行监控等多个方面,能够实现对应负责人反馈机制,并最终实现数据的统计报表。提升船厂…...
Springboot社区养老保险系统小程序
一、前言 随着我国经济迅速发展,人们对手机的需求越来越大,各种手机软件也都在被广泛应用,但是对于手机进行数据信息管理,对于手机的各种软件也是备受用户的喜爱,社区养老保险系统小程序被用户普遍使用,为方…...
云原生安全实战:API网关Kong的鉴权与限流详解
🔥「炎码工坊」技术弹药已装填! 点击关注 → 解锁工业级干货【工具实测|项目避坑|源码燃烧指南】 一、基础概念 1. API网关(API Gateway) API网关是微服务架构中的核心组件,负责统一管理所有API的流量入口。它像一座…...
Windows安装Miniconda
一、下载 https://www.anaconda.com/download/success 二、安装 三、配置镜像源 Anaconda/Miniconda pip 配置清华镜像源_anaconda配置清华源-CSDN博客 四、常用操作命令 Anaconda/Miniconda 基本操作命令_miniconda创建环境命令-CSDN博客...
Unity UGUI Button事件流程
场景结构 测试代码 public class TestBtn : MonoBehaviour {void Start(){var btn GetComponent<Button>();btn.onClick.AddListener(OnClick);}private void OnClick(){Debug.Log("666");}}当添加事件时 // 实例化一个ButtonClickedEvent的事件 [Formerl…...
前端中slice和splic的区别
1. slice slice 用于从数组中提取一部分元素,返回一个新的数组。 特点: 不修改原数组:slice 不会改变原数组,而是返回一个新的数组。提取数组的部分:slice 会根据指定的开始索引和结束索引提取数组的一部分。不包含…...
Axure 下拉框联动
实现选省、选完省之后选对应省份下的市区...
yaml读取写入常见错误 (‘cannot represent an object‘, 117)
错误一:yaml.representer.RepresenterError: (‘cannot represent an object’, 117) 出现这个问题一直没找到原因,后面把yaml.safe_dump直接替换成yaml.dump,确实能保存,但出现乱码: 放弃yaml.dump,又切…...
数据结构:泰勒展开式:霍纳法则(Horner‘s Rule)
目录 🔍 若用递归计算每一项,会发生什么? Horners Rule(霍纳法则) 第一步:我们从最原始的泰勒公式出发 第二步:从形式上重新观察展开式 🌟 第三步:引出霍纳法则&…...
