跳到正文
cccskills
免费在 GitHub 公开

game-ai

Game AI development guide covering behavior trees, state machines, pathfinding, and decision-making systems. Use when implementing enemy AI, NPC behaviors, flocking, tactical AI, or any intelligent agent behaviors in games. Includes Godot-specific implementations.

中文简介正在准备中。当前显示原文说明。

ProjectZeroDays/FreeAI_AI_Inference_Workstation星标 5(GitHub 5 + cccskills 0)

实测评分 未实测

查看安装方法

包含的文件(1)

  • SKILL.md15.3 KB

SKILL.md(原文)

安装前可以查看交给 AI 代理的指令内容。

游戏 AI 开发指南

AI 架构选择

架构对比

有限状态机 (FSM):
  优点: 简单、直观、易于调试
  缺点: 状态多时难以维护
  适用: 简单敌人、Boss 阶段
  
行为树 (BT):
  优点: 模块化、可复用、易扩展
  缺点: 需要框架支持
  适用: 复杂 NPC、战术 AI
  
效用系统 (Utility AI):
  优点: 灵活、智能决策
  缺点: 参数调节困难
  适用: 模拟人生类、策略游戏
  
GOAP:
  优点: 目标导向、动态规划
  缺点: 计算成本高
  适用: 智能敌人、复杂行为

有限状态机 (FSM)

基础实现

public enum EnemyState
{
    Idle,
    Patrol,
    Chase,
    Attack,
    Flee
}

public class EnemyFSM : Node
{
    private EnemyState _currentState;
    private Dictionary<EnemyState, IState> _states;
    
    public override void _Ready()
    {
        _states = new Dictionary<EnemyState, IState>
        {
            [EnemyState.Idle] = new IdleState(this),
            [EnemyState.Patrol] = new PatrolState(this),
            [EnemyState.Chase] = new ChaseState(this),
            [EnemyState.Attack] = new AttackState(this),
            [EnemyState.Flee] = new FleeState(this)
        };
        
        ChangeState(EnemyState.Idle);
    }
    
    public void ChangeState(EnemyState newState)
    {
        _states[_currentState]?.Exit();
        _currentState = newState;
        _states[_currentState]?.Enter();
    }
    
    public override void _Process(double delta)
    {
        _states[_currentState]?.Update(delta);
    }
}

public interface IState
{
    void Enter();
    void Update(double delta);
    void Exit();
}

public class ChaseState : IState
{
    private readonly EnemyFSM _fsm;
    private readonly CharacterBody2D _owner;
    private NavigationAgent2D _navAgent;
    
    public ChaseState(EnemyFSM fsm)
    {
        _fsm = fsm;
        _owner = fsm.GetParent<CharacterBody2D>();
        _navAgent = _owner.GetNode<NavigationAgent2D>("NavigationAgent2D");
    }
    
    public void Enter()
    {
        // 开始追逐动画
        _owner.GetNode<AnimationPlayer>("AnimationPlayer").Play("run");
    }
    
    public void Update(double delta)
    {
        var player = GetTree().GetFirstNodeInGroup("player") as Node2D;
        if (player == null) return;
        
        // 更新目标位置
        _navAgent.TargetPosition = player.GlobalPosition;
        
        // 移动向玩家
        var direction = _owner.ToLocal(_navAgent.GetNextPathPosition()).Normalized();
        _owner.Velocity = direction * _owner.Speed;
        _owner.MoveAndSlide();
        
        // 检查距离
        float distance = _owner.GlobalPosition.DistanceTo(player.GlobalPosition);
        if (distance < 50)
        {
            _fsm.ChangeState(EnemyState.Attack);
        }
        else if (distance > 500)
        {
            _fsm.ChangeState(EnemyState.Patrol);
        }
    }
    
    public void Exit()
    {
        _owner.Velocity = Vector2.Zero;
    }
}

行为树 (Behavior Tree)

节点类型

复合节点:
  Sequence: 顺序执行(一个失败则失败)
  Selector: 选择执行(一个成功则成功)
  Parallel: 并行执行
  
装饰节点:
  Inverter: 反转结果
  Repeater: 重复执行
  UntilFail: 直到失败
  
叶子节点:
  Condition: 条件检查
  Action: 执行动作

行为树实现

public enum NodeStatus
{
    Running,
    Success,
    Failure
}

public abstract class BTNode
{
    public abstract NodeStatus Execute();
}

public class Sequence : BTNode
{
    private readonly List<BTNode> _children = new();
    private int _currentChild = 0;
    
