要求
1、物体移动主要因素:速度、方向;
2、移动的范围不能超出屏幕边界,当碰触到屏幕左右边界时,应更换方向;
3、可开启追踪模式,如果与Player在一定距离内,则追踪Player,否则,正常运行;
4、应增加一定随机性,增加运动的趣味性;
知识点
环境:
2D游戏;
物体通过Rigidbody2d来控制;
Rigidbody2d设置BodyType属性为Kinematic(不受重力等影响,可通过velocity来控制其运动)
1、Rigidbody2d.velocity分析
1、velocity可表示物体的速度和方向性
2、数值越大,表示速度越快
3、坐标系上、右为正方向,数值应为正数
4、坐标系左、下为负方向,数值应为负数
2、运动AI分析
1、碰撞屏幕边界自动转向能力:y方向不变,数值可波动;x方向改变,数值可波动;
2、自动追踪能力:距离限定
3、波动性:随机系数
3、追踪分析
1、一个正常运动的物体如何朝向另外一个物体运动,且速率基本不变?
2、计算两物体向量差值,取其normalized,指定给rigidbody.velocity属性即可实现追踪能力
Vector2 vDistance = target.transform.position - transform.position;
rigidbody.velocity = vDistance.normalized;
代码实现
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class EnemyMove : MonoBehaviour {
//velocity可表示物体的速度和方向性
//数值越大,表示速度越快
//坐标系上、右为正方向,数值应为正数
//坐标系左、下为负方向,数值应为负数
//运动AI:
//1、碰撞屏幕边界自动转向能力:y方向不变,数值可波动;x方向改变,数值可波动;
//2、自动追踪能力:距离限定
//3、波动性:随机系数
public float velocity_x = 0f;//x方向速度
public float velocity_y = 0f;//y方向速度
public float fluctuate = 0f;//速度波动范围
public bool doFollow = false;//追踪?
public float doFollowDistance = 2f;//触发追踪的有效距离
private bool isFollowing = false;//是否正在追踪
private Rigidbody2D rigidbody;//2D刚体组件
/// <summary>
/// 初始化运动参数
/// </summary>
/// <param name="velocity_x">x方向速度</param>
/// <param name="velocity_y">y方向速度</param>
/// <param name="fluctuate">速度波动范围</param>
public void reInit(float velocity_x, float velocity_y, float fluctuate){
this.velocity_x = velocity_x;
this.velocity_y = velocity_y;
this.fluctuate = fluctuate;
}
/// <summary>
/// 设置追踪参数
/// </summary>
/// <param name="doFollow">是否开启追踪模式</param>
/// <param name="doFollowDistance">触发追踪的有效距离</param>
public void setDoFollow(bool doFollow, float doFollowDistance){
this.doFollow = doFollow;
this.doFollowDistance = doFollowDistance;
}
void Awake() {
rigidbody = GetComponent<Rigidbody2D> ();
}
void Update () {
if(rigidbody == null){
return;
}
//如果开启了追踪模式,则执行自动追踪能力AI
if(doFollow){
moveFollow ();
}
//碰撞屏幕边界自动转向能力,同时波动速度大小
moveRotation ();
//移动
move ();
}
/// <summary>
/// 移动
/// </summary>
void move(){
//如果没有在追踪,则按照正常速度运行
if(!isFollowing){
rigidbody.velocity = new Vector2 (velocity_x, velocity_y);
}
}
/// <summary>
/// 碰撞屏幕边界自动转向能力,同时波动速度大小
/// </summary>
private void moveRotation(){
//检测是否与屏幕边界碰撞,如果是,则改变方向
if (AppCommon.isWidthBoundary (transform, velocity_x)) {
//仅x方向改变即可
velocity_x = -velocity_x;
//根据波动范围,波动速度的数值,使其效果更随机,AI更灵活智能
velocity_x = doFluctuate (velocity_x);
velocity_y = doFluctuate (velocity_y);
}
}
/// <summary>
/// 追踪模式
/// </summary>
private void moveFollow(){
//如果设定的距离为0,则不追踪
if(doFollowDistance == 0){
return;
}
//获得追踪目标对象,即Player
GameObject target = GameObject.FindGameObjectWithTag ("Player");
if(target == null){
return;
}
//获得与目标对象的距离,如果在触发追踪的有效距离内,则开始追踪Player
float distance = Vector2.Distance (target.transform.position, transform.position);
if(distance > doFollowDistance){
isFollowing = false;
return;
}
isFollowing = true;
//计算两物体向量差值,取其normalized,指定给rigidbody.velocity属性即可实现追踪能力
Vector2 vDistance = target.transform.position - transform.position;
rigidbody.velocity = vDistance.normalized;
}
/// <summary>
/// 波动数据
/// </summary>
/// <returns>波动后的值</returns>
/// <param name="value">需要波动的值</param>
private float doFluctuate(float value){
if (fluctuate != 0) {
float fluctuateAbs = Mathf.Abs (fluctuate);
float fluctuateRandom = Random.Range (-fluctuateAbs, fluctuateAbs);
value += fluctuateRandom;
}
return value;
}
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class AppCommon : MonoBehaviour {
public static float app_velocity = 1f;
private static float width;
private static float height;
private static float left;
private static float right;
private static float top;
private static float bottom;
void Start ()
{
Camera cam = Camera.main;
height = 2f * cam.orthographicSize;
width = height * cam.aspect;
left = -width / 2;
right = width / 2;
top = height / 2;
bottom = -height / 2;
}
/// <summary>
/// Ises the width boundary.
/// </summary>
/// <returns><c>true</c>, if width boundary was ised, <c>false</c> otherwise.</returns>
/// <param name="transform">Transform.</param>
/// <param name="h">The height.</param>
public static bool isWidthBoundary (Transform transform, float h)
{
//在left与right之间,返回false
//在left左边,手势为正方向,返回false
//在right右边,手势为反方向,返回false
if (transform.position.x > left && transform.position.x < right) {
return false;
}
if (transform.position.x < left && h > 0) {
return false;
}
if (transform.position.x > right && h < 0) {
return false;
}
return true;
}
/// <summary>
/// Ises the height boundary.
/// </summary>
/// <returns><c>true</c>, if height boundary was ised, <c>false</c> otherwise.</returns>
/// <param name="transform">Transform.</param>
/// <param name="v">V.</param>
public static bool isHeightBoundary (Transform transform,float v)
{
//在top与right之间,返回false
//在top上边,手势为正方向,返回false
//在bottom下边,手势为反方向,返回false
if (transform.position.y > bottom && transform.position.y < top) {
return false;
}
if (transform.position.y > top && v < 0) {
return false;
}
if (transform.position.y < bottom && v > 0) {
return false;
}
return true;
}
}