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

news2024/11/18 9:25:26

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

    • 继续编写魂斗罗
      • 1. 在子弹类中修改敌人发射子弹的位置
      • 2. 创建显示敌人子弹的函数
      • 3. 解决敌人不会向下掉落的问题
      • 4. 给敌人碰撞体组增加碰撞体
      • 5. 解决敌人叠加在一起的问题

继续编写魂斗罗

在上次的博客学习 Python 之 Pygame 开发魂斗罗(八)中,我们加入了敌人,但是敌人不能发射子弹,而且也没有碰撞体,接下来我们来实现一下

下面是图片的素材

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

1. 在子弹类中修改敌人发射子弹的位置

敌人和玩家的图片不一样,所以发射子弹的位置就不一样

下面是敌人发射子弹的图片

在这里插入图片描述
通过这个图片,我们就可以计算出发射子弹的位置了

我们修改子弹类代码

在__init__()函数中增加一个参数,isEnemy,用来指定这个子弹是不是敌人发射的

class Bullet(pygame.sprite.Sprite):

    def __init__(self, person, isEnemy = False):
        pygame.sprite.Sprite.__init__(self)
        self.images = [
            loadImage('../Image/Bullet/bullet1.png')
        ]

然后把下面红框框出的代码进行修改

在这里插入图片描述

def __init__(self, person, isEnemy = False):
    pygame.sprite.Sprite.__init__(self)
    self.images = [
        loadImage('../Image/Bullet/bullet1.png')
    ]
    self.index = 0
    self.image = self.images[self.index]
    # 速度
    self.xSpeed = 1
    self.ySpeed = 1
    self.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_SCALE
            self.rect.y += 7 * PLAYER_SCALE
            self.ySpeed = 0
            self.xSpeed = 7

        else:
            self.rect.x += -1 * PLAYER_SCALE
            self.rect.y += 7 * PLAYER_SCALE
            self.ySpeed = 0
            self.xSpeed = -7

    # 销毁开关
    self.isDestroy = False

接下来来到敌人1类
打开下面框出的代码的注释

在这里插入图片描述

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

在这里插入图片描述

没有报错信息,但是没看到敌人的子弹,这是为什么呢?

原来是我们没有写显示敌人子弹的函数

2. 创建显示敌人子弹的函数

下面我们来写一下,进入主类

在主类外面创建全局函数

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

该函数用来显示子弹,并让子弹移动

之后在update()函数中调用

在这里插入图片描述
现在运行一下游戏

在这里插入图片描述
敌人确实发射子弹了

3. 解决敌人不会向下掉落的问题

在这里插入图片描述
我们走到桥边,发现敌人没办法掉下去,这不对,我们需要解决这个问题

在主类外面写一个全局函数,用来让检测敌人碰撞问题,敌人下落是垂直方向的碰撞问题

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 += 4
            enemy.isFalling = True
            # 改变下落时的图片
            enemy.image = enemy.rightFallImage if enemy.direction == Direction.RIGHT else enemy.leftFallImage
        else:
            # 如果与河发生碰撞,表示敌人落到了水中,那么敌人直接死亡
            if collide in MainGame.enemyRiverGroup:
                enemy.isDestroy = True
        t.rect.y -= 1

之后调用一下这个函数,在主类的update()函数中加入该函数

在这里插入图片描述
然后我们给敌人加入下降时的图片

来到敌人1类,在__init__()函数中加入下面的代码

self.rightFireImage = loadImage('../Image/Enemy/Enemy1/fire.png')
self.leftFireImage = loadImage('../Image/Enemy/Enemy1/fire.png', True)
self.rightFallImage = loadImage('../Image/Enemy/Enemy1/fall.png')
self.leftFallImage = loadImage('../Image/Enemy/Enemy1/fall.png', True)

在这里插入图片描述

接下来运行一下游戏
在这里插入图片描述
我们看到敌人直接掉下去了,这是为什么?

4. 给敌人碰撞体组增加碰撞体

