LoL mock-up Day 1: let’s get those cubes rolling

Hi again! Ali here. I’m keeping up my promise to do game dev seriously, so let’s cut out the intro and get that Unity project started.

So, as a reminder, I’m going for this:

I asked ChatGPT what a sensible list of steps to achieve this would be and the first thing was this:

🔧 Phase 1 – Basic Player Unit (Box) Setup

Goal: Move a box with mouse clicks and activate skills via keyboard

  1. Create a new Unity project (3D or URP)
    • Empty plane as the ground
    • A simple cube as the player character
  2. Implement Click-to-Move system
    • Use NavMeshAgent for pathfinding (quick and close to LoL-style movement)
    • On right-click, raycast to the ground and set agent destination
  3. Basic camera control
    • Lock the camera over the field
    • Add WASD or edge-screen movement if you want a LoL-style camera later

So let’s go!

First things I need: a big rectangle for the floor, a cube for the player, setup some player input.

I won’t get obsessed with pretty refactored code from the start because I don’t even know what a clean codebase for Unity looks like – I’ll turn my suffering later into knowledge. For now, I’ll just set up some Game Objects.

Plane’s there, cube’s there. Does it work? I don’t know — the camera for the game starts locked on the horizon, so even if you press play you don’t see if the default box colliders and gravity are working, so let’s work on that.

Camera Controls

Now, on a great beginner tutorial I saw by CodeMonkey where he makes an Overcooked mock-up (I can’t believe he’s so nice to give those tutorials for free), he used Cinemachine for camera controls so I’ll try using it here and seeing if it applies to my use case.

Get Cinemachine on the Package Manager…

…get a Cinemachine camera in there…

…and setup the position and rotation. For starters, I’ll forget moving the camera with the mouse and make it follow my player. What we want in a LoL setting is:

  • Position: change according to the player position, but always at a fixed distance
  • Rotation: manually set. The camera will never rotate in this game; we want it almost top-down, but slightly slanted for that good old isometric feel.

Luckily, Cinemachine lets you give two different controls to your Position and Rotation in your camera (they all start at “None”). Rotation is left at None; we just set the Rotation values manually in the Transform component. My “slightly slanted” camera will be at an angle of 70 on the X axis.

Now, we set the Position component to “Position Composer” which gives us a Cinemachine Position Composer in the bottom where we can set up more properties, including “Camera Distance”. Lovely! I’ll set it to 20 for now. Remember to set the “Tracking Target” in the camera to an object or it won’t work.

Camera settings. You can see the Rotation values are the ones I set; Position, the Position Composer takes care of.

Now, if you press play and edit the Player’s position manually, the camera follows it around!

Moving the cube

Unity has a default NavMesh system built in (apparently) so I’ll try that. To the ground, you can apply the NavMesh Surface component and set it up as a walkable surface (at this, point you’ll want to create a Layer for what your walkable area will be in and put the Floor object there)

Once you “Bake” the mesh, the Scene tab will give you a blue area that is walkable by default:

Now, to the Player object you add the Nav Mesh Agent. I’m fuzzy on each setting’s details right now so I’ll leave them as-is.

Now, we’ll need a script focused on controlling our player, so I’ll add a Scripts folder and a PlayerController script under it:

Now, a little side note: my InputSystem_Actions (based on Unity’s new Input System) didn’t come with the C# class automatically generated for me, so I had to enable that:

After that, you can use that class inside your MonoBehaviour, and my initial script pretty much goes like this:

using UnityEngine;
using UnityEngine.AI;
using UnityEngine.InputSystem;

public class PlayerController : MonoBehaviour {
    private NavMeshAgent agent;
    private InputSystem_Actions inputActions;

    private void Awake() {
        inputActions = new InputSystem_Actions();
    }

    // Start is called once before the first execution of Update after the MonoBehaviour is created
    void Start() {
        agent = GetComponent<NavMeshAgent>();

        inputActions.UI.Enable();
        inputActions.UI.RightClick.performed += OnRightClick;
    }

    private void OnRightClick(InputAction.CallbackContext obj) {
        Vector3 mousePos = Mouse.current.position.ReadValue();
        Ray ray = Camera.main.ScreenPointToRay(mousePos);
        if (Physics.Raycast(ray, out RaycastHit hitInfo)) {
            agent.SetDestination(hitInfo.point);
        }
    }

    // Update is called once per frame
    void Update() {
    }

    void OnDestroy() {
        inputActions.UI.RightClick.performed -= OnRightClick;
        inputActions.UI.Disable();
    }
}

Now we attach it to our Player object, press Play and there we go!

Phew. I guess we’re good for today. I do want to test whether this actually works around obstacles and how to prevent the player from falling off the edge of the screen, but I guess this is a good start! Stay tuned for updates.