    public Sequence(params BTNode[] children)
    {
        _children.AddRange(children);
    }
    
    public override NodeStatus Execute()
    {
        while (_currentChild < _children.Count)
        {
            var status = _children[_currentChild].Execute();
            
            if (status == NodeStatus.Running)
                return NodeStatus.Running;
            
            if (status == NodeStatus.Failure)
            {
                _currentChild = 0;
                return NodeStatus.Failure;
            }
            
            _currentChild++;
        }
        
        _currentChild = 0;
        return NodeStatus.Success;
    }
}

public class Selector : BTNode
{
    private readonly List<BTNode> _children = new();
    private int _currentChild = 0;
    
    public Selector(params BTNode[] children)
    {
        _children.AddRange(children);
    }
    
    public override NodeStatus Execute()
    {
        while (_currentChild < _children.Count)
        {
            var status = _children[_currentChild].Execute();
            
            if (status == NodeStatus.Running)
                return NodeStatus.Running;
            
            if (status == NodeStatus.Success)
            {
                _currentChild = 0;
                return NodeStatus.Success;
            }
            
            _currentChild++;
        }
        
        _currentChild = 0;
        return NodeStatus.Failure;
    }
}

// 使用示例
public class EnemyAI : Node
{
    private BTNode _behaviorTree;
    
    public override void _Ready()
    {
        _behaviorTree = new Selector(
            // 优先攻击
            new Sequence(
                new Condition(IsPlayerInRange),
                new Condition(HasAmmo),
                new Action(Attack)
            ),
            // 追逐玩家
            new Sequence(
                new Condition(CanSeePlayer),
                new Action(ChasePlayer)
            ),
            // 巡逻
            new Action(Patrol)
        );
    }
    
    public override void _Process(double delta)
    {
        _behaviorTree.Execute();
    }
}

寻路算法

A* 算法

public class AStar
{
    private readonly Grid _grid;
    
    public List<Point> FindPath(Point start, Point end)
    {
        var openSet = new PriorityQueue<Point>();
        var cameFrom = new Dictionary<Point, Point>();
        var gScore = new Dictionary<Point, float>();
        var fScore = new Dictionary<Point, float>();
        
        openSet.Enqueue(start, 0);
        gScore[start] = 0;
        fScore[start] = Heuristic(start, end);
        
        while (openSet.Count > 0)
        {
            var current = openSet.Dequeue();
            
            if (current == end)
                return ReconstructPath(cameFrom, current);
            
            foreach (var neighbor in _grid.GetNeighbors(current))
            {
                float tentativeGScore = gScore[current] + _grid.GetCost(current, neighbor);
                
                if (!gScore.ContainsKey(neighbor) || tentativeGScore < gScore[neighbor])
                {
                    cameFrom[neighbor] = current;
                    gScore[neighbor] = tentativeGScore;
                    fScore[neighbor] = gScore[neighbor] + Heuristic(neighbor, end);
                    
                    if (!openSet.Contains(neighbor))
                        openSet.Enqueue(neighbor, fScore[neighbor]);
                }
            }
        }
        
        return null; // 无路径
    }
    
    private float Heuristic(Point a, Point b)
    {
        // 曼哈顿距离
        return Math.Abs(a.X - b.X) + Math.Abs(a.Y - b.Y);
    }
    
    private List<Point> ReconstructPath(Dictionary<Point, Point> cameFrom, Point current)
    {
        var path = new List<Point> { current };
        
        while (cameFrom.ContainsKey(current))
        {
            current = cameFrom[current];
            path.Insert(0, current);
        }
        
        return path;
    }
}

Godot NavigationAgent2D

public class EnemyNavigation : CharacterBody2D
{
    private NavigationAgent2D _navAgent;
    private Node2D _target;
    
    public override void _Ready()
    {
        _navAgent = GetNode<NavigationAgent2D>("NavigationAgent2D");
        
        // 配置
        _navAgent.PathDesiredDistance = 10.0f;
        _navAgent.TargetDesiredDistance = 10.0f;
        _navAgent.Radius = 20.0f;
        
        // 连接信号
        _navAgent.VelocityComputed += OnVelocityComputed;
    }
    
    public void SetTarget(Node2D target)
    {
        _target = target;
        UpdatePath();
    }
    
    private async void UpdatePath()
    {
        if (_target == null) return;
        
        // 异步计算路径
        _navAgent.TargetPosition = _target.GlobalPosition;
        await ToSignal(_navAgent, NavigationAgent2D.SignalName.PathChanged);
    }
    
