前往小程序,Get更优阅读体验!
立即前往
发布
社区首页 >专栏 >AI 助力游戏开发实践-有限状态机

AI 助力游戏开发实践-有限状态机

原创
作者头像
腾讯云AI代码助手
发布2025-01-08 10:47:25
发布2025-01-08 10:47:25
7600
代码可运行
举报
运行总次数:0
代码可运行

文章摘要

本文用实际案例讲述了腾讯 AI 代码助手是如何在 FSM 的开发过程中提供了高效的代码补全、优化和知识共享支持,显著提升了开发效率和代码质量的。

全文阅读约 3-5 分钟。

引言

在数字娱乐产业中,游戏开发无疑是最具活力和创新性的领域之一。随着技术的进步和玩家需求的日益增长,游戏开发者面临着前所未有的挑战和机遇。游戏不仅要在图形和玩法上不断创新,还要提供流畅的用户体验和智能的游戏逻辑。在这样的背景下,有限状态机(FSM)成为了游戏开发中一个不可或缺的工具,它为游戏角色和系统的行为提供了一种清晰、可控的实现方式。

有限状态机(FSM)基础

定义和基本概念

有限状态机(FSM)是一种计算模型,它可以根据一组规则从一个状态转换到另一个状态。这种模型由有限个状态、事件和转换组成,广泛应用于计算机科学和软件工程中,特别是在需要对系统行为进行建模和控制的场合。在 FSM 中,状态代表了系统的某种情况或条件,事件是导致状态转换的触发器,而转换则定义了从一个状态到另一个状态的具体路径。

 FSM 的核心思想是将复杂的行为分解为一系列简单的状态和事件。每个状态都对应着系统在某一时刻的行为,而事件则是导致系统从一个行为切换到另一个行为的原因。这种模型的优势在于其简单性和可预测性,使得系统的行为更容易被理解和控制。

为何游戏开发需要使用有限状态机

在游戏开发初期,开发者通常会依赖于复杂的条件判断(if-else语句)来管理角色的状态和行为。这种编程方式在初期可能看起来简单直接,但随着游戏逻辑的增加和复杂性的提升,它会导致代码难以维护和扩展。以下是一些具体的问题和对应的代码示例:

代码冗余和复杂性高

使用 if-else 来控制角色动作的时候,角色的每个行为都需要通过一系列的条件判断来实现,这会导致代码重复和复杂性增加。例如,为了处理角色的跳跃、下蹲和下斩攻击,代码可能会变得非常冗长和难以管理:

代码语言:javascript
代码运行次数:0
复制

void Heroine::handleInput(Input input) {
    if (input == PRESS_UP) {
        if (!isJumping_ && !isDucking_) {
            isJumping_ = true;
            yVelocity_ = JUMP_VELOCITY;
            setGraphics(IMAGE_JUMP);
        }
    } else if (input == PRESS_DOWN) {
        if (!isJumping_) {
            isDucking_ = true;
            setGraphics(IMAGE_DUCK);
        } else {
            isJumping_ = false;
            setGraphics(IMAGE_DIVE);
        }
    } else if (input == RELEASE_DOWN) {
        if (isDucking_) {
            isDucking_ = false;
            setGraphics(IMAGE_STAND);
        }
    }
    // 其他状态
}

这段代码中,每个 if-else 块都依赖于多个布尔变量,随着新状态的添加,这些变量之间的关系变得越来越复杂,增加了代码出错的风险。

状态冲突和逻辑错误

在没有状态机的情况下,角色的状态管理可能会导致一些逻辑错误,比如角色可能在空中尝试再次跳跃,或者在下蹲时错误地开始跳跃。以下是具体的代码示例:

代码语言:javascript
代码运行次数:0
复制

bool isJumping_ = false;
bool isDucking_ = false;

void Heroine::handleInput(Input input) {
    if (input == PRESS_UP) {
        if (!isJumping_) { // 这里应该还要检查是否在地面上
            isJumping_ = true;
            yVelocity_ = JUMP_VELOCITY;
            setGraphics(IMAGE_JUMP);
        }
    } else if (input == PRESS_DOWN) {
        if (!isJumping_) {
            isDucking_ = true;
            setGraphics(IMAGE_DUCK);
        } else {
            // 这里尝试在跳跃时进行下蹲,逻辑上是错误的
            isJumping_ = false; // 这会导致角色突然停止跳跃
            setGraphics(IMAGE_DIVE);
        }
    } else if (input == RELEASE_DOWN) {
        if (isDucking_) {
            isDucking_ = false;
            setGraphics(IMAGE_STAND);
        }
    }
    // 这里缺少了跳跃结束的逻辑,导致isJumping_可能永远为true
}33

难以扩展和维护

