C# Sfml i dont see the mistake? - c#

I dont know why but my jump method does not work. My character can only jump on one single object. The other obstacle haven't any influence on the player. I really don't see my mistake
foreach (RectangleShape obstacles in MoveAtObjectList)
{
MainPlayer.Move(deltaTime, obstacles);
}
foreach (RectangleShape obstacles in JumpAtObjectList)
{
MainPlayer.Jump(deltaTime, obstacles);
break;
}
Draw();
Window.Display();
}
}
}
}
This was part of my main Class, where i call the jump method within a foreach loop. Here in my Payer class I tried to write the jump function.
using SFML.Graphics;
using SFML.System;
using SFML.Window;
namespace Pong3final
{
class Player : RectangleShape
{
float CollisionDistance = 0.5f;
float PlayerSpeed = 50;
float JumpSpeed = 100;
float FallSpeed = 100;
float JumpTimer;
bool JumpBool = false;
bool Fall = true;
public void Jump(float deltaTime, RectangleShape collisionObject)
{
if (Keyboard.IsKeyPressed(Keyboard.Key.Space) && !Fall && CheckCollision(this, collisionObject))
{
JumpBool = true;
}
//Player is jumping
if (JumpBool)
{
JumpTimer += deltaTime;
this.Position -= new Vector2f(0, JumpSpeed) * deltaTime;
if (JumpTimer > 0.5f)
{
JumpBool = false;
Fall = true;
JumpTimer = 0;
}
}
//Player is falling when he doesnt touch anything and he isnt jumping
else if (!CheckCollision(this, collisionObject))
{
Fall = true;
}
//Player is falling
if (!JumpBool && !CheckCollision(this, collisionObject) && Fall)
{
this.Position += new Vector2f(0, FallSpeed) * deltaTime;
if (CheckCollision(this, collisionObject)) //Player stops falling because of a collision with an object
{
Fall = false;
}
}
}
public void Move(float deltaTime, RectangleShape collisionObject)
{
{
Vector2f MovePlayerPosition = Position;
if ((Keyboard.IsKeyPressed(Keyboard.Key.Left) || Keyboard.IsKeyPressed(Keyboard.Key.A)))
{
MovePlayerPosition -= new Vector2f(PlayerSpeed, 0) * deltaTime;
FloatRect collisionOverlap;
if (CheckCollision(this, collisionObject, out collisionOverlap))
{
MovePlayerPosition = MovePlayerPosition + new Vector2f(collisionOverlap.Width + CollisionDistance, 0);
}
}
if (Keyboard.IsKeyPressed(Keyboard.Key.Right) || Keyboard.IsKeyPressed(Keyboard.Key.D))
{
MovePlayerPosition += new Vector2f(PlayerSpeed, 0) * deltaTime;
FloatRect collisionOverlap;
if (CheckCollision(this, collisionObject, out collisionOverlap))
{
MovePlayerPosition = MovePlayerPosition - new Vector2f(collisionOverlap.Width + CollisionDistance, 0);
}
}
Position = MovePlayerPosition;
}
}
public static bool CheckCollision(RectangleShape obj1, RectangleShape obj2, out FloatRect overlap)
{
FloatRect obj1Collider = obj1.GetGlobalBounds();
FloatRect obj2Collider = obj2.GetGlobalBounds();
//Nur die rechte, linke und obere Seite kollidiert
if (obj1Collider.Intersects(obj2Collider, out overlap))
{
return true;
}
overlap = new FloatRect();
return false;
}
public static bool CheckCollision(RectangleShape obj1, RectangleShape obj2)
{
FloatRect obj1Collider = obj1.GetGlobalBounds();
FloatRect obj2Collider = obj2.GetGlobalBounds();
return obj1Collider.Intersects(obj2Collider);
}
}
}

It looks like you are breaking out of your loop after the first iteration, which is resulting in only that first iteration being performed:
foreach (RectangleShape obstacles in JumpAtObjectList)
{
MainPlayer.Jump(deltaTime, obstacles);
break;
}
Remove the break statement from your loop:
foreach (RectangleShape obstacles in JumpAtObjectList)
{
MainPlayer.Jump(deltaTime, obstacles);
}