这是因为现在敌人碰撞体组中什么都没有,敌人脚下是空的,当地人出现后,就直接会掉下去啦

接下来我们给敌人增加碰撞体

在这里插入图片描述
注意看这个图,position one表示这是产生敌人的第一个地区,之前我们在Constants.py中设置了,这个变量记录着敌人产生的高度

我们给敌人增加碰撞体,需要清楚哪些地方需要增加

2的位置需要吗?不需要,因为敌人不会向下跳
1的位置需要吗?需要,因为敌人一出来就会在这个地方

根据分析我们得到

1需要增加陆地碰撞体,r1和r3需要增加河碰撞体

下面我们来添加一下

修改initLand()函数河initRiver()函数

先把这两个函数拿出来,作为全局函数

在这里插入图片描述
修改代码

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)

在这里插入图片描述
e开头的是敌人碰撞体,这里我多加入了一些碰撞体,为地图后面的陆地也增加了

我们在Constants.py中加入

RATIO = 1.3571428571428572

我其实不太确定地图中冲突的尺寸,在图片中1000的位置应该是一个陆地,但是在窗口中,这个地方不是陆地,里面有一个对应的系数,我试了放大倍数2.5,发现对不上,所以我就想找一个系数1.3571428571428572,但是这个系数也有问题,窗口上面的图片的系数和下面的系数不一样

我觉得这个地方不需要明白,能在地图中的对应位置设置碰撞体就行,至于位置大家可以自己探索

在这里插入图片描述
把碰撞体加入不同的组

接下来修改camera()函数,让敌人碰撞体也随地图移动而移动

在这里插入图片描述

之后运行一下游戏,看看效果

在这里插入图片描述
我们可以看到敌人掉不下去了,我们来到河边看看
在这里插入图片描述

哈哈,敌人掉下去了

但是又遇到了新的问题,敌人会出现多个叠加在一起,看上去重合了

下面来修复一下

5. 解决敌人叠加在一起的问题

敌人出现重叠的问题,是产生敌人时,两个敌人产生的地方很近导致的

我们修改产生敌人的代码即可

在这里插入图片描述

也可以增加玩家速度

我们让这两个if语句只执行一次就行,执行多次就会出现敌人重叠

在这里插入图片描述

把代码改成3,试试
在这里插入图片描述
运行后发现问题解决了

现在,敌人有了,子弹有了,下一步就是实现玩家死亡和子弹消灭敌人了

完整的主类代码

import copy
import sys
import pygame
from Constants import *
from PlayerOne import PlayerOne
from Collider import Collider
from Enemy1 import Enemy1


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

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 += 4
            enemy.isFalling = True
            # 改变下落时的图片
            enemy.image = enemy.rightFallImage if enemy.direction == Direction.RIGHT else enemy.leftFallImage
        else:
            # 如果与河发生碰撞,表示敌人落到了水中,那么敌人直接死亡
            if collide in MainGame.enemyRiverGroup:
                enemy.isDestroy = True
                # MainGame.explodeList.append(Explode(enemy))
        t.rect.y -= 1

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


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)



