I've been recently working on a project using Unity Engine that involves a sort of Top-Down, 3rd person view, and I have been having trouble with the character movement.
I want to implement a way for the player to move throughout the map using either WASD movement, Click-to-Move movement, or Drag-to-Move movement, allowing them to use either of these freely and at any time, yet I have not yet found a way of doing this, since the methods end up cancelling each other out, leading the Player Character to awkward movement and to getting stuck in place.
Is there any way of achieving this? If so, any tips/suggestions would be greatly appreciated. Please keep in mind I am a complete beginner when it comes to both Unity and C#, so I might not grasp some core concepts yet.
I have attached my PlayerMovement
C# code below.
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.AI;
[RequireComponent(typeof(test))]
public class PlayerMovement : MonoBehaviour
{
private test _input;
//click2move
private NavMeshAgent agent;
//x
[SerializeField]
private bool RotateTowardMouse;
[SerializeField]
private float MovementSpeed;
[SerializeField]
private float RotationSpeed;
[SerializeField]
private Camera Camera;
void Start()
{
//c2m
agent = GetComponent<NavMeshAgent>();
//x
}
private void Awake()
{
_input = GetComponent<test>();
}
// Update is called once per frame
void Update()
{
var targetVector = new Vector3(_input.InputVector.x, 0, _input.InputVector.y);
var movementVector = MoveTowardTarget(targetVector);
agent.autoBraking = true;
if (!RotateTowardMouse)
{
RotateTowardMovementVector(movementVector);
}
if (RotateTowardMouse)
{
RotateFromMouseVector();
}
//c2m
Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
RaycastHit hit;
if (Physics.Raycast(ray, out hit))
{
if (Input.GetMouseButtonDown(0))
{
agent.SetDestination(hit.point);
}
}
else
{
if (agent.remainingDistance < 1)
{
agent.ResetPath();
}
}
}
private void RotateFromMouseVector()
{
Ray ray = Camera.ScreenPointToRay(_input.MousePosition);
if (Physics.Raycast(ray, out RaycastHit hitInfo, maxDistance: 300f))
{
var target = hitInfo.point;
target.y = transform.position.y;
transform.LookAt(target);
}
}
private Vector3 MoveTowardTarget(Vector3 targetVector)
{
var speed = MovementSpeed * Time.deltaTime;
// transform.Translate(targetVector * (MovementSpeed * Time.deltaTime)); Demonstrate why this doesn't work
//transform.Translate(targetVector * (MovementSpeed * Time.deltaTime), Camera.gameObject.transform);
targetVector = Quaternion.Euler(0, Camera.gameObject.transform.rotation.eulerAngles.y, 0) * targetVector;
var targetPosition = transform.position targetVector * speed;
transform.position = targetPosition;
return targetVector;
}
private void RotateTowardMovementVector(Vector3 movementDirection)
{
if (movementDirection.magnitude == 0) { return; }
var rotation = Quaternion.LookRotation(movementDirection);
transform.rotation = Quaternion.RotateTowards(transform.rotation, rotation, RotationSpeed);
}
}
CodePudding user response:
I would highly recommend that you use the Unity Input System. It can automate switching between input devices and decouple your code from any specific controls. It might be a bit overwhelming if you have limited experience with C#, but there is a vast library of tutorial videos and written guides you can rely on.
The PlayerInput
component is what detects when different input devices are added or removed and switches to the first valid control scheme. When a user activates the inputs required to trigger something in your game, that is represented as an Action
. A set of callbacks for that action are called depending on the states of the input: started
, performed
, and canceled
. These are where you hook up your character controller to the input and run any extra logic necessary to turn an input into movement. The Input System also has a feature called interactions that will probably be useful, especially for drag-to-move controls.
Good luck! If you'd like me to explain something further or point you to a good tutorial, feel free to tag me in a comment.
CodePudding user response:
First create a Capsule in the scene, drag the main camera to its object, hang the script under the Capsule object, WASD controls the movement direction, the space moves up along the Y axis, and the F moves down along the Y axis, thank you
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class MoveCam : MonoBehaviour
{
private Vector3 m_camRot;
private Transform m_camTransform;//Camera Transform
private Transform m_transform;//Camera parent object Transform
public float m_movSpeed=10;//Movement factor
public float m_rotateSpeed=1;//Rotation factor
private void Start()
{
m_camTransform = Camera.main.transform;
m_transform = GetComponent<Transform>();
}
private void Update()
{
Control();
}
void Control()
{
if (Input.GetMouseButton(0))
{
//Get the mouse movement distance
float rh = Input.GetAxis("Mouse X");
float rv = Input.GetAxis("Mouse Y");
// rotate the camera
m_camRot.x -= rv * m_rotateSpeed;
m_camRot.y = rh*m_rotateSpeed;
}
m_camTransform.eulerAngles = m_camRot;
// Make the main character face in the same direction as the camera
Vector3 camrot = m_camTransform.eulerAngles;
camrot.x = 0; camrot.z = 0;
m_transform.eulerAngles = camrot;
// Define 3 values to control movement
float xm = 0, ym = 0, zm = 0;
//Press W on the keyboard to move up
if (Input.GetKey(KeyCode.W))
{
zm = m_movSpeed * Time.deltaTime;
}
else if (Input.GetKey(KeyCode.S))//Press keyboard S to move down
{
zm -= m_movSpeed * Time.deltaTime;
}
if (Input.GetKey(KeyCode.A))//Press keyboard A to move left
{
xm -= m_movSpeed * Time.deltaTime;
}
else if (Input.GetKey(KeyCode.D))//Press keyboard D to move right
{
xm = m_movSpeed * Time.deltaTime;
}
if (Input.GetKey(KeyCode.Space) && m_transform.position.y <= 3)
{
ym =m_movSpeed * Time.deltaTime;
}
if (Input.GetKey(KeyCode.F) && m_transform.position.y >= 1)
{
ym -= m_movSpeed * Time.deltaTime;
}
m_transform.Translate(new Vector3(xm,ym,zm),Space.Self);
}
}