当前位置: 首页 > news >正文

学习 Python 之 Pygame 开发魂斗罗(三)

学习 Python 之 Pygame 开发魂斗罗(三)

    • 继续编写魂斗罗
      • 1. 角色站立
      • 2. 角色移动
      • 3. 角色跳跃
      • 4. 角色下落

继续编写魂斗罗

在上次的博客学习 Python 之 Pygame 开发魂斗罗(二)中,我们完成了角色的创建和更新,现在具体实现一下更新函数中的角色状态函数

1. 角色站立

在写角色站立函数时,先把其他状态函数注释了,方便测试
在这里插入图片描述

在角色站立函数中,首先设置当前角色的状态

站立时,其他状态都是False,只有isStanding = True

# 设置角色状态
self.isStanding = True
self.isWalking = False
self.isJumping = False
self.isSquating = False
self.isUp = False
self.isDown = False
self.isFiring = False

其次,修改人物的速度,站立时速度均为0

# 设置速度
self.ySpeed = 0
self.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]:# K按下,角色进入跳跃状态,但是不会改变方向self.state = State.JUMP# 设置站立状态为False,跳跃状态为True# 不改变移动状态,因为移动的时候也可以跳跃self.isStanding = Falseself.isJumping = True# 设置速度,速度为负数,因为角色跳起后,要下落self.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 = True

完整的角色类

import pygame
from Constants import *class PlayerOne(pygame.sprite.Sprite):def __init__(self, currentTime):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.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.STAND# 角色的方向self.direction = Direction.RIGHT# 速度self.xSpeed = PLAYER_X_SPEEDself.ySpeed = 0self.jumpSpeed = -11# 人物当前的状态标志self.isStanding = Falseself.isWalking = Falseself.isJumping = Trueself.isSquating = Falseself.isFiring = False# 重力加速度self.gravity = 0.7self.isUp = Falseself.isDown = Falsedef update(self, keys, currentTime):# 更新站或者走的状态# 根据状态响应按键if self.state == State.STAND:self.standing(keys, currentTime)# elif self.state == State.WALK:#   self.walking(keys, currentTime)# elif self.state == State.JUMP:#     self.jumping(keys, currentTime)# elif self.state == State.FALL:#     self.falling(keys, currentTime)# 更新位置# 记录前一次的位置坐标pre = self.rect.xself.rect.x += self.xSpeedself.rect.y += self.ySpeed# 如果x位置小于0了,就不能移动,防止人物跑到屏幕左边if self.rect.x <= 0:self.rect.x = pre# 更新动画# 跳跃状态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 standing(self, keys, currentTime):"""角色站立"""# 设置角色状态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]:# K按下,角色进入跳跃状态,但是不会改变方向self.state = State.JUMP# 设置站立状态为False,跳跃状态为True# 不改变移动状态,因为移动的时候也可以跳跃self.isStanding = Falseself.isJumping = True# 设置速度,速度为负数,因为角色跳起后,要下落self.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 = True

完成角色站立后,我们试一下效果怎么样

在主类中创建角色,并放入pygame.sprite.Group中

class MainGame:player1 = NoneallSprites = None

在__init__()函数中添加代码

# 初始化角色
MainGame.player1 = PlayerOne(pygame.time.get_ticks())
# 设置角色的初始位置
# 这里设置为(0,80),可以实现一开始玩家掉下来的动画,目前没有实现掉落,所以直接设置为(80,300)
# MainGame.player1.rect.x = 80
# MainGame.player1.rect.bottom = 0
MainGame.player1.rect.x = 80
MainGame.player1.rect.bottom = 300# 把角色放入组中,方便统一管理
MainGame.allSprites = pygame.sprite.Group(MainGame.player1)

之后在循环中调用角色的update函数

为了方便,我把物体的更新全部放在一起,创建一个update()函数

在主类中添加函数

def update(self, window):# 更新物体currentTime = pygame.time.get_ticks()MainGame.allSprites.update(self.keys, currentTime)# 显示物体MainGame.allSprites.draw(window)

pygame.sprite.Group()中的物体,可以统一更新,这就是它的方便之处

因为魂斗罗中玩家移动的时候,场景中的物体也是要移动的,所以地图是一个长条状,当玩家向右移动时,实际上是地图向左移动,玩家不动,创建中的物体向左移动,如果不把全部物体放到组中,不好统一管理

完整的主类代码

