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

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

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

    • 继续编写魂斗罗
      • 1. 创建子弹类
      • 2. 根据玩家方向和状态设置子弹发射的位置
        • (1). 站立向右发射子弹
        • (2). 站立向左发射子弹
        • (3). 站立朝上发射子弹
        • (4). 蹲下发射子弹
        • (5). 向斜方发射子弹
        • (6). 奔跑时发射子弹
        • (7). 跳跃时发射子弹
      • 3. 在玩家类中加入开火
      • 4. 修改主类实现玩家开火

继续编写魂斗罗

在上次的博客学习 Python 之 Pygame 开发魂斗罗(二)中,我们完成了角色的移动和跳跃,下面我们来继续写魂斗罗。

下面是图片的素材

链接:https://pan.baidu.com/s/1X7tESkes_O6nbPxfpHD6hQ?pwd=hdly
提取码:hdly

1. 创建子弹类

发射子弹首先要有子弹类
我们来创建一下

import pygame
from Constants import *class Bullet(pygame.sprite.Sprite):def __init__(self, person):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)# 销毁开关self.isDestroy = Falsedef 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 = True

2. 根据玩家方向和状态设置子弹发射的位置

由于玩家的方向和状态不一样,所以玩家开火后,子弹发射的位置也不一样

下面我们来看看角色状态和发射子弹的位置

(1). 站立向右发射子弹

(x,y) 是图片的位置,我们计算出,此状态下,子弹发射的位置是 (x+24,y+11)

在这里插入图片描述
下面我们来设置一下

self.rect.x += 24 * 2.5
self.rect.y += 11 * 2.5
self.ySpeed = 0
self.xSpeed = 7

2.5是人物放大的倍数,加载图像的时候把图像放大了2.5倍,所以设置子弹发射位置的时候,同样要乘以2.5

if person.isStanding:# 判断方向# 方向向右if person.direction == Direction.RIGHT:# 向上if person.isUp:pass# 向右else:self.rect.x += 24 * 2.5self.rect.y += 11 * 2.5self.ySpeed = 0self.xSpeed = 7# 方向向左else:if person.isUp:passelse:passelif person.isSquating and not person.isWalking:if person.direction == Direction.RIGHT:passelse:passelif person.isWalking:if person.direction == Direction.RIGHT:if person.isUp:passelif person.isDown:passelse:passelse:if person.isUp:passelif person.isDown:passelse:passelif person.isJumping or person.state == State.FALL:if person.direction == Direction.RIGHT:passelse:pass

(2). 站立向左发射子弹

在这里插入图片描述

self.rect.y += 11 * 2.5
self.ySpeed = 0
self.xSpeed = -7
# 根据角色的方向和状态设置子弹发射的位置
# 角色站着
if person.isStanding:# 判断方向if person.direction == Direction.RIGHT:# 向上if person.isUp:passelse:self.rect.x += 24 * 2.5self.rect.y += 11 * 2.5self.ySpeed = 0self.xSpeed = 7else:if person.isUp:passelse:self.rect.y += 11 * 2.5self.ySpeed = 0self.xSpeed = -7elif person.isSquating and not person.isWalking:if person.direction == Direction.RIGHT:passelse:passelif person.isWalking:if person.direction == Direction.RIGHT:if person.isUp:passelif person.isDown:passelse:passelse:if person.isUp:passelif person.isDown:passelse:passelif person.isJumping or person.state == State.FALL:if person.direction == Direction.RIGHT:passelse:pass

(3). 站立朝上发射子弹

站立向右朝上发射子弹
在这里插入图片描述

self.rect.x += 10 * 2.5
self.rect.y += -1 * 2.5
self.ySpeed = -7
self.xSpeed = 0

这里我微微调整了一下y的值,方向向上,所以子弹的y是逐渐减小的,所以y速度是负数

# 根据角色的方向和状态设置子弹发射的位置
# 角色站着
if person.isStanding:# 判断方向if person.direction == Direction.RIGHT:# 向上if person.isUp:self.rect.x += 10 * 2.5self.rect.y += -1 * 2.5self.ySpeed = -7self.xSpeed = 0else:self.rect.x += 24 * 2.5self.rect.y += 11 * 2.5self.ySpeed = 0self.xSpeed = 7else:if person.isUp:passelse:self.rect.y += 11 * 2.5self.ySpeed = 0self.xSpeed = -7elif person.isSquating and not person.isWalking:if person.direction == Direction.RIGHT:passelse:passelif person.isWalking:if person.direction == Direction.RIGHT:if person.isUp:passelif person.isDown:passelse:passelse:if person.isUp:passelif person.isDown:passelse:passelif person.isJumping or person.state == State.FALL:if person.direction == Direction.RIGHT:passelse:pass

