I’m currently using Unity standard to make a game with wandering civilians who can be infected by the player (red) and will then identify civilians on the blue team and shoot at them.
[Syndicate civilian-Persuadertron interaction example here][1]
I’m using the navmesh to move the unaffected civilian/humans to randomly selected positions in an array of transforms - and so far, so smooth.
The problem is when different populations of newly infected humans start to interact with each other. To identify an enemy, the enemy has to be within an infected human’s vision sphere (collision sphere trigger), has to be within a field of view angle and there has to be an uninterrupted line of raycast between them (and their infection state has to be non-clean and not the infection state of the infected human) - at which point, they can fire at each other!
But while running a level with 9 or so civilians wandering about (and occasionally entering infection zones), my wimpy laptop starts stuttering, movement slows to a crawl, etc.
I’m using a lot of physics, I’m using a lot of hit.getComponent, so I imagine that this is where my code is getting bogged down. But I’m trying to accomplish nothing more than Syndicate from 1993 with far fewer characters (and indeed, Satellite Reign is doing similar) … so where do I find the performance boosts to boost my performance?
Vision code follows…
using UnityEngine;
using System.Collections;
public class HumanVisionAttack : MonoBehaviour {
public Color debugRayColor = Color.green;
[SerializeField]
private float fieldOfViewAngle = 110f; // Number of degrees, centred on forward, for the enemy see.
private float halfFieldOfViewAngle;
private const float eyeHeight = 1.60f;
[SerializeField]
private LayerMask humanLayerMask; // So vision raycast only detects humans, set in inspector for your pleasure!
private HumanInfection myInfection;
private bool hasTarget = false;
// Use this for initialization
void Start () {
myInfection = GetComponent<HumanInfection>();
halfFieldOfViewAngle = fieldOfViewAngle * 0.5f;
}
// Update is called once per frame
void Update () {
}
void OnTriggerStay (Collider other){
if(other.CompareTag("human") && myInfection.infectionState != HumanInfection.InfectionState.Clean){
RaycastHit hit;
Vector3 humanToTarget = other.transform.position - transform.position;
Vector3 eyePos = new Vector3 (transform.position.x, transform.position.y + eyeHeight, transform.position.z);
// Create a vector from the enemy to the player and store the angle between it and forward.
float enemyRelativeAngle = Vector3.Angle(humanToTarget, transform.forward);
// If the angle between forward and where the player is, is less than half the angle of view...
if(IsWithinFieldOfView(enemyRelativeAngle)) {
if(Physics.Raycast(eyePos, humanToTarget, out hit, humanLayerMask) && hit.transform.CompareTag("human")){
HumanInfection.InfectionState otherInfection = hit.transform.GetComponent<HumanInfection>().infectionState;
if(otherInfection != myInfection.infectionState && otherInfection != HumanInfection.InfectionState.Clean){
// Debug.DrawLine(eyePos, hit.point, debugRayColor);
// Shooting stuff goes here
}
}
}
}
}
bool IsWithinFieldOfView (float enemyRelativeAngle) {
return enemyRelativeAngle < halfFieldOfViewAngle;
}
}
Here’s hoping somebody out there has some solutions or suggestions to speed this sucker up!
–Rev
EDIT: Hope this doesn’t count as necro’ing an old thread (10 days old?), but I’ve spent some time smacking together a solution to this problem, taking advice from the gents below. I hope it’s useful for somebody else.
HumanVision’s InspectNearbyHumans method is now triggered by a Coroutine which sweeps through an object pool of humans every .25 seconds, selecting 3-4 humans to test. The HumanVision script now reads as:
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
public class HumanVision : MonoBehaviour {
public Color debugRayColor = Color.green;
[SerializeField]
private float fieldOfViewAngle = 110f; // Number of degrees, centred on forward, for the enemy viewcone.
private float halfFieldOfViewAngle;
private const float eyeHeight = 1.60f;
[SerializeField]
private LayerMask humanLayerMask; // So vision raycast only detects humans, set in inspector for your pleasure!
private HumanInfection myInfection;
public List<HumanInfection> nearbyHumans = new List<HumanInfection>();
private HumanAttack humanAttack;
void Awake () {
myInfection = GetComponent<HumanInfection>();
humanAttack = GetComponent<HumanAttack>();
halfFieldOfViewAngle = fieldOfViewAngle * 0.5f;
}
void OnTriggerEnter (Collider other){
if(other.CompareTag("human")){
nearbyHumans.Add(other.GetComponent<HumanInfection>());
}
}
void OnTriggerExit (Collider other){
if(other.CompareTag("human")){
nearbyHumans.Remove (other.GetComponent<HumanInfection>()); // Really unsure if this is removing the correct corresponding HumanInfection
}
}
public void InspectNearbyHumans() {
// Debug.Log ("Running TestVision");
if(humanAttack.armed == HumanAttack.Armed.unarmed){
return;
}else {
for(int i = 0; i < nearbyHumans.Count; i++){
RaycastHit hit;
Vector3 humanToTarget = nearbyHumans*.transform.position - transform.position;*
-
Vector3 eyePos = new Vector3 (transform.position.x, transform.position.y + eyeHeight, transform.position.z);*
-
// Create a vector from the enemy to the player and store the angle between it and forward.*
-
float enemyRelativeAngle = Vector3.Angle(humanToTarget, transform.forward);*
-
// If the angle between forward and where the player is, is less than half the angle of view...*
-
if(IsWithinFieldOfView(enemyRelativeAngle)) {*
-
if(Physics.Raycast(eyePos, humanToTarget, out hit, humanLayerMask) && hit.transform.CompareTag("human")){*
-
HumanInfection.InfectionState otherInfection = hit.transform.GetComponent<HumanInfection>().infectionState;*
-
if(otherInfection != myInfection.infectionState && otherInfection != HumanInfection.InfectionState.Clean){*
-
humanAttack.Shoot (eyePos, hit.point, hit.transform.GetComponent<HumanHealth>());*
-
}*
-
}*
-
}*
-
}*
-
}*
-
}*
_ /* Stick an else in here which if THIS human is clean and the human in view is NOT && is !UNARMED,_
_ * then setdirection to transform.position - other.transform.position normalised * run distance (evac zone? Cower state?)_
_ */_
- bool IsWithinFieldOfView (float enemyRelativeAngle) {*
-
return enemyRelativeAngle < halfFieldOfViewAngle;*
- }*
}
The horrible, unfinished, janky, awful outcome of this is https://dl.dropboxusercontent.com/u/53322618/230115%2000.56/230115%2000.56.html Two player split-screen - pick a cat and get infecting humans with Toxoplasmosis!
[1]: Syndicate - Fun with Persuadertron (Kenya) - YouTube