import sys
import pygame
from Constants import *
from PlayerOne import PlayerOneclass MainGame:player1 = NoneallSprites = Nonewindow = Nonedef __init__(self):# 初始化展示模块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()# 初始化角色MainGame.player1 = PlayerOne(pygame.time.get_ticks())# 设置角色的初始位置# 这里设置为(0,80),可以实现一开始玩家掉下来的动画MainGame.player1.rect.x = 80MainGame.player1.rect.bottom = 300# 把角色放入组中,方便统一管理MainGame.allSprites = pygame.sprite.Group(MainGame.player1)def run(self):while not self.isEnd:# 设置背景颜色pygame.display.get_surface().fill((0, 0, 0))# 游戏场景和景物更新函数self.update(MainGame.window)# 获取窗口中的事件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):# 更新物体currentTime = pygame.time.get_ticks()MainGame.allSprites.update(self.keys, currentTime)# 显示物体MainGame.allSprites.draw(window)if __name__ == '__main__':MainGame().run()

我们现在运行一下,看看效果

在这里插入图片描述
我们发现角色处于跳跃的样子,并且向前移动,这不符合我们的预期,预期应该是站在那里

原因在于角色一开始创建时的状态不对
在这里插入图片描述
当前没有实现falling()函数,所以下落状态没有办法显示,所以我们修改一下,修改角色类中__init__()函数

# 设置角色的状态
self.state = State.FALL 改为 self.state = State.STAND

在这里插入图片描述
改完后运行一下,看看结果

在这里插入图片描述
按a和d键玩家会一直移动,不会停下来

在这里插入图片描述
到此,我们就写好了玩家站立函数了,下面我们来写玩家移动函数

完整的玩家类__init__()函数代码

def __init__(self, currentTime):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.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.STAND# 角色的方向self.direction = Direction.RIGHT# 速度self.xSpeed = PLAYER_X_SPEEDself.ySpeed = 0self.jumpSpeed = -11# 人物当前的状态标志self.isStanding = Falseself.isWalking = Falseself.isJumping = Trueself.isSquating = Falseself.isFiring = False# 重力加速度self.gravity = 0.7self.isUp = Falseself.isDown = False

2. 角色移动

打开注释,开始编写角色移动函数
在这里插入图片描述
同样的,先设置角色的状态,因为是角色移动,所以只有isWalking为真,其他都是假

self.isStanding = False
self.isWalking = True
self.isJumping = False
self.isSquating = False
self.isFiring = False

设置速度

self.ySpeed = 0
self.xSpeed = PLAYER_X_SPEED

判断当前状态,根据当前状态准备下一状态的图片

# 如果当前是站立的图片
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 = currentTime
else:# 如果是走动的图片,先判断方向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 = 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 = True# 按下W键
if keys[pygame.K_w]:self.isUp = Trueself.isDown = False
# 没有按键按下
else:self.state = State.STAND# 移动时按下K键
if keys[pygame.K_k]:# 角色状态变为跳跃self.state = State.JUMPself.ySpeed = self.jumpSpeedself.isJumping = Trueself.isStanding = False

完整的walking()函数代码

    def walking(self, keys, currentTime):"""角色行走,每10帧变换一次图片"""self.isStanding = Falseself.isWalking = Trueself.isJumping = Falseself.isSquating = Falseself.isFiring = Falseself.ySpeed = 0self.xSpeed = PLAYER_X_SPEED# 如果当前是站立的图片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 = 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 = True# 按下W键if keys[pygame.K_w]:self.isUp = Trueself.isDown = False# 没有按键按下else:self.state = State.STAND# 移动时按下K键if keys[pygame.K_k]:# 角色状态变为跳跃self.state = State.JUMPself.ySpeed = self.jumpSpeedself.isJumping = Trueself.isStanding = False

运行一下,看看效果

在这里插入图片描述
哇,实现了,我们就完成了角色移动了

3. 角色跳跃

首先设置状态标志

# 设置标志
self.isJumping = True
self.isStanding = False
self.isDown = False
self.isSquating = False
self.isFiring = False

更新速度

self.ySpeed += self.gravity

跳跃后,角色的y坐标是减少的,所以速度原来是负数,由于跳起到最高点速度一直减小,所以这里我们设置了重力,保证速度慢慢减少到0

根据时间决定是否显示下一张图片

if currentTime - self.runLastTimer > 115:if self.upImageIndex < 3:self.upImageIndex += 1else:self.upImageIndex = 0# 记录变换图片的时间,为下次变换图片做准备self.runLastTimer = currentTime

设置按键响应事件

if 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 = False
elif keys[pygame.K_s]:self.isUp = Falseself.isDown = True# 当速度变为正数,玩家进入下落状态
if self.ySpeed >= 0:self.state = State.FALLif not keys[pygame.K_k]:self.state = State.FALL