class MainGame:

    player1 = None
    allSprites = None

    # 敌人
    enemyList = []

    window = None
    # 子弹
    player1BulletList = []
    enemyBulletList = []

    # 冲突
    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):
        # 初始化展示模块
        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 = 60
        self.clock = pygame.time.Clock()

        # 初始化角色
        MainGame.player1 = PlayerOne(pygame.time.get_ticks())
        # 设置角色的初始位置
        MainGame.player1.rect.x = 80
        MainGame.player1.rect.bottom = 0

        # 把角色放入组中,方便统一管理
        MainGame.allSprites = pygame.sprite.Group(MainGame.player1)

        # 读取背景图片
        self.background = pygame.image.load('../Image/Map/1/Background/First(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

        # 摄像头调整
        self.cameraAdaption = 0

        # 加载场景景物
        initLand()
        initRiver()

        # 碰撞失效间隔
        self.index = 0

    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)
        enemyUpdate(MainGame.enemyList, MainGame.enemyBulletList)
        # 更新物体
        currentTime = pygame.time.get_ticks()
        MainGame.allSprites.update(self.keys, currentTime, player1BulletList)
        self.updatePlayerPosition()
        drawPlayerOneBullet(player1BulletList)
        drawEnemyBullet(MainGame.enemyBulletList)
        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
                # 场景中的物体都走这么多距离
                for sprite in MainGame.allSprites:
                    sprite.rect.x -= self.cameraAdaption
                for collider in MainGame.playerColliderGroup:
                    collider.rect.x -= self.cameraAdaption
                for collider in MainGame.colliderStack:
                    collider.rect.x -= self.cameraAdaption
                for collider in MainGame.enemyColliderGroup:
                    collider.rect.x -= self.cameraAdaption

    def updatePlayerPosition(self):
        # 在index的循环次数中,不进行碰撞检测,用来让玩家向下跳跃
        if self.index > 0:
            self.index -= 1
            self.player1.rect.x += self.player1.xSpeed
            self.player1.rect.y += self.player1.ySpeed
            self.player1.isDown = False
        else:
            # 首先更新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 = 15
            else:
                # 检测碰撞
                # 这里是玩家和所有碰撞组中的碰撞体检测碰撞,如果发生了碰撞,就会返回碰撞到的碰撞体对象
                collider = pygame.sprite.spritecollideany(self.player1, MainGame.playerColliderGroup)
                # 如果发生碰撞,判断是不是在河里
                if collider in MainGame.playerRiverGroup:
                    # 在河里设置isInWater
                    self.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.rightInWaterImage
                    else:
                        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 = 0
                        self.player1.state = State.WALK
                        self.player1.rect.bottom = collider.rect.top
                else:
                    # 否则的话,我们创建一个玩家的复制
                    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.FALL
                    tempPlayer.rect.y -= 1

            # 更新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.left
                else:
                    # 左边有碰撞体
                    self.player1.rect.left = collider.rect.right
                self.player1.xSpeed = 0

            tempPlayer = copy.copy(self.player1)
            tempPlayer.rect.y += 1
            if c := pygame.sprite.spritecollideany(tempPlayer, MainGame.playerColliderGroup):
                if c in MainGame.playerLandGroup:
                    self.player1.isInWater = False
                elif c in MainGame.playerRiverGroup:
                    self.player1.isInWater = True
            tempPlayer.rect.y -= 1

    def generateEnemy(self, x, y, direction, currentTime):
        # 根据玩家的当前位置和方向产生一个敌人
        enemy = Enemy1(x, y, direction, currentTime)
        # 分别加入敌人列表,所有角色组,敌人碰撞组
        MainGame.enemyList.append(enemy)
        MainGame.allSprites.add(enemy)
        MainGame.enemyGroup.add(enemy)

if __name__ == '__main__':
    MainGame().run()

完整的敌人1类代码

import random

import pygame
from Constants import *
from Bullet import Bullet

