Game Project: Flying Game – Part 3 – Camera Controller and Zoom Control

May 25, 2021

Flying Game

Camera Controller


Overview

After getting the basics of the camera controller down, I wanted to explore ways to make it feel more immersive. One of the ways I’ve seen racing or other fast moving games handle this was to have a zoom that mimicked the acceleration to make that feel all the more impactful. Following this, I wanted to look into connecting the player’s speed with the amount the camera zooms in on the player.

Setting the Camera Zoom Suggested by Player Speed

Since the game has a speed boost option, I wanted the impact of the speed boost to be larger than any normal speed the player can reach. With this in mind, I was looking at an approach where normally their max speed gets the camera up to around 80% of the maximum zoom, and activating a boost is the only way to hit the 100% zoom mark (creating a significant difference in zoom specifically when boosting).

One immediate issue with this approach is that any zoom that is directly tied to player speed has a jarring jump in zoom position when the player boosts, since in a single frame it jumps from rather low zoom (because charing boost goes with slowing down) to maximum zoom. So while this was a decent initial approach, I knew I would want a smoother transition system to especially deal with this common extreme case.

The approach I thought of was that the camera zoom system would read the player’s speed and suggest a position for the camera to move to. If that new position is substantially far away from the current position, it would only move a portion of the way there instead of directly there. This would help me spread out extremely large zoom changes over several frames, similar to how a Lerp function may handle this.

This ended up working rather well, and can be seen in action in the video I have linked. Another hopeful benefit of this system was that I was hoping I could remove the small zoom jitter when the player’s speed is not changing any appreciable amount. This is an effect that happens often when the player is consistently maintaing the normal top speed. I was hoping to use the opposite distance check of not changing the zoom at all at very small distance changes, but as can be seen in the video as well this does not particularly fix it currently.

Camera Controller – Zoom Focus from Steve Lilley on Vimeo.

Video: Zoom Based on Speed System for Camera Controller

via Blogger http://stevelilleyschool.blogspot.com/2021/05/game-project-flying-game-part-3-camera.html

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

via Blogger http://stevelilleyschool.blogspot.com/2021/04/game-project-flying-game-part-1.html

2014 GDC Talk – 50 Game Camera Mistakes

April 6, 2021

GDC 2014 Talk

Camera Controller


Title:
GDC 2014 Talk – 50 Game Camera Mistakes


Youtube – Link

Description:
A talk on common issues with camera controllers game developers make and how to avoid them.


Overview

As I was fixing some issues I had with my Unity camera for my architecture project, I came across this talk and thought it would be useful moving forward to understand camera controllers in games in general. It’s a bit older, but it should still be very useful for getting some tips for establishing a base understanding of some issues you may run into starting a camera controller.

via Blogger http://stevelilleyschool.blogspot.com/2021/04/2014-gdc-talk-50-game-camera-mistakes.html

2D Platformer Follow Camera Tutorial by Press Start and my Chunk Camera Concept

January 26, 2021

Camera

2D Platformer Design


Title:
Mario Style Camera Follow Tutorial

By:
Press Start


Youtube – Tutorial

Description:
Camera tutorial that follows similar to Mario for 2D platformers.


Overview

I got to implementing this tutorial into my 2D platformer project, which let me observe some of the pros and cons of this approach the way they created it. They created a direct following camera, which used a threshold to determine if the player is some distance from the center of the camera, and if so, starts to follow them as they move. I also created my own camera controller variation which moves in more

Camera Controller: Follow Camera (by Press Start)

This is the camera controller created in the tutorial linked above. The camera follows an object, generally the player, smoothly as they press against the borders of the camera threshold. The object must move some significant amount of distance before the camera moves. This keeps the camera from constantly moving, keeping more of the environment in a static frame longer.

There is an offset distance which is the distance from the edge of the camera that sets the bounds of the threshold box. When the follow object moves outside of this box, the camera begins to follow it. As long as the object continues to move out of the box, the camera will continue to keep following it.

Unity Orthographic Size

Orthographic Size: half the height in world units that the camera renders


The horizontal dimension rendered is solely determined by the screen ratio along with the height determined by orthographic size. Determining the size of a camera to fit objects vertically is very straightforward, as it is just half of the world units you would like to render. If you want to fit something horizontally however, you must include the screen ratio and use that as a multiplier (screen height / screen width) to convert the world width into an orthographic size value.

Issue: Stuttering

Originally the camera following gave a stuttering, glitchy effect while following the player at times, especially when jumping. I believe this is a result of changing the speed value set for the camera to match the player speed when it is large, since it uses the magnitude of the player’s velocity vector. This can change a lot very quickly, especially when jumping since this combines the x and y vector values of the player’s movement at that point.

Changing this speed check and set to solely the x-axis helped with consistency for most movement because most movement is horizontal. This however will most likely have a large impact if there is a lot of vertical movement since it will still be looking at the player’s velocity in the x to move the camera, regardless of their y velocity.

My Implementation of the FollowCamera Script with Modification

Alternate Camera Controller: Chunk Camera

Because of the stuttering effect I originally encountered, I tried making another type of camera controller that I thought may be a good option. I wanted to use a chunk movement approach where once the player reached the threshold of the current camera position, it would move the camera in that direction an entire chunk distance, centering the camera on the next location as opposed to directly moving with the player. The idea with this is that it keeps the camera movement more consistent, as well as showing the player much more of the next area they intend to move into more quickly.

I approached this by creating an IEnumerator named TransitionCamera that activates when the player hits a threshold. This begins a Lerp movement for the camera to the next designated chunk area, determined at Start based on the screen size and the threshold distance. A chunk distance is determined as: screen size – threshold distance. This centers the camera one full screen over, with an overlap from the previous screen equal to the threshold distance.

I also added a check to stop the coroutine if it was running and it was determined that it should start moving again to prevent weird whiplash effects if a player somehow was able to move back and forth between two screens very quickly. While mostly effective, this did have the negative resulting bug of slightly offsetting the camera completely over time because the TransitionCamera coroutine would be stopped prematurely and start moving to a new location solely determined by the current location +/- the chunk distance.

My Chunk Camera Variation

Summary

The original FollowCamera camera controller had more issues than I anticipated, so making it clean and consistent will take significantly more work. The jitteriness of the original implementation is unusable, but the modification at least makes it decent to use as a base for now as long as most movement is horizontal.

The chunk camera modification is at least cleaner already, although it still needs a bit of tweaking to make something that does not get slowly offset over time. This however probably only works for specific games and cannot be used for every 2D game case. Having both of these options is nice moving forward and is easy to switch between.

via Blogger http://stevelilleyschool.blogspot.com/2021/01/2d-platformer-follow-camera-tutorial-by.html

2D Platformer Mario Style Camera Follow Tutorial by Press Start

January 14, 2021

Camera

2D Platformer Design


Title:
Mario Style Camera Follow Tutorial

By:
Press Start


Youtube – Tutorial

Description:
Camera tutorial that follows similar to Mario for 2D platformers.


Overview

I want to get back to working with 2D platforming programming and came across this useful tutorial for creating a decent camera controller. Tutorials like this are always nice as the camera is a very critical element of the overall feel of a 2D platformer, but it isn’t something I necessarily want to focus my time on for now, so this gives me a good starting point that I can quickly implement and tweak for my needs starting out. If it becomes more critical later in the process, I can come back to it with other methods.

via Blogger http://stevelilleyschool.blogspot.com/2021/01/2d-platformer-mario-style-camera-follow.html