Пару месяцев назад начал осваивать Юньку ... Всё шло хорошо, пока не добрался до написания кода ИИ ... Т.к. использую инди-версию, NAVIGATOR (NAVMESH), соответственно, не работает. Пришлось скачать замену - AstarPathfindingProject ... Кое-как разобрался, как сделать, чтобы моб начал преследование на определённой дистанции и атаку на ближней, чтобы поворачивался всегда лицом ко Мне и проигрывались соответствующие анимации ... Но проблема в том, что если между Мной и мобом стена , а расстояние соответствует расстоянию агра, то моб всё-равно Меня "видит" и рулит ко Мне ... Покопавшись в интернетах, понял, что можно решить эту проблему , например, рэйкастом , но не могу понять , как именно вписать код с райкастом в скрипт AIFollow , который идёт в комплекте с AstarPathfindingProject и в котором происходит всё вышеперечисленное ... Будьте добры, подскажите как решить эту проблему. Может не райкастом, а как-то по-ругому .... Скрипт этот на шарпе ...
Сообщение отредактировал TheReaper - Чт, 24 Янв 2013, 23:43
using UnityEngine; using System.Collections; using Pathfinding;
/** Example AI. * \deprecated This script has been deprecated, use AIPath or MineBotAI instead */ [RequireComponent (typeof(Seeker))] [RequireComponent (typeof(CharacterController))] public class AIFollow : MonoBehaviour {
/** Target to move to */ public Transform target;
/** How often to search for a new path */ public float repathRate = 0.1F;
/** The minimum distance to a waypoint to consider it as "reached" */ public float pickNextWaypointDistance = 2F;
/** The minimum distance to the end point of a path to consider it "reached" (multiplied with #pickNextWaypointDistance). * This value is multiplied with #pickNextWaypointDistance before it is used. Recommended range [0...1] */ public float targetReached = 1.0F;
/** Units per second */ public float speed = 6;
/** How fast the AI can turn around */ public float rotationSpeed = 7;
public bool drawGizmos = false;
/** Should paths be searched for. * Setting this to false will make the AI not search for paths anymore, can save some CPU cycles. * It will check every #repathRate seconds if it should start to search for paths again. * \note It will not cancel paths which are currently being calculated */ public bool canSearch = true;
/** Can it move. Enables or disables movement and rotation */ public bool canMove = true;
/** CharacterController which handles movement */ protected CharacterController controller;
/** NavmeshController which handles movement if not null*/ protected NavmeshController navmeshController;
/** Transform, cached because of performance */ protected Transform tr;
protected float lastPathSearch = -9999;
protected int pathIndex = 0;
/** This is the path the AI is currently following */ protected Vector3[] path;
/** Use this for initialization */ public void Start () { seeker = GetComponent<Seeker>(); controller = GetComponent<CharacterController>(); navmeshController = GetComponent<NavmeshController>();
tr = transform; Repath (); }
/** Will make the AI give up it's current path and stop completely. */ public void Reset () { path = null; }
/** Called when a path has completed it's calculation */ public void OnPathComplete (Path p) {
//If the path didn't succeed, don't proceed if (p.error) { return; }
//Get the calculated path as a Vector3 array path = p.vectorPath;
//Find the segment in the path which is closest to the AI //If a closer segment hasn't been found in '6' iterations, break because it is unlikely to find any closer ones then float minDist = Mathf.Infinity; int notCloserHits = 0;
/** Waits the remaining time until the AI should issue a new path request. * The remaining time is defined by Time.time - lastPathSearch */ public IEnumerator WaitToRepath () { float timeLeft = repathRate - (Time.time-lastPathSearch);
yield return new WaitForSeconds (timeLeft); Repath (); }
/** Stops the AI. * Also stops new search queries from being made * \version Before 3.0.8 This does not prevent new path calls from making the AI move again * \see #Resume * \see #canMove * \see #canSearch */ public void Stop () { canMove = false; canSearch = false; }
/** Resumes walking and path searching the AI. * \version Added in 3.0.8 * \see #Stop * \see #canMove * \see #canSearch */ public void Resume () { canMove = true; canSearch = true; }
/** Recalculates the path to #target. * Queries a path request to the Seeker, the path will not be calculated instantly, but will be put on a queue and calculated as fast as possible. * It will wait if the current path request by this seeker has not been completed yet. * \see Seeker::IsDone */ public virtual void Repath () { lastPathSearch = Time.time;
//for (int i=0;i<1000;i++) { //MultithreadPath mp = new MultithreadPath (transform.position,target.position,null); //Path p = new Path (transform.position,target.position,null); // AstarPath.StartPath (mp); //} //Debug.Log (AstarPath.pathQueue.Count);
//StartCoroutine (WaitToRepath ()); /*ConstantPath cpath = new ConstantPath(transform.position,null); //Must be set to avoid it from searching towards Vector3.zero cpath.heuristic = Heuristic.None; //Here you set how far it should search cpath.maxGScore = 2000; AstarPath.StartPath (cpath);*/ //FloodPathTracer fpathTrace = new FloodPathTracer (transform.position,fpath,null); //seeker.StartPath (fpathTrace,OnPathComplete);
Path p = new Path(transform.position,target.position,null); seeker.StartPath (p,OnPathComplete); //Start a new path from transform.positon to target.position, return the result to the function OnPathComplete //seeker.StartPath (transform.position,target.position,OnPathComplete); }
/** Start a new path moving to \a targetPoint */ public void PathToTarget (Vector3 targetPoint) { lastPathSearch = Time.time;
if (seeker == null) { return; }
//Start a new path from transform.positon to target.position, return the result to OnPathComplete seeker.StartPath (transform.position,targetPoint,OnPathComplete); }
/** Called when the AI reached the end of path. * This will be called once for every path it completes, so if you have a really fast repath rate it will call this function often if when it stands on the end point. */ public virtual void ReachedEndOfPath () { //The AI has reached the end of the path //Set animation tr.animation.Play("attack"); tr.LookAt(target.position); tr.eulerAngles = new Vector3(0, tr.eulerAngles.y, 0); }
/** Update is called once per frame */ public void Update () {
//Change target to the next waypoint if the current one is close enough Vector3 currentWaypoint = path[pathIndex]; currentWaypoint.y = tr.position.y; while ((currentWaypoint - tr.position).sqrMagnitude < pickNextWaypointDistance*pickNextWaypointDistance) { pathIndex++; if (pathIndex >= path.Length) { //Use a lower pickNextWaypointDistance for the last point. If it isn't that close, then decrement the pathIndex to the previous value and break the loop if ((currentWaypoint - tr.position).sqrMagnitude < (pickNextWaypointDistance*targetReached)*(pickNextWaypointDistance*targetReached)) { ReachedEndOfPath (); return; } else { pathIndex--; //Break the loop, otherwise it will try to check for the last point in an infinite loop break; } } currentWaypoint = path[pathIndex]; currentWaypoint.y = tr.position.y; }
Vector3 dir = currentWaypoint - tr.position;
// Rotate towards the target tr.rotation = Quaternion.Slerp (tr.rotation, Quaternion.LookRotation(dir), rotationSpeed * Time.deltaTime); tr.eulerAngles = new Vector3(0, tr.eulerAngles.y, 0);
/** Draws helper gizmos. * Currently draws a circle around the current target point with the size showing how close the AI need to get to it for it to count as "reached". */ public void OnDrawGizmos () {
есть очень хороший пример по раю в справке юньки. вот этот а именно :
Код
void Update() { Vector3 fwd = transform.TransformDirection(Vector3.forward); if (Physics.Raycast(transform.position, fwd, 10)) print("There is something in front of the object!");
} }
этот код разъясняется так :
Код
Vector3 fwd = transform.TransformDirection(Vector3.forward); // создается вектор направления луча, //направлен он вперед от нашего игрока(transform), ну по идее //не обязательно игрока, это может быть что угодно . if (Physics.Raycast(transform.position, fwd, 10)) // если Луч(позиция, откуда будет бросаться наш луч(в данном случае это наш субъект(transform)) и // задается направление (fwd), которую мы задавали выше // и расстояние "10" , 10 юнитов/метров. // Получается у нас, тут условие : Если от начальной точки, до точки конца луча на 10 юнитов есть что-нибудь, то пишется print("There is something in front of the object!"); // вот это
А вот урок , где разъясняют довольна четко про райкаст и столкновения с лучом . Ссылка_ТЫК С помощью этого, сделайте мобов умнее :))
Сообщение отредактировал thiefbrother - Вт, 22 Янв 2013, 15:50
БЛИН ! Написал ответ, а он не появился :(( Ща заново наштампую БЛАГОДАРЮ ЗА ОТВЕТ Я уже кое-что разчехлил ... Вот решил сделать зрение при помощи триггера-бокса и лайнкаста. Триггер повесил на моба так, чтобы он ловил игрока по площади спереди и по бокам (типа бокового зрения), ну , а лайн проверяет нет ли прекрад между мобом и гроком , и ввёл переменную VIDIT, которая становится правдивой, когда именно ИГРОК попадает в триггер и луч его достаёт. Вот скрипт using UnityEngine;
if (other.gameObject.name == "Player1") { VIDIT = false;}
}
}
Добавлено (22.01.2013, 21:53) --------------------------------------------- Блин , опять неправильно код вставил сюда ... Надо между рамочками ? :)) Ну, так вот ... Это только скрипт зрения, сам по себе он работает нормально, а нахождение пути и передвижение в других находятся ... Так вот теперь Я не могу никак нормально эти скрипты соединить. Вот , в частности, нужно это "зрение" добавить в скрипт AIFollow, который Я подготовил, как мог, но результат неутешительный ... Может подскажет Кто как правильно прицепить ЗРЕНИЕ К СЛЕЖЕНИЮ Переменная VIDIT открытая, использую её из скрипта AIFollow , там для этого переменная VZOR
Код
using UnityEngine; using System.Collections; using Pathfinding;
/** Example AI. * \deprecated This script has been deprecated, use AIPath or MineBotAI instead */ [RequireComponent (typeof(Seeker))] [RequireComponent (typeof(CharacterController))] public class AIFollow : MonoBehaviour { public bool VZOR; /** Target to move to */ public Transform target;
/** How often to search for a new path */ public float repathRate = 0.1F;
/** The minimum distance to a waypoint to consider it as "reached" */ public float pickNextWaypointDistance = 2F;
/** The minimum distance to the end point of a path to consider it "reached" (multiplied with #pickNextWaypointDistance). * This value is multiplied with #pickNextWaypointDistance before it is used. Recommended range [0...1] */ public float targetReached = 1.0F;
/** Units per second */ public float speed = 6;
/** How fast the AI can turn around */ public float rotationSpeed = 7;
public bool drawGizmos = false;
/** Should paths be searched for. * Setting this to false will make the AI not search for paths anymore, can save some CPU cycles. * It will check every #repathRate seconds if it should start to search for paths again. * \note It will not cancel paths which are currently being calculated */ public bool canSearch = true;
/** Can it move. Enables or disables movement and rotation */ public bool canMove = true;
/** CharacterController which handles movement */ protected CharacterController controller;
/** NavmeshController which handles movement if not null*/ protected NavmeshController navmeshController;
/** Transform, cached because of performance */ protected Transform tr;
protected float lastPathSearch = -9999;
protected int pathIndex = 0;
/** This is the path the AI is currently following */ protected Vector3[] path;
/** Use this for initialization */ public void Start () { seeker = GetComponent<Seeker>(); controller = GetComponent<CharacterController>(); navmeshController = GetComponent<NavmeshController>();
tr = transform; Repath (); }
/** Will make the AI give up it's current path and stop completely. */ public void Reset () { path = null; }
/** Called when a path has completed it's calculation */ public void OnPathComplete (Path p) {
//If the path didn't succeed, don't proceed if (p.error) { return; }
//Get the calculated path as a Vector3 array path = p.vectorPath;
//Find the segment in the path which is closest to the AI //If a closer segment hasn't been found in '6' iterations, break because it is unlikely to find any closer ones then float minDist = Mathf.Infinity; int notCloserHits = 0;
/** Waits the remaining time until the AI should issue a new path request. * The remaining time is defined by Time.time - lastPathSearch */ public IEnumerator WaitToRepath () { float timeLeft = repathRate - (Time.time-lastPathSearch);
yield return new WaitForSeconds (timeLeft); Repath (); }
/** Stops the AI. * Also stops new search queries from being made * \version Before 3.0.8 This does not prevent new path calls from making the AI move again * \see #Resume * \see #canMove * \see #canSearch */ public void Stop () { canMove = false; canSearch = false; }
/** Resumes walking and path searching the AI. * \version Added in 3.0.8 * \see #Stop * \see #canMove * \see #canSearch */ public void Resume () { canMove = true; canSearch = true; }
/** Recalculates the path to #target. * Queries a path request to the Seeker, the path will not be calculated instantly, but will be put on a queue and calculated as fast as possible. * It will wait if the current path request by this seeker has not been completed yet. * \see Seeker::IsDone */ public virtual void Repath () { lastPathSearch = Time.time;
//for (int i=0;i<1000;i++) { //MultithreadPath mp = new MultithreadPath (transform.position,target.position,null); //Path p = new Path (transform.position,target.position,null); // AstarPath.StartPath (mp); //} //Debug.Log (AstarPath.pathQueue.Count);
//StartCoroutine (WaitToRepath ()); /*ConstantPath cpath = new ConstantPath(transform.position,null); //Must be set to avoid it from searching towards Vector3.zero cpath.heuristic = Heuristic.None; //Here you set how far it should search cpath.maxGScore = 2000; AstarPath.StartPath (cpath);*/ //FloodPathTracer fpathTrace = new FloodPathTracer (transform.position,fpath,null); //seeker.StartPath (fpathTrace,OnPathComplete);
Path p = new Path(transform.position,target.position,null); seeker.StartPath (p,OnPathComplete); //Start a new path from transform.positon to target.position, return the result to the function OnPathComplete //seeker.StartPath (transform.position,target.position,OnPathComplete); }
/** Start a new path moving to \a targetPoint */ public void PathToTarget (Vector3 targetPoint) { lastPathSearch = Time.time;
if (seeker == null) { return; }
//Start a new path from transform.positon to target.position, return the result to OnPathComplete seeker.StartPath (transform.position,targetPoint,OnPathComplete); }
/** Called when the AI reached the end of path. * This will be called once for every path it completes, so if you have a really fast repath rate it will call this function often if when it stands on the end point. */ public virtual void ReachedEndOfPath () { //The AI has reached the end of the path //Set animation tr.animation.Play("attack"); tr.LookAt(target.position); tr.eulerAngles = new Vector3(0, tr.eulerAngles.y, 0); }
/** Update is called once per frame */ public void Update () { VZOR = GameObject.Find("TRIG").GetComponent<ZRENIE>().VIDIT; if(VZOR == true) {
//Change target to the next waypoint if the current one is close enough Vector3 currentWaypoint = path[pathIndex]; currentWaypoint.y = tr.position.y; while ((currentWaypoint - tr.position).sqrMagnitude < pickNextWaypointDistance*pickNextWaypointDistance) { pathIndex++; if (pathIndex >= path.Length) { //Use a lower pickNextWaypointDistance for the last point. If it isn't that close, then decrement the pathIndex to the previous value and break the loop if ((currentWaypoint - tr.position).sqrMagnitude < (pickNextWaypointDistance*targetReached)*(pickNextWaypointDistance*targetReached)) { ReachedEndOfPath (); return; } else { pathIndex--; //Break the loop, otherwise it will try to check for the last point in an infinite loop break; } } currentWaypoint = path[pathIndex]; currentWaypoint.y = tr.position.y; }
Vector3 dir = currentWaypoint - tr.position;
// Rotate towards the target tr.rotation = Quaternion.Slerp (tr.rotation, Quaternion.LookRotation(dir), rotationSpeed * Time.deltaTime); tr.eulerAngles = new Vector3(0, tr.eulerAngles.y, 0);
/** Draws helper gizmos. * Currently draws a circle around the current target point with the size showing how close the AI need to get to it for it to count as "reached". */ public void OnDrawGizmos () {
using UnityEngine; using System.Collections; using Pathfinding;
/** Example AI. * \deprecated This script has been deprecated, use AIPath or MineBotAI instead */ [RequireComponent (typeof(Seeker))] [RequireComponent (typeof(CharacterController))] public class AIFollow : MonoBehaviour { public bool VZOR; /** Target to move to */
public bool VIDIT;
//public Transform target;
public Transform target;
/** How often to search for a new path */ public float repathRate = 0.1F;
/** The minimum distance to a waypoint to consider it as "reached" */ public float pickNextWaypointDistance = 2F;
/** The minimum distance to the end point of a path to consider it "reached" (multiplied with #pickNextWaypointDistance). * This value is multiplied with #pickNextWaypointDistance before it is used. Recommended range [0...1] */ public float targetReached = 1.0F;
/** Units per second */ public float speed = 6;
/** How fast the AI can turn around */ public float rotationSpeed = 7;
public bool drawGizmos = false;
/** Should paths be searched for. * Setting this to false will make the AI not search for paths anymore, can save some CPU cycles. * It will check every #repathRate seconds if it should start to search for paths again. * \note It will not cancel paths which are currently being calculated */ public bool canSearch = true;
/** Can it move. Enables or disables movement and rotation */ public bool canMove = true;
/** CharacterController which handles movement */ protected CharacterController controller;
/** NavmeshController which handles movement if not null*/ protected NavmeshController navmeshController;
/** Transform, cached because of performance */ protected Transform tr;
protected float lastPathSearch = -9999;
protected int pathIndex = 0;
/** This is the path the AI is currently following */ protected Vector3[] path;
/** Use this for initialization */ public void Start () { seeker = GetComponent<Seeker>(); controller = GetComponent<CharacterController>(); navmeshController = GetComponent<NavmeshController>();
tr = transform; Repath (); }
/** Will make the AI give up it's current path and stop completely. */ public void Reset () { path = null; }
/** Called when a path has completed it's calculation */ public void OnPathComplete (Path p) {
//If the path didn't succeed, don't proceed if (p.error) { return; }
//Get the calculated path as a Vector3 array path = p.vectorPath;
//Find the segment in the path which is closest to the AI //If a closer segment hasn't been found in '6' iterations, break because it is unlikely to find any closer ones then float minDist = Mathf.Infinity; int notCloserHits = 0;
/** Waits the remaining time until the AI should issue a new path request. * The remaining time is defined by Time.time - lastPathSearch */ public IEnumerator WaitToRepath () { float timeLeft = repathRate - (Time.time-lastPathSearch);
yield return new WaitForSeconds (timeLeft); Repath (); }
/** Stops the AI. * Also stops new search queries from being made * \version Before 3.0.8 This does not prevent new path calls from making the AI move again * \see #Resume * \see #canMove * \see #canSearch */ public void Stop () { canMove = false; canSearch = false; }
/** Resumes walking and path searching the AI. * \version Added in 3.0.8 * \see #Stop * \see #canMove * \see #canSearch */ public void Resume () { canMove = true; canSearch = true; }
/** Recalculates the path to #target. * Queries a path request to the Seeker, the path will not be calculated instantly, but will be put on a queue and calculated as fast as possible. * It will wait if the current path request by this seeker has not been completed yet. * \see Seeker::IsDone */ public virtual void Repath () { lastPathSearch = Time.time;
//for (int i=0;i<1000;i++) { //MultithreadPath mp = new MultithreadPath (transform.position,target.position,null); //Path p = new Path (transform.position,target.position,null); // AstarPath.StartPath (mp); //} //Debug.Log (AstarPath.pathQueue.Count);
//StartCoroutine (WaitToRepath ()); /*ConstantPath cpath = new ConstantPath(transform.position,null); //Must be set to avoid it from searching towards Vector3.zero cpath.heuristic = Heuristic.None; //Here you set how far it should search cpath.maxGScore = 2000; AstarPath.StartPath (cpath);*/ //FloodPathTracer fpathTrace = new FloodPathTracer (transform.position,fpath,null); //seeker.StartPath (fpathTrace,OnPathComplete);
Path p = new Path(transform.position,target.position,null); seeker.StartPath (p,OnPathComplete); //Start a new path from transform.positon to target.position, return the result to the function OnPathComplete //seeker.StartPath (transform.position,target.position,OnPathComplete); }
/** Start a new path moving to \a targetPoint */ public void PathToTarget (Vector3 targetPoint) { lastPathSearch = Time.time;
if (seeker == null) { return; }
//Start a new path from transform.positon to target.position, return the result to OnPathComplete seeker.StartPath (transform.position,targetPoint,OnPathComplete); }
/** Called when the AI reached the end of path. * This will be called once for every path it completes, so if you have a really fast repath rate it will call this function often if when it stands on the end point. */ public virtual void ReachedEndOfPath () { //The AI has reached the end of the path //Set animation tr.animation.Play("attack"); tr.LookAt(target.position); tr.eulerAngles = new Vector3(0, tr.eulerAngles.y, 0); }
//Change target to the next waypoint if the current one is close enough Vector3 currentWaypoint = path[pathIndex]; currentWaypoint.y = tr.position.y; while ((currentWaypoint - tr.position).sqrMagnitude < pickNextWaypointDistance*pickNextWaypointDistance) { pathIndex++; if (pathIndex >= path.Length) { //Use a lower pickNextWaypointDistance for the last point. If it isn't that close, then decrement the pathIndex to the previous value and break the loop if ((currentWaypoint - tr.position).sqrMagnitude < (pickNextWaypointDistance*targetReached)*(pickNextWaypointDistance*targetReached)) { ReachedEndOfPath (); return; } else { pathIndex--; //Break the loop, otherwise it will try to check for the last point in an infinite loop break; } } currentWaypoint = path[pathIndex]; currentWaypoint.y = tr.position.y; }
Vector3 dir = currentWaypoint - tr.position;
// Rotate towards the target tr.rotation = Quaternion.Slerp (tr.rotation, Quaternion.LookRotation(dir), rotationSpeed * Time.deltaTime); tr.eulerAngles = new Vector3(0, tr.eulerAngles.y, 0);
/** Draws helper gizmos. * Currently draws a circle around the current target point with the size showing how close the AI need to get to it for it to count as "reached". */ public void OnDrawGizmos () {