Unity C# bool keeps turning true - c#

Very confused about what's going on. I will post code, but just a brief description of my game is a space invaders remix. I have a CPU that is currently moving on the X axis, stops when it hits -900f, then moves down on the Z axis. Now I am trying to get to to stop moving down on the Z axis (accomplished), then move in the opposite X direction is was previously going in (before the X axis was moving 7f every update, I want it to move -7f every update from that point forward). My problem is that now when it hits the designated Z axis to stop, then move on the X axis, it starts to move, but then keeps going back to -900 on the X axis. In my code below you will see that I have the program telling the transform.position.x to equal -900f, however, I put it inside an if loop that only run that code if a bool value is true, which I set to false after I want the program to ignore the code that shows the x position to -900f.
public class InvaderController : MonoBehaviour {
public float resistance;
public int resistcount;
public int numhits;
public float newX; //set to public so I can see it change in Unity, will go private
float newZ;
public float invaderSpeed; //this is set to 7 in Unity
public GameObject Invader;
Quaternion rotation;
public GameObject explosion;
int expcount;
bool firstxoff = false;
bool test = true;
public GameObject explosion2;
// Use this for initialization
void Start () {
}
void Awake() {
firstxoff = true;
}
// Update is called once per frame
void Update () {
if (firstxoff == true)
{
firstmove ();
}
}
void firstmove()
{
Vector3 newPos = transform.position;
newPos.x -= invaderSpeed;
//newX = newPos.x;
transform.position = newPos;
if (newPos.x < -900f)
{
Vector3 newPosZ = transform.position;
newPosZ.z -= invaderSpeed;
float x = -900f;
newX = x;
newPosZ.x = newX;
transform.position = newPosZ;
}
moveX1 ();
}
void moveX1()
{
Vector3 newPos = transform.position;
if (newPos.z < 500f)
{
Vector3 newPosX = transform.position;
newX = newX + invaderSpeed;
float z = 500f;
newZ = z;
newPosX.z = newZ;
newPosX.x = newX;
transform.position = newPosX;
if (newX > 800f)
{
firstxoff = false;
}
}
}
void FixedUpdate() //need to figure out how to run update first, then this.
{
//firstxoff = false;
}

First time z is less than 500, your x will increase 7, right?
newX = newX + invaderSpeed;
So you go from -900 to -893. -893 is not greater than 800, so firstxoff is not set to false. The firstmove method is then called again.
newPos.x -= invaderSpeed;
X is now -893 minus 7, which is -900. That cycle will repeat perpetually. Z will always be 500 and x will always be -900.
Hopefully you can figure out the solution. Let me know if not.

Related

Why when rotating the object on z axis it's rotating also the x and y and not setting z to 0?

I want the object to rotate only on z. To keep x and y and changing z to 0.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Whilefun.FPEKit;
public class PlayAnimation : MonoBehaviour
{
public List<GameObject> cameras = new List<GameObject>();
public GameObject head;
private Animator anim;
private bool started = true;
private float animationLenth;
private bool rotateHead = false;
// Start is called before the first frame update
void Start()
{
anim = GetComponent<Animator>();
}
private void Update()
{
if (FPESaveLoadManager.gameStarted == true && started == true)
{
FPEInteractionManagerScript.Instance.BeginCutscene();
anim.enabled = true;
anim.Play("Stand Up", 0, 0);
animationLenth = anim.GetCurrentAnimatorStateInfo(0).length;
StartCoroutine(AnimationEnded());
started = false;
}
if(rotateHead == true)
{
head.transform.rotation = Quaternion.Lerp(transform.rotation, Quaternion.Euler(transform.rotation.x, transform.rotation.y, 0f), 1.0f * Time.deltaTime);
}
}
IEnumerator AnimationEnded()
{
yield return new WaitForSeconds(animationLenth);
anim.enabled = false;
FPEInteractionManagerScript.Instance.EndCutscene();
rotateHead = true;
}
}
I'm trying to rotate the head.
When the animation is end the head rotation is : X = -9.922001 Y = 6.804 Z = 4.167
When the rotation of the head is ending or maybe it's never ending since it's in the update ? The head rotation is : X = -4.529 Y = -9.392 Z = 0.988 Why x and y change and z never get to 0 ?
Another strange thing I saw now the position of the transform on X when the animation is ended is -5.089218e-12 what is this e-12 ?
An example of what I said on Musaps answer:
using UnityEngine;
public class ExampleLerp: MonoBehaviour
{
public float Start = 2.0f;
public float End = 0.0f;
public float TimeToTravel = 3.0f;
private float elapsedTime = 0.0f;
private float inverseTime;
// Start is called before the first frame update
void Start()
{
inverseTime = 1.0f/TimeToTravel;
}
private void Update()
{
float ratio = 0.0f;
// Increment our elapsedTime
elapsedTime += Time.deltaTime;
if(elapsedTime > TimeToTravel)
{
ratio = 1.0f;
}
else
{
ratio = elapsedTime * inverseTime // Or can be done as elapsedTime/TimeToTravel
}
Debug.log("value is: " + Math.Lerp(Start, End, ratio));
}
}
By using the current roation, and using the same target rotation, and not storing your progress over time, you will see a slowdown as it approaches the end but it will never actually reach the end mathematically.
First of all, e-12 is 10^-12 or in your case, it is -0.000000000005089218. This occurs maybe because of the float math.
z does not get to 0 because you are using a lerp function without altering the interpolation ratio on the way. Lerp stands for linear interpolation. The third parameter it gets (1.0f * Time.deltaTime in your code) is the interpolation ratio. If this ratio was 0.5, the value of z would jump to the middle value of the difference (which is (0 - 4.167) * 0.5). For example; Lerp(0, 1, 0.5f) makes it jump to 0.5 in the next frame and 0.75 in the other frame.
Let's consider your game runs at 60 frames per second. That makes Time.deltaTime = 1/60. When Lerp starts executing in your code, z is 4.167 in the first frame. You want it to reach zero. The ratio of the interpolation is 1.0f * Time.deltaTime which is 0.01666... or 1/60. That means z will jump to 1/60 of the difference.
In the second frame, z reaches to (4.167 + (0 - 4.167) / 60) = 4.09755
In the third frame, z reaches to (4.09755 + (0 - 4.09755 / 60) = 4.0292575
You can overcome this by testing the z value against a tolerance value.
if (rotateHead)
{
const float end = 0f;
var rotation = transform.rotation;
var z = Mathf.Lerp(rotation.z, end, 1.0f * Time.deltaTime);
const float tolerance = 1f;
if (Math.Abs(z - end) < tolerance) z = 0;
head.transform.rotation = Quaternion.Euler(rotation.x, rotation.y, z);
}

Strange outputs for a moving platform in Unity

First off, sorry it this isn't written very well, I've spend hours debugging this and I'm very stressed. I'm trying to make a moving platform in unity that can move between way-points, I don't want to have to have tons of gameobjects in the world taking up valuable processing power though so I'm trying to use something I can just add to the script through the editor.
The only problem is that it seems to be doing this at an incredible speed:
Black = The Camera View, Blue = The platform and where it should be going based on waypoints, Red = What it is currently doing.
I've spend hours trying to find a fix but I have no idea why it's doing this.
My Script on the Platform:
public Vector3[] localWaypoints;
Vector3[] globalWaypoints;
public float speed;
public bool cyclic;
public float waitTime;
[Range(0, 2)]
public float easeAmount;
int fromWaypointIndex;
float percentBetweenWaypoints;
float nextMoveTime;
void Start()
{
globalWaypoints = new Vector3[localWaypoints.Length];
for (int i = 0; i < localWaypoints.Length; i++)
{
globalWaypoints[i] = localWaypoints[i] + transform.position;
}
}
void Update()
{
Vector3 velocity = CalculatePlatformMovement();
transform.Translate(velocity);
}
float Ease(float x)
{
float a = easeAmount + 1;
return Mathf.Pow(x, a) / (Mathf.Pow(x, a) + Mathf.Pow(1 - x, a));
}
Vector3 CalculatePlatformMovement()
{
if (Time.time < nextMoveTime)
{
return Vector3.zero;
}
fromWaypointIndex %= globalWaypoints.Length;
int toWaypointIndex = (fromWaypointIndex + 1) % globalWaypoints.Length;
float distanceBetweenWaypoints = Vector3.Distance(globalWaypoints[fromWaypointIndex], globalWaypoints[toWaypointIndex]);
percentBetweenWaypoints += Time.deltaTime * speed / distanceBetweenWaypoints;
percentBetweenWaypoints = Mathf.Clamp01(percentBetweenWaypoints);
float easedPercentBetweenWaypoints = Ease(percentBetweenWaypoints);
Vector3 newPos = Vector3.Lerp(globalWaypoints[fromWaypointIndex], globalWaypoints[toWaypointIndex], easedPercentBetweenWaypoints);
if (percentBetweenWaypoints >= 1)
{
percentBetweenWaypoints = 0;
fromWaypointIndex++;
if (!cyclic)
{
if (fromWaypointIndex >= globalWaypoints.Length - 1)
{
fromWaypointIndex = 0;
System.Array.Reverse(globalWaypoints);
}
}
nextMoveTime = Time.time + waitTime;
}
return newPos - transform.position;
}
struct PassengerMovement
{
public Transform transform;
public Vector3 velocity;
public bool standingOnPlatform;
public bool moveBeforePlatform;
public PassengerMovement(Transform _transform, Vector3 _velocity, bool _standingOnPlatform, bool _moveBeforePlatform)
{
transform = _transform;
velocity = _velocity;
standingOnPlatform = _standingOnPlatform;
moveBeforePlatform = _moveBeforePlatform;
}
}
void OnDrawGizmos()
{
if (localWaypoints != null)
{
Gizmos.color = Color.red;
float size = .3f;
for (int i = 0; i < localWaypoints.Length; i++)
{
Vector3 globalWaypointPos = (Application.isPlaying) ? globalWaypoints[i] : localWaypoints[i] + transform.position;
Gizmos.DrawLine(globalWaypointPos - Vector3.up * size, globalWaypointPos + Vector3.up * size);
Gizmos.DrawLine(globalWaypointPos - Vector3.left * size, globalWaypointPos + Vector3.left * size);
}
}
}
UPDATE: Upon further testing I found that if the first object in my localWaypoint array is set to 0,0,0 and my 2nd object is set to 1,0,0 then the platform will spiral to the right, making sure to hit the waypoints as it's spiraling, and then spiraling out into nowhere like in the image above. But if I set my first object to 0,0,0 and my second object to -1,0,0 then the object will act the same way as before, but will spiral to the left as displayed in this image. (The second image has also bee updated to display how the platfrom makes sure to hit both waypoints before is spirals out into nowhere).
I've also noticed that if I set both waypoints to 0,0,0 then the platform stays still, these 2 things prove that it has somthing to do with the way the waypoints are being handled and not some other script or parent object interfering.
Using the updated numbers ([0,0,0], [1,0,0]) works in my test app. However, if I put a rotation on the object's Y axis, then I see behavior like you are seeing. In Update, if you change:
transform.Translate(velocity);
to
transform.Translate(velocity, Space.World);
You should see your desired behavior. Note that "transform.Translate(velocity)" is the same as "transform.Translate(velocity, Space.Self)". Your translation is being rotated.
If you are curious, take a look at this for more information on how the values in the transform are applied:
https://gamedev.stackexchange.com/questions/138358/what-is-the-transformation-order-when-using-the-transform-class

Unity2D: Enemy doesn't follow Player when in its radius

Hey Guys I've been having a problem lately that I cant seem to solve.
A sprite is supposed to roam around (as it does) while nothing is inside its radius, however if the player moves close to it the sprite should theoretically move towards it and stop roaming.
The sprite doesn't follow the player and cant even see its tag since I cant even see the contents of the "Collider2D[] hits".
using System.Collections.Generic;
using UnityEngine;
public class FireCultist : MonoBehaviour
{
public float moveTimeSeconds; //Time it will take object to move, in seconds.
private float xMax = 10.0f; // The boundaries of the spawn area
private float yMax = 10.0f;
private float xMin = -10.0f; // The boundaries of the spawn area
private float yMin = -10.0f;
public int xDistanceRange; // The max distance you can move at one time
public int yDistanceRange;
private BoxCollider2D boxCollider; //The BoxCollider2D component attached to this object.
private Rigidbody2D rb2D; //The Rigidbody2D component attached to this object.
private float inverseMoveTime; //Used to make movement more efficient.
public Vector2 start;
public Vector2 end;
public bool roam = true;
public Collider2D[] hits;
void Start()
{
boxCollider = GetComponent<BoxCollider2D>();
rb2D = GetComponent<Rigidbody2D>();
inverseMoveTime = 1f / moveTimeSeconds;
InvokeRepeating("RandomMove", 0.0f, 5.0f);
}
void Update()
{
Collider2D[] hits = Physics2D.OverlapCircleAll(transform.position, 10); // returns all colliders within radius of enemy
int i = 0;
while(hits.Length > i)
{
Debug.Log("Sees");
Debug.Log(hits[i]);
i++;
}
followPlayer();
if (roam)
{
Debug.Log("Roam");
transform.position = Vector2.MoveTowards(transform.position, end, inverseMoveTime * Time.deltaTime); //Random move to new position
}
}
public void followPlayer()
{
foreach (Collider2D hit in hits)
{
if (hit.tag == "Player") // if the player is within a radius
{
Debug.Log("Chasing Player");
transform.position = Vector2.MoveTowards(transform.position, GameObject.Find("Prefabs/Player").GetComponent<Transform>().position, inverseMoveTime * Time.deltaTime); // chase player
roam = false;
}
else
{
Debug.Log("Continues");
roam = true; // Continue RandomMove()
}
}
}
public void RandomMove() // gets random coordinates near enemy and moves there
{
float xDistance = Random.Range(-xDistanceRange, xDistanceRange); // check
float yDistance = Random.Range(-yDistanceRange, yDistanceRange);// check
if (xDistance < xMax && xDistance > xMin && yDistance < yMax && yDistance > yMin && roam == true) // If within boundaries of walking space
{
start = transform.position;
end = start + new Vector2(xDistance, yDistance);
Debug.Log("Roaming From : " + start + " To : " + end);
}
}
}
The roaming algorithm works however not too sure about the tag detection.
The script belongs to this enemy object
Player Object Properties
It looks like you are declaring a new hits variable during every update instead of using your class-level variable. This means the variable inside of followPlayer() will never be instantiated, and the information will not be passed between the two methods.
Try this:
void Update()
{
hits = Physics2D.OverlapCircleAll(transform.position, 10);
//...
}
You might also consider attaching a trigger collider to the enemy which sends a notification when the player enters/exits the trigger instead of relying on OverlapCircleAll()
void OnTriggerEnter2D(Collider2D col)
{
if(col.gameObject.tag == "Player"){
roam = false;
}
}
void OnTriggerExit2D(Collider2D col)
{
if(col.gameObject.tag == "Player"){
roam = true;
}
}

How can I rotate the camera around group of objects and not only a single one?

The camera is child of one soldier only and also the target is this soldier.
And the script attached to the camera.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class CameraMove : MonoBehaviour
{
public Transform target;
public float speed = 0.1f;
// Use this for initialization
void Start ()
{
}
// Update is called once per frame
void Update ()
{
transform.RotateAround(target.transform.position, new Vector3(0, 1, 0), 100 * Time.deltaTime * speed);
}
}
But now I want to do two things. To make the camera to rotate around the whole soldiers and not only the specific one. And also to make the camera stop slowly when it's facing the soldiers. Now the camera is behind when starting the game.
Using a bool flag if true to make the camera rotate around the soldiers until it's facing them then stop rotation and keep moving with the soldiers.
If unchecked false make the camera rotating around the solders none stop.
UPDATE what I tried so far:
This code will make it rotating around all the soldiers and it's working fine:
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
public class CameraMove : MonoBehaviour
{
public float speed = 0.1f;
private List<GameObject> Soldiers = new List<GameObject>();
// Use this for initialization
void Start()
{
Soldiers.AddRange(GameObject.FindGameObjectsWithTag("Soldier"));
}
// Update is called once per frame
void Update()
{
RotateAround();
}
private void RotateAround()
{
transform.RotateAround(GetAverageLocationOfSoliders(), new Vector3(0, 1, 0), 100 * Time.deltaTime * speed);
}
private Vector3 GetAverageLocationOfSoliders()
{
var total = new Vector3();
foreach (var soldier in Soldiers)
total += soldier.transform.position;
return total / Soldiers.Count(); // Assuming Soldiers is List<Soldier>
}
}
Then I tried to add a slowDown bool flag variable, But I messed it all and it's not working at all.
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
public class CameraMove : MonoBehaviour
{
public float speed = 0.1f;
public bool slowDown = false;
private List<Vector3> SoldiersPositions = new List<Vector3>();
private List<Vector3> SoldiersFacingDirection = new List<Vector3>();
// Use this for initialization
void Start()
{
}
// Update is called once per frame
void FixedUpdate()
{
RotateAround();
}
private void RotateAround()
{
var getSoldiers = GameObject.FindGameObjectsWithTag("Soldier");
foreach (GameObject soldier in getSoldiers)
{
SoldiersPositions.Add(soldier.transform.position);
SoldiersFacingDirection.Add(soldier.transform.forward);
}
var Center = GetAverageLocationOfSoliders();
var FacingDirections = GetAverageFacingDirectionOfSoldiers();
if (slowDown == true)
{
var D = transform.position - Center;
var CamAngle = Vector3.Angle(D, FacingDirections);
speed = speed - CamAngle;
}
transform.RotateAround(Center, new Vector3(0, 1, 0), 100 * Time.deltaTime * speed);
SoldiersPositions = new List<Vector3>();
SoldiersFacingDirection = new List<Vector3>();
}
private Vector3 GetAverageLocationOfSoliders()
{
var total = new Vector3();
foreach (var soldier in SoldiersPositions)
total += soldier;
return total / SoldiersPositions.Count(); // Assuming Soldiers is List<Soldier>
}
private Vector3 GetAverageFacingDirectionOfSoldiers()
{
var total = new Vector3();
foreach (var soldierfacingdir in SoldiersFacingDirection)
total += soldierfacingdir;
return total / SoldiersFacingDirection.Count();
}
}
I'm not sure if the first code example only for the rotation is fine the way I wrote it. It's working but not sure if this is a good way to do the code ?
It seems to me that in the first code only the rotation the camera is a bit shaking or stuttering I mean the camera is not moving smooth when rotating around. It's almost hard to see in the game view in the editor but you can see it a bit in the scene view I think.
The reason I'm calling RotateAround(); in the Update is that the soldiers are in a move they are walking forward non stop.
How should I do the slowDown part ?
UPDATE 2:
This is the full coed now:
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
public class CameraMove : MonoBehaviour
{
[Header("Spin")]
public bool spin = false;
public Vector3 Direction;
[Range(0, 300)]
public float speed = 10f;
public bool randomSpeed = false;
public bool randomDirection = false;
[Range(0f, 100f)]
public float timeDirChange;
public Vector3 defaultDirection;
[Space(5)]
[Header("Move in circles")]
public bool moveInCircles = true;
public GameObject rotateAroundTarget;
public Vector3 axis;//by which axis it will rotate. x,y or z.
public float rotationSpeed; //or the speed of rotation.
public float upperLimit, lowerLimit, delay;// upperLimit & lowerLimit: heighest & lowest height;
public bool randomHeight = false;
public bool stopRotatingWhenFacing = false;
private float height, prevHeight, time;//height:height it is trying to reach(randomly generated); prevHeight:stores last value of height;delay in radomness;
[Space(5)]
[Header("Follow objects")]
public GameObject[] objectsToFollow;
public bool randomFollow;
private float nextRotationTime = 0f;
private int counter = 0;
private List<GameObject> Soldiers = new List<GameObject>();
// Use this for initialization
void Start()
{
Soldiers.AddRange(GameObject.FindGameObjectsWithTag("Soldier"));
}
private void Update()
{
if (randomSpeed)
{
speed = UnityEngine.Random.Range(0, 300);
}
if (spin)
{
if (randomDirection == false)
{
nextRotationTime = 0;
timeDirChange = 0;
Direction = defaultDirection;
}
else
{
if (Time.time > nextRotationTime)
{
nextRotationTime += timeDirChange;
RandomDirection();
}
}
transform.Rotate(Direction, speed * Time.deltaTime);
}
else
{
timeDirChange = 0;
randomDirection = false;
randomSpeed = false;
}
if (moveInCircles)
{
MoveInCircles();
}
}
private void RandomDirection()
{
Direction = new Vector3(UnityEngine.Random.Range(-1, 1), UnityEngine.Random.Range(-1, 1), UnityEngine.Random.Range(-1, 1));
while (Direction == new Vector3(0, 0, 0))
{
counter++;
Direction = new Vector3(UnityEngine.Random.Range(-1, 1), UnityEngine.Random.Range(-1, 1), UnityEngine.Random.Range(-1, 1));
if (counter == 2)
{
Direction = new Vector3(1, 0, 0);
break;
}
}
counter = 0;
}
private void MoveInCircles()
{
var F = GetAverageDirectionsOfSoliders();
var D = transform.position - GetAverageLocationOfSoliders();
var angle = Vector3.Angle(D, F);
if (angle < 5f)
{
rotationSpeed -= 0.1f;
}
transform.RotateAround(GetAverageLocationOfSoliders(), axis, rotationSpeed);
time += Time.deltaTime;
//Sets value of 'height' randomly within 'upperLimit' & 'lowerLimit' after delay
if (time > delay)
{
prevHeight = height;
if (randomHeight)
{
height = UnityEngine.Random.Range(lowerLimit, upperLimit);
}
time = 0;
}
if (randomHeight == false)
{
height = transform.position.y;
}
if (randomHeight)
{
//Mathf.Lerp changes height from 'prevHeight' to 'height' gradually (smooth transition)
transform.position = new Vector3(transform.position.x, Mathf.Lerp(prevHeight, height, time), transform.position.z);
}
else
{
transform.position = new Vector3(transform.position.x, height, transform.position.z);
}
}
private Vector3 GetAverageLocationOfSoliders()
{
var total = new Vector3();
foreach (var soldier in Soldiers)
{
total += soldier.transform.position;
}
return total / Soldiers.Count(); // Assuming Soldiers is List<Soldier>
}
private Vector3 GetAverageDirectionsOfSoliders()
{
var totalf = new Vector3();
foreach (var soldier in Soldiers)
{
totalf += soldier.transform.forward;
}
return totalf / Soldiers.Count();
}
}
The RotateAround part is working fine:
transform.RotateAround(GetAverageLocationOfSoliders(), axis, rotationSpeed);
But the slow down part is not working. It's not slowing down at all when the camera is facing the soldiers.
This is how I calculate the average transform.forward vector of all the soldiers:
private Vector3 GetAverageDirectionsOfSoliders()
{
var totalf = new Vector3();
foreach (var soldier in Soldiers)
{
totalf += soldier.transform.forward;
}
return totalf / Soldiers.Count();
}
Then inside the MoveInCircles method I did:
var F = GetAverageDirectionsOfSoliders();
var D = transform.position - GetAverageLocationOfSoliders();
var angle = Vector3.Angle(D, F);
if (angle < 5f)
{
rotationSpeed -= 0.1f;
}
But it's never getting to the line:
rotationSpeed -= 0.1f;
To rotate around all the soldiers:
Get the center of the all the soldiers (sum the world position of all soldiers and divide by N number of soldiers)
Get the maximum distance of the soldiers from the center
Rotate the camera about the center, and ensure that it is further than the max distance from the center
To slow the camera down when facing the soldiers' front:
Average out the transform.forward vector of all the soldiers. We call this vector F. This is fair since all your soldiers will typically be facing in the same general direction for this request to even make sense.
Calculate the direction D, which is the direction from the soldiers' center to the camera. This is easy: D = camera.transform.position - soldiersCenter
Finally, find the acute angle between D and F, using Vector3.Angle(). If this angle is lower than a certain threshold, decrease the moveSpeed of the camera.
The actual code is easy to write, but I'll let you practice. Let me know if you need any help
From the sounds of it, it seems you have it already able to orbit around a single soldier, so do to more than one, simply take the average of their locations.
Pseudo code:
transform.RotateAround(GetAverageLocationOfSoliders(), ...);
...
private static Vector3 GetAverageLocationOfSoliders
{
var total = new Vector3();
foreach(var soldier in Soldiers)
total += soldier.transform.position;
return total / Soliders.Count(); // Assuming Soldiers is List<Soldier>
}
Now, Vector3 might not have stuff like Vector3 += Vector3 or Vector3 / int, but if that's the case just create your own methods were you do that manually (adding vectorA.x + vectorB.x, and vectorA.x / num, etc.
As far as making the camera stop when it's in front, that's a bit trickier. You might want to do some checks first to make sure they all have the same rotation, and then check, each Update, if the look at rotation of the camera will point to one of the soldiers.
But, if you want it to slow down, then, instead of checking if the lookAtRotation can point to a soldier, check if it can point to some offset of the camera's rotation, like so:
Pseudo Code:
lookRotation(transform.Rotation + offset) // Use something like this to find Soldiers[0]
Then, if that finds one, you can use a Lerp on your speed to lerp back down to a speed of 0.
You will also have to maintain a List<Soldier> or Soldier[] somehow.

Add force to ball based on direction of camera

I am attempting to create a minigolf game but am having trouble solving how to calculate the direction to hit the ball. I am thinking that it is easiest to hit the ball in the forward direction that the camera is facing, but I get unexpected results after the first hit as the ball will not calculate the correct direction after hitting the first time. How can I set the direction for hitting the ball and then apply the force I am calculating?
This is my script attached to my ball object at the moment. Sorry for the messiness.
using UnityEngine;
using System.Collections;
using UnityEngine.UI;
public class Golfball : MonoBehaviour {
public GameObject ball = null;
public GameObject hole = null;
public GameObject cam = null;
public Text distance;
public Text score;
public Slider powerbar;
private int strokes = 0;
private bool isMoving = false;
private bool increasing = true;
private float distanceToHole;
public float minHitPower = 40.0f;
public float maxHitPower = 270.0f;
private float hitPower = 0;
private float powerIncrement = 5.0f;
private float powerMultiplier = 10;
private float ballRollTime = 0;
private Vector3 ballDir;
// Use this for initialization
void Start() {
distance.GetComponent<Text>().text = "Distance To Hole:" + distanceToHole;
ball.GetComponent<Rigidbody> ();
score.GetComponent<Text>().text = "Strokes:" + strokes;
}
// Update is called once per frame
void Update () {
//Allow the ball to be hit if the ball is not null, not currently moving, and the left mouse button is clicked.
if (ball != null) {
if (Input.GetButton("Fire1") && !isMoving) {
calculatePower ();
}
//Hit ball using power level and set ball to moving.
if (Input.GetButtonUp("Fire1"))
{/**********************************************
//Calculate direction to hit ball
ballDir = cam.transform.forward.normalized;
hitBall(hitPower);
isMoving = true;
}**********************************************/
//Detect when the ball stops
if (isMoving) {
ballRollTime += Time.deltaTime;
if (ballRollTime > 1 && GetComponent<Rigidbody> ().velocity.magnitude <= 0.5) {
GetComponent<Rigidbody> ().velocity = Vector3.zero;
GetComponent<Rigidbody> ().angularVelocity = Vector3.zero;
isMoving = false;
}
} else {
ballRollTime = 0;
}
}
//Calculate distance to hole
distanceToHole = Mathf.Round((Vector3.Distance(ball.transform.position, hole.transform.position) * 100f) / 100f);
distance.GetComponent<Text>().text = "Distance To Hole: " + distanceToHole;
Debug.DrawLine(ball.transform.position, ballDir, Color.red, Mathf.Infinity);
}
void calculatePower(){
//Increase power if it is less than the max power.
if (increasing)
{
if (hitPower < maxHitPower)
{
hitPower += powerIncrement * powerMultiplier;
increasing = true;
}
else if (hitPower >= maxHitPower)
{
increasing = false;
}
}
//Decrease power if power level is not increasing until the power hits the minimum level.
if(!increasing) {
//Debug.Log ("Not Increasing");
if (hitPower > minHitPower) {
//Debug.Log ("HitPower: " + hitPower);
hitPower -= powerIncrement * powerMultiplier;
} else if (hitPower <= minHitPower) {
increasing = true;
}
}
//Update the slider
powerbar.value = hitPower / powerMultiplier;
}
void hitBall (float power){
//Add force to the ball
//ball.GetComponent<Rigidbody>().AddForce(new Vector3(0, 0, power));
//Camera.main.transform.forward
ball.GetComponent<Rigidbody>().AddRelativeForce(ballDir * power);
//Increase stroke count
strokes++;
updateScore(strokes);
//Reset the power and power bar level to minimum default after hitting ball
hitPower = minHitPower;
powerbar.value = hitPower / powerMultiplier;
Debug.Log("HitPower Reset: " + hitPower);
}
void updateScore(int stroke)
{
score.GetComponent<Text>().text = "Strokes:" + stroke;
}
}
You'll have to apply the force like that:
ball.GetComponent<Rigidbody>().AddForce(ballDir * power, ForceMode.Impulse);
But you'll probably have to play with your 'power' variable.
Also note that you want to use impulse because you are hitting the ball and not applying force for some period of time.
The ballDir * power multiples the ballDir vector by your float number. You probably already know how it works, but here is the rundown:
scalarValue * new Vector(x0, x1, ..., xn) == new Vector(scalarValue * x0, scalarValue * x1, ... scalarValue * xn);]
You might also want to get rid of direction's y component so that your ball doesn't fly into the air (you are playing minigolf, right?)
ballDir.y = 0;

Categories

Resources