class Enemy1(pygame.sprite.Sprite):

    def __init__(self, x, y, direction, currentTime):
        pygame.sprite.Sprite.__init__(self)

        self.lastTime = currentTime
        self.fireTime = currentTime
        self.rightImages = [
            loadImage('../Image/Enemy/Enemy1/1.png'),
            loadImage('../Image/Enemy/Enemy1/2.png'),
            loadImage('../Image/Enemy/Enemy1/3.png')
        ]
        self.leftImages = [
            loadImage('../Image/Enemy/Enemy1/1.png', True),
            loadImage('../Image/Enemy/Enemy1/2.png', True),
            loadImage('../Image/Enemy/Enemy1/3.png', True)
        ]
        self.rightFireImage = loadImage('../Image/Enemy/Enemy1/fire.png')
        self.leftFireImage = loadImage('../Image/Enemy/Enemy1/fire.png', True)
        self.fallImage = loadImage('../Image/Enemy/Enemy1/fall.png', True)

        self.rightFireImage = loadImage('../Image/Enemy/Enemy1/fire.png')
        self.leftFireImage = loadImage('../Image/Enemy/Enemy1/fire.png', True)
        self.rightFallImage = loadImage('../Image/Enemy/Enemy1/fall.png')
        self.leftFallImage = loadImage('../Image/Enemy/Enemy1/fall.png', True)

        self.index = 0
        self.direction = direction
        if self.direction == Direction.RIGHT:
            self.image = self.rightImages[self.index]
        else:
            self.image = self.leftImages[self.index]
        self.rect = self.image.get_rect()
        self.isFalling = False
        self.rect.x = x
        self.rect.y = y
        self.speed = 3
        self.isDestroy = False
        self.isFiring = False
        self.life = 1

    def move(self, currentTime):
        # 首先判断敌人是否开火,如果是开火状态,就不能移动
        if not self.isFiring:
            # 没有开火,就根据方向移动,这里我设置敌人只能向一个方向移动,不能转身
            if self.direction == Direction.RIGHT:
                self.rect.left += self.speed
            else:
                self.rect.left -= self.speed
        else:
            # 如果此时是开火状态,判断一下上次开火的时间和这次的时间是否相差1000
            # 这个的作用在于让敌人开火的时候站在那里不动,因为敌人移动时是不能开火的
            if currentTime - self.fireTime > 1000:
                # 如果两次开火间隔相差很大,那么就可以让敌人再次开火
                self.isFiring = False
                self.fireTime = currentTime

    def draw(self, currentTime):
        if self.isFiring:
            if self.direction == Direction.RIGHT:
                self.image = self.rightFireImage
            else:
                self.image = self.leftFireImage
        else:
            if currentTime - self.lastTime > 115:
                if self.index < 2:
                    self.index += 1
                else:
                    self.index = 0
                self.lastTime = currentTime
            if self.direction == Direction.RIGHT:
                self.image = self.rightImages[self.index]
            else:
                self.image = self.leftImages[self.index]

    def fire(self, enemyBulletList):
        if not self.isFalling:
            i = random.randint(0, 50)
            if i == 5:
                if not self.isFiring:
                    self.isFiring = True
                    enemyBulletList.append(Bullet(self, True))

    def checkPosition(self, x, y):
        if abs(self.rect.x - x) > 1000:
            self.isDestroy = True
        elif abs(self.rect.y - y) > 600:
            self.isDestroy = True

完整的子弹类代码

import pygame
from Constants import *