站立向左朝上发射子弹也是同样的计算方式

self.rect.x += 10 * 2.5
self.rect.y += -1 * 2.5
self.ySpeed = -7
self.xSpeed = 0
# 根据角色的方向和状态设置子弹发射的位置
# 角色站着
if person.isStanding:# 判断方向if person.direction == Direction.RIGHT:# 向上if person.isUp:self.rect.x += 10 * 2.5self.rect.y += -1 * 2.5self.ySpeed = -7self.xSpeed = 0else:self.rect.x += 24 * 2.5self.rect.y += 11 * 2.5self.ySpeed = 0self.xSpeed = 7else:if person.isUp:self.rect.x += 10 * 2.5self.rect.y += -1 * 2.5self.ySpeed = -7self.xSpeed = 0else:self.rect.y += 11 * 2.5self.ySpeed = 0self.xSpeed = -7elif person.isSquating and not person.isWalking:if person.direction == Direction.RIGHT:passelse:passelif person.isWalking:if person.direction == Direction.RIGHT:if person.isUp:passelif person.isDown:passelse:passelse:if person.isUp:passelif person.isDown:passelse:passelif person.isJumping or person.state == State.FALL:if person.direction == Direction.RIGHT:passelse:pass

(4). 蹲下发射子弹

向右示意图

在这里插入图片描述

self.rect.x += 34 * 2.5
self.rect.y += 25 * 2.5
self.ySpeed = 0
self.xSpeed = 7
# 根据角色的方向和状态设置子弹发射的位置
# 角色站着
if person.isStanding:# 判断方向if person.direction == Direction.RIGHT:# 向上if person.isUp:self.rect.x += 10 * 2.5self.rect.y += -1 * 2.5self.ySpeed = -7self.xSpeed = 0else:self.rect.x += 24 * 2.5self.rect.y += 11 * 2.5self.ySpeed = 0self.xSpeed = 7else:if person.isUp:self.rect.x += 10 * 2.5self.rect.y += -1 * 2.5self.ySpeed = -7self.xSpeed = 0else:self.rect.y += 11 * 2.5self.ySpeed = 0self.xSpeed = -7elif person.isSquating and not person.isWalking:if person.direction == Direction.RIGHT:self.rect.x += 34 * 2.5self.rect.y += 25 * 2.5self.ySpeed = 0self.xSpeed = 7else:passelif person.isWalking:if person.direction == Direction.RIGHT:if person.isUp:passelif person.isDown:passelse:passelse:if person.isUp:passelif person.isDown:passelse:passelif person.isJumping or person.state == State.FALL:if person.direction == Direction.RIGHT:passelse:pass

同样的,设置向左的发射位置

self.rect.y += 25 * 2.5
self.ySpeed = 0
self.xSpeed = -7
# 根据角色的方向和状态设置子弹发射的位置
# 角色站着
if person.isStanding:# 判断方向if person.direction == Direction.RIGHT:# 向上if person.isUp:self.rect.x += 10 * 2.5self.rect.y += -1 * 2.5self.ySpeed = -7self.xSpeed = 0else:self.rect.x += 24 * 2.5self.rect.y += 11 * 2.5self.ySpeed = 0self.xSpeed = 7else:if person.isUp:self.rect.x += 10 * 2.5self.rect.y += -1 * 2.5self.ySpeed = -7self.xSpeed = 0else:self.rect.y += 11 * 2.5self.ySpeed = 0self.xSpeed = -7elif person.isSquating and not person.isWalking:if person.direction == Direction.RIGHT:self.rect.x += 34 * 2.5self.rect.y += 25 * 2.5self.ySpeed = 0self.xSpeed = 7else:self.rect.y += 25 * 2.5self.ySpeed = 0self.xSpeed = -7elif person.isWalking:if person.direction == Direction.RIGHT:if person.isUp:passelif person.isDown:passelse:passelse:if person.isUp:passelif person.isDown:passelse:passelif person.isJumping or person.state == State.FALL:if person.direction == Direction.RIGHT:passelse:pass

