Character vibrates when movement starts unity - c#

I'm working through a book and have come to an issue. it's a top down shooting game that has the player rotate with the mouse and move with the keyboard. problem is when testing if either the mouse or the keyboard set off movement the image vibrates. If i push the arrow keys it moves in a circle the longer I hold the key the wider the circle. Below is the script I'm working with.
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
public class PlayerBehaviour : MonoBehaviour
{
//movement modifier applied to directional movement
public float playerSpeed = 2.0f;
//current player speed
private float currentSpeed = 0.0f;
/*
* Allows us to have multiple inputs and supports keyboard,
* joystick, etc.
*/
public List<KeyCode> upButton;
public List<KeyCode> downButton;
public List<KeyCode> leftButton;
public List<KeyCode> rightButton;
//last movement made
private Vector3 lastMovement = new Vector3();
// Update is called once per frame
void Update()
{
//rotates ship to face mouse
Rotation();
//moves ship
Movement();
}
void Rotation()
{
//finds mouse in relation to player location
Vector3 worldPos = Input.mousePosition;
worldPos = Camera.main.ScreenToWorldPoint(worldPos);
/*
get x and y screen positions
*/
float dx = this.transform.position.x - worldPos.x;
float dy = this.transform.position.y - worldPos.y;
//find the angle between objects
float angle = Mathf.Atan2(dy, dx) * Mathf.Rad2Deg;
/*
* The transform's rotation property uses a Quaternion,
* so we need to convert the angle in a Vector
* (The Z axis is for rotation for 2D).
*/
Quaternion rot = Quaternion.Euler(new Vector3(0, 0, angle + 90));
// Assign the ship's rotation
this.transform.rotation = rot;
}
// Will move the player based off of keys pressed
void Movement()
{
// The movement that needs to occur this frame
Vector3 movement = new Vector3();
// Check for input
movement += MoveIfPressed(upButton, Vector3.up);
movement += MoveIfPressed(downButton, Vector3.down);
movement += MoveIfPressed(leftButton, Vector3.left);
movement += MoveIfPressed(rightButton, Vector3.right);
/*
* If we pressed multiple buttons, make sure we're only
* moving the same length.
*/
movement.Normalize();
// Check if we pressed anything
if (movement.magnitude > 0)
{
// If we did, move in that direction
currentSpeed = playerSpeed;
this.transform.Translate(movement * Time.deltaTime * playerSpeed, Space.World);
lastMovement = movement;
}
else
{
// Otherwise, move in the direction we were going
this.transform.Translate(lastMovement * Time.deltaTime * currentSpeed, Space.World);
// Slow down over time
currentSpeed *= .9f;
}
}
/*
* Will return the movement if any of the keys are pressed,
* otherwise it will return (0,0,0)
*/
Vector3 MoveIfPressed(List<KeyCode> keyList, Vector3 Movement)
{
// Check each key in our list
foreach (KeyCode element in keyList)
{
if (Input.GetKey(element))
{
/*
* It was pressed so we leave the function
* with the movement applied.
*/
return Movement;
}
}
// None of the keys were pressed, so don't need to move
return Vector3.zero;
}
}

I studied your code for a while and could not find anything wrong with it. So I tested it myself and it works perfectly.
So I suppose there's something wrong with your scene. You might for example have your player object be a child of some object that rotates your axes: this would cause problems I suppose.
Have a new, empty scene. Add a new GameObject (a 3D cube for example, or a 2D sprite) and assign PlayerBehaviour to it. Now test: it should work perfectly.

Related

Making a 2d player look at the cursor, and then move towards it