完整jumping()函数代码

def jumping(self, keys, currentTime):"""跳跃"""# 设置标志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.FALL

4. 角色下落

def falling(self, keys, currentTime):# 下落时速度越来越快,所以速度需要一直增加self.ySpeed += self.gravityif currentTime - self.runLastTimer > 115:if self.upImageIndex < 3:self.upImageIndex += 1else:self.upImageIndex = 0self.runLastTimer = currentTime# 防止落到窗口外面,当落到一定高度时,就不会再掉落了if self.rect.bottom > SCREEN_HEIGHT - GROUND_HEIGHT:self.state = State.WALKself.ySpeed = 0self.rect.bottom = SCREEN_HEIGHT - GROUND_HEIGHTself.isJumping = Falseif keys[pygame.K_d]:self.direction = Direction.RIGHTself.isWalking = Falseelif keys[pygame.K_a]:self.direction = Direction.LEFTself.isWalking = False

我们现在来看看效果,运行一下

不要忘记打开注释

在这里插入图片描述

在这里插入图片描述
到现在,我们实现了角色移动、跳跃啦,下面就是发射子弹了

相关文章:

学习 Python 之 Pygame 开发魂斗罗(三)

学习 Python 之 Pygame 开发魂斗罗&#xff08;三&#xff09;继续编写魂斗罗1. 角色站立2. 角色移动3. 角色跳跃4. 角色下落继续编写魂斗罗 在上次的博客学习 Python 之 Pygame 开发魂斗罗&#xff08;二&#xff09;中&#xff0c;我们完成了角色的创建和更新&#xff0c;现…...

【华为OD机试模拟题】用 C++ 实现 - 最多获得的短信条数(2023.Q1)

最近更新的博客 【华为OD机试模拟题】用 C++ 实现 - 分积木(2023.Q1) 【华为OD机试模拟题】用 C++ 实现 - 吃火锅(2023.Q1) 【华为OD机试模拟题】用 C++ 实现 - RSA 加密算法(2023.Q1) 【华为OD机试模拟题】用 C++ 实现 - 构成的正方形数量(2023.Q1) 【华为OD机试模拟…...

linux系统加exfat驱动

u盘假如是fat格式不支持大于4G文件&#xff0c;所以一般u盘用exfat格式&#xff0c;兼容性更好 有的老linux没支持exfat格式&#xff0c;那就自己装个驱动吧 sudo apt-get install exfat-fuse exfat-utils 有一台fedora27需要yum安装&#xff0c;国外源比较慢&#xff0c;改…...

3,预初始化(一)(大象无形9.2)

正如书中所说&#xff0c;预初始化流程由FEngineLoop::PreInit()所实现 主要处理流程 1&#xff0c;设置路径&#xff1a;当前程序路径&#xff0c;当前工作目录路径&#xff0c;游戏的工程路径 2,设置标准输出&#xff1a;设置GLog系统输出的设备&#xff0c;是输出到命令行…...

【PAT甲级题解记录】1013 Battle Over Cities (25 分)

【PAT甲级题解记录】1013 Battle Over Cities (25 分) 前言 Problem&#xff1a;1013 Battle Over Cities (25 分) Tags&#xff1a;DFS 连通图 Difficulty&#xff1a;剧情模式 想流点汗 想流点血 死而无憾 Address&#xff1a;1013 Battle Over Cities (25 分) 问题描述 给…...

CSS-关键帧动画

animation和transition的区别 相同点:都是随时间改变元素的属性值 不同点:transition需要触发一个时间(hover或者click事件)才会随时间改变其css属性;而animation在不需要触发任何事件的情况下也是可以显示的随时间变化来改变元素的css属性值,从而达到一种动画的效果,cs…...

Allegro如何画Photoplot_Outline操作指导

Allegro如何画Photoplot_Outline操作指导 在用Allegro进行PCB设计的时候,最后进行光绘输出前,Photoplot_Outline是必备一个图形,所有在Photoplot_Outline中的图形将被输出,Photoplot_Outline以外的图形都将不被输出。 如何绘制Photoplot_Outline,具体操作如下 点击Shape点…...

ChatGPT对于普通人有什么机会和影响?

ChatGPT爆火“出圈”&#xff0c;短短三个月里&#xff0c;势如破竹。 月活已经达到1亿&#xff0c;什么概念呢&#xff1f;Tiktok在海外达到1亿月活用了将近9个月时间&#xff0c;Instagram用了大约2年半&#xff0c;就连比尔盖茨都表示“Web3没那么重要&#xff0c;元宇宙没…...

