Roll-a-Ball (Unity)
Setting up the Game
Create a new Unity project
- Login
- New Project - 3D (URP) - Universal Render Pipeline
Create a new Scene
- Layout
- All files in "Template" folder
- File - New scene
- File - Save as - Minigame (Scenes folder)
Create a primitive plane
- Add GameObject - Plane
- Rename "Ground"
- Reset transform
- F to focus
- Grid settings
Scale the Ground plane
- Scale x-2 y-1 z-2
Create a player GameObject
- Add GameObject - Sphere
- Reset transform
- F to focus
- Unity unit - 1 meter
- Elevate Sphere y +0.5
Adjust the default lighting
- Game view
- Directional light - set color to white
- Directional light rotation: x-50 y-50 z-0
Add colors with Materials
- Create materials folder
- Create background material - 130/130/130 - metallic - 0 / smoothness - 0.25
- Create player material - 0/220/255 - metallic - 0 / smoothness - 0.75
- Drag material to object
Moving the player
Add a Rigidbody to the player
- Add physics component to player - Rigidbody
Install the Input System package
- Window - Package manager - Input system - Install
- Enable new backend system - Yes
- (Windows only) File - Build settings - Architecture - x86_64
Add a Player Input component
- Add Player Input component to player
- Create Input actions - "Create actions" button
- Create "Input" folder - save action "InputActions"
- In Player Input - Actions field choose created Asset
Create a new script
- Create "Scripts" folder
- Add "PlayerController" script to player
Write the OnMove function declaration
- Remove Update function
- Namespaces
- Add namespace "UnityEngine.InputSystem"
- Create OnMove function (InputValue movementValue)
Apply input data to the Player
In PlayerController
1 Vector2 movementVector = movementValue.Get<Vector2>();
2
3 private Rigidbody rb;
In Start function
1 rb = GetComponent<Rigidbody>();
Add FixedUpdate() function
Apply force to the Player
private float movementX; private float movementY;
In OnMove movementX = movementVector.x; movementY = movementVector.y;
In FixedUpdate Vector3 movement = new Vector3(movementX, 0.0f, movementY); rb.AddForce(movement);
Fix the Player movement speed
public float speed = 0; rb.AddForce(movement * speed); speed in Editor = 10
Moving the camera
Set the Camera position
- Set camera position x=0 y=10 z=-10
- Rotate x=45 y=0 z=0
- Camera child of Player but will rotate with it
Write a CameraController script
Create CameraController script for camera public GameObject player; private Vector3 offset;
In Start function calculate offset offset = transform.position - player.transform.position;
Update functions order undefined so we use LateUpdate In LateUpdate function transform.position = player.transform.position + offset;
Reference the Player GameObject
- Drag player into player slot of the camera script
Setting up the Play Area
Create a wall for the play field
- Create empty object as root for Walls
- Create Cube as West/East/North/South walls
- Scale x=0.5 y=2 z=20.5
- Position -10
- New Material Walls - 79/79/79 - metallic 0 / smoothness - 0.25
Finish the play field walls
- Duplicate object
- Rotate or rescale
Creating collectibles
Create a collectible GameObject
- Add cube
- Move up 0.5
- Scale 0.5
- Rotate 45 45 45
- Material Pickup color 255 200 0
Rotate the PickUp GameObject
Add Rotator script to pickup Remove Start function in Update function transform.Rotate(new Vector3(15, 30, 45) * Time.deltaTime);
Make PickUp a Prefab
- Create Prefabs folder
- Open Prefab edit mode
Add more collectibles
- New Empty Object - PickupParent
- Reset transform
- Duplicate Pickup and move
Detecting Collisions with Collectibles
Disable PickUps with OnTriggerEnter
PlayerController create OnTriggerEnter(Collider other) other.gameObject.SetActive(false);
Add a tag to the PickUp Prefab
- Add Pickup tag to PickUp Prefab
- Create & Apply
Write a conditional statement
OnTriggerEnter if (other.gameObject.CompareTag("PickUp"))
Set the PickUp Colliders as triggers
Set Pickup Collider prefab as IsTrigger
Add a Rigidbody to the PickUp Prefab
- Add to improve performance
- Disable Use Gravity
- Check IsKinematic - no Physics
Displaying Score and Text
Store the value of collected PickUps
PlayerController private int count;
Start function count = 0;
OnTriggerEnter count++;
Create a UI text element
- Add UI => Text - TextMeshPro
- Import TMP Essentials
- All UI in Canvas
- Rename New Text CountText
- Add CountText as placeholder
- Anchor text left top with Alt + Shift
- PosX = 10 PosY = -10
Display the count value
PlayerController Add TMPro namespace public TextMeshProUGUI countText;
new function SetCountText countText.text = "Count: " + count.ToString();
Add SetCountText() to Start and OnTriggerEnter
Drop Text object to script
EventSystem push "Replace with InputSystemUIInputModule"
Create a game end message
new TextMeshPro
- Text - Black size 32
- Set Text - You win!
- PosX = 0 posY = 130
- Align center
Add reference to text as GameObject Disable in Start function - SetActive(false);
In SetCountText function
1 if (count >= 12)
2 {
3 winTextObject.SetActive(true);
4 }
Drop WinText in script
Build the Game
Create a build of your game
- Save ALL
- Build Settings
- For web build 2020 disable compression
- Choose platform
- Add open scenes
- Scenes list
- Player settings
- Full screen or windowed