imported music, added combat and death

This commit is contained in:
2023-04-21 03:30:43 -04:00
parent 0b7b2515d1
commit c4094b169c
82 changed files with 11177 additions and 2270 deletions

View File

@ -2,6 +2,7 @@ using System.Collections;
using System.Collections.Generic;
using UnityEditor.Rendering;
using UnityEngine;
using UnityEngine.Events;
public class SkinlessMonsterAnimator : MonoBehaviour
{
@ -9,56 +10,144 @@ public class SkinlessMonsterAnimator : MonoBehaviour
private Animator animator;
private float speed = 0f;
[SerializeField]
[Tooltip("This is the object with the skin dissolve material")]
private GameObject modelObject;
[SerializeField]
private List<GameObject> objectsThatFallOnDeath= new List<GameObject>();
private Material dissolveMaterial;
private bool isAlive = true;
[SerializeField]
private float deathSpeed = 5f;
private float curDeathSpeed = 5f;
private bool isRunning = false;
public bool IsRunning { get { return isRunning; } }
[SerializeField]
private float fastDeathduration = 1f;
[SerializeField]
private float deathDuration = 5f;
[SerializeField]
private string deathAnimationName = "PainScream";
// Start is called before the first frame update
void Start()
{
dissolveMaterial = modelObject.GetComponent<SkinnedMeshRenderer>().materials[0];
curDeathSpeed = deathSpeed;
}
// Update is called once per frame
void Update()
{
if (isAlive)
{
animator.SetFloat("Speed", speed);
}
else
{
float quantity = dissolveMaterial.GetFloat("_DissolveQuantity");
quantity = Mathf.Lerp(quantity, -2, Time.deltaTime *curDeathSpeed);
dissolveMaterial.SetFloat("_DissolveQuantity", quantity);
}
animator.SetFloat("speed", speed);
}
public void StartMoving()
{
speed = 1;
if (isAlive)
{
isRunning = true;
speed = 1;
}
}
public void StopMoving()
{
speed = 0;
if (isAlive)
{
speed = 0;
isRunning = false;
}
}
public void Attack()
{
animator.SetTrigger("Attack");
if (isAlive)
{
animator.SetTrigger("Attack");
}
}
/// <summary>
/// 0,1,2,3
/// </summary>
/// <param name="attackType"></param>
public void SetAttackType(int attackType)
{
animator.SetInteger("AttackIndex", attackType);
}
public void InLight()
{
if(isAlive)
animator.SetBool("InLight", true);
}
public void NotInLight()
{
if(isAlive)
animator.SetBool("InLight", false);
}
public void AttackScream()
{
if(isAlive)
animator.SetTrigger("AttackScream");
}
public void Kill(bool fast = false)
{
//animator.speed = 0;
InLight();
//animator.Play(this.deathAnimationName);
isAlive = false;
foreach(GameObject obj in this.objectsThatFallOnDeath)
{
obj.AddComponent<Rigidbody>();
if (obj.GetComponent<Collider>() != null)
{
obj.GetComponent<Collider>().enabled = false;
}
}
float dur = this.deathDuration;
if (fast)
{
dur = this.fastDeathduration;
curDeathSpeed = deathSpeed * (this.deathDuration / this.fastDeathduration);
}
StartCoroutine(destroyAfterSeconds(dur));
}
private IEnumerator destroyAfterSeconds(float duration)
{
yield return new WaitForSeconds(duration);
Destroy(this.gameObject);
}
}

View File

