Object coordinates not updating as expected - c#

I'm having an issue with a prefab I'm instantiating in my script. What I'm attempting to do is simulate the physics behind the projectile motion of a cannonball. I have the following script attached to my prefab:
using UnityEngine;
using System.Collections;
public class ShootPhysics : MonoBehaviour {
// vectors & angles to be calculated
private float fx = 0f;
private float fy = 0f;
private float angle;
// forces acting upon object
private float gravity = 9.8f;
private float force = 1.2f;
// new distance & vector variables
private float dis_x = 0f;
private float dis_y = 0f;
// Script & CannonBall transform
private CannonPhysics cannon_angle;
void Start() {
cannon_angle = GameObject.FindWithTag("Gun").GetComponent<CannonPhysics>();
angle = cannon_angle.getAngle ();
fx = Mathf.Round (force * Mathf.Cos(Mathf.Deg2Rad * angle));
fy = Mathf.Round (force * Mathf.Sin(Mathf.Deg2Rad * angle));
}
void FixedUpdate() {
dis_x = (float)(fx * Time.timeSinceLevelLoad);
dis_y = (float)(fy + Time.timeSinceLevelLoad + (0.5) * (-gravity) * Time.timeSinceLevelLoad * Time.timeSinceLevelLoad);
Debug.Log (dis_x+", "+dis_y);
gameObject.transform.Translate (new Vector2(dis_x, dis_y));
}
}
And the prefab will be instantiated from the following script:
using UnityEngine;
using System.Collections;
public class CannonPhysics : MonoBehaviour {
// This will be our script to rotate our cannon
private float angle = 0f;
// cannonball object
public Transform FirePoint;
GameObject cannon = null;
void Update() {
if(Input.GetKey(KeyCode.UpArrow)) {
angle = angle + 1;
}
if(Input.GetKey(KeyCode.DownArrow)) {
angle = angle - 1;
}
// update cannon angle
transform.rotation = Quaternion.Euler (new Vector3(0, 0, angle));
if(Input.GetMouseButtonDown(0)) {
CreateCannon();
}
}
public float getAngle() {
return angle;
}
private void CreateCannon() {
cannon = Instantiate (Resources.Load("Prefabs/CannonBall"), FirePoint.position, FirePoint.rotation) as GameObject;
Destroy (cannon, 3f);
}
}
The object gets instantiated as it should, and the object is destroyed after 3 seconds as it should, however the object x and y position do not change at all, and are not what i should expect them to be. Let me give you an example:
These are the x and y coordinates i should expect which i have displaying in the console.
However these are the actual coordinates displayed in Unity's inspector:
What's strange too, is that these coordinates will not change for each object, they will literally stay the same, even after the object has been destroyed. Can anyone explain why this is happening? And perhaps offer a solution?
Edit: For a more clear example:
Each time i instantiate my cannonball object the x and y coordinates for the next object to be instantiated are referenced from the last. Here are the result of my first instantiated object after being destroyed.
And here they are after instantiating a second object.
Now what I'm expecting is that each new object instantiated should start from it "original" position (figuratively speaking) and the x and y values should reset and start again effectively.

There are a few things happening in the code you have provided in the FixedUpdate() portion of your code which I have copied below:
void FixedUpdate()
{
dis_x = (float)(fx * Time.timeSinceLevelLoad);
dis_y = (float)(fy + Time.timeSinceLevelLoad + (0.5) * (-gravity) * Time.timeSinceLevelLoad * Time.timeSinceLevelLoad);
Debug.Log (dis_x+", "+dis_y);
gameObject.transform.Translate (new Vector2(dis_x, dis_y));
}
First, Time.timeSinceLevelLoad provides you the time, in seconds, that has passed since your level was loaded. What this means for your code is that dis_x and dis_y always have larger values the longer you have your application open. So, when you spawn a new prefab, the d_x and d_y values are already at a position that seems as if it's using the position of the last prefab.
Instead, if you want to calculate the new position of an object given it's velocity, you'd typically want to use the deltaTime instead. For example:
dx = vel.x * Time.fixedDeltaTime;
dy = vel.y * Time.fixedDeltaTime;
In this example, dx and dy represent the change in position given the velocity of the object. Time.fixedDeltaTime represents the amount of time in seconds that has passed since the last time FixedUpdate() was called. You would then add dx and dy to your position to get the new position.
Secondly, gameObject.transform.Translate() translates the position of the GameObject; it does not set the position of the GameObject. Translate will just add the Vector3 to your current position. This is why your debugging output looks so strange; dis_x and dis_y are not your positions; they are how far you moved the GameObject by calling Translate().
To set the position of the GameObject, do this instead:
gameobject.transform.position = newPosition;
...where newPosition is a Vector3 that represents the new position of your gameobject.

Related

When I make an object face a mouse cursor in Unity it eventually offsets

