#10 Testing long range ai (arrow attack system)

Additional commit content
1. Modified ObjectPool Function(OnReleaseArrow and naming).
2. Modified hitBox tag in aiPrefab.
3. Modified Physics layer.
4. Modified TargetInfo variable from TargetTransform variable in FieldOfView script.
5. Added GetCurrentHp() in IAiStat script.
This commit is contained in:
NTG_Lenovo 2023-08-09 16:44:09 +09:00
parent 01a9906e95
commit 86065e52a9
31 changed files with 2648 additions and 273 deletions

File diff suppressed because it is too large Load Diff

View File

@ -6,12 +6,21 @@ using Random = UnityEngine.Random;
// ReSharper disable once CheckNamespace
namespace BlueWaterProject
{
public enum AttackerType
{
NONE,
PLAYER,
PIRATE,
ENEMY
}
[Serializable]
public abstract class AiController : MonoBehaviour, IDamageable
{
#region Property and variable
protected bool isAttacking;
protected AttackerType attackerType;
protected Animator aiAnimator;
protected AiMover aiMover;
@ -19,7 +28,7 @@ namespace BlueWaterProject
protected NavMeshAgent navMeshAgent;
public static readonly int SpeedHash = Animator.StringToHash("Speed");
public static readonly int AttackHash = Animator.StringToHash("TakeDamage");
public static readonly int AttackHash = Animator.StringToHash("Attack");
public static readonly int DamageHash = Animator.StringToHash("TakeDamage");
public static readonly int DeathTypeHash = Animator.StringToHash("DeathType");
public static readonly int DeathHash = Animator.StringToHash("Death");
@ -40,6 +49,19 @@ namespace BlueWaterProject
aiMover = Utils.GetComponentAndAssert<AiMover>(transform);
fieldOfView = Utils.GetComponentAndAssert<FieldOfView>(transform);
navMeshAgent = Utils.GetComponentAndAssert<NavMeshAgent>(transform);
if (gameObject.layer == LayerMask.NameToLayer("Player"))
{
attackerType = AttackerType.PLAYER;
}
else if (gameObject.layer == LayerMask.NameToLayer("Pirate"))
{
attackerType = AttackerType.PIRATE;
}
else if (gameObject.layer == LayerMask.NameToLayer("Enemy"))
{
attackerType = AttackerType.ENEMY;
}
}
private void Start()
@ -57,6 +79,7 @@ namespace BlueWaterProject
#region interface property and function
[field: SerializeField] public AiStat AiStat { get; set; } = new();
public float GetCurrentHp() => AiStat.currentHp;
public void TakeDamage(AiStat attacker, AiStat defender)
{

View File

@ -43,9 +43,9 @@ namespace BlueWaterProject
}
else
{
if (!GetTarget() || moveType is MoveType.NONE or MoveType.FIXED) return;
if (!GetTargetInfo().transform || moveType is MoveType.NONE or MoveType.FIXED) return;
GetNavMeshAgent().SetDestination(GetTarget().position);
GetNavMeshAgent().SetDestination(GetTargetInfo().transform.position);
}
}
@ -54,7 +54,7 @@ namespace BlueWaterProject
#region Custom function
public bool GetIsCommanded() => isCommanded;
private Transform GetTarget() => aiController.GetFieldOfView().GetTargetTransform();
private TargetInfo GetTargetInfo() => aiController.GetFieldOfView().GetTargetInfo();
private NavMeshAgent GetNavMeshAgent() => aiController.GetNavMeshAgent();
#endregion

View File