【人工智能 AI】可以从 RPA 中受益的 10 个行业 10 Industries That Can Benefit From RPA

目录 RPA技术介绍 Which industries can use robotic process automation?哪些行业可以使用机器人过程自动化? Robotic process automation in the retail industry零售业中的机器人过程自动化 Robotic process automation in the construction industry建筑行业的机器人…...

PHP 程序如何实现加密解密?

PHP 中有很多加密和解密的函数可用&#xff0c;以下是一些常用的加密解密方式和函数&#xff1a;对称加密&#xff1a;对称加密是一种加密方式&#xff0c;使用同一个密钥加密和解密数据。PHP 中可用的对称加密算法包括 AES、DES、3DES 等。以下是一些常用的对称加密函数&#…...

使用IDEA社区版如何创建SpringBoot项目?

Spring Boot 就是 Spring 框架的脚⼿架&#xff0c;它就是为了快速开发 Spring 框架⽽诞⽣的。首先谈谈SpringBoot的优点&#xff1a;1.快速集成框架&#xff0c;Spring Boot 提供了启动添加依赖的功能&#xff0c;⽤于秒级集成各种框架。 2.内置运⾏容器&#xff0c;⽆需配置 …...

HTML、CSS学习笔记3(平面转换:位移、旋转、缩放,渐变)

1.平面转换 使用 transform 属性实现元素的位移、旋转、缩放等效果 2D转换 2D转换是改变标签在二维平面上的位置和形状 移动&#xff1a;translate 旋转&#xff1a;rotate 缩放&#xff1a;scale 1.1位移translate translate语法 x就是X轴上水平移动&#xff0c;正向为右…...

【C语言经典例题】打印菱形

目录 一、题目要求 二、解题思路 上半部分三角形 打印空格 打印星号* 下半部分三角形 打印空格 打印星号* 三、完整代码 代码 运行截图&#xff1a; 一、题目要求 输入一个整数n&#xff08;n为奇数&#xff09;&#xff0c;n为菱形的高&#xff0c;打印出该菱形 例&a…...

easyExcel与poi版本不兼容导致的后台报错问题

1、背景&#xff1a;最新接手公司系统excel导入解析模块&#xff0c;点击批量导入&#xff0c;后台报错如下 com.alibaba.excel.exception.ExcelAnalysisException: java.lang.NoClassDefFoundError: org/apache/poi/poifs/filesystem/FileMagicat com.alibaba.excel.analysis.…...

Fiddler报文分析-断点应用、模拟网络限速-HTTPS的 拦截

目录 一、报文分析 Statistics 请求性能数据 检查器&#xff08;Inspectors&#xff09; 自定义响应&#xff08;AutoResponder&#xff09; Composer Composer的功能就是用来创建HTTP Request然后发送请求。 允许自定义请求发送到服务器&#xff0c;即可以手动创建一个新…...

PHP基础(3)

PHP基础表单提交文件处理PHP连接数据库异常抛出表单提交 PHP通过全局变量 $_GET和 $_POST来收集表单数据。 接下来改用post方式进行提交&#xff0c;再次查看是否隐藏了提交的内容&#xff1a; 发现提交的信息已经不在链接之中进行显示了。 GET与POST区别在于一个会在连接…...

跳槽进字节跳动了,面试真的很简单

前言: 最近金三银四跳槽季&#xff0c;相信很多小伙伴都在面试找工作&#xff0c; 怎样才能拿到大厂的offer&#xff0c;没有掌握绝对的技术&#xff0c;那么就要不断的学习 如何拿下阿里等大厂的offer的呢&#xff0c;今天分享一个秘密武器&#xff0c;资深测试工程师整理的…...

【SpringBoot9】HandlerInterceptor拦截器的使用 ——防重复提交

看本篇博客前应当先看完前面三篇&#xff0c;这一篇是基于前面三篇的知识点的整合。所以很多重复的代码这里就不写出了 后台通过拦截器和redis实现防重复提交&#xff0c;避免因为网络原因导致多次请求同时进入业务系统&#xff0c;导致数据错乱&#xff0c;也可以防止对外暴露…...

内网渗透(五十八)之域控安全和跨域攻击-约束性委派攻击

系列文章第一章节之基础知识篇 内网渗透(一)之基础知识-内网渗透介绍和概述 内网渗透(二)之基础知识-工作组介绍 内网渗透(三)之基础知识-域环境的介绍和优点 内网渗透(四)之基础知识-搭建域环境 内网渗透(五)之基础知识-Active Directory活动目录介绍和使用 内网渗透(六)之基…...

Linux僵尸进程理解作业详解