This is the code:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class PlayerMovement : MonoBehaviour
{
// Tweekable move speed
public float MoveSpeed = 4;
// Set what distance it should be from the target
int MaxDist = 10;
int MinDist = 5;
// This is the target
public Transform Mouse;
// Start is called before the first frame update
void Start()
{
}
// Update is called once per frame
void Update()
{
// Keep looking at an object
transform.LookAt();
// Turn off gravity
Physics2D.gravity = Vector2.zero;
// When distance is over minimun
if (Vector3.Distance(Mouse.position, Mouse.position) >= MinDist)
{
// Keep distance
transform.position += transform.forward * MoveSpeed * Time.deltaTime;
// When it's between max and minimun
if (Vector3.Distance(transform.position, Mouse.position) <= MaxDist)
{
}
}
}
// I imported this code from another project so the enemy keeps looking at the player, and keeps his distance. it was a 3D project, so there may be more errors, and this is also my first time creating a game. Be gentle
I am working on a similar project right now.
Here is the code I use to rotate the player (first part) and then move it into that direction (second part):
public Rigidbody2D rb;
public float speed;
void Update()
{
//get mouse position
Vector3 mousePos = Camera.main.ScreenToWorldPoint(Input.mousePosition);
//calculating the angle
float AngleRad = Mathf.Atan2(mousePos.y - transform.position.y, mousePos.x -
transform.position.x);
float AngleDeg = (180 / Mathf.PI) * AngleRad;
//rotating the player
Player.transform.rotation = Quaternion.Euler(0, 0, AngleDeg);
//second part
Vector3 mouseDir = mousePos - transform.position;
mouseDir.z = 0f;
mouseDir = mouseDir.normalized;
rb.AddForce(mouseDir * speed);
}
If the player rotates, but it is looking in the wrong way (in my case), then play around with the the last line of the first part. The following code worked fine for me:
transform.rotation = Quaternion.Euler(0, 0, AngleDeg - 90);
If you want the player to move at a constant speed, then you can use
rb.velocity = mouseDir * speed;
instead of
rb.AddForce(mouseDir * speed);
in the last line of the second part.
Your Player-Gameobject needs a Rigidbody2D component. I also added an if-statement around the second part, so the player only moves to the wanted direction when (for example) space is pressed, but always looks to the mouse.

trouble understanding movement along local and global space in unity

CharacterController _charController;
// ...
moveInputX = Input.GetAxis("Horizontal") * speed;
moveInputZ = Input.GetAxis("Vertical") * speed;
Vector3 movement = new Vector3(moveInputX, 0, moveInputZ);
movement = Vector3.ClampMagnitude(movement, speed);
movement.y = -9.81f;
movement *= Time.deltaTime;
movement = transform.TransformDirection(movement);
_charController.Move(movement);
I have a player that rotates and I want to make him move to his local direction but i don't understand when I remove movement = transform.TransformDirection(movement); from the code it moves to global direction which doesn't make any sense because this line of code converts the direction from local to global space.
It's because CharacterController.Move expects a vector in world space. Sadly, the documentation on that has never been clear about that.
When you calculate movement here:
Vector3 movement = new Vector3(moveInputX, 0, moveInputZ);
You can see that it doesn't take the rotation of the character's transform into account. In order for it to do that, you want to find what this vector looks like in world space when interpreted as being in the character's local space. That's exactly what this line does:
movement = transform.TransformDirection(movement);
It converts movement from local space to world space.
The 2018.1 CharacterController.Move documentation actually uses transform.TransformDirection in its example:
using UnityEngine;
using System.Collections;
// The GameObject is made to bounce using the space key.
// Also the GameOject can be moved forward/backward and left/right.
// Add a Quad to the scene so this GameObject can collider with a floor.
public class ExampleScript : MonoBehaviour
{
public float speed = 6.0f;
public float jumpSpeed = 8.0f;
public float gravity = 20.0f;
private Vector3 moveDirection = Vector3.zero;
private CharacterController controller;
void Start()
{
controller = GetComponent<CharacterController>();
// let the gameObject fall down
gameObject.transform.position = new Vector3(0, 5, 0);
}
void Update()
{
if (controller.isGrounded)
{
// We are grounded, so recalculate
// move direction directly from axes
moveDirection = new Vector3(Input.GetAxis("Horizontal"), 0.0f, Input.GetAxis("Vertical"));
moveDirection = transform.TransformDirection(moveDirection);
moveDirection = moveDirection * speed;
if (Input.GetButton("Jump"))
{
moveDirection.y = jumpSpeed;
}
}
// Apply gravity
moveDirection.y = moveDirection.y - (gravity * Time.deltaTime);
// Move the controller
controller.Move(moveDirection * Time.deltaTime);
}
}
Your movement vector is in local space
You want the player to move forward locally and move horizontally locally and so you construct a forward/rightward movement vector based on the player input. This vector is in local coordinates and you TransformDirection back to world space before applying the result to world position with _charController.Move (presumably, you didn't include that method's code).

Need helping getting a character controller to jump

So far I have a character controller that enables me to move around, sprint and crouch (no animation) , but I am unable to get the controller to jump. I know 100% the character is getting the input to jump, and the movement vector is around ~40 on the Y axis, so the player should be moving. The problem is, nothing happens. The player can still move around, and fall of ledges, but nothing happens when i press space
This is my code:
using UnityEngine;
public class KeyboardMovement : MonoBehaviour
{
private CharacterController controller;
public float walkSpeed;
public float sprintSpeed;
public float crouchSpeed;
public float jumpHeight;
Vector3 up = Vector3.zero;
Vector3 movement = Vector3.zero;
Vector3 forward = Vector3.zero;
Vector3 sideways = Vector3.zero;
void Start()
{
controller = GetComponent<CharacterController>();
}
void Update()
{
float speed = walkSpeed;
//If crouching, set speed to crouch speed. This ovverides sprinting
if (SingletonSettings.GetKey(SingletonSettings.Keybindings.crouch))
speed = crouchSpeed;
//Else if sprinting, set speed to sprint speed
else if (SingletonSettings.GetKey(SingletonSettings.Keybindings.sprint))
speed = sprintSpeed;
//Create vectors for movement
forward = transform.TransformDirection(Vector3.forward) * Input.GetAxis("Vertical");
sideways = transform.TransformDirection(Vector3.right) * Input.GetAxis("Horizontal");
//up = SingletonSettings.GetKey(SingletonSettings.Keybindings.jump) && controller.isGrounded ? Vector3.up * jumpHeight : Vector3.zero;
movement = (up * 100) + ((forward + sideways) * 10 * Time.deltaTime * speed);
//Combine vectors and Multiply by DeltaTime to ensure smooth movement at different framerates.
//Also multiply by 10*speed to ensure correct speed in different states
if (controller.isGrounded && Input.GetKey(KeyCode.Space))
{
movement.y = jumpHeight*50 * Time.deltaTime;
}
controller.SimpleMove(movement);
}
void OnGUI()
{
GUILayout.Label('\n' + Newtonsoft.Json.JsonConvert.SerializeObject(movement.y, Newtonsoft.Json.Formatting.Indented, new Newtonsoft.Json.JsonSerializerSettings
{
ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore
}));
}
}
CharacterController.SimpleMove from the docs
Moves the character with speed.
Velocity along the y-axis is ignored.
Gravity is automatically applied.
https://docs.unity3d.com/ScriptReference/CharacterController.SimpleMove.html
You should use CharacterController.Move
A more complex move function taking absolute movement deltas.
Attempts to move the controller by motion, the motion will only be constrained by collisions. It will slide along colliders
...
This function does not apply any gravity.
https://docs.unity3d.com/ScriptReference/CharacterController.Move.html
With this method, you'll need to apply gravity yourself
movement.y -= gravity * Time.deltaTime;
controller.Move(movement * Time.deltaTime);

PlayerMovement And CameraFollow

I am making a thirdperson Unity game. I think that I'm almost done but I just can't figure out how to make so the WASD control is relative to the camera?
Right now when I'm moving with WASD it works, but if i start to rotate the camera by using mouse, suddenly my (W) button makes the player walk backwards and left button (A) goes right. All controls are just bugging.
This is my PlayerMovement.cs and CameraFollow.cs:
PlayerMovement:
public float speed = 6f; // The speed that the player will move at.
Vector3 movement; // The vector to store the direction of the player's movement.
Animator anim; // Reference to the animator component.
Rigidbody playerRigidbody; // Reference to the player's rigidbody.
int floorMask; // A layer mask so that a ray can be cast just at gameobjects on the floor layer.
float camRayLength = 100f; // The length of the ray from the camera into the scene.
void Awake ()
{
// Create a layer mask for the floor layer.
floorMask = LayerMask.GetMask ("Floor");
// Set up references.
anim = GetComponent <Animator> ();
playerRigidbody = GetComponent <Rigidbody> ();
}
void FixedUpdate ()
{
// Store the input axes.
float h = CrossPlatformInputManager.GetAxisRaw("Horizontal");
float v = CrossPlatformInputManager.GetAxisRaw("Vertical");
// Move the player around the scene.
Move (h, v);
// Turn the player to face the mouse cursor.
Turning ();
// Animate the player.
Animating (h, v);
Shooting ();
}
void Move (float h, float v)
{
// Set the movement vector based on the axis input.
movement.Set (h, 0f, v);
// Normalise the movement vector and make it proportional to the speed per second.
movement = movement.normalized * speed * Time.deltaTime;
// Move the player to it's current position plus the movement.
playerRigidbody.MovePosition (transform.position + movement);
}
void Turning ()
{
// Create a ray from the mouse cursor on screen in the direction of the camera.
Ray camRay = Camera.main.ScreenPointToRay (Input.mousePosition);
// Create a RaycastHit variable to store information about what was hit by the ray.
RaycastHit floorHit;
// Perform the raycast and if it hits something on the floor layer...
if(Physics.Raycast (camRay, out floorHit, camRayLength, floorMask))
{
// Create a vector from the player to the point on the floor the raycast from the mouse hit.
Vector3 playerToMouse = floorHit.point - transform.position;
// Ensure the vector is entirely along the floor plane.
playerToMouse.y = 0f;
// Create a quaternion (rotation) based on looking down the vector from the player to the mouse.
Quaternion newRotatation = Quaternion.LookRotation (playerToMouse);
// Set the player's rotation to this new rotation.
playerRigidbody.MoveRotation (newRotatation);
}
}
void Animating (float h, float v)
{
// Create a boolean that is true if either of the input axes is non-zero.
bool walking = h != 0f || v != 0f;
// Tell the animator whether or not the player is walking.
anim.SetBool ("IsWalking", walking);
}
void Shooting ()
{
// Create a boolean that is true if either of the input axes is non-zero.
bool shooting = (Input.GetMouseButtonDown(0));
// Tell the animator whether or not the player is walking.
anim.SetBool ("IsShooting", shooting);
}
CameraFollow:
// Camera target to look at.
public Transform target;
// Exposed vars for the camera position from the target.
public float height = 20f;
public float distance = 20f;
// Camera limits.
public float min = 10f;
public float max = 60;
// Rotation.
public float rotateSpeed = 1f;
// Options.
public bool doRotate;
public bool doZoom;
// The movement amount when zooming.
public float zoomStep = 30f;
public float zoomSpeed = 5f;
private float heightWanted;
private float distanceWanted;
// Result vectors.
private Vector3 zoomResult;
private Quaternion rotationResult;
private Vector3 targetAdjustedPosition;
void Start(){
// Initialise default zoom vals.
heightWanted = height;
distanceWanted = distance;
// Setup our default camera. We set the zoom result to be our default position.
zoomResult = new Vector3(0f, height, -distance);
}
void LateUpdate(){
// Check target.
if( !target ){
Debug.LogError("This camera has no target, you need to assign a target in the inspector.");
return;
}
if( doZoom ){
// Record our mouse input. If we zoom add this to our height and distance.
float mouseInput = Input.GetAxis("Mouse ScrollWheel");
heightWanted -= zoomStep * mouseInput;
distanceWanted -= zoomStep * mouseInput;
// Make sure they meet our min/max values.
heightWanted = Mathf.Clamp(heightWanted, min, max);
distanceWanted = Mathf.Clamp(distanceWanted, min, max);
height = Mathf.Lerp(height, heightWanted, Time.deltaTime * zoomSpeed);
distance = Mathf.Lerp(distance, distanceWanted, Time.deltaTime * zoomSpeed);
// Post our result.
zoomResult = new Vector3(0f, height, -distance);
}
if( doRotate ){
// Work out the current and wanted rots.
float currentRotationAngle = transform.eulerAngles.y;
float wantedRotationAngle = target.eulerAngles.y;
// Smooth the rotation.
currentRotationAngle = Mathf.LerpAngle(currentRotationAngle, wantedRotationAngle, rotateSpeed * Time.deltaTime);
// Convert the angle into a rotation.
rotationResult = Quaternion.Euler(0f, currentRotationAngle, 0f);
}
// Set the camera position reference.
targetAdjustedPosition = rotationResult * zoomResult;
transform.position = target.position + targetAdjustedPosition;
// Face the desired position.
transform.LookAt(target);
}
Your 'movement' vector should not be independent of camera forward vector, if you want a normal 3-rd person movement. Instead of moving in the 'h' or 'v' directions, move in camera.right and camera.forward directions, multiplied by 'h' and 'v' magnitudes respectively.
To be more accurate, if your camera is slightly inclined (so that its forward will go downward), you should first project camera.forward onto [player.forward, player.right] plane. Unity has a helper function just for that (Vector3.ProjectOnPlane()). If your camera also rotates around its forward direction (e.g. camera shake), you should also project camera.right on the same plane.
// Set the movement vector based on the axis input.
movement.Set (camera.right * h, 0f, camera.forward * v);

Shooting a projectile but goes in wrong direction - 2D game

I am trying to make a simple game where I am shooting a projectile when the user touches the screen, I first spawn 8 projectiles (sprites) and when the user touches the screen I would like the top projectile to fly in the touch direction. I was able to do this; However, every time I shoot, the projectile goes in the wrong direction, here is an image which will illustrate the issue.
Obviously the image is still here but the object will continue flying until it goes out of the screen and then gets destroyed.
Here is the code snippet that handles this
GameplayController.cs
if (Input.GetMouseButtonDown(0))
{
Vector3 position = new Vector3(Input.mousePosition.x, Input.mousePosition.y, 0);
position = Camera.main.ScreenToWorldPoint(position);
GameObject target;
target = new GameObject();
target.transform.position = position;
Arrow comp = currentArrows[0].GetComponent<Arrow>();
comp.setTarget(target.transform);
comp.GetComponent<Arrow>().arrowSpeed = 12;
comp.GetComponent<Arrow>().shoot = true;
currentArrows.RemoveAt(0);
Destroy(target);
}
I know I am getting the mouse input here and not the phone touch and that's fine for me, later I will convert it to the touch input.
Arrow.cs
public bool shoot = false;
public float arrowSpeed = 0.0f;
public Vector3 myDir;
public float speed = 30.0f;
private Transform target;
// Use this for initialization
void Start () {
}
// Update is called once per frame
void Update () {
if(shoot)
{
transform.position += transform.right * arrowSpeed * Time.deltaTime;
}
}
public void setTarget(Transform targetTransform)
{
this.target = targetTransform;
Vector3 vectorToTarget = target.position - transform.position;
float angle = Mathf.Atan2(vectorToTarget.y, vectorToTarget.x) * Mathf.Rad2Deg;
Quaternion q = Quaternion.AngleAxis(angle, Vector3.forward);
transform.rotation = Quaternion.Slerp(transform.rotation, q, Time.deltaTime * speed);
}
private void OnBecameInvisible()
{
print("Disappeared");
Destroy(gameObject);
Gameplay.instance.isShooting = false;
}
Vector3 position = new Vector3(Input.mousePosition.x, Input.mousePosition.y, 0);
I think that your problem is that you're getting the screen coordinates by click, not the world coordinates, which is actually two different things. In order to direct your projectile correctly you need to convert your screen coordinates to world like it's done here.
The next thing is how you move the projectile:
transform.position += transform.right * arrowSpeed * Time.deltaTime;
You're moving the projectile to the right and then rotating it somehow. Maybe you should try to move it with Vector3.Lerp, which will be easier and rotate it with Transform.LookAt.

Categories

Resources