I’m making a platformer-style game with some enemies that patrol/chase the player around. Everything works pretty much as expected, but the script driving these guys is just so SLOW: for every enemy on screen, the framerate dives to half of what it was before hand. 'm entirely at wits end right now, because due to the design of the game, I’ve got to have all ten enemies on screen at once (you can see the old version of the game in my sig, before the new enemies). I’m not trying to have anybody re-write the script for me, but I would like some pointers on optimizing it. Thanks in advance
Here’s the script (it’s a bigg’n). Don’t mind the commented out sections, those were for testing/posterity:
////////////////////////////////////////////////////////////////////////////////////////
//The new, improved Enemy script. Fear he who hath it.
//Written by Ethan Redd. 10/6/11. All Rights Reserved.
//////////////////////////////////////////////////////////////////////////////////////
//////////////////
//Var Declarations
var p1 : Transform;
var shouldDoSomething = false;
var myTransform : Transform;
var isFalling =true;
var state : String = "patrol";//Convienience var. Only use "patrol", "attack", and "evade".
var facingLeft = false;
var isWalking = false;
var enemyRunning = false;
var player1 : Transform;
var jumpForce = 10;
var stop = false;
var canTurn = true;
var canCount = true;
var distanceTest = 8;
//Sensors. You know, for sensing
var above_L : Transform;
var above_R : Transform;
var diag_L : Transform;
var diag_R : Transform;
var left : Transform;
var right : Transform;
var fallCheck_L : Transform;
var fallCheck_R : Transform;
var shoot_L : Transform;
var shoot_R : Transform;
var shoot_Down : Transform;
var melee_L : Transform;
var melee_R : Transform;
var star : Transform;
var star2 : Transform;
var backside : Transform;
var above_Lscript ;
var above_Rscript ;
var diag_Lscript ;
var diag_Rscript ;
var leftscript ;
var rightscript ;
var fallCheck_Lscript;
var fallCheck_Rscript;
var shoot_Lscript ;
var shoot_Rscript ;
var shoot_Downscript;
var melee_Rscript ;
var melee_Lscript ;
var enemiesDowned ;
var enemiesText ;
var enemyScoreScript ;
function Awake(){
above_Lscript = above_L.GetComponent("Sensors");
above_Rscript = above_R.GetComponent("Sensors");
diag_Lscript = diag_L.GetComponent("Sensors");
diag_Rscript = diag_R.GetComponent("Sensors");
leftscript = left.GetComponent("Sensors");
rightscript = right.GetComponent("Sensors");
fallCheck_Lscript = fallCheck_L.GetComponent("Sensors");
fallCheck_Rscript = fallCheck_R.GetComponent("Sensors");
shoot_Lscript = shoot_L.GetComponent("Sensors");
shoot_Rscript = shoot_R.GetComponent("Sensors");
shoot_Downscript = shoot_Down.GetComponent("Sensors");
melee_Rscript = melee_R.GetComponent("Sensors");
melee_Lscript = melee_L.GetComponent("Sensors");
enemiesDowned = GameObject.Find("Enemies Downed(Clone)");
enemiesText = enemiesDowned.GetComponent("TextMesh");
enemyScoreScript = enemiesDowned.GetComponent("Enemy Scoring");
state = "patrol";
transform.rotation.y = 45;
}
////////////////////////////////////////////////
/////////////////////
//Function Definitions
function Score(){
/* var enemiesDowned = GameObject.Find("Enemies Downed(Clone)");
* var enemiesText = enemiesDowned.GetComponent("TextMesh");
* var enemyScoreScript = enemiesDowned.GetComponent("Enemy Scoring");
*/
for (var i = 1; i == 1&canCount == true; --i)
{
enemyScoreScript.enemiesLeft-= 1;
canCount = false;
}
canCount = false;
yield WaitForSeconds (0.05);
collider.isTrigger = true;
yield WaitForSeconds (2);
Destroy(gameObject);
}
//Turn around
function Turn(){
if (state == "attack")
{
var toTarget = player1.position - myTransform.position;
toTarget.y = 0;
// without smoothing:
myTransform.right = myTransform.InverseTransformDirection(toTarget);
//transform.LookAt (new Vector3(transform.position.x, player1.transform.position.x,transform.position.z));
}
if (state == "evade")
{
toTarget = player1.position - transform.position;
toTarget.y = 0;
toTarget * -1;
// without smoothing:
myTransform.right = myTransform.InverseTransformDirection(toTarget);
//transform.LookAt (transform.InverseTransformDirection(new Vector3(transform.position.x, player1.transform.position.x,transform.position.z)));
}
if (state == "patrol")
{
if (canTurn == true)
{
var backTarget = backside.position;// - transform.position;
backTarget.y = 0;
// without smoothing:
myTransform.right = myTransform.InverseTransformDirection(backTarget);
canTurn = false;
yield WaitForSeconds (3);
canTurn = true;
}
}
}
//Dictates which state we use and when
function Switch()
{
var randomState = Mathf.Clamp(Random.value, 0.1, 0.3) * 10;
if (state == "patrol")
{return;}
if (state != "patrol")
{
if (randomState == 1)
{state = "attack";}
if (randomState == 2)
{state = "evade";}
if (randomState == 3)
{state = "patrol";}
}
}
//Continuously Run Right
function Run()
{
//~ var above_Lscript = above_L.GetComponent("Sensors");
//~ var above_Rscript = above_R.GetComponent("Sensors");
//~ var diag_Lscript = diag_L.GetComponent("Sensors");
//~ var diag_Rscript = diag_R.GetComponent("Sensors");
//~ var leftscript = left.GetComponent("Sensors");
//~ var rightscript = right.GetComponent("Sensors");
//~ var fallCheck_Lscript = fallCheck_L.GetComponent("Sensors");
//~ var fallCheck_Rscript = fallCheck_R.GetComponent("Sensors");
//~ var shoot_Lscript = shoot_L.GetComponent("Sensors");
//~ var shoot_Rscript = shoot_R.GetComponent("Sensors");
//~ var shoot_Downscript = shoot_Down.GetComponent("Sensors");
//~ var melee_Rscript = melee_R.GetComponent("Sensors");
//~ var melee_Lscript = melee_L.GetComponent("Sensors");
/*
* if(above_Rscript.touching == "player"
* ||diag_Rscript.touching == "player"
* ||melee_Rscript.touching == "player"
* ||rightscript.touching == "player"
* ||fallCheck_Rscript.touching == "player"
* ||shoot_Rscript.touching == "player")
* {transform.rotation.y = -135;}
*
*/
stop = false;
while (stop == false)
{
rigidbody.velocity = transform.InverseTransformDirection(Vector3.left*10);
//transform.Translate( transform.InverseTransformDirection(Vector3.left*10*Time.deltaTime));
isWalking = true;
//Break out of loop, and function
yield WaitForSeconds (2);
stop = true;
break;
}
return;
}
//Jump Straight Up
function Jump()
{
if (isFalling == false)
rigidbody.velocity.y = jumpForce;
}
// Shoot Forward
function Shoot()
{
for(var i = 1; i == 1; i++)
{
var enemyShot = Instantiate(star2, transform.position,star.rotation);
enemyShot.gameObject.name = "enemyShot";
enemyShot.rigidbody.velocity.x = -15;
}
}
// Shoot Straight Down
function ShootDown()
{
for(var i = 1; i == 1; i++)
{
var enemyShot = Instantiate(star, transform.position,star.rotation);
enemyShot.gameObject.name = "enemyShot";
enemyShot.rigidbody.velocity.y = -5;
}
yield WaitForSeconds (1.8);
}
//What to do while in the Attack mode
function Attack()
{
//~ var above_Lscript = above_L.GetComponent("Sensors");
//~ var above_Rscript = above_R.GetComponent("Sensors");
//~ var diag_Lscript = diag_L.GetComponent("Sensors");
//~ var diag_Rscript = diag_R.GetComponent("Sensors");
//~ var leftscript = left.GetComponent("Sensors");
//~ var rightscript = right.GetComponent("Sensors");
//~ var fallCheck_Lscript = fallCheck_L.GetComponent("Sensors");
//~ var fallCheck_Rscript = fallCheck_R.GetComponent("Sensors");
//~ var shoot_Lscript = shoot_L.GetComponent("Sensors");
//~ var shoot_Rscript = shoot_R.GetComponent("Sensors");
//~ var shoot_Downscript = shoot_Down.GetComponent("Sensors");
//~ var melee_Rscript = melee_R.GetComponent("Sensors");
//~ var melee_Lscript = melee_L.GetComponent("Sensors");
//Grounded Behavior
if (isFalling == false)
{
if (above_Lscript.touching == "player")
{Turn(); Run(); Jump();}
if (above_Rscript.touching == "player")
{Turn(); Run();}
if (diag_Lscript.touching == "player")
{Turn();Shoot();}
if (diag_Rscript.touching == "player")
{Turn();Shoot();}
if (fallCheck_Lscript.touching == "player")
{Turn();Run();Shoot();}
if (fallCheck_Rscript.touching == "player")
{Turn(); Run();Jump();Shoot();}
if (shoot_Lscript.touching == "player")
{Turn(); Run(); Shoot();}
if (shoot_Rscript.touching == "player")
{Turn(); Run();Shoot();}
if (melee_Lscript.touching == "player")
{Shoot();}
if (leftscript.touching == "player")
{Jump();}
if (rightscript.touching == "player")
{Jump();}
if (shoot_Downscript.touching == "player")
{ShootDown();}
}
//Midair Behavior
if (isFalling == true)
{
if (above_Lscript.touching == "player")
{Run();}
if (above_Rscript.touching == "player")
{Run();}
if (diag_Lscript.touching == "player")
{Run();}
if (diag_Rscript.touching == "player")
{Run();}
if (fallCheck_Lscript.touching == "player")
{Run(); ShootDown();}
if (fallCheck_Rscript.touching == "player")
{Run(); ShootDown();}
if (shoot_Lscript.touching == "player")
{}
if (shoot_Rscript.touching == "player")
{}
if (melee_Lscript.touching == "player")
{Shoot();}
if (leftscript.touching == "player")
{Run(); Shoot();}
if (rightscript.touching == "player")
{Run(); Shoot();}
if (shoot_Downscript.touching == "player")
{ShootDown();}
}
}
//What to do while in the Evade mode
function Evade()
{
//~ var above_Lscript = above_L.GetComponent("Sensors");
//~ var above_Rscript = above_R.GetComponent("Sensors");
//~ var diag_Lscript = diag_L.GetComponent("Sensors");
//~ var diag_Rscript = diag_R.GetComponent("Sensors");
//~ var leftscript = left.GetComponent("Sensors");
//~ var rightscript = right.GetComponent("Sensors");
//~ var fallCheck_Lscript = fallCheck_L.GetComponent("Sensors");
//~ var fallCheck_Rscript = fallCheck_R.GetComponent("Sensors");
//~ var shoot_Lscript = shoot_L.GetComponent("Sensors");
//~ var shoot_Rscript = shoot_R.GetComponent("Sensors");
//~ var shoot_Downscript = shoot_Down.GetComponent("Sensors");
//~ var melee_Rscript = melee_R.GetComponent("Sensors");
//~ var melee_Lscript = melee_L.GetComponent("Sensors");
//Grounded Behavior
if (isFalling == false)
{
if (above_Lscript.touching == "player")
{Run();}
if (above_Rscript.touching == "player")
{Run();}
if (diag_Lscript.touching == "player")
{Run();}
if (diag_Rscript.touching == "player")
{Run();}
if (fallCheck_Lscript.touching == "player")
{Jump();}
if (fallCheck_Rscript.touching == "player")
{Jump();}
if (shoot_Lscript.touching == "player")
{Run();}
if (shoot_Rscript.touching == "player")
{Run();}
if (melee_Lscript.touching == "player")
{Run(); Shoot();}
if (leftscript.touching == "player")
{Run();}
if (rightscript.touching == "player")
{Run();}
if (shoot_Downscript.touching == "player")
{ShootDown();}
if (melee_Lscript.touching == "block"||melee_Rscript.touching == "block")
{Run();Jump();}
}
//Midair Behavior
if (isFalling == true)
{
if (above_Lscript.touching == "player")
{Run();}
if (above_Rscript.touching == "player")
{Run();}
if (diag_Lscript.touching == "player")
{Run();}
if (diag_Rscript.touching == "player")
{Run();}
if (fallCheck_Lscript.touching == "player")
{Shoot();}
if (fallCheck_Rscript.touching == "player")
{Shoot();}
if (shoot_Lscript.touching == "player")
{Run();}
if (shoot_Rscript.touching == "player")
{Run();}
if (melee_Lscript.touching == "player")
{Run();Shoot();}
if (leftscript.touching == "player")
{Run();}
if (rightscript.touching == "player")
{Run();}
if (shoot_Downscript.touching == "player")
{Run();}
if (melee_Lscript.touching == "block"||melee_Rscript.touching == "block")
{Run();}
}
}
//What to do while in the Patrol mode
function Patrol()
{
//~ var above_Lscript = above_L.GetComponent("Sensors");
//~ var above_Rscript = above_R.GetComponent("Sensors");
//~ var diag_Lscript = diag_L.GetComponent("Sensors");
//~ var diag_Rscript = diag_R.GetComponent("Sensors");
//~ var leftscript = left.GetComponent("Sensors");
//~ var rightscript = right.GetComponent("Sensors");
//~ var fallCheck_Lscript = fallCheck_L.GetComponent("Sensors");
//~ var fallCheck_Rscript = fallCheck_R.GetComponent("Sensors");
//~ var shoot_Lscript = shoot_L.GetComponent("Sensors");
//~ var shoot_Rscript = shoot_R.GetComponent("Sensors");
//~ var shoot_Downscript = shoot_Down.GetComponent("Sensors");
//~ var melee_Rscript = melee_R.GetComponent("Sensors");
//~ var melee_Lscript = melee_L.GetComponent("Sensors");
if (isFalling == false)
{
if (melee_Lscript.touching == "player"
//||above_Lscript.touching == "player"
||diag_Lscript.touching == "player"
//||fallCheck_Lscript.touching == "player"
||shoot_Lscript.touching == "player"
//||above_Rscript.touching == "player"
||diag_Rscript.touching == "player"
||fallCheck_Rscript.touching == "player"
//||shoot_Rscript.touching == "player"
||melee_Rscript.touching == "player")
{state = "attack";}
//Turn Around when you touch something
if (melee_Lscript.touching == "block"
||melee_Rscript.touching == "block")
{
Turn();
}
yield WaitForSeconds (Random.value * 100);
Run();
yield WaitForSeconds (Random.value * 100);
Turn();
Run();
Turn();
}
}
///////////////////////////////////////////////////////////////
//////////////////WHEWWWW.////////////////////////////////
///////////////////////////////////////////////////////////////
///////////////////
//Unity's Functions
//InvokeRepeating("Switch", 20, 25);
function Update () {
//State-based Statements
//Patrol Mode. Walk back&forth aimlessly . It's a tradition.
//Baton-down all the axes, constrain to 2D
myTransform.position.z = 0;
myTransform.rotation.z = 0;
myTransform.rotation.x = 0;
if (state == "patrol")
{
Patrol();
}
//Attack Mode. Aggressively be aggressive, play to win.
if (state == "attack")
{
Attack();
}
//Evade Mode. Run for your life, live to fight another day.
if (state == "evade")
{
Evade();
}
}
function OnCollisionEnter(col:Collision)
{
if (col.gameObject.tag == "Water")
{
Score();
}
if (col.gameObject.tag == "Trampoline")
{
rigidbody.velocity.y = 30;
}
isFalling = false;
}
function OnCollisionStay()
{
isFalling = false;
}
function OnCollisionExit()
{
isFalling = true;
}
If you have the pro version open up the profiler and set it to deep and see what pops up as the top time user.
But at a glance it looks like you are using a lot of yields which should be ok, but if all enemies start at the same time then they will mostly be in sync, you could try an incremental offset for each enemy e.g yeild WaitForSeconds(3+enemyTimeOffset);
Add a simple script to find all enemies and ensure they all have an offset of about 0.1 seconds apart.
Alternatively you could have a simple collision sphere trigger on the enemies so they are inactive until the player is within a certain range, what use is a patrolling enemy when the players in the next valley?
Thanks for the speedy reply, @Arowx! I don’t have the Pro version (I’m on a ramen-noodle-everyday budget ), so using the profiler is out. How would I implement the time offset? Would I get/set through an iterative loop, or some other method?
Also, the game is 2-D and all of the AI are on screen at once (think PacMan), and just having a bunch of stoic AI just standing there was not very engaging.
You can set up a static variable in the script that is accessed and incremented in each enemies Start function, or you can set up a script that uses FindObjectsWithTag() Unity - Scripting API: GameObject.FindGameObjectsWithTag
And ensure it is scheduled to run before the enemies Start function!
You can get the Pro version for 30 days, handy for profiling your game prior to release!
Good idea, the Pro version might be handy for a few days of intense bugfixing. Thanks!
As for staggering the enemies updating, I’ll try it, but I don’t think that’s the root problem here. If the problem was too many enemies updating at the same time, why would having one enemy on screen half the framerate? Is there anything in the else script just messy/un-optimized? I really appreciate the help, because I tried every trick I know to speed up the code, but my bag of tricks is getting empty (>.<)
To be painfully honest, yes, there’s a lot. You’re starting new coroutines every frame in Update, so you probably have hundreds or thousands of them running, which is probably the main thing. I’d highly recommend removing Update, and just using coroutines. Just so you know, transform.rotation is a quaternion, and .x and .z aren’t what you think they are, but you can just use rigidbody constraints instead of setting that stuff manually. Also, use enums instead of strings. When you have mutually exclusive conditions, use “else” with “if” statements, so you’re not evaluating conditions that can’t be true anyway. Also I see some bugs, such as
var randomState = Mathf.Clamp(Random.value, 0.1, 0.3) * 10;
That will virtually never result in 2. I guess you just want
@Eric5h5: You just made my day That was precisely the help I needed! (I’m new to the coding side of things, so I really am out of my element here). I’ll post again after I’ve applied your advice.
Thanks for the insight!
EDIT: I’m trying to replace the Update function w/ Coroutines, but I’m not exactly sure how to begin… would I do something like this?
function Start(){
while (true)
{
//Update stuff goes here
}
}
OK, I swapped all of the ‘ifs’ with switches, and if/else-s, and made a bunch of other changes that were suggested, but the script is only about 2fps faster, so needless to say I’m pretty confused now >.<
Would the fact that the script is dynamically typed affect the performance this severely? I’m trying to re-write it statically now, but I’m not even sure it’s worth the effort…
Thanks for all the help, btw You guys are great.
UPDATE: Used #pragma strict, statically typed the whole thing, and it’s still slower than molasses. I am officially out of ideas, and will try ANYTHING.
Here’s the newer script:
#pragma strict
enum State
{
Patrol = 0,
Attack = 1,
Evade = 2
}
var state:int = State.Patrol;
var p1 : Transform;
var shouldDoSomething = false;
var myTransform : Transform;
var isFalling: boolean =true;
var facingLeft :boolean= false;
var isWalking :boolean= false;
var enemyRunning :boolean= false;
var player1 : Transform;
var jumpForce:float = 10;
var stop :boolean= false;
var canTurn :boolean= true;
var canCount :boolean= true;
var distanceTest :float= 8;
enum Touching
{
mYnull = 0,
player = 1,
block= 2
}
//EnemySensors. You know, for sensing
var above_L : Transform;
var above_R : Transform;
var diag_L : Transform;
var diag_R : Transform;
var left : Transform;
var right : Transform;
var fallCheck_L : Transform;
var fallCheck_R : Transform;
var shoot_L : Transform;
var shoot_R : Transform;
var shoot_Down : Transform;
var melee_L : Transform;
var melee_R : Transform;
var star : Transform;
var star2 : Transform;
var backside : Transform;
var above_Lscript :EnemySensors;
var above_Rscript :EnemySensors ;
var diag_Lscript :EnemySensors ;
var diag_Rscript :EnemySensors ;
var leftscript :EnemySensors ;
var rightscript :EnemySensors ;
var fallCheck_Lscript :EnemySensors ;
var fallCheck_Rscript :EnemySensors ;
var shoot_Lscript :EnemySensors ;
var shoot_Rscript :EnemySensors ;
var shoot_Downscript :EnemySensors ;
var melee_Rscript :EnemySensors;
var melee_Lscript :EnemySensors;
private var enemiesDowned : GameObject;
private var enemiesText :Component ;
private var enemyScoreScript : Enemy_Scoring;
function Awake(){
InvokeRepeating("Switch", 20, 25);
above_Lscript = above_L.GetComponent("EnemySensors") as EnemySensors;
above_Rscript = above_R.GetComponent("EnemySensors") as EnemySensors;
diag_Lscript = diag_L.GetComponent("EnemySensors") as EnemySensors;
diag_Rscript = diag_R.GetComponent("EnemySensors") as EnemySensors;
leftscript = left.GetComponent("EnemySensors") as EnemySensors;
rightscript = right.GetComponent("EnemySensors") as EnemySensors;
fallCheck_Lscript = fallCheck_L.GetComponent("EnemySensors") as EnemySensors;
fallCheck_Rscript = fallCheck_R.GetComponent("EnemySensors") as EnemySensors;
shoot_Lscript = shoot_L.GetComponent("EnemySensors") as EnemySensors;
shoot_Rscript = shoot_R.GetComponent("EnemySensors") as EnemySensors;
shoot_Downscript = shoot_Down.GetComponent("EnemySensors") as EnemySensors;
melee_Rscript = melee_R.GetComponent("EnemySensors") as EnemySensors;
melee_Lscript = melee_L.GetComponent("EnemySensors") as EnemySensors;
//enemiesDowned = GameObject.Find("Enemies Downed(Clone)") as GameObject;
enemiesText = GameObject.Find("Enemies Downed(Clone)").GetComponent("TextMesh") as TextMesh;
//enemiesText :enemiesDowned = enemiesDowned.GetComponent("TextMesh") as TextMesh;
enemyScoreScript = GameObject.Find("Enemies Downed(Clone)").GetComponent("Enemy_Scoring") as Enemy_Scoring;
transform.rotation.y = 45;
}
function Score(){
/* var enemiesDowned = GameObject.Find("Enemies Downed(Clone)");
* var enemiesText = enemiesDowned.GetComponent("EnemySensors") as EnemySensors;("TextMesh");
* var enemyScoreScript = enemiesDowned.GetComponent("EnemySensors") as EnemySensors;("Enemy Scoring");
*/
for (var i = 1; i == 1&canCount == true; --i)
{
enemyScoreScript.enemiesLeft += -1;
canCount = false;
}
canCount = false;
yield WaitForSeconds (0.05);
collider.isTrigger = true;
yield WaitForSeconds (2);
Destroy(gameObject);
}
function Turn(){
if (state == State.Attack)
{
var toTarget = player1.position - myTransform.position;
toTarget.y = 0;
// without smoothing:
myTransform.right = myTransform.InverseTransformDirection(toTarget);
//transform.LookAt (new Vector3(transform.position.x, player1.transform.position.x,transform.position.z));
}
if (state == State.Evade)
{
toTarget = player1.position - transform.position;
toTarget.y = 0;
toTarget * -1;
// without smoothing:
myTransform.right = myTransform.InverseTransformDirection(toTarget);
//transform.LookAt (transform.InverseTransformDirection(new Vector3(transform.position.x, player1.transform.position.x,transform.position.z)));
}
else
{
if (canTurn == true)
{
var backTarget : Vector3 = backside.position;// - transform.position;
backTarget.y = 0;
// without smoothing:
myTransform.right = myTransform.InverseTransformDirection(backTarget);
canTurn = false;
yield WaitForSeconds (3);
canTurn = true;
}
}
}
function Switch()
{
var randomState = Random.Range(1, 4);
if (state != 0)
{
if (randomState == 1)
{state = 1;}
if (randomState == 2)
{state = 2;}
else
{state = 0;}
}
}
//Continuously Run Right
function Run()
{
stop = false;
while (stop == false)
{
rigidbody.velocity = transform.InverseTransformDirection(Vector3.left*10);
//transform.Translate( transform.InverseTransformDirection(Vector3.left*10*Time.deltaTime));
isWalking = true;
//Break out of loop, and function
yield WaitForSeconds (2);
stop = true;
break;
}
return;
}
//Jump Straight Up
function Jump()
{
if (isFalling == false)
rigidbody.velocity.y = jumpForce;
else
return;
}
// Shoot Forward
function Shoot()
{
for(var i = 1; i == 1; i++)
{
var enemyShot = Instantiate(star2, transform.position,star.rotation) as GameObject;
enemyShot.gameObject.name = "enemyShot";
enemyShot.rigidbody.velocity.x = -15;
}
}
// Shoot Straight Down
function ShootDown()
{
for(var i = 1; i == 1; i++)
{
var enemyShot = Instantiate(star, transform.position,star.rotation) as GameObject;
enemyShot.gameObject.name = "enemyShot";
enemyShot.rigidbody.velocity.y = -5;
}
yield WaitForSeconds (1.8);
}
//What to do while in the Attack mode
function Attack(): IEnumerator
{
//Grounded Behavior
if (isFalling == false)
{
if (above_Lscript.touching == 1)
{Turn(); Run(); Jump();}
if (above_Rscript.touching == 1)
{Turn(); Run();}
if (diag_Lscript.touching == 1)
{Turn();Shoot();}
if (diag_Rscript.touching == 1)
{Turn();Shoot();}
if (fallCheck_Lscript.touching == 1)
{Turn();Run();Shoot();}
if (fallCheck_Rscript.touching == 1)
{Turn(); Run();Jump();Shoot();}
if (shoot_Lscript.touching == 1)
{Turn(); Run(); Shoot();}
if (shoot_Rscript.touching == 1)
{Turn(); Run();Shoot();}
if (melee_Lscript.touching == 1)
{Shoot();}
if (leftscript.touching == 1)
{Jump();}
if (rightscript.touching == 1)
{Jump();}
if (shoot_Downscript.touching == 1)
{ShootDown();}
else
{Run();}
}
//Midair Behavior
else//if (isFalling == true)
{
if (above_Lscript.touching == 1)
{Run();}
if (above_Rscript.touching == 1)
{Run();}
if (diag_Lscript.touching == 1)
{Run();}
if (diag_Rscript.touching == 1)
{Run();}
if (fallCheck_Lscript.touching == 1)
{Run(); ShootDown();}
if (fallCheck_Rscript.touching == 1)
{Run(); ShootDown();}
if (shoot_Lscript.touching == 1)
{}
if (shoot_Rscript.touching == 1)
{}
if (melee_Lscript.touching == 1)
{Shoot();}
if (leftscript.touching == 1)
{Run(); Shoot();}
if (rightscript.touching == 1)
{Run(); Shoot();}
if (shoot_Downscript.touching == 1)
{ShootDown();}
else
{Run();}
}
}
//What to do while in the Evade mode
function Evade(): IEnumerator
{
//Grounded Behavior
if (isFalling == false)
{
if (above_Lscript.touching == 1)
{Run();}
if (above_Rscript.touching == 1)
{Run();}
if (diag_Lscript.touching == 1)
{Run();}
if (diag_Rscript.touching == 1)
{Run();}
if (fallCheck_Lscript.touching == 1)
{Jump();}
if (fallCheck_Rscript.touching == 1)
{Jump();}
if (shoot_Lscript.touching == 1)
{Run();}
if (shoot_Rscript.touching == 1)
{Run();}
if (melee_Lscript.touching == 1)
{Run(); Shoot();}
if (leftscript.touching == 1)
{Run();}
if (rightscript.touching == 1)
{Run();}
if (shoot_Downscript.touching == 1)
{ShootDown();}
if (melee_Lscript.touching == 2||melee_Rscript.touching == 2)
{Run();Jump();}
else
{Run();}
}
//Midair Behavior
else//if (isFalling == true)
{
if (above_Lscript.touching == 1)
{Run();}
if (above_Rscript.touching == 1)
{Run();}
if (diag_Lscript.touching == 1)
{Run();}
if (diag_Rscript.touching == 1)
{Run();}
if (fallCheck_Lscript.touching == 1)
{Shoot();}
if (fallCheck_Rscript.touching == 1)
{Shoot();}
if (shoot_Lscript.touching == 1)
{Run();}
if (shoot_Rscript.touching == 1)
{Run();}
if (melee_Lscript.touching == 1)
{Run();Shoot();}
if (leftscript.touching == 1)
{Run();}
if (rightscript.touching == 1)
{Run();}
if (shoot_Downscript.touching == 1)
{Run();}
if (melee_Lscript.touching == 2||melee_Rscript.touching == 2)
{Run();}
else
{Run();}
}
}
//What to do while in the Patrol mode
function Patrol(): IEnumerator
{
if (isFalling == false)
{
if (melee_Lscript.touching == 1
//||above_Lscript.touching == 1
||diag_Lscript.touching == 1
//||fallCheck_Lscript.touching == 1
||shoot_Lscript.touching == 1
//||above_Rscript.touching == 1
||diag_Rscript.touching == 1
||fallCheck_Rscript.touching == 1
//||shoot_Rscript.touching == 1
||melee_Rscript.touching == 1)
{state = State.Attack;}
//Turn Around when you touch something
if (melee_Lscript.touching == 2
||melee_Rscript.touching == 2)
{
Turn();
}
else
{Run();}
yield WaitForSeconds (Random.value * 100);
Run();
yield WaitForSeconds (Random.value * 100);
Turn();
Run();
Turn();
}
}
function Start(){
while (true)
{
switch(state)
{
case 0:
yield Patrol();
break;
case 1:
yield Attack();
break;
case 2:
yield Evade();
break;
CancelInvoke();
}
}
}
function OnCollisionEnter(col:Collision)
{
if (col.gameObject.tag == "Water")
{
Score();
}
if (col.gameObject.tag == "Trampoline")
{
rigidbody.velocity.y = 30;
}
isFalling = false;
}
function OnCollisionStay()
{
isFalling = false;
}
function OnCollisionExit()
{
isFalling = true;
}
idk if this has been mentioned or not, or if it’s optimal for your case, but you could use a Finite State Machine (FSM) instead of the Update function. I hear they’re much better.
there’s a link to a tutorial burgzergarcade did during their hack and slash tutorial. while it’s not in the same context game-wise, the basic principles should still be the same.
np. I haven’t personally made a game big enough where they would matter, but according to some of the comments on that video they really helped with framerate.
@Arowx: Yeah, I never really ‘got’ for loops until recently In both of those examples, I was trying to make sure that the nested code in that loop would only execute once per call.
The Enemy sensor code is VERY simple, some thing like : OnTriggerEnter → Find out what’s inside → Store a value for the AI to interpret. Think of them as the AI’s eyes.
In other news, I got the AI running at a very zippy 60-90fps, with occasional drops to 30fps, which is completely palatable. To anyone who’s curious what I did, I noticed that my modelling app assigned 15 separate[/I ]materials (!) to each AI model, which I reduced to 1 shared material. 15 separate materials per AI, so 150 additional separate materials per level, which equates to 150 additional draw calls. OUCH. Thanks for all the help everybody! If you spotted anything else odd/unoptimized/plain wrong, I’d love to know