1 下面有关孤儿进程和僵尸进程的描述&#xff0c;说法错误的是&#xff1f; A.孤儿进程&#xff1a;一个父进程退出&#xff0c;而它的一个或多个子进程还在运行&#xff0c;那么那些子进程将成为孤儿进程。 B.僵尸进程&#xff1a;一个进程使用fork创建子进程&#xff0c;如果…...

XML Group端口详解

在XML数据映射过程中&#xff0c;经常需要对数据进行分组聚合操作。例如&#xff0c;当处理包含多个物料明细的XML文件时&#xff0c;可能需要将相同物料号的明细归为一组&#xff0c;或对相同物料号的数量进行求和计算。传统实现方式通常需要编写脚本代码&#xff0c;增加了开…...

synchronized 学习

学习源&#xff1a; https://www.bilibili.com/video/BV1aJ411V763?spm_id_from333.788.videopod.episodes&vd_source32e1c41a9370911ab06d12fbc36c4ebc 1.应用场景 不超卖&#xff0c;也要考虑性能问题&#xff08;场景&#xff09; 2.常见面试问题&#xff1a; sync出…...

【HarmonyOS 5.0】DevEco Testing:鸿蒙应用质量保障的终极武器

——全方位测试解决方案与代码实战 一、工具定位与核心能力 DevEco Testing是HarmonyOS官方推出的​​一体化测试平台​​&#xff0c;覆盖应用全生命周期测试需求&#xff0c;主要提供五大核心能力&#xff1a; ​​测试类型​​​​检测目标​​​​关键指标​​功能体验基…...

鸿蒙中用HarmonyOS SDK应用服务 HarmonyOS5开发一个医院挂号小程序

一、开发准备 ​​环境搭建​​&#xff1a; 安装DevEco Studio 3.0或更高版本配置HarmonyOS SDK申请开发者账号 ​​项目创建​​&#xff1a; File > New > Create Project > Application (选择"Empty Ability") 二、核心功能实现 1. 医院科室展示 /…...

Axios请求超时重发机制

Axios 超时重新请求实现方案 在 Axios 中实现超时重新请求可以通过以下几种方式&#xff1a; 1. 使用拦截器实现自动重试 import axios from axios;// 创建axios实例 const instance axios.create();// 设置超时时间 instance.defaults.timeout 5000;// 最大重试次数 cons…...

今日学习:Spring线程池|并发修改异常|链路丢失|登录续期|VIP过期策略|数值类缓存

文章目录 优雅版线程池ThreadPoolTaskExecutor和ThreadPoolTaskExecutor的装饰器并发修改异常并发修改异常简介实现机制设计原因及意义 使用线程池造成的链路丢失问题线程池导致的链路丢失问题发生原因 常见解决方法更好的解决方法设计精妙之处 登录续期登录续期常见实现方式特…...

iOS性能调优实战:借助克魔(KeyMob)与常用工具深度洞察App瓶颈

在日常iOS开发过程中&#xff0c;性能问题往往是最令人头疼的一类Bug。尤其是在App上线前的压测阶段或是处理用户反馈的高发期&#xff0c;开发者往往需要面对卡顿、崩溃、能耗异常、日志混乱等一系列问题。这些问题表面上看似偶发&#xff0c;但背后往往隐藏着系统资源调度不当…...

LangChain知识库管理后端接口:数据库操作详解—— 构建本地知识库系统的基础《二》

这段 Python 代码是一个完整的 知识库数据库操作模块&#xff0c;用于对本地知识库系统中的知识库进行增删改查&#xff08;CRUD&#xff09;操作。它基于 SQLAlchemy ORM 框架 和一个自定义的装饰器 with_session 实现数据库会话管理。 &#x1f4d8; 一、整体功能概述 该模块…...

C/C++ 中附加包含目录、附加库目录与附加依赖项详解

在 C/C 编程的编译和链接过程中&#xff0c;附加包含目录、附加库目录和附加依赖项是三个至关重要的设置&#xff0c;它们相互配合&#xff0c;确保程序能够正确引用外部资源并顺利构建。虽然在学习过程中&#xff0c;这些概念容易让人混淆&#xff0c;但深入理解它们的作用和联…...

Linux 中如何提取压缩文件 ?

Linux 是一种流行的开源操作系统&#xff0c;它提供了许多工具来管理、压缩和解压缩文件。压缩文件有助于节省存储空间&#xff0c;使数据传输更快。本指南将向您展示如何在 Linux 中提取不同类型的压缩文件。 1. Unpacking ZIP Files ZIP 文件是非常常见的&#xff0c;要在 …...