随着游戏功能的增加,基于 if-else 的代码结构会变得越来越难以扩展和维护。每次添加新功能或状态时,都需要修改多个条件判断,这不仅增加了工作量,也增加了引入新 bug 的风险。比如在已有状态基础上,添加行走状态后,我们需要在多个地方添加对 isWalking_ 的检查,这使得代码变得更加复杂。如果未来还需要添加更多的状态或行为,这种模式将导致代码难以维护,且容易出错。每次修改都可能影响到其他部分的逻辑,导致 bug 的产生。这就是为什么在游戏开发中,使用有限状态机是一个更好的选择。

 FSM 在游戏开发中的作用

在游戏开发中, FSM 扮演着至关重要的角色。它主要用于管理游戏对象(如角色、敌人、NPC)的行为状态,以及游戏世界的状态(如游戏关卡、天气系统)。以下是 FSM 在游戏开发中的一些主要作用:

行为控制: FSM 允许开发者定义游戏角色在不同情况下的行为,如站立、行走、奔跑、攻击等,并通过事件(如玩家输入、敌人接近)来触发这些行为之间的转换。

逻辑简化:通过将复杂的逻辑分解为简单的状态和事件, FSM 有助于简化游戏逻辑的开发和维护。

状态预测: FSM 提供了一种预测游戏对象行为的方式,这对于游戏 AI 和敌人行为的预测尤为重要。

代码组织: FSM 有助于组织代码,使得状态相关的代码块保持在一起,提高了代码的可读性和可维护性。

调试和测试: FSM 使得游戏逻辑的调试和测试变得更加容易,因为开发者可以清晰地看到状态之间的转换和触发这些转换的事件。

 FSM 的组成部分:状态、事件、转换

 FSM 由三个主要部分组成:状态、事件和转换。

状态(States):状态是 FSM 中最基本的元素,代表了系统的一个具体条件或行为。在游戏开发中,状态可以是角色的“行走”、“攻击”或“受伤”等。

事件(Events):事件是导致状态转换的触发器。它们可以是玩家的输入、游戏世界的变化或其他游戏对象的行为。事件通常会导致 FSM 从一个状态切换到另一个状态。

转换(Transitions):转换定义了从一个状态到另一个状态的具体路径。每个转换都与一个事件相关联,并指定了在该事件发生时应该切换到哪个状态。

在实际应用中, FSM 可以通过图表或代码来表示。图表形式的 FSM 有助于直观地展示状态之间的转换关系,而代码形式则更便于实现和调试。无论哪种形式, FSM 都是游戏开发中一个强大的工具,它使得游戏逻辑的构建和管理变得更加高效和系统化。

实际案例:

游戏物体的状态切换

为了更直观地展示有限状态机在游戏开发中的应用,我们将通过一个具体的代码示例来描述其在游戏物体状态切换中的开发过程,下面是一个简单的物体移动与状态转换的示例。

确定状态和转换条件

首先,我们需要明确游戏物体可能存在的状态以及状态之间的转换条件。以一个简单的 2D 角色为例,它可能有以下几种状态:

Idle(空闲):角色没有进行任何移动操作。

Moving(移动):角色根据玩家的输入进行水平移动。

状态之间的转换条件如下:

当玩家没有进行任何水平方向的输入时,角色从 Moving 状态转换到 Idle 状态。

当玩家进行水平方向的输入时,角色从 Idle 状态转换到 Moving 状态。

接下来,我们需要设计一个状态机框架来管理这些状态和转换。这个框架包括一个基类 BaseState ,用于定义状态的基本行为,以及一个 StateMachine 类,用于控制状态的切换和执行状态的行为。

代码语言:javascript
代码运行次数:0
复制