(5). 向斜方发射子弹

向斜右上方发射子弹示意图
在这里插入图片描述

self.rect.x += 20 * 2.5
self.rect.y += -1 * 2.5
self.ySpeed = -7
self.xSpeed = 7

向斜左上方发射子弹时的子弹位置

self.rect.x += -3 * 2.5
self.rect.y += -1 * 2.5
self.ySpeed = -7
self.xSpeed = -7

向斜右下方发射子弹示意图
在这里插入图片描述

self.rect.x += 21 * 2.5
self.rect.y += 20 * 2.5
self.ySpeed = 7
self.xSpeed = 7

向斜左下方发射子弹时的子弹位置

self.rect.x += -3 * 2.5
self.rect.y += 20 * 2.5
self.ySpeed = 7
self.xSpeed = -7

(6). 奔跑时发射子弹

奔跑时发射子弹和站立发射子弹是一样的

向右

self.rect.x += 24 * 2.5
self.rect.y += 11 * 2.5
self.ySpeed = 0
self.xSpeed = 7

向左

self.rect.y += 11 * 2.5
self.ySpeed = 0
self.xSpeed = -7

完整的代码

if person.isStanding:if person.direction == Direction.RIGHT:if person.isUp:self.rect.x += 10 * 2.5self.rect.y += -1 * 2.5self.ySpeed = -7self.xSpeed = 0else:self.rect.x += 24 * 2.5self.rect.y += 11 * 2.5self.ySpeed = 0self.xSpeed = 7else:if person.isUp:self.rect.x += 10 * 2.5self.rect.y += -1 * 2.5self.ySpeed = -7self.xSpeed = 0else:self.rect.y += 11 * 2.5self.ySpeed = 0self.xSpeed = -7elif person.isSquating and not person.isWalking:if person.direction == Direction.RIGHT:self.rect.x += 34 * 2.5self.rect.y += 25 * 2.5self.ySpeed = 0self.xSpeed = 7else:self.rect.y += 25 * 2.5self.ySpeed = 0self.xSpeed = -7elif person.isWalking:if person.direction == Direction.RIGHT:if person.isUp:self.rect.x += 20 * 2.5self.rect.y += -1 * 2.5self.ySpeed = -7self.xSpeed = 7elif person.isDown:self.rect.x += 21 * 2.5self.rect.y += 20 * 2.5self.ySpeed = 7self.xSpeed = 7else:self.rect.x += 24 * 2.5self.rect.y += 11 * 2.5self.ySpeed = 0self.xSpeed = 7else:if person.isUp:self.rect.x += -3 * 2.5self.rect.y += -1 * 2.5self.ySpeed = -7self.xSpeed = -7elif person.isDown:self.rect.x += -3 * 2.5self.rect.y += 20 * 2.5self.ySpeed = 7self.xSpeed = -7else:self.rect.y += 11 * 2.5self.ySpeed = 0self.xSpeed = -7elif person.isJumping or person.state == State.FALL:if person.direction == Direction.RIGHT:passelse:pass

(7). 跳跃时发射子弹

在这里插入图片描述

elif person.isJumping or person.state == State.FALL:if person.direction == Direction.RIGHT:self.rect.x += 16 * 2.5self.rect.y += 8 * 2.5self.ySpeed = 0self.xSpeed = 7else:self.rect.x += -2 * 2.5self.rect.y += 8 * 2.5self.ySpeed = 0self.xSpeed = -7

完整子弹类代码