Related

How and where in the code should I use the loop bool flag to decide if to loop or to make once movement between the waypoints?

The goal is to be able to decide if to loop or to move only once between the waypoints.
I added the loop bool flag for that.
Added the most details I can.
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
using UnityEngine.AI;
public class Move : MonoBehaviour
{
public Transform[] targets;
public LineRenderer lineRenderer;
public float speed;
public bool go = false;
public bool countOrigPosAsWaypoint = true;
public bool startFromFirstPositionOnStart = false;
public bool goForward = true;
public bool loop = true;
private List<Vector3> pos = new List<Vector3>();
private List<Vector3> positions = new List<Vector3>();
private int index = 0;
private List<GameObject> objectsToMoveCopy = new List<GameObject>();
// Start is called before the first frame update
void Start()
{
if (lineRenderer != null)
{
pos = GetLinePointsInWorldSpace();
}
else
{
if (countOrigPosAsWaypoint == true)
{
pos.Add(transform.position);
}
for (int i = 0; i < targets.Length; i++)
{
pos.Add(targets[i].position);
}
}
if (startFromFirstPositionOnStart == true)
{
transform.position = pos[index];
}
if (pos.Count <= 1)
{
Debug.LogWarning("Targets list count must be more then 1");
}
}
List<Vector3> GetLinePointsInWorldSpace()
{
positions = new Vector3[lineRenderer.positionCount].ToList();
//Get the positions which are shown in the inspector
lineRenderer.GetPositions(positions.ToArray());
//the points returned are in world space
return positions;
}
// Update is called once per frame
void Update()
{
if (go == true && pos.Count > 1)
{
Moving();
}
}
void Moving()
{
Vector3 newPos = transform.position;
float distanceToTravel = speed * Time.deltaTime;
bool stillTraveling = true;
while (stillTraveling)
{
Vector3 oldPos = newPos;
newPos = Vector3.MoveTowards(oldPos, pos[index], distanceToTravel);
distanceToTravel -= Vector3.Distance(newPos, oldPos);
if (newPos == pos[index]) // Vector3 comparison is approximate so this is ok
{
// when you hit a waypoint:
if (goForward)
{
bool atLastOne = index >= pos.Count - 1;
if (!atLastOne) index++;
else { index--; goForward = false; }
}
else
{ // going backwards:
bool atFirstOne = index <= 0;
if (!atFirstOne) index--;
else { index++; goForward = true; }
}
}
else
{
stillTraveling = false;
}
}
transform.position = newPos;
}
}
If true make a loop between the waypoints either backward or forward and if false just move forward or backward once and stop the last/first waypoint.
I'ld say e.g. at
if (!atLastOne)
{
index++;
}
else if(!loop)
{
stillTraveling = false;
}
else
{
index--;
goForward = false;
}
and accordingly
if (!atFirstOne)
{
index--;
}
else if(!loop)
{
stillTraveling = false;
}
else
{
index++;
goForward = true;
}
And probably remove the current
else
{
stillTraveling = false;
}
as it will be the case most of the time between the points.
In general though: Currently this will all happen in one single frame without any animation... This should probably rather happen in a Coroutine or only do one step at a time .. not in a while loop at all.

How can I move each object in his turn using time to start each object to move?

