- Home /
Array? usage for multiple transforms
I am rather new to coding and I am having troubles with writing a script for being able to move multiple transforms in a sequence. In this case, the script is being used to control the opening and closing of drawers whenever the player interacts with them.
#pragma strict
var smooth : float = 1;
var openAmount : float = .5;
var drawerCount : int = 1;
var drawer1 : GameObject;
var drawer2 : GameObject;
var drawer3 : GameObject;
private var defaultPos1 : Vector3;
private var defaultPos2 : Vector3;
private var defaultPos3 : Vector3;
private var openPos1 : Vector3;
private var openPos2 : Vector3;
private var openPos3 : Vector3;
var drawerState : int = 0;
function Start(){
defaultPos1 = drawer1.transform.position;
defaultPos2 = drawer2.transform.position;
defaultPos3 = drawer3.transform.position;
openPos1 = new Vector3 (defaultPos1.x - openAmount, defaultPos1.y, defaultPos1.z);
openPos2 = new Vector3 (defaultPos2.x - openAmount, defaultPos2.y, defaultPos2.z);
openPos3 = new Vector3 (defaultPos3.x - openAmount, defaultPos3.y, defaultPos3.z);
}
function use() {
drawerState = ++drawerState;
if (drawerState > drawerCount){
drawerState = 0;
}
}
function Update() {
if (drawerState == 0) {
drawer1.transform.position = Vector3.Lerp(drawer1.transform.position, defaultPos1, Time.deltaTime * smooth);
drawer2.transform.position = Vector3.Lerp(drawer2.transform.position, defaultPos2, Time.deltaTime * smooth);
drawer3.transform.position = Vector3.Lerp(drawer3.transform.position, defaultPos3, Time.deltaTime * smooth);
}
if (drawerState == 1) {
drawer1.transform.position = Vector3.Lerp(drawer1.transform.position, openPos1, Time.deltaTime * smooth);
drawer2.transform.position = Vector3.Lerp(drawer2.transform.position, defaultPos2, Time.deltaTime * smooth);
drawer3.transform.position = Vector3.Lerp(drawer3.transform.position, defaultPos3, Time.deltaTime * smooth);
}
if (drawerState == 2) {
drawer1.transform.position = Vector3.Lerp(drawer1.transform.position, defaultPos1, Time.deltaTime * smooth);
drawer2.transform.position = Vector3.Lerp(drawer2.transform.position, openPos2, Time.deltaTime * smooth);
drawer3.transform.position = Vector3.Lerp(drawer3.transform.position, defaultPos3, Time.deltaTime * smooth);
}
if (drawerState == 3) {
drawer2.transform.position = Vector3.Lerp(drawer2.transform.position, defaultPos2, Time.deltaTime * smooth);
drawer3.transform.position = Vector3.Lerp(drawer3.transform.position, openPos3, Time.deltaTime * smooth);
drawer1.transform.position = Vector3.Lerp(drawer1.transform.position, defaultPos1, Time.deltaTime * smooth);
}
}
When using this on an object that has 3 openable drawers, it works flawlessly. However, if I use it on an object that only has one drawer, it moves to an entirely different location than intended, which I have found to be because there are not two other game objects that the script that can be controlled by it. Null reference and whatnot.
So how would I write this so that it can be more versatile? I can not find a way to simplify this with my current knowledge. Thanks for any help or advice.
Why not animate it using the curve editor or in an animation package like maya/3dsmax/softimage/ c4d/modo etc ?
Answer by robhuhn · Aug 09, 2013 at 12:09 PM
I would recommend using a separate class "Drawer" with methods like "Open()" and "Close()". Store the defaultPosition in Start() just like you did but move it to the Drawer class. So each Drawer will store it's own defaultPosition.
There are several ways now to control the Drawer objects. One way could be to create a DrawerController or DrawerManager similar to your script above. The controller would have an array as field variable where all Drawers are stored (may be using FindObjectsOfType)
To Open the current drawer and Close the previous you could write something like:
drawers[drawerState].Close(); //the previous drawer
drawerState = 1;
drawers[drawerState].Open(); //the current drawer
HOTween is a great tweening engine which you can use to move your drawer instead of using Lerp in the Update method (code in c#):
TweenParms parms = new TweenParms();
parms.Prop("position", openPos); //use openPos in method Open() and defaultPos in Close()
parms.Ease(EaseType.EaseOutCubic);
HOTween.To(transform, time, parms);
Answer by Jamora · Aug 09, 2013 at 12:51 PM
Looking at this from the Object Oriented Programming point of view, one indicator of a missing abstraction is that there is a lot of copy-paste code (your if blocks).
If you want to follow the OOP paradigm, you should create a class for each object you have that has different functionality, I'm thinking Drawer, Furniture, *IDrawerFurniture*, ChestOfDrawers (extends Furniture implements IDrawerFurniture)
.
The Drawer class contains all the data a drawer would: openposition, closeposition and whatnot. It would also contain methods to open and close the drawer.
The Furniture
abstract class contains all shared functionality of furniture and is extended by all concrete furniture. The Furniture class is used to store all the common functionality all concerete furniture share, with or without drawers.
The IDrawerFurniture interface defines the behaviour of furniture with drawers, that is, contains method declarations for opening and closing them and whatever else you can do with drawers.
The ChestOfDrawers class then is just a collection of drawers plus whatever specialized functionality a ChestOfDrawers has compared to other furniture. This class is responsible for opening and closing the correct drawers.
Having said all this, if you just want to get something working in a jiffy, you'll want GameObjects (Drawers) that have a script that contains their own positions; default and open. Then something like this, I haven't even tested if it compiles, so consider it pseudocode to demonstrate the (logic) flow of the program:
#pragma strict
var drawerList : List.<GameObject>;
var drawerState : int = 0;
function Start(){
//Get all the drawers that are this gameobject's children
for (var child : Transform in transform) {
if(child.gameObject.GetComponent<Drawer>() != null)
drawerList.Add(child.gameObject);
}
/** **/
/*If order matters, the list should be sorted here, possibly according to an ID given to each drawer.*/
/** **/
}
function use() {
SetNextDrawerState();
}
function Update() {
if (drawerState == 0) {
CloseAllDrawers();
}else{
SetAppropriateDrawerPositions();
}
}
private function SetNextDrawerState(){
drawerState++;
if(drawerState>drawerList.Count)
drawerState = 0;
}
private function GetPreviousDrawerState(){
var previousState = drawerState-1;
if(previousState <= 0)
drawerState = drawerList.Count;
}
private function CloseAllDrawers(){
for(var drawer : GameObject in drawerList)
drawer.transform.position = Vector3.Lerp(drawer.transform.position, drawer.openPos, Time.deltaTime * smooth);
}
private function SetAppropriateDrawerPositions(){
drawerList[drawerState].transform.position = Vector3.Lerp(drawerList[drawerState].transform.position, drawerList[drawerState].openPos, Time.deltaTime * smooth);
drawerList[GetPreviousDrawerState()].transform.position = Vector3.Lerp(drawerList[GetPreviousDrawerState()].transform.position, drawerList[GetPreviousDrawerState()].defaultPos, Time.deltaTime * smooth);
}