跳到主要内容

使用决策树实现智能游戏 AI

1. 简介

  在游戏开发中,人工智能(AI) 扮演着至关重要的角色。本教程将介绍如何利用 Dora SSR 引擎提供的 C4.5 决策树 算法来创建智能的游戏 AI。我们将通过一个简单的示例,逐步学习这一过程。

1.1 什么是决策树?

  决策树是一种类似于流程图的结构,用于辅助决策。想象一下我们在玩“猜动物”的游戏:

  这就是一个简单的决策树示例。在游戏 AI 中,我们可以使用类似的结构来做出智能决策。

2. 准备工作

  首先,我们需要准备训练数据。假设我们正在开发一个简单的格斗游戏 AI,需要决定何时攻击防守逃跑

2.1 准备训练数据(CSV 格式)

  训练数据的格式说明:

  • 第一行:包含所有特征的名称,例如“距离”、“敌人血量”等。
  • 第二行:定义每个特征的数据类型,其中:
    • C 表示分类(Categorical)数据,如“近”、“远”等离散值。
    • N 表示数值(Numerical)数据,如具体的血量数值。
  • 第三行开始:实际的训练数据,每行代表一个训练样本。
  • 最后一列:决策结果,即 AI 应采取的行动,这是决策树要学习预测的目标值,可以是分类值或数值。
距离,敌人血量,我方血量,行为
C,C,C,C
近,高,高,攻击
近,低,高,攻击
远,高,低,逃跑
中,中,低,防守
远,低,高,攻击

3. 基础代码实现

  让我们通过这组训练数据训练并生成一个决策树,以实现简单的战斗 AI:

local thread <const> = require("thread")
local ML <const> = require("ML")

-- 准备训练数据
local trainingData = [[
距离,敌人血量,我方血量,行为
C,C,C,C
近,高,高,攻击
近,低,高,攻击
远,高,低,逃跑
中,中,低,防守
远,低,高,攻击
]]

-- 构建决策树
function buildDecisionTreeAsync()
local trainingResult = {}

-- 最大深度设置为 3
local accuracy, err = ML.BuildDecisionTreeAsync(trainingData, 3, function(depth, name, op, value)
-- 根据深度添加缩进
local line = string.rep("\t", depth + 1)

-- 处理叶子节点(结果节点)
if op == "return" then
line = line .. 'return "' .. value .. '"'
else
-- 构建条件语句
local valueStr = (op == '==' and '"' .. value .. '"' or value)
line = line .. "if " .. name .. " " .. op .. " " .. valueStr
end
table.insert(trainingResult, line)
end)

if err then
print("构建决策树时出错:", err)
return
end

print("决策树准确度:", accuracy)
print("决策树结构:\n" .. table.concat(trainingResult, "\n"))

return trainingResult
end

-- 用下面的代码测试异步构建决策树
thread(buildDecisionTreeAsync)

3.1 可视化生成的决策树

  生成的决策树结构如下:

4. 在游戏中使用

  下面是一个简单的续写示例,展示如何在游戏角色中应用这个 AI 决策树:

local yue <const> = require("yue")
local Vec2 <const> = require("Vec2")

thread(function()
-- 构建决策树
local trainingResult = buildDecisionTreeAsync()

-- 加载决策树为一个 YueScript 函数
local decisionFunction = yue.loadstring(
"(data)->\n" ..
"\t:距离, :敌人血量, :我方血量 = data\n" ..
table.concat(trainingResult, "\n")
)()

-- 定义角色类
local Character = {}
function Character:new()
local char = {
position = Vec2.zero,
health = 100,
maxHealth = 100
}
setmetatable(char, {__index = Character})
return char
end

-- 根据血量百分比返回状态
function Character:getHealthState()
local healthPercent = self.health / self.maxHealth
if healthPercent > 0.7 then return "高"
elseif healthPercent > 0.3 then return "中"
else return "低" end
end

-- 根据实际距离返回状态
function Character:calculateDistance(enemy)
local distance = self.position:distance(enemy.position)
if distance < 50 then return "近"
elseif distance < 150 then return "中"
else return "远" end
end

-- 决定行动
function Character:decideAction(enemy)
return decisionFunction{
["距离"] = self:calculateDistance(enemy),
["敌人血量"] = enemy:getHealthState(),
["我方血量"] = self:getHealthState()
}
end

-- 更新角色状态并采取行动
function Character:update(enemy)
local action = self:decideAction(enemy)
-- 执行对应的行为
print("执行动作:" .. action)
end

-- 创建角色实例
local character = Character:new()
local enemy = Character:new()

-- 设置敌人的位置
enemy.position = Vec2(100, 100)
-- 当前角色应执行“攻击”
character:update(enemy)

-- 更新角色血量
character.health = 10
-- 当前角色应执行“防守”
character:update(enemy)
end)

