How to extend the curve created using quadratic interpolation in C# & Unity? - c#

I am attempting to use quadratic interpolation in order to throw a rock at the player's position. The rock simply follows the curve. However, if the player moves, the rock begins to loop and starts back at its original position. I have stopped the rock following the curve once it reaches the end of the curve and add force to the rock's rigidbody but it only works in specific examples. I was wondering if there was a way to extend the curve so the rock hits the ground and destroys itself using the code I already have. The code I am using is below. Thanks in advance. The code is below.
Quadratic Interpolation Code (it is run every frame)
private void FollowQuadraticPath()
{
interpolateAmount = (interpolateAmount + Time.deltaTime) % 1f;
pointAB.transform.position = Vector3.Lerp(transformerPosition, throwHeightPosition, interpolateAmount);
pointBC.transform.position = Vector3.Lerp(throwHeightPosition, playerPosition, interpolateAmount);
transform.position = Vector3.Lerp(pointAB.transform.position, pointBC.transform.position, interpolateAmount);
}
Damage
private void OnCollisionEnter2D(Collision2D collision)
{
if (collision.gameObject.GetComponent<PlayerHealth>())
{
Destroy(pointABInstance);
Destroy(pointBCInstance);
collision.gameObject.GetComponent<PlayerHealth>().DealDamage(damage);
Destroy(gameObject);
}
else
{
Destroy(pointABInstance);
Destroy(pointBCInstance);
Destroy(gameObject);
}
}
This is what I want to happen. Pretending the player had moved, the rock would continue and hit the ground past the player point.
Instead, once again pretending the player wasn't there, the object is destroyed before it reaches the ground
Edit: Check comments of the answer for the solution I used

I guess you are using FollowQuadraticPath() within Update so what happens is you always use it with the current updated position of the player.
Instead I would use a Coroutine. A Coroutine is somewhat like a temporary Update method so it has a clear start and end and you can have local variables that persist through all frames the routine is running and do something like e.g.
private IEnumerator FollowQuadraticPath()
{
// Cash the target positions ONCE so they are not updated later
var startAB = TransformerPosition;
var targetAB = throwHeightPosition;
var targetBC = playerPosition;
// Iterates until 1 second has passed
// linearly increasing interpolateAmount from 0 to 1
for(var interpolateAmount = 0f; interpolateAmount < 1f; interpolateAmount += Time.deltaTime)
{
pointAB.transform.position = Vector3.Lerp(startAB, targetAB, interpolateAmount);
pointBC.transform.position = Vector3.Lerp(targetAB, targetBC, interpolateAmount);
transform.position = Vector3.Lerp(pointAB.transform.position, pointBC.transform.position, interpolateAmount);
// Tells Unity to "pause" the routine here, render this frame
// and continue from here in the next frame
yield return null;
}
// Destroy if it reaches the original player position
Destroy (gameObject);
}
You run this ONCE e.g. in
private void Start ()
{
StartCorouine(FollowQuadraticPath());
}
or Start can also be the routine itself like
private IEnumerator Start()
{
var startAB = TransformerPosition;
var targetAB = throwHeightPosition;
.....
}
you don't have to worry about terminating the routine because it either reaches the original player position and is then destroyed or it hits the ground before and is destroyed. In either case the coroutine is automatically gone as well.
What I don't really get though is why you have 2 additional transforms for this. Why not simply only calculate with Vector3 itself like
var ab = Vector3.Lerp(startAB, targetAB, interpolateAmount);
var bc = Vector3.Lerp(targetAB, targetBC, interpolateAmount);
transform.position = Vector3.Lerp(ab, bc, interpolateAmount);

Related

How to get Direction after cueBall collide with any ball in unity3d? Like in 8 ball pool