I made a script that makes the player point towards the mouse cursor, but recently I discovered a bug. When I move the mouse cursor too much (An example being when I spin the mouse around the object in circles, causing the object to move around.), the object ends up pointing a bit off of where the mouse should be. As in, the cursor would signal the object to look at it, and the object ends up looking the slightest bit off, making it feel quite odd after maneuvering quickly. How can I make it so the object always faces the cursor, with no offsets, even when I move the cursor as much as possible.
private void LateUpdate()
{
Vector3 lookAtPoint = Camera.main.ScreenToWorldPoint(Input.mousePosition);
Vector3 mousePoint = new Vector3(lookAtPoint.x, lookAtPoint.y, 0);
float angle = getAngle(transform.position, mousePoint);
transform.rotation = Quaternion.Lerp(transform.rotation, Quaternion.Euler(0, 0, angle), 9f * Time.deltaTime);
float getAngle(Vector3 currentLocation, Vector3 mouseLocation)
{
float x = mouseLocation.x - currentLocation.x;
float y = mouseLocation.y - currentLocation.y;
return angle = Mathf.Rad2Deg * Mathf.Atan2(y, x);
}
}
Looks like it's down to the way that you are using Quaternion.Lerp(). In particular, the last parameter - it is meant to be a value between 0f and 1f which you supply, it does not auto-increment for you.
So to fix this issue, what you want to do is save off a float somewhere. When you move the mouse (mouse position has changed since last frame) then start that value at 0f again. Then increment it at some value every frame until it is equal to or greater than 1f.
Doing this will not only fix your bug. It will, depending on how fast your increment, give you a smooth rotation effect. Below is an example.
internal class SomeClass : MonoBehaviour
{
private float lerpAmount = 0f;
private Vector3 cachedMousePosition = Vector3.zero;
private void LateUpdate()
{
var mousePosition
= Camera.main.ScreenToWorldPoint(Input.mousePosition)
* new Vector3(1, 1, 0);
bool recalculateRotation = false;
if (this.cachedMousePosition != mousePosition)
{
this.lerpAmount = 0f;
recalculateRotation = true;
}
if (this.lerpAmount < 1f)
{
this.lerpAmount = Mathf.Min(this.lerpAmount + Time.deltaTime, 1f);
recalculateRotation = true;
}
if (recalculateRotation)
{
float angle = getAngle(transform.position, mousePoint);
transform.rotation = Quaternion.Lerp(transform.rotation, Quaternion.Euler(0, 0, angle), this.lerpAmount);
}
float getAngle(Vector3 currentLocation, Vector3 mouseLocation)
{
float x = mouseLocation.x - currentLocation.x;
float y = mouseLocation.y - currentLocation.y;
return angle = Mathf.Rad2Deg * Mathf.Atan2(y, x);
}
}

Unity: Move camera based on forward horiz direction without changing y position

I'm creating a Google Cardboard VR app in Unity. I want the camera to constantly move forwards horizontally in the direction the camera is facing but not change its Y position, i.e. not rise or fall.
I've managed to get it so that the camera moves forwards in whichever direction it's looking but can go up and down if you look that way, using this line of code:
transform.position = transform.position + cam.transform.forward * WalkingSpeed * Time.deltaTime;
Is there a simple way of fixing the Y axis, so that I get the behaviour I'm looking for? Here's the full code so far:
using UnityEngine;
using System.Collections;
public class CameraMovement : MonoBehaviour {
public float WalkingSpeed = 1.0f;
public bool WalkEnabled = true;
GameObject cam;
void Start () {
// This is the part of the Cardboard camera where I'm getting
// the forward position from:
cam = GameObject.FindWithTag("CCHead");
}
void Update ()
{
if (WalkEnabled)
{
walk();
}
}
void walk()
{
transform.localPosition = transform.localPosition + cam.transform.forward * WalkingSpeed * Time.deltaTime;
}
}
Note: ticking the 'freeze position' y value in rigidbody constraints doesn't work.
Many thanks in advance.
You can try and split the forward vector up and build a new one where the y axis does not change:
transform.position =
transform.position +
new Vector3(
cam.transform.forward.x * WalkingSpeed * Time.deltaTime,
0, // add 0 to keep the y coordinate the same
cam.transform.forward.z * WalkingSpeed * Time.deltaTime);

Adding additional vertical velocity in projectile motion Unity3D

I have my point of projectile at some height above ground and my enemy(that are moving from right to left and towards the shooting point at horizontal axis) are at ground.The projectile motion that I have it shoots directly in downward motion at angle facing the enemy but I want the projectile to first go upwards and then shoot the enemy.
I have attached the snapshot below:
Here is my code:
using UnityEngine;
using System.Collections;
public class bullet : MonoBehaviour {
public Transform target;
private Transform mytransform;
public GameObject bulletprefab;
public GameObject enemyprefab;
private gamenemy e;
public float firingAngle = 20;
public float gravity = 9.8f;
void Awake()
{
mytransform = transform;
}
// Use this for initialization
void Start () {
mytransform.LookAt(target);
StartCoroutine (project ());
//follow();
}
IEnumerator project()
{ yield return new WaitForSeconds(0.25f);
float target_Distance = Vector3.Distance(mytransform.position * target_Distance , target.position);
// Calculate the velocity needed to throw the object to the target at specified angle.
float projectile_Velocity = target_Distance / (Mathf.Sin(2 * target_Distance * Mathf.Deg2Rad) / gravity);
// Extract the X Y componenent of the velocity
float Vx = Mathf.Sqrt(projectile_Velocity) * Mathf.Cos(target_Distance * Mathf.Deg2Rad);
float Vy = Mathf.Sqrt(projectile_Velocity) * Mathf.Sin( 1/target_Distance * Mathf.Deg2Rad);
// Calculate flight time.
float flightDuration = target_Distance / Vx;
// Rotate projectile to face the target.
mytransform.rotation = Quaternion.LookRotation(target.position - mytransform.position);
float elapse_time = 0;
while (elapse_time < flightDuration)
{
mytransform.Translate(0, (Vy - (gravity * elapse_time)) * Time.deltaTime, Vx * Time.deltaTime);
elapse_time += Time.deltaTime;
yield return null;
}
}
Snapshot of how it is with given code:
This is how I want it to be:
Rather than calculating the movement in your code, look at using a Rigidbody on your projectile. Then at the point of firing, apply a force relative to the initial trajectory (i.e direction the gun barrel is facing) and also have gravity affect your bullet.
More on Rigidbodies

Unity rotate while moving forward

I have the following code for my 2D game, it makes object randomly wonder on the screen. What I am having issues with, is when an object looks at the point it is going to, I would like it to rotate as it moves forward. What is happening now, is it rotates instantly to the point it is going towards. So, how can I get it to rotate slowly and move forward at the same time?
using UnityEngine;
using System.Collections;
public class Wonder : MonoBehaviour {
protected Vector2 wayPoint;
protected float speed;
// Use this for initialization
void Start () {
speed = gameObject.GetComponent<Move>().playerSpeed;
wonder();
}
void wonder(){
wayPoint = Random.insideUnitCircle * 10;
}
// Update is called once per frame
void Update () {
Vector2 dir = wayPoint - new Vector2(transform.position.x, transform.position.y);
float angle = Mathf.Atan2(dir.y, dir.x) * Mathf.Rad2Deg;
transform.rotation = Quaternion.Euler(new Vector3(0, 0,Mathf.Atan2 (dir.y, dir.x) * Mathf.Rad2Deg - 90));
transform.position = Vector2.MoveTowards(transform.position, wayPoint, Time.deltaTime * speed);
float magnitude = (new Vector2(transform.position.x, transform.position.y) - wayPoint).magnitude;
if(magnitude < 3){
wonder();
}
}
}
Here is an example Image:
So, once the ship gets to its point another will be created and it will move there. I am thinking I will have to have a list of 5+ points, then calculate the arch the ship needs to take adding new points as the ship hits a way point then removing old ones after. I am not sure how to do this though...
using UnityEngine;
using System.Collections;
public class Wander : MonoBehaviour {
protected Vector3 velocity;
protected Vector2 waypoint;
protected float speed;
// Use this for initialization
void Start () {
speed = gameObject.GetComponent<Move>().playerSpeed;
RandomizeWaypoint();
}
void RandomizeWaypoint(){
waypoint = Random.insideUnitCircle * 10;
}
// Update is called once per frame
void Update () {
transform.position = Vector3.SmoothDamp( transform.position, waypoint, ref velocity, Time.deltaTime * speed );
transform.rotation = Quaternion.AngleAxis( Mathf.Atan2( velocity.y, velocity.x ) * Mathf.Rad2Deg, Vector3.forward );
if( Vector3.Distance( transform.position, waypoint ) < 3 ){
RandomizeWaypoint();
}
}
}
Untested. Vector3.SmoothDamp can be pretty handy. Note the spelling also.

Rotate cameran around a gameobject in unity3d

I want to rotate camera around an fbx object when a key is being pressed using unity 3d.How it do? I tried some examples but its not working. First i create a game object and add main camera child of it.
public class CameraOrbit : MonoBehaviour
{
public Transform target;
public float speed = 1f;
private float distance;
private float currentAngle = 0;
void Start()
{
distance = (new Vector3(transform.position.x, 0, transform.position.z)).magnitude;
}
void Update()
{
currentAngle += Input.GetAxis("Horizontal") * speed * Time.deltaTime;
Quaternion q = Quaternion.Euler(0, currentAngle, 0);
Vector3 direction = q * Vector3.forward;
transform.position = target.position - direction * distance + new Vector3(0, transform.position.y, 0);
transform.LookAt(target.position);
}
}
I dont have access to unity at the moment so i might have messed something up.
The idea is keep an angle that you change based on input. Create a Quaternion from the angle (the Quaternion say how to rotate a vector to a certain direction), then rotate a Vector to that direction. Starting from the targets position move in that direction a certain distance and then look at the targets position.
This only implements rotation around the y axis, if you want rotation around the x axis all you need is another angle variable and then change to this Quaternion.Euler(currentAngleX, currentAngleY, 0);

Categories