The goal is to use a time variable for example if the variable int value is 5 then each 5 seconds another object will start moving on the positions.
Now with the loop inside the Move method :
for (int i = 0; i < objectsToMove.Count; i++)
All the objects are moving at the same time but I want to make some kind of queue logic so each N seconds another object will start moving on the positions.
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
public class MoveOnCurvedLines : MonoBehaviour
{
public LineRenderer lineRenderer;
public List<GameObject> objectsToMove = new List<GameObject>();
public float speed;
public bool go = false;
public bool moveToFirstPositionOnStart = false;
private Vector3[] positions;
private Vector3[] pos;
private int index = 0;
private bool goForward = true;
// Start is called before the first frame update
void Start()
{
objectsToMove = GameObject.FindGameObjectsWithTag("New Prefab").ToList();
pos = GetLinePointsInWorldSpace();
if (moveToFirstPositionOnStart == true)
{
objectsToMove[0].transform.position = pos[index];
}
}
Vector3[] GetLinePointsInWorldSpace()
{
positions = new Vector3[lineRenderer.positionCount];
//Get the positions which are shown in the inspector
lineRenderer.GetPositions(positions);
//the points returned are in world space
return positions;
}
// Update is called once per frame
void Update()
{
if (go == true)
{
Move();
}
}
void Move()
{
for (int i = 0; i < objectsToMove.Count; i++)
{
Vector3 newPos = objectsToMove[i].transform.position;
float distanceToTravel = speed * Time.deltaTime;
bool stillTraveling = true;
while (stillTraveling)
{
Vector3 oldPos = newPos;
newPos = Vector3.MoveTowards(oldPos, pos[index], distanceToTravel);
distanceToTravel -= Vector3.Distance(newPos, oldPos);
if (newPos == pos[index]) // Vector3 comparison is approximate so this is ok
{
// when you hit a waypoint:
if (goForward)
{
bool atLastOne = index >= pos.Length - 1;
if (!atLastOne) index++;
else { index--; goForward = false; }
}
else
{ // going backwards:
bool atFirstOne = index <= 0;
if (!atFirstOne) index--;
else { index++; goForward = true; }
}
}
else
{
stillTraveling = false;
}
}
objectsToMove[i].transform.position = newPos;
}
}
}
This is what I tried with InvokeRepeating :
Starting InvokeRepeating in the Start() and cancelled the Move() calling in the Update.
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
public class MoveOnCurvedLines : MonoBehaviour
{
public LineRenderer lineRenderer;
public List<GameObject> objectsToMove = new List<GameObject>();
public float speed;
public bool go = false;
public bool moveToFirstPositionOnStart = false;
private Vector3[] positions;
private Vector3[] pos;
private int index = 0;
private bool goForward = true;
// Start is called before the first frame update
void Start()
{
objectsToMove = GameObject.FindGameObjectsWithTag("New Prefab").ToList();
pos = GetLinePointsInWorldSpace();
if (moveToFirstPositionOnStart == true)
{
objectsToMove[0].transform.position = pos[index];
}
InvokeRepeating("Move", 3f, 0.1f);
}
Vector3[] GetLinePointsInWorldSpace()
{
positions = new Vector3[lineRenderer.positionCount];
//Get the positions which are shown in the inspector
lineRenderer.GetPositions(positions);
//the points returned are in world space
return positions;
}
// Update is called once per frame
void Update()
{
if (go == true)
{
//Move();
}
}
void Move()
{
for (int i = 0; i < objectsToMove.Count; i++)
{
Vector3 newPos = objectsToMove[i].transform.position;
float distanceToTravel = speed * Time.deltaTime;
bool stillTraveling = true;
while (stillTraveling)
{
Vector3 oldPos = newPos;
newPos = Vector3.MoveTowards(oldPos, pos[index], distanceToTravel);
distanceToTravel -= Vector3.Distance(newPos, oldPos);
if (newPos == pos[index]) // Vector3 comparison is approximate so this is ok
{
// when you hit a waypoint:
if (goForward)
{
bool atLastOne = index >= pos.Length - 1;
if (!atLastOne) index++;
else { index--; goForward = false; }
}
else
{ // going backwards:
bool atFirstOne = index <= 0;
if (!atFirstOne) index--;
else { index++; goForward = true; }
}
}
else
{
stillTraveling = false;
}
}
objectsToMove[i].transform.position = newPos;
}
}
}
int i = 0;
void StartMove()
{
i = 0;
InvokeRepeating(nameof(Move), 3f, 0.1f);
}
void Move()
{
if( i < objectsToMove.Count)
{
Vector3 newPos = objectsToMove[i].transform.position;
float distanceToTravel = speed * Time.deltaTime;
bool stillTraveling = true;
while (stillTraveling)
{
Vector3 oldPos = newPos;
newPos = Vector3.MoveTowards(oldPos, pos[index], distanceToTravel);
distanceToTravel -= Vector3.Distance(newPos, oldPos);
if (newPos == pos[index]) // Vector3 comparison is approximate so this is ok
{
// when you hit a waypoint:
if (goForward)
{
bool atLastOne = index >= pos.Length - 1;
if (!atLastOne) index++;
else { index--; goForward = false; }
}
else
{ // going backwards:
bool atFirstOne = index <= 0;
if (!atFirstOne) index--;
else { index++; goForward = true; }
}
}
else
{
stillTraveling = false;
}
}
objectsToMove[i].transform.position = newPos;
i++;
}
}
Try this one might help you. Here What I did is to remove the for() loop and instead use an if() condition this way You move function will only execute one time only for one object each time Move() get called by InvokeRepeating(). Nove Call StartMove() where/when you want to start moving the objects.

