备份CatanBuilding瘦身独立工程
This commit is contained in:
482
Assets/Scripts/Aquarium/FishMovement.cs
Normal file
482
Assets/Scripts/Aquarium/FishMovement.cs
Normal file
@@ -0,0 +1,482 @@
|
||||
using asap.core;
|
||||
using cfg;
|
||||
using DG.Tweening;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading.Tasks;
|
||||
using Unity.Mathematics;
|
||||
using UnityEngine;
|
||||
using UnityEngine.AddressableAssets;
|
||||
|
||||
public class FishMovement : AquariumFishBase
|
||||
{
|
||||
[SerializeField] private Rigidbody rb;
|
||||
private Vector3 Orientation => transform.rotation * Vector3.forward;
|
||||
public int index = 0, groupId = -1;
|
||||
public Rigidbody Rb => rb;
|
||||
FishManager fishManager;
|
||||
GameObject goPrefab;
|
||||
float startSizeZ = 0;
|
||||
float avoidRadius = 0;
|
||||
float maxPitchAngle = 30f;
|
||||
GameObject leftEye;
|
||||
GameObject rightEye;
|
||||
public float AvoidRadius => avoidRadius * transform.localScale.x;
|
||||
public Vector3 targetPos;
|
||||
public Transform fishPos;
|
||||
GameObject fishUnDownloadAlter;
|
||||
public FishData fishData;
|
||||
public Fish fish;
|
||||
List<Collider> colliders = new List<Collider>();
|
||||
//public int triggerCount;
|
||||
public bool isResult;
|
||||
public float mutantScale;
|
||||
float loadTime;
|
||||
float startLoadTime;
|
||||
public void Init(FishManager fishManager, AquariumSlotData slotData, float startSizeZ, FishData fishData, float mutantScale)
|
||||
{
|
||||
this.mutantScale = mutantScale;
|
||||
this.slotData = slotData;
|
||||
this.fishData = fishData;
|
||||
this.fishManager = fishManager;
|
||||
this.startSizeZ = startSizeZ;
|
||||
rb.velocity = rb.rotation * Vector3.forward;
|
||||
LoadFishUnDownloadAlter(fishData.Quality - 1);
|
||||
startLoadTime = Time.time;
|
||||
}
|
||||
public void RemoveEye()
|
||||
{
|
||||
if (leftEye != null)
|
||||
{
|
||||
DestroyImmediate(leftEye);
|
||||
}
|
||||
if (rightEye != null)
|
||||
{
|
||||
DestroyImmediate(rightEye);
|
||||
}
|
||||
}
|
||||
void LoadFishUnDownloadAlter(int quality)
|
||||
{
|
||||
if (fishManager.fishUnDownloadAlter != null && fishManager.fishUnDownloadAlter.ContainsKey(quality))
|
||||
{
|
||||
fishUnDownloadAlter = Instantiate(fishManager.fishUnDownloadAlter[quality], transform);
|
||||
fish = fishUnDownloadAlter.GetComponent<Fish>();
|
||||
fish.animator.transform.localPosition = Vector3.zero;
|
||||
fish.EnableCollider();
|
||||
avoidRadius = fish.GetColliderSize(fishManager.avoidRadius);
|
||||
fishUnDownloadAlter.transform.localPosition = Vector3.zero;
|
||||
fishUnDownloadAlter.transform.localEulerAngles = Vector3.up * 180;
|
||||
fishUnDownloadAlter.transform.localScale = Vector3.one;
|
||||
fishUnDownloadAlter.name = $"{fishUnDownloadAlter.name}_{index}";
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
public async Task LoadFish(Material mutantMaterial, GameObject fxLeftEye, GameObject fxRightEye)
|
||||
{
|
||||
goPrefab = await Addressables.InstantiateAsync(fishData.Fbx, transform).Task;
|
||||
loadTime = Time.time - startLoadTime;
|
||||
if (rb == null || isResult || loadTime > fishManager.MaxLoadTime)
|
||||
{
|
||||
Debug.LogWarning($"LoadFish TimeOut:{loadTime} {fishData.Fbx}");
|
||||
Addressables.ReleaseInstance(goPrefab);
|
||||
goPrefab = null;
|
||||
}
|
||||
else if (goPrefab != null)
|
||||
{
|
||||
//Destroy(fishUnDownloadAlter);
|
||||
//fishUnDownloadAlter = null;
|
||||
if (fishUnDownloadAlter != null)
|
||||
{
|
||||
fishUnDownloadAlter.SetActive(false);
|
||||
}
|
||||
fish = goPrefab.GetComponent<Fish>();
|
||||
fish.animator.transform.localPosition = Vector3.zero;
|
||||
fish.EnableCollider();
|
||||
fish.animator.Play("Swim01", 0, UnityEngine.Random.Range(0, 0.8f));
|
||||
avoidRadius = fish.GetColliderSize(fishManager.avoidRadius);
|
||||
goPrefab.transform.localPosition = Vector3.zero;
|
||||
goPrefab.transform.localEulerAngles = Vector3.up * 180;
|
||||
goPrefab.transform.localScale = Vector3.one;
|
||||
goPrefab.name = $"{fishData.Fbx}_{index}";
|
||||
if (slotData.mutants <= index)
|
||||
{
|
||||
return;
|
||||
}
|
||||
var _tables = GContext.container.Resolve<Tables>();
|
||||
float eyeScale = _tables.TbFishMutant.FxAquariumScale[fishData.Quality - 1];
|
||||
if (fish.LeftEye != null && fxLeftEye != null)
|
||||
{
|
||||
leftEye = Instantiate(fxLeftEye);
|
||||
leftEye.transform.localScale = Vector3.one * eyeScale;
|
||||
leftEye.transform.parent = fish.LeftEye;
|
||||
leftEye.transform.localPosition = Vector3.zero;
|
||||
leftEye.transform.localRotation = Quaternion.identity;
|
||||
}
|
||||
|
||||
if (fish.RightEye != null && fxRightEye != null)
|
||||
{
|
||||
rightEye = Instantiate(fxRightEye);
|
||||
rightEye.transform.localScale = Vector3.one * eyeScale;
|
||||
rightEye.transform.parent = fish.RightEye;
|
||||
rightEye.transform.localPosition = Vector3.zero;
|
||||
rightEye.transform.localRotation = Quaternion.identity;
|
||||
}
|
||||
|
||||
Renderer[] meshRenderer = goPrefab.GetComponentsInChildren<Renderer>();
|
||||
if (meshRenderer != null && meshRenderer.Length > 0)
|
||||
{
|
||||
var render = meshRenderer[0];
|
||||
var materials = render.materials;
|
||||
for (int i = 0; i < materials.Length; i++)
|
||||
{
|
||||
var material = materials[i];
|
||||
var material_P = new Material(mutantMaterial);
|
||||
material_P.SetTexture("_BaseMap", material.GetTexture("_BaseMap"));
|
||||
material_P.SetTexture("_BumpMap", material.GetTexture("_BumpMap"));
|
||||
materials[i] = material_P;
|
||||
}
|
||||
render.materials = materials;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void OnShoot(bool isRob, float speed, float time, Vector3 reasonableCenter, Vector3 reasonableLocation, float reasonableDistance)
|
||||
{
|
||||
rb.isKinematic = true;
|
||||
isResult = true;
|
||||
|
||||
var pos = transform.position;
|
||||
var startPos = Vector3.zero;
|
||||
startPos.z = UnityEngine.Random.Range(-reasonableLocation.z, reasonableLocation.z);
|
||||
if (pos.x > fishManager.tankCenter.x)
|
||||
{
|
||||
startPos.x = UnityEngine.Random.Range(0, reasonableLocation.x);
|
||||
}
|
||||
else
|
||||
{
|
||||
startPos.x = UnityEngine.Random.Range(-reasonableLocation.x, 0);
|
||||
}
|
||||
if (pos.y > fishManager.tankCenter.y)
|
||||
{
|
||||
startPos.y = UnityEngine.Random.Range(0, reasonableLocation.y);
|
||||
}
|
||||
else
|
||||
{
|
||||
startPos.y = UnityEngine.Random.Range(-reasonableLocation.y, 0);
|
||||
}
|
||||
transform.position = startPos + reasonableCenter;
|
||||
|
||||
targetPos = startPos + reasonableCenter + rb.rotation * Vector3.forward * reasonableDistance;
|
||||
|
||||
float l = speed * time;
|
||||
float t = l / (targetPos - transform.position).magnitude;
|
||||
if (t < 1)
|
||||
{
|
||||
targetPos = Vector3.Lerp(transform.position, targetPos, t);
|
||||
}
|
||||
//转弯
|
||||
//Quaternion rotation1 = Quaternion.LookRotation(targetPos - transform.position);
|
||||
//transform.DORotateQuaternion(rotation1, time * 0.8f);
|
||||
// Move the fish along the path
|
||||
transform.DOMove(targetPos, time).SetEase(Ease.Linear);
|
||||
|
||||
SetTargetPos(isRob);
|
||||
}
|
||||
|
||||
void SetTargetPos(bool isRob)
|
||||
{
|
||||
fishPos = fish.mouthPos;
|
||||
if (!isRob)
|
||||
{
|
||||
int i = UnityEngine.Random.Range(0, 3);
|
||||
if (i == 0)
|
||||
{
|
||||
fishPos = fish.Fin;
|
||||
}
|
||||
else if (i == 1)
|
||||
{
|
||||
fishPos = fish.Neck;
|
||||
}
|
||||
else if (i == 2)
|
||||
{
|
||||
fishPos = fish.Tail;
|
||||
}
|
||||
}
|
||||
if (fishPos != null)
|
||||
{
|
||||
targetPos += fishPos.position - transform.position;
|
||||
}
|
||||
}
|
||||
|
||||
public void AllEscape()
|
||||
{
|
||||
if (!isResult)
|
||||
{
|
||||
rb.isKinematic = true;
|
||||
isResult = true;
|
||||
var ta = transform.position + rb.rotation * Vector3.forward * 50;
|
||||
transform.DOMove(ta, 3).OnComplete(() => fish.gameObject.SetActive(false)).SetEase(Ease.Linear);
|
||||
}
|
||||
}
|
||||
|
||||
public void SetFishSpeed(float speed, float time)
|
||||
{
|
||||
if (fish != null)
|
||||
{
|
||||
float curSpeed = speed;
|
||||
DOTween.To(() => speed, x => curSpeed = x, 1f, time).OnUpdate(() =>
|
||||
{
|
||||
fish.FishAnimSpeed = curSpeed;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
public void Shock(float distance, float time, AnimationCurve shockCurve)
|
||||
{
|
||||
transform.DOMoveZ(transform.position.z + distance, time).SetEase(shockCurve);
|
||||
}
|
||||
|
||||
public void Capture(float minSpeed, float maxSpeed, float addRotation, float addRotationPeriod)
|
||||
{
|
||||
fish.FishAnimSpeed = UnityEngine.Random.Range(minSpeed, maxSpeed);
|
||||
//鱼的朝向y轴 增加 rotation
|
||||
float add = UnityEngine.Random.Range(-addRotation, addRotation);
|
||||
Quaternion rotation = Quaternion.AngleAxis(add, Vector3.up);
|
||||
rb.rotation = rb.rotation * rotation; //rb.transform.forward;
|
||||
StartCoroutine(AddRotation(addRotation, addRotationPeriod));
|
||||
}
|
||||
|
||||
IEnumerator AddRotation(float addRotation, float addRotationPeriod)
|
||||
{
|
||||
Quaternion startRotation = rb.rotation;
|
||||
while (enabled)
|
||||
{
|
||||
float add = UnityEngine.Random.Range(-addRotation, addRotation);
|
||||
Quaternion rotation = Quaternion.AngleAxis(add, Vector3.up);
|
||||
//rb.rotation = startRotation * rotation; //rb.transform.forward;
|
||||
transform.DORotateQuaternion(startRotation * rotation, addRotationPeriod);
|
||||
yield return new WaitForSeconds(addRotationPeriod);
|
||||
}
|
||||
}
|
||||
|
||||
public void Escape(float distance, float duration)
|
||||
{
|
||||
transform.DOKill();
|
||||
rb.isKinematic = true;
|
||||
isResult = true;
|
||||
var ta = transform.position + rb.rotation * Vector3.forward * distance;
|
||||
transform.DOMove(ta, duration).OnComplete(() => fish.gameObject.SetActive(false)).SetEase(Ease.InSine);
|
||||
}
|
||||
public void OnShooted(bool isRob)
|
||||
{
|
||||
if (fish != null)
|
||||
{
|
||||
fish.animator.SetInteger("HurtIndex", isRob ? 2 : 1);
|
||||
fish.animator.SetTrigger("Hurt");
|
||||
}
|
||||
rb.isKinematic = true;
|
||||
isResult = true;
|
||||
}
|
||||
private void OnTriggerEnter(Collider other)
|
||||
{
|
||||
colliders.Add(other);
|
||||
}
|
||||
private void OnTriggerExit(Collider other)
|
||||
{
|
||||
colliders.Remove(other);
|
||||
}
|
||||
|
||||
private Vector3 _dv = Vector3.zero;
|
||||
private Vector3 _lastDv = Vector3.zero;
|
||||
private void FixedUpdate()
|
||||
{
|
||||
if (fishManager == null || isResult)
|
||||
{
|
||||
return;
|
||||
}
|
||||
var s = fishManager.tankSize / 2;
|
||||
float offsetX = fishManager.tankCenter.x;
|
||||
float offsetY = fishManager.tankCenter.y;
|
||||
float offsetZ = fishManager.tankCenter.z + startSizeZ;
|
||||
|
||||
//区域外
|
||||
_dv = Vector3.zero;
|
||||
// Area Constraint
|
||||
|
||||
if (rb.position.x > s.x + offsetX)
|
||||
{
|
||||
_dv += Vector3.left * (rb.position.x - s.x - offsetX);
|
||||
|
||||
}
|
||||
else if (rb.position.x < -s.x + offsetX)
|
||||
{
|
||||
_dv += Vector3.right * (-s.x + offsetX - rb.position.x);
|
||||
}
|
||||
if (rb.position.y > s.y + offsetY)
|
||||
{
|
||||
_dv += Vector3.down * (rb.position.y - s.y - offsetY);
|
||||
}
|
||||
else if (rb.position.y < -s.y + offsetY)
|
||||
{
|
||||
_dv += Vector3.up * (-s.y + offsetY - rb.position.y);
|
||||
}
|
||||
if (rb.position.z > s.z + offsetZ)
|
||||
{
|
||||
_dv += Vector3.back * (rb.position.z - s.z - offsetZ);
|
||||
}
|
||||
else if (rb.position.z < -s.z + offsetZ)
|
||||
{
|
||||
_dv += Vector3.forward * (-s.z + offsetZ - rb.position.z);
|
||||
}
|
||||
_dv *= fishManager.areaConstrain;
|
||||
|
||||
// Boids Constraint
|
||||
var colliderCount = fishManager.allFish.Count;
|
||||
// var flockMates = new List<Rigidbody>();
|
||||
var alignVelocity = Vector3.zero;
|
||||
var avoidPosition = Vector3.zero;
|
||||
var coherePosition = Vector3.zero;
|
||||
int alignBoidCount = 0, avoidBoidCount = 0, cohereBoidCount = 0;
|
||||
|
||||
for (int i = colliders.Count - 1; i >= 0; i--)
|
||||
{
|
||||
if (colliders[i] == null)
|
||||
{
|
||||
colliders.RemoveAt(i);
|
||||
continue;
|
||||
}
|
||||
Transform obstacleTransform = colliders[i].transform;
|
||||
var fromToVector = obstacleTransform.position - transform.position;
|
||||
var distance = fromToVector.magnitude;
|
||||
_dv -= fromToVector.normalized / distance * fishManager.trigger;
|
||||
}
|
||||
|
||||
for (int i = 0; i < fishManager.obstacleGo.Count; i++)
|
||||
{
|
||||
Transform obstacleTransform = fishManager.obstacleGo[i].transform;
|
||||
Vector3 localScale = obstacleTransform.localScale / 2;
|
||||
Vector3 localPos = obstacleTransform.position;
|
||||
if (transform.position.x < localPos.x - localScale.x)
|
||||
{
|
||||
localPos.x -= localScale.x;
|
||||
}
|
||||
else if (transform.position.x > localPos.x + localScale.x)
|
||||
{
|
||||
localPos.x += localScale.x;
|
||||
}
|
||||
|
||||
if (transform.position.y < localPos.y - localScale.y)
|
||||
{
|
||||
localPos.y -= localScale.y;
|
||||
}
|
||||
else if (transform.position.y > localPos.y + localScale.y)
|
||||
{
|
||||
localPos.y += localScale.y;
|
||||
}
|
||||
|
||||
if (transform.position.z < localPos.z - localScale.z)
|
||||
{
|
||||
localPos.z -= localScale.z;
|
||||
}
|
||||
else if (transform.position.z > localPos.z + localScale.z)
|
||||
{
|
||||
localPos.z += localScale.z;
|
||||
}
|
||||
|
||||
var fromToVector = localPos - transform.position;
|
||||
var distance = fromToVector.magnitude;
|
||||
// Obstacle has a higher weight than other boids
|
||||
if (distance <= fishManager.obstacleDetectionRadius)
|
||||
{
|
||||
_dv -= fromToVector.normalized / distance * fishManager.obstacle;
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < colliderCount; i++)
|
||||
{
|
||||
var flockMate = fishManager.allFish[i];
|
||||
var fromToVector = fishManager.allFish[i].transform.position - transform.position;
|
||||
var distance = fromToVector.magnitude;
|
||||
|
||||
if (fishManager.allFish[i].gameObject.name == gameObject.name || flockMate is null)
|
||||
continue;
|
||||
|
||||
if (flockMate.groupId == groupId && distance <= fishManager.alignRadius)
|
||||
{
|
||||
alignBoidCount++;
|
||||
alignVelocity += flockMate.Rb.velocity;
|
||||
}
|
||||
|
||||
if (flockMate.fishData.Quality >= fishData.Quality
|
||||
&& distance <= (AvoidRadius + flockMate.AvoidRadius))
|
||||
// && ((triggerCount > 0 && flockMate.groupId == groupId) || flockMate.groupId != groupId)
|
||||
//)
|
||||
{
|
||||
avoidBoidCount++;
|
||||
avoidPosition += flockMate.Rb.position;
|
||||
}
|
||||
|
||||
if (flockMate.groupId == groupId)
|
||||
{
|
||||
cohereBoidCount++;
|
||||
coherePosition += flockMate.Rb.position;
|
||||
}
|
||||
}
|
||||
|
||||
if (avoidBoidCount > 0)
|
||||
_dv += (rb.position - avoidPosition / avoidBoidCount) * fishManager.avoidance;
|
||||
if (alignBoidCount > 0)
|
||||
_dv += (alignVelocity / alignBoidCount - rb.velocity) * fishManager.alignment;
|
||||
if (cohereBoidCount > 0)
|
||||
_dv += (coherePosition / cohereBoidCount - rb.position) * fishManager.cohesion;
|
||||
_dv = Vector3.Lerp(_lastDv, _dv, math.saturate(fishManager.dvLerp));
|
||||
_lastDv = _dv;
|
||||
var targetVelocity = rb.velocity + _dv * Time.fixedDeltaTime;
|
||||
var newVelocity = Vector3.RotateTowards(rb.transform.forward * rb.velocity.magnitude, targetVelocity, fishManager.angularAcc,
|
||||
fishManager.magnitudeAcc);
|
||||
|
||||
//仰角限制
|
||||
float maxPitchAngle = 30f;
|
||||
float maxY = Mathf.Sin(maxPitchAngle * Mathf.Deg2Rad) * newVelocity.magnitude;
|
||||
newVelocity.y = Mathf.Clamp(newVelocity.y, -maxY, maxY);
|
||||
|
||||
if (newVelocity.magnitude < 0.001)
|
||||
{
|
||||
return;
|
||||
}
|
||||
rb.rotation = Quaternion.LookRotation(newVelocity);
|
||||
newVelocity = Vector3.RotateTowards(newVelocity, targetVelocity, fishManager.angularAcc,
|
||||
fishManager.magnitudeAcc);
|
||||
|
||||
maxY = Mathf.Sin(maxPitchAngle * Mathf.Deg2Rad) * newVelocity.magnitude;
|
||||
newVelocity.y = Mathf.Clamp(newVelocity.y, -maxY, maxY);
|
||||
|
||||
float angle = Vector3.Angle(rb.velocity, targetVelocity);
|
||||
newVelocity *= 1 - (angle / 185);
|
||||
rb.velocity = newVelocity;
|
||||
|
||||
//Max-Min Constraint
|
||||
if (rb.velocity.magnitude > fishManager.maxVel)
|
||||
rb.velocity = rb.velocity.normalized * fishManager.maxVel;
|
||||
else if (rb.velocity.magnitude < fishManager.minVel)
|
||||
rb.velocity = rb.velocity.normalized * fishManager.minVel;
|
||||
}
|
||||
private void OnDestroy()
|
||||
{
|
||||
if (goPrefab != null)
|
||||
{
|
||||
Addressables.ReleaseInstance(goPrefab);
|
||||
goPrefab = null;
|
||||
}
|
||||
}
|
||||
private void OnDrawGizmosSelected()
|
||||
{
|
||||
// Display the explosion radius when selected
|
||||
Gizmos.color = Color.red;
|
||||
Gizmos.DrawWireSphere(transform.position, AvoidRadius);
|
||||
Gizmos.color = Color.blue;
|
||||
Gizmos.DrawLine(transform.position, transform.position + _dv * (5 * Time.fixedDeltaTime));
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user