Lesson 4: Player Character & Movement
Introduction
Welcome to Lesson 4 of the "Build an AI-Powered RPG Game" course! In this lesson, we'll create the foundation of your RPG game by building a responsive player character with smooth movement, camera controls, and basic interactions. This is where your game starts to feel alive and playable.
Learning Objectives
By the end of this lesson, you will be able to:
- Create a player character with smooth movement controls
- Implement camera systems for RPG gameplay
- Add basic player interactions and animations
- Set up input systems for keyboard and gamepad
- Understand character controller vs rigidbody movement
- Create responsive and polished player movement
1. Setting Up the Player Character
Step 1: Create the Player GameObject
- In your Unity scene, right-click in the Hierarchy
- Create Empty and name it "Player"
- Add a Capsule as a child (right-click Player → 3D Object → Capsule)
- Rename the Capsule to "PlayerModel"
- Position the Player at (0, 1, 0) in the scene
Step 2: Add Character Controller
- Select the Player GameObject
- Add Component → Character Controller
- Adjust the Character Controller settings:
- Height: 2
- Radius: 0.5
- Center: (0, 1, 0)
- Slope Limit: 45
- Step Offset: 0.3
- Skin Width: 0.08
Step 3: Create Player Movement Script
- Create a new C# script called "PlayerController"
- Attach it to the Player GameObject
using UnityEngine;
public class PlayerController : MonoBehaviour
{
[Header("Movement Settings")]
public float walkSpeed = 5f;
public float runSpeed = 8f;
public float jumpHeight = 3f;
public float gravity = -9.81f;
[Header("Camera Settings")]
public Transform cameraTransform;
public float mouseSensitivity = 2f;
public float cameraPitchRange = 80f;
private CharacterController controller;
private Vector3 velocity;
private bool isGrounded;
private float cameraPitch = 0f;
void Start()
{
controller = GetComponent<CharacterController>();
// Lock cursor to center of screen
Cursor.lockState = CursorLockMode.Locked;
}
void Update()
{
HandleMovement();
HandleCamera();
HandleJump();
}
void HandleMovement()
{
// Check if grounded
isGrounded = controller.isGrounded;
if (isGrounded && velocity.y < 0)
{
velocity.y = -2f; // Small negative value to keep grounded
}
// Get input
float horizontal = Input.GetAxis("Horizontal");
float vertical = Input.GetAxis("Vertical");
// Calculate movement direction
Vector3 move = transform.right * horizontal + transform.forward * vertical;
// Apply speed (walk or run)
float currentSpeed = Input.GetKey(KeyCode.LeftShift) ? runSpeed : walkSpeed;
controller.Move(move * currentSpeed * Time.deltaTime);
// Apply gravity
velocity.y += gravity * Time.deltaTime;
controller.Move(velocity * Time.deltaTime);
}
void HandleCamera()
{
// Get mouse input
float mouseX = Input.GetAxis("Mouse X") * mouseSensitivity;
float mouseY = Input.GetAxis("Mouse Y") * mouseSensitivity;
// Rotate player left/right
transform.Rotate(Vector3.up * mouseX);
// Rotate camera up/down
cameraPitch -= mouseY;
cameraPitch = Mathf.Clamp(cameraPitch, -cameraPitchRange, cameraPitchRange);
cameraTransform.localEulerAngles = Vector3.right * cameraPitch;
}
void HandleJump()
{
if (Input.GetButtonDown("Jump") && isGrounded)
{
velocity.y = Mathf.Sqrt(jumpHeight * -2f * gravity);
}
}
}
2. Setting Up the Camera System
Step 1: Create Camera Setup
- Create an Empty GameObject called "CameraController"
- Add the Main Camera as a child
- Position the camera at (0, 1.6, 0) relative to the Player
- Create a new script called "CameraController" and attach it to the CameraController
using UnityEngine;
public class CameraController : MonoBehaviour
{
[Header("Camera Settings")]
public Transform target; // The player transform
public float followSpeed = 10f;
public Vector3 offset = new Vector3(0, 1.6f, 0);
void LateUpdate()
{
if (target != null)
{
// Smoothly follow the target
Vector3 desiredPosition = target.position + offset;
transform.position = Vector3.Lerp(transform.position, desiredPosition, followSpeed * Time.deltaTime);
}
}
}
Step 2: Connect Camera to Player
- Select the CameraController
- In the CameraController script, drag the Player into the "Target" field
- Test the camera by moving the player around
3. Improving Player Movement
Step 1: Add Movement Smoothing
Update your PlayerController script with these improvements:
[Header("Movement Settings")]
public float walkSpeed = 5f;
public float runSpeed = 8f;
public float jumpHeight = 3f;
public float gravity = -9.81f;
public float acceleration = 10f;
public float deceleration = 10f;
private Vector3 currentVelocity;
private Vector3 targetVelocity;
void HandleMovement()
{
// Check if grounded
isGrounded = controller.isGrounded;
if (isGrounded && velocity.y < 0)
{
velocity.y = -2f;
}
// Get input
float horizontal = Input.GetAxis("Horizontal");
float vertical = Input.GetAxis("Vertical");
// Calculate target movement direction
Vector3 move = transform.right * horizontal + transform.forward * vertical;
targetVelocity = move * (Input.GetKey(KeyCode.LeftShift) ? runSpeed : walkSpeed);
// Smooth acceleration/deceleration
if (move.magnitude > 0.1f)
{
currentVelocity = Vector3.Lerp(currentVelocity, targetVelocity, acceleration * Time.deltaTime);
}
else
{
currentVelocity = Vector3.Lerp(currentVelocity, Vector3.zero, deceleration * Time.deltaTime);
}
// Apply movement
controller.Move(currentVelocity * Time.deltaTime);
// Apply gravity
velocity.y += gravity * Time.deltaTime;
controller.Move(velocity * Time.deltaTime);
}
Step 2: Add Movement Animations
- Create an Animator Controller for your player
- Add basic animation states: Idle, Walk, Run, Jump
- Create transitions between states based on movement speed
- Connect the Animator to your PlayerController script
[Header("Animation")]
public Animator animator;
void HandleMovement()
{
// ... existing movement code ...
// Update animation parameters
if (animator != null)
{
animator.SetFloat("Speed", currentVelocity.magnitude);
animator.SetBool("IsGrounded", isGrounded);
animator.SetFloat("VerticalVelocity", velocity.y);
}
}
4. Adding Basic Interactions
Step 1: Create Interaction System
Add this to your PlayerController script:
[Header("Interaction")]
public float interactionRange = 3f;
public LayerMask interactionLayer = 1;
void Update()
{
HandleMovement();
HandleCamera();
HandleJump();
HandleInteraction();
}
void HandleInteraction()
{
if (Input.GetKeyDown(KeyCode.E))
{
TryInteract();
}
}
void TryInteract()
{
// Raycast forward to find interactable objects
RaycastHit hit;
if (Physics.Raycast(transform.position, transform.forward, out hit, interactionRange, interactionLayer))
{
// Check if the hit object has an interactable component
IInteractable interactable = hit.collider.GetComponent<IInteractable>();
if (interactable != null)
{
interactable.Interact();
}
}
}
Step 2: Create Interactable Interface
Create a new script called "IInteractable":
public interface IInteractable
{
void Interact();
}
Step 3: Create Example Interactable
Create a simple interactable object:
using UnityEngine;
public class SimpleInteractable : MonoBehaviour, IInteractable
{
[Header("Interaction Settings")]
public string interactionText = "Press E to interact";
public void Interact()
{
Debug.Log("Player interacted with " + gameObject.name);
// Add your interaction logic here
}
void OnDrawGizmosSelected()
{
// Visualize interaction range
Gizmos.color = Color.yellow;
Gizmos.DrawWireSphere(transform.position, 1f);
}
}
5. Input System Setup
Step 1: Configure Input Manager
- Go to Edit → Project Settings → Input Manager
- Verify these inputs exist:
- Horizontal: A/D keys and Left/Right arrow keys
- Vertical: W/S keys and Up/Down arrow keys
- Jump: Space key
- Mouse X: Mouse X axis
- Mouse Y: Mouse Y axis
Step 2: Add Gamepad Support
Update your PlayerController to support gamepad input:
[Header("Input Settings")]
public bool useGamepad = true;
void HandleMovement()
{
// Get input (keyboard or gamepad)
float horizontal = Input.GetAxis("Horizontal");
float vertical = Input.GetAxis("Vertical");
// Apply deadzone for gamepad
if (useGamepad)
{
float deadzone = 0.1f;
if (Mathf.Abs(horizontal) < deadzone) horizontal = 0;
if (Mathf.Abs(vertical) < deadzone) vertical = 0;
}
// ... rest of movement code ...
}
6. Testing and Polish
Step 1: Create a Test Scene
- Add some basic geometry to your scene (cubes, planes)
- Create ramps and platforms to test jumping
- Add an interactable object with the SimpleInteractable script
- Test all movement features:
- Walking and running
- Jumping
- Camera controls
- Interactions
Step 2: Performance Optimization
[Header("Performance")]
public bool enableMovementSmoothing = true;
public int maxCollisionChecks = 10;
void HandleMovement()
{
// Limit collision checks for performance
if (controller.isGrounded)
{
// ... movement code ...
}
}
7. Common Issues and Solutions
Issue: Player Sliding on Slopes
Solution: Adjust the Character Controller's Slope Limit and Step Offset values.
Issue: Camera Jitter
Solution: Use LateUpdate() for camera movement and adjust follow speed.
Issue: Movement Feels Sluggish
Solution: Increase acceleration and deceleration values, or adjust input sensitivity.
Issue: Jumping Through Ground
Solution: Ensure the Character Controller's Skin Width is appropriate for your ground colliders.
8. Mini-Task: Create Your First Level
Task: Create a simple test level with:
- A ground plane for the player to walk on
- Some obstacles to navigate around
- A platform to jump onto
- An interactable object to test the interaction system
Requirements:
- Player can move smoothly around the level
- Camera follows the player properly
- Jumping works on the platform
- Interaction system responds to the interactable object
9. Pro Tips for RPG Movement
Movement Feel
- Responsive Input: Keep input lag minimal
- Smooth Transitions: Use lerping for acceleration/deceleration
- Visual Feedback: Add particle effects for footsteps, dust, etc.
Camera Design
- Comfortable FOV: Use 60-75 degrees for RPG games
- Smooth Following: Avoid camera snapping or jittering
- Collision Avoidance: Implement camera collision with walls
Performance
- Optimize Collision Detection: Use appropriate collision layers
- Limit Update Frequency: Don't update every frame if not needed
- Profile Your Code: Use Unity's Profiler to identify bottlenecks
Conclusion & Next Steps
Congratulations! You've successfully created a responsive player character with smooth movement, camera controls, and basic interactions. Your RPG game now has a solid foundation for gameplay.
What you've accomplished:
- ✅ Player character with Character Controller
- ✅ Smooth movement with acceleration/deceleration
- ✅ Camera system with mouse look
- ✅ Jumping and gravity system
- ✅ Basic interaction system
- ✅ Input handling for keyboard and gamepad
In the next lesson, we'll dive into "Basic Combat System" where you'll learn to implement:
- Attack mechanics and animations
- Health and damage systems
- Combat UI and feedback
- Enemy AI basics
Community Support
Stuck? Have questions? Share your progress or ask for help in our Discord community! Join Discord