@ -4,6 +4,42 @@ using UnityEngine;
// ReSharper disable once CheckNamespace
namespace BlueWaterProject
{
[Serializable]
public class TargetInfo
{
public Transform transform;
public Collider collider;
public IAiStat iAiStat;
public TargetInfo()
{
transform = null;
collider = null;
iAiStat = null;
}
public TargetInfo(Transform transform, Collider collider, IAiStat iAiStat)
{
this.transform = transform;
this.collider = collider;
this.iAiStat = iAiStat;
}
public void SetTargetInfo(Transform targetTransform, Collider collider, IAiStat targetIAiStat)
{
transform = targetTransform;
this.collider = collider;
iAiStat = targetIAiStat;
}
public void DefaultSetting()
{
transform = null;
collider = null;
iAiStat = null;
}
}
public class FieldOfView : MonoBehaviour
{
#region Property and variable
@ -23,7 +59,10 @@ namespace BlueWaterProject
[Header("시야 내 타겟 정보")]
[SerializeField] private Collider[] colliderWithinRange = new Collider[TARGET_MAX_SIZE];
[SerializeField] private Transform targetTransform;
[SerializeField] private TargetInfo targetInfo = new();
private Collider targetCollider;
private IAiStat iAiStat;
private const int TARGET_MAX_SIZE = 20;
@ -41,9 +80,9 @@ namespace BlueWaterProject
Gizmos.color = Color.green;
Gizmos.DrawWireSphere(myPos, viewRadius);
if (targetTransform == null) return;
if (targetInfo.transform == null) return;
Debug.DrawLine(myPos, targetTransform.position, Color.red);
Debug.DrawLine(myPos, targetInfo.transform.position, Color.red);
}
#endif
@ -57,12 +96,25 @@ namespace BlueWaterProject
if (maxColliderCount <= 0)
{
targetTransform = null;
targetInfo.DefaultSetting();
return;
}
var nearestDistance = Vector3.Distance(colliderWithinRange[0].transform.position, myPos);
var nearestTargetTransform = colliderWithinRange[0].transform;
iAiStat = colliderWithinRange[0].GetComponent<IAiStat>();
float nearestDistance;
Transform nearestTargetTransform;
if (iAiStat.GetCurrentHp() <= 0)
{
nearestDistance = float.PositiveInfinity;
nearestTargetTransform = null;
}
else
{
nearestDistance = Vector3.Distance(colliderWithinRange[0].transform.position, myPos);
nearestTargetTransform = colliderWithinRange[0].transform;
}
for (var i = 1; i < maxColliderCount; i++)
{
@ -70,25 +122,36 @@ namespace BlueWaterProject
if (nearestDistance < distance) continue;
iAiStat = colliderWithinRange[i].GetComponent<IAiStat>();
if (iAiStat.GetCurrentHp() <= 0) continue;
nearestDistance = distance;
nearestTargetTransform = colliderWithinRange[i].transform;
}
targetTransform = nearestTargetTransform;
if (nearestTargetTransform)
{
targetCollider = nearestTargetTransform.GetComponent<Collider>();
iAiStat = nearestTargetTransform.GetComponent<IAiStat>();
targetInfo.SetTargetInfo(nearestTargetTransform, targetCollider, iAiStat);
if (!targetTransform) return;
var targetPos = targetTransform.position;
var targetPos = targetInfo.transform.position;
targetPos.y = transform.position.y;
transform.LookAt(targetPos);
}
else
{
targetInfo.DefaultSetting();
}
}
#endregion
#region Custom Function
public int GetTargetLayer() => targetLayer;
public Transform GetTargetTransform() => targetTransform;
public TargetInfo GetTargetInfo() => targetInfo;
#endregion
}

View File

