Unity3d - Random Start direction and ForceMode.Impulse? - unity3d

I have a cube. A script is attached to it. I want, that the cube gets an impulse at the start in a random direction. My problem is the addForce. I don't know what to add there.
public Transform myObject;
void Start () {
Vector3 randomDirection = new Vector3(0f,0f,Random.Range(-359, 359));
myObject.Rotate (randomDirection);
myObject.rigidbody.AddForce(transform.?????? * speed, ForceMode.Impulse);
}

For random you want
myObject.rigid body.AddForce(Random.Range(0, 10), Random.Range(0, 10), Random.Range(0, 10), ForceMode.Impulse);
The code is saying, give me a random force value for the x, y, z.
Rotation has nothing to do with it. If you push a cat from a random Angle, you add force to the cat. You don't need to rotate the cat to push it. Although you shouldn't go around pushing cats.
If you insist on random rotation then make your object fire off forwards:
myObject.rigid body.AddForce(myObject.transform.forward * speed, ForceMode.Impulse);

transform.forward is a property on Transform that represents the direction the object is facing. In the Editor, it is represented by the blue axis on the object's transform handle.
If you use it in your script, the object will have a force applied to it in the random direction determined by the myObject.Rotate(...) line.

Related

How can I rotate an Object around the camera (angle)?

What I want to do is spawn an object in front of the camera and the side I am looking at. When I change the rotation of the camera (looking at a different side), the object is still spawned at the same position. How can I change this (that the Object also changes his angle)?
public void Create(Object myPrefab)
{
Vector3 instantGO = Camera.main.transform.position + new Vector3(0, 0, 7);
Instantiate(myPrefab, instantGO, Quaternion.identity);
}
Use transform.forward - this gives a position relative to the transform e.g. Camera.main.transform.position + (Camera.main.transform.forward * 5) for 5m in front of the cam.
The forward and left properties return a vector of magnitude one, pointing in the direction the transform is facing, or to it's left. You can use -forward and -left to align backwards or to the right. Add this to the position of the object and multiply it to give a position a number of units away. In recent versions of Unity you also have transform... up, down, right etc.
Use this Instantiate variant:
Instantiate(Object original, Vector3 position, Quaternion rotation, Transform parent);
And pass the Camera transform as the parent parameter. This will make the new object a child of the camera and thus always moves/rotates with the camera.

Only rotate one axis on Unity gameobject