class Bullet(pygame.sprite.Sprite):

    def __init__(self, person, isEnemy = False):
        pygame.sprite.Sprite.__init__(self)
        self.images = [
            loadImage('../Image/Bullet/bullet1.png')
        ]
        self.index = 0
        self.image = self.images[self.index]
        # 速度
        self.xSpeed = 1
        self.ySpeed = 1
        self.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_SCALE
                self.rect.y += 7 * PLAYER_SCALE
                self.ySpeed = 0
                self.xSpeed = 7

            else:
                self.rect.x += -1 * PLAYER_SCALE
                self.rect.y += 7 * PLAYER_SCALE
                self.ySpeed = 0
                self.xSpeed = -7

        # 销毁开关
        self.isDestroy = False

    def landPosition(self, person):
        if person.isStanding:
            if person.direction == Direction.RIGHT:
                if person.isUp:
                    self.rect.x += 10 * PLAYER_SCALE
                    self.rect.y += -1 * PLAYER_SCALE
                    self.ySpeed = -7
                    self.xSpeed = 0
                else:
                    self.rect.x += 24 * PLAYER_SCALE
                    self.rect.y += 11 * PLAYER_SCALE
                    self.ySpeed = 0
                    self.xSpeed = 7
            else:
                if person.isUp:
                    self.rect.x += 10 * PLAYER_SCALE
                    self.rect.y += -1 * PLAYER_SCALE
                    self.ySpeed = -7
                    self.xSpeed = 0
                else:
                    self.rect.y += 11 * PLAYER_SCALE
                    self.ySpeed = 0
                    self.xSpeed = -7

        elif person.isSquating and not person.isWalking:
            if person.direction == Direction.RIGHT:
                self.rect.x += 34 * PLAYER_SCALE
                self.rect.y += 25 * PLAYER_SCALE
                self.ySpeed = 0
                self.xSpeed = 7
            else:
                self.rect.y += 25 * PLAYER_SCALE
                self.ySpeed = 0
                self.xSpeed = -7

        elif person.isWalking:
            if person.direction == Direction.RIGHT:
                if person.isUp:
                    self.rect.x += 20 * PLAYER_SCALE
                    self.rect.y += -1 * PLAYER_SCALE
                    self.ySpeed = -7
                    self.xSpeed = 7
                elif person.isDown:
                    self.rect.x += 21 * PLAYER_SCALE
                    self.rect.y += 20 * PLAYER_SCALE
                    self.ySpeed = 7
                    self.xSpeed = 7
                else:
                    self.rect.x += 24 * PLAYER_SCALE
                    self.rect.y += 11 * PLAYER_SCALE
                    self.ySpeed = 0
                    self.xSpeed = 7
            else:
                if person.isUp:
                    self.rect.x += -3 * PLAYER_SCALE
                    self.rect.y += -1 * PLAYER_SCALE
                    self.ySpeed = -7
                    self.xSpeed = -7
                elif person.isDown:
                    self.rect.x += -3 * PLAYER_SCALE
                    self.rect.y += 20 * PLAYER_SCALE
                    self.ySpeed = 7
                    self.xSpeed = -7
                else:
                    self.rect.y += 11 * PLAYER_SCALE
                    self.ySpeed = 0
                    self.xSpeed = -7

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

    def waterPosition(self, person):
        if person.isStanding:
            if person.direction == Direction.RIGHT:
                if person.isUp:
                    self.rect.x += 14 * PLAYER_SCALE
                    self.rect.y += 7 * PLAYER_SCALE
                    self.ySpeed = -7
                    self.xSpeed = 0
                else:
                    self.rect.x += 27 * PLAYER_SCALE
                    self.rect.y += 29 * PLAYER_SCALE
                    self.ySpeed = 0
                    self.xSpeed = 7
            else:
                if person.isUp:
                    self.rect.x += 7 * PLAYER_SCALE
                    self.rect.y += 3 * PLAYER_SCALE
                    self.ySpeed = -7
                    self.xSpeed = 0
                else:
                    self.rect.x += -1 * PLAYER_SCALE
                    self.rect.y += 29 * PLAYER_SCALE
                    self.ySpeed = 0
                    self.xSpeed = -7

        elif person.isWalking:
            if person.direction == Direction.RIGHT:
                if person.isUp:
                    self.rect.x += 23 * PLAYER_SCALE
                    self.rect.y += 17 * PLAYER_SCALE
                    self.ySpeed = -7
                    self.xSpeed = 7
                else:
                    self.rect.x += 27 * PLAYER_SCALE
                    self.rect.y += 29 * PLAYER_SCALE
                    self.ySpeed = 0
                    self.xSpeed = 7
            else:
                if person.isUp:
                    self.rect.x += -3 * PLAYER_SCALE
                    self.rect.y += -1 * PLAYER_SCALE
                    self.ySpeed = -7
                    self.xSpeed = -7
                else:
                    self.rect.x += -1 * PLAYER_SCALE
                    self.rect.y += 29 * PLAYER_SCALE
                    self.ySpeed = 0
                    self.xSpeed = -7

    def move(self):
        self.rect.x += self.xSpeed
        self.rect.y += self.ySpeed
        self.checkBullet()

    def draw(self, window):
        window.blit(self.image, self.rect)

    def checkBullet(self):
        toDestroy = False
        if self.rect.top < 0 or self.rect.top > 600:
            toDestroy = True
        if self.rect.left < 0 or self.rect.right > 900:
            toDestroy = True
        if toDestroy:
            self.isDestroy = True

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/388953.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

linux入门---如何实现用户切换