@ -25,6 +25,10 @@ namespace BlueWaterProject
[Tooltip("화살 발사 후 오브젝트 저장될 위치")]
[SerializeField] private Transform arrowsPoolLocation;
[Tooltip("화살이 타겟에 도달하는 오차 범위(부정확함)")]
[Range(0f, 2f)]
[SerializeField] private float inaccuracy;
private IEnumerator shootArrowCoroutine;
private IObjectPool<Arrow> arrowPool;
@ -37,12 +41,10 @@ namespace BlueWaterProject
{
base.Awake();
shootArrowTime = AiStat.atkCooldown;
shootLocation = Utils.GetComponentAndAssert<Transform>(transform.
Find("Bip001/Bip001 Pelvis/Bip001 Spine/Bip001 L Clavicle/Bip001 L UpperArm/Bip001 L Forearm/Bip001 L Hand/L_hand_container"));
arrowsPoolLocation = GameObject.Find("ObjectPoolManager/Arrows").transform;
arrowPool = new ObjectPool<Arrow>(CreateArrow, OnGetBullet, OnReleaseBullet, OnDestroyBullet, maxSize:arrowMaxSize);
arrowPool = new ObjectPool<Arrow>(CreateArrow, OnGetArrow, OnReleaseArrow, OnDestroyArrow, maxSize:arrowMaxSize);
}
#endregion
@ -61,13 +63,12 @@ namespace BlueWaterProject
}
else
{
if (shootArrowCoroutine != null || !fieldOfView.GetTargetTransform() ||
AiStat.atkRange < Vector3.Distance(transform.position, fieldOfView.GetTargetTransform().position)) return;
if (shootArrowCoroutine != null || !fieldOfView.GetTargetInfo().transform ||
AiStat.atkRange < Vector3.Distance(transform.position, fieldOfView.GetTargetInfo().transform.position)) return;
isAttacking = true;
shootArrowCoroutine = ShootArrowAnimation();
StartCoroutine(shootArrowCoroutine);
print("1");
}
}
@ -75,14 +76,18 @@ namespace BlueWaterProject
{
while (true)
{
if (!fieldOfView.GetTargetInfo().transform) yield break;
aiAnimator.SetTrigger(AttackHash);
print(shootArrowTime + "초 대기");
yield return new WaitForSeconds(shootArrowTime);
if (!fieldOfView.GetTargetInfo().transform) yield break;
var arrow = arrowPool.Get();
arrow.SetShootingArrow(fieldOfView.GetTargetTransform().position, AiStat, fieldOfView.GetTargetLayer());
arrow.SetShootingArrow(shootLocation.position,
fieldOfView.GetTargetInfo().collider.bounds.center, AiStat, attackerType, inaccuracy);
StartCoroutine(arrow.Shoot());
print("2");
yield return new WaitForSeconds(AiStat.atkCooldown);
}
}
@ -97,9 +102,9 @@ namespace BlueWaterProject
return arrow;
}
private void OnGetBullet(Arrow arrow) => arrow.gameObject.SetActive(true);
private void OnReleaseBullet(Arrow arrow) => arrow.gameObject.SetActive(false);
private void OnDestroyBullet(Arrow arrow) => Destroy(arrow.gameObject);
private void OnGetArrow(Arrow arrow) => arrow.gameObject.SetActive(true);
private void OnReleaseArrow(Arrow arrow) => arrow.ReleaseArrowSetting();
private void OnDestroyArrow(Arrow arrow) => Destroy(arrow.gameObject);
#endregion
}

View File

@ -1,7 +1,7 @@
using System;
using System.Collections;
using UnityEngine;
using UnityEngine.Pool;
using Random = UnityEngine.Random;
// ReSharper disable once CheckNamespace
namespace BlueWaterProject
@ -10,22 +10,22 @@ namespace BlueWaterProject
{
#region Property and variable
[Tooltip("화살 발사 시작할 때의 속도")]
[SerializeField] private float initialVelocity;
[Tooltip("화살이 타겟에 도달하는 오차 범위(부정확함)")]
[Range(0f, 1f)]
[SerializeField] private float inaccuracy;
[Tooltip("발사 이후 자동으로 사라지는데 까지 걸리는 시간")]
[Range(0f, 10f)]
[SerializeField] private float autoDestroyTime;
[Tooltip("화살이 날아가는 속도")]
[SerializeField] private float arrowSpeed = 15f;
private float g = Mathf.Abs(Physics.gravity.y);
private Vector3 targetPos;
private AttackerType attackerType;
private float inaccuracy;
private Transform attackerTransform;
private AiStat attackerStat;
private LayerMask targetLayer;
private IObjectPool<Arrow> managedArrowPool;
private Rigidbody arrowRigidbody;
private IObjectPool<Arrow> managedArrowPool;
#endregion
@ -38,11 +38,45 @@ namespace BlueWaterProject
private void OnTriggerEnter(Collider other)
{
if (other.gameObject.layer != targetLayer) return;
var iDamageable = other.GetComponent<IDamageable>();
print(other.gameObject.name);
if (other.gameObject.layer == LayerMask.NameToLayer("Ground") ||
other.gameObject.layer == LayerMask.NameToLayer("Water"))
{
DestroyObject();
}
else if (other.gameObject.layer == LayerMask.NameToLayer("HitBox"))
{
switch (attackerType)
{
case AttackerType.NONE:
break;
case AttackerType.PLAYER:
if (!other.gameObject.CompareTag("Enemy"))
{
return;
}
break;
case AttackerType.PIRATE:
if (!other.gameObject.CompareTag("Enemy"))
{
return;
}
break;
case AttackerType.ENEMY:
if (!other.gameObject.CompareTag("Player") || !other.gameObject.CompareTag("Pirate"))
{
return;
}
break;
default:
throw new ArgumentOutOfRangeException();
}
var iDamageable = other.transform.parent.GetComponent<IDamageable>();
print(iDamageable);
iDamageable.TakeDamage(attackerStat, iDamageable.AiStat);
DestroyObject();
}
}
#endregion
@ -51,58 +85,53 @@ namespace BlueWaterProject
public IEnumerator Shoot()
{
// TODO : 화살 발사 기능 구현
var time = 0f;
var inaccuracyOffset = new Vector3(
UnityEngine.Random.Range(-inaccuracy, inaccuracy),
UnityEngine.Random.Range(-inaccuracy, inaccuracy),
UnityEngine.Random.Range(-inaccuracy, inaccuracy)
);
var inaccurateTargetPos = targetPos + inaccuracyOffset;
transform.rotation = Quaternion.LookRotation(inaccurateTargetPos);
transform.rotation *= Quaternion.Euler(0f, -90f, 0f);
while (time < autoDestroyTime)
{
time += Time.deltaTime;
var myPos = transform.position;
var toTargetFlat = new Vector3(inaccurateTargetPos.x - myPos.x, 0, inaccurateTargetPos.z - myPos.z);
var horizontalDistance = toTargetFlat.magnitude;
var timeToTarget = horizontalDistance / arrowSpeed;
var toTarget = targetPos - transform.position;
var angle = CalcLaunchAngle(toTarget);
var yOffset = targetPos.y - myPos.y;
angle += Random.Range(-inaccuracy, inaccuracy);
var initialVerticalSpeed = (yOffset + (0.5f * g * timeToTarget * timeToTarget)) / timeToTarget;
var velocity = Quaternion.Euler(0, 0, angle) * Vector3.right * initialVelocity;
var launchVelocity = toTargetFlat.normalized * arrowSpeed + Vector3.up * initialVerticalSpeed;
arrowRigidbody.velocity = launchVelocity;
transform.rotation = Quaternion.LookRotation(arrowRigidbody.velocity);
transform.rotation *= Quaternion.Euler(0f, -90f, 0f);
arrowRigidbody.velocity = velocity;
yield return null;
}
if (gameObject.activeSelf)
{
DestroyObject();
}
private float CalcLaunchAngle(Vector3 toTarget)
{
var distance = Vector3.Distance(toTarget, Vector3.zero);
var heightDifference = toTarget.y;
var gravity = Physics.gravity.magnitude;
var velocitySqr = initialVelocity * initialVelocity;
var underSqrt = (velocitySqr * velocitySqr) - (gravity * ((gravity * distance * distance) + (2 * heightDifference * velocitySqr)));
if (underSqrt >= 0)
{
var angle1 = Mathf.Atan((velocitySqr + Mathf.Sqrt(underSqrt)) / (gravity * distance));
var angle2 = Mathf.Atan((velocitySqr - Mathf.Sqrt(underSqrt)) / (gravity * distance));
return Mathf.Min(angle1, angle2) * Mathf.Rad2Deg;
}
else
{
return 45f;
}
}
public void SetShootingArrow(Vector3 targetPosition, AiStat attacker, int targetLayerMask)
public void SetShootingArrow(Vector3 shootPos, Vector3 targetPosition, AiStat attackerAiStat, AttackerType type, float inaccuracyValue)
{
transform.position = shootPos;
targetPos = targetPosition;
attackerStat = attacker;
targetLayer = targetLayerMask;
attackerStat = attackerAiStat;
attackerType = type;
inaccuracy = inaccuracyValue;
}
//public void SetAiStat(AiStat attacker) => attackerStat = attacker;
//public void SetTargetLayer(int targetLayerMask) => targetLayer = targetLayerMask;
#endregion
@ -114,5 +143,17 @@ namespace BlueWaterProject
public void SetManagedPool(IObjectPool<Arrow> pool) => managedArrowPool = pool;
#endregion
#region Custom function
public void ReleaseArrowSetting()
{
StopAllCoroutines();
gameObject.SetActive(false);
arrowRigidbody.velocity = Vector3.zero;
arrowRigidbody.angularVelocity = Vector3.zero;
}
#endregion
}
}

View File

@ -4,5 +4,6 @@ namespace BlueWaterProject
public interface IAiStat : IAiBase
{
public AiStat AiStat { get; set; }
public float GetCurrentHp();
}
}

View File

@ -146,6 +146,9 @@ MonoBehaviour:
m_Script: {fileID: 11500000, guid: b92a5d3b88920fb49a3f6cbb978d4256, type: 3}
m_Name:
m_EditorClassIdentifier:
initialVelocity: 10
inaccuracy: 0.2
autoDestroyTime: 5
targetLayer:
serializedVersion: 2
m_Bits: 0
arrowSpeed: 15

View File

@ -9062,7 +9062,9 @@ MonoBehaviour:
- {fileID: 0}
- {fileID: 0}
- {fileID: 0}
targetTransform: {fileID: 0}
targetInfo:
transform: {fileID: 0}
collider: {fileID: 0}
--- !u!114 &7718871607120422351
MonoBehaviour:
m_ObjectHideFlags: 0
@ -9103,9 +9105,10 @@ MonoBehaviour:
arrowPrefab: {fileID: 3190292116200820221, guid: 09f461c60481dea4b975222675a2682f,
type: 3}
arrowMaxSize: 100
shootArrowTime: 0.2
shootLocation: {fileID: 0}
shootArrowTime: 0.45
shootLocation: {fileID: 461634}
arrowsPoolLocation: {fileID: 0}
inaccuracy: 1.5
--- !u!1 &156456
GameObject:
m_ObjectHideFlags: 0
@ -19358,7 +19361,7 @@ GameObject:
- component: {fileID: 8182090084654357926}
m_Layer: 12
m_Name: HitBox
m_TagString: Untagged
m_TagString: Enemy
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0

View File

@ -19352,7 +19352,7 @@ GameObject:
- component: {fileID: 5959726075807422171}
m_Layer: 12
m_Name: HitBox
m_TagString: Untagged
m_TagString: Enemy
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0

View File

@ -18820,7 +18820,7 @@ GameObject:
- component: {fileID: 3275332057743206174}
m_Layer: 12
m_Name: HitBox
m_TagString: Untagged
m_TagString: Enemy
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0