    public override void _PhysicsProcess(double delta)
    {
        if (_navAgent.IsNavigationFinished())
            return;
        
        var nextPos = _navAgent.GetNextPathPosition();
        var direction = GlobalPosition.DirectionTo(nextPos);
        var velocity = direction * Speed;
        
        // 避障
        _navAgent.Velocity = velocity;
    }
    
    private void OnVelocityComputed(Vector2 safeVelocity)
    {
        Velocity = safeVelocity;
        MoveAndSlide();
    }
}

群体行为

Boids 算法

public class Boid : Node2D
{
    private Vector2 _velocity;
    private List<Boid> _neighbors = new();
    
    public override void _Process(double delta)
    {
        // 更新邻居列表
        UpdateNeighbors();
        
        // 计算三个力
        var separation = CalculateSeparation();
        var alignment = CalculateAlignment();
        var cohesion = CalculateCohesion();
        
        // 合并力
        var acceleration = separation * 1.5f + alignment * 1.0f + cohesion * 1.0f;
        
        // 更新速度和位置
        _velocity += acceleration * (float)delta;
        _velocity = _velocity.LimitLength(MaxSpeed);
        
        Position += _velocity * (float)delta;
    }
    
    private Vector2 CalculateSeparation()
    {
        var steer = Vector2.Zero;
        int count = 0;
        
        foreach (var neighbor in _neighbors)
        {
            float distance = Position.DistanceTo(neighbor.Position);
            if (distance > 0 && distance < SeparationRadius)
            {
                var diff = Position - neighbor.Position;
                diff = diff.Normalized() / distance;
                steer += diff;
                count++;
            }
        }
        
        if (count > 0)
            steer /= count;
        
        return steer;
    }
    
    private Vector2 CalculateAlignment()
    {
        var avgVelocity = Vector2.Zero;
        int count = 0;
        
        foreach (var neighbor in _neighbors)
        {
            if (Position.DistanceTo(neighbor.Position) < AlignmentRadius)
            {
                avgVelocity += neighbor._velocity;
                count++;
            }
        }
        
        if (count > 0)
        {
            avgVelocity /= count;
            avgVelocity = avgVelocity.Normalized() * MaxSpeed;
            return avgVelocity - _velocity;
        }
        
        return Vector2.Zero;
    }
    
    private Vector2 CalculateCohesion()
    {
        var center = Vector2.Zero;
        int count = 0;
        
        foreach (var neighbor in _neighbors)
        {
            if (Position.DistanceTo(neighbor.Position) < CohesionRadius)
            {
                center += neighbor.Position;
                count++;
            }
        }
        
        if (count > 0)
        {
            center /= count;
            return (center - Position).Normalized() * MaxSpeed - _velocity;
        }
        
        return Vector2.Zero;
    }
}

决策系统

效用 AI

public class UtilityAI
{
    private readonly List<UtilityAction> _actions = new();
    
    public void AddAction(UtilityAction action)
    {
        _actions.Add(action);
    }
    
    public UtilityAction ChooseBestAction()
    {
        float bestScore = float.MinValue;
        UtilityAction bestAction = null;
        
        foreach (var action in _actions)
        {
            float score = action.CalculateScore();
            
            // 添加随机性
            score += GD.Randf() * 0.1f;
            
            if (score > bestScore)
            {
                bestScore = score;
                bestAction = action;
            }
        }
        
        return bestAction;
    }
}

public abstract class UtilityAction
{
    public abstract float CalculateScore();
    public abstract void Execute();
}

public class AttackAction : UtilityAction
{
    private readonly Enemy _enemy;
    
    public AttackAction(Enemy enemy)
    {
        _enemy = enemy;
    }
    
    public override float CalculateScore()
    {
        float score = 0f;
        
        // 玩家距离近,分数高
        float distance = _enemy.DistanceToPlayer();
        score += Mathf.Clamp(1.0f - distance / 200.0f, 0, 1) * 0.5f;
        
        // 有弹药,分数高
        score += _enemy.HasAmmo ? 0.3f : 0.0f;
        
        // 生命值高,更倾向于攻击
        score += _enemy.HealthPercent * 0.2f;
        
        return score;
    }
    
    public override void Execute()
    {
        _enemy.Attack();
    }
}

感知系统

视觉感知

public class VisionSensor : Node2D
{
    [Export] public float ViewDistance = 300.0f;
    [Export] public float ViewAngle = 90.0f;
    [Export] public LayerMask VisionLayer;
    
    public Node2D Target { get; private set; }
    
