2025-02-04

用pygame做了一个2D横板格斗游戏。

代码是自己写,图片是网上找的,角色的动画是用开源软件LPC character gen0.9生成的。


角色1


角色2



角色1的远程攻击

就是幻影剑舞。当然这个图片仅仅用来做游戏开发学习,不商用!



角色2的远程攻击

背景图片是用下面这张图片利用移位和循环播放效果制作成动态的游戏背景,看起来像是不断有月球经过。


# 更新背景

        background_x_1 -= background_speed

        background_x_2 -= background_speed

        if background_x_1 <= -background_width:

            background_x_1 = background_width

        if background_x_2 <= -background_width:

            background_x_2 = background_width

        # 绘制背景

        win.blit(background_image, (background_x_1, 0))

        win.blit(background_image, (background_x_2, 0))

有两个游戏音乐特效,一个是背景音乐,一个是游戏结束提示音。


一共两个类, fight类和Boss类。

class Boss:

    def __init__(self, x, y, idle_images, walk_images, attack_images, defend_images=None):

        self.x = x

        self.y = y

        self.idle_images = idle_images

        self.walk_images = walk_images

        self.attack_images = attack_images

        self.defend_images = defend_images

        self.current_images = idle_images

        self.image_index = 0

        self.image = self.current_images[self.image_index]

        self.vel = 5

        self.health = 100

        self.is_jump = False

        self.jump_count = 10

        self.attacking = False

        self.attack_start_time = 0

        self.attack_duration = 300

        self.attack_range = pygame.Rect(self.x, self.y, self.image.get_width() + 20, self.image.get_height())

        self.attack_objects = []

        self.state = FighterState.IDLE

        self.animation_speed = 100

        self.last_update = pygame.time.get_ticks()

        self.is_defending = False  # 新增防御状态标志

        self.defend_images = defend_images


    def draw(self, win):

        if self.attacking and pygame.time.get_ticks() - self.attack_start_time < self.attack_duration:

            win.blit(self.attack_images[self.image_index], (self.x, self.y))

        elif self.is_defending and self.defend_images:

            win.blit(self.defend_images[self.image_index], (self.x, self.y))

        else:

            win.blit(self.image, (self.x, self.y))

        for obj in self.attack_objects:

            obj.draw(win)




    def move(self, keys):

        if keys[pygame.K_LEFT] and self.x > 0:

            self.x -= self.vel

            self.state = FighterState.MOVING_LEFT

        elif keys[pygame.K_RIGHT] and self.x < WIDTH - self.image.get_width():

            self.x += self.vel

            self.state = FighterState.MOVING_RIGHT

        else:

            self.state = FighterState.IDLE

        if not self.is_jump:

            if keys[pygame.K_UP]:

                self.is_jump = True

                self.state = FighterState.JUMPING

        else:

            if self.jump_count >= -10:

                neg = 1

                if self.jump_count < 0:

                    neg = -1

                self.y -= (self.jump_count ** 2) * 0.5 * neg

                self.jump_count -= 1

            else:

                self.is_jump = False

                self.jump_count = 10

        if keys[pygame.K_d]: 

            self.state = FighterState.DEFENDING

            self.is_defending = True

            if self.defend_images:

                self.current_images = self.defend_images

        else:

            if not (keys[pygame.K_LEFT] or keys[pygame.K_RIGHT] or keys[pygame.K_UP]):

                self.state = FighterState.IDLE

                self.is_defending = False

                self.current_images = self.idle_images       

    def attack(self, opponent):

        if self.attacking and pygame.time.get_ticks() - self.attack_start_time < self.attack_duration:

            if self.attack_range.colliderect(opponent.rect()) and opponent.is_defending == False:

                opponent.health -= 10

    def release_attack_object(self):

        self.attacking = True

        self.attack_start_time = pygame.time.get_ticks()

        obj = AttackObject(self.x, self.y + self.image.get_height() // 2)

        self.attack_objects.append(obj)

    def rect(self):

        return pygame.Rect(self.x, self.y, self.image.get_width(), self.image.get_height())

    def update_attack_objects(self, opponent):

        for obj in self.attack_objects[:]:

            obj.move()

            if obj.off_screen():

                self.attack_objects.remove(obj)

            elif obj.collide(opponent) and opponent.is_defending == False:

                opponent.health -= 10

                self.attack_objects.remove(obj)

    def update_animation(self):

        now = pygame.time.get_ticks()

        if now - self.last_update > self.animation_speed:

            self.last_update = now

            if self.state == FighterState.IDLE:

                self.current_images = self.idle_images

            elif self.state == FighterState.MOVING_LEFT or self.state == FighterState.MOVING_RIGHT:

                self.current_images = self.walk_images

            elif self.state == FighterState.ATTACKING:

                self.current_images = self.attack_images

            elif self.state == FighterState.DEFENDING and self.defend_images:

                self.current_images = self.defend_images

            self.image_index = (self.image_index + 1) % len(self.current_images)

            self.image = self.current_images[self.image_index]

class Fighter:

    def __init__(self, x, y, idle_images, walk_images, attack_images, defend_images=None):

        self.x = x

        self.y = y

        self.idle_images = idle_images

        self.walk_images = walk_images

        self.attack_images = attack_images

        self.defend_images = defend_images

        self.current_images = idle_images

        self.image_index = 0

        self.image = self.current_images[self.image_index]

        self.vel = 5

        self.health = 100

        self.is_jump = False

        self.jump_count = 10

        self.attacking = False

        self.attack_start_time = 0

        self.attack_duration = 300

        self.attack_range = pygame.Rect(self.x, self.y, self.image.get_width() + 20, self.image.get_height())

        self.attack_objects = []

        self.state = FighterState.IDLE

        self.animation_speed = 100

        self.last_update = pygame.time.get_ticks()

        self.is_defending = False  # 新增防御状态标志

        self.defend_images = defend_images


    def draw(self, win):

        if self.attacking and pygame.time.get_ticks() - self.attack_start_time < self.attack_duration:

            win.blit(self.attack_images[self.image_index], (self.x, self.y))

        elif self.is_defending and self.defend_images:

            win.blit(self.defend_images[self.image_index], (self.x, self.y))

        else:

            win.blit(self.image, (self.x, self.y))

        for obj in self.attack_objects:

            obj.draw(win)




    def move(self, keys):

        if keys[pygame.K_LEFT] and self.x > 0:

            self.x -= self.vel

            self.state = FighterState.MOVING_LEFT

        elif keys[pygame.K_RIGHT] and self.x < WIDTH - self.image.get_width():

            self.x += self.vel

            self.state = FighterState.MOVING_RIGHT

        else:

            self.state = FighterState.IDLE

        if not self.is_jump:

            if keys[pygame.K_UP]:

                self.is_jump = True

                self.state = FighterState.JUMPING

        else:

            if self.jump_count >= -10:

                neg = 1

                if self.jump_count < 0:

                    neg = -1

                self.y -= (self.jump_count ** 2) * 0.5 * neg

                self.jump_count -= 1

            else:

                self.is_jump = False

                self.jump_count = 10

        if keys[pygame.K_d]: 

            self.state = FighterState.DEFENDING

            self.is_defending = True

            if self.defend_images:

                self.current_images = self.defend_images

        else:

            if not (keys[pygame.K_LEFT] or keys[pygame.K_RIGHT] or keys[pygame.K_UP]):

                self.state = FighterState.IDLE

                self.is_defending = False

                self.current_images = self.idle_images       

    def attack(self, opponent):

        if self.attacking and pygame.time.get_ticks() - self.attack_start_time < self.attack_duration:

            if self.attack_range.colliderect(opponent.rect()) and opponent.is_defending == False:

                opponent.health -= 10

    def release_attack_object(self):

        self.attacking = True

        self.attack_start_time = pygame.time.get_ticks()

        obj = fight1_AttackObject(self.x, self.y + self.image.get_height() // 4)

        self.attack_objects.append(obj)

    def rect(self):

        return pygame.Rect(self.x, self.y, self.image.get_width(), self.image.get_height())

    def update_attack_objects(self, opponent):

        for obj in self.attack_objects[:]:

            obj.move()

            if obj.off_screen():

                self.attack_objects.remove(obj)

            elif obj.collide(opponent) and opponent.is_defending == False:

                opponent.health -= 10

                self.attack_objects.remove(obj)

    def update_animation(self):

        now = pygame.time.get_ticks()

        if now - self.last_update > self.animation_speed:

            self.last_update = now

            if self.state == FighterState.IDLE:

                self.current_images = self.idle_images

            elif self.state == FighterState.MOVING_LEFT or self.state == FighterState.MOVING_RIGHT:

                self.current_images = self.walk_images

            elif self.state == FighterState.ATTACKING:

                self.current_images = self.attack_images

            elif self.state == FighterState.DEFENDING and self.defend_images:

                self.current_images = self.defend_images

            self.image_index = (self.image_index + 1) % len(self.current_images)

            self.image = self.current_images[self.image_index]

实现功能如下:

左边的角色1  可以 左右移动,上下跳跃(通过键盘上的方向键)。





左边的角色1 可以发动远程攻击,类似剑气一样, 攻击的时候会触发动画切换(其实就是切换图片)。




右边的角色2 可以发动冲击波攻击。




左边的角色1按下D键可以进入防御状态



防御状态下受到攻击生命值不会受到削减。

每个角色上面都有一个血条值,受到一次攻击会削减10%,任何一个角色的生命值为0时游戏结束。



# 游戏主循环

def main():

    # 加载资源

    fighter1_defend = [load_image("backgr/defend.png", alpha=True)]

    background_image = load_image("backgr/backgr77.JPG")

    background_width = background_image.get_width()

    background_x_1 = 0

    background_x_2 = background_width

    background_speed = 2

    fighter1_idle = [load_image("backgr/fighterd1.png", alpha=True)]

    fighter1_walk = [load_image("backgr/left.PNG", alpha=True), load_image("backgr/right.PNG", alpha=True)]

    fighter1_attack = [load_image("backgr/attack.png", alpha=True)]

    fighter2_idle = [load_image("backgr/fighter2222.png", alpha=True)]

    fighter2_walk = [load_image("backgr/evilrun.PNG", alpha=True), load_image("backgr/evilrun2.PNG", alpha=True)]

    fighter2_attack = [load_image("backgr/fighter2_attack.png", alpha=True)]

    # 创建角色

    fighter1 = Fighter(100, 400, fighter1_idle, fighter1_walk, fighter1_attack, fighter1_defend)

    fighter2 = Boss(700, 400, fighter2_idle, fighter2_walk, fighter2_attack)

    # 字体设置

    font = pygame.font.Font(None, 74)

    # 游戏主循环

    clock = pygame.time.Clock()

    run = True

    while run:

        clock.tick(60)

        # 更新背景

        background_x_1 -= background_speed

        background_x_2 -= background_speed

        if background_x_1 <= -background_width:

            background_x_1 = background_width

        if background_x_2 <= -background_width:

            background_x_2 = background_width

        # 绘制背景

        win.blit(background_image, (background_x_1, 0))

        win.blit(background_image, (background_x_2, 0))

        # 处理事件

        for event in pygame.event.get():

            if event.type == pygame.QUIT:

                run = False

            if event.type == pygame.KEYDOWN:

                if event.key == pygame.K_SPACE:

                  # fighter1.attacking = True

                    fighter1.release_attack_object()

                if event.key == pygame.K_RETURN:

                    fighter2.release_attack_object()

        # 获取按键状态

        keys = pygame.key.get_pressed()

        # 角色移动和攻击

        fighter1.move(keys)

        fighter1.attack(fighter2)

        fighter2.attack(fighter1)

        fighter1.update_attack_objects(fighter2)

        fighter2.update_attack_objects(fighter1)

        # 更新动画

        fighter1.update_animation()

        fighter2.update_animation()

        # 绘制角色

        fighter1.draw(win)

        fighter2.draw(win)

        # 绘制生命值条

        pygame.draw.rect(win, RED, (10, 10, 100, 20))

        pygame.draw.rect(win, YELLOW, (10, 10, fighter1.health, 20))

        pygame.draw.rect(win, RED, (WIDTH - 110, 10, 100, 20))

        pygame.draw.rect(win, YELLOW, (WIDTH - 110, 10, fighter2.health, 20))

        # 检查游戏结束

        if fighter1.health <= 0 or fighter2.health <= 0:

            text = font.render("Game Over", True, RED)

            game_over_sound.play()

            text_rect = text.get_rect(center=(WIDTH // 2, HEIGHT // 2))

            win.blit(text, text_rect)

        # 更新显示

        pygame.display.update()

    # 退出 Pygame

    pygame.quit()

    sys.exit()

if __name__ == "__main__":

    main()

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容