Prefabs of mobs in the game on Unity do not go on the phone

There was a very interesting error with game characters, on the first level they walk quietly and everything is OK, and on the second they go only in the editor, and after compilation they are no longer there. Ai navigation exists. The character must find ... by the tag maybe he is on stage. What could be the problem? error only at the second level and only after assembly
mob script(They do not go, they do not attack if you approach. So either they don’t see or an error in the script on the phone occurs)
using System.Collections;
using UnityEngine;
using UnityEngine.AI;
public class EmenScript: MonoBehaviour
{
public NavMeshAgent agent;
public Animator animator;
public GameObject zombieObject;
private Transform player;
private float curr_time;
private int xp = 100;
void Start()
{
player = GameObject.FindGameObjectsWithTag("Player")[0].transform;
StartCoroutine(findPath());
StartCoroutine(playerDetected());
curr_time = 0f;
}
public void damage()
{
if(xp == 0)
{
gameObject.transform.Find("Xp/Cube/").gameObject.active = false;
StopAllCoroutines();
agent.enabled = false;
animator.SetTrigger("death");
Destroy(zombieObject, 30f);
} else {
xp = xp > 15 ? xp - 15 : 0;
Transform xpp = gameObject.transform.Find("Xp/Cube/XpLine").transform;
xpp.localScale = new Vector3(xpp.localScale.x, xpp.localScale.y, xp / 100f);
xpp.localPosition = new Vector3(xpp.localPosition.x, xpp.localPosition.y, (0.97f - xpp.localScale.z) / 2);
}
}
public void damageFull()
{
gameObject.transform.Find("Xp/Cube").gameObject.active = false;
StopAllCoroutines();
agent.enabled = false;
animator.SetTrigger("death");
Destroy(zombieObject, 30f);
}
IEnumerator playerDetected()
{
while(true)
{
if(player == null)
{
break;
}
if(player.GetComponent<UserController>().xp <= 0)
{
agent.GetComponent<NavMeshAgent>().isStopped = true;
animator.SetBool("walk", false);
}
if(Vector3.Distance(transform.position, player.position) < 1.2f)
{
animator.SetTrigger("attack");
curr_time -= Time.deltaTime;
if(curr_time <= 0)
{
if(player.GetComponent<UserController>().xp - 25 > 0)
{
player.GetComponent<UserController>().xp -= 25;
}
else
{
player.GetComponent<UserController>().xp = 0;
}
curr_time = 0.5f;
}
}
yield return new WaitForSeconds(.3f);
}
}
IEnumerator findPath()
{
while(true)
{
if(player.GetComponent<UserController>().xp > 0)
{
if(Vector3.Distance(transform.position, player.position) < 40f)
{
animator.SetBool("walk", true);
if(player && agent.isActiveAndEnabled)
{
agent.GetComponent<NavMeshAgent>().isStopped = false;
agent.SetDestination(player.position);
}
} else {
agent.GetComponent<NavMeshAgent>().isStopped = true;
animator.SetBool("walk", false);
}
}
yield return new WaitForSeconds(0.2f);
}
}
}
I think error must be about scene change but I need to see script and lvl's.

