Multiple Else Statments?

Hey, so I have a situation in which a person can open something with openable parts inside. Say for example an dishwasher with the dishracks inside. When a person opens the dishwasher door they can open up the racks at will. This all works fine in script, but Im having trouble figuring out how to close the dishwasher, as if the racks are open they just stay open even if the door is closed (and therefore poke through the door). This is the script I am attempting at, and its probably more complicated than need be;

#pragma strict
private var open : boolean;
var playOpen : AnimationClip;
var openSound : AudioClip;
var playClose : AnimationClip;
var closeSound : AudioClip;
var part1 : GameObject;
var part2 : GameObject;

function Start(){
 open = false;
}

function OnMouseDown () {
    if (open == false) {
        animation.Play(playOpen.name);
        audio.PlayOneShot(openSound);
        open = true;
    } else {
       if (part1.GetComponent(Open_ClosePart1).open1 == true){
        animation.Play(playClose.name);
        audio.PlayOneShot(closeSound);
        part1.GetComponent(Open_ClosePart1).open1 = false;
        open = false;
        
    }
	else{
	 if (part2.GetComponent(Open_ClosePart2).open2 == true){
        animation.Play(playClose.name);
        audio.PlayOneShot(closeSound);
        part2.GetComponent(Open_ClosePart2).open2 = false;
        open = false;
       }
       else{
         if (part1.GetComponent(Open_ClosePart1).open1 == true){
          if (part2.GetComponent(Open_ClosePart2).open2 == true){
        animation.Play(playClose.name);
        audio.PlayOneShot(closeSound);
        part1.GetComponent(Open_ClosePart1).open1 = false;
        part2.GetComponent(Open_ClosePart2).open2 = false;
        open = false;
     }
  }   
}
}
}
}

This script is attached to the main door and is referencing two other scripts that look like this;

#pragma strict
var open1 : boolean = false;
var playOpen : AnimationClip;
var openSound : AudioClip;
var playClose : AnimationClip;
var closeSound : AudioClip;

function OnMouseDown () {
    open1 = !open1;
    if (open1) {
        animation.Play(playOpen.name);
        audio.PlayOneShot(openSound);
    } else {
        animation.Play(playClose.name);
        audio.PlayOneShot(closeSound);
    }
}

Except the 2nd version of this script has ‘open2’ instead of ‘open1’ everywhere. These scripts are attached one to the first rack and the second to the second rack. When I use the script the Main door opens correctly and the two racks move correctly. However when I press the main door to close, it shuts the second rack, and on a second click shuts the main door without shutting the first rack. Can someone please help me figure out what I’m doing wrong? I have never tried to do multiple ‘else’ statements like this and Im sure that’s why it’s all going wrong. Thanks in advance!

Use this:

if () {
}
else if () {
}
else {
}

Not this:

if () {
}
else {
}
else {
}

There can be only one … else, that is. One else for each if. You can nest more if/else stuff inside an else though.

Ok so I’ve modified your code a bit to make a basic state machine and remove some of those complexities. You now have an array of parts (which you can drop your two parts into). And only a single script to attach to both parts.

Just a thought:

If you start writing routines with lots of elses in them think:

  • Can I write a list of states down.

  • Can I write a function to work out step by step what state I’m in - OR can I dictate each state.

Write your code as separate functions and keep the control logic simple. That way you’ve just got a couple of routines to debug, no syntax and indentation getting in the way.

Note

Also I should point out that while I used some fancy LINQ in here:

parts.Any(function(part){return part.open;})

That could have been achieved that with a normal for next loop - but the LINQ is just elegant and in a single line, it takes getting your head around but when you do it really simplifies the logic because the code is neater and expressive. I want to know is Any part open etc. There’s lot’s more to LINQ, but that’s a nice first usage of it.

Using this code

You will need to attach the script to the parts and drag the game objects onto the members of the array.

Here is the main script:

OpenClose_Main.js


#pragma strict

import System.Collections.Generic;
import System.Linq;

var open : boolean;
var playOpen : AnimationClip;
var openSound : AudioClip;
var playClose : AnimationClip;
var closeSound : AudioClip;
var parts : Open_ClosePart[];

//Status for the dishwasher
enum status {
	closed,
	open,
	drawsOpen,
	animating
}

//Work out the current status
function GetStatus() : status {
	//If anything is animating then return status.animating
	if(animation.isPlaying || 
		parts.Any(function(part) { return part.animation.isPlaying;}))
	{
		return status.animating;
	}
	//If any draws are open then return drawsOpen
	if(parts.Any(function(part) {return part.open;})) {
		return status.drawsOpen;
	}
	//Else return the state of the dishwasher
	return open ? status.open : status.closed;
}

function Start(){
 open = false;
 for(var part in parts) {
 	part.door = this;
 }
}

//Coroutine to close everything
function Close() : IEnumerator {
	for(var part in parts) {
		//Tell the part to close, it just
		//returns immediately if it is
		//otherwise animates
		part.Close();
		yield WaitForEndOfFrame();
		//Wait for it to be closed and finished
		while(part.open || part.animation.isPlaying)
		   yield WaitForEndOfFrame();
	}
	//Close the dishwasher
	animation.Play(playClose.name);
	yield WaitForEndOfFrame();
	//Wait for it to be closed		
	while(animation.isPlaying) 
		yield WaitForEndOfFrame();
	//It's closed now
	open = false;
}

function OnMouseDown () {
	
	//Check the status and react accordingly
	//NOTE: we don't do anything if it is 
	//animating
	switch(GetStatus())
	{
		case status.closed:
			animation.Play(playOpen.name);
			audio.PlayOneShot(openSound);
			open = true;
			break;
		case status.open:
		case status.drawsOpen:
			StartCoroutine(Close());
			break;
			
	}
    
}

And this is the parts script which must be called Open_ClosePart.js (to match the array definition above)

OpenClose_Part.js


#pragma strict


var open : boolean = false;
var playOpen : AnimationClip;
var openSound : AudioClip;
var playClose : AnimationClip;
var closeSound : AudioClip;
var door : Open_CloseMain;

function OnMouseDown()
	{
	    if(!door.open)
	        return;
	        
		if(open)
		    Close();
		else
		    Open();
	}

function Close() {
	if(!open)
	   return;
	animation.Play(playClose.name);
	audio.PlayOneShot(closeSound);
	open = false;
}

function Open() {
	if(open)
		return;
	animation.Play(playOpen.name);
	audio.PlayOneShot(openSound);
	open = true;
}

Setting the parts:

[1028-Screen+Shot+2012-05-28+at+16.27.32.png|1028]