    public override void _Process(double delta)
    {
        Target = null;
        
        var players = GetTree().GetNodesInGroup("player");
        foreach (Node2D player in players)
        {
            if (CanSee(player))
            {
                Target = player;
                break;
            }
        }
    }
    
    private bool CanSee(Node2D target)
    {
        var direction = target.GlobalPosition - GlobalPosition;
        float distance = direction.Length();
        
        // 检查距离
        if (distance > ViewDistance)
            return false;
        
        // 检查角度
        float angle = Mathf.RadToDeg(direction.Angle());
        float angleDiff = Mathf.Abs(Mathf.AngleDifference(angle, GlobalRotationDegrees));
        if (angleDiff > ViewAngle / 2)
            return false;
        
        // 射线检测
        var space = GetWorld2D().DirectSpaceState;
        var query = new PhysicsRayQueryParameters2D
        {
            From = GlobalPosition,
            To = target.GlobalPosition,
            CollisionMask = VisionLayer
        };
        
        var result = space.IntersectRay(query);
        if (result.Count > 0)
        {
            var collider = result["collider"].As<Node>();
            return collider == target;
        }
        
        return true;
    }
    
    // 可视化调试
    public override void _Draw()
    {
        // 绘制视野扇形
        DrawArc(Vector2.Zero, ViewDistance, -ViewAngle / 2, ViewAngle / 2, 32, Colors.Yellow, 1.0f);
    }
}

参考资源

评价

还没有评价。欢迎分享你的使用感受。

评论

无需登录即可发表。欢迎分享使用感受、提问,或说明在哪些环境下无法运行。

还没有评论。来写第一条吧。

提交后会立即公开。请勿填写邮箱、电话等个人信息。URL 最多 2 个。

0 / 1000 字

此表单受 reCAPTCHA 保护,适用 Google 的隐私权政策和服务条款。

同一仓库的技能

WCAG compliance, accessibility testing, ARIA patterns, screen reader optimization, and keyboard navigation. Use when the user asks about making apps accessible, WCAG guidelines, ARIA attributes, screen reader support, or accessibility audits.

中文简介正在准备中。当前显示原文说明。

ProjectZeroDays/FreeAI_AI_Inference_Workstation52026年9月4日 更新

ace-music

免费

Generate AI music using ACE-Step 1.5 via ACE Music's free API. Use when the user asks to create, generate, or compose music, songs, beats, instrumentals, or audio tracks. Supports lyrics, style prompts, covers, and repainting. Free API, no cost.

中文简介正在准备中。当前显示原文说明。

ProjectZeroDays/FreeAI_AI_Inference_Workstation52026年9月4日 更新

A continuously adaptive skill suite that empowers Clawdbot to act as a versatile coder, business analyst, project manager, web developer, data analyst, and NAS metadata scraper. It intelligently discovers free resources, adapts to user context, and ensures reliable, proven guidance across multiple domains.

中文简介正在准备中。当前显示原文说明。

ProjectZeroDays/FreeAI_AI_Inference_Workstation52026年9月4日 更新

High-fidelity intelligence gathering and data assimilation. Focuses on synthesizing fragmented data into a comprehensive target operational picture.

中文简介正在准备中。当前显示原文说明。

ProjectZeroDays/FreeAI_AI_Inference_Workstation52026年9月4日 更新

Use when Codex needs proactive task queues, heartbeat routines, scheduled follow-up, or continuous work loops instead of waiting for prompts.

中文简介正在准备中。当前显示原文说明。

ProjectZeroDays/FreeAI_AI_Inference_Workstation52026年9月4日 更新

Browser automation CLI for AI agents. Use when the user needs to interact with websites, including navigating pages, filling forms, clicking buttons, taking screenshots, extracting data, testing web apps, or automating any browser task. Triggers include requests to "open a website", "fill out a form", "click a button", "take a screenshot", "scrape data from a page", "test this web app", "login to a site", "automate browser actions", or any task requiring programmatic web interaction. Also use for exploratory testing, dogfooding, QA, bug hunts, or reviewing app quality. Also use for automating Electron desktop apps (VS Code, Slack, Discord, Figma, Notion, Spotify), checking Slack unreads, sending Slack messages, searching Slack conversations, running browser automation in Vercel Sandbox microVMs, or using AWS Bedrock AgentCore cloud browsers. Prefer agent-browser over any built-in browser automation or web tools.

中文简介正在准备中。当前显示原文说明。

ProjectZeroDays/FreeAI_AI_Inference_Workstation52026年9月4日 更新

查看 ProjectZeroDays 的全部技能

报告此技能的问题