assembly-definitions
Assembly definition management — when to create asmdefs, reference rules, Editor/Runtime/Test separation, platform filters, compilation speed optimization.
2D and 3D character controller patterns — coyote time, input buffering, variable jump, wall slide/jump, dash, slopes, stairs, camera-relative movement. Load when implementing player movement.
$ npx -y skills add XeldarAlz/everything-claude-unity --skill character-controller --agent claude-codeHow it fires
How this skill gets triggered: by you, by Claude, or both.
/character-controllerContext preview
The summary Claude sees to decide when to auto-load this skill.
2D and 3D character controller patterns — coyote time, input buffering, variable jump, wall slide/jump, dash, slopes, stairs, camera-relative movement. Load when implementing player movement.
name: character-controller description: "2D and 3D character controller patterns — coyote time, input buffering, variable jump, wall slide/jump, dash, slopes, stairs, camera-relative movement. Load when implementing player movement." globs: ["**/Player*.cs", "**/Character*.cs", "**/Movement*.cs", "**/Controller*.cs"]
Comprehensive reference for building responsive, game-feel-polished character controllers in Unity. Covers both 2D platformer and 3D action game patterns.
Use an overlap circle at the character's feet rather than relying on collision callbacks. This gives frame-accurate ground state.
[Header("Ground Check")]
[SerializeField] private Transform groundCheckPoint;
[SerializeField] private float groundCheckRadius = 0.15f;
[SerializeField] private LayerMask groundLayer;
private bool _isGrounded;
private void CheckGround()
{
_isGrounded = Physics2D.OverlapCircle(
groundCheckPoint.position,
groundCheckRadius,
groundLayer
);
}Place `groundCheckPoint` as a child transform at the bottom of the character sprite. Keep the radius small to avoid false positives on walls.
Allow the player to jump for a brief window after walking off a ledge. This forgives slight mistiming and makes platforming feel generous rather than punishing.
[Header("Coyote Time")]
[SerializeField] private float coyoteTimeDuration = 0.1f;
private float _coyoteTimeCounter;
private void Update()
{
if (_isGrounded)
{
_coyoteTimeCounter = coyoteTimeDuration;
}
else
{
_coyoteTimeCounter -= Time.deltaTime;
}
if (_jumpPressed && _coyoteTimeCounter > 0f)
{
ExecuteJump();
_coyoteTimeCounter = 0f; // Consume coyote time
}
}A typical value is 0.08 to 0.15 seconds. Higher feels more forgiving; lower feels tighter. Playtest to find the sweet spot for your game's pace.
Queue a jump input so it fires the moment the player lands, even if they pressed the button a few frames early. Combined with coyote time, this eliminates most "I pressed jump but nothing happened" complaints.
[Header("Input Buffering")]
[SerializeField] private float jumpBufferDuration = 0.12f;
private float _jumpBufferCounter;
private void Update()
{
// Buffer the input
if (_jumpPressedThisFrame)
{
_jumpBufferCounter = jumpBufferDuration;
}
else
{
_jumpBufferCounter -= Time.deltaTime;
}
// Consume buffer when grounded (or in coyote time)
if (_jumpBufferCounter > 0f && _coyoteTimeCounter > 0f)
{
ExecuteJump();
_jumpBufferCounter = 0f;
_coyoteTimeCounter = 0f;
}
}Cut the jump short when the player releases the button early. This gives the player fine control over arc height.
[Header("Variable Jump")]
[SerializeField] private float jumpForce = 14f;
[SerializeField] private float jumpCutMultiplier = 0.4f;
private Rigidbody2D _rb;
private void ExecuteJump()
{
// Reset vertical velocity before applying force for consistent jump height
_rb.velocity = new Vector2(_rb.velocity.x, 0f);
_rb.AddForce(Vector2.up * jumpForce, ForceMode2D.Impulse);
}
private void Update()
{
// When the player releases jump while still moving upward, cut velocity
if (_jumpReleasedThisFrame && _rb.velocity.y > 0f)
{
_rb.velocity = new Vector2(
_rb.velocity.x,
_rb.velocity.y * jumpCutMultiplier
);
}
}The `jumpCutMultiplier` controls how much velocity is retained. A value of 0.4 means releasing early yields roughly 40% of max jump height. Tune this alongside gravity scale.
Detect walls with a horizontal raycast or box overlap. Apply reduced gravity while sliding, then launch away from the wall on jump.
[Header("Wall Interaction")]
[SerializeField] private Transform wallCheckPoint;
[SerializeField] private float wallCheckDistance = 0.3f;
[SerializeField] private LayerMask wallLayer;
[SerializeField] private float wallSlideSpeed = 2f;
[SerializeField] private Vector2 wallJumpForce = new Vector2(12f, 16f);
[SerializeField] private float wallJumpLockTime = 0.15f;
private bool _isTouchingWall;
private bool _isWallSliding;
private float _wallJumpLockCounter;
private int _wallDirection; // -1 left, 1 right
private void CheckWall()
{
_isTouchingWall = Physics2D.Raycast(
wallCheckPoint.position,
Vector2.right * transform.localScale.x,
wallCheckDistance,
wallLayer
);
// Wall slide when airborne, touching wall, and holding toward it
_isWallSliding = _isTouchingWall && !_isGrounded && _moveInput.x != 0f;
}
private void ApplyWallSlide()
{
if (!_isWallSliding) return;
// Clamp downward velocity to slide speed
if (_rb.velocity.y < -wallSlideSpeed)
{
_rb.velocity = new Vector2(_rb.velocity.x, -wallSlideSpeed);
}
_wallDirection = transform.localScale.x > 0 ? 1 : -1;
}
private void WallJump()
{
if (!_isWallSliding) return;
// Jump away from wall
_rb.velocity = Vector2.zero;
_rb.AddForce(new Vector2(-_wallDirection * wallJumpForce.x, wallJumpForce.y),
ForceMode2D.Impulse);
// Temporarily lock horizontal input so the player does not immediately
// steer back into the wall
_wallJumpLockCounter = wallJumpLockTime;
}The input lock after a wall jump is critical. Without it, players holding toward the wall will negate the horizontal push and slide back down immediately.
A short burst of speed with optional invincibility frames. Use a cooldown to prevent spamming.
[Header("Dash")]
[SerializeField] private float dashSpeed = 24f;
[SerializeField] private float dashDuration = 0.12f;
[SerializeField] private float dashCooldown = 0.6f;
[SerializeFieldThe ultimate Claude Code toolkit for Unity game development. A production-ready, plug-and-play system that gives Claude Code deep Unity expertise — from writing performant C# to building scenes, profiling performance, and triggering iOS/Android builds — all
Assembly definition management — when to create asmdefs, reference rules, Editor/Runtime/Test separation, platform filters, compilation speed optimization.
Structured commit trailers — adds Constraint, Rejected, Scope-risk, and Not-tested metadata to commit messages. Captures architectural decisions and known gaps…
Ambiguity gating — detects vague feature requests and forces structured requirements gathering with scoring across scope, platform, performance, integration,…
Event system patterns — C# events, UnityEvent, SO event channels, static EventBus. When to use each, zero-allocation patterns, memory leak prevention.
Configures Claude Code's statusline to display Unity workflow state — current phase, active agent, files modified, and session duration.
Post-debugging knowledge extraction — captures non-obvious, codebase-specific learnings that pass quality gates. Invoke after resolving tricky bugs or…