目录标题基本用户认识用户的切换susu -exitsu 用户名sudo基本用户认识 在linux系统中将用户分为两个大类一个是root用户一个是普通用户&#xff0c;root用户是linux操作系统的超级管理员&#xff0c;相当于古代的皇帝不会受到任何的权限约束&#xff0c;而普通用户就会受到权限…

循环缓冲区概述

传送门 >> AutoSAR入门和实战系列总目录 文章目录概述使用循环缓冲区机制循环缓冲区、循环队列、循环缓冲区或环形缓冲区是一种数据结构&#xff0c;它使用单个固定大小的缓冲区&#xff0c;就好像它是端到端连接的一样。这种结构很容易用于缓冲数据流。 概述 循环缓冲…

Linux性能学习(2.2):内存_进程线程内存分配机制探究

文章目录1 进程内存分配探究1.1 代码1.2 试验过程2 线程内存分配探究2.1 代码2.2 试验过程3 总结参考资料&#xff1a;1. 嵌入式软件开发杂谈&#xff08;3&#xff09;&#xff1a;Linux下内存与虚拟内存2. 嵌入式软件开发杂谈&#xff08;1&#xff09;&#xff1a;Linux下最…

Cookie+Session详解

文章目录批量删除会话技术简介CookieCookie 查看Cookie 的删除Cookie 使用页面获取 cookie 信息cookie 特点Sessionsession 的使用Session 登录权限验证过滤器简介过滤器的使用WebFilter 注解过滤放行登录权限验证批量删除 servlet 类 dao 层 会话技术 简介 在计算机领域…

论文阅读_近端策略优化_PPO

论文信息 name_en: Proximal Policy Optimization Algorithms name_ch: 近端策略优化算法 paper_addr: http://arxiv.org/abs/1707.06347 date_publish: 2017-08-28 if: IF 8.665 Q1 B1 Top EI author: John Schulman citation: 9685 读后感 PPO近端策略优化是一种强化学习算…

Linux 练习四 (目录操作 + 文件操作)

文章目录1 基于文件指针的文件操作1.1 文件的创建&#xff0c;打开和关闭1.2 文件读写操作2 基于文件描述符的文件操作2.1 打开、创建和关闭文件2.2 文件读写2.3 改变文件大小2.4 文件映射2.5 文件定位2.6 获取文件信息2.7 复制文件描述符2.8 文件描述符和文件指针2.9 标准输入…

Git标签与版本发布

1. 什么是git标签 标签&#xff0c;就类似我们阅读时的书签&#xff0c;可以很轻易找到自己阅读到了哪里。 对于git来说&#xff0c;在使用git对项目进行版本管理的时候&#xff0c;当我们的项目开发到一定的阶段&#xff0c;需要发布一个版本。这时&#xff0c;我们就可以对…

Spring 实战 第六版 学习笔记

Spring 实战 第六版 学习笔记 There is no nutrition in the blog content. After reading it, you will not only suffer from malnutrition, but also impotence. The blog content is all parallel goods. Those who are worried about being cheated should leave quickly.…

【C语言督学训练营 第一天】课程导学,编程环境的安装

文章目录前言一、C语言学习常遇到的问题二、程序员职业发展三、C语言简介及环境搭建1.C语言简介2.安装编译器3.windows按装CLion前言 本系列是本人在复习408的时候记录的一些学习笔记&#xff0c;看的课程是王道的课程&#xff0c;只不过加入了一些个人的见解。不得不说王道的…

PTL仓库提货照明解决方案

仓库拣货到光解决方案是一种先进的导光技术&#xff0c;用货架空间上的全套电子显示装置&#xff08;如信号灯、显示器、确认按钮&#xff09;代替拣货单&#xff0c;简化仓储或配送&#xff1b;订单仓库中心履行流程的无纸化、高效且经济高效的解决方案。 什么是按光拣货系统(…

Java——包装类和List及ArrayList