I have inherited some code that simply does this....
transform.rotation = m.rotation;
I know that my model will always be standing upright and therefore it only needs to rotate around on one axis. How can I only change the Y rotation.
I can't seem to get this to work because I get stuck right away when I try:
transform.rotation = Quaternion.Euler(m.rotation.x, m.rotation.y, m.rotation.z);
Which does not align it the same as:
transform.rotation = m.rotation;
I was hoping to then just change the m.rotation.y. Any reason this doesn't work?
The m value looks like this
public MarkerInfo(string name, bool isVisible, Vector3 position, Quaternion rotation, Vector3 scale){
this.name = name;
this.isVisible = isVisible;
this.position = position;
this.rotation = rotation;
this.scale = scale;
}
If m stands for a c# class and not a uniy one, changing its rotations will have no effect. You need to apply your rotation to a unity Transform, that normally is an instance of a component of a gameobject of the scene. That way you can see in the scene the changes you apply to the transform of that specific gameobject.
I think you need to know what unity gameobject does MarkerInfo manipulate or stands for, get its Transform with gameObject.transform and rotate that.
With transform.RotateAround or manipulating directly yout transform's Transform.eulerAngles you should be able to get your rotation.
Take into account that this line: transform.rotation = Quaternion.Euler(m.rotation.x, m.rotation.y, m.rotation.z); you are trying wont do what I think you think it does. The x,y,z of a quaternion are not the euler angles.
To apply that rotation to the transform you need to do transform.rotation = m.rotation, so the fact those line do not do same make perfect sense.
The best ways to do this are by using Quaternion.Euler, which converts a Vector3 to a Quaternion (Unity's confusing variable for storing rotation), or by using Quaternion.Set, which sets the values of a Quaternion similar to Vector3.Set. The first one has 2 declarations: 1 where you pass a vector3 variable, and another where you pass 3 ints/floats. The following 2 lines of code both do the same thing using both declarations.
transform.rotation += Quaternion.Euler(Vector3.up);
transform.rotation += Quaternion.Euler(0, 1, 0);
The second method works like this (I don't know what the fourth one does, but it's typically 1):
// transform.Set(x, y, z, 1);
transform.Set(0, 45, 0, 1);
transform.Set(transform.x + 1, transform.y, transform.z, 1);
Quaternions are confusing and annoying at first, but Unity comes with a lot of fancy rotation-focused functions that coultn't be possible without them. You can use Quaternion.Euler to convert a Vector3 to a Quaternion and then use those functions on them. They could come in handy later. You can find them here under "public/static methods".
I suppose you want player to have same forward vector as other object but keep the original up vector?
I would avoid Euler Angles as much as possible because they are "glitchy" and try like that:
var forward = m.forward;
forward.y = 0;
transform.rotation = Quaternion.LookRotation(forward, Vector3.up);
just resolve the case
m.forwad == Vector3.down || m.forward == Vector3.up
and it should be working

Unintended player movement from transform.InverseTransformDirection

this is my first time posting on here. I'm working on a game using the new Unity multiplayer networking solution.
In summary, the issue is that the player is not moving as intended.
I am trying to take player input as follows:
Vector3 worldSpaceDir = new Vector3(Input.GetAxisRaw("Vertical"), 0, Input.GetAxisRaw("Horizontal"));
then convert it to the object space coordinates of the player character:
_inputDirection = transform.InverseTransformDirection(worldSpaceDir);
The issue I'm having is with a rotation of 0 or 180 the player moves as expected with the WASD inputs, however, at 90 or 270 all the inputs are flipped(A = right, D = left, W = backward, S = forward).
I found a question that is exactly my question but no one responded with an answer. The question is quite old now so I wanted to ask it again for more visibility.
Here's a link to the original question.
Firstly, you are taking the worldSpaceDir wrong, it should be as follow
Vector3 worldSpaceDir = new Vector3(Input.GetAxisRaw("Horizontal"), 0, Input.GetAxisRaw("Vertical"));
here we take horizontal input as X and vertical input as Z, because in Unity Forward is pointed as Z and not Y.
Secondly, we do not need to use InverseTransformDirection() we just need TransformDirection() something like following
Vector3 inputDirection = transform.TransformDirection(worldSpaceDir);
here we are telling unity to convert the worldSpaceDir that is relative to transform (local direction) into a world space direction, so we might actually give a proper name to worldSpaceDir.
The following would work for you.
private void Update() {
Move();
}
private void Move() {
Vector3 directionToMove = new Vector3(Input.GetAxisRaw("Horizontal"), 0, Input.GetAxisRaw("Vertical"));
Vector3 inputDirection = transform.TransformDirection(directionToMove);
transform.position += inputDirection * Time.deltaTime;
}
I think you want to go the other way round actually!
Transform.InverseTransformDirection converts a vector from world space into local space.
What you get as input however is a local vector on the XZ plane. You want to apply this direction according to your player objects orientation, if e.g. pressing right (your input is 1,0,0) the object shall move towards its transform.right vector.
So you rather want to convert in the opposite direction into world space to move the object in the Unity world space.
You should rather be using Transform.TransformDirection!
var worldMove = transform.TransformDirection(input);
Or alternatively you can also just multiply by the rotation like
var worldMove = transform.rotation * input;
Note that if you are also using a Rigidbody like the question you linked there is also Rigidbody.AddRelativeForce which basically works the same way and expects a local space vector which is then internally converted into a world space force.

Rotate Object around point and move it along sine function

First off: I am very new to Unity, as in VERY new.
I want to do the following: I want to rotate a cube around a stationary point (in my case a camera) with a radius that is adjustable in the inspector. The cube should always have its Z-axis oriented towards the camera's position. While the cube is orbiting around the camera, it should additionally follow a sine function to move up and down with a magnitude of 2.
I have some working code, the only problem is an increase in distance over time. The longer the runtime, the higher the distance between the cube and the camera.
Here is what I currently have:
void Awake()
{
cameraPosition = GameObject.FindGameObjectWithTag("MainCamera").transform;
transform.position = new Vector3(x: transform.position.x,
y: transform.position.y,
z: cameraPosition.position.z + radius);
movement = transform.position;
}
I instantiate some variables in the Awake()-method and set the cube's position to where it should be (do you instantiate in Awake()?). I'll use the Vector3 movement later in my code for the "swinging" of the cube.
void Update()
{
transform.LookAt(cameraPosition);
transform.RotateAround(cameraPosition.position, cameraPosition.transform.up, 30 * Time.deltaTime * rotationSpeed);
MoveAndRotate();
}
Here I set the orientation of the cube's z-axis and rotate it around the camera. 30 is just a constant i am using for tests.
void MoveAndRotate()
{
movement += transform.right * Time.deltaTime * movementSpeed;
transform.position = movement + Vector3.up * Mathf.Sin(Time.time * frequency) * magnitude;
}
To be quite frank, I do not understand this bit of code completely. I do however understand that this includes a rotation as it moves the cube along it's x-axis as well as along the world's y-axis. I have yet to get into Vector and matrices, so if you could share your knowledge on that topic as well I'd be grateful for that.
It seems like I have found the solution for my problem, and it is an easy one at that.
First of all we need the initial position of our cube because we need to have access to its original y-coordinate to account for offsets.
So in Awake(), instead of
movement = transform.position;
We simply change it to
initialPosition = transform.position;
To have more readable code.
Next, we change our MoveAndRotate()-method to only be a single line long.
void MoveAndRotate()
{
transform.position = new Vector3(transform.position.x,
Mathf.Sin(Time.time * frequency) * magnitude + initialPosition.y,
transform.position.z);
}
What exactly does that line then? It sets the position of our cube to a new Vector3. This Vector consists of
its current x-value
our newly calculated y-value (our height, if you want to say so) + the offset from our original position
its current z value
With this, the cube will only bop up and down with distancing itself from the camera.
I have also found the reason for the increase in distance: My method of movement does not describe a sphere (which would keep the distance the same no matter how you rotate the cube) but rather a plane. Of course, moving the cube along a plane will automatically increase the distance for some points of the movement.
For instantiating variables in Awake it should be fine, but you could also do it in the Start(){} Method that Unity provides if you wanted to.
For the main problem itself I'm guessing that calling this function every frame is the Problem, because you add on to the position.
movement += transform.right * Time.deltaTime * movementSpeed;
Would be nice if you could try to replace it with this code and see if it helped.
movement = transform.right * Time.deltaTime * movementSpeed;

unity3d - Clamp rotation value

I have an object that rotates according to mouse position, but I want to clamp it so it doesn't get further or lower than certain value. Here is my code:
void LookAt () {
float distance = transform.position.z - Camera.main.transform.position.z;
Vector3 position = new Vector3(Input.mousePosition.x, Input.mousePosition.y, distance);
position = Camera.main.ScreenToWorldPoint(position);
position.x = Mathf.Clamp(position.x, -70, 70);
position.z = Mathf.Clamp(position.z, -70, 70);
Vector3 target = new Vector3 (position.x, transform.position.y, position.z); // Use current object positin.y
transform.LookAt(target);
}
But unfortunately it doesn't work, it keeps rotating 360.
Edit:
This is a 3D top-down game, I have a tank and I want to rotate it's upper half. The code I wrote above works perfect for the job, but now I don't know how to limit it so the barrel( the part I'm rotating) always facing upwards where the enemies will come from. 70 or whatever are just random values I was testing, first I want to figure what exactly the proper code is, then determining the values is the easy part.
Actually, the problem is that you're clamping a position, not a rotation. You're having it look at a certain point, but limiting that point rather than the angle that it will need to rotate to meet it. You'll have to use trigonometry to calculate the angle it wants to point in (more specifically, the atan2 function), clamp that value to (-70, 70), and then apply that rotation to the object (using euler angles). Do you require further clarification on any of these steps?
Cheers.
P.S. Note that atan2 returns a value in radians, but your range and euler angles use degrees.
You limit your target position by 70 units in world space, which is usually a lot, but depends on your game scale. What I think you wanted to do is to limit mouse position by 70 pixels around the screen center. (Please, provide this remarks in the question itself, so we won't have to guess). However, because you used the same variable both for screen space and world space position of the target, you likely got confused and clamped the position after converting it to world space.
Also, you made the y coordinate of the target to be the same as the object. But this means that the object would have to rotate 360 degrees every time the target passed it. I assume that what you wanted to do instead is to assume that the target location is located on camera place.
void LookAt () {
var cursorPosition = new Vector3(Input.mousePosition.x, Input.mousePosition.y, camera.main.nearClipPlane);
cursorPosition.x = Mathf.Clamp(position.x, -70, 70);
cursorPosition.z = Mathf.Clamp(position.z, -70, 70);
var targetPosition = Camera.main.ScreenToWorldPoint(cursorPosition);
transform.LookAt(targetPosition);
}
Please, provide details about your reasoning and desired behavior when you ask to find errors in your code.