Game Project: Flying Game - Part 1 - Introductory Movement and Camera Controller
April 30, 2021
Flying Game
Game Project
Overview
I wanted to do some work on a small, simple 3D game in Unity I could make within a week or so. My original focus is on player movement, and from there I decided to hone in on a flying game of some kind. I have been watching Thabeast721 on Twitch and he recently played Super Man 64 which I have also seen at Games Done Quick (GDQ) events and thought building off of and improving their flying controller could be a fun project.
Player Controllers
Controller #1 - Rotate Forward Axis
My initial thoughts on a basic flying player controller was to have left/right rotate the player on the y-axis, up/down rotate the player on the x-axis, and a separate button to propel the player in their current forward direction.
As a controller standard, I also tend to have the player's input be received in the Update method to receive as often as possible, but then output these inputs as movement in FixedUpdate to keep it consistent on machines with different frame rates.
private void Update() { horizontalInput = Input.GetAxisRaw("Horizontal"); verticalInput = Input.GetAxisRaw("Vertical"); if (Input.GetButton("Jump")) { isMoving = true; } else { isMoving = false; } } private void FixedUpdate() { // Inputs in reverse position for direction vector because that influences which axis that input rotates AROUND Vector3 direction = Vector3.Normalize(new Vector3(verticalInput * inversion, horizontalInput, 0.0f)); Flying(direction); } private void Flying(Vector3 dir) { RotatePlayer(dir); MovePlayer(dir); } private void RotatePlayer(Vector3 dir) { transform.Rotate(dir * rotationSpeed * Time.deltaTime); } private void MovePlayer(Vector3 dir) { if (isMoving) { transform.position += transform.forward * movementSpeed * Time.deltaTime; } }
Controller #2 - Rotate on Y-Axis but Translate Directly Vertically
With my second approach I wanted to try and emulate the flying controller from Super Man 64 just to see how it felt. It seems like a more acarde-y style of flying with easier controls, so I thought it would be a good option to investigate. For this horizontal rotation (rotation on the y-axis) remained the same, as this is pretty standard with grounded player controllers as well.
The up and down rotation (rotation on the x-axis) however, was completely removed. The up/down inputs from the player simply influence the movement vector of the player, adding some amount of up or down movement to the player. This makes it much easier to keep the player's forward vector relatively parallel to the ground and is much less disorienting than free-form rotational movement in the air.
private void Start() { if (isInvertedControls) { inversion = -1.0f; } } private void Update() { horizontalInput = Input.GetAxisRaw("Horizontal"); verticalInput = Input.GetAxisRaw("Vertical"); if (Input.GetButton("Jump")) { isMoving = true; } else { isMoving = false; } } private void FixedUpdate() { // Inputs in reverse position for direction vector because that influences which axis that input rotates AROUND Vector3 direction = Vector3.Normalize(new Vector3(verticalInput * inversion, horizontalInput, 0.0f)); Flying(direction); } private void Flying(Vector3 dir) { RotatePlayer(dir); MovePlayer(dir); } private void RotatePlayer(Vector3 dir) { transform.Rotate(dir.y * Vector3.up * rotationSpeed * Time.deltaTime); } private void MovePlayer(Vector3 dir) { if (isMoving) { Vector3 movementDirection = Vector3.Normalize(transform.forward + dir.x * Vector3.up); transform.position += movementDirection * movementSpeed * Time.deltaTime; } }
Camera Controller
Follow Position
To follow the player's position, I am using a really simple case where it just follows them at some fixed offset. The offset is originally determined by the initial position of the camera relative to the player, and then for the rest of its run its position is just that of the player summed with the offset.
Where transform.position is the position of the camera object: offset = transform.position - player.transform.position; transform.position = player.transform.position + offset;
Rotate to Follow
My first test just to initialize the camera follow was to child it to the player to see how it looked that way. This worked ok for following position, but having multiple rotation influences made this impossible to use quickly at first. As I changed the player controller to a more general, arcade-style, it worked better but was still poor for rotation.
To fix this I put the camera as a child onto a separate empty gameobject. This gameobject could then follow the player and rotate to rotate the camera around the player while keeping it at a fixed offset distance. This also made determining the rotation angle/looking vector from the camera to the player much simpler. Since the camera is rotate downward some, its forward vector is not in-line with the world z-axis anymore. This camera container however could keep its axes algined with the world's axes. This meant I could just make sure to align this container's forward vector with the player's forward facing vector on the xz-plane. To do so it just required the following:
private void RotateView() { Vector3 lookDirection = new Vector3(player.transform.forward.x, 0.0f, player.transform.forward.z); transform.rotation = Quaternion.LookRotation(lookDirection, Vector3.up); }
Unity's Quaternion.LookRotation method allows me to set the rotation of the object based on the direction of a forward facing vector (lookDirection in this case), with a perpendicular upward vector to make sure I keep the rotation solely around the y-axis.
The following is a quick look at how the final player controller and camera controller interact from this initial prototype approach:
Flying Game Project: Initial Player Controller and Camera Controller Prototypes from Steve Lilley on Vimeo.
Summary
Comments
Post a Comment