5. 实际运用说明

5.1 决策树的优势

  决策树作为一种机器学习算法,在游戏 AI 开发中具有以下优势:

  • 易于理解和实现:决策树的结构直观,类似于人类的决策过程,便于开发者理解和实现复杂的决策逻辑。
  • 透明的决策过程:每个决策步骤都是清晰可见的,方便调试和优化 AI 的行为。
  • 灵活性强:可以根据游戏需求,随时调整决策树的结构和参数,使 AI 行为更符合设计目标。
  • 高效性:决策树在运行时仅需简单的条件判断,计算开销小,适合实时性要求高的游戏场景。

5.2 使用注意事项

  在使用决策树构建游戏 AI 时,需要注意以下几点:

  • 训练数据的代表性:确保训练数据覆盖各种可能的游戏情景,使 AI 能够应对不同的状态。建议使用真实玩家的数据作为训练样本。
  • 避免过拟合:决策树深度不宜过大,过深的树可能过度拟合训练数据,降低对新数据的泛化能力。可以从较小的深度开始,根据效果逐步调整。
  • 持续优化:在游戏运行过程中,持续收集新的数据,定期重新训练模型,使 AI 能够适应玩家的策略变化。

6. 进阶优化建议

  • 添加更多特征:例如:

    • 技能冷却时间
    • 可用道具数量
    • 周围地形信息
  • 动态调整 AI 行为

      在游戏过程中,可以根据玩家的行为数据,动态更新训练数据,重新训练决策树,使 AI 更贴近玩家的风格。

    function Character:updateAI(enemy, battleAction)
    -- 记录新的战斗数据
    local newTrainingData = string.format("%s,%s,%s,%s\n",
    self:calculateDistance(enemy),
    enemy:getHealthState(),
    self:getHealthState(),
    battleAction
    )
    trainingData = trainingData .. newTrainingData
    -- 定期重新训练 AI
    thread(function()
    buildDecisionTreeAsync()
    -- ... 其他处理逻辑
    end)
    end

7. 常见问题解答

  • Q: 决策树的深度应该设定为多少?

    A: 建议初始深度设置为 3 或 4。深度过大可能导致过拟合,深度过小可能无法捕捉复杂的决策逻辑。

  • Q: 如何改进 AI 的表现?

    A: 可以通过以下方式改进:

    • 增加训练数据的数量和多样性
    • 调整决策树的深度和参数
    • 添加更多有意义的特征(如环境因素、敌人类型等)
  • Q: 需要多少训练数据才够?

    A: 起初可以使用 50-100 条数据,根据游戏复杂度和测试结果,逐步增加数据量以提升 AI 的准确性。

8. 总结

  通过本教程,我们学习了:

  • 决策树的基本概念:理解了决策树如何辅助决策,以及其在游戏 AI 中的应用。
  • 如何准备训练数据:掌握了构建有效训练数据集的方法,为模型训练打下基础。
  • 使用 Dora SSR 的 ML 模块构建决策树:学会了如何利用引擎提供的工具,快速构建决策树模型。
  • 在游戏中实际应用决策树:了解了如何将训练好的模型整合到游戏逻辑中,实现智能决策。
  • 优化和改进 AI 系统的方法:认识到持续优化的重要性,以及如何通过调整模型和数据来提升 AI 的表现。

  记住,一个优秀的游戏 AI 不仅要有复杂的算法,更要能提升玩家的游戏体验。通过不断地调整和优化,你可以创造出既有趣又具有挑战性的游戏 AI。