@ -12,34 +12,315 @@ public class SkinlessMonsterComponent : MonoBehaviour
private NavMeshAgent agent;
[SerializeField]
private SkinlessMonsterAnimator animator;
private bool inRangeOfTarget = false;
private bool inDamageRange = false;
private bool inDamageMargin = false;
private bool atTarget = false;
[SerializeField]
private float atTargetDistance = 3;
private float atTargetDistance = 2;
private TargetInformation target;
[SerializeField]
private float health = 2f;
private void Update()
private bool isAlive = true;
private Vector3 oppositeVector;
private PlayerComponent player;
private float distanceToPlayer;
private FlareRegister flareRegister;
[SerializeField]
[Tooltip("This is the angle of visibility the enemy has")]
private float visibilityConeLimit = 90f;
[SerializeField]
private float bulletSoundRange = 15f;
private GameObject targetObject;
[SerializeField]
private float newTargetCooldown = 5f;
private float timeSinceTarget = 0f;
private void Awake()
{
if (target != null)
//Find active player rn.
PlayerComponent[] players = GameObject.FindObjectsOfType<PlayerComponent>();
foreach (PlayerComponent p in players)
{
//Update booleans for movement
float distToTarget = Vector3.Distance(target.target.transform.position, agent.transform.position);
atTarget = atTargetDistance >= distToTarget;
if (target.hasDamageRange)
if (p.isActiveAndEnabled)
{
inRangeOfTarget = target.damageRange <= distToTarget;
player = p;
}
}
}
private void Start()
{
flareRegister = GameObject.FindObjectOfType<FlareRegister>();
if (targetObject == null)
targetObject = new GameObject();
targetObject.name = "Enemy Target";
}
void HandleTargetOperations()
{
//Update booleans for movement
float distToTarget = Vector3.Distance(target.target.transform.position, agent.transform.position);
atTarget = atTargetDistance >= distToTarget;
if (target.hasDamageRange)
{
inDamageRange = target.damageRange <= distToTarget;
inDamageMargin = target.damageMargin + target.damageRange <= distToTarget;
}
else
{
inDamageRange = false;
inDamageMargin = false;
}
//Perform actions.
if (target.runTowards)
{
if (inDamageRange)
{
//Damage is being dealt
animator.InLight();
//Deal Damage
health -= Time.deltaTime;
if (health < 0 && this.isAlive)
{
this.Kill();
}
}
else if (inDamageMargin)
{
//Effective stop
agent.SetDestination(transform.position);
animator.StopMoving();
}
else
{
inRangeOfTarget = false;
}
//Perform actions.
if (atTarget)
{
//Effective stop
agent.SetDestination(transform.position);
animator.StopMoving();
if (target.isHostile)
{
animator.Attack();
animator.SetAttackType(Random.Range(0, 0));
}
}
else
{
agent.SetDestination(target.target.transform.position);
animator.StartMoving();
animator.NotInLight();
}
}
}
else
{
//Run away logic
if (atTarget || distToTarget < 3)
{
animator.StopMoving();
}
else
{
Ray r = new Ray();
r.origin = transform.position;
r.direction = oppositeVector;
RaycastHit hit;
if (Physics.Raycast(r, out hit))
{
animator.StartMoving();
agent.SetDestination(hit.point);
}
else
{
agent.SetDestination(transform.position + oppositeVector * 100);
agent.isStopped = false;
}
}
}
if (atTarget&&target.isHostile)
{
SlowLookAt(target.target.transform.position-transform.position);
}
}
void SlowLookAt(Vector3 targetVector,float animatedRotationSpeed=1f)
{
Vector3 relativePos = targetVector;
Quaternion toRotation = Quaternion.LookRotation(relativePos);
transform.rotation = Quaternion.Lerp(transform.rotation, toRotation, animatedRotationSpeed * Time.deltaTime);
}
void CheckForAOERanges()
{
foreach(BulletComponent bullet in flareRegister.bullets)
{
float dist = Vector3.Distance(bullet.transform.position, transform.position);
if (dist <= bullet.DamageRange)
{
this.health = 0;
this.Kill(true);
}
}
foreach(FlareBeacon beacon in flareRegister.beacons)
{
float dist = Vector3.Distance(beacon.transform.position, transform.position);
if (dist <= beacon.Range)
{
this.health = 0f;
}
}
if (this.health <= 0)
{
this.Kill();
}
}
public bool isPlayerVisible(bool withAngle)
{
Ray r = new Ray();
r.origin = transform.position;
r.direction = player.transform.position - transform.position;
Vector3 toPosition = (player.transform.position - transform.position).normalized;
float angleToPosition = Vector3.Angle(transform.forward, toPosition);
RaycastHit hit;
if(Physics.Raycast(r, out hit))
{
GameObject hitObject = hit.transform.gameObject;
if (hitObject.GetComponent<PlayerComponent>() != null)
{
//hit player
return angleToPosition <= this.visibilityConeLimit||!withAngle;
}else if (hitObject.GetComponentInParent<PlayerComponent>() != null)
{
//also hit player
return angleToPosition <= this.visibilityConeLimit||!withAngle;
}
}
return false;
}
void SetLiveTargeting()
{
if (!isAlive)
{
//this.targetObject.transform.position = transform.position;
this.Stop();
}
distanceToPlayer = Vector3.Distance(this.transform.position, player.transform.position);
//print("Dist Comparison "+distanceToPlayer.ToString()+" Noise:"+player.NoiseManager.NoiseDistance);
bool isPlayerVisible = this.isPlayerVisible(true);
//check if player is heard or player line of sight
if (distanceToPlayer <= player.NoiseManager.NoiseDistance||isPlayerVisible)
{
//check that nothing in between
if (this.isPlayerVisible(false))
{
this.Target(player.gameObject, true);
}
}
else
{
if (this.timeSinceTarget < this.newTargetCooldown)
{
//no further targeting
//Stop();
return;
}
BulletComponent closestBullet = null;
float closestDistance = Mathf.Infinity;
foreach(BulletComponent bullet in this.flareRegister.bullets)
{
float bDist = Vector3.Distance(bullet.transform.position, transform.position);
if (closestBullet==null||(bDist< bulletSoundRange&&bDist<closestDistance))
{
closestBullet = bullet;
closestDistance = bDist;
}
}
if (closestBullet != null)
{
targetObject.transform.position= closestBullet.transform.position;
this.Target(targetObject,false);
}
else
{
targetObject.transform.position = transform.position;
this.Target(targetObject,false);
this.Stop();
}
}
}
private void Update()
{
if (!player.IsAlive)
{
Stop();
}
if (target != null)
{
HandleTargetOperations();
}
CheckForAOERanges();
if(isAlive&&player.IsAlive)
SetLiveTargeting();
timeSinceTarget += Time.deltaTime;
/*
AI Behavior:
A. If not targeting player
1. Get distance to player
- if distance < player.NoiseDistance then target player.
2. Raycast to player to test line of sight
- if in line of sight and angle between LOS vector and forward vector is < LOF margin, then
target player.
B. If targeting player
1. If out of sound range and no line of sight then lose target.
- stop()
2. If beacon placed down and in range
- remove agent
- kill()
3. If beacon placed down and in margin:
- stop() and wait for player to leave AOE (enforced by navigation).
*/
}
/*
STANDARD BEHAVIOR:
@ -58,17 +339,32 @@ public class SkinlessMonsterComponent : MonoBehaviour
//Runs towards target. If its meant to be hostile, it will melee attack once in range.
public void Target(GameObject obj,bool hostile=false)
{
if(target.target!= obj)
if(target == null || target.target!= obj)
{
//target = new TargetInformation(obj,hostile,false,runTowards:true);
target = new TargetInformation();
target.target = obj;
target.isHostile = hostile;
target.hasDamageRange = false;
target.runTowards = true;
timeSinceTarget = 0;
}
}
//Runs towards flare such that it stops randomly within margin before range.
public void TargetFlare(GameObject obj,float range,float margin)
{
if(target.target != obj)
if(target == null || target.target != obj)
{
//target = new TargetInformation(obj, false, true, range, margin,runTowards:true);
target = new TargetInformation();
target.target = obj;
target.isHostile = false;
target.hasDamageRange = true;
target.damageRange = range;
target.damageMargin = margin;
target.runTowards = true;
timeSinceTarget = 0;
}
}
/// <summary>
@ -79,13 +375,53 @@ public class SkinlessMonsterComponent : MonoBehaviour
/// <param name="minRange"></param>
/// <param name="minMargin"></param>
public void RunAwayFrom(GameObject obj,float minRange,float minMargin) {
if(target.target != obj)
if(target== null ||target.target != obj)
{
//target = new TargetInformation(obj, false, true, minRange, minMargin, false);
target = new TargetInformation();
target.target = obj;
target.isHostile = false;
target.hasDamageRange = true;
target.damageRange = minRange;
target.damageMargin = minMargin;
target.runTowards = false;
oppositeVector = -(target.target.transform.position - transform.position).normalized;
timeSinceTarget = 0;
}
}
public void Stop()
{
target = new TargetInformation();
target.target = this.gameObject;
target.isHostile = false;
target.hasDamageRange = false;
target.runTowards = true;
}
public void Kill(bool fast=false)
{
if (this.isAlive)
{
this.animator.Kill(fast);
this.isAlive = false;
agent.isStopped = true;
}
}
private void OnTriggerEnter(Collider other)
{
if (other.gameObject.GetComponent<BulletComponent>() != null)
{
this.health -= other.gameObject.GetComponent<BulletComponent>().DamageMagnitude;
}
}
}
class TargetInformation
{

View File

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

View File

@ -0,0 +1,38 @@
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class TestSkinnlessMonster : MonoBehaviour
{
[SerializeField]
private SkinlessMonsterComponent monster;
[SerializeField]
private Camera cam;
// Start is called before the first frame update
void Start()
{
}
// Update is called once per frame
void Update()
{
if (Input.GetKeyDown(KeyCode.Alpha1))
{
monster.Target(cam.gameObject, true);
}
if (Input.GetKeyDown(KeyCode.Alpha2))
{
monster.TargetFlare(cam.gameObject, 1, 1);
}
if (Input.GetKeyDown(KeyCode.Alpha3))
{
monster.RunAwayFrom(cam.gameObject, 1, 1);
}
if (Input.GetKeyDown(KeyCode.Alpha0))
{
monster.Stop();
}
}
}

View File

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

View File

@ -0,0 +1,26 @@
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class MonsterComponent : MonoBehaviour
{
[SerializeField]
private float attackDamage = 1f;
public float AttackDamage { get { return this.attackDamage; } }
[SerializeField]
private bool shakeCameraOnHit = true;
public bool ShakeCameraOnHit { get { return this.shakeCameraOnHit; } }
// Start is called before the first frame update
void Start()
{
}
// Update is called once per frame
void Update()
{
}
}

View File

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