// BaseState.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public abstract class BaseState
{
    public string name;
    protected StateMachine stateMachine;

    public BaseState(string name, StateMachine stateMachine)
{
        this.name = name;
        this.stateMachine = stateMachine;
    }

    public virtual void Enter() { }
    public virtual void UpdateLogic() { }
    public virtual void UpdatePhysics() { }
    public virtual void Exit() { }
代码语言:javascript
代码运行次数:0
复制

// StateMachine.cs
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class StateMachine : MonoBehaviour
{
    BaseState currentState;

    void Start()
{
        currentState = GetInitialState();
        if (currentState != null)
        {
            currentState.Enter();
        }
    }

    void Update()
{
        if (currentState != null)
            currentState.UpdateLogic();
    }

    void LateUpdate()
{
        if (currentState != null)
            currentState.UpdatePhysics();
    }

    public void ChangeState(BaseState newState)
{
        currentState.Exit();
        currentState = newState;
        currentState.Enter();
    }

    protected virtual BaseState GetInitialState()
{
        return null;
    }
}

在代码编写过程中,可以通过腾讯云 AI 代码助手的代码补全能力,帮助我们进行工程级别的感知与准确补全。

实现具体状态

有了状态机框架之后,我们可以根据之前确定的状态来实现具体的 Idle 和 Moving 状态。可以使用 AI 代码补全来生成物体移动代码

集成到游戏物体中

最后,我们需要将状态机集成到游戏物体中,使其能够根据状态机的控制来执行相应的行为。这里我们创建了一个 MovementSM 类,用于管理角色的状态机,并在 Awake 方法中初始化状态机的初始状态。

代码语言:javascript
代码运行次数:0
复制

// MovementSM.cs
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class MovementSM : StateMachine
{
    [HideInInspector]
    public Idle idleState;
    [HideInInspector]
    public Moving movingState;
    public SpriteRenderer spriteRenderer;
    public Rigidbody2D rb;
    public float speed = 4f;

    void Awake()
{
        idleState = new Idle(this);
        movingState = new Moving(this);
    }

    protected override BaseState GetInitialState()
{
        return idleState;
    }
}

最终效果展示

通过这个实际案例,我们可以看到有限状态机在游戏物体状态切换中的应用价值,以及腾讯云 AI 代码助手在开发过程中提供的有力支持。希望这个示例能够帮助大家更好地理解和掌握有限状态机的设计与实现,从而在游戏开发中更加高效地管理游戏物体的行为状态。

实际案例:

游戏智能 NPC 的巡逻行为

在肉鸽游戏或开放世界游戏中,智能 NPC 是游戏世界真实性和互动性的重要组成部分。NPC 的行为逻辑是由多层次的人工智能(AI)系统设计和实现的,旨在创造出令人信服且具有挑战性的游戏体验。NPC 行为逻辑的核心原理包括有限状态机(FSM)、行为树(Behavior Tree)和感知系统(Perception System)。

其中,NPC 的巡逻行为主要通过有限状态机(FSM)来实现。以下图为例,一个怪物的基本状态包括:待机状态、巡逻状态、追击状态、攻击状态、受伤状态、死亡状态。

在实际开发过程中,我们可以使用腾讯云 AI 代码助手,使用 #Codebase 的能力,结合当前工程的已有代码来生成解决方案, 同时在命令中结合 “#Unity 设计模式” 这个知识库,让生成的答案更准确。

从知识库召回了状态机的相关知识和实现代码
从知识库召回了状态机的相关知识和实现代码
从当前代码工程中,找到实现本需求的相关性代码
从当前代码工程中,找到实现本需求的相关性代码
状态机的实现代码
状态机的实现代码
敌人类的相关实现
敌人类的相关实现

可以看到,腾讯云 AI 代码助手不仅帮我们生成了符合需求的状态机代码,包括 IState.cs、PatrolState.cs、ChaseState.cs 等,还给出了当前的敌人类、玩家类的修改建议。

我们可以继续补充巡逻与追击逻辑代码,可以结合腾讯云 AI 代码助手的代码补全功能,在具体的编码文件中通过上下文准确补全。比如在追击过程中,我们需要让怪物保持移动,并且注意移动过程中的方向翻转。

同时,也可以使用代码优化能力,在写完功能之后,优化相关方法。

写完状态逻辑之中,我们可以在敌人类中,实例化状态,并完成状态转换的业务逻辑

通过代码对话和代码补全功能,我们可以逐步完成通过状态机实现 NPC 的巡逻机制,下面是最终展示效果:

总结

通过本次实践,我们深刻认识到有限状态机(FSM)在游戏开发中管理复杂逻辑和行为状态方面的强大能力,它使得代码结构更加清晰、易于维护和扩展。同时,腾讯云 AI 代码助手在 FSM 的开发过程中提供了高效的代码补全、优化和知识共享支持,显著提升了开发效率和代码质量。未来,FSM 有望与其他 AI 技术结合,实现更高级的游戏逻辑,推动游戏开发向更高水平发展,为玩家带来更丰富、智能的游戏体验。

欢迎扫码入群了解更多 AI 编码知识。

https://copilot.tencent.com/
https://copilot.tencent.com/

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 文章摘要
  • 引言
  • 有限状态机(FSM)基础
    • 定义和基本概念
    • 为何游戏开发需要使用有限状态机
    • 代码冗余和复杂性高
    • 状态冲突和逻辑错误
    • 难以扩展和维护
    •  FSM 在游戏开发中的作用
    •  FSM 的组成部分:状态、事件、转换
  • 实际案例:
    • 游戏物体的状态切换
    • 实现具体状态
    • 集成到游戏物体中
    • 最终效果展示
  • 实际案例:
    • 游戏智能 NPC 的巡逻行为
  • 总结
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档