Hi!
i am making something like 8 ball pool in 3d with unity 3d C#.
A is que ball and I know Dir1. I want to calculate Dir2.I am using Raycast to i can get point of contact.
If you really want to go manual
Instead of a Raycast you would rather use a Physics.SphereCast (according to your balls shape) or alternatively you could also use Rigidbody.SweepTest in order to get hit information for if you object would move.
Both provide you with the information
whether something is hit or not (e.g. check via tag if the first thing hit is a wall or another ball)
both give you a RaycastHit which contains detailed information such as
point the exact contact point
distance how far the ball traveled before hitting something (e.g. for calculating the already applied damping/table friction)
normal of the surface you hit so you can calculate your two balls new direction from that
and of course most importantly which object was hit so you can start a new calculation for that ball as well
The rest is The Math and Physics of Billard or Physics of Billard etc and you will find that a complete answer is way to complex for this page ;)
There are way to many things to consider when calculating physics manually and first of all you will need to decide how realistic you want to go actually. There are spins, frictions, jumps and you know in the real world there doesn't exist any fully elastic collision at all ... So boy if you are going to pre-calculate all this by hand you can as well just write your own physics engine ;)
Use the existing physics without calculating yourself at all
Now as a complete alternative approach to all that, which doesn't require you to calculate anything at all:
You could simulate the whole physics!
You could
Store all balls current positions (in order to restore them later)
Use Physics.Simulate in a loop, as condition checking if any sphere has moved between the two calls -> If not (or after certain preview time) then break.
Every step track the positions of all balls
After breaking of the loop reset all positions and velocities
=> You already get all the tracked points for each balls LineRenderer ;)
You could even use the positions in order to move the balls yourself instead of use the physics again to show the actual movement ;)
For large systems this would of course cause immense lag (depends also on your target preview time range). But I'd say for only a limited amount of balls this should be fine.
Here a little code I cluched together in a few minutes (way not perfect of course)
// little helper component for storing some references and identify clearly as a ball
// (rather then allowing to reference just any GameObject)
public class Ball : MonoBehaviour
{
[SerializeField]
private Rigidbody _rigidbody;
public Rigidbody Rigidbody => _rigidbody;
[SerializeField]
private LineRenderer _line;
public LineRenderer Line => _line;
private void Awake()
{
if (!_rigidbody) _rigidbody = GetComponent<Rigidbody>();
if (_line) _line = GetComponentInChildren<LineRenderer>(true);
}
}
and
public class Example : MonoBehaviour
{
// A simple data container for transform values
private class TransformData
{
public Vector3 Position;
public Quaternion Rotation;
private readonly Rigidbody _rigidbody;
public TransformData(Rigidbody rigidbody)
{
_rigidbody = rigidbody;
Update();
}
public void Update()
{
Position = _rigidbody.position;
Rotation = _rigidbody.rotation;
}
}
// all balls
public Ball[] balls;
// the white ball in particular
public Ball whiteBall;
// direction to shoot in
public Vector3 direction;
// force to apply
public float force;
// How far to predict into the future
public float maxPreviewTime = 10;
// shall this be done every frame (careful with performance!)
public bool continousUpdates;
// stores all initial transform values before starting the prediction in order to restore the state later
private readonly Dictionary<Ball, TransformData> initialPositions = new Dictionary<Ball, TransformData>();
// stores all the predicted positions in order - but for now without the information about the exact frame
// for simplicity and performance we only store WHERE the balls move, not exactly WHEN (could change that though if you wish)
private readonly Dictionary<Ball, List<Vector3>> simulatedPositions = new Dictionary<Ball, List<Vector3>>();
private void Awake()
{
// Initialize empty data sets for the existing balls
foreach (var ball in balls)
{
initialPositions.Add(ball, new TransformData(ball.Rigidbody));
simulatedPositions.Add(ball, new List<Vector3>());
}
}
private void Update()
{
// you could call this every frame e.g. in order to see prediction lines while the player changes force and direction
// have performance in mind though!
if (continousUpdates)
{
UpdateLines();
}
// for demo we shoot on space key
if (Input.GetKeyDown(KeyCode.Space))
{
ShootWhiteBall();
}
}
private void ShootWhiteBall()
{
whiteBall.Rigidbody.AddForce(direction.normalized * force, ForceMode.Impulse);
}
[ContextMenu("Update Preview Lines")]
public void UpdateLines()
{
// update all balls initial transform values to the current ones
foreach (var transformData in initialPositions.Values)
{
transformData.Update();
}
// clear all prediction values
foreach (var list in this.simulatedPositions.Values)
{
list.Clear();
}
// disable autosimulation - the API is a bit unclear whether this is required when manually calling "Physics.Simulate"
// so just to be sure
Physics.autoSimulation = false;
// we will track if any transform values changed during the prediction
// if not we break out of the loop immediately to avoid unnecessary overhead
var somethingChanged = true;
// as second break condition we use time - we don't want o get stuck in prediction forever
var simulatedTime = 0f;
// Do the same thing as you would later for shooting the white ball
// preferably even actually use the exact same method to avoid double maintenance
ShootWhiteBall();
while (somethingChanged && simulatedTime < maxPreviewTime)
{
// Simulate a physics step
Physics.Simulate(Time.fixedDeltaTime);
// always assume there was no change (-> would break out of prediction loop)
somethingChanged = false;
foreach (var kvp in simulatedPositions)
{
var ball = kvp.Key;
var positions = kvp.Value;
var currentPosition = ball.Rigidbody.position;
// either this is the first frame or the current position is different from the previous one
var hasChanged = positions.Count == 0 || currentPosition != positions[positions.Count - 1];
if (hasChanged)
{
positions.Add(currentPosition);
}
// it is enough for only one ball to be moving to keep running the prediction loop
somethingChanged = somethingChanged || hasChanged;
}
// increase the counter by one physics step
simulatedTime += Time.fixedDeltaTime;
}
// Reset all balls to the initial state
foreach (var kvp in initialPositions)
{
kvp.Key.Rigidbody.velocity = Vector3.zero;
kvp.Key.Rigidbody.angularVelocity = Vector3.zero;
kvp.Key.Rigidbody.position = kvp.Value.Position;
kvp.Key.Rigidbody.rotation = kvp.Value.Rotation;
}
// apply the line renderers
foreach (var kvp in simulatedPositions)
{
var ball = kvp.Key;
var positions = kvp.Value;
ball.Line.positionCount = positions.Count;
ball.Line.SetPositions(positions.ToArray());
}
// re-enable the physics
Physics.autoSimulation = true;
}
}
as you can see it is not exactly 100% accurate, tbh no sure why but it is probably something that can be tweaked out.

