Make a player move towards the direction he is facing (Unity3D/C#) - c#

Right now I have a small soldier on the screen that moves with W, A, S, D and rotates / changes direction with the arrow keys. What I want to happen is when the player's direction changes (by using the arrow keys), pushing W will send him in that direction instead of up the screen.
Also (for example), if you are holding D and the right arrow key at the same time he should move in a circle about a point on the ground (instead of spinning in a circle while moving in a straight line to the right).
Here is my current code:
public class MovePlayer : MonoBehaviour {
void Update() {
// Rotate left
if (Input.GetKey (KeyCode.LeftArrow)) {
transform.Rotate(0, 0, 1.3f);
}
// Rotate right
if (Input.GetKey(KeyCode.RightArrow)) {
transform.Rotate(0, 0, -1.3f);
}
// Strafe left
if (Input.GetKey (KeyCode.A)) {
Vector3 position = this.transform.position;
position.x -= 0.055f;
this.transform.position = position;
}
// Move up
if (Input.GetKey (KeyCode.W)) {
Vector3 position = this.transform.position;
position.y += 0.043f;
this.transform.position = position;
}
// Move down
if (Input.GetKey (KeyCode.S)) {
Vector3 position = this.transform.position;
position.y -= 0.043f;
this.transform.position = position;
isMoving = true;
}
// Strafe right
if (Input.GetKey (KeyCode.D)) {
Vector3 position = this.transform.position;
position.x += 0.055f;
this.transform.position = position;
}
}
}
Any ideas? Wasn't sure what to search exactly.

Here is what I've done for my character (Plus a mouse script for directions)
update()
{
Vector3 dir = new Vector3(); //(0,0,0)
//float CharacterSpeed = 10.0f;
if (Input.GetKey(KeyCode.W) || Input.GetKey(KeyCode.UpArrow))
dir.z += 1.0f;
else if (Input.GetKey(KeyCode.A) || Input.GetKey(KeyCode.LeftArrow))
dir.x -= 1.0f;
else if (Input.GetKey(KeyCode.S) || Input.GetKey(KeyCode.DownArrow))
dir.z -= 1.0f;
else if (Input.GetKey(KeyCode.D) || Input.GetKey(KeyCode.RightArrow))
dir.x += 1.0f;
dir.Normalize();
transform.Translate(dir * CharacterSpeed * Time.deltaTime);
}
If you only have keyboard for movement : (I'm not %100 sure this one)
Vector3 dir = new Vector3(); //(0,0,0)
//float CharacterSpeed = 10.0f;
if (Input.GetKey(KeyCode.W) || Input.GetKey(KeyCode.UpArrow))
dir.z += 1.0f;
else if (Input.GetKey(KeyCode.A) || Input.GetKey(KeyCode.LeftArrow))
{
var Rotation = Quaternion.AngleAxis("Rotation Angle Here", transform.InverseTransformDirection(Vector3.up));
transform.localRotation *= Rotation;
}
else if (Input.GetKey(KeyCode.S) || Input.GetKey(KeyCode.DownArrow))
dir.z -= 1.0f;
else if (Input.GetKey(KeyCode.D) || Input.GetKey(KeyCode.RightArrow))
{
var Rotation = Quaternion.AngleAxis("Rotation Angle Here", transform.InverseTransformDirection(Vector3.up));
transform.localRotation *= Rotation;
}
dir.Normalize();
transform.Translate(dir * CharacterSpeed * Time.deltaTime);

You can use Transform.forward to get the facing direction in world space, then simply scale, and add up to the current position. Just hook up this to W:
this.transform.position += this.transform.forward * 0.043f;

Related

Clamping my camera to a min and max value

I tried many approaches, watched tutorials but can't wrap my head around to make the clamp work with my code that I have right now.
So I can zoom in and out but infinitely, how to clamp the camera to max value -5 which is slightly above my player, and min value around -15 which is far above my player.
// Control the distance between the object && camera
private void ZoomIntoObject(float maxZoom, float minZoom)
{
float scrollInput = Input.GetAxis("Mouse ScrollWheel");
//zPos = scrollInput;
// zPos = Mathf.Clamp(zPos, minZoom, maxZoom);
// While scrollwheel
if (scrollInput > 0.0f)
{
// Move forward on the z-as && Clamp maxZoom
transform.position += transform.forward;
} else if (scrollInput < 0.0) {
// Move forward on the z-as && Clamp maxZoom
transform.position -= transform.forward;
}
Debug.Log(zPos);
}
Calculate your new position, clamp its z component, then assign to position.
private void ZoomIntoObject(float maxZoom, float minZoom)
{
float scrollInput = Input.GetAxis("Mouse ScrollWheel");
Vector3 newPos = transform.position;
if (scrollInput > 0.0f)
{
newPos += transform.forward;
} else if (scrollInput < 0.0) {
newPos -= transform.forward;
}
newPos.z = Mathf.Clamp(newPos.z, minZoom, maxZoom);
transform.position = newPos;
}

Unity Player's Shoot Function Will Not Work

I am creating a game in Unity. I have so far been able to get my player to follow the mouse at a somewhat correct angle. I am also trying to implement a shooting function for the character that shoots from the correct angle (straight from the top of the player, toward the mouse at the time of shooting). When I click using this code, nothing happens. I have objects set up for player, bullet and fire Point.
public void Update()
{
if (FollowMouse || Input.GetMouseButton(0))
{
_target = Camera.ScreenToWorldPoint(Input.mousePosition);
_target.z = 0;
}
var delta = ShipSpeed * Time.deltaTime;
var bulletDelta = shootSpeed * Time.deltaTime;
bulletDelta *= Vector3.Distance(transform.position, _target);
if (ShipAccelerates)
{
delta *= Vector3.Distance(transform.position, _target);
}
angle = Mathf.Atan2(_target.y, _target.x) * Mathf.Rad2Deg;
transform.position = Vector3.MoveTowards(transform.position, _target, delta);
transform.rotation = Quaternion.Euler(0, 0, angle);
if (Input.GetMouseButtonDown(0) && Time.time > nextFire && numOfBullets > 0)
{
nextFire = Time.time + fireRate;
Instantiate(bullet, firePoint.position, firePoint.rotation);
numOfBullets--;
bullet.transform.position = Vector3.MoveTowards(bullet.transform.position, _target, bulletDelta);
}
}

Unity hold touch move horizontally

I have no idea how to start this, I want to move my character left and right when holding the touch.
Like in this game:
Example Game - Stairs from Ketchapp
I have only my script that detects the left or right space of the screen.
public float forwardSpeed = 5f;
public float sideSpeed = 5f;
private void Update()
{
Vector3 deltaPosition = transform.forward * forwardSpeed;
if (Input.touchCount > 0)
{
Vector3 touchPosition = Input.GetTouch(0).position;
if (touchPosition.x > Screen.width * 0.5f)
deltaPosition += transform.right * sideSpeed;
else
deltaPosition -= transform.right * sideSpeed;
}
transform.position += deltaPosition * Time.deltaTime;
}
This solution works for me. Its used in a simple block breaker game to move a paddle left or right.
void Update () {
if (Input.touchCount > 0){
Touch touch = Input.GetTouch(0);
int direction = (touch.position.x > (Screen.width / 2)) ? 1 : -1;
MovePaddle(direction);
}
}
void MovePaddle(int direction){
float xPos = transform.position.x + (direction * Time.deltaTime * paddleSpeed);
playerPos = new Vector3 (Mathf.Clamp (xPos, -8f, 8f), -9.5f, 0f);
transform.position = playerPos;
}
i think that what you are trying to say is to only move when you are pressing the screen, not?
maybe this might help you:
public float forwardSpeed = 5f;
public float sideSpeed = 5f;
private void Update()
{
Vector3 deltaPosition = transform.forward * forwardSpeed;
if (Input.touchCount > 0)
{
Vector3 touchPosition = Input.GetTouch(0).position;
if (touchPosition.x > Screen.width * 0.5f)
deltaPosition += transform.right * sideSpeed;
else
deltaPosition -= transform.right * sideSpeed;
}
else{
deltaPosition = sideSpeed;
}
transform.position += deltaPosition * Time.deltaTime;
}
pd: not tested because yet
I have a solution that is not really smooth
public float speed = 5;
public Rigidbody rb;
public void FixedUpdate()
{
float h = Input.GetAxis("Horizontal");
//Add touch support
if (Input.touchCount > 0 && Input.GetTouch(0).phase == TouchPhase.Moved)
{
Touch touch = Input.touches[0];
h = touch.deltaPosition.x;
}
//Move only if we actually pressed something
if (h > 0 || h < 0)
{
Vector3 tempVect = new Vector3(h, 0, 0);
tempVect = tempVect.normalized * speed * Time.deltaTime;
//rb.MovePosition(rb.transform.position + tempVect);
Vector3 newPos = rb.transform.position + tempVect;
checkBoundary(newPos);
}
}
void checkBoundary(Vector3 newPos)
{
//Convert to camera view point
Vector3 camViewPoint = Camera.main.WorldToViewportPoint(newPos);
//Apply limit
camViewPoint.x = Mathf.Clamp(camViewPoint.x, 0.04f, 0.96f);
camViewPoint.y = Mathf.Clamp(camViewPoint.y, 0.07f, 0.93f);
//Convert to world point then apply result to the target object
Vector3 finalPos = Camera.main.ViewportToWorldPoint(camViewPoint);
rb.MovePosition(finalPos);
}
private void Start()
{
Application.targetFrameRate = 60;
}
void Update()
{
if (Input.touchCount > 0)
{
Touch t = Input.GetTouch(0);
transform.position = new Vector3(transform.position.x + t.deltaPosition.x * .02f, transform.position.y, transform.position.z );
}
}
You can use this. Simple :)

How to Limit (clamp) Y axis Rotation for transform.rotatearound Unity

I have a camera that I want to rotate around a point (0,0,0) in all directions, but I want to put a clamp on it so that it can't go too far above or below the point. I have seen this question answered for the left and right directions before but never for the vertical one.
I have tried converting the code from these two questions (that basically say the same thing) to work in the vertical direction, but it bugs out at some points along the rotation, and I can't figure out why.
First Question, Second Question
And this is how I tried to convert it:
//how much we want to rotate by this frame
float rotX = Input.GetAxis("Mouse X") * rotSpeed;
float rotY = Input.GetAxis("Mouse Y") * rotSpeed; //(before clamping)
//find current direction
Vector3 currentDirection = transform.position - Vector3.zero;
//find current angle between basis for clamp & where we are now
float angle = Vector3.Angle(Vector3.forward, currentDirection);
//finds out if it's up or down
if (Vector3.Cross(Vector3.forward, currentDirection).x < 0) angle = -angle;
//find out how much you can move without violating limits
float newAngle = Mathf.Clamp(angle + rotY, yMinLimit, yMaxLimit);
//grabs how much you are allowed to move the angle from the current angle
rotY = newAngle - angle;
//spinning the garden
transform.RotateAround(Vector3.zero, Vector3.up, rotX);
transform.RotateAround(Vector3.zero, transform.TransformDirection(Vector3.right), -rotY); //vertical rotation
If anyone knows of the correct way to make this work for the Y axis, or a different way to clamp the vertical rotation, I would be super excited to hear it! Ty!
I have a class here that do exactly what you want. It rotates a camera around a target and clamps the Y rotation. It uses the left button to rotate and the scroll press button to translate the target.
You can edit it to adjust to your specific needs - you might want to change the target to a Vector3 so you can set it to (0,0,0) without the need of an object. Hope it helps.
using UnityEngine;
public class RotateAroundCamera : MonoBehaviour
{
Camera cam;
public bool isControlable;
private Vector3 screenPoint;
private Vector3 offset;
public Transform target;
public float distance = 5.0f;
public float xSpeed = 50.0f;
public float ySpeed = 50.0f;
public float yMinLimit = -80f;
public float yMaxLimit = 80f;
public float distanceMin = .5f;
public float distanceMax = 15f;
public float smoothTime = 2f;
public float rotationYAxis = 0.0f;
float rotationXAxis = 0.0f;
float velocityX = 0.0f;
float velocityY = 0.0f;
float moveDirection = -1;
public void SetControllable(bool value)
{
isControlable = value;
}
// Use this for initialization
void Start()
{
cam = GetComponentInChildren<Camera>();
Vector3 angles = transform.eulerAngles;
rotationYAxis = (rotationYAxis == 0) ? angles.y : rotationYAxis;
rotationXAxis = angles.x;
Rigidbody rigidbody = GetComponent<Rigidbody>();
// Make the rigid body not change rotation
if (rigidbody)
{
rigidbody.freezeRotation = true;
}
}
void LateUpdate()
{
if (target)
{
if (Input.GetMouseButton(1) && isControlable)
{
velocityX += xSpeed * Input.GetAxis("Mouse X") * 0.02f;
velocityY += ySpeed * Input.GetAxis("Mouse Y") * 0.02f;
}
if (Input.GetMouseButton(2) && isControlable)
{
Vector3 curScreenPoint = new Vector3(moveDirection*Input.mousePosition.x, moveDirection*Input.mousePosition.y, screenPoint.z);
Vector3 curPosition = cam.ScreenToWorldPoint(curScreenPoint) + offset;
target.transform.position = curPosition;
}
if (Input.GetKeyDown(KeyCode.R) && isControlable)
{
target.transform.position = Vector3.zero;
}
if (Input.GetKeyDown(KeyCode.T) && isControlable)
{
moveDirection *= -1;
}
if (isControlable)
{
distance -= Input.GetAxis("Mouse ScrollWheel");
if (distance > distanceMax)
{
distance = distanceMax;
}
else if (distance < distanceMin)
{
distance = distanceMin;
}
}
rotationYAxis += velocityX;
rotationXAxis -= velocityY;
rotationXAxis = ClampAngle(rotationXAxis, yMinLimit, yMaxLimit);
Quaternion fromRotation = Quaternion.Euler(transform.rotation.eulerAngles.x, transform.rotation.eulerAngles.y, 0);
Quaternion toRotation = Quaternion.Euler(rotationXAxis, rotationYAxis, 0);
Quaternion rotation = toRotation;
Vector3 negDistance = new Vector3(0.0f, 0.0f, -distance);
Vector3 position = rotation * negDistance + target.position;
transform.rotation = rotation;
transform.position = position;
velocityX = Mathf.Lerp(velocityX, 0, Time.deltaTime * smoothTime);
velocityY = Mathf.Lerp(velocityY, 0, Time.deltaTime * smoothTime);
screenPoint = cam.WorldToScreenPoint(target.transform.position);
offset = target.transform.position - cam.ScreenToWorldPoint(new Vector3(moveDirection*Input.mousePosition.x, moveDirection*Input.mousePosition.y, screenPoint.z));
}
}
public static float ClampAngle(float angle, float min, float max)
{
if (angle < -360F)
angle += 360F;
if (angle > 360F)
angle -= 360F;
return Mathf.Clamp(angle, min, max);
}
}

Rotate an object diagonally and prevent it from going back to 90,180,0,360 degrees

After holding down on a combination keys of AS,SD,DW or WA to move my object, it will successfully move diagonally and rotate to the correct position, but after releasing the keys, it will rotate back to either 0,90,180 or 360 depending on the nearest rotation after releasing my keys, I guess it's because of that 1 frame that I left the keys touched, so it ran that code and moved it to 0,90,180,360. But I don't know how to solve it.
I hope I've provided enough information, and thanks for helping out.
I'm pressing onto AW keys together
After releasing the keys, it doesn't stay that way but moves to either left or top
PlayerMovement.cs
using UnityEngine;
using System.Collections;
public class playerMovement : MonoBehaviour {
private float speedWalk = 7.5f;
private float speedRotate = 7.5f;
private GameObject raycastObject;
// Update is called once per frame
void FixedUpdate ()
{
//Non-Diagonal Movements
if (Input.GetKey(KeyCode.W) && !Input.GetKey(KeyCode.A) && !Input.GetKey(KeyCode.S) && !Input.GetKey(KeyCode.D)) //player movement up
{
transform.localPosition += new Vector3(0.0f, 0.0f, speedWalk * Time.deltaTime);
}
if (Input.GetKey(KeyCode.S) && !Input.GetKey(KeyCode.A) && !Input.GetKey(KeyCode.W) && !Input.GetKey(KeyCode.D)) //player movement down
{
transform.localPosition -= new Vector3(0.0f, 0.0f, speedWalk * Time.deltaTime);
}
if (Input.GetKey(KeyCode.D) && !Input.GetKey(KeyCode.A) && !Input.GetKey(KeyCode.W) && !Input.GetKey(KeyCode.S)) //player movement right
{
transform.localPosition += new Vector3(speedWalk * Time.deltaTime, 0.0f, 0.0f);
}
if (Input.GetKey(KeyCode.A) && !Input.GetKey(KeyCode.D) && !Input.GetKey(KeyCode.W) && !Input.GetKey(KeyCode.S)) //player movement left
{
transform.localPosition -= new Vector3(speedWalk * Time.deltaTime, 0.0f, 0.0f);
}
//Diagonal Movements **########** I think this is the problem.
if (Input.GetKey(KeyCode.A) && Input.GetKey(KeyCode.W)) //player movement Top Left
{
transform.localPosition -= new Vector3(speedWalk * Time.deltaTime, 0.0f, 0.0f);
transform.localPosition += new Vector3(0.0f, 0.0f, speedWalk * Time.deltaTime);
}
if (Input.GetKey(KeyCode.W) && Input.GetKey(KeyCode.D)) //player movement Top Right
{
transform.localPosition += new Vector3(0.0f, 0.0f, speedWalk * Time.deltaTime);
transform.localPosition += new Vector3(speedWalk * Time.deltaTime, 0.0f, 0.0f);
}
if (Input.GetKey(KeyCode.D) && Input.GetKey(KeyCode.S)) //player movement Bottom Right
{
transform.localPosition += new Vector3(speedWalk * Time.deltaTime, 0.0f, 0.0f);
transform.localPosition -= new Vector3(0.0f, 0.0f, speedWalk * Time.deltaTime);
}
if (Input.GetKey(KeyCode.S) && Input.GetKey(KeyCode.A)) //player movement Bottom Left
{
transform.localPosition -= new Vector3(0.0f, 0.0f, speedWalk * Time.deltaTime);
transform.localPosition -= new Vector3(speedWalk * Time.deltaTime, 0.0f, 0.0f);
}
}
}
playerRotateMouse.cs
using UnityEngine;
using System.Collections;
public class playerRotateMouse : MonoBehaviour
{
public Transform Player;
private float speed = 7.5f;
Quaternion targetRotation;
void FixedUpdate()
{
Plane playerPlane = new Plane(Vector3.up, transform.position);
// Generates a ray from cursor
Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
float hitdist = 0.0f;
if (Input.GetButtonDown("Fire1") || Input.GetButtonDown("Fire2"))
{
if (playerPlane.Raycast(ray, out hitdist))
{
Vector3 targetPoint = ray.GetPoint(hitdist);
Debug.DrawRay(transform.position, targetPoint, Color.green);
targetRotation = Quaternion.LookRotation(targetPoint - transform.position);
}
}
// Smooth rotation towards point.
transform.rotation = Quaternion.Slerp(transform.rotation, targetRotation, speed * Time.deltaTime);
//Rotate base on key pressed
if (Input.GetKey(KeyCode.W) && !(Input.GetButton("Fire1") || Input.GetButton("Fire2"))) //player rotate up
{
targetRotation = Quaternion.LookRotation(Vector3.forward);
transform.rotation = Quaternion.Slerp(transform.rotation, targetRotation, speed * Time.deltaTime);
}
if (Input.GetKey(KeyCode.S) && !(Input.GetButton("Fire1") || Input.GetButton("Fire2"))) //player rotate down
{
targetRotation = Quaternion.LookRotation(Vector3.forward * -1);
transform.rotation = Quaternion.Slerp(transform.rotation, targetRotation, speed * Time.deltaTime);
}
if (Input.GetKey(KeyCode.D) && !(Input.GetButton("Fire1") || Input.GetButton("Fire2"))) //player rotate right
{
targetRotation = Quaternion.LookRotation(Vector3.right);
transform.rotation = Quaternion.Slerp(transform.rotation, targetRotation, speed * Time.deltaTime);
}
if (Input.GetKey(KeyCode.A) && !(Input.GetButton("Fire1") || Input.GetButton("Fire2"))) //player rotate left
{
targetRotation = Quaternion.LookRotation(Vector3.left);
transform.rotation = Quaternion.Slerp(transform.rotation, targetRotation, speed * Time.deltaTime);
}
}
}
I would save a last timestamp, and check if the second key release is within a certain timeframe. If it is release within (for example) 20ms, don't reset it is pressed.
For example: (pseudo)
private bool[] _directionKeysPressed = new bool[4];
private DateTime _previousKeyRelease;
private void KeyDown(object sender, EventArgs e)
{
_keyPressedCount++;
switch(keys)
{
case(W): _directionKeysPressed[0] = true;
case(D): _directionKeysPressed[1] = true;
// .................
}
}
private void KeyUp(object sender, EventArgs e)
{
_keyPressedCount--;
if(_keyPressedCount == 0)
{
// all keys released
_directionKeysPressed[] <--- last direction...
// reset all bools
return;
}
// ONLY if the key is released outside the 20 ms, reset the key.
if(_previousKeyRelease.AddMilliseconds(20) < DateTime.UTCNow)
{ // RESET KEY
switch(keys)
{
case(W): _directionKeysPressed[0] = false;
case(D): _directionKeysPressed[1] = false;
// .................
}
}
_previousKeyRelease = DateTime.UTCNow;
}
Personally I would do this with an bitfield in a Int32, but it is more clear with an array of bool.

Categories