first commit

This commit is contained in:
lethanhsonvsp
2025-11-17 15:36:52 +07:00
commit 6f2eafa33c
14093 changed files with 1253472 additions and 0 deletions

View File

@@ -0,0 +1,87 @@
using UnityEngine;
using UnityEngine.AI;
using System.Collections;
namespace Unity.AI.Navigation.Samples
{
public enum OffMeshLinkMoveMethod
{
Teleport,
NormalSpeed,
Parabola,
Curve
}
/// <summary>
/// Move an agent when traversing a OffMeshLink given specific animated methods
/// </summary>
[RequireComponent(typeof(NavMeshAgent))]
public class AgentLinkMover : MonoBehaviour
{
public OffMeshLinkMoveMethod m_Method = OffMeshLinkMoveMethod.Parabola;
public AnimationCurve m_Curve = new AnimationCurve();
IEnumerator Start()
{
NavMeshAgent agent = GetComponent<NavMeshAgent>();
agent.autoTraverseOffMeshLink = false;
while (true)
{
if (agent.isOnOffMeshLink)
{
if (m_Method == OffMeshLinkMoveMethod.NormalSpeed)
yield return StartCoroutine(NormalSpeed(agent));
else if (m_Method == OffMeshLinkMoveMethod.Parabola)
yield return StartCoroutine(Parabola(agent, 2.0f, 0.5f));
else if (m_Method == OffMeshLinkMoveMethod.Curve)
yield return StartCoroutine(Curve(agent, 0.5f));
agent.CompleteOffMeshLink();
}
yield return null;
}
}
IEnumerator NormalSpeed(NavMeshAgent agent)
{
OffMeshLinkData data = agent.currentOffMeshLinkData;
Vector3 endPos = data.endPos + Vector3.up * agent.baseOffset;
while (agent.transform.position != endPos)
{
agent.transform.position =
Vector3.MoveTowards(agent.transform.position, endPos, agent.speed * Time.deltaTime);
yield return null;
}
}
IEnumerator Parabola(NavMeshAgent agent, float height, float duration)
{
OffMeshLinkData data = agent.currentOffMeshLinkData;
Vector3 startPos = agent.transform.position;
Vector3 endPos = data.endPos + Vector3.up * agent.baseOffset;
float normalizedTime = 0.0f;
while (normalizedTime < 1.0f)
{
float yOffset = height * 4.0f * (normalizedTime - normalizedTime * normalizedTime);
agent.transform.position = Vector3.Lerp(startPos, endPos, normalizedTime) + yOffset * Vector3.up;
normalizedTime += Time.deltaTime / duration;
yield return null;
}
}
IEnumerator Curve(NavMeshAgent agent, float duration)
{
OffMeshLinkData data = agent.currentOffMeshLinkData;
Vector3 startPos = agent.transform.position;
Vector3 endPos = data.endPos + Vector3.up * agent.baseOffset;
float normalizedTime = 0.0f;
while (normalizedTime < 1.0f)
{
float yOffset = m_Curve.Evaluate(normalizedTime);
agent.transform.position = Vector3.Lerp(startPos, endPos, normalizedTime) + yOffset * Vector3.up;
normalizedTime += Time.deltaTime / duration;
yield return null;
}
}
}
}

View File

@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: 03bc8063c9e95401f9a8a38bc716750d
timeCreated: 1460116525
licenseType: Pro
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,30 @@
using UnityEngine;
using UnityEngine.AI;
namespace Unity.AI.Navigation.Samples
{
/// <summary>
/// Use physics raycast hit from mouse click to set agent destination
/// </summary>
[RequireComponent(typeof(NavMeshAgent))]
public class ClickToMove : MonoBehaviour
{
NavMeshAgent m_Agent;
RaycastHit m_HitInfo = new RaycastHit();
void Start()
{
m_Agent = GetComponent<NavMeshAgent>();
}
void Update()
{
if (Input.GetMouseButtonDown(0) && !Input.GetKey(KeyCode.LeftShift))
{
var ray = Camera.main.ScreenPointToRay(Input.mousePosition);
if (Physics.Raycast(ray.origin, ray.direction, out m_HitInfo))
m_Agent.destination = m_HitInfo.point;
}
}
}
}

View File