Player unable to move after being teleported/transported Unity3d

I've been trying to fix this one bug in my code for over 7 hours now, upon being teleported, the movement controls cease to function, the mouse works fine, you can look around, but you can't move around.
I wanted to set up some simple code that would teleport the player to a "checkpoint" upon achieving a negative or null y level. I was doing this for a parkour based game, if the player fell off the platform they would have to start over, but after teleporting, it becomes impossible to move as I'm sure I have already said. My code is pretty simple:
public class Main : MonoBehaviour
{
float Fall;
// Start is called before the first frame update
void Start()
{
}
// Update is called once per frame
void Update()
{
Vector3 Checkpoint = new Vector3 (0,3,0);
GameObject Player = GameObject.FindGameObjectWithTag("Player");
Fall = GameObject.FindGameObjectWithTag("Player").transform.position.y;
if (Fall<-4)
{
Player.transform.position = Checkpoint;
}
}
}
You would think that this would just simply change the coordinates of the player, but I think this might be screwing with the FPSController script.
I am using Unity3d, with Standard Assets imported, All of the code is in C#.
Instead of checking the Y value of your character, I would instead place a death collider under the map. Make this a trigger and if the player touches this trigger, then teleport them back. Nothing with your code should screw with the FPS controller so it might be something else. I would also highly recommend not using a FindGameObjectWithTag in the Update() method as it is extremely expensive to use this every frame, especially twice. If you would rather keep the Update() Y component of the position check, please rewrite the code to something like this:
public class Main : MonoBehaviour
{
// assign this object of your player in the inspector - it stores the reference to reuse
// instead of grabbing it every frame
[SerializeField] private Transform playerTransform = null;
// make this a variable as it is not changing - might as well make this const too
private Vector3 checkpoint = new Vector3(0, 3, 0);
// constant value of what to check for in the Y
private const int FALL_Y_MARKER = -4;
// Update is called once per frame
void Update()
{
if (playerTransform.position.y < FALL_Y_MARKER)
{
playerTransform.position = checkpoint;
}
}
}
With your current code, there should be nothing breaking your input/movement, but with that said, we can not see your input/movement code. All the above snippet does is check if the Y component of the player objects position is below a certain value, and if it is, it sets the position to a new vector. Can you post a bit more movement code or somewhere else it can go wrong that you think is the issue?

Unity - How do I increase a value while a key is held down?

public int power;
// Start is called before the first frame update
void Start()
{
player = GameObject.Find("Whyareyoulikethis");
while (Input.GetKey(KeyCode.Space))
{
power = power + 10;
}
// Places the ball at the player's current position.
transform.Translate(-player.transform.forward);
rb = GetComponent<Rigidbody>();
rb.AddForce(-player.transform.forward * power);
}
What this is meant to do is while the space key is held down, power will increase by 10. Unfortunately, this does absolutely nothing. When the ball is spawned, it simply just drops down with no force added whatsoever. I have also tried GetKeyUp and GetKeyDown as opposed to Getkey, but they made no difference to the final result. I have also tried this in an if statement under void Update(), but the same happened. As stupid as it was, I also tried it in its while statement under void Update() and crashed the engine as expected.
That while loop blocks your game until it is done. So as soon as you enter it you will never come out since the Input is not updated inside of your while loop.
Also it makes no sense in Start which is only called once when your GameObject is initialized and the space key won't be pressed there.
Move the check for Input.GetKey it to Update which is called every frame.
Than Cid's comment is correct and this will increase the power quite fast and frame dependent. You probably want to increase rather with a frame-independent 60/second so rather use Time.deltaTime
in this case power should be a float instead
Than it depends where the rest should be executed but I guess e.g. at button up
public float power;
private void Start()
{
player = GameObject.Find("Whyareyoulikethis");
rb = GetComponent<Rigidbody>();
}
private void Update()
{
if(Input.GetKey(KeyCode.Space))
{
power += 10 * Time.deltaTime;
}
if(Input.GetKeyUp(KeyCode.Space))
{
// Places the ball at the player's current position
transform.position = player.transform.position;
// you don't want to translate it but set it to the players position here
// rather than using addforce you seem to simply want to set a certain velocity
// though I don't understand why you shoot backwards...
rb.velocity = -player.transform.forward * power;
}
}

What code do I need for my Unity character to shoot the bullet correctly?

