Hi I Have two Scripts ProjectileMotion and FSMArcherTower. I will brief you on how it works then ill tell you the problem. I Have attached both scripts to this tower and it shoots a projectile. Right now I have managed it to work almost the way i want but the code is a bit confusing. I have created a FSM in FSMArcherTower where In my update method I have Switch cases for different states of the tower. However I cannot call InvokeRepeating or StartCoroutine in update as it is called every frame. Thus I have called StartCoroutine In Start and created a while loop in the Co routine. The PROBLEM is that the code in public IEnumerator States() is not clean as attackSpeed variable is actually the input for yield waitForSeconds which if the value of attackSpeed is less causes to be actually More attack Speed. I just want a better way to use coroutines and Invoke and update in this situation. Any Insight will be helpfull. Thank you
public class FSMArcherTower : MonoBehaviour {
public enum ArcherTowerState
{
Idle,
Attacking,
Destroyed
}
public ArcherTowerState currentArcherTowerState;
// Less is more speed
// so 0.1f is faster attackSpeed than 0.9f
public float attackSpeed = 0.5f;
private bool canShoot;
void awake()
{
}
// Use this for initialization
void Start ()
{
currentArcherTowerState = ArcherTowerState.Idle;
StartCoroutine (States());
}
// Update is called once per frame
void Update ()
{
switch (currentArcherTowerState)
{
case ArcherTowerState.Attacking:
// logic for attacking
canShoot=true;
Debug.Log("Attacking");
break;
case ArcherTowerState.Idle:
// what to do when idle
canShoot = false;
Debug.Log("Idle");
break;
case ArcherTowerState.Destroyed:
// what happens when destroyed
Debug.Log("Destroyed");
break;
}
}
public IEnumerator States()
{
while (true) {
Debug.Log("True");
if (canShoot)
{
Invoke("callAttack",0.0001f);
}
if (!canShoot)
{
// what to do when idle
CancelInvoke("callAttack");
}
// }
yield return new WaitForSeconds (attackSpeed);
}
}
public void callAttack()
{
GetComponent().attack();
}
}
ProjectileMotion only create the projectile and its motion towards the target
public class ProjectileMotion : MonoBehaviour {
public GameObject Target;
public float firingAngle = 45.0f;
public float gravity = 9.8f;
public GameObject Projectile;
private Transform myTransform;
void Awake()
{
myTransform = transform;
Target = (GameObject)Instantiate (Target, transform.position + new Vector3(10,-3,0), Quaternion.identity);
Target.name = "Capsule";
}
void Start()
{
}
public void attack()
{
StartCoroutine(SimulateProjectile());
}
public IEnumerator SimulateProjectile()
{
// Instantiate projectile
GameObject projectile = (GameObject)Instantiate (Projectile,myTransform.position, Quaternion.identity);
Debug.Log ("Projectile initiated");
// Calculate distance to target
float target_Distance = Vector3.Distance(projectile.transform.position, Target.transform.position);
// Calculate the velocity needed to throw the object to the target at specified angle.
float projectile_Velocity = target_Distance / (Mathf.Sin(2 * firingAngle * Mathf.Deg2Rad) / gravity);
// Extract the X Y componenent of the velocity
float Vx = Mathf.Sqrt(projectile_Velocity) * Mathf.Cos(firingAngle * Mathf.Deg2Rad);
float Vy = Mathf.Sqrt(projectile_Velocity) * Mathf.Sin(firingAngle * Mathf.Deg2Rad);
// Calculate flight time.
float flightDuration = target_Distance / Vx;
// Rotate projectile to face the target.
projectile.transform.rotation = Quaternion.LookRotation(Target.transform.position - projectile.transform.position);
float elapse_time = 0;
while (elapse_time < flightDuration)
{
projectile.transform.Translate(0, (Vy - (gravity * elapse_time)) * Time.deltaTime, Vx * Time.deltaTime);
elapse_time += Time.deltaTime;
yield return null;
}
StartCoroutine (DestroyAfterWait (projectile));
}
public IEnumerator DestroyAfterWait(GameObject projectile)
{
// destroy projectile after 0.5 sec
yield return new WaitForSeconds (0.5f);
if (projectile != null)
{
Destroy (projectile);
}
}
void Update ()
{
}
}
↧