@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: c9472e73a59274b9b8da79d72004bd8b
timeCreated: 1430734266
licenseType: Pro
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,17 @@
using System;
using UnityEngine;
namespace Unity.AI.Navigation.Samples
{
/// <summary>
/// Destroy GameObjects upon collision
/// </summary>
[RequireComponent(typeof(Collider))]
public class Despawner : MonoBehaviour
{
void OnCollisionEnter(Collision collision)
{
Destroy(collision.gameObject);
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: d3be0b2e79a40424c88b51776d94b8a5
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,18 @@
using UnityEngine;
namespace Unity.AI.Navigation.Samples
{
/// <summary>
/// Destroy owning GameObject if any collider with a specific tag is trespassing
/// </summary>
public class DestroyOnTrigger : MonoBehaviour
{
public string m_Tag = "Player";
void OnTriggerEnter(Collider other)
{
if (other.gameObject.tag == m_Tag)
Destroy(gameObject);
}
}
}

View File

@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: c786c4b29e72040b881bf13065fb9788
timeCreated: 1430999621
licenseType: Pro
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,56 @@
using UnityEngine;
namespace Unity.AI.Navigation.Samples
{
/// <summary>
/// Initialize dungeon tiles with a specified width and height
/// </summary>
[DefaultExecutionOrder(-200)]
public class DungeonManager : MonoBehaviour
{
public int m_Width = 10;
public int m_Height = 10;
public float m_Spacing = 4.0f;
public GameObject[] m_Tiles = new GameObject[16];
void Awake()
{
Random.InitState(23431);
var map = new int[m_Width * m_Height];
for (int y = 0; y < m_Height; y++)
{
for (int x = 0; x < m_Width; x++)
{
bool px = false;
bool py = false;
if (x > 0)
px = (map[(x - 1) + y * m_Width] & 1) != 0;
if (y > 0)
py = (map[x + (y - 1) * m_Width] & 2) != 0;
int tile = 0;
if (px)
tile |= 4;
if (py)
tile |= 8;
if (x + 1 < m_Width && Random.value > 0.5f)
tile |= 1;
if (y + 1 < m_Height && Random.value > 0.5f)
tile |= 2;
map[x + y * m_Width] = tile;
}
}
for (int y = 0; y < m_Height; y++)
{
for (int x = 0; x < m_Width; x++)
{
var pos = new Vector3(x * m_Spacing, 0, y * m_Spacing);
if (m_Tiles[map[x + y * m_Width]] != null)
Instantiate(m_Tiles[map[x + y * m_Width]], pos, Quaternion.identity, transform);
}
}
}
}
}

View File

@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: c56d911659e3c4b499e11b47a73a4dbb
timeCreated: 1430743428
licenseType: Pro
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,38 @@
using UnityEngine;
namespace Unity.AI.Navigation.Samples
{
/// <summary>
/// Component for moving GameObjects within a NavMesh.
/// Requests a NavMesh update whenever its owning GameObject has stopped moving.
/// </summary>
[RequireComponent(typeof(Rigidbody))]
[RequireComponent(typeof(NavMeshModifier))]
public class DynamicNavMeshObject : MonoBehaviour
{
Rigidbody m_Rigidbody;
NavMeshModifier m_NavMeshModifier;
bool m_WasMoving;
void Start()
{
m_Rigidbody = GetComponent<Rigidbody>();
m_NavMeshModifier = GetComponent<NavMeshModifier>();
m_NavMeshModifier.enabled = true;
m_WasMoving = !m_Rigidbody.IsSleeping();
}
void Update()
{
bool isMoving = !m_Rigidbody.IsSleeping() && m_Rigidbody.velocity.sqrMagnitude > 0.1f;
if ((m_WasMoving && !isMoving) || (!m_WasMoving && isMoving))
{
m_NavMeshModifier.ignoreFromBuild = isMoving;
GloballyUpdatedNavMeshSurface.RequestNavMeshUpdate();
}
m_WasMoving = isMoving;
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: ac596217843ab3647b721eacaea9c581
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,31 @@
using UnityEngine;
namespace Unity.AI.Navigation.Samples
{
/// <summary>
/// Enables a behaviour when a rigidbody settles movement
/// otherwise disables the behaviour
/// </summary>
public class EnableIffSleeping : MonoBehaviour
{
public Behaviour m_Behaviour;
Rigidbody m_Rigidbody;
void Start()
{
m_Rigidbody = GetComponent<Rigidbody>();
}
void Update()
{
if (m_Rigidbody == null || m_Behaviour == null)
return;
if (m_Rigidbody.IsSleeping() && !m_Behaviour.enabled)
m_Behaviour.enabled = true;
if (!m_Rigidbody.IsSleeping() && m_Behaviour.enabled)
m_Behaviour.enabled = false;
}
}
}

View File

@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: c56046daca8eb46f3af030c05f030e37
timeCreated: 1431001396
licenseType: Pro
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,64 @@
using UnityEngine;
namespace Unity.AI.Navigation.Samples
{
/// <summary>
/// Manipulating the camera with standard inputs
/// </summary>
public class FreeCam : MonoBehaviour
{
public enum RotationAxes { MouseXAndY = 0, MouseX = 1, MouseY = 2 }
public RotationAxes axes = RotationAxes.MouseXAndY;
public float sensitivityX = 15F;
public float sensitivityY = 15F;
public float minimumX = -360F;
public float maximumX = 360F;
public float minimumY = -60F;
public float maximumY = 60F;
public float moveSpeed = 1.0f;
public bool lockHeight = false;
float rotationY = 0F;
void Update()
{
if (axes == RotationAxes.MouseXAndY)
{
float rotationX = transform.localEulerAngles.y + Input.GetAxis("Mouse X") * sensitivityX;
rotationY += Input.GetAxis("Mouse Y") * sensitivityY;
rotationY = Mathf.Clamp(rotationY, minimumY, maximumY);
transform.localEulerAngles = new Vector3(-rotationY, rotationX, 0);
}
else if (axes == RotationAxes.MouseX)
{
transform.Rotate(0, Input.GetAxis("Mouse X") * sensitivityX, 0);
}
else
{
rotationY += Input.GetAxis("Mouse Y") * sensitivityY;
rotationY = Mathf.Clamp(rotationY, minimumY, maximumY);
transform.localEulerAngles = new Vector3(-rotationY, transform.localEulerAngles.y, 0);
}
var xAxisValue = Input.GetAxis("Horizontal");
var zAxisValue = Input.GetAxis("Vertical");
if (lockHeight)
{
var dir = transform.TransformDirection(new Vector3(xAxisValue, 0.0f, zAxisValue) * moveSpeed);
dir.y = 0.0f;
transform.position += dir;
}
else
{
transform.Translate(new Vector3(xAxisValue, 0.0f, zAxisValue) * moveSpeed);
}
}
}
}

View File

@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: b6c30eb361e754b75ac25325c5d024bd
timeCreated: 1430921534
licenseType: Pro
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,37 @@
using System;
using System.Collections.Generic;
using UnityEngine;
namespace Unity.AI.Navigation.Samples
{
/// <summary>
/// NavMeshSurface that updates only once per frame upon request
/// </summary>
[RequireComponent(typeof(NavMeshSurface))]
public class GloballyUpdatedNavMeshSurface : MonoBehaviour
{
static bool s_NeedsNavMeshUpdate;
NavMeshSurface m_Surface;
public static void RequestNavMeshUpdate()
{
s_NeedsNavMeshUpdate = true;
}
void Start()
{
m_Surface = GetComponent<NavMeshSurface>();
m_Surface.BuildNavMesh();
}
void Update()
{
if (s_NeedsNavMeshUpdate)
{
m_Surface.UpdateNavMesh(m_Surface.navMeshData);
s_NeedsNavMeshUpdate = false;
}
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: f48d3001ccdce69418119f74f39f090d
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,118 @@
using UnityEngine;
using System.Collections.Generic;
using UnityEngine.AI;
namespace Unity.AI.Navigation.Samples
{
/// <summary>
/// Manipulation tool for displacing the vertices in a list of meshes
/// </summary>
[DefaultExecutionOrder(-101)]
public class MeshTool : MonoBehaviour
{
NavMeshSurface m_Surface;
public enum ExtrudeMethod
{
Vertical,
MeshNormal
}
public List<MeshFilter> m_Filters = new List<MeshFilter>();
public float m_Radius = 1.5f;
public float m_Power = 2.0f;
public ExtrudeMethod m_Method = ExtrudeMethod.Vertical;
RaycastHit m_HitInfo = new RaycastHit();
AsyncOperation m_LastNavMeshUpdate;
void OnEnable()
{
Cursor.lockState = CursorLockMode.Locked;
Cursor.visible = false;
m_Surface = GetComponent<NavMeshSurface>();
if (m_Surface != null)
{
m_Surface.BuildNavMesh();
m_LastNavMeshUpdate = m_Surface.UpdateNavMesh(m_Surface.navMeshData);
}
}
void Update()
{
var ray = new Ray(Camera.main.transform.position, Camera.main.transform.forward);
if (Physics.Raycast(ray.origin, ray.direction, out m_HitInfo))
{
Debug.DrawRay(m_HitInfo.point, m_HitInfo.normal, Color.red);
Vector3 displacement = (m_Method == ExtrudeMethod.Vertical) ? Vector3.up : m_HitInfo.normal;
if (Input.GetMouseButton(0) || (Input.GetKey(KeyCode.Space) && !Input.GetKey(KeyCode.LeftShift)))
{
ModifyMesh(m_Power * displacement, m_HitInfo.point);
if (m_Surface != null)
{
if (m_LastNavMeshUpdate.isDone)
m_LastNavMeshUpdate = m_Surface.UpdateNavMesh(m_Surface.navMeshData);
}
}
else if (Input.GetMouseButton(1) || (Input.GetKey(KeyCode.Space) && Input.GetKey(KeyCode.LeftShift)))
{
ModifyMesh(-m_Power * displacement, m_HitInfo.point);
if(m_Surface != null)
{
if (m_LastNavMeshUpdate.isDone)
m_LastNavMeshUpdate = m_Surface.UpdateNavMesh(m_Surface.navMeshData);
}
}
else if(Input.GetMouseButtonUp(0) || Input.GetMouseButtonUp(1) || Input.GetKeyUp(KeyCode.Space))
{
if (m_Surface != null)
{
if (!m_LastNavMeshUpdate.isDone)
NavMeshBuilder.Cancel(m_Surface.navMeshData);
m_LastNavMeshUpdate = m_Surface.UpdateNavMesh(m_Surface.navMeshData);
}
}
}
}
void ModifyMesh(Vector3 displacement, Vector3 center)
{
foreach (var filter in m_Filters)
{
Mesh mesh = filter.mesh;
Vector3[] vertices = mesh.vertices;
for (int i = 0; i < vertices.Length; ++i)
{
Vector3 v = filter.transform.TransformPoint(vertices[i]);
vertices[i] = vertices[i] + displacement * Gaussian(v, center, m_Radius);
}
mesh.vertices = vertices;
mesh.RecalculateBounds();
var col = filter.GetComponent<MeshCollider>();
if (col != null)
{
var colliMesh = new Mesh();
colliMesh.vertices = mesh.vertices;
colliMesh.triangles = mesh.triangles;
col.sharedMesh = colliMesh;
}
}
}
static float Gaussian(Vector3 pos, Vector3 mean, float dev)
{
float x = pos.x - mean.x;
float y = pos.y - mean.y;
float z = pos.z - mean.z;
float n = 1.0f / (2.0f * Mathf.PI * dev * dev);
return n * Mathf.Pow(2.718281828f, -(x * x + y * y + z * z) / (2.0f * dev * dev));
}
}
}

View File

@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: 9d5a3e609186342b2a976cd32fd7d0f0
timeCreated: 1430920188
licenseType: Pro
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,72 @@
using System;
using UnityEngine;
using UnityEngine.AI;
namespace Unity.AI.Navigation.Samples
{
/// <summary>
/// Update a NavMeshSurface with Volume object collection
/// </summary>
[DefaultExecutionOrder(-102)]
public class NavMeshSurfaceVolumeUpdater : MonoBehaviour
{
[SerializeField]
NavMeshAgent trackedAgent;
NavMeshSurface m_Surface;
Vector3 m_VolumeSize;
void Awake()
{
m_Surface = GetComponent<NavMeshSurface>();
}
void OnEnable()
{
m_VolumeSize = m_Surface.size;
m_Surface.center = QuantizedCenter();
m_Surface.BuildNavMesh();
}
void Update()
{
UpdateNavMeshOnCenterOrSizeChange();
}
void UpdateNavMeshOnCenterOrSizeChange()
{
var updatedCenter = QuantizedCenter();
var updateNavMesh = false;
if (m_Surface.center != updatedCenter)
{
m_Surface.center = updatedCenter;
updateNavMesh = true;
}
if (m_Surface.size != m_VolumeSize)
{
m_VolumeSize = m_Surface.size;
updateNavMesh = true;
}
if (updateNavMesh)
m_Surface.UpdateNavMesh(m_Surface.navMeshData);
}
static Vector3 Quantize(Vector3 v, Vector3 quant)
{
float x = quant.x * Mathf.Floor(v.x / quant.x);
float y = quant.y * Mathf.Floor(v.y / quant.y);
float z = quant.z * Mathf.Floor(v.z / quant.z);
return new Vector3(x, y, z);
}
Vector3 QuantizedCenter()
{
// Quantize the center position to update only when there's a 10% change in position relative to size
var center = trackedAgent.transform.position;
return Quantize(center, 0.1f * m_Surface.size);
}
}
}

View File

@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: 115dfe7b0938447cbbf9507076f54049
timeCreated: 1454852118
licenseType: Pro
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,31 @@
using UnityEngine;
using UnityEngine.AI;
namespace Unity.AI.Navigation.Samples
{
/// <summary>
/// Use physics raycast hit from mouse click to set agent destination
/// </summary>
[RequireComponent(typeof(NavMeshAgent))]
public class NavigationLoop : MonoBehaviour
{
NavMeshAgent m_Agent;
public Transform[] goals = new Transform[3];
private int m_NextGoal = 1;
void Start()
{
m_Agent = GetComponent<NavMeshAgent>();
}
void Update()
{
float distance = Vector3.Distance(m_Agent.transform.position, goals[m_NextGoal].position);
if (distance < 0.5f)
{
m_NextGoal = m_NextGoal != 2 ? m_NextGoal + 1 : 0;
}
m_Agent.destination = goals[m_NextGoal].position;
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 7e11f36a144a248cbacbea0c8cf7803e
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,26 @@
using UnityEngine;
namespace Unity.AI.Navigation.Samples
{
/// <summary>
/// Makes a transform oscillate relative to its start position
/// </summary>
public class Oscillator : MonoBehaviour
{
public float m_Amplitude = 1.0f;
public float m_Period = 1.0f;
public Vector3 m_Direction = Vector3.up;
Vector3 m_StartPosition;
void Start()
{
m_StartPosition = transform.position;
}
void Update()
{
var pos = m_StartPosition + m_Direction * m_Amplitude * Mathf.Sin(2.0f * Mathf.PI * Time.time / m_Period);
transform.position = pos;
}
}
}

View File

@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: c59ac8154f1b24ea7a85cab0f39a4489
timeCreated: 1454359265
licenseType: Pro
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 3521e0f45779e394db0026c17503fe8a
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: b965d7c48dbdb594cb2678be44f7ea34
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,192 @@
using UnityEditor;
using UnityEngine;
using UnityEngine.AI;
namespace Unity.AI.Navigation.Samples.Editor
{
/// <summary>
/// This class creates (if missing) or resets (after reimporting the samples) the agent types used by the samples.
/// It is in no way necessary for using the Navigation package and is only used for the correct functioning of the samples.
/// </summary>
public static class NavigationSampleProjectSettingsGenerator
{
const string k_NavMeshSettingsPath = "ProjectSettings/NavMeshAreas.asset";
const float k_DefaultAgentRadius = 0.5f;
const float k_DefaultAgentHeight = 2.0f;
const float k_DefaultAgentClimb = 0.4f;
const float k_DefaultAgentSlope = 45.0f;
const string k_HumanoidAgentTypeName = "Humanoid for Navigation Sample";
const int k_HumanoidAgentTypeID = 1;
const float k_HumanoidAgentClimb = 0.75f;
const string k_OgreAgentTypeName = "Ogre for Navigation Sample";
const int k_OgreAgentTypeID = 2;
const float k_OgreAgentRadius = 1.0f;
const float k_OgreAgentSlope = 36.0f;
static SerializedObject s_NavMeshParameters;
static SerializedProperty s_AgentsSettings;
static SerializedProperty s_SettingNames;
public static void GenerateAllProjectSettings(NavigationSampleSettingsState settingsState)
{
s_NavMeshParameters = new SerializedObject(AssetDatabase.LoadAllAssetsAtPath(k_NavMeshSettingsPath)[0]);
s_AgentsSettings = s_NavMeshParameters.FindProperty("m_Settings");
s_SettingNames = s_NavMeshParameters.FindProperty("m_SettingNames");
var hasInitializedOnProjectLoad = settingsState.generated;
GenerateProjectSettings(k_HumanoidAgentTypeName, k_HumanoidAgentTypeID, CreateHumanoidAgentSettings, hasInitializedOnProjectLoad);
GenerateProjectSettings(k_OgreAgentTypeName, k_OgreAgentTypeID, CreateOgreAgentSettings, hasInitializedOnProjectLoad);
s_NavMeshParameters.ApplyModifiedProperties();
settingsState.generated = true;
AssetDatabase.Refresh();
}
static void GenerateProjectSettings(string agentTypeName, int agentTypeID, CreateAgentSettings createAgentSettings, bool hasInitializedOnProjectLoad)
{
var agentProperty = GetSerializedSettingsByID(agentTypeID, out var index);
if (index < 0)
{
// Create new settings
var agentSettings = createAgentSettings();
agentSettings.agentTypeID = agentTypeID;
AddAgentSettings(agentSettings, agentTypeName, agentTypeID);
}
else
{
if (!HasSettingsNameAtIndex(index, agentTypeName))
{
// Don't update the settings
var settingsName = s_SettingNames.GetArrayElementAtIndex(index).stringValue;
if (!IsAgentTypeSetWithDefaultValues(index, agentTypeID))
{
Debug.LogWarning($"The agent type {agentTypeName} used in the Navigation Samples could not be created. The agent type {settingsName} will be used instead. {settingsName} does not have the expected values for {agentTypeName}. The expected values for {agentTypeName} are written in the README.md file of the samples. The values of agent types are updatable in the Agents tab of the AI > Navigation window.");
}
}
else if (!hasInitializedOnProjectLoad && !IsAgentTypeSetWithDefaultValues(index, agentTypeID))
{
// Update existing settings to default values
var radius = agentProperty.FindPropertyRelative("agentRadius").floatValue;
var height = agentProperty.FindPropertyRelative("agentHeight").floatValue;
var climb = agentProperty.FindPropertyRelative("agentClimb").floatValue;
var slope = agentProperty.FindPropertyRelative("agentSlope").floatValue;
var tempAgentSettings = createAgentSettings();
UpdateSettings(agentProperty, tempAgentSettings);
NavMesh.RemoveSettings(tempAgentSettings.agentTypeID);
Debug.Log($"Navigation Samples reimport detected. The agent type {agentTypeName} has been reset to its default values. Its values before the reset were: Radius = {radius}, Height = {height}, Step height = {climb} and Max Slope = {slope}.");
}
}
}
static bool IsAgentTypeSetWithDefaultValues(int index, int agentTypeID)
{
var agentTypeSettings = s_AgentsSettings.GetArrayElementAtIndex(index);
var radius = agentTypeSettings.FindPropertyRelative("agentRadius").floatValue;
var height = agentTypeSettings.FindPropertyRelative("agentHeight").floatValue;
var climb = agentTypeSettings.FindPropertyRelative("agentClimb").floatValue;
var slope = agentTypeSettings.FindPropertyRelative("agentSlope").floatValue;
var result = false;
switch (agentTypeID)
{
case k_HumanoidAgentTypeID:
result = radius == k_DefaultAgentRadius && height == k_DefaultAgentHeight && climb == k_HumanoidAgentClimb && slope == k_DefaultAgentSlope;
break;
case k_OgreAgentTypeID:
result = radius == k_OgreAgentRadius && height == k_DefaultAgentHeight && climb == k_DefaultAgentClimb && slope == k_OgreAgentSlope;
break;
}
return result;
}
delegate NavMeshBuildSettings CreateAgentSettings();
static NavMeshBuildSettings CreateHumanoidAgentSettings()
{
var humanoidAgentSettings = NavMesh.CreateSettings();
humanoidAgentSettings.agentRadius = k_DefaultAgentRadius;
humanoidAgentSettings.agentHeight = k_DefaultAgentHeight;
humanoidAgentSettings.agentClimb = k_HumanoidAgentClimb;
humanoidAgentSettings.agentSlope = k_DefaultAgentSlope;
return humanoidAgentSettings;
}
static NavMeshBuildSettings CreateOgreAgentSettings()
{
var ogreAgentSettings = NavMesh.CreateSettings();
ogreAgentSettings.agentRadius = k_OgreAgentRadius;
ogreAgentSettings.agentHeight = k_DefaultAgentHeight;
ogreAgentSettings.agentClimb = k_DefaultAgentClimb;
ogreAgentSettings.agentSlope = k_OgreAgentSlope;
return ogreAgentSettings;
}
static SerializedProperty GetSerializedSettingsByID(int agentTypeID, out int index)
{
index = -1;
SerializedProperty settings = null;
for (var i = 0; i < s_AgentsSettings.arraySize; i++)
{
if (s_AgentsSettings.GetArrayElementAtIndex(i).FindPropertyRelative("agentTypeID").intValue == agentTypeID)
{
index = i;
settings = s_AgentsSettings.GetArrayElementAtIndex(i);
break;
}
}
return settings;
}
static bool HasSettingsNameAtIndex(int index, string agentTypeName)
{
return s_SettingNames.GetArrayElementAtIndex(index).stringValue.Equals(agentTypeName);
}
static void AddAgentSettings(NavMeshBuildSettings agentSettings, string agentTypeName, int agentTypeID)
{
var nbNames = s_SettingNames.arraySize;
s_SettingNames.InsertArrayElementAtIndex(nbNames);
var newName = s_SettingNames.GetArrayElementAtIndex(nbNames);
newName.stringValue = agentTypeName;
var nbAgents = s_AgentsSettings.arraySize;
s_AgentsSettings.InsertArrayElementAtIndex(nbAgents);
var addedAgentType = s_AgentsSettings.GetArrayElementAtIndex(nbAgents);
UpdateSettings(addedAgentType, agentSettings);
SetAgentPropertyValue(addedAgentType, "agentTypeID", agentTypeID);
}
static void UpdateSettings(SerializedProperty agentToUpdate, NavMeshBuildSettings newSettings)
{
SetAgentPropertyValue(agentToUpdate, "agentRadius", newSettings.agentRadius);
SetAgentPropertyValue(agentToUpdate, "agentHeight", newSettings.agentHeight);
SetAgentPropertyValue(agentToUpdate, "agentClimb", newSettings.agentClimb);
SetAgentPropertyValue(agentToUpdate, "agentSlope", newSettings.agentSlope);
}
static void SetAgentPropertyValue(SerializedProperty agent, string propertyName, int value)
{
var property = agent.FindPropertyRelative(propertyName);
property.intValue = value;
}
static void SetAgentPropertyValue(SerializedProperty agent, string propertyName, float value)
{
var property = agent.FindPropertyRelative(propertyName);
property.floatValue = value;
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 7eeb774ee02ee2e4eb6e3387169f1ada
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,20 @@
using UnityEngine;
namespace Unity.AI.Navigation.Samples.Editor
{
/// <summary>
/// This ScriptableObject is used by the NavigationSampleProjectSettingsGenerator to check whether the generation of agent types for the samples has already been done.
/// It is in no way necessary for using the Navigation package and is only used for the correct functioning of the samples.
/// </summary>
public class NavigationSampleSettingsState : ScriptableObject
{
[SerializeField]
bool hasGeneratedSettings;
public bool generated
{
get => hasGeneratedSettings;
set => hasGeneratedSettings = value;
}
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 299341368f0a4ce5beba0c07f7bb5bbb
timeCreated: 1655319459

View File

@@ -0,0 +1,16 @@
{
"name": "Unity.AI.Navigation.Samples.Initialization.Editor",
"rootNamespace": "",
"references": [],
"includePlatforms": [
"Editor"
],
"excludePlatforms": [],
"allowUnsafeCode": false,
"overrideReferences": false,
"precompiledReferences": [],
"autoReferenced": true,
"defineConstraints": [],
"versionDefines": [],
"noEngineReferences": false
}

View File

@@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: 1dcde1c83efa6e14e8e75ed67addeba3
AssemblyDefinitionImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,40 @@
using System;
#if UNITY_EDITOR
using Unity.AI.Navigation.Samples.Editor;
using UnityEditor.SceneManagement;
#endif
using UnityEngine;
namespace Unity.AI.Navigation.Samples
{
/// <summary>
/// The Navigation samples use a couple of custom agent types.
/// This class calls the NavigationSampleProjectSettingsGenerator to ensure that these agent types do exist within your Unity project.
/// It is in no way necessary for using the Navigation package and is only used for the correct functioning of the samples.
/// </summary>
[ExecuteAlways]
public class NavigationSampleInitializer : MonoBehaviour
{
#if UNITY_EDITOR
[SerializeField]
NavigationSampleSettingsState settingsState;
void Start()
{
if (!Application.isPlaying)
{
NavigationSampleProjectSettingsGenerator.GenerateAllProjectSettings(settingsState);
DestroyGameObjectAndSave(gameObject);
}
}
static void DestroyGameObjectAndSave(GameObject gameObject)
{
var scene = gameObject.scene;
DestroyImmediate(gameObject);
EditorSceneManager.SaveScene(scene);
}
#endif
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 4b4f798af8320134f8549651d7ea621a
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,143 @@
using System.Collections;
using UnityEngine;
using System.Collections.Generic;
using UnityEngine.AI;
namespace Unity.AI.Navigation.Samples
{
/// <summary>
/// Fill 5x5 tiles around the local position procedurally by instantiating prefabs at random positions/orientations
/// </summary>
[DefaultExecutionOrder(-200)]
public class RandomInstancing : MonoBehaviour
{
public GameObject m_Prefab;
public int m_PoolSize = 250;
public int m_InstancesPerTile = 10;
public bool m_RandomPosition = true;
public bool m_RandomOrientation = true;
public float m_Height;
public int m_BaseHash = 347652783;
public float m_Size = 100.0f;
[SerializeField]
Transform parent;
[SerializeField]
NavMeshAgent trackedAgent;
List<Transform> m_Instances = new List<Transform>();
int m_Used;
int m_LocX, m_LocZ;
void Awake()
{
for (int i = 0; i < m_PoolSize; ++i)
{
var go = Instantiate(m_Prefab, Vector3.zero, Quaternion.identity, parent) as GameObject;
go.SetActive(false);
m_Instances.Add(go.transform);
}
}
void OnEnable()
{
m_LocX = ~0;
m_LocZ = ~0;
UpdateInstances();
}
void OnDestroy()
{
for (int i = 0; i < m_Instances.Count; ++i)
{
if (m_Instances[i])
Destroy(m_Instances[i].gameObject);
}
m_Instances.Clear();
}
void Update()
{
if (trackedAgent.remainingDistance > 0.1f)
{
UpdateInstances();
}
}
void UpdateInstances()
{
var x = (int)Mathf.Floor(transform.position.x / m_Size);
var z = (int)Mathf.Floor(transform.position.z / m_Size);
if (x == m_LocX && z == m_LocZ)
return;
m_LocX = x;
m_LocZ = z;
m_Used = 0;
for (var i = x - 2; i <= x + 2; ++i)
{
for (var j = z - 2; j <= z + 2; ++j)
{
var count = UpdateTileInstances(i, j);
if (count != m_InstancesPerTile)
return;
}
}
// Deactivate the remaining active elements in the pool.
// Here we assume all active elements are contiguous and first in the list.
for (int i = m_Used; i < m_PoolSize && m_Instances[i].gameObject.activeSelf; ++i)
m_Instances[i].gameObject.SetActive(false);
}
int UpdateTileInstances(int i, int j)
{
var seed = Hash2(i, j) ^ m_BaseHash;
var count = System.Math.Min(m_InstancesPerTile, m_PoolSize - m_Used);
for (var end = m_Used + count; m_Used < end; ++m_Used)
{
float x = 0;
float y = 0;
if (m_RandomPosition)
{
x = Random(ref seed);
y = Random(ref seed);
}
var pos = new Vector3((i + x) * m_Size, m_Height, (j + y) * m_Size);
if (m_RandomOrientation)
{
float r = 360.0f * Random(ref seed);
m_Instances[m_Used].rotation = Quaternion.AngleAxis(r, Vector3.up);
}
m_Instances[m_Used].position = pos;
m_Instances[m_Used].gameObject.SetActive(true);
}
if (count < m_InstancesPerTile)
Debug.LogWarning("Pool exhausted", this);
return count;
}
static int Hash2(int i, int j)
{
return (i * 73856093) ^ (j * 19349663);
}
static float Random(ref int seed)
{
seed = (seed ^ 123459876);
var k = seed / 127773;
seed = 16807 * (seed - k * 127773) - 2836 * k;
if (seed < 0)
seed = seed + 2147483647;
float ran0 = seed * 1.0f / 2147483647.0f;
seed = (seed ^ 123459876);
return ran0;
}
}
}

View File

@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: 0805752a20e62489680c7c8ba929bccc
timeCreated: 1430813999
licenseType: Pro
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,28 @@
using UnityEngine;
using UnityEngine.AI;
namespace Unity.AI.Navigation.Samples
{
/// <summary>
/// Walk to a random position and repeat
/// </summary>
[RequireComponent(typeof(NavMeshAgent))]
public class RandomWalk : MonoBehaviour
{
public float m_Range = 25.0f;
NavMeshAgent m_Agent;
void Start()
{
m_Agent = GetComponent<NavMeshAgent>();
}
void Update()
{
if (m_Agent.pathPending || !m_Agent.isOnNavMesh || m_Agent.remainingDistance > 0.1f)
return;
m_Agent.destination = m_Range * Random.insideUnitCircle;
}
}
}

View File

@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: dd76b8ee2dbcf4be6998e917c65cd6ed
timeCreated: 1431075769
licenseType: Pro
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,38 @@
using System;
using UnityEngine;
namespace Unity.AI.Navigation.Samples
{
/// <summary>
/// Prefab spawner with a key input
/// </summary>
public class SpawnPrefabOnKeyDown : MonoBehaviour
{
[SerializeField]
GameObject prefab;
[SerializeField]
KeyCode keyCode;
[SerializeField]
Transform spawnedPrefabsHolder;
Transform m_Transform;
void Start()
{
m_Transform = transform;
if (spawnedPrefabsHolder == null)
{
spawnedPrefabsHolder = m_Transform;
}
}
void Update()
{
if (Input.GetKeyDown(keyCode) && prefab != null)
Instantiate(prefab, m_Transform.position, m_Transform.rotation, spawnedPrefabsHolder);
}
}
}

View File

@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: c751607f01df8445c86b012985b8b152
timeCreated: 1430998893
licenseType: Pro
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant: