游戏AI-实现AI角色的自主移动——操控行为

Unity操控行为编程的基类:Vehicle类、AILocomotion类和Steering类

1.将AI角色抽象成一个质点——Vehicle类

这个类直译为“交通工具”包括了很宽泛的能自主移动的AI角色。
操作对象抽象为一个质点,包含位置信息、质量、速度等,速度随着施加力的变化而变化。力与速度都有一个限制,因此还需要最大力、最大速度。还需要一个朝向。
位置计算方法
1.每一帧的力(最大不超过最大力)
2.交通工具的质量,来确定加速度
3.加速度与原速度相加,得到新的速度
4.新的速度与一帧的时间相乘,计算出位移
5.原位置加上位移得到新位置

此类通过获取AI角色的操控行为列表,对表中的行为进行带权重的求和,再求得加速度

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Vehicle : MonoBehaviour {

    //操控行为的列表
    private Steering[] steerings;
    //最大速度
    public float maxSpeed = 10f;
    //能施加的最大力
    public float maxForce = 100;
    //最大速度平方
    protected float sqrMaxSpeed;

    public float mass = 1;
    public Vector3 velocity;

    //转向速度
    public float damping = 0.9f;

    //操控力的计算间隔,操控力每隔一段时间进行计算,来提高帧率
    public float computeInterval = 0.2f;

    //是否在平面上
    public bool isPlanar = true;

    //计算得到的操控力
    private Vector3 steeringForce;

    //加速度
    protected Vector3 acceleration;

    private float timer;


    protected void Start () {
        steeringForce = new Vector3(0, 0, 0);
        sqrMaxSpeed = maxSpeed * maxSpeed;
        timer = 0;
        //获得AI角色上的全部操控行为
        steerings = GetComponents<Steering>();
    }


    
    // Update is called once per frame
    void Update () {
        timer += Time.deltaTime;
        steeringForce = new Vector3(0, 0, 0);
        //力量检测时间一定间隔后才重新计算
        if (timer > computeInterval)
        {
            //AI最终被施加的力,就是各个力的权值相乘后的和
            foreach (var item in steerings)
            {
                if (item.enabled)
                {
                    steeringForce += item.Force() * item.weight;
                }
            }
            //ClampMagnitude方法返回一个Vector(maxForce,maxForce,maxForce)与steeringForce中更小的一个
            steeringForce = Vector3.ClampMagnitude(steeringForce, maxForce);
            //F = ma
            acceleration = steeringForce / mass;
            timer = 0;
        }       
    }
}

2.控制AI角色移动——AILocomotion类

真正控制AI角色的移动,计算每次移动的距离播放动画等

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

//控制角色移动的类
public class AILocomotion : Vehicle {

    private CharacterController characterController;
    private Rigidbody theRigidbody;
    //每次移动的距离
    private Vector3 moveDistance;

    // Use this for initialization
    void Start () {
        characterController = GetComponent<CharacterController>();
        theRigidbody = GetComponent<Rigidbody>();
        moveDistance = new Vector3(0, 0, 0);
        //调用基类的Start(),对所需进行初始化
        base.Start();
    }

    //物理相关操作在FixedUpdate中进行
    private void FixedUpdate()
    {
        //计算速度
        velocity += acceleration * Time.fixedDeltaTime;
        //限制速度 velocity.sqrMagnitude 即为向量三个值的平方和
        if (velocity.sqrMagnitude > sqrMaxSpeed)
        {
            velocity = velocity.normalized * maxSpeed;
        }
        //计算位移
        moveDistance = velocity * Time.fixedDeltaTime;

        //如果要让AI在平面上移动,将y设置为0;
        if (isPlanar)
        {
            velocity.y = 0;
            moveDistance.y = 0;
        }

        //有角色控制器,直接传速度
        if (characterController != null)
        {
            characterController.SimpleMove(velocity);
        }
        //没有角色控制器和刚体
        //或有刚体但要由动力学方式控制
        else if (theRigidbody == null || theRigidbody.isKinematic)
        {
            transform.position += moveDistance;
        }
        //通过刚体控制
        else
        {
            theRigidbody.MovePosition(theRigidbody.position + moveDistance);
        }
        //更新朝向,如果速度大于一个阈值(防止抖动)
        if(velocity.sqrMagnitude > 0.0001)
        {

            //通过当前朝向和速度方向插值,计算新的朝向
            Vector3 newForward = Vector3.Lerp
                (transform.forward, velocity, damping * Time.fixedDeltaTime);
            //将y值设置为0
            if (isPlanar)
            {
                newForward.y = 0;
            }
            transform.forward = newForward;
        }

        //播放动画
        //gameObject.GetComponent<Animation>().Play("walk");

    }
}
3.各种操控行为的基类——Steering类

Steering类操控行为的基类,包括操控行为共有的变量和方法,操控AI角色的寻找、逃跑、躲避等都可由此类派生
此类为抽象类,每个子类有定义自己的权重,重写操控力的计算方法

public abstract class Steering : MonoBehaviour {
    //操控力的权重
    public float weight = 1;
    //操控力的计算方法
    public virtual Vector3 Force()
    {
        return new Vector3(0, 0, 0);
    }
}
  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值