View File

@ -18520,7 +18520,7 @@ GameObject:
- component: {fileID: 5295021211657267008}
m_Layer: 12
m_Name: HitBox
m_TagString: Untagged
m_TagString: Enemy
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0

View File

@ -8847,7 +8847,7 @@ GameObject:
- component: {fileID: 1001412064052513076}
m_Layer: 10
m_Name: Swordman_E
m_TagString: Untagged
m_TagString: Enemy
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0

View File

@ -9062,7 +9062,9 @@ MonoBehaviour:
- {fileID: 0}
- {fileID: 0}
- {fileID: 0}
targetTransform: {fileID: 0}
targetInfo:
transform: {fileID: 0}
collider: {fileID: 0}
--- !u!114 &-4856147847642951458
MonoBehaviour:
m_ObjectHideFlags: 0
@ -9103,9 +9105,10 @@ MonoBehaviour:
arrowPrefab: {fileID: 3190292116200820221, guid: 09f461c60481dea4b975222675a2682f,
type: 3}
arrowMaxSize: 100
shootArrowTime: 0.2
shootLocation: {fileID: 0}
shootArrowTime: 0.45
shootLocation: {fileID: 449662}
arrowsPoolLocation: {fileID: 0}
inaccuracy: 1.5
--- !u!1 &156456
GameObject:
m_ObjectHideFlags: 0
@ -19358,7 +19361,7 @@ GameObject:
- component: {fileID: 1931168354309611384}
m_Layer: 12
m_Name: HitBox
m_TagString: Untagged
m_TagString: Pirate
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0

View File

@ -18520,7 +18520,7 @@ GameObject:
- component: {fileID: 5546785881875289881}
m_Layer: 12
m_Name: HitBox
m_TagString: Untagged
m_TagString: Pirate
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0

View File

@ -17889,7 +17889,7 @@ GameObject:
- component: {fileID: 5714371243005721170}
m_Layer: 12
m_Name: HitBox
m_TagString: Untagged
m_TagString: Pirate
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0

View File

@ -18820,7 +18820,7 @@ GameObject:
- component: {fileID: 2829027457767136232}
m_Layer: 12
m_Name: HitBox
m_TagString: Untagged
m_TagString: Pirate
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0

View File

@ -18720,7 +18720,7 @@ GameObject:
- component: {fileID: 6546119915803687715}
m_Layer: 12
m_Name: HitBox
m_TagString: Untagged
m_TagString: Pirate
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0

View File

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

View File

@ -1,7 +0,0 @@
fileFormatVersion: 2
guid: 41e59f562b69648719f2424c438758f3
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

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

View File

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

View File

@ -1,7 +0,0 @@
fileFormatVersion: 2
guid: 5f3f53ee059b45a4d9a5b9fc75e8aea9
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

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

View File

@ -1,7 +0,0 @@
fileFormatVersion: 2
guid: 4368c9be31b3c174dbfd80f2caf98889
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

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

View File

@ -1,7 +0,0 @@
fileFormatVersion: 2
guid: 48e08dc33330d11e9d4a1b246c52e4f6
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

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

View File

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

View File

@ -18,7 +18,7 @@ PhysicsManager:
m_ClothInterCollisionDistance: 0.1
m_ClothInterCollisionStiffness: 0.2
m_ContactsGeneration: 1
m_LayerCollisionMatrix: 0000000000000000000000000007000000000000000000000000000000000000080700000807000008070000001000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
m_LayerCollisionMatrix: 000000000000000000000000000f000000080000000000000000000000000000080700000807000008070000181000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
m_SimulationMode: 0
m_AutoSyncTransforms: 0
m_ReuseCollisionCallbacks: 0

View File

@ -6,6 +6,9 @@ TagManager:
tags:
- Ship
- Ground
- Stair
- Enemy
- Pirate
layers:
- Default
- TransparentFX