i'm currently in progress of a new game where my character has to move. While my character walks forward and i'm rotating it on the z axis, it just rotates instead of walking down the new z axis.
void Update()
{
{
if (Input.GetKeyDown(KeyCode.W))
{
anim.SetInteger("Condition", 1);
moveDir = new Vector3(0, 0, 1);
moveDir *= speed;
moveDir = transform.TransformDirection(moveDir);
}
if (Input.GetKeyUp(KeyCode.W))
{
anim.SetInteger("Condition", 0);
moveDir = new Vector3(0, 0, 0);
}
moveDir.y -= gravity * Time.deltaTime;
controller.Move(moveDir * Time.deltaTime);
}
rot += Input.GetAxisRaw("Horizontal") * rotSpeed * Time.deltaTime;
transform.eulerAngles = new Vector3(0, rot, 0);
}
}
I want to be able to walk forward while changing the z axis instead of walking then stop and then walk again.
You can't do that using a CharacterController because your call to controller.move() overwrites the rotation ... you need to write a custom move function.
Related
basically i am trying to move a character around so when i press W it goes forward but when i let go it doesn't stop(only once in a while). I am on Update void and not fixed Update.
private void Update()
{
if (controller.isGrounded)
{
if(Input.GetKey(KeyCode.W))
{
anim.SetInteger("condition", 1);
moveDir = new Vector3(0, 0, 1);
moveDir *= speed;
moveDir = transform.TransformDirection(moveDir);
}
if(Input.GetKeyUp (KeyCode.W))
{
anim.SetInteger("condition", 0);
moveDir = new Vector3(0, 0, 0);
}
}
rot += Input.GetAxis("Horizontal") * rotSpeed * Time.deltaTime;
transform.eulerAngles = new Vector3(0, rot, 0);
moveDir.y -= gravity * Time.deltaTime;
controller.Move (moveDir * Time.deltaTime);
}
}
Try looking at your animator and checking that Apply Root Motion is checked off.
Animator in Inspector
What root motion does is that it moves your character through the animation instead of through code. Here is a detailed explanation on root motion. What's root motion and how it works
I think I was able to recreate your issue and I was getting the same results. After I unchecked Apply Root Motion, my character stopped once I let go of "W".
I'm working on a small experimental project in Unity. I have a 2d sprite that moves forward with a velocity but I want it to turn left or right in a wide arc and keep moving in that direction on keypress.
I've tried to tweak its angular velocity to get the desired affect. Looks unnatural and it won't stop rotating.
Tried Lerping. Looks unnatural as well.
Code Snippet 1:
bool forward = true;
Vector3 movement;
void FixedUpdate()
{
if (forward)
{
//Moves forward
movement = new Vector3(0.0f, 0.1f, 0.0f);
rb.velocity = movement * speed;
}
if (Input.GetKeyDown(KeyCode.LeftArrow))
{
forward = false;
movement = new Vector3(-0.05f, 0.05f, 0.0f);
rb.velocity = movement * speed;
rb.angularVelocity = 30;
}
if (transform.rotation.z == 90)
{
movement = new Vector3(-0.1f, 0.0f, 0.0f);
rb.velocity = movement * speed;
rb.angularVelocity = 0;
}
}
Code Snippet 2:
void Update(){
if (Input.GetKeyDown(KeyCode.LeftArrow))
{
Vector3 target = transform.position + new Vector3(-0.5f, 0.5f, 0);
transform.position
=Vector3.Lerp(transform.position,target,Time.deltaTime);
transform.eulerAngles = Vector3.Lerp(transform.rotation.eulerAngles,
new Vector3(0, 0, 90), Time.deltaTime);
}
}
Can anyone point me in the right direction of what is the actual correct way to implement this?
Not entirely sure if this is what youre trying to accomplish but here's some pseudo code of what I came up with to get you started...
Essentially, when a direction is pressed, you want to increase the velocity in that direction until all of the velocity is pointed that way. At the same time you want to decrease the velocity in the direction you were previously going until it is zero.
This is a simplified formula however - if you truly wanted the velocity to be constant throughout the entirety of the arc you would have to use some geometry, knowing that V=(velX^2 + velY^2)^.5 but this would get you pretty close...
float yvel = 1f, xvel;
float t;
void Update()
{
GetComponent<Rigidbody2D>().velocity = new Vector2(xvel, yvel);
t += Time.deltaTime;
if (Input.GetKeyDown(KeyCode.D))
{
t = 0;
StartCoroutine(Move());
}
}
private IEnumerator Move()
{
while (t < 2) // at time t, yvel will be zero and xvel will be 1
{
yvel = 1 - .5f * t; // decrease velocity in old direction
xvel = .5f * t; // increase velocity in new direction
yield return null;
}
}
I have a main camera in Unity3D that I want to rotate depending on mouse input, so it works as a first person video-game where you move the mouse depending on where do you want to look at.
The starting values of the camera (Transform tab in Inspector tab in Unity) are:
Position: X = -1, Y = 1, Z = -11.
Rotation: X = 0, Y = 0, Z = 0.
Scale: X = 1, Y = 1, Z = 1.
I added a Script component for the Main Camera. And it is the following class:
using UnityEngine;
using System.Collections;
public class CameraMove : MonoBehaviour {
float deltaRotation = 50f;
// Use this for initialization
void Start () {
}
// Update is called once per frame
void Update () {
if(Input.GetAxis("Mouse X") < 0){
//Code for action on mouse moving left
transform.Rotate (new Vector3 (0f, -deltaRotation, 0f) * Time.deltaTime);
}
else if(Input.GetAxis("Mouse X") > 0){
//Code for action on mouse moving right
transform.Rotate (new Vector3 (0f, deltaRotation, 0f) * Time.deltaTime);
}
if(Input.GetAxis("Mouse Y") < 0){
//Code for action on mouse moving left
transform.Rotate (new Vector3 (deltaRotation, 0f, 0f) * Time.deltaTime);
}
else if(Input.GetAxis("Mouse Y") > 0){
//Code for action on mouse moving right
transform.Rotate (new Vector3 (-deltaRotation, 0f, 0f) * Time.deltaTime);
}
}
}
However, when I play the scene the camera doesn't rotate like it should. The values of the rotation change in x-axis, y-axis and even for z-axis.
What am I doing wrong?
That's a problem with how Quaternion is calculated. This happens when multiple axis are being modified. If you comment all the x rotation or the y rotation, and only rotate in one axis at a time, you will realize that this problem will go away.
To properly rotate your camera with the mouse input, use the eulerAngles or localEulerAngles variables. The option between these two depends on what you are doing.
public float xMoveThreshold = 1000.0f;
public float yMoveThreshold = 1000.0f;
public float yMaxLimit = 45.0f;
public float yMinLimit = -45.0f;
float yRotCounter = 0.0f;
float xRotCounter = 0.0f;
// Update is called once per frame
void Update()
{
xRotCounter += Input.GetAxis("Mouse X") * xMoveThreshold * Time.deltaTime;
yRotCounter += Input.GetAxis("Mouse Y") * yMoveThreshold * Time.deltaTime;
yRotCounter = Mathf.Clamp(yRotCounter, yMinLimit, yMaxLimit);
transform.localEulerAngles = new Vector3(-yRotCounter, xRotCounter, 0);
}
I am writing a kind of RTS CameraController in Unity using C#. I already managed to implement the basic functions, but now I am facing a tricky problem. I managed to rotate my camera and afterwards move into the right direction, BUT my scrolling boundaries are not working anymore after rotating (of course because I am just checking for x on the horizontal scrolling, but after rotation I would need to check for y instead). With boundaries I mean the restriction to only scroll until a certain position is reached (x < 0).
I am a bit stuck on how to solve my problem easily. One way would seems to be using conditions and check the rotation before checking for the boundaries, but this doesn't seem like a good aproach for me, just fixing the problem, but not really taking care of the cause. Now my question: Is there an easier or better way to achieve what I am doing? Did I miss something completely?
This is how I want the camera to move in all 4 rotations. The rectangles are my the world, the arrows define my bounds. The camera should always overshoot in backwards direction and stop before the bounds in forward direction.:
Here is my update method (vertDist and horDist are just defining from when on the mousescroll should start):
void LateUpdate() {
//LEFT
if((Input.mousePosition.x < horDist || Input.GetAxis("Horizontal") < 0)
&& transform.position.x > 0)
transform.Translate(-speed, 0, 0);
//RIGHT
if((Input.mousePosition.x > Screen.width - horDist || Input.GetAxis("Horizontal") > 0)
&& transform.position.x < world.worldX)
transform.Translate(speed, 0, 0);
//UP
if((Input.mousePosition.y > Screen.height - vertDist || Input.GetAxis("Vertical") > 0)
&& transform.position.z < world.worldZ - 30) {
Vector3 temp = transform.eulerAngles;
transform.eulerAngles = new Vector3(0, transform.eulerAngles.y, transform.eulerAngles.z);
transform.Translate(0, 0, speed);
transform.eulerAngles = temp;
}
//DOWN
if((Input.mousePosition.y < vertDist || Input.GetAxis("Vertical") < 0)
&& transform.position.z > -10) {
Vector3 temp = transform.eulerAngles;
transform.eulerAngles = new Vector3(0, transform.eulerAngles.y, transform.eulerAngles.z);
transform.Translate(0, 0, -speed);
transform.eulerAngles = temp;
}
//ZOOM
//camera.fieldOfView -= Input.GetAxis("Mouse ScrollWheel");
//ROTATE
if(Input.GetButtonDown("Rotate")){
Vector3 targetPosition = transform.position;
targetPosition += transform.forward * 27;
//transform.Rotate(new Vector3(0, Mathf.Sign(Input.GetAxis("Rotate")) * 90, 0), Space.World);
transform.RotateAround(targetPosition, Vector3.up, Mathf.Sign(Input.GetAxis("Rotate")) * 90);
}
}
Use
transform.Translate(0, 0, -speed, Space.Self); // For all the Translate, use Space.Self
It will only move based on it's local position instead of world position. But you will get what you wanted.
Hope it helps.
Finally I got a solution! I decided to define a Rect, depending on the current rotation and afterwards check if the camera-position is inside the Rect. Thus I had to mess a bit around with the positions, because I don't know why Rect.Contains() only takes the x- and y- coordinate of a position. My camera just moves along the x- and z-axis, so I did this weird coordinate swapping there:
void LateUpdate() {
Rect bounds = DefineBounds();
Vector3 pos = transform.position;
//LEFT
if((/*Input.mousePosition.x < horDist ||*/ Input.GetAxis("Horizontal") < 0)) {
pos += transform.TransformDirection(-speed * Time.deltaTime, 0, 0);
//reset pos if out of bounds
if(!bounds.Contains(new Vector2(pos.x, pos.z)))
pos -= transform.TransformDirection(-speed * Time.deltaTime, 0, 0);
}
//RIGHT
if((/*Input.mousePosition.x > Screen.width - horDist ||*/ Input.GetAxis("Horizontal") > 0)) {
pos += transform.TransformDirection(speed * Time.deltaTime, 0, 0);
//reset pos if out of bounds
if(!bounds.Contains(new Vector2(pos.x, pos.z)))
pos -= transform.TransformDirection(speed * Time.deltaTime, 0, 0);
}
//UP
if((/*Input.mousePosition.y > Screen.height - vertDist ||*/ Input.GetAxis("Vertical") > 0)) {
//Set camera x-angle to 0
Vector3 temp = transform.eulerAngles;
transform.eulerAngles = new Vector3(0, transform.eulerAngles.y, transform.eulerAngles.z);
pos += transform.TransformDirection(0, 0, speed * Time.deltaTime);
//reset pos if out of bounds
if(!bounds.Contains(new Vector2(pos.x, pos.z)))
pos -= transform.TransformDirection(0, 0, speed * Time.deltaTime);
//Reset camera x-angle
transform.eulerAngles = temp;
}
//DOWN
if((/*Input.mousePosition.y < vertDist ||*/ Input.GetAxis("Vertical") < 0)) {
//Set camera x-angle to 0
Vector3 temp = transform.eulerAngles;
transform.eulerAngles = new Vector3(0, transform.eulerAngles.y, transform.eulerAngles.z);
pos += transform.TransformDirection(0, 0, -speed * Time.deltaTime);
//reset pos if out of bounds
if(!bounds.Contains(new Vector2(pos.x, pos.z)))
pos -= transform.TransformDirection(0, 0, -speed * Time.deltaTime);
//Reset camera x-angle
transform.eulerAngles = temp;
}
transform.position = pos;
//ZOOM
//camera.fieldOfView -= Input.GetAxis("Mouse ScrollWheel");
transform.position = new Vector3(pos.x, pos.y - Input.GetAxis("Mouse ScrollWheel"), pos.z);
//ROTATE
if(Input.GetButtonDown("Rotate")){
Vector3 targetPosition = transform.position;
Vector2 posXZ;
targetPosition += transform.forward * 27;
transform.RotateAround(targetPosition, Vector3.up, Mathf.Sign(Input.GetAxis("Rotate")) * 90);
bounds = DefineBounds();
pos = transform.position;
posXZ = new Vector2(pos.x, pos.z);
while(!bounds.Contains(posXZ)) {
posXZ = Vector2.MoveTowards(posXZ, bounds.center, 1);
pos.x = posXZ.x;
pos.z = posXZ.y;
}
transform.position = pos;
}
}
Good day. I'm working on a fps game, and I have a problem with camera, or with movement to be pricese... as it doesn't take camera position into accound when performs movement...
I tried to fix it in several different ways, but I guess I just don't understand the math needed :(
Anyway, here's the code:
static public void UpdateCharacterPositionAndCamera(float time)
{
//mouse look update
float rotationSpeed = 3f;
if (Input.mouseState != Input.mouseStatePrevious)
{
float xDifference = Input.mouseState.X - Display.gd.Viewport.Width / 2;
float yDifference = Input.mouseState.Y - Display.gd.Viewport.Height / 2;
yRotation -= rotationSpeed * xDifference * time;
xRotation -= rotationSpeed * yDifference * time;
Mouse.SetPosition(Display.gd.Viewport.Width / 2, Display.gd.Viewport.Height / 2);
}
//camera
Vector3 cameraPosition = playerPos;
Vector3 cameraReference = new Vector3(0f, 0f, -1f);
Matrix rotationMatrix = Matrix.CreateRotationY(MathHelper.ToRadians(yRotation)) * Matrix.CreateRotationX(MathHelper.ToRadians(xRotation));
Vector3 transformedReference = Vector3.Transform(cameraReference, rotationMatrix);
Vector3 cameraLookat = cameraPosition + transformedReference;
viewMatrix = Matrix.CreateLookAt(cameraPosition, cameraLookat, new Vector3(0.0f, 1.0f, 0.0f));
projectionMatrix = Matrix.CreatePerspectiveFieldOfView(MathHelper.PiOver4, Display.gd.Viewport.AspectRatio, 0.1f, 2500.0f);
//movement
float moveSpeed = 5.0f;
Vector3 moveVector = new Vector3(0, 0, 0);
if (Input.keyState.IsKeyDown(Keys.Up) || Input.keyState.IsKeyDown(Keys.W))
moveVector += new Vector3(0, 0, -1);
if (Input.keyState.IsKeyDown(Keys.Down) || Input.keyState.IsKeyDown(Keys.S))
moveVector += new Vector3(0, 0, 1);
if (Input.keyState.IsKeyDown(Keys.Right) || Input.keyState.IsKeyDown(Keys.D))
moveVector += new Vector3(1, 0, 0);
if (Input.keyState.IsKeyDown(Keys.Left) || Input.keyState.IsKeyDown(Keys.A))
moveVector += new Vector3(-1, 0, 0);
if (Input.keyState.IsKeyDown(Keys.Q))
moveVector += new Vector3(0, 1, 0);
if (Input.keyState.IsKeyDown(Keys.Z))
moveVector += new Vector3(0, -1, 0);
playerPos += moveVector * moveSpeed;
}
Can you tell me how to change the move vector so it takes camera direction into account...?
Multiply the move vector by the camera rotation matrix, or its inverse (I think it's the inverse). It's the same as the view matrix, but without the translation. If you want to fix the camera onto a plane, you need to zero out the respective component afterwards and perhaps normalize the new vector.
I'm not familiar with the XNA API, so I cannot tell you exactly which methods to use. You might be able to extract the rotation matrix from the view matrix, or you might need to look at the difference (lookAt-positios) from the origin.
aere's how I usually do it:
//movement
Matrix camWorld = Matrix.Invert(view);
Vector3 moveVector = Vector3.Zero;
...
if(...keys.Up... or ...keys.W...)
moveVector += camWorld.Forward;
if(... keys.right or ... keys.D...)
moveVector += camWorld.Right;
...
moveVector.Normalize();
PlayerPos += moveVector * moveSpeed;