Attempting to create a 2D game where force is added to a RigidBody2D according to the rotation of the object.
The object is a projectile. Objects spawn at their intended rotation but only move right along the X axis instead according to the rotation.
Anyone know where I'm going wrong?
// Start is called before the first frame update
void Start()
{
myRB = gameObject.GetComponent<Rigidbody2D>();
timer = Time.time + lifetime;
}
private void FixedUpdate()
{
myRB.AddRelativeForce(transform.right * thrust);
if(Time.time > timer)
{
Destroy(this.gameObject);
}
}
transform.right is already
The red axis of the transform in world space.
with the orientation applied.
You are passing that in again as a Vector relative to the local space of the object which is not what you want.
Either use in world space
myRB.AddForce(transform.right * thrust);
or in local space
myRB.AddRelativeForce(Vector3.right * thrust);
Related
This is my current script it already makes the camera follow the players object. But the players object will get bigger as the game goes on and when it gets to big. It becomes very difficult to see. There are no errors I just don't know how to fix it, and I tried to find it online but I can't.
using UnityEngine;
using System.Collections;
public class CameraController : MonoBehaviour {
public GameObject player;
private Vector3 offset;
void Start ()
{
offset = transform.position - player.transform.position;
}
void LateUpdate ()
{
transform.position = player.transform.position + offset;
}
}
Depends ofcourse on how exactly your player "grows" but you could do something like e.g.
void Start ()
{
offset = (transform.position - player.transform.position) / player.transform.lossyScale.x;
}
void LateUpdate ()
{
transform.position = player.transform.position + offset * player.transform.lossyScale.x * someAdditionalFactor;
}
So the offset grows linear together with the size of the player object. Via the someAdditonalFactor you could e.g. say if the player grows to double size the offset should be multiplied by 4 (set the factor 2) or only 1.5 (set the factor 0.5) .. or just use 1 or leave it out.
Alternatively you could directly store and add the offset in the local space of the player using InverseTransformPoint and TransformPoint
void Start ()
{
offset = player.transform.InverseTransformPoint(transform.position);
}
void LateUpdate ()
{
transform.position = player.transform.TransformPoint(offset);
}
This way the offset is calculated automatically when the player changes its scale, rotation or position.
One approach you could use is to scale your offset vector by some value relative to the size of your player character.
void LateUpdate ()
{
transform.position = player.transform.position + (offset * GetAdjustmentValue());
}
private float GetAdjustmentValue() {
// Some code to determine the amount you want to shift the camera
// For example, if your player character is 50% bigger you might
// want to move the offset 10% further out so you would return 1.1
// By default, you would return 1, so that no scaling occurs.
// The details of this calculation really depend on how you are changing
// the size of your character and what specific effect you want that to have
// on your camera position
}
Another approach could be to have fixed positions for your camera depending on the character size. These could be empty GameObjects that are children of your player character. Then, when your player grows, you could set the camera transform.position = bigCharacterPositionObject.transform.position.
I am trying to create a script in Unity that when another object touches it, it grabs the object, rotates it in a random direction, and launches it, but I only want to rotate and launch the other object on the z axis.
Here is my script:
public BallController ballController;
private GameObject ball;
private Rigidbody2D ballRb;
void OnTriggerEnter2D(Collider2D other)
{
ball = other.gameObject;
ballRb = ball.GetComponent<Rigidbody2D>();
ball.transform.position = this.transform.position;
// Freeze the ball
ballRb.velocity = Vector2.zero;
// Rotate the ball
ball.transform.rotation = Quaternion.Euler(0, 0, Random.Range(0, 360));
// Start moving the ball again
ballRb.velocity = ballRb.velocity * ballController.bulletSpeed * Time.deltatime;
}
The other script (The ball) is has a Ridgidbody and is launched by another object into this one, the script gets the ball to rotate how I want to, but it won't get the ball moving again.
The ballController is set in the editor and the bulletSpeed is just an int that I want the ball to travel at (currently set to 6).
When dealing with Rigidbody2D you shouldn't use the transform for setting the rotation but rather use ballRb.rotation.
Later you are using
ballRb.velocity = ballRb.velocity * ballController.bulletSpeed * Time.deltatime;
but right before you have set
ballRb = Vector2.zero;
So the multiplication results in Vector2.zero. Also adding Time.deltaTime(typo btw) in this one-time assignment makes no sense.
Also if you remove this line you are not taking the new rotation into account when assigning a new velocity.
The velocity is in global space. You also can't use e.g. transform.right as new direction since the transform isn't updated .. the Rigidbody2D is .. so you can use GetRelativeVector in order to set the new local direction after rotating
private void OnTriggerEnter2D(Collider2D ball)
{
// The assignment of the GameObject
// was kind of redundant except
// you need the reference for something else later
var ballRb = ball.GetComponent<Rigidbody2D>();
// set position through RigidBody component
ballRb.position = this.transform.position;
// Rotate the ball using the Rigidbody component
// Was the int overload intented here? Returning int values 0-359
// otherwise rather use the float overload by passing float values as parameters
ballRb.rotation = Random.Range(0f, 360f);
// Start moving the ball again
// with a Vector different to Vector2.zero
// depending on your setup e.g.
ballRb.velocity = ballRb.GetRelativeVector(Vector2.right * ballController.bulletSpeed);
}
little demo
for the walls btw I used something very similar:
var ballRb = ball.GetComponent<Rigidbody2D>();
var newDirection = Vector2.Reflect(ballRb.velocity, transform.up);
ballRb.rotation = ballRb.rotation + Vector2.SignedAngle(ballRb.velocity, newDirection);
ballRb.velocity = newDirection.normalized * ballController.bulletSpeed;
screenshot hereI want to clamp Y-axis on a cube. I can do it in Unity camera. But, it does not react correctly when I am using it in Vuforia camera.
My problem was that the cube follows the camera. I would like the cube to stay in its position and ignore the AR camera position. I sense it has something to do with WorldtoViewpoint but I cannot figure it out. Can you teach me how to do this please? thankyou
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class ClampMovementController : MonoBehaviour
{
// Start is called before the first frame update
void Start()
{
}
// Update is called once per frame
void Update()
{
Vector3 pos = transform.localPosition;
pos.y = Mathf.Clamp(transform.position.y, 0f, 0f);
transform.localPosition = pos;
}
}
This is my solution:
Actually its very simple. The INcorrect concept was my object attached to the AR camera, hence, object position is always moving related to camera position. Now. In order to make the object stays in its place. I need to get its localPosition. First. Store the localposition in Vector3 pos. And then do modification on Vector3 pos. At last, reassign the new value to the object localposition.
public class ClampMovementController : MonoBehaviour
{
public float currentPos;
public GameObject capsule;
void Update()
{
//store the value of object localPosition
Vector3 pos = capsule.transform.localPosition;
//modification on the value
pos.y = Mathf.Clamp(pos.y, currentPos, currentPos);
//rerassign the new value to the object localPosition
capsule.transform.localPosition = pos;
}
}
First of all your cube is moving with the camera because your image target is child of your ARCamera. Therefore, when you move the camera image target moves, then your cube moves as well. Make sure your ImageTarget has no parent.
I did not understand why you have to lock any movement in Y axis. I guess you are doing something wrong with lean touch when you move object. I have not used lean touch but i have achieved this with keyboard inputs. You can convert it to lean touch by modifying following script. Just add these line to your ImageTarget's DefaultTrackableEventHandler script:
//Variables for getting capsule and checking if ImageTarget is tracked
private bool isTracked = false;
private GameObject capsule;
Then create an Update method for getting input from user like this.
void Update()
{
if(isTracked)
{
if(Input.GetKey(KeyCode.W))
{
//using forward for moving object in z axis only.
//Also using local position since you need movement to be relative to image target
//Global forward can be very different depending on your World Center Mode
capsule.transform.localPosition += Vector3.forward * Time.deltaTime;
}
else if (Input.GetKey(KeyCode.S))
{
capsule.transform.localPosition -= Vector3.forward * Time.deltaTime;
}
if (Input.GetKey(KeyCode.A))
{
//Using Vector3.left and right to be make sure movement is in X axis.
capsule.transform.localPosition += Vector3.left * Time.deltaTime;
}
else if (Input.GetKey(KeyCode.D))
{
capsule.transform.localPosition += Vector3.right * Time.deltaTime;
}
}
}
As you can see there is no movement in Y axis because i used forward, left and right vectors to make sure movement in in only X and Y axis.
Last you have to make sure isTracked is updated. In order to do that you have to add isTracked = false; in OnTrackingLost method and isTracked = true; in OnTrackingFound method. Good luck!
I have a first person rigidbody capsule that rotates so that he will always be upright against the gravity direction. I want to rotate my player to the side so that the player camera will not rotate vertically.
My code is,
void Update() {
FixOrientation();
}
void FixOrientation()
{
if (trans.up != -GetGravityDirection())
{
Quaternion targetRotation = Quaternion.FromToRotation(trans.up, -GetGravityDirection()) * trans.localRotation;
trans.localRotation = Quaternion.RotateTowards(trans.localRotation, targetRotation, 5f);
}
}
The result is,
In the image above, I changed the gravity direction to point to the ceiling.
This code only rotates the player at the global x-axis no matter where he is facing which means when i'm facing global forward or backward, the player will rotate vertically the camera. What I want is for it to rotate on the side(local z axis).
Unity already has a method for exactly that: Transform.Rotate has an overload taking an angle and a rotation axis.
It might look like
// rotation speed in degrees per second
public float RotationSpeed;
void Update()
{
FixOrientation();
}
void FixOrientation()
{
if (transform.up != -GetGravityDirection())
{
// Get the current angle between the up axis and your negative gravity vector
var difference = Vector3.Angle(transform.up, -GetGravityDirection());
// This simply assures you don't overshoot and rotate more than required
// to avoid a back-forward loop
// also use Time.deltaTime for a frame-independent rotation speed
var maxStep = Mathf.Min(difference, RotationSpeed * Time.deltaTime);
// you only want ot rotate around local Z axis
// Space.Self makes sure you use the local axis
transform.Rotate(0, 0, maxStep, Space.Self);
}
}
A Sidenote:
Just in general be careful with the direct comparison of two Vectors
trans.up != -GetGravityDirection()
uses an approximation of 0.00001. In your case that should be fine anyway but for comparing you should rather use
Vector3.Angle(vector1, vector2) > threshold
to define a wider or stronger threshold
How do I make my GameObject move towards another GameObject using Vector3.MoveTowards method?
Heres my current code:
void update()
{
TargetObject.transform.position = Vector3.MoveTowards (TargetObject.transform.position, Cube.transform.position , MaxDistanceDelta);
}
void Update() {
myGameObject.transform.position = Vector3.MoveTowards(myGameObject.transform.position, targetObject.transform.position, Time.deltaTime * speed);
}
myGameObject - object you want to move
targetObject - object you are moving to
speed - float value to set the speed
First, let's see the details and parameters of the method:
MoveTowards(Vector3 current, Vector3 target, float maxDistanceDelta);
Understanding the parameters
Vector3 current: 3D vector of the object position (example: new Vector(0,0,1))
Vector3 target: 3D vector of the target position (example: new Vector(3,4,5))
maxDistanceDelta: maximum distance that the object will move when the method is called. (Example: if maxDistanceDelta is 1, the object will move 1 unit every time it's called. In case we are not using Time.deltaTime it would move 50 units a second if the frame rate is 50)
Note: If the actual distance remaining is less than maxDistanceDelta, it will be placed on target position. Meaning the object will no longer move unless the target position changes.
Example:
Declaring the variables:
public float speed;
public Transform target;
Using the method:
transform.position = Vector3.MoveTowards(
transform.position,
target.position,
speed * Time.deltaTime
);