Originally posted here but with 3,000 views I don’t have an answer and this is preventing me from proceeding further.
Suppose I have two nearly identical game objects, RedObject and BlueObject, they share the same script because their behaviors are similar and to save on creating scripts and maintanance I’d rather have one script defining an arbitrary number of ‘behaviours’ and then have the object switch between them or be set to a behavour when instantiated.
So two objects, and I have two scripts ObjectStateController:
private float elapsedTime = 0.0f;
//private float elapsedTime2 = 0.0f;
private float timer = 0.25f;
public bool ticker = false;
private bool myTicker = false;
public enum objectStates
{
idle = 0,
move2next, // easier debugging omfg
roll,
firing,
kill,
//patterns
pattern0,
//homingpatterns
homing0,
_stateCount
}
public delegate void FairyStateHandler(FairyStateController.objectStates newState);
public static event FairyStateHandler onStateChange;
// Use this for initialization
void Start()
{
elapsedTime = Time.time + timer;
onStateChange(FairyStateController.objectStates.idle);
myTicker = ticker;
Debug.Log("myTicker: " + ticker);
}
public FairyStateController()
{
}
// Update is called once per frame
void LateUpdate()
{
//Debug.Log("Init Pattern: " + ticker);
if (myTicker)
{
onStateChange(FairyStateController.objectStates.homing0);
Debug.Log("True");
if ( elapsedTime < Time.time)
{
//elapsedTime = Time.time + timer;
}
else
{
//onStateChange(FairyStateController.objectStates.idle);
}
}
else
{
onStateChange(FairyStateController.objectStates.firing);
Debug.Log("False");
if (elapsedTime < Time.time)
{
//elapsedTime = Time.time + timer;
}
else
{
//onStateChange(FairyStateController.objectStates.idle);
}
}
Which is my AI state file, it switches between which ‘pattern’/‘behavour’ the object should be executing, and then signals ObjectStateListener as to what to do, I’m 99% sure the problem is either related to the Controller script for some limitation with Unity but I’ll post anyways:
public float objectTurnSpeed = 1.05f;
public float objectMoveSpeed = 5.05f;
public GameObject dispenserObjectBulletPrefab = null;
public Transform turret = null;
public Transform bulletSpawnTransform;
protected Transform currTarPos;
private Transform nextPoint;
public GameObject target;
private List<GameObject> myList;
private int counter = 0;
public FairyStateController.objectStates currentState = FairyStateController.objectStates.idle;
public TakeDamageFromPlayerBullet bulletColliderListener = null;
private Animator fairyAnimator = null;
// Use this for initialization
void Start()
{
fairyAnimator = GetComponent<Animator>();
}
void initListPoints()
{
var array = GameObject.FindGameObjectsWithTag("NavPoint");
myList = new List<GameObject>();
for (int i = 0; i < array.Length; i++)
{
myList.Add(array[i]);
}
//Debug.Log("ListSize: " + myList.Count);
}
void OnEnable()
{
//target = GameObject.FindGameObjectWithTag("MarisaHitBox");
FairyStateController.onStateChange += onStateChange;
bulletColliderListener.hitByBullet += hitByPlayerBullet;
//currTarPos = target.transform;
//initListPoints();
//Debug.Log(counter);
//nextPoint = myList[counter].transform;
//counter++;
}
void OnDisable()
{
FairyStateController.onStateChange -= onStateChange;
bulletColliderListener.hitByBullet -= hitByPlayerBullet;
}
// onStateChange is called whenever we make a change to the player's state
// from anywhere within the game's code.
public void onStateChange(FairyStateController.objectStates newState)
{
if (newState == currentState)
{
return;
}
// Check if the current state is allowed to transition into this state. If it's not, abort.
if (!checkForValidStatePair(newState))
return;
switch (newState)
{
case FairyStateController.objectStates.idle:
fairyAnimator.SetBool("attacking", false);
//moveThroughPoints();
//onStateChange(FairyStateController.objectStates.move2next);
break;
case FairyStateController.objectStates.firing:
fairyAnimator.SetBool("attacking", true);
for (int i = 0; i < 24; i++)
{
//fireBullet((i * 15.0f));
}
break;
case FairyStateController.objectStates.pattern0:
fairyAnimator.SetBool("attacking", true);
//pattern0();
break;
case FairyStateController.objectStates.homing0:
fairyAnimator.SetBool("attacking", true);
//Debug.Log("Debug");
//homingBullet();
break;
}
// And finally, assign the new state to the player object
currentState = newState;
}
bool checkForValidStatePair(FairyStateController.objectStates newState)
{
bool returnVal = false;
// Compare the current against the new desired state.
switch (currentState)
{
case FairyStateController.objectStates.homing0:
// Any state can take over from idle.
returnVal = true;
break;
case FairyStateController.objectStates.idle:
// Any state can take over from idle.
returnVal = true;
break;
case FairyStateController.objectStates.pattern0:
returnVal = true;
break;
case FairyStateController.objectStates.move2next:
returnVal = true;
break;
case FairyStateController.objectStates.kill:
// The only state that can take over from kill is resurrect
case FairyStateController.objectStates.firing:
returnVal = true;
break;
}
return returnVal;
}
void onStateCycle()
{
switch (currentState)
{
case FairyStateController.objectStates.move2next:
//moveToNextNavPoint2(transform.position, nextPoint.position);
break;
case FairyStateController.objectStates.idle:
{
//moveThroughPoints();
//onStateChange(FairyStateController.objectStates.move2next);
break;
}
case FairyStateController.objectStates.pattern0:
transform.Translate(Vector3.up * objectMoveSpeed * Time.deltaTime);
break;
case FairyStateController.objectStates.homing0:
transform.Translate(Vector3.up * objectMoveSpeed * Time.deltaTime);
break;
case FairyStateController.objectStates.kill:
//onStateChange(FairyStateController.playerStates.resurrect);
break;
case FairyStateController.objectStates.firing:
transform.Translate(-Vector3.up * objectMoveSpeed * Time.deltaTime);
break;
default:
break;
}
}
void homingBullet()
{
//Debug.Log("Am I here");
//Debug.Log("Bullet firing...");
GameObject newBullet = (GameObject)Instantiate(dispenserObjectBulletPrefab);
//bulletSpawnTransform.transform.rotation = Quaternion.LookRotation(currTarPos.position - newBullet.transform.position, Vector3.up);
bulletSpawnTransform.transform.LookAt(currTarPos);
//turret.transform.LookAt(currTarPos);
newBullet.transform.position = bulletSpawnTransform.position;
newBullet.transform.rotation = bulletSpawnTransform.rotation;
//newBullet.transform.rotation = Quaternion.Slerp(newBullet.transform.rotation, Quaternion.LookRotation(currTarPos.position - newBullet.transform.position), 100.0f*Time.deltaTime);
newBullet.transform.rotation = Quaternion.LookRotation(currTarPos.position - newBullet.transform.position);
BulletController bullCon = newBullet.GetComponent<BulletController>();
bullCon.enemyObject = GameObject.FindGameObjectWithTag("CrystalOne");
bullCon.launchBullet();
onStateChange(currentState);
}
void fireBullet()
{
GameObject newBullet = (GameObject)Instantiate(dispenserObjectBulletPrefab);
newBullet.transform.position = bulletSpawnTransform.position;
newBullet.transform.rotation = bulletSpawnTransform.rotation;
BulletController bullCon = newBullet.GetComponent<BulletController>();
bullCon.enemyObject = GameObject.FindGameObjectWithTag("TestDispenser");
bullCon.launchBullet();
onStateChange(currentState);
}
void fireBullet(float offsetRot)
{
GameObject newBullet = (GameObject)Instantiate(dispenserObjectBulletPrefab);
newBullet.transform.position = bulletSpawnTransform.position;
newBullet.transform.rotation = bulletSpawnTransform.rotation;
Vector3 newRotation = newBullet.transform.rotation.eulerAngles;
newRotation.y += offsetRot;
newBullet.transform.rotation = Quaternion.Euler(newRotation);
BulletController bullCon = newBullet.GetComponent<BulletController>();
bullCon.enemyObject = GameObject.FindGameObjectWithTag("TestDispenser");
bullCon.launchBullet();
onStateChange(currentState);
}
void pattern0()
{
Transform myRot = bulletSpawnTransform;
myRot.LookAt(currTarPos);
Vector3 newRotation0 = myRot.transform.rotation.eulerAngles;
newRotation0.y -= 45;
myRot.rotation = Quaternion.Euler(newRotation0);
for (int i = 0; i < 18; i++)
{
GameObject newBullet = (GameObject)Instantiate(dispenserObjectBulletPrefab);
newBullet.transform.position = myRot.position;
newBullet.transform.rotation = myRot.rotation;
Vector3 newRotation = newBullet.transform.rotation.eulerAngles;
newRotation.y += (5 * i);
newBullet.transform.rotation = Quaternion.Euler(newRotation);
BulletController bullCon = newBullet.GetComponent<BulletController>();
bullCon.enemyObject = GameObject.FindGameObjectWithTag("CrystalOne");
bullCon.launchBullet();
onStateChange(currentState);
}
}
void moveToNextNavPoint(Vector3 start, Vector3 end)
{
/*
* Lerp Dashing Left/Right
*/
//Transform myPosition = transform;
//Vector3 startPos = myPosition.position;
//transform.Translate(new Vector3((playerDashSpeed * 1.0f) * Time.deltaTime, 0.0f, 0.0f));
//myPosition.Translate(new Vector3(0.0f, 0.0f, objectMoveSpeed));
//Vector3 endPos = myPosition.position;
float t = 0.0f;
float time = 1.0f;
while (t < 0.00001f)
{
t += Time.deltaTime / time;
transform.position = Vector3.Lerp(start, end, t);
}
}
void moveToNextNavPoint2(Vector3 start, Vector3 end)
{
if (myList.Count < 7)
{
//Debug.Log(myList.Count);
}
transform.LookAt(end);
if (Vector3.Distance(transform.position, end) >= 0.5f)
{
transform.position += transform.forward * objectMoveSpeed * Time.deltaTime;
if (Vector3.Distance(transform.position, end) <= 0.5)
{
onStateChange(FairyStateController.objectStates.idle);
}
}
}
void moveThroughPoints()
{
//Debug.Break();
if (counter < myList.Count)
{
//Debug.Log("Movin' to next point: "+counter);
nextPoint = myList[counter].transform;
counter++;
}
else
{
counter = 0;
nextPoint = myList[counter].transform;
counter++;
}
}
// Update is called once per frame
void Update()
{
currTarPos = target.transform;
onStateCycle();
}
public void hitByPlayerBullet()
{
Destroy(gameObject, 0.1f);
}
Pretty standard.
The problem is that, if I set one object to be true in the inspector (trigger is checked) and the other is false, they both insist on doing the same action, whichever is the “last” is becomes the action both objects are to execute, the debug output will alternate true/false but both execute true or false depending in which order they are set to true/false.
Even if I use random numbers set to private, they both do the same action.
So how do I get it so that if I have two objects sharing the same two scripts they will execute two different actions at the same time?