I am trying to make enemy patrolling system, where evrytime guard reaches his point, he stopes for 10 seconds, and then continue his movement. I've tried combining animations from Blend tree with isStopped property from NavMeshAgent.
EDIT: My current script makes agent move to point, then he stopes for some time, and then only walk animation plays, but he staing on one place.
public Transform[] points;
private int destPoint = 0;
public NavMeshAgent agent;
public Animator animator;
public int time;
void Start()
{
agent = GetComponent<NavMeshAgent>();
animator = transform.Find("Enemy").GetComponent<Animator>();
// Disabling auto-braking allows for continuous movement
// between points (ie, the agent doesn't slow down as it
// approaches a destination point).
//agent.autoBraking = false;
}
void GotoNextPoint()
{
// Returns if no points have been set up
if (points.Length == 0)
return;
// Set the agent to go to the currently selected destination.
agent.destination = points[destPoint].position;
// Choose the next point in the array as the destination,
// cycling to the start if necessary.
destPoint = (destPoint + 1) % points.Length;
//agent.speed = 1f;
//animator.SetFloat("Blend", agent.speed);
}
void Update()
{
if (agent.remainingDistance == 0f && time == 100000)
{
agent.speed = 1f;
Debug.Log(agent.remainingDistance);
animator.SetFloat("Blend", 1);
GotoNextPoint();
}
else if (agent.remainingDistance <= 0.5f && agent.remainingDistance != 0f && time == 100000)
{
animator.SetFloat("Blend",0);
agent.enabled = false;
GotoNextPoint();
}
else if(animator.GetFloat("Blend") == 0)
{
time--;
}
if (time == 99000 && animator.GetFloat("Blend") == 0)
{
time = 10000;
agent.enabled = true;
agent.isStopped = false;
animator.SetFloat("Blend", 1);
agent.autoRepath = true;
GotoNextPoint();
}
}
I changed few lines of code, now agent moves after first stop, but second time he stops at second poitm,walking animation still working, time doesn't decrementing
if (time == 99000 && animator.GetFloat("Blend") == 0)
{
time = 10000;
agent.enabled = true;
agent.isStopped = false;
animator.SetFloat("Blend", 1);
//New lines of code
agent.ResetPath();
destPoint = (destPoint + 1) % points.Length;
agent.SetDestination(points[destPoint].position);
}[enter image description here][1]
First of all, I would use the "SetDestination" function in order to set the next destination.
In the end you wrote:
if (time == 99000 && animator.GetFloat("Blend") == 0)
{
time = 10000; *-> needs to be 100000, not 10000*
agent.enabled = true;
agent.isStopped = false;
animator.SetFloat("Blend", 1);
agent.autoRepath = true;
GotoNextPoint();
}
You can use "NavMeshAgent.ResetPath" to reset the path instead of using "autoRepath".
After the "ResetPath", use the "SetDestination" inside the function GotoNextPoint().
One more very important thing - Check that there is more than one point.
If there is just one point, your guard will just walk at the same spot.
For more information, is suggest to check out Unity NavMeshAgent
Related
The post is a bit long but both scripts are connected to each other. I tried to reduce the amount of code.
The Waypoints script is attached to empty GameObject and I added to it a rotation part :
[Header("Rotation")]
public Quaternion rotationTothinkWhatToDoHere;
but I'm not sure how to use it here in the Waypoints script and in the WaypointsFollower script.
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
using Cinemachine;
public class Waypoints : MonoBehaviour
{
[Header("Objects To Move")]
public Transform objectToMovePrefab;
public int numberOfObjectsToMove = 1;
public bool moveInReverse = false;
[Header("Speed")]
public float speed;
public bool randomSpeed = false;
public float minRandomSpeed = 1;
public float maxRandomSpeed = 100;
private bool changeSpeedOnce = false;
[Header("Rotation")]
public Quaternion rotationTothinkWhatToDoHere;
[Header("Waypoints")]
[SerializeField] private List<Transform> waypoints;
public bool moveOnWaypoints = false;
[Header("Delay")]
public bool useDelay = false;
public float delay = 3;
public bool randomDelay = false;
public float minRandomDelay = 0.3f;
public float maxRandomDelay = 5;
[Header("LineRenderer")]
public LineRenderer lineRenderer;
public bool moveOnLineRenderer = false;
public List<Vector3> lineRendererPositions = new List<Vector3>();
[Header("Cinemachine Cameras")]
public CinemachineVirtualCamera virtualCamera;
private List<WaypointsFollower> waypointsFollowers = new List<WaypointsFollower>();
private void Start()
{
for (int i = 0; i < numberOfObjectsToMove; i++)
{
var parent = GameObject.Find("Moving Object Parent");
var objectToMove = Instantiate(objectToMovePrefab, parent.transform);
objectToMove.name = "Platfrom";
waypointsFollowers.Add(objectToMove.GetComponent<WaypointsFollower>());
}
virtualCamera.Follow = waypointsFollowers[0].gameObject.transform;
virtualCamera.LookAt = waypointsFollowers[0].gameObject.transform;
foreach (WaypointsFollower wpf in waypointsFollowers)
{
wpf.goForward = moveInReverse;
}
WaypointsMovementStates();
SpeedUpdater();
if (useDelay)
StartCoroutine(SendObjectstomoveWithDelay());
}
private void Update()
{
lineRendererPositions.Clear();
lineRendererPositions.AddRange(GetLinePointsInWorldSpace());
SpeedUpdater();
}
IEnumerator SendObjectstomoveWithDelay()
{
{
foreach (WaypointsFollower follower in waypointsFollowers)
{
if (randomDelay)
{
delay = Random.Range(minRandomDelay, maxRandomDelay);
}
yield return new WaitForSeconds(delay);
follower.go = true;
}
}
}
private void SpeedUpdater()
{
if (changeSpeedOnce == false)
{
foreach (WaypointsFollower follower in waypointsFollowers)
{
if (randomSpeed)
{
follower.speed = Random.Range(minRandomSpeed, maxRandomSpeed);
}
else
{
follower.speed = speed;
}
}
changeSpeedOnce = true;
}
}
Vector3[] GetLinePointsInWorldSpace()
{
var 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;
}
private void WaypointsMovementStates()
{
// If moving on both linerenderer positions and waypoints objects
if (moveOnLineRenderer && moveOnWaypoints && waypoints.Count > 0)
{
if (useDelay == false)
{
foreach (WaypointsFollower wpf in waypointsFollowers)
{
wpf.go = true;
}
}
}
// If moving on linerenderer positions only without moving on waypoints objects
if (moveOnLineRenderer && moveOnWaypoints == false)
{
if (waypoints.Count > 0)
waypoints.Clear();
if (useDelay == false)
{
foreach (WaypointsFollower wpf in waypointsFollowers)
{
wpf.go = true;
}
}
}
// If only to move on waypoints objects without moving on linerenderer positions
if (moveOnWaypoints && waypoints.Count > 0 && moveOnLineRenderer == false)
{
lineRendererPositions.Clear();
foreach (Transform wp in waypoints)
{
lineRendererPositions.Add(wp.position);
}
if (useDelay == false)
{
foreach (WaypointsFollower wpf in waypointsFollowers)
{
wpf.go = true;
}
}
}
if(moveInReverse)
{
foreach (WaypointsFollower wpf in waypointsFollowers)
{
wpf.go = true;
}
}
}
}
In the WaypointsFollower script, this script is attached to each object that moves along the waypoints.
It's working fine if goForward is true but when goFoward is false for some reason the index value is -1 and I'm getting exception out of index was out of range on line 73 :
newPos = Vector3.MoveTowards(oldPos, waypoints.lineRendererPositions[index], distanceToTravel);
The idea when goForward is false to move the object from the last waypoint to the first waypoint and then when it's reaching the first waypoint then switch the goForward to true and move forward from the first waypoint to the last.
It's working when goFoward is first time true then it's moving from the first waypoint to the last waypoint and then it's moving from the last waypoint to the first one but it's not working when goForward is first time false.
I can't figure out why it's -1
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
public class WaypointsFollower : MonoBehaviour
{
public float speed;
public Waypoints waypoints;
public bool go;
public bool goForward;
private int index = 0;
private int counter = 0;
private int c = 0;
private List<GameObject> curvedLinePoints = new List<GameObject>();
public int numofposbetweenpoints;
private bool getonce;
private void Start()
{
waypoints = GameObject.Find("Waypoints").GetComponent<Waypoints>();
curvedLinePoints = GameObject.FindGameObjectsWithTag("Curved Line Point").ToList();
if(waypoints.moveInReverse == false)
{
goForward = true;
}
else
{
goForward = false;
}
if(goForward)
{
index = 0;
}
else
{
index = waypoints.lineRendererPositions.Count - 1;
}
}
private void Update()
{
if (getonce == false)
{
numofposbetweenpoints = curvedLinePoints.Count;
getonce = true;
}
if (go == true && waypoints.lineRendererPositions.Count > 0)
{
Move();
}
}
private void Move()
{
Vector3 newPos = transform.position;
float distanceToTravel = speed * Time.deltaTime;
bool stillTraveling = true;
while (stillTraveling)
{
Vector3 oldPos = newPos;
// error exception out of bound on line 55 to check !!!!!
newPos = Vector3.MoveTowards(oldPos, waypoints.lineRendererPositions[index], distanceToTravel);
distanceToTravel -= Vector3.Distance(newPos, oldPos);
if (newPos == waypoints.lineRendererPositions[index]) // Vector3 comparison is approximate so this is ok
{
// when you hit a waypoint:
if (goForward)
{
bool atLastOne = index >= waypoints.lineRendererPositions.Count - 1;
if (!atLastOne)
{
index++;
counter++;
if (counter == numofposbetweenpoints)
{
c++;
counter = 0;
}
if (c == curvedLinePoints.Count - 1)
{
c = 0;
}
}
else { index--; goForward = false; }
}
else
{ // going backwards:
bool atFirstOne = index <= 0;
if (!atFirstOne)
{
index--;
counter++;
if (counter == numofposbetweenpoints)
{
c++;
counter = 0;
}
if (c == curvedLinePoints.Count - 1)
{
c = 0;
}
}
else { index++; goForward = true; }
}
}
else
{
stillTraveling = false;
}
}
transform.position = newPos;
}
}
I saw your previous post before it was deleted, so here is the answer I had for your original question of moving between waypoints by both rotating and movement with the option of what occurs at the end of the motion. I can answer your current question if answering your last deleted question has still not solved your issue.
Instead of using the Update function to handle the rotation and movement between a series of waypoints in a list, I would recommend using a Coroutine. If you are unfamiliar, think of them as a process that handles small increments of work overtime and will jump back where it leaves off. It should simplify the issue of rotation and movement into smaller bite-sized pieces of logic, allowing an easier time to understand your issue.
// new enum - outside of your class
public enum WaypointMovementType
{
REPEAT_START, // will repeat to the start waypoint when end is reached
REPEAT_REVERSE, // will reverse the waypoint list when end is reached
STOP // will terminate when end is reached
};
// new variables - this is inside your class
// keep a reference of our coroutine to not run duplicates
Coroutine movingWayPoints = null;
// time it takes to rotate to our goal waypoint
private float rotateTime = 0.5f;
// time it takes to move to our goal waypoint
private float movementTime = 1.5f;
// Start is called before the first frame update
void Start()
{
parent = GameObject.Find("Waypoints");
// generate the waypoints
GenerateWaypoints();
// run our process
if (movingWayPoints == null)
movingWayPoints = StartCoroutine(MoveBetweenWaypoints(tmpList, WaypointMovementType.STOP));
}
private IEnumerator MoveBetweenWaypoints(List<Vector3> waypoints, WaypointMovementType movementType)
{
int currentWaypointIdx = 0;
// continue our loop until we have reached our end goal waypoint
while (currentWaypointIdx < waypoints.Count)
{
// rotate towards out goal point
yield return StartCoroutine(RotateTowardsGoalWaypoint(waypoints[currentWaypointIdx]));
// move towards our goal point
yield return StartCoroutine(MoveTowardsGoalWaypoint(waypoints[currentWaypointIdx]));
// increment our index count or wait for further time if you would like a delay between rotation / movement
++currentWaypointIdx;
}
// coroutine is done, so set the motion to null
movingWayPoints = null;
// now that we have reached the end, determine what we want to do
if (movementType != WaypointMovementType.STOP)
{
// if we want to reverse, then reverse our list
if (movementType == WaypointMovementType.REPEAT_REVERSE)
waypoints.Reverse();
// now call the coroutine again
movingWayPoints = StartCoroutine(MoveBetweenWaypoints(waypoints, movementType));
}
}
private IEnumerator RotateTowardsGoalWaypoint(Vector3 goalWaypoint)
{
// store our current rotation
Quaternion initialRotation = transform.rotation;
// find our direction to the goal
Vector3 dir = goalWaypoint - transform.position;
// calculate the final / goal rotation
Quaternion finalRotation = Quaternion.LookRotation(dir);
// store our current time
float currentTime = 0.0f;
// rotate until we reach our goal
while (currentTime <= rotateTime)
{
currentTime += Time.deltaTime;
transform.rotation = Quaternion.Lerp(initialRotation, finalRotation, currentTime / rotateTime);
yield return null;
}
// set our rotation in case there are floating point precision errors
transform.rotation = finalRotation;
}
private IEnumerator MoveTowardsGoalWaypoint(Vector3 goalWaypoint)
{
// store our current position
Vector3 initialPostion = transform.position;
// store our current time
float currentTime = 0.0f;
while (currentTime <= movementTime)
{
currentTime += Time.deltaTime;
transform.position = Vector3.Lerp(initialPostion, goalWaypoint, currentTime / movementTime);
yield return null;
}
// set our position in case there are floating point precision errors
transform.position = goalWaypoint;
}
The current code uses time instead of speed which can be changed by changing how the Lerp steps are inputted. One other issue currently is the repeat backwards will move and rotate to the first element in the reversed list, but this can be fixed by passing in an index parameter for where to start in the list.
If you would rather use your current implementation, I can help debug it, but in the future do not delete questions you expect an answer to unless you have a good reason to do so. I should also mention, as your original question had only 1 script, the current script is expecting the object that generates the waypoints is the same object that is moving between them. It would be very easy to fix by creating a new public field that references some other Transform that should move between the waypoints, then replace all of the transform.rotation and transform.position with yourObject.position and yourobject.rotation.
I should also add, to change how the waypoint movement will function after a single pass is finished, simply change the WaypointMovementType parameter to a different value before making the initial call.
Edit: As derHugo mentioned that a speed variant of the answer would better suit the needs of the use case, here is an additional snippet with speed instead of time.
private IEnumerator MoveBetweenWaypoints(List<Vector3> waypoints, WaypointMovementType movementType)
{
int currentWaypointIdx = 0;
// continue our loop until we have reached our end goal waypoint
while (currentWaypointIdx < waypoints.Count)
{
// rotate towards out goal point
yield return StartCoroutine(RotateTowardsGoalWaypoint(waypoints[currentWaypointIdx]));
// move towards our goal point
yield return StartCoroutine(MoveTowardsGoalWaypoint(waypoints[currentWaypointIdx]));
// increment our index count or wait for further time if you would like a delay between rotation / movement
++currentWaypointIdx;
}
// coroutine is done, so set the motion to null
movingWayPoints = null;
// now that we have reached the end, determine what we want to do
if (movementType != WaypointMovementType.STOP)
{
// if we want to reverse, then reverse our list
if (movementType == WaypointMovementType.REPEAT_REVERSE)
waypoints.Reverse();
// now call the coroutine again
movingWayPoints = StartCoroutine(MoveBetweenWaypoints(waypoints, movementType));
}
}
private IEnumerator RotateTowardsGoalWaypoint(Vector3 goalWaypoint)
{
// find our direction to the goal
Vector3 dir = goalWaypoint - transform.position;
// calculate the final / goal rotation
Quaternion finalRotation = Quaternion.LookRotation(dir);
// continue until our angles match
while(Vector3.Angle(transform.forward, dir) > ROTATION_CHECK_EPSILON)
{
transform.rotation = Quaternion.RotateTowards(transform.rotation, finalRotation, Time.deltaTime * rotateSpeed);
yield return null;
}
// set our rotation in case there are floating point precision errors
transform.rotation = finalRotation;
}
private IEnumerator MoveTowardsGoalWaypoint(Vector3 goalWaypoint)
{
// continue until our distance is close to our goal
while(Vector3.Distance(transform.position, goalWaypoint) > DISTANCE_CHECK_EPSILON)
{
transform.position = Vector3.MoveTowards(transform.position, goalWaypoint, Time.deltaTime * movementSpeed);
yield return null;
}
// set our position in case there are floating point precision errors
transform.position = goalWaypoint;
}
I am trying to get characters to move around by randomly going left/right/forward at turns, and for the most part the characters do that, but every once in a while they walk through the walls, and I don't want that to happen. Is there anything you can see in my code that I am missing?
The walls have colliders on them, and so do the circles, but the circles colliders are just a trigger because I want the circles to be able to go through each other, just not through the walls.
It seems like the character turns, and some time turns again towards a wall.
Here is a video example: https://www.youtube.com/watch?v=ZOfGn3bsuLA
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
[RequireComponent(typeof(Rigidbody2D))]
public class Character : MonoBehaviour {
public float speed;
protected Transform frontRaycast, leftRaycast, rightRaycast;
protected List<int> lastPossibleDirs = new List<int>();
protected int lastDir;
protected bool changed = false;
protected bool forward, left, right;
// Use this for initialization
void Awake () {
frontRaycast = transform.FindChild("FrontRaycast").transform;
leftRaycast = transform.FindChild("LeftRaycast").transform;
rightRaycast = transform.FindChild("RightRaycast").transform;
}
void Update(){
// Test for a wall in front and on sides
forward = Physics2D.Linecast(transform.position, frontRaycast.position, 1 << LayerMask.NameToLayer("Wall"));
left = Physics2D.Linecast(transform.position, leftRaycast.position, 1 << LayerMask.NameToLayer("Wall"));
right = Physics2D.Linecast(transform.position, rightRaycast.position, 1 << LayerMask.NameToLayer("Wall"));
// Add each direction to the list of possible turns
List<int> possibleDirs = new List<int>();
if(!forward){
possibleDirs.Add(0);
}
if(!left){
possibleDirs.Add(1);
}
if(!right){
possibleDirs.Add(2);
}
int dir = 0;
if(possibleDirs.Count > 0){
dir = (int)possibleDirs[Random.Range(0, possibleDirs.Count)];
}
if(changed){
// Move forward with left or right option
if(lastPossibleDirs.Exists(element => element == 0) && lastPossibleDirs.Exists(element => element > 0) && (left || right) && lastDir == 0){
changed = false;
}
// Left
else if(lastPossibleDirs.Exists(element => element == 1) && left && lastDir == 1){
changed = false;
}
// Right
else if(lastPossibleDirs.Exists(element => element == 2) && right && lastDir == 2){
changed = false;
}
}else{
switch(dir){
case 0:
if(!left || !right){
transform.Rotate(new Vector3(0,0,0));
changed = true;
}
break;
case 1:
transform.Rotate(new Vector3(0,0,90));
changed = true;
break;
case 2:
transform.Rotate(new Vector3(0,0,-90));
changed = true;
break;
}
lastDir = dir;
lastPossibleDirs = possibleDirs;
}
transform.Translate(Vector2.right * Time.deltaTime * speed);
}
}
Here is a screenshot of where the detection areas are located on the character
Fist thing I would do is uncheck trigger on your circle and make use of
Physics2d.IgnoreLayerCollision(circle layer)
in the Awake()
So here's what I'd like to do: The player is idling on the ground, not moving at all. And after some time a random idle animation should be played. How do I detect that the player hasn't been moving for a certain amount of time?
IEnumerator Idle()
{
// check if player is idling on the ground
if (grounded && (_controller.velocity.x == 0))
{
// Now what?
//...
}
idleIndex = IdleRandom();
_animator.SetInteger("IdleIndex", idleIndex);
_animator.SetTrigger("Idle");
}
int IdleRandom()
{
// choose random index of idle animations
int i = Random.Range(0, numberOfIdleAnims);
// if it's the same as the previous one...
if (i == idleIndex) {
// try another one
return IdleRandom ();
}
else
return i;
}
I've already set up my animator controller so that it would play one of the idle animations (chosen by the idleIndex) if the idle-Trigger is pushed. The only thing I cannot figure out is the not-moving-in-certain-time thing!
You need to count the time your player has been idle, not moving. You can do this in the void FixedUpdate() function.
I have drastically changed my code. Make sure you include the code for playing animations.
public class IdleManager : MonoBehaviour
{
private isIdle = false;
private float previousTime;
private const float IDLE_TIME = 5.0f;
void Update()
{
if(!isIdle && grounded && (_controller.velocity.x == 0))
{
isIdle = true;
previousTime = Time.timeSinceLevelLoad();
}
else if(isIdle && Time.timeSinceLevelLoad - previousTime > IDLE_TIME)
{
// Play animation here.
// Reset previousTime.
previousTime = Time.timeSinceLevelLoad;
}
else if(grounded || _controller.velocity.x > 0)
isIdle = false;
}
}
Basically I have been given a project to develop a game in unity using c# and the device Leap Motion. The problem I am having is that I have a basic power bar that goes up and down through a range of 0 - 100, when the user releases his fist I want to shoot using the selected power. the problem I am having is I cannot figure out a way to set the bool "shoot" to true on release of the fists.
Controller m_leapController;
public GameObject CannonBarrel;
[Range(0, 100)] public float ballPower = 0f;
public bool increasing = true;
public bool shoot = false;
if (frame.Hands.Count >= 2)
{
Hand leftHand = GetLeftMostHand(frame);
Hand rightHand = GetRightMostHand(frame);
Vector3 handDiff = leftHand.PalmPosition.ToUnityScaled() - rightHand.PalmPosition.ToUnityScaled();
Vector3 newRot = CannonBarrel.transform.localRotation.eulerAngles;
float leftRightSpeed = handDiff.y * 5.0f;
float handPitch = leftHand.Direction.Pitch + rightHand.Direction.Pitch * 0.5f;
newRot.x = 0;
newRot.y = 90;
newRot.z = 70 + -handPitch * 20.0f;
shoot = true;
// if closed fist...
if (frame.Fingers.Count < 3)
{
leftRightSpeed = 0;
shoot = false;
if (increasing == true)
{
ballPower++;
if (ballPower >= 100)
{
increasing = false;
}
}
else if (increasing == false)
{
ballPower--;
if (ballPower <= 0)
{
increasing = true;
}
}
}
else
{
//Move left or right depending on hands height difference.
transform.parent.rigidbody.velocity = transform.parent.right * leftRightSpeed;
//Rotate the barrel
CannonBarrel.transform.localRotation = Quaternion.Slerp(CannonBarrel.transform.localRotation, Quaternion.Euler(newRot), 0.1f);
}
if (shoot == true)
{
Debug.Log("fired");
//add code here to spawn projectile
}
}
I hope that this code makes sense to you. All that is happening is if you're holding your fists above the Leap sensor the ball power will increase till you hit 100, then it will decrease back down to 0 and so on until you release your fists. I need a way to set the "shoot" bool to true once a power has been selected as the way I currently do it I can only set it to true either during the power selection or it gets set to true before you clench your fists.
Thanks in advance.
A somewhat simple way you could do this is by setting a bool to check if the player has clenched his fist at least once, thus setting the power. Let's call it hasClenchedFist:
if (frame.Hands.Count >= 2)
{
Hand leftHand = GetLeftMostHand(frame);
Hand rightHand = GetRightMostHand(frame);
Vector3 handDiff = leftHand.PalmPosition.ToUnityScaled() - rightHand.PalmPosition.ToUnityScaled();
Vector3 newRot = CannonBarrel.transform.localRotation.eulerAngles;
float leftRightSpeed = handDiff.y * 5.0f;
float handPitch = leftHand.Direction.Pitch + rightHand.Direction.Pitch * 0.5f;
newRot.x = 0;
newRot.y = 90;
newRot.z = 70 + -handPitch * 20.0f;
//shoot = true;
// if closed fist...
if (frame.Fingers.Count < 3)
{
leftRightSpeed = 0;
hasClenchedFist = true;
shoot = false;
if (increasing == true)
{
ballPower++;
if (ballPower >= 100)
{
increasing = false;
}
}
else if (increasing == false)
{
ballPower--;
if (ballPower <= 0)
{
increasing = true;
}
}
}
else if(hasClenchedFist)
{
shoot = true;
}
else
{
//Move left or right depending on hands height difference.
transform.parent.rigidbody.velocity = transform.parent.right * leftRightSpeed;
//Rotate the barrel
CannonBarrel.transform.localRotation = Quaternion.Slerp(CannonBarrel.transform.localRotation, Quaternion.Euler(newRot), 0.1f);
}
if (shoot == true)
{
Debug.Log("fired");
//add code here to spawn projectile
}
}
This should work, unless I've misunderstood the code/requirements.
Im trying to do a coroutine that sets the character to hurt mode for a persiod. During this period i want it to flash. Im not familiar with modulus but i tried to use it to flip the sprite renderer every 10 or so cycles. But i get really weird values, is it cause its a float? How should i do this in unity?
public IEnumerator Hurt_cr (float sec, Vector2 attackPosition, float force)
{
isHurt = true;
AddForceAtPosition (attackPosition, force);
SpriteRenderer sprite = GetComponent< SpriteRenderer> ();
float t = Time.deltaTime;
while (t < sec) {
if ((t % 10) == 0) {
print ("sprite on : " + sprite.enabled);
sprite.enabled = !sprite.enabled;
}
yield return null;
t += Time.deltaTime;
}
isHurt = false;
}
Don't use a coroutine, it's totally useless. Put this into Update:
sprite.enabled = ((int)(Time.time / 10)) % 2 == 0;
EDIT: added (int) cast for good measure.
EDIT 2: to have it flash a fixed number of times
Add the class propery:
public int flashes = 0;
private bool flashingLastFrame = false;
In Update count the flashes, if any:
bool flashingNow;
if (flashes > 0)
{
flashingNow = ((int)(Time.time / 10)) % 2 == 0;
if (flashingNow != flashingLastFrame)
{
flashingLastFrame = flashingNow;
sprite.enabled = flashingNow;
flashes--; // forgot this to make it stop
}
}
To have it flash 3 times set from the outside:
obj.flashes = 6;
Or add a convenience method:
public void Flash(int times)
{
flashes = times * 2;
}
EDIT 3: For super-fast flashing:
if (flashes > 0)
{
flashingLastFrame = !flashingLastFrame;
sprite.enabled = flashingLastFrame;
flashes--;
}