Trying to generate prefabs over and over in semi-random positions

So I made this code in an effort to start making a script that generates bush objects in my scene randomly, however when in runs it only spawns the first bush. Here is the code:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class BushSpawner : MonoBehaviour
{
public GameObject bush;
private float x = 0f;
private float y = -.47f;
private float z = 0f;
private int bushCount = 0;
private Vector3 origPos;
private bool xPlus = false;
private bool xMinus = false;
private bool zPlus = false;
private bool zMinus = false;
// Use this for initialization
void Start()
{
SpawnBushes();
}
// Update is called once per frame
void Update()
{
}
void SpawnBushes()
{
Vector3 startPos = new Vector3(x, y, z);
Instantiate(bush, startPos, Quaternion.identity);
bushCount += 1;
while (bushCount < 100)
{
Vector3 checkPos = new Vector3(x, y, z);
Collider[] intersecting = Physics.OverlapSphere(checkPos, 1f);
if (intersecting.Length == 0)
{
//code to run if nothing is intersecting as the length is 0
Instantiate(bush, checkPos, Quaternion.identity);
bushCount += 1;
}
else
{
//code to run if something is intersecting it
RollPos();
}
}
}
void RollPos()
{
if (xPlus == true
&& xMinus == true
&& zPlus == true
&& zMinus == true)
{
int newRoll = Random.Range(1, 4);
if (newRoll == 1)
{
x += 10f;
}
else if (newRoll == 2)
{
x -= 10f;
}
else if (newRoll == 3)
{
z += 10f;
}
else if (newRoll == 4)
{
z -= 10f;
}
xPlus = false;
xMinus = false;
zPlus = false;
zMinus = false;
}
else
{
int roll = Random.Range(1, 4);
if (roll == 1)
{
if (xPlus == false)
{
x += 2f;
xPlus = true;
}
else
{
RollPos();
}
}
if (roll == 2)
{
if (xMinus == false)
{
x -= 2f;
xMinus = true;
}
else
{
RollPos();
}
}
if (roll == 3)
{
if (zPlus == false)
{
z += 2f;
zPlus = true;
}
else
{
RollPos();
}
}
if (roll == 4)
{
if (zMinus == false)
{
z -= 2f;
zMinus = true;
}
else
{
RollPos();
}
}
}
}
}
I tried putting SpawnBushes in Update to run while a bool is true then make it false when SpawnBushes is done, but that creates the first bush, then 99 other bushes in one random position next to it.
If someone can point me in the right direction or tell me I'm completely off-base I would appreciate it immensely!
Ron Beyer pointed out that I didn't have a large enough range in my Random.Range in RollPos(). Thanks again Ron!

Only one gameobject being affected by script

