Transferred from: http://blog.csdn.net/zhangxiao13627093203/article/details/47658673
The previous article talked about the simpler form of the tracking algorithm, which looks fake because AI-controlled objects track targets too precisely. A more natural way of tracking can be done so that the tracer's direction vector is aligned with the direction vectors defined from the center of the tracking target to the center of the tracker. :
The basic idea of this algorithm is this: Assume that the AI-controlled object, the tracker, has the following properties
1, Position: (TRACKER.X,TRACKER.Y)
2. Velocity: (Tracker.vx,tracker.vy)
The tracking target has the following properties:
1, postion: (TARGET.X,TARGET.Y)
2. Velocity: (Target.vx,target.vy)
The next step is to adjust the common logic of the tracker's speed vectors:
1, the calculation from the tracker to the tracking target vector: tv= (target.x-tracker.x,target.y-tracker.y) = (tvx,tvy), normalized TV, so you can get a unit vector, so as to facilitate the calculation of its angle with the axis. Normalization is also known as sqrt (x^2+y^2).
2, adjust the tracker's current speed vector, plus a rate proportional to the tv*
TRACKER.X+=RATE*TVX;
Traker.y+=rate*tvy;
Note that this step is the key, it makes the missile tracking is not the previous direct close tracking but there will be a change trajectory of the process, in addition, when rate equals 1, the tracking vector rendezvous faster, tracking algorithm to target tracking the basis of close, and faster to correct the movement of the target.
3, after the tracking speed vector modification, it is possible that the speed of the vector will overflow the maximum value. In other words, the tracker will continue to accelerate in that direction once the target's direction is locked. So you need to set an upper limit so that the tracker slows down from somewhere.
Implemented in Unity5.1.1: Here I also adjusted the direction of the missile tracking rotation change, in fact, if it is 3D space can be directly used LookAt method to make the direction of the missile's motion always toward the target, but in the 2D plane there is no such a good way for us to call, so I wrote an algorithm. If you do not add this direction to correct the results of the algorithm:
The operation of the missile is not very stiff, the trajectory of the motion and the direction of the missile head is not consistent, this section of the revised missile head of the code as follows:
void Lookattarget () { float zangles; if (movevy==0) { zangles = movevx >= 0? -90:90; } Zangles = Mathf.atan (movevx/movevy) * ( -180/MATHF.PI); if (movevy<0) { zangles = zAngles-180; } Vector3 tempangles = new Vector3 (0, 0, zangles); quaternion tempqua = this.transform.rotation; Tempqua.eulerangles = Tempangles; This.transform.rotation = Tempqua; }
The calculation method of the algorithm is:
Note: The angle on this plane is mainly the angle of the z-axis, and the angle of the z-axis is the angle between the straight and the y-axis of the missile head, which is more painful than the egg. In addition, the vertex of the coordinate is located in the upper left corner of the screen.
1. Adjust the direction of the missile head according to the velocity vector of the missile
2, the speed vector of the missile is the vector of X and y direction, and calculates the angle between the missile and the screen coordinate y-axis according to the inverse trigonometric function.
3, pay special attention to the situation when the Movevy is 0, do not consider this will lead to the calculation of the reverse triangle when the denominator is zero and error due to overflow, and Movevy less than 0, do not consider this will make the direction just think.
The final code is:
Sing Unityengine; Using System.Collections; Using Unityengine.ui; public class Aitrackadvanced:monobehaviour {public Image target; public float target_movespeed; Public float min_trackingrate;//the smallest tracking vector change rate public float Min_trackingdis; public float Max_trackingvel; Public float movevx;//x Direction Speed public float movevy;//y direction speed//Use this for initialization void Start () { }//update is called once per frame void Update () {Debug.Log (Mathf.atan (Movevx/mov EVy) * ( -180/MATHF.PI))); Lookattarget (); This.transform.position + = new Vector3 (MOVEVX * time.deltatime, Movevy * time.deltatime, 0); Movetarget (); Track_aiadvanced (); Checkmoveboundary (); } void Lookattarget () {float zangles; if (movevy==0) {zangles = Movevx >= 0? -90:90; } zangles = Mathf.atan (Movevx/movevy) * (-180 /Mathf.pi); if (movevy<0) {zangles = zAngles-180; } Vector3 tempangles = new Vector3 (0, 0, zangles); quaternion Tempqua = this.transform.rotation; Tempqua.eulerangles = Tempangles; This.transform.rotation = Tempqua; }///<summary>///keyboard to control moving target////</summary> void Movetarget () {Float x = Input.getaxis ("horizontal") * 100; Float y = input.getaxis ("Vertical") * 100; If the screen is out of range, let it appear on the other side target.transform.Translate (x * time.deltatime * target_movespeed, y * time.deltatime * target _movespeed, 0); if (target.transform.position.x >= screen.width) {//Use the target.recttransform.lossyscale.x of the image to table Image width Target.transform.position = new Vector3 (-target.recttransform.lossyscale.x, Target.transform.positio N.Y, 0); } else if (Target.transform.position.x <-TARGET.RECTTRANSFOrm.lossyscale.x) {target.transform.position = new Vector3 (Screen.width, TARGET.TRANSFORM.POSITION.Y , 0); } if (Target.transform.position.y >= screen.height) {target.transform.position = new Ve Ctor3 (target.transform.position.x,-target.recttransform.lossyscale.y, 0); } else if (Target.transform.position.y <-target.recttransform.lossyscale.y) {target.tr Ansform.position = new Vector3 (target.transform.position.x, screen.height, 0); }}///<summary>//Tracking algorithm///</summary> void track_aiadvanced () {//Count Calculate and track the direction vector of the target float VX = target.transform.position.x-this.transform.position.x; float VY = TARGET.TRANSFORM.POSITION.Y-THIS.TRANSFORM.POSITION.Y; Float length = pointdistance_2d (VX, VY); If the distance is reached, trace if (length<min_trackingdis) {VX = Min_trackingrate * Vx/length; VY = Min_trackingrate * VY/LENGTH; MOVEVX + = VX; Movevy + = VY; Add a bit of perturbation if (Random.range (1,10) ==1) {VX = Random.range (-1, 1); VY = Random.range (-1, 1); MOVEVX + = VX; Movevy + = VY; } length = pointdistance_2d (Movevx,movevy); If the missile flies too fast, let it slow down if (length>max_trackingvel) {//Let it slow down move Vx *= 0.75f; Movevy *= 0.75f; }}//If not in the tracking range, random motion else {if (Random.range (1,10) ==1) {vx= Random.range (-2, 2); VY = Random.range (-2, 2); MOVEVX + = VX; Movevy + = VY; } length = pointdistance_2d (Movevx, Movevy); If the missile flies too fast,Just let it slow down if (length > Max_trackingvel) {//Let it slow down movevx *= 0. 75f; Movevy *= 0.75f; }} this.transform.position + = new Vector3 (MOVEVX * time.deltatime, Movevy * time.deltatime, 0); }///<summary>//Calculate the distance from 0 to this point///</summary>//<param name= "x" ></param> <param name= "y" ></param>///<returns></returns> float pointdistance_2d (float x, Float y) {//used the Taylor expansion to calculate, there are 3.5% of errors, the direct use of the root calculation will be slower, but the test of my computer seems to be no change may be the amount of data is not reflected/*x = Mathf.abs (x); y = mathf.abs (y); float MN = Mathf.min (x, y);//Gets the smallest number in X, y, float result = x + y-(MN/2)-(MN/4) + (MN/8); */float result = MATHF.SQRT (x * x + y * y); return result; } void Checkmoveboundary () {//detects if the boundary is exceeded if (this.transform.position.x >= ScReen.width) {this.transform.position = new Vector3 (-this. Getcomponent<image> (). recttransform.lossyscale.x, 0, 0); } else if (This.transform.position.x <-this. Getcomponent<image> (). recttransform.lossyscale.x) {this.transform.position = new Vector3 (scre En.width, THIS.TRANSFORM.POSITION.Y, 0); } if (This.transform.position.y >= screen.height) {this.transform.position = new Vector 3 (this.transform.position.x,-this. Getcomponent<image> (). recttransform.lossyscale.y, 0); } else if (This.transform.position.y <-this. Getcomponent<image> (). recttransform.lossyscale.y) {this.transform.position = new Vector3 (this . transform.position.x, Screen.height, 0); } } }
Finally, I enclose the project, which is the demo program I wrote with Unity5.1.1, and also includes the demo program in the previous two articles. Click to open link
Unity AI Learning-the tracking algorithm of deterministic AI algorithm II