import pygame
from Constants import *class Bullet(pygame.sprite.Sprite):def __init__(self, person):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 person.isStanding:if person.direction == Direction.RIGHT:if person.isUp:self.rect.x += 10 * 2.5self.rect.y += -1 * 2.5self.ySpeed = -7self.xSpeed = 0else:self.rect.x += 24 * 2.5self.rect.y += 11 * 2.5self.ySpeed = 0self.xSpeed = 7else:if person.isUp:self.rect.x += 10 * 2.5self.rect.y += -1 * 2.5self.ySpeed = -7self.xSpeed = 0else:self.rect.y += 11 * 2.5self.ySpeed = 0self.xSpeed = -7elif person.isSquating and not person.isWalking:if person.direction == Direction.RIGHT:self.rect.x += 34 * 2.5self.rect.y += 25 * 2.5self.ySpeed = 0self.xSpeed = 7else:self.rect.y += 25 * 2.5self.ySpeed = 0self.xSpeed = -7elif person.isWalking:if person.direction == Direction.RIGHT:if person.isUp:self.rect.x += 20 * 2.5self.rect.y += -1 * 2.5self.ySpeed = -7self.xSpeed = 7elif person.isDown:self.rect.x += 21 * 2.5self.rect.y += 20 * 2.5self.ySpeed = 7self.xSpeed = 7else:self.rect.x += 24 * 2.5self.rect.y += 11 * 2.5self.ySpeed = 0self.xSpeed = 7else:if person.isUp:self.rect.x += -3 * 2.5self.rect.y += -1 * 2.5self.ySpeed = -7self.xSpeed = -7elif person.isDown:self.rect.x += -3 * 2.5self.rect.y += 20 * 2.5self.ySpeed = 7self.xSpeed = -7else:self.rect.y += 11 * 2.5self.ySpeed = 0self.xSpeed = -7elif person.isJumping or person.state == State.FALL:if person.direction == Direction.RIGHT:self.rect.x += 16 * 2.5self.rect.y += 8 * 2.5self.ySpeed = 0self.xSpeed = 7else:self.rect.x += -2 * 2.5self.rect.y += 8 * 2.5self.ySpeed = 0self.xSpeed = -7# 销毁开关self.isDestroy = Falsedef 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 = True

3. 在玩家类中加入开火

在常量文件中设置子弹上限

# 设置玩家子弹上限
PLAYER_BULLET_NUMBER = 15

在玩家类的四个状态函数中加入发射的代码

if keys[pygame.K_j]:self.isFiring = Trueif len(playerBulletList) < PLAYER_BULLET_NUMBER:# 设置子弹发射的间隔为150if currentTime - self.fireLastTimer  > 150:playerBulletList.append(Bullet(self))self.fireLastTimer = currentTime

完整的玩家类

import pygame
from Constants import *
from Bullet import Bulletclass 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, 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)# 更新位置# 记录前一次的位置坐标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, 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]:# 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 = Trueif keys[pygame.K_j]:self.isFiring = Trueif len(playerBulletList) < PLAYER_BULLET_NUMBER:if currentTime - self.fireLastTimer  > 150:playerBulletList.append(Bullet(self))self.fireLastTimer = currentTimedef walking(self, keys, currentTime, playerBulletList):"""角色行走,每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 = Falseif keys[pygame.K_j]:self.isFiring = Trueif len(playerBulletList) < PLAYER_BULLET_NUMBER:if currentTime - self.fireLastTimer  > 150:playerBulletList.append(Bullet(self))self.fireLastTimer = 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.isFiring = Trueif len(playerBulletList) < PLAYER_BULLET_NUMBER:if currentTime - self.fireLastTimer  > 150:playerBulletList.append(Bullet(self))self.fireLastTimer = currentTimedef falling(self, keys, currentTime, playerBulletList):# 下落时速度越来越快,所以速度需要一直增加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 = Falseif keys[pygame.K_j]:self.isFiring = Trueif len(playerBulletList) < PLAYER_BULLET_NUMBER:if currentTime - self.fireLastTimer  > 150:playerBulletList.append(Bullet(self))self.fireLastTimer = currentTime

4. 修改主类实现玩家开火

由于玩家类中的update()方法多了一个子弹列表的参数,现在要修改主类

在主类中加入子弹列表

# 子弹
player1BulletList = []

在这里插入图片描述
修改run()函数,把子弹列表传入update()函数

def run(self):while not self.isEnd:# 获取窗口中的事件self.getPlayingModeEvent()# 游戏场景和景物更新函数self.update(MainGame.window, MainGame.player1BulletList)# 更新窗口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()

修改update()函数

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

创建显示子弹函数,在类外创建

def drawPlayerOneBullet(player1BulletList):for bullet in player1BulletList:if bullet.isDestroy:player1BulletList.remove(bullet)else:bullet.draw(MainGame.window)bullet.move()

完整的主类代码