Making a state machine AI "game" I have 3 states Movement, Combat, and View. They all work very well, now I'm making a flee (by the way if anyone has any good links to tutorials or info that they have off hand I would love that) state so I want to make all three previous state in their Idle mode. Which works perfectly when I have 1 AI. As soon as I put the rest (there is 6 total now) it will still only affect 1, but then after some time it will "release" I guess it the best term the script and just goes back to the three states that are supposed to be idle. I think that in my Coin script I am saying find and I think it needs to be something else, I'm just not sure if that's even right but based off of my previous experiences that's usually the case with Unity. I'll post some code, but here's some info that may help your eyes by not having to read through everything:
-I have a bool set up in my AIClass that is false until one of my gameobjects collides with a 'coin', and coin is jsut a gameobject i put in my game to test out my AI behaviors. When that bool is true, in my update in my AIClass(sorry it's at the very bottom of the script you can scroll down, but I had to put other code just in case I was doing something in that to cause my problem.) It sets the state of MovementState to Idle, CombatState to Idle and ViewState to Idle.
-Also, when that bool is false is the only time that the call for the transition of states occur. For example, normally the AI will search around trying to find player, if they find him they go near him, and if they are in a certain distance they fire. Pretty simple. The movement between those states happens at the end of each IENumerator when the 'NextMovementState()' or 'NextCombatState()' or 'NextViewState()' are called. So when the bool is true those should never be called, halting the AI from moving to another state other than Idle (to what it's set at when the bool is true in the update).
And this works fine when I have only 1 AI in the game.
CoinScript.cs
using UnityEngine;
using System.Collections;
public class CoinScript : MonoBehaviour {
private AIClass a;
// Use this for initialization
void Start () {
a = GameObject.Find ("Enemy").GetComponent<AIClass>();
}
// Update is called once per frame
void Update () {
}
void OnCollisionEnter(Collision collision)
{
if (collision.collider)
{
if(collision.gameObject.tag == "Enemy" || collision.gameObject.tag == "EnemyProjectile")
{
Physics.IgnoreCollision(rigidbody.collider,collision.collider);
//Debug.Log ("Enemy");
}
if(collision.gameObject.tag == "Player")
{
Debug.Log ("triggered!");
a.fleeBool = true;
Destroy(gameObject);
}
}
}
}
AIClass.cs
using UnityEngine;
using System.Collections;
public class AIClass : MonoBehaviour
{
public NavMeshAgent agent;
//Ammo in gun before reloading is required
public int ammo = 30;
public int maxAmmo = 30;
//Number of bullets a gun fires in sequence on 1 trigger pull
public int chamber = 3;
public int maxChamber = 3;
//Pause between bursts or mouse presses, set to 0 for fully automatic
public double chamberTime = 120;
//How fast a gun fires in RPS
public int fireRate = 7;
public int fireTimer = 0;
//How fast a gun can reload
public int reloadTime = 3;
public int reloadTimer = 0;
//Number of bullets fired per shot
public int bulletsFired = 1;
public GameObject bulletClone;
//Acceptable degrees as to which the AI will begin firing at its target
public int firingAngle = 5;
//Vision cone of degrees to left and right
public int visionAngle = 35;
public int visionDistance = 100;
public int vRotationSpeed = 3;
public int vIdleTimer = 0;
public int vIdleTime = 300;
public int searchTimer = 0;
public int searchTime = 300;
public int mIdleTimer = 0;
public int mIdleTime = 300;
public bool isFocusedOnPlayer = false;
public bool seesPlayer = false;
//
public bool fleeBool;
public bool flee;
public enum MovementState
{
MSearch,
MMoving,
MIdle,
}
public enum CombatState
{
CFiring,
CReloading,
CIdle,
}
public enum ViewState
{
VSearch,
VFocus,
VIdle,
}
public enum FleeState
{
FSearch,
FMoving,
FIdle
}
public CombatState combatState;
public ViewState viewState;
public MovementState movementState;
public FleeState fleeState;
//Search state (knows where player is and will head to the player's location)
IEnumerator MSearchState ()
{
mIdleTimer = 0;
int stuckTimer = 0;
while (movementState == MovementState.MSearch)
{
//I've arrived at my location, if idle too long, then go back to idle state
if(Vector3.Distance(transform.position,agent.destination) < 3)
mIdleTimer++;
//I'm stuck and haven't moved in a while, go back to idle state
if(agent.velocity.magnitude < 1)
stuckTimer++;
if(seesPlayer || mIdleTimer > mIdleTime + 200 || stuckTimer > 300)
{
agent.destination = transform.position;
movementState = MovementState.MIdle;
}
yield return 0;
}
if (!flee) {
NextMovementState();
}
}
//Wander state
IEnumerator MMovingState ()
{
while (movementState == MovementState.MMoving)
{
//Wander code... Create a random angle and convert it to radians
float randomAngle = (float)(3.14/180)*Random.Range(0,360);
//Normalize direction vector, as we will be using it to calculate where we place the circle
Vector3 tempV = agent.velocity;
Vector3.Normalize (tempV);
//Using our relative position, 5 units in front of us. Use the generated angle to find the point on the circle that we want to go to
agent.destination = transform.position + tempV * 3 + new Vector3(Mathf.Cos (randomAngle)*3,0,Mathf.Sin (randomAngle)*3);
//Check to see if we are within the arena bounds, if not, push our projected vector back inside
if(agent.destination.x > 24)
agent.destination = agent.destination + new Vector3(-7,0,0);
if(agent.destination.x < -24)
agent.destination = agent.destination + new Vector3(7,0,0);
if(agent.destination.z > 24)
agent.destination = agent.destination + new Vector3(0,0,-7);
if(agent.destination.z < -24)
agent.destination = agent.destination + new Vector3(0,0,7);
if(seesPlayer)
{
agent.destination = transform.position;
movementState = MovementState.MIdle;
}
yield return 0;
}
if (!flee) {
NextMovementState ();
}
}
//Not moving, if I don't see the player for awhile, then go wander
IEnumerator MIdleState ()
{
mIdleTimer = 0;
while (movementState == MovementState.MIdle)
{
if(seesPlayer)
mIdleTimer = 0;
else
mIdleTimer++;
if(mIdleTimer > mIdleTime + Random.Range (-100,100))
movementState = MovementState.MMoving;
yield return 0;
}
if (!flee) {
NextMovementState ();
}
}
//Visual search state, randomly look around and check to see if we see the player
IEnumerator VSearchState ()
{
Transform target = GameObject.FindWithTag ("Player").transform;
Vector3 targetPosition = target.position;
while (viewState == ViewState.VSearch)
{
searchTimer--;
//Vision Cone calculation
Vector3 targetDir = target.position - transform.position;
Vector3 forward = transform.forward;
float angle = Vector3.Angle(targetDir, forward);
//If player is within vision cone then proceed
if (angle < visionAngle)
{
//Check to see if there are any object between player and myself
RaycastHit hit;
if (Physics.Raycast(transform.position, targetDir, out hit))
{
if(hit.transform == target)
{
seesPlayer = true;
viewState = ViewState.VFocus;
}
}
}
//Look in another direction
if(searchTimer < 0)
{
searchTimer = searchTime + Random.Range (-100,100);
targetPosition = new Vector3(Random.Range (-100,100),transform.position.y,Random.Range (-100,100));
}
transform.rotation = Quaternion.Slerp(transform.rotation,Quaternion.LookRotation(targetPosition - transform.position), vRotationSpeed*Time.deltaTime);
yield return 0;
}
if (!flee) {
NextViewState ();
}
}
//Focus on player
IEnumerator VFocusState ()
{
Transform target = GameObject.FindWithTag ("Player").transform;
while (viewState == ViewState.VFocus)
{
//Vision Cone calculation
Vector3 targetDir = target.position - transform.position;
Vector3 forward = transform.forward;
float angle = Vector3.Angle(targetDir, forward);
if (angle > visionAngle)
viewState = ViewState.VIdle;
else
{
RaycastHit hit;
//Check if there are any objects in the way
if (Physics.Raycast(transform.position, targetDir, out hit))
{
if(hit.transform == target)
{
//Tell other AI where player is
GameObject[] objArray = GameObject.FindGameObjectsWithTag ("Enemy");
AIClass[] enemyArray = new AIClass[objArray.Length];
for(int i = 0; i < enemyArray.Length; i++)
{
enemyArray[i] = (AIClass)objArray[i].GetComponent(typeof(AIClass));
if(i >= enemyArray.Length/2)
enemyArray[i].agent.destination = target.position;
else
enemyArray[i].agent.destination = target.position + target.forward*5;
enemyArray[i].movementState = MovementState.MSearch;
}
seesPlayer = true;
transform.rotation = Quaternion.Slerp(transform.rotation,Quaternion.LookRotation(target.position - transform.position), vRotationSpeed*Time.deltaTime);
//Check to see player is within sights of the gun
if (angle < firingAngle)
isFocusedOnPlayer = true;
else
isFocusedOnPlayer = false;
}
else
{
//I no longer see the player
seesPlayer = false;
viewState = ViewState.VIdle;
isFocusedOnPlayer = false;
}
}
}
yield return 0;
}
if (!flee) {
NextViewState ();
}
}
//Visual idle state, basically the ai is just looking forward
IEnumerator VIdleState ()
{
vIdleTimer = 0;
Transform target = GameObject.FindWithTag ("Player").transform;
while (viewState == ViewState.VIdle)
{
//Vision cone calculation
vIdleTimer++;
Vector3 targetDir = target.position - transform.position;
Vector3 forward = transform.forward;
float angle = Vector3.Angle(targetDir, forward);
//Check to see if there is an object is between the ai and the player
if (angle < visionAngle)
{
RaycastHit hit;
if (Physics.Raycast(transform.position, targetDir, out hit))
{
if(hit.transform == target)
{
seesPlayer = true;
viewState = ViewState.VFocus;
}
}
}
if(vIdleTimer > vIdleTime)
viewState = ViewState.VSearch;
yield return 0;
}
if (!flee) {
NextViewState ();
}
}
//Firing gun state
IEnumerator CFiringState ()
{
while (combatState == CombatState.CFiring)
{
if(!isFocusedOnPlayer)
combatState = CombatState.CIdle;
fireTimer--;
if(ammo > 0)
{
if(chamber > 0)
{
if(fireTimer <= 0)
{
for(int i = 0; i < bulletsFired;i++)
{
GameObject temp = (GameObject) Instantiate (bulletClone,transform.position + transform.forward,transform.rotation);
temp.rigidbody.AddForce(transform.forward*500);
}
fireTimer = 60 / fireRate;
ammo--;
chamber--;
}
}
else
{
chamber = maxChamber;
fireTimer = (int)(60/chamberTime);
}
}
else
{
combatState = CombatState.CReloading;
}
yield return 0;
}
if (!flee) {
NextCombatState ();
}
}
IEnumerator CReloadingState ()
{
reloadTimer = reloadTime * 60;
while (combatState == CombatState.CReloading)
{
reloadTimer--;
if(reloadTimer <= 0)
{
ammo = maxAmmo;
combatState = CombatState.CIdle;
}
yield return 0;
}
if (!flee) {
NextCombatState ();
}
}
IEnumerator CIdleState ()
{
while (combatState == CombatState.CIdle)
{
if(isFocusedOnPlayer)
combatState = CombatState.CFiring;
yield return 0;
}
if (!flee) {
NextCombatState ();
}
}
void Start ()
{
fleeBool = false;
flee = false;
NextCombatState();
NextViewState();
NextMovementState();
}
void NextMovementState()
{
string methodName = movementState.ToString() + "State";
System.Reflection.MethodInfo info = GetType().GetMethod(methodName, System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance);
StartCoroutine((IEnumerator)info.Invoke(this, null));
}
void NextCombatState ()
{
string methodName = combatState.ToString() + "State";
System.Reflection.MethodInfo info = GetType().GetMethod(methodName, System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance);
StartCoroutine((IEnumerator)info.Invoke(this, null));
}
void NextViewState ()
{
string methodName = viewState.ToString() + "State";
System.Reflection.MethodInfo info = GetType().GetMethod(methodName, System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance);
StartCoroutine((IEnumerator)info.Invoke(this, null));
}
void NextFleeState()
{
string methodName = viewState.ToString() + "State";
System.Reflection.MethodInfo info = GetType().GetMethod(methodName, System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance);
StartCoroutine((IEnumerator)info.Invoke(this, null));
}
void Update()
{
Debug.DrawLine(transform.position, transform.position+transform.forward*5, Color.red);
if (fleeBool == true)
{
flee = true;
}
if (flee == true)
{
Debug.Log ("flee is true");
combatState = CombatState.CIdle;
movementState = MovementState.MIdle;
viewState = ViewState.VIdle;
Debug.Log ("End of idles");
}
}
}
You can use GameObject.FindObjectsOfType() or GameObject.FindGameObjectsWithTag
you can do that with store all the AIClass into array and then loop it become specific, so every enemy can affected
AIClass[] AIObject = GameObject.Find("Enemy").GetComponents<AIClass>();
foreach(AIClass a in AIObject ){
//do something with a
}
it should work.

Categories