目录 包装类&#xff08;Wrapped Class) 包装类的使用---装箱和拆箱 自动装箱和自动拆箱 Integer的易错题 javap反编译工具 List接口的使用 方法 ArrayList 使用 打印 区别 扩容机制 ArrayList练习 字符集合 杨辉三角 ​编辑 包装类&#xff08;Wrapped Class) Object 引用可…

CSS居中之 { left:50%; top:50%; transform:translate(-50%,-50%); }

CSS居中之 { left:50%; top:50%; transform:translate(-50%,-50%); } left:50%; top:50%; transform:translate(-50%,-50%); left:50%; top:50%; transform:translate(-50%,-50%);也可以写成: left:50%; top:50%; translate: -50% -50%; left:50%; top:50%; translate: -50%…

电子技术——CMOS反相器的动态响应

电子技术——CMOS反相器的动态响应 数字系统的速度&#xff08;例如计算机&#xff09;取决于其构成逻辑门的信号传播速度。因为反相器是数字逻辑门电路的基础&#xff0c;反相器的传播速度是一个很重要的特性。 传播延迟 传播延迟定义为反相器响应他的输入所需要的时间。特…

项目管理报告工具的功能

项目报告软件哪个好&#xff1f;Zoho Projects的项目管理报告工具为您提供整个组织的360可见性&#xff0c;获取所有项目的实时更新&#xff0c;使用强大的项目报告软件推动成功。Zoho Projects的项目报告软件允许团队整理和监控他们的资源和项目&#xff0c;以评估进度并避免对…

例1.10 几何概型题型一——(会面问题)

【例 1.10】&#xff08;会面问题&#xff09;甲乙两人约定在下午6 点到7点之间在某处会面,并约定先到者应等候另一人20 分钟,过时即可离去,求两人能会面的概率。我的答案&#xff1a;一、信息(1)对于甲乙会面约定事件是6~7点。(2)对于规则要求先到者等另一个人20分钟。(3)求两…

SAP会计科目打删除标记及如何物理删除

如果一个科目如果创建错误了&#xff0c;需要删除。如果在FS00上操作&#xff0c;点删除按钮&#xff0c;那么只是打删除标记而已&#xff08;相当于冻结&#xff09;。 删除和打删除标记是不一样的&#xff1a;打删除标记只是锁定该科目不再被用于记账业务&#xff0c;该科目仍…

进程概念~

进程概念 &#xff08;冯诺依曼体系结构&#xff0c;操作系统&#xff0c;进程概念&#xff0c;进程状态&#xff0c;环境变量&#xff0c;程序地址空间&#xff09; 冯诺依曼体系结构&#xff1a;&#xff08;计算机硬件体系结构&#xff09; 输入设备&#xff0c;输出设备&a…

【Java|基础篇】超详细讲解运算符

文章目录1. 什么是运算符2. 算术运算符隐式类型转换强制类型转换字符串的拼接字符相加自增和自减运算符3.赋值运算符4. 关系运算符5. 逻辑运算符短路与(&&)和短路或(||)6.三目运算符7. 位运算符8. 移位运算1. 什么是运算符 运算符用于执行程序代码运算&#xff0c;会针…

OpenCV-PyQT项目实战(11)项目案例07:摄像头操作与拍摄视频

欢迎关注『OpenCV-PyQT项目实战 Youcans』系列&#xff0c;持续更新中 OpenCV-PyQT项目实战&#xff08;1&#xff09;安装与环境配置 OpenCV-PyQT项目实战&#xff08;2&#xff09;QtDesigner 和 PyUIC 快速入门 OpenCV-PyQT项目实战&#xff08;3&#xff09;信号与槽机制 …

【大数据实时数据同步】超级详细的生产环境OGG(GoldenGate)12.2实时异构同步Oracle数据部署方案(中)

系列文章目录 【大数据实时数据同步】超级详细的生产环境OGG(GoldenGate)12.2实时异构同步Oracle数据部署方案(上) 【大数据实时数据同步】超级详细的生产环境OGG(GoldenGate)12.2实时异构同步Oracle数据部署方案(中) 文章目录系列文章目录前言安装OGG12C软件一、Linux本地GUI…