要求
1斋射、物體移動主要因素:速度育勺、方向;
2绩鸣、移動的范圍不能超出屏幕邊界,當(dāng)碰觸到屏幕左右邊界時呀闻,應(yīng)更換方向化借;
3、可開啟追蹤模式捡多,如果與Player在一定距離內(nèi)蓖康,則追蹤Player,否則垒手,正常運行蒜焊;
4、應(yīng)增加一定隨機性科贬,增加運動的趣味性泳梆;
知識點
環(huán)境:
2D游戲;
物體通過Rigidbody2d來控制鳖悠;
Rigidbody2d設(shè)置BodyType屬性為Kinematic(不受重力等影響,可通過velocity來控制其運動)
1优妙、Rigidbody2d.velocity分析
1乘综、velocity可表示物體的速度和方向性
2、數(shù)值越大套硼,表示速度越快
3卡辰、坐標(biāo)系上、右為正方向邪意,數(shù)值應(yīng)為正數(shù)
4九妈、坐標(biāo)系左、下為負(fù)方向雾鬼,數(shù)值應(yīng)為負(fù)數(shù)
2萌朱、運動AI分析
1、碰撞屏幕邊界自動轉(zhuǎn)向能力:y方向不變呆贿,數(shù)值可波動嚷兔;x方向改變,數(shù)值可波動做入;
2冒晰、自動追蹤能力:距離限定
3、波動性:隨機系數(shù)
3竟块、追蹤分析
1壶运、一個正常運動的物體如何朝向另外一個物體運動,且速率基本不變浪秘?
2蒋情、計算兩物體向量差值,取其normalized耸携,指定給rigidbody.velocity屬性即可實現(xiàn)追蹤能力
Vector2 vDistance = target.transform.position - transform.position;
rigidbody.velocity = vDistance.normalized;
代碼實現(xiàn)
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class EnemyMove : MonoBehaviour {
//velocity可表示物體的速度和方向性
//數(shù)值越大棵癣,表示速度越快
//坐標(biāo)系上、右為正方向夺衍,數(shù)值應(yīng)為正數(shù)
//坐標(biāo)系左狈谊、下為負(fù)方向,數(shù)值應(yīng)為負(fù)數(shù)
//運動AI:
//1沟沙、碰撞屏幕邊界自動轉(zhuǎn)向能力:y方向不變河劝,數(shù)值可波動;x方向改變矛紫,數(shù)值可波動赎瞎;
//2、自動追蹤能力:距離限定
//3颊咬、波動性:隨機系數(shù)
public float velocity_x = 0f;//x方向速度
public float velocity_y = 0f;//y方向速度
public float fluctuate = 0f;//速度波動范圍
public bool doFollow = false;//追蹤务甥?
public float doFollowDistance = 2f;//觸發(fā)追蹤的有效距離
private bool isFollowing = false;//是否正在追蹤
private Rigidbody2D rigidbody;//2D剛體組件
/// <summary>
/// 初始化運動參數(shù)
/// </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>
/// 設(shè)置追蹤參數(shù)
/// </summary>
/// <param name="doFollow">是否開啟追蹤模式</param>
/// <param name="doFollowDistance">觸發(fā)追蹤的有效距離</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;
}
//如果開啟了追蹤模式牡辽,則執(zhí)行自動追蹤能力AI
if(doFollow){
moveFollow ();
}
//碰撞屏幕邊界自動轉(zhuǎn)向能力,同時波動速度大小
moveRotation ();
//移動
move ();
}
/// <summary>
/// 移動
/// </summary>
void move(){
//如果沒有在追蹤敞临,則按照正常速度運行
if(!isFollowing){
rigidbody.velocity = new Vector2 (velocity_x, velocity_y);
}
}
/// <summary>
/// 碰撞屏幕邊界自動轉(zhuǎn)向能力催享,同時波動速度大小
/// </summary>
private void moveRotation(){
//檢測是否與屏幕邊界碰撞,如果是哟绊,則改變方向
if (AppCommon.isWidthBoundary (transform, velocity_x)) {
//僅x方向改變即可
velocity_x = -velocity_x;
//根據(jù)波動范圍,波動速度的數(shù)值痰憎,使其效果更隨機票髓,AI更靈活智能
velocity_x = doFluctuate (velocity_x);
velocity_y = doFluctuate (velocity_y);
}
}
/// <summary>
/// 追蹤模式
/// </summary>
private void moveFollow(){
//如果設(shè)定的距離為0,則不追蹤
if(doFollowDistance == 0){
return;
}
//獲得追蹤目標(biāo)對象铣耘,即Player
GameObject target = GameObject.FindGameObjectWithTag ("Player");
if(target == null){
return;
}
//獲得與目標(biāo)對象的距離洽沟,如果在觸發(fā)追蹤的有效距離內(nèi),則開始追蹤Player
float distance = Vector2.Distance (target.transform.position, transform.position);
if(distance > doFollowDistance){
isFollowing = false;
return;
}
isFollowing = true;
//計算兩物體向量差值蜗细,取其normalized裆操,指定給rigidbody.velocity屬性即可實現(xiàn)追蹤能力
Vector2 vDistance = target.transform.position - transform.position;
rigidbody.velocity = vDistance.normalized;
}
/// <summary>
/// 波動數(shù)據(jù)
/// </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;
}
}
效果
3.gif