// Update is called once per frame void FixedUpdate() { // timer to control change in wander and digestion applications if (Time.time > timer) { timer = Time.time + thinktime; float rndm_angle = 360 * Random.value; radrndm_angle = Mathf.Deg2Rad * rndm_angle; fed = Mathf.Min(((fed * digestionrate) + food), appettite); hunger = (1f - (fed / appettite)); food = 0; } //set wander direction float x = (wander_circlediameter / 2) * Mathf.Cos(radrndm_angle) + (transform.position.x + Mathf.Clamp(transform.GetComponent <Rigidbody>().velocity.x, -maxvel, maxvel)); float y = (wander_circlediameter / 2) * Mathf.Sin(radrndm_angle) + (transform.position.y + Mathf.Clamp(transform.GetComponent <Rigidbody>().velocity.y, -maxvel, maxvel)); float z = (wander_circlediameter / 2) * Mathf.Sin(radrndm_angle) + (transform.position.z + Mathf.Clamp(transform.GetComponent <Rigidbody>().velocity.z, -maxvel, maxvel)); wander_dir.Set(x, (y), z); //////// find boids to hunt if (boids == null) { boids = GameObject.FindGameObjectsWithTag("boid"); } for (int boid_index = 0; boid_index < boids.Length; boid_index++) { Vector3 fishpos = boids [boid_index].transform.position; if (closestfish == null) { closestfish = boids [boid_index]; } boid_script r = (boid_script)boids [boid_index].GetComponent(typeof(boid_script)); // if state not dead hunt if (r.returnstate() != 2) { if (Vector3.Distance(transform.position, fishpos) < Vector3.Distance(transform.position, closestfish.transform.position)) { closestfish = boids [boid_index]; } } } // sets fsm to hunt if hungry if (hunger > hungerlimit) { val = 1; } else { val = 0; } ////////////////////////// fsm switch (fsmArray [currentState, val + 1]) { case 0: Debug.Log("Wander"); currentState = 0; break; case 1: Debug.Log("Hunt"); currentState = 1; break; default: break; } // if hunting moves towards fish and attacks if (currentState == 1) { boid_script r = (boid_script)closestfish.GetComponent(typeof(boid_script)); if (r.returnstate() != 2) { Vector3 fishpredpos = closestfish.transform.position + 0.5f * Vector3.Distance(transform.position, closestfish.transform.position) * closestfish.GetComponent <Rigidbody>().velocity; GetComponent <Rigidbody>().AddForce(fishpredpos - transform.position, ForceMode.Force); Debug.DrawLine(transform.position, closestfish.transform.position, Color.magenta); Debug.DrawLine(closestfish.transform.position, fishpredpos, Color.cyan); if (Vector3.Distance(transform.position, closestfish.transform.position) < attackdistance) { food = r.eaten(); } } // otherwise apply wander force } else if (currentState == 0) { GetComponent <Rigidbody>().AddForce(wander_dir - transform.position, ForceMode.Force); } ///////////////////////////////////////////////////////////////////////////////// // if the boids list is null if (sharkboids == null) { // get the other boids sharkboids = GameObject.FindGameObjectsWithTag("shark"); } else { // deal with the boid escape case - must stay within simulation_radius if (Vector3.Distance(simulation_centre, transform.position) > simulation_radius - 2) { if (Vector3.Distance(simulation_centre, transform.position) > simulation_radius) { } float radius_scalar = Vector3.Distance(simulation_centre, transform.position) - (simulation_radius - 2) / 2; GetComponent <Rigidbody>().AddForce(Vector3.ClampMagnitude(simulation_centre - transform.position * radius_scalar, max_wallvel), ForceMode.Force); } } // swarm control for shark boids for (int boid_index = 0; boid_index < sharkboids.Length; boid_index++) { // position of boid at index Vector3 pos = sharkboids [boid_index].transform.position; Quaternion rot = sharkboids [boid_index].transform.rotation; // the distance float dist = Vector3.Distance(transform.position, pos); // if not this boid if (dist > 0f) { // if within separation if (dist <= separation_distance) { // compute the scale of separationt float scale = separation_strength / dist; // add a separation force between this boid and its neighbour GetComponent <Rigidbody>().AddForce(Vector3.Normalize(transform.position - pos) * scale, ForceMode.Force); //Debug.DrawLine (transform.position, transform.position + Vector3.Normalize (transform.position - pos), Color.white); } if (dist < cohesion_distance && dist > separation_distance) // if within cohesive distance but not separation // compute the cohesive position { cohesive_number++; cohesion_pos = cohesion_pos + pos; // alignment - small rotations are applied based on the alignments of the neighbours transform.rotation = Quaternion.RotateTowards(transform.rotation, rot, 1f); } } } if (cohesive_number > 1) { cohesion_pos = cohesion_pos * (1 / cohesive_number); //add cohesive force // compute the scale cohesive_force = (cohesion_strength / Vector3.Distance(cohesion_pos, transform.position)) * (cohesion_pos - transform.position); // apply force GetComponent <Rigidbody>().AddForce(cohesive_force, ForceMode.Force); Debug.DrawLine(transform.position, cohesion_pos, Color.yellow); // zero the cohesion vector cohesion_pos = transform.position; cohesive_number = 1; } // clamp magitude and rotate towards center of velocity transform.GetComponent <Rigidbody>().velocity = Vector3.ClampMagnitude(transform.GetComponent <Rigidbody>().velocity, maxvel); Debug.DrawLine(transform.position, wander_dir, Color.blue); Debug.DrawLine(transform.position, transform.position + transform.GetComponent <Rigidbody>().velocity, Color.red); transform.rotation = Quaternion.RotateTowards(transform.rotation, Quaternion.LookRotation(transform.position + transform.GetComponent <Rigidbody>().velocity), 20f); }
void FixedUpdate() { //fsm to control fish states switch (fsmArray [currentState, val + 1]) { case 0: Debug.Log("Wander"); currentState = 0; GetComponent <Renderer>().material.color = Color.gray; break; case 1: Debug.Log("Flee"); currentState = 1; GetComponent <Renderer>().material.color = Color.white; break; case 2: Debug.Log("Dead"); currentState = 2; GetComponent <Renderer>().material.color = Color.black; break; default: break; } //when fish is dead controls actions if (currentState == 2) { if (Time.time < deadtimer) { return; } else { val = 2; return; } } /////////////////////////////////////////////////////////////////////////// //deals with each shark determining fear and if action should be taken if (sharkboids == null) { sharkboids = GameObject.FindGameObjectsWithTag("shark"); if (fears == null) { fears = new float[sharkboids.Length]; } } else { for (int sharkboid_index = 0; sharkboid_index < sharkboids.Length; sharkboid_index++) { Vector3 sharkpos = sharkboids [sharkboid_index].transform.position; fears [sharkboid_index] = Mathf.Min(comfortdistance / Vector3.Distance(transform.position, sharkpos), 1); if (fears [sharkboid_index] == 1) { val = 0; } else { val = 1; } if (currentState == 1) { //determines predator predicated pos and adds force away from position Vector3 predator_predicted_pos = sharkpos + .5f * Vector3.Distance(transform.position, sharkpos) * sharkboids [sharkboid_index].GetComponent <Rigidbody>().velocity; GetComponent <Rigidbody>().AddForce(Vector3.ClampMagnitude(predator_predicted_pos - transform.position, 50f), ForceMode.Force); Debug.DrawLine(sharkpos, predator_predicted_pos, Color.white); } // } } } ///////////////////////////////////////////////////////////////////////////////// // if the boids list is null if (boids == null) { // get the other boids boids = GameObject.FindGameObjectsWithTag("boid"); } else { // deal with the boid escape case - must stay within simulation_radius if (Vector3.Distance(simulation_centre, transform.position) > simulation_radius - 2) { if (Vector3.Distance(simulation_centre, transform.position) > simulation_radius) { } //push boids back into simulation the closer to the wall the more force is given float radius_scalar = Vector3.Distance(simulation_centre, transform.position) - (simulation_radius - 2) / 2; GetComponent <Rigidbody>().AddForce(Vector3.ClampMagnitude(simulation_centre - transform.position * radius_scalar, max_wallvel), ForceMode.Force); } } for (int boid_index = 0; boid_index < boids.Length; boid_index++) { boid_script r = (boid_script)boids [boid_index].GetComponent(typeof(boid_script)); if (r.returnstate() != 2) { // position of boid at index Vector3 pos = boids [boid_index].transform.position; Quaternion rot = boids [boid_index].transform.rotation; // the distance float dist = Vector3.Distance(transform.position, pos); // if not this boid if (dist > 0f) { // if within separation if (dist <= separation_distance) { // compute the scale of separationt float scale = separation_strength / dist; // add a separation force between this boid and its neighbour GetComponent <Rigidbody>().AddForce(Vector3.Normalize(transform.position - pos) * scale, ForceMode.Force); //Debug.DrawLine (transform.position, transform.position + Vector3.Normalize (transform.position - pos), Color.white); } if (dist < cohesion_distance && dist > separation_distance) // if within cohesive distance but not separation // compute the cohesive position { cohesive_number++; cohesion_pos = cohesion_pos + pos; // alignment - small rotations are applied based on the alignments of the neighbours transform.rotation = Quaternion.RotateTowards(transform.rotation, rot, 1f); } //else if(dist >= cohesion_distance){ } } } if (cohesive_number > 1) { cohesion_pos = cohesion_pos * (1 / cohesive_number); //add cohesive force // compute the scale cohesive_force = (cohesion_strength / Vector3.Distance(cohesion_pos, transform.position)) * (cohesion_pos - transform.position); // apply force GetComponent <Rigidbody>().AddForce(cohesive_force, ForceMode.Force); Debug.DrawLine(transform.position, cohesion_pos, Color.yellow); // zero the cohesion vector cohesion_pos = transform.position; cohesive_number = 1; } //timer controls creates random angle if (Time.time > timer) { timer = Time.time + fishthinktime; float rndm_angle = 360 * Random.value; radrndm_angle = Mathf.Deg2Rad * rndm_angle; } //sets coords for wander circle float x = (wander_circlediameter / 2) * Mathf.Cos(radrndm_angle) + (transform.position.x + Mathf.Clamp(transform.GetComponent <Rigidbody>().velocity.x, -maxvel, maxvel)); float y = (wander_circlediameter / 2) * Mathf.Sin(radrndm_angle) + (transform.position.y + Mathf.Clamp(transform.GetComponent <Rigidbody>().velocity.y, -maxvel, maxvel)); float z = (wander_circlediameter / 2) * Mathf.Sin(radrndm_angle) + (transform.position.z + Mathf.Clamp(transform.GetComponent <Rigidbody>().velocity.z, -maxvel, maxvel)); wander_dir.Set(x, (y), z); // adds force for wander GetComponent <Rigidbody>().AddForce(wander_dir - transform.position, ForceMode.Force); Debug.DrawLine(transform.position, wander_dir, Color.blue); Debug.DrawLine(transform.position, transform.position + transform.GetComponent <Rigidbody>().velocity, Color.red); transform.rotation = Quaternion.RotateTowards(transform.rotation, Quaternion.LookRotation(transform.position + transform.GetComponent <Rigidbody>().velocity), 6f); // clamps velocity of fish transform.GetComponent <Rigidbody>().velocity = Vector3.ClampMagnitude(transform.GetComponent <Rigidbody>().velocity, maxvel); }