1. 程式人生 > >waypoint——使物體按著既定的路線運動

waypoint——使物體按著既定的路線運動

這裡寫圖片描述


using UnityEngine;
using System.Collections;
using System.Collections.Generic;
#if UNITY_EDITOR
using UnityEditor;
#endif

public class WaypointCircuit : MonoBehaviour 
{
    public WaypointList waypointList = new WaypointList();
    [SerializeField] bool smoothRoute = true;
    int numPoints;
    Vector3[] points;
    float
[] distances; public float editorVisualisationSubsteps = 100; public float Length { get; private set; } public Transform[] Waypoints { get { return waypointList.items; } } //this being here will save GC allocs int p0n; int p1n; int p2n; int p3n; private float i; Vector3 P0; Vector3 P1; Vector3 P2; Vector3 P3; // Use this for initialization
void Awake() { if (Waypoints.Length > 1) { CachePositionsAndDistances(); } numPoints = Waypoints.Length; } public RoutePoint GetRoutePoint(float dist) { // position and direction Vector3 p1 = GetRoutePosition(dist); Vector3 p2 = GetRoutePosition(dist + 0.1
f); Vector3 delta = p2 - p1; return new RoutePoint(p1, delta.normalized); } public Vector3 GetRoutePosition(float dist) { int point = 0; if (Length == 0) { Length = distances[distances.Length - 1]; } dist = Mathf.Repeat(dist, Length); while (distances[point] < dist) { ++point; } // get nearest two points, ensuring points wrap-around start & end of circuit p1n = ((point - 1) + numPoints) % numPoints; p2n = point; // found point numbers, now find interpolation value between the two middle points i = Mathf.InverseLerp(distances[p1n], distances[p2n], dist); if (smoothRoute) { // smooth catmull-rom calculation between the two relevant points // get indices for the surrounding 2 points, because // four points are required by the catmull-rom function p0n = ((point - 2) + numPoints) % numPoints; p3n = (point + 1) % numPoints; // 2nd point may have been the 'last' point - a dupe of the first, // (to give a value of max track distance instead of zero) // but now it must be wrapped back to zero if that was the case. p2n = p2n % numPoints; P0 = points[p0n]; P1 = points[p1n]; P2 = points[p2n]; P3 = points[p3n]; return CatmullRom(P0, P1, P2, P3, i); } else { // simple linear lerp between the two points: p1n = ((point - 1) + numPoints) % numPoints; p2n = point; return Vector3.Lerp(points[p1n], points[p2n], i); } } Vector3 CatmullRom(Vector3 _P0, Vector3 _P1, Vector3 _P2, Vector3 _P3, float _i) { // comments are no use here... it's the catmull-rom equation. // Un-magic this, lord vector! return 0.5f * ((2 * _P1) + (-_P0 + _P2) * _i + (2 * _P0 - 5 * _P1 + 4 * _P2 - _P3) * _i * _i + (-_P0 + 3 * _P1 - 3 * _P2 + _P3) * _i * _i * _i); } void CachePositionsAndDistances() { // transfer the position of each point and distances between points to arrays for // speed of lookup at runtime points = new Vector3[Waypoints.Length + 1]; distances = new float[Waypoints.Length + 1]; float accumulateDistance = 0; for (int i = 0; i < points.Length; ++i) { var t1 = Waypoints[(i) % Waypoints.Length]; var t2 = Waypoints[(i + 1) % Waypoints.Length]; if (t1 != null && t2 != null) { Vector3 p1 = t1.position; Vector3 p2 = t2.position; points[i] = Waypoints[i % Waypoints.Length].position; distances[i] = accumulateDistance; accumulateDistance += (p1 - p2).magnitude; } } } void OnDrawGizmos() { DrawGizmos(false); } void OnDrawGizmosSelected() { DrawGizmos(true); } void DrawGizmos(bool selected) { waypointList.circuit = this; if (Waypoints.Length > 1) { numPoints = Waypoints.Length; CachePositionsAndDistances(); Length = distances[distances.Length - 1]; Gizmos.color = selected ? Color.yellow : new Color(1, 1, 0, 0.5f); Vector3 prev = Waypoints[0].position; if (smoothRoute) { for (float dist = 0; dist < Length; dist += Length / editorVisualisationSubsteps) { Vector3 next = GetRoutePosition(dist + 1); Gizmos.DrawLine(prev, next); prev = next; } Gizmos.DrawLine(prev, Waypoints[0].position); } else { for (int n = 0; n < Waypoints.Length; ++n) { Vector3 next = Waypoints[(n + 1) % Waypoints.Length].position; Gizmos.DrawLine(prev, next); prev = next; } } } } [System.Serializable] public class WaypointList { public WaypointCircuit circuit; public Transform[] items = new Transform[0]; } public struct RoutePoint { public Vector3 position; public Vector3 direction; public RoutePoint(Vector3 position, Vector3 direction) { this.position = position; this.direction = direction; } } } #if UNITY_EDITOR [CustomPropertyDrawer(typeof(WaypointCircuit.WaypointList))] public class WaypointListDrawer : PropertyDrawer { float lineHeight = 18; float spacing = 4; public override void OnGUI(Rect position, SerializedProperty property, GUIContent label) { EditorGUI.BeginProperty(position, label, property); float x = position.x; float y = position.y; float inspectorWidth = position.width; // Draw label // Don't make child fields be indented var indent = EditorGUI.indentLevel; EditorGUI.indentLevel = 0; var items = property.FindPropertyRelative("items"); string[] titles = new string[] { "Transform", "", "", "" }; string[] props = new string[] { "transform", "^", "v", "-" }; float[] widths = new float[] { .7f, .1f, .1f, .1f }; float lineHeight = 18; bool changedLength = false; if (items.arraySize > 0) { for (int i = -1; i < items.arraySize; ++i) { var item = items.GetArrayElementAtIndex(i); float rowX = x; for (int n = 0; n < props.Length; ++n) { float w = widths[n] * inspectorWidth; // Calculate rects Rect rect = new Rect(rowX, y, w, lineHeight); rowX += w; if (i == -1) { EditorGUI.LabelField(rect, titles[n]); } else { if (n == 0) { EditorGUI.ObjectField(rect, item.objectReferenceValue, typeof(Transform), true); } else { if (GUI.Button(rect, props[n])) { switch (props[n]) { case "-": items.DeleteArrayElementAtIndex(i); items.DeleteArrayElementAtIndex(i); changedLength = true; break; case "v": if (i > 0) items.MoveArrayElement(i, i + 1); break; case "^": if (i < items.arraySize - 1) items.MoveArrayElement(i, i - 1); break; } } } } } y += lineHeight + spacing; if (changedLength) { break; } } } else { // add button var addButtonRect = new Rect((x + position.width) - widths[widths.Length - 1] * inspectorWidth, y, widths[widths.Length - 1] * inspectorWidth, lineHeight); if (GUI.Button(addButtonRect, "+")) { items.InsertArrayElementAtIndex(items.arraySize); } y += lineHeight + spacing; } // add all button var addAllButtonRect = new Rect(x, y, inspectorWidth, lineHeight); if (GUI.Button(addAllButtonRect, "Assign using all child objects")) { var circuit = property.FindPropertyRelative("circuit").objectReferenceValue as WaypointCircuit; var children = new Transform[circuit.transform.childCount]; int n = 0; foreach (Transform child in circuit.transform) children[n++] = child; System.Array.Sort(children, new TransformNameComparer()); circuit.waypointList.items = new Transform[children.Length]; for (n = 0; n < children.Length; ++n) { circuit.waypointList.items[n] = children[n]; } } y += lineHeight + spacing; // rename all button var renameButtonRect = new Rect(x, y, inspectorWidth, lineHeight); if (GUI.Button(renameButtonRect, "Auto Rename numerically from this order")) { var circuit = property.FindPropertyRelative("circuit").objectReferenceValue as WaypointCircuit; int n = 0; foreach (Transform child in circuit.waypointList.items) child.name = "Waypoint " + (n++).ToString("000"); } y += lineHeight + spacing; // Set indent back to what it was EditorGUI.indentLevel = indent; EditorGUI.EndProperty(); } public override float GetPropertyHeight(SerializedProperty property, GUIContent label) { SerializedProperty items = property.FindPropertyRelative("items"); float lineAndSpace = lineHeight + spacing; return 40 + (items.arraySize * lineAndSpace) + lineAndSpace; } // comparer for check distances in ray cast hits public class TransformNameComparer : IComparer { public int Compare(object x, object y) { return ((Transform)x).name.CompareTo(((Transform)y).name); } } } #endif

這裡寫圖片描述

指令碼掛在空物體上,空物體下有四個立方體,可以把元件去掉只剩下transform元件,四個在不同位置,

這裡寫圖片描述
點選“Assign using all child objects”,使之自動獲取到下面的子物體,(如果獲取不到,看看是四個位置相同)

圓柱是運動的物體,它上面同樣要掛一個跟隨指令碼

using UnityEngine;
using System.Collections;

public class Follow : MonoBehaviour
{

    // 路徑指令碼
    [SerializeField]
    private WaypointCircuit circuit;

    //移動距離
    private float dis;
    //移動速度
    private float speed;
    // Use this for initialization
    void Start()
    {
        dis = 0;
        speed = 10;
    }

    // Update is called once per frame
    void Update()
    {
        //計算距離
        dis += Time.deltaTime * speed;
        //獲取相應距離在路徑上的位置座標
        transform.position = circuit.GetRoutePoint(dis).position;
        //獲取相應距離在路徑上的方向
        transform.rotation = Quaternion.LookRotation(circuit.GetRoutePoint(dis).direction);
    }
}

這裡寫圖片描述

點選執行後即可看到圓柱在一圈一圈的繞著軌跡行走、

如果想要更好的效果,需要更細緻的設定,另外不適合動態生成障礙物的情況,也不適合地形複雜的情況

相關推薦

waypoint——使物體既定路線運動

using UnityEngine; using System.Collections; using System.Collections.Generic; #if UNITY_EDITOR using UnityEditor; #endif publi

Maya Mel 表示式動畫——使物體螺旋向外運動

1.建立一個球體 2.在通道欄中新增屬性 名稱:distance 資料型別:float 屬性型別:標量 3.開啟表示式編輯器 pSphere1.distance = time; pSphere1.translateX = pSphere1.distance * sin(ti

使物體平滑旋轉不完全筆記

//旋轉速度 public float RotateSpeed = 15; private bool isTurn = true; //private Vector3 newCameraRotate; private Quaternion newCamRoatation; private f

Unity射線/右鍵點選某一點會使物體跟隨至滑鼠點選位置/計算目標物體距離滑鼠點選位置的距離

public class MyRay : MonoBehaviour { public GameObject GameObject;//要例項化的物體 粒子特效 public GameObject Player; private Animation ani;

號度為在政平代問心土得象過

代許切成山院及品和任只存與種例屬馬百任節性多容書比四型壓院術各面世好邊使京意據維金共風必設況生線準基品並式革許公張裡務近回那調界準自理看市所現學看深整況千經革白式斯上識圓術馬習約加他五幾確給員圓半品究從計標層深根每期價驗性七來千命多象林拉什參觀方率想叫做變周具那道真或制力工如

青島理工邀請賽(難受的一次經歷)之顯示屏(倍數放大數字)

這是一次慘痛的經歷,三個人照著一個連知識點也沒有聽過的題做了三個小時,把這個水題給放過去了。哇呀呀,難受的一批啊。 題目描述:就是按著放大的倍數放大數字 程式碼如下: #include<iostream> #include<cstdio>

U使物體朝向某個方位

思路 核心是利用transform.lookAt這個API Vector3 tar = target.Position; tar.y = transform.position.y; transfo

Unity射線&自動尋路/右鍵點選某一點會使物體跟隨至滑鼠點選位置/計算目標物體距離滑鼠點選位置的距離

public class MyRay : MonoBehaviour { public GameObject GameObject;//要例項化的物體 粒子特效 public GameObject Player; // private Animation ani; priva

使物體發光的外掛highlighting system v2.0

標題使物體邊緣發光的外掛highlighting system v2.0 今天給大家分享一個使物體發光的外掛,highlighting system v2.0,可以根據自己的需要,設定從某種顏色到另一種顏色閃爍發光的效果,操作十分簡單,希望能幫到需要的人。 下面為大家展示的是從Red到Y

parttion by ~~~針對某個欄位或多個欄位重複,資料只取前n條。問題例子:1.主評論下的評論 時間正序最多隻取前5條 2.獲取最新登入記錄......

分組目前已知partition by、group by partition by用於給結果集分組分割槽,如果沒有指定那麼它把整個結果集作為一個分組,最後顯示具體資料 group by:通過所查詢的資料的某一欄位或屬性進行分組,最後顯示組資料,而不是具體資料,因為select 後面的所有列中,沒有使用聚合函

shift鍵對dbgrid進行多條記錄選擇的問題(50分)

可以用sendmessage,想dbgrid 發鍵盤資訊,按下shift鍵,同時按下button1procedure TForm1.Button1Click(Sender: TObject);vari:integer;beginfor i:=1 to Table1.Recordcount-1 dosendme

頁面佈局使按鈕比例顯示 ,水平和垂直

<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layou

物體多屬性維度的運動框架示例

讓不同的div區塊從寬度(width)、高度(height)、邊框(border)、文字大小(font-size)、不透明度(opacity)等多個維度實現JS運動框架構建。 多物體多屬性維度JavaScript運動框架示例HTML程式碼部分 <div class=

如何使物體回到初始位置

記錄初始位置 vector3 Pos = Obj.transform.position; 回到原位 Obj.transform.position = Pos; 缺點是這樣會導致物體瞬間到達。 還可以通過程式碼,讓物體慢慢移動回去。 比如Speed

js 多物體運動框架

eight 設置 bsp htm 目標 floor class width h+ 多物體運動框架例子:多個Div,鼠標移入biankuan 單定時器,存在問題每個Div一個定時器總結:參數問題:當運動當前的div的時候可以傳參數onStart(obj,tag);o

js多物體運動之淡入淡出效果

javascrip targe query mpat clear scrip ava clas start <!DOCTYPE html> <html lang="zh"> <head> <meta charset="UT

Unity3d讓某個物體一直正對相機

his 綁定 unit pub rotate sys init iou bject //將以下代碼綁定到相機上 using UnityEngine; using System.Collections; public class LookatScipt : MonoBeh

【圖像處理】openCV光流法追蹤運動物體

num blank ndis water 不同 h+ width 相關性 ida openCV光流法追蹤運動物體 email:[email protected]/* */ 一、光流簡單介紹 摘自:zouxy09 光流的概念是G

算法刷題路線

方格取數 貪心 數獨 地震 生日蛋糕 最大 旅行 貨車運輸 字符 搜索:八數碼,生日蛋糕,靶形數獨,(蟲食算),最優貿易,引水入城,埃及分數,(p1189) dp:方格取數,樹網的核,旅行路線 貪心:huffman,疫情控制 生成樹:災後重建,貨車運輸 連通塊:間諜網絡,星