import sys
import pygame
from Constants import *
from PlayerOne import PlayerOnedef drawPlayerOneBullet(player1BulletList):for bullet in player1BulletList:if bullet.isDestroy:player1BulletList.remove(bullet)else:bullet.draw(MainGame.window)bullet.move()class MainGame:player1 = NoneallSprites = Nonewindow = None# 子弹player1BulletList = []def __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, 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):# 更新物体currentTime = pygame.time.get_ticks()MainGame.allSprites.update(self.keys, currentTime, player1BulletList)drawPlayerOneBullet(player1BulletList)# 显示物体MainGame.allSprites.draw(window)if __name__ == '__main__':MainGame().run()

运行一下,看看效果
在这里插入图片描述
哈哈,完成了

相关文章:

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

学习 Python 之 Pygame 开发魂斗罗&#xff08;四&#xff09;继续编写魂斗罗1. 创建子弹类2. 根据玩家方向和状态设置子弹发射的位置(1). 站立向右发射子弹(2). 站立向左发射子弹(3). 站立朝上发射子弹(4). 蹲下发射子弹(5). 向斜方发射子弹(6). 奔跑时发射子弹(7). 跳跃时发射…...

Linux 基础知识:指令与shell

目录一、操作系统二、指令三、shell一、操作系统 什么是操作系统&#xff1f; 单纯的操作系统应该是指操作系统内核。内核的作用就是管理计算机的软硬件资源&#xff0c;让计算机在合适的时候干合适的事情。 但是有一个问题&#xff0c;并不是人人都会直接通过内核来操作计算机…...

【数通网络交换基础梳理1】二层交换机、以太网帧、MAC地址数据帧转发原理详解

一、网络模型 万年不变&#xff0c;先从模型结构分析&#xff0c;现在大家熟知的网络模型有两种。第一种是&#xff0c;OSI七层模型&#xff0c;第二种是TCP/IP模型。在实际运用中&#xff0c;参考更多的是TCP/IP模型。 OSI七层模型 TCP/IP模型 不需要全部理解&#xff0c;…...

《分布式技术原理与算法解析》学习笔记Day22

哈希与一致性哈希 在分布式系统中&#xff0c;哈希和一致性哈希是数据索引或者数据分布的常见实现方式。 数据分布设计原则 在分布式数据存储系统中&#xff0c;做存储方案选型时&#xff0c;一般会考虑以下因素&#xff1a; 数据均匀数据稳定节点异构性隔离故障域性能稳定…...

[MySQL]MySQL数据类型

文章目录数据类型分类数值类型tinyint类型bit类型float类型decimal类型字符串类型char类型varchar类型char和varchar对比日期和时间类型enum和set类型数据类型分类 MySQL中&#xff0c;支持各种各样的类型&#xff0c;比如表示数值的整型浮点型&#xff0c;文本、二进制类型、…...

利用steam搬砖信息差赚钱,单账号200+,小白也能轻松上手!

现在很多人在做互联网而且也赚到钱了&#xff0c;但还是有很多人赚不到钱&#xff0c;这是为什么&#xff1f; 这里我不得不说一个词叫做赛道&#xff0c;也就是选择&#xff0c;选择大于努力&#xff0c;项目本身大于一切&#xff0c;90%的人都觉得直播带货赚钱&#xff0c;但…...

树与二叉树与森林的相关性质

文章目录树的度树的性质二叉树的性质二叉树与森林树的度 树的度指的是树内所有节点的度数的最大值。 节点的度&#xff1a;节点所拥有的子树的数量。简单来说&#xff0c;我们直接数分支即可&#xff0c;例如下图&#xff1a; 在这颗二叉树中&#xff0c;节点2的度为2&#…...

MySQL面试题

文章目录MySQL索引Mysql索引分类InnDB索引与MyISAM索引实现有什么区别一个表中如果没有创建索引&#xff0c;那么还会创建B树么&#xff1f;B树原理B树怎么来的B树 叶子节点和非叶子节点B树能存储多少数据&#xff1f;MySQL索引 Mysql索引分类 mysql 索引分为三类&#xff1a…...

【蓝桥OJ—C语言】高斯日记、马虎的算式、第39级台阶

文章目录高斯日记马虎的算式第39级台阶总结高斯日记 题目&#xff1a; 大数学家高斯有个好习惯&#xff1a;无论如何都要记日记。 他的日记有个与众不同的地方&#xff0c;他从不注明年月日&#xff0c;而是用一个整数代替&#xff0c;比如&#xff1a;4210。 后来人们知道&am…...

