Unit 2: Player Controls and Positioning
I. Orientation: The Control–Physics–Animation Loop
A 3D player character is never a single object; it is a stack of cooperating systems — an input layer that samples the device, a controller that converts intent into displacement, a physics layer that validates that displacement against the world, and an animation layer that makes it readable. This unit uses Unity (2019.3+, with the Input System 1.x and Animation Rigging 1.x packages) and the free 3D Game Kit as its reference implementation, since the Kit ships a complete, inspectable player (Ellen) built exactly on this stack.
Defining assumptions used throughout:
- Frame model:
Update()runs once per rendered frame (variableTime.deltaTime);FixedUpdate()runs on a fixed physics tick (Time.fixedDeltaTime, default 0.02 s = 50 Hz);LateUpdate()runs after all animation evaluation. - Left-handed coordinate space: +X right, +Y up, +Z forward. Rotations are stored as
Quaternion, authored in the Inspector as Euler degrees. - Transform hierarchy: every positioned object has a
Transform; child positions are expressed in parent-local space, which is why rig targets and weapon mounts are parented rather than copied each frame. - Determinism boundary: physics forces are frame-rate independent only inside
FixedUpdate; directtransformwrites bypass physics and must be reconciled by a controller. - Composition over inheritance: behaviour is assembled from components on a GameObject, so a "player" is a prefab-level contract, not a class.
II. Game Manager Physics — the rules that validate movement
A. The physics model and its components
Unity's 3D physics is a wrapper over PhysX; a manager-level configuration governs every moving actor.
- Rigidbody: grants mass (kg), drag, and integration of forces.
mass = 70withuseGravity = trueyields weight ≈ 70 × 9.81 ≈ 687 N. - Collider: the collision shape (
BoxCollider,CapsuleCollider,MeshCollider). Capsules are standard for humanoids because they slide off ledges instead of catching. - Project Settings → Physics: global gravity
(0, -9.81, 0), default solver iterations (6), bounce threshold, and the Layer Collision Matrix, which cheaply disables whole interaction pairs (e.g.Player×PlayerAttackunchecked). - PhysicMaterial: static/dynamic friction and bounciness; an icy platform is simply friction 0.02, combine mode Minimum.
B. Integration and the manager's role
A GameManager-style singleton owns global physics state (time scale, gravity tuning, pause) so that no individual actor mutates it.
void FixedUpdate() {
verticalVelocity += Physics.gravity.y * gravityMultiplier * Time.fixedDeltaTime;
rb.MovePosition(rb.position + moveDir * speed * Time.fixedDeltaTime);
}
// verticalVelocity: m/s; gravityMultiplier: dimensionless tuning (2–3 for snappy jumps)- Jump velocity: to reach height
h,v₀ = √(2·g·h); forh = 2 m,v₀ ≈ 6.26 m/s. - Pausing:
Time.timeScale = 0haltsFixedUpdateaccumulation; anything driven byTime.unscaledDeltaTime(menus) keeps running.
C. CharacterController versus Rigidbody control
- Rigidbody (simulated): responds to forces, explosions and joints; realistic but prone to slide, jitter on stairs, and unpredictable air control.
- CharacterController (kinematic sweep):
controller.Move(motion)sweeps a capsule, resolvingslopeLimit(default 45°) andstepOffset(0.3 m), and reports contacts incollisionFlags. The 3D Game Kit's Ellen uses this — precise authored feel, but gravity and pushback must be coded by hand.
D. Limitations
- Tunnelling: fast objects skip thin colliders; fix with
collisionDetectionMode = ContinuousDynamicor raycast-based sweeps. - Cost:
MeshCollider(non-convex) is static-only and expensive; prefer primitive compounds.
III. Gameplay Components — the reusable behaviour vocabulary
A. What a gameplay component is
A gameplay component is a small MonoBehaviour exposing serialized fields and events, so designers assemble mechanics in the Inspector without new code.
- Contract: one responsibility, public tuning fields,
UnityEventhooks for outcomes. - Discovery: components locate one another via
GetComponent<T>()cached inAwake(), never inUpdate().
B. The 3D Game Kit's component set
PlayerController: reads input, drives theCharacterController, and sets animator floats such as forward speed.Damageable: holdsmaxHitPoints,invulnerabilityTime, a hit-angle/direction filter, and firesOnDeath,OnReceiveDamage,OnHitWhileInvulnerable.Damager: a box-shaped trigger volume enabled for the active frames of an attack; callsDamageable.ApplyDamage().InteractOnTrigger/InteractOnButton: raise UnityEvents when a tagged collider enters, used for doors and pressure pads.CheckpointSystem/Checkpoint: stores respawn transform; on death the player is teleported and health restored.SceneController: handles transition, fade and persistence between scenes.
C. Positioning-specific components
SimpleTransformer(translate/rotate): moves platforms on a curve between waypoints; the player parented on contact so relative position is preserved.TargetScanner: cone-of-vision check (detectionAngle,detectionRadius) used by enemies to acquire the player's transform.
IV. Objects in the 3D Game Kit — the authored content layer
A. Kit structure
The Kit is a prefab library plus a set of scene-authoring tools sitting on the systems above.
- Folders:
3DGamekit/Prefabs,/Art,/Scripts,/ScriptableObjects. - Kit Tools menu: creates a preconfigured scene containing player, camera rig, post-processing volume and UI.
B. Object categories
- Character objects: Ellen (player prefab: mesh,
CharacterController,PlayerInput,Damageable, staffDamager); enemies Chomper, Spitter, Grenadier, each withEnemyController,TargetScannerand a behaviour state machine. - Interactive objects: doors, pressure pads, moving platforms, destructible boxes, acid pits — all
InteractOnTrigger+UnityEventcompositions. - Environment objects: modular ProBuilder-friendly meshes snapped to a 1-unit grid so positioning stays consistent.
C. Positioning conventions
- Pivot at feet: character prefabs place the origin at ground level so
transform.position.yequals ground height. - Snapping: hold Ctrl while dragging to snap by the Grid Snapping increment; use V (vertex snap) to align modular pieces exactly.
V. Advanced Input System — device-agnostic intent
A. Purpose and architecture
The Input System package replaces polling of hard-coded axes with a data asset that maps physical controls to named actions, resolved at runtime per device.
- Input Actions asset (
.inputactions): contains Action Maps (Player, UI), Actions, Bindings, and Control Schemes (Keyboard&Mouse, Gamepad). - Action types:
Value(continuous, e.g. Move →Vector2),Button(Jump),Pass Through. - Composite binding: 2D Vector composite binds W/A/S/D into one
Vector2; a Stick Deadzone processor filters drift.
B. Reading input
public void OnMove(InputAction.CallbackContext ctx) {
moveInput = ctx.ReadValue<Vector2>(); // x = strafe, y = forward, each in [-1,1]
}
public void OnJump(InputAction.CallbackContext ctx) {
if (ctx.performed) jumpQueued = true; // phases: started → performed → canceled
}- PlayerInput component: behaviours Send Messages, Broadcast Messages, Invoke Unity Events, or Invoke C# Events; also handles device pairing and split-screen for local multiplayer.
- Generated C# class: tick "Generate C# Class" for compile-time-checked access, e.g.
controls.Player.Move.performed += OnMove;withcontrols.Enable()inOnEnable().
C. Camera-relative movement
Raw input is in screen space and must be re-expressed in world space before it reaches the controller.
Vector3 fwd = Vector3.ProjectOnPlane(cam.forward, Vector3.up).normalized;
Vector3 right = Vector3.Cross(Vector3.up, fwd);
Vector3 desired = fwd * moveInput.y + right * moveInput.x;- Rebinding:
action.PerformInteractiveRebinding()lets players remap at runtime and serialise overrides as JSON.
VI. Event Handling — decoupling cause from consequence
A. Principle
Events invert dependencies: the emitter knows nothing about the listener, so a pressure pad can open a door, play audio and score points without referencing any of them.
B. Mechanisms
UnityEvent: serialized, wired in the Inspector, designer-facing; slower (reflection) and limited to public methods with ≤ 4 arguments.- C#
event/Action: code-only, fast, type-safe; must be unsubscribed inOnDisable()to avoid leaked references.
public UnityEvent<int> OnHealthChanged; // designer-wired
public static event Action<Damageable> OnDeath; // code-wired observerC. Engine-sent messages
- Physics callbacks:
OnCollisionEnter/Stay/Exit(solid contacts, givesContactPoint),OnTriggerEnter/Exit(volumes withisTrigger = true; at least one body must have a Rigidbody). - Animation Events: keyframed on a clip to enable a
Damageron the swing frame and disable it on the follow-through — the standard way to sync hitboxes to animation. - UI: the
EventSystemGameObject routes pointer and navigation events throughGraphic RaycastertoIPointerClickHandlerimplementations.
VII. Animation Rigging — procedural correction of authored motion
A. Purpose and evaluation order
The Animation Rigging package layers constraint solvers after the Animator evaluates clips, letting runtime data (aim direction, ground normal) modify bone transforms without new animations.
- Order: Animator plays clip → Rig Builder's animation jobs solve constraints →
LateUpdatescripts read final pose. - Setup:
RigBuilderon the root with theAnimator; one or moreRigGameObjects, each withweight ∈ [0,1]; constraints as children.
B. Core constraints
- Two Bone IK: solves upper/lower limb to a
Targettransform with aHintfor the elbow/knee pole — used for foot planting and gripping a weapon. - Multi-Aim: rotates a bone so its
Aimed Axispoints at a source; head look-at, withSource Objectsweighted. - Multi-Parent / Multi-Position: blends between attachment points, e.g. a sword moving from back to hand.
- Damped Transform: propagates motion with damping for secondary sway (ponytail, holster).
- Twist Correction / Chain IK: distributes forearm twist; solves tails and ropes over an arbitrary bone chain.
C. Foot IK worked example
Goal: keep feet on a 15° slope.
1. Raycast down from each foot bone, length 0.5 m, layer = Ground.
2. footTarget.position = hit.point + Vector3.up * footOffset; // 0.02–0.05 m
3. footTarget.rotation = Quaternion.FromToRotation(Vector3.up, hit.normal) * footBone.rotation;
4. Blend: constraint.weight = Mathf.Lerp(constraint.weight, grounded ? 1 : 0, 10 * Time.deltaTime);Fading weight to 0 in air prevents the leg snapping to a stale hit point.
D. Limitations
- Cost: every constraint is an animation job; deep chains on many characters justify LOD — drop rig weight to 0 beyond ~15 m.
- Authoring risk: IK targets fighting an authored clip cause knee popping; constrain the hint, and never scale rigged bones non-uniformly.
Did this save you a night before the exam?
LPU Notes is free, and it stays free. Ads cover part of the server bill. The rest comes out of a student's own pocket: the domain, the storage, and keeping the site up through the weeks everyone needs it at once.
The payment button didn't load. An ad blocker or a filtered network is the usual reason. to try again.
Nothing here is ever locked, and nothing unlocks. Chip in only if it was worth it. What it pays for →