I am not new to programming, but I am new to C#. I am experienced in Python, Java, and HTML. My game is 2D I have a game where my character currently has to touch the enemy to kill it. Now I added code for shooting a bullet to kill the enemy. I also want the bullet to be shot if the spacebar is pressed. The character is supposed to a shoot bullet in either direction. I have taken my code from an example my professor gave me which was originally Javascript and I converted it to C#. Unity no longer supports Javascript. The example code he gave me was basically a rocket shooting as many bullets as I clicked (clicking the mouse shoots bullets) to eliminate an enemy, however the rocket in that example does not move. In my game, the character moves, so the bullet has to get the position of the character. What is the correct code for getting the character position and shooting a bullet correctly?
I tested my game with my current code. The bullet is being spit out of nowhere (from the bottom of my background wallpaper [smack in the middle of the bottom] to a little below the wallpaper). Not even from the character...
Also, I added the Hit class script to my Bullet category in Unity.
Complete Camera Controller (no issues here at all)
using UnityEngine;
using System.Collections;
public class CompleteCameraController : MonoBehaviour {
public GameObject player; //Public variable to store a reference to the player game object
private Vector3 offset; //Private variable to store the offset distance between the player and camera
// Use this for initialization
void Start ()
{
//Calculate and store the offset value by getting the distance between the player's position and camera's position.
offset = transform.position - player.transform.position;
}
// LateUpdate is called after Update each frame
void LateUpdate ()
{
// Set the position of the camera's transform to be the same as the player's, but offset by the calculated offset distance.
transform.position = player.transform.position + offset;
}
}
Complete Player Control Class (If you read the comments in the code that say the "BULLET CODE", that's new code I have placed in the game for the bullets.
using UnityEngine;
using System.Collections;
//Adding this allows us to access members of the UI namespace including Text.
using UnityEngine.UI;
public class CompletePlayerController : MonoBehaviour
{
public float speed; //Floating point variable to store the player's movement speed.
public Text countText; //Store a reference to the UI Text component which will display the number of pickups collected.
public Text winText; //Store a reference to the UI Text component which will display the 'You win' message.
private Rigidbody2D rb2d; //Store a reference to the Rigidbody2D component required to use 2D Physics.
private int count; //Integer to store the number of pickups collected so far.
Rigidbody2D bullet;
float speed2 = 30f; //BULLET CODE
// Use this for initialization
void Start()
{
//Get and store a reference to the Rigidbody2D component so that we can access it.
rb2d = GetComponent<Rigidbody2D> ();
//Initialize count to zero.
count = 0;
//Initialze winText to a blank string since we haven't won yet at beginning.
winText.text = "";
//Call our SetCountText function which will update the text with the current value for count.
SetCountText ();
}
//FixedUpdate is called at a fixed interval and is independent of frame rate. Put physics code here.
void FixedUpdate()
{
//Store the current horizontal input in the float moveHorizontal.
float moveHorizontal = Input.GetAxis ("Horizontal");
//Store the current vertical input in the float moveVertical.
float moveVertical = Input.GetAxis ("Vertical");
Rigidbody2D bulletInstance; //BULLET CODE
//Use the two store floats to create a new Vector2 variable movement.
Vector2 movement = new Vector2 (moveHorizontal, moveVertical);
//Call the AddForce function of our Rigidbody2D rb2d supplying movement multiplied by speed to move our player.
rb2d.AddForce (movement * speed);
if(Input.GetKeyDown(KeyCode.Space)&& Hit.hit == false) //BULLET CODE IN HERE
{
// ... instantiate the bullet facing right and set it's velocity to the right.
bulletInstance = Instantiate(bullet, transform.position, Quaternion.Euler(new Vector3(0,0,0)));
bulletInstance.velocity = new Vector2(speed2, 0);
bulletInstance.name = "Bullet";
}
}
//OnTriggerEnter2D is called whenever this object overlaps with a trigger collider.
void OnTriggerEnter2D(Collider2D other)
{
//Check the provided Collider2D parameter other to see if it is tagged "PickUp", if it is...
if (other.gameObject.CompareTag ("PickUp"))
{
//... then set the other object we just collided with to inactive.
other.gameObject.SetActive(false);
transform.localScale += new Vector3(0.1f, 0.1f, 0);
//Add one to the current value of our count variable.
count = count + 1;
//Update the currently displayed count by calling the SetCountText function.
SetCountText ();
}
}
//This function updates the text displaying the number of objects we've collected and displays our victory message if we've collected all of them.
void SetCountText()
{
//Set the text property of our our countText object to "Count: " followed by the number stored in our count variable.
countText.text = "Count: " + count.ToString ();
//Check if we've collected all 12 pickups. If we have...
if (count >= 12)
//... then set the text property of our winText object to "You win!"
winText.text = "You win!";
}
}
Hit code. All code in this class is made for the bullet.
using UnityEngine;
using System.Collections;
public class Hit : MonoBehaviour
{
GameObject[] gameObjects;
public static bool hit = false;
void Removal ()
{
gameObjects = GameObject.FindGameObjectsWithTag("Bullet");
for(var i= 0 ; i < gameObjects.Length ; i ++)
Destroy(gameObjects[i]);
}
void OnCollisionEnter2D ( Collision2D other )
{
if(other.gameObject.name=="Bullet")
{
Removal();
Destroy(gameObject);
hit = true;
}
}
}
I see several issues with the code you wrote. as #Kyle Delaney suggested, I'd also highly recommend you check out the Unity Learn website, and go through several tutorials before moving through. I've highlighted a few issues below that may help solve your problem, but you could really benefit from changing your approach in the first place to avoid many of these issues. See below.
In your camera controller class, why not make the offset public so you can set it yourself in the inspector>
In Player controller class:
changed:
if (Input.GetKeyDown(KeyCode.Space)) //Shoot bullet
{
// ... instantiate the bullet facing right and set it's velocity to the right.
Rigidbody2D bulletRB = Instantiate(bullet, transform.position, transform.rotation);
bulletRB.AddForce(new Vector2(speed2,0), ForceMode2D.Impulse);
}
On a click, this instantiates the bullet prefab and sets its transform to copy the position and rotation of the player. It then adds a force to it to the right. You should avoid setting the velocity manually with rigidbodies, this can cause unwanted behaviour. Use the Addforce/addTorque methods instead. The ForceMode says to ignore its mass and set its velocity.
Then delete your Hit class, and replace with this Bullet class, which you drag onto the bullet prefab. Your player shouldn't be in charge of checking for bullet hits. that's the bullet's job. The player just launches the bullets and then the bullets do what bullets do. this just checks to see if the bullet hit anything, if so it destroys it. You can make this more complicated if you want. I would recommend using layers to determine which layers the bullet checks collisions with. You probably don't want bullets destroying your terrain. and you definitely don't want bullets destroying the player itself!
public class Bullet : MonoBehaviour
{
private void OnCollisionEnter2D(Collision2D collision)
{
Destroy(collision.gameObject);
Destroy(this.gameObject);
}
}
Also you shouldn't need to set the name of the bullet, since your prefab bullet should already be named "bullet".
I hope this gets you started in the right direction. But based on your code, I HIGHLY recommend you work through the tutorials before continuing with any projects. The unity staff that make them are super helpful and the tutorials start off really simple but get really complicated fast, so you actually come away learning a ton!
Perhaps the problem has to do with the player's parent transform. You could try something like this to make sure the bullet has the right parent:
bulletInstance = Instantiate(bullet);
bulletInstance.transform.parent = transform.parent;
bulletInstance.transform.position = transform.position;
bulletInstance.velocity = new Vector2(speed2, 0);
bulletInstance.name = "Bullet";
If that doesn't work it may be worthwhile to check the player's Rect Transform to see where the anchors and pivot are. Perhaps the player's actual "position" coordinates aren't where you think they are.
Have you done the Space Shooter tutorial? It has a segment about shooting bullets.

Using Switch for Simple Unity3D Patrol Movement

I'm using a switch statement to create two movement types on an enemy: Forward, and Backwards. The enemy has three patrol points. When he begins, I want him moving from the first patrol point and adding 1 to the current point when he hits his second patrol point (empty 3D gameobject), and so on. Then I'll have him reverse direction when he hits the final point.
switch (moveType)
{
case MoveType.Forward:
if (transform.position == patrolPoints[currentPoint].position)
{
currentPoint ++;
}
break;
case MoveType.Backwards:
if (transform.position == patrolPoints[patrolPointsLength].position)
{
currentPoint --;
}
break;
}
The problem is, I can't figure out a way to "trigger" the two MoveTypes. How do I code this so that when the enemy hits his final patrol point, he switches to MoveType.Backwards? I'm sure I'm making this way harder than it needs to be. Thanks for the help!
This is how I would do it if I really wanted to use the switch statement:
float someSmallValue = 0.5f; // Adjust this as per your needs
if (Vector3.Distance(transform.position, patrolPoints[currentPoint].position) < someSmallValue)
{
switch (moveType)
{
case MoveType.Forward:
currentPoint++;
if (currentPoint > patrolPoints.Length - 1)
{
currentPoint -= 1;
moveType = MoveType.Backwards;
}
break;
case MoveType.Backwards:
currentPoint--;
if (currentPoint < 0)
{
currentPoint = 1;
moveType = MoveType.Forward;
}
break;
}
}
I think renaming currentPoint to targetPoint would make the variable name more clear for this chunk of code.
EDIT: I forgot to decrement currentPoint inside the Backwards case block. Updated my answer.
The solution I have here adds some things like a pause time. It also ensures that fast moving entities won't overshoot the destination and not turn around or something.
// Movement speed normalized. So 1 is instantaneous travel and zero is no movement.
public float movementSpeed = 0.025;
// Let's add a 'pause' time where the unit waits a while at the turning point.
public float waitTime = 1;
// Lets say the list has 5 points.
public List<Vector3> patrolPoints ...
// We keep track of our starting and ending points. Here we start at zero and move to position 1.
public Vector2 currentLeg = new Vector2(0,1);
// We use a coroutine
IEnumerator Patrol()
{
// This keeps track of where we are. 0 is at the starting point and 1 is at the destination.
float progress = 0;
while(true)
{
Vector3 startingPoint = patrolPoints[currentLeg.x];
Vector3 destination = patrolPoints[currentLeg.y];
// Please note this won't compile. It's for brevity. You must lerp x,y,z indiviualy in C#.
transform.position = Mathf.Lerp(startingPoint, destination, progress);
progress+= movementSpeed;
// If we are at our destination
if(progress >=1 )
{
// Reset our progress so wa can start over.
progress = 0;
// Our current point is now what our destination was before.
currentLeg.x = currentLeg.y;
switch(moveType)
{
case MoveType.Forward:
{
// If this condition is true then it means we are at the final point (4 in this case). So we invert the movement direction and set the current point to 3.
if(currentLeg.y == patrolPoints.Count()-1)
{
currentLeg.y -= 1;
moveType = MoveType.Backwards;
// We wait 1 seconds and then do everything again.
yield return new WaitForSeconds(waitTime);
}
else
currentLeg.y++;
}
break;
case MoveType.Backward:
{
// If this condition is true then it means we are at the starting point (0). So we invert the movement direction and set the current point to 1.
if(currentLeg.y == 0)
{
currentLeg.y += 1;
moveType = MoveType.Forward;
// We wait 1 seconds and then do everything again.
yield return new WaitForSeconds(waitTime);
}
else
currentLeg.y--;
}
break;
}
}
}
}
For a quick fix Jayson's answer will be better. But it might fail if the unit moves fast or the unit will stop too early if it moves too slow.
EDIT: The wait time was in the wrong place.
So you want to use a switch to patrol because only 1 enum can be selected at a time?
Why not use a public Transform target; variable and have your AI always follow whats in that variable? Then just make an empty game object and stick it into that variable and he will follow it wherever it goes. He wont be limited to "Forward" and "Backward", and you wont have to recode or be confused, when you want to recycle the code for an AI moving "Left" to "Right"
This will speed up execution, clean up your code, get rid of tons of lines of code as well, and you can still use your switch statement too, because this actually will open your code up to more dynamic abilities such as:
public enum ActionType
{
Patrol,
Veer,
Stop
}
Lets say hes patrolling and halfway to the target he spots an enemy, ActionType curAction; Can be set to ActionType.Veer , now he is veering off the patrol line to attack the enemy, and after you can set it back to ActionType.Patrol and he continues to the target.
So for patrolling you can set up a public List<Vector3> wayPoints; and just add a bunch of Vector3's in there. When he reaches the target, he can stop for a sec or two, then have the empty game object target jump to the next vector3 in the list.

Categories