基于深度学习的三维重建网络PatchMatchNet(二):dtu数据集介绍及PatchMatchNet中加载数据部分代码解析

目录 1.dtu数据集介绍 2. PatchMatchNet中数据加载模块详解(dtu_yao_eval.py) 1.dtu数据集介绍 dtu数据集下载地址:dtu...

一文3000字从0到1实现基于requests框架接口自动化测试项目实战(建议收藏)

requests库是一个常用的用于http请求的模块&#xff0c;它使用python语言编写&#xff0c;在当下python系列的接口自动化中应用广泛&#xff0c;本文将带领大家深入学习这个库 Python环境的安装就不在这里赘述了&#xff0c;我们直接开干。 01、requests的安装 windows下执行…...

【RockerMQ】001-RockerMQ 概述

【RockerMQ】001-RockerMQ 概述 文章目录【RockerMQ】001-RockerMQ 概述一、MQ 概述1、MQ 简介2、MQ 用途限流削峰异步解耦数据收集3、常见 MQ 产品概述对比4、MQ 常见协议二、RocketMQ 概述1、简介2、发展历史一、MQ 概述 1、MQ 简介 MQ&#xff0c;Message Queue&#xff0…...

阿里是如何做Code Review的?

作为卓越工程文化的一部分&#xff0c;Code Review其实一直在进行中&#xff0c;只是各团队根据自身情况张驰有度&#xff0c;松紧可能也不一&#xff0c;这里简单梳理一下CR的方法和团队实践。 一、为什么要CR 提前发现缺陷 在CodeReview阶段发现的逻辑错误、业务理解偏差、性…...

内核调试:一次多线程调试与KASAN检测实例

内核调试&#xff1a;一次多线程调试与KASAN检测实例1. 环境说明2. 问题描述3. 问题排查与定位3.1 线程并发问题&#xff08;减少线程数&#xff09;3.2 轻量地跟踪对象的分配与释放3.3 检查空指针与潜在修改者3.4 KASAN检查4. 总结博主最近遇到一个非常顽固的多线程BUG&#x…...

Java - 数据结构,队列

一、什么是队列 普通队列&#xff1a;只允许在一端进行插入数据操作&#xff0c;在另一端进行删除数据操作的特殊线性表&#xff0c;队列具有先进先出FIFO(FirstIn First Out) 入队列&#xff1a;进行插入操作的一端称为队尾&#xff08;Tail/Rear&#xff09; 出队列&#xf…...

ccc-pytorch-感知机算法(3)

文章目录单一输出感知机多输出感知机MLP反向传播单一输出感知机 内容解释&#xff1a; w001w^1_{00}w001​&#xff1a;输入标号1连接标号0&#xff08;第一层&#xff09;x00x_0^0x00​&#xff1a;第0层的标号为0的值O11O_1^1O11​:第一层的标号为0的输出值t&#xff1a;真实…...

LeetCode 225.用队列实现栈

请你仅使用两个队列实现一个后入先出&#xff08;LIFO&#xff09;的栈&#xff0c;并支持普通栈的全部四种操作&#xff08;push、top、pop 和 empty&#xff09;。实现 MyStack 类&#xff1a;void push(int x) 将元素 x 压入栈顶。int pop() 移除并返回栈顶元素。int top() …...

【面试】spring控制反转IOC

目录一.说明二.ioc的概念和作用三.优点四.实现机制五.IOC和DI的区别六.设计原则一.说明 1.ioc的概念2.ioc的作用3.ioc的优点4.ioc的实现机制 二.ioc的概念和作用 1.全称Inversion of Control2.控制&#xff1a;创建对象的控制权3.反转&#xff1a;以前对象是程序员主动去new…...

Spring 事务管理详解及使用

✅作者简介&#xff1a;2022年博客新星 第八。热爱国学的Java后端开发者&#xff0c;修心和技术同步精进。 &#x1f34e;个人主页&#xff1a;Java Fans的博客 &#x1f34a;个人信条&#xff1a;不迁怒&#xff0c;不贰过。小知识&#xff0c;大智慧。 &#x1f49e;当前专栏…...

LeetCode 232.用栈实现队列

请你仅使用两个栈实现先入先出队列。队列应当支持一般队列支持的所有操作&#xff08;push、pop、peek、empty&#xff09;&#xff1a;实现 MyQueue 类&#xff1a;void push(int x) 将元素 x 推到队列的末尾int pop() 从队列的开头移除并返回元素int peek() 返回队列开头的元…...

DockerHub与私有镜像仓库在容器化中的应用与管理

哈喽&#xff0c;大家好&#xff0c;我是左手python&#xff01; Docker Hub的应用与管理 Docker Hub的基本概念与使用方法 Docker Hub是Docker官方提供的一个公共镜像仓库&#xff0c;用户可以在其中找到各种操作系统、软件和应用的镜像。开发者可以通过Docker Hub轻松获取所…...

Python爬虫(二):爬虫完整流程

爬虫完整流程详解&#xff08;7大核心步骤实战技巧&#xff09; 一、爬虫完整工作流程 以下是爬虫开发的完整流程&#xff0c;我将结合具体技术点和实战经验展开说明&#xff1a; 1. 目标分析与前期准备 网站技术分析&#xff1a; 使用浏览器开发者工具&#xff08;F12&…...

C++.OpenGL (10/64)基础光照(Basic Lighting)

基础光照(Basic Lighting) 冯氏光照模型(Phong Lighting Model) #mermaid-svg-GLdskXwWINxNGHso {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-GLdskXwWINxNGHso .error-icon{fill:#552222;}#mermaid-svg-GLd…...

Rust 异步编程

Rust 异步编程 引言 Rust 是一种系统编程语言,以其高性能、安全性以及零成本抽象而著称。在多核处理器成为主流的今天,异步编程成为了一种提高应用性能、优化资源利用的有效手段。本文将深入探讨 Rust 异步编程的核心概念、常用库以及最佳实践。 异步编程基础 什么是异步…...

均衡后的SNRSINR

本文主要摘自参考文献中的前两篇&#xff0c;相关文献中经常会出现MIMO检测后的SINR不过一直没有找到相关数学推到过程&#xff0c;其中文献[1]中给出了相关原理在此仅做记录。 1. 系统模型 复信道模型 n t n_t nt​ 根发送天线&#xff0c; n r n_r nr​ 根接收天线的 MIMO 系…...

重启Eureka集群中的节点,对已经注册的服务有什么影响

先看答案&#xff0c;如果正确地操作&#xff0c;重启Eureka集群中的节点&#xff0c;对已经注册的服务影响非常小&#xff0c;甚至可以做到无感知。 但如果操作不当&#xff0c;可能会引发短暂的服务发现问题。 下面我们从Eureka的核心工作原理来详细分析这个问题。 Eureka的…...

A2A JS SDK 完整教程:快速入门指南

目录 什么是 A2A JS SDK?A2A JS 安装与设置A2A JS 核心概念创建你的第一个 A2A JS 代理A2A JS 服务端开发A2A JS 客户端使用A2A JS 高级特性A2A JS 最佳实践A2A JS 故障排除 什么是 A2A JS SDK? A2A JS SDK 是一个专为 JavaScript/TypeScript 开发者设计的强大库&#xff…...

力扣热题100 k个一组反转链表题解

题目: 代码: func reverseKGroup(head *ListNode, k int) *ListNode {cur : headfor i : 0; i < k; i {if cur nil {return head}cur cur.Next}newHead : reverse(head, cur)head.Next reverseKGroup(cur, k)return newHead }func reverse(start, end *ListNode) *ListN…...

搭建DNS域名解析服务器(正向解析资源文件)

正向解析资源文件 1&#xff09;准备工作 服务端及客户端都关闭安全软件 [rootlocalhost ~]# systemctl stop firewalld [rootlocalhost ~]# setenforce 0 2&#xff09;服务端安装软件&#xff1a;bind 1.配置yum源 [rootlocalhost ~]# cat /etc/yum.repos.d/base.repo [Base…...

Ubuntu系统复制(U盘-电脑硬盘)

所需环境 电脑自带硬盘&#xff1a;1块 (1T) U盘1&#xff1a;Ubuntu系统引导盘&#xff08;用于“U盘2”复制到“电脑自带硬盘”&#xff09; U盘2&#xff1a;Ubuntu系统盘&#xff08;1T&#xff0c;用于被复制&#xff09; &#xff01;&#xff01;&#xff01;建议“电脑…...