Character 2D Animation Tutorial
Learn how to create smooth 2D character animations using the Character 2D Animation Editor.
2D Animation System Overview
The Character 2D Animation Editor provides a complete solution for creating directional 2D character animations with automatic animator controller generation.
🎯 Multi-Directional
Support for 4-directional, 8-directional, or single-direction animations
📋 Sprite Sheet Support
Automatic sprite extraction from sprite sheets with customizable slicing
🎮 Animator Generation
Automatic creation of animator controllers with blend trees and transitions
👁️ Live Preview
Real-time animation preview with playback controls
Supported Animation Types
Idle
Character standing still, breathing or subtle movement
Walk
Character walking at normal speed
Run
Character running at increased speed
Jump
Character jumping or in air
Attack
Character performing attack actions
Custom
Any custom animation you define
Character Setup
Step 1: Create Character GameObject
Start by creating your character GameObject with the required components:
- Create a new GameObject in your scene
- Name it appropriately (e.g., "Player", "Hero", "NPC")
- Add the required components:
- SpriteRenderer - Displays the character sprite
- Animator - Controls animation playback
- Collider2D - For physics and interactions (optional)
- Rigidbody2D - For physics-based movement (optional)
1"comment">// Example character setup script
2"keyword">public "keyword">class CharacterSetup : MonoBehaviour
3{
4 "keyword">void Start()
5 {
6 "comment">// Ensure required components exist
7 "keyword">if (GetComponent<SpriteRenderer>() == null)
8 gameObject.AddComponent<SpriteRenderer>();
9
10 "keyword">if (GetComponent<Animator>() == null)
11 gameObject.AddComponent<Animator>();
12
13 "comment">// Optional physics components
14 "keyword">if (GetComponent<Collider2D>() == null)
15 {
16 BoxCollider2D collider = gameObject.AddComponent<BoxCollider2D>();
17 collider.size = "keyword">new Vector2(0.8f, 0.8f); "comment">// Adjust size as needed
18 }
19 }
20}
Step 2: Configure Sprite Settings
Proper sprite configuration is crucial for good-looking animations:
Recommended Sprite Import Settings:
- Texture Type: Sprite (2D and UI)
- Sprite Mode: Multiple (for sprite sheets) or Single (for individual sprites)
- Pixels Per Unit: Match your game's scale (typically 16, 32, or 64)
- Filter Mode: Point (for pixel art) or Bilinear (for smooth art)
- Compression: None or High Quality for best results
- Pivot: Bottom for characters (feet on ground)
Step 3: Tag and Layer Setup
Organize your character for easy identification:
- Set appropriate Tag (e.g., "Player", "Enemy", "NPC")
- Assign to proper Layer (e.g., "Characters", "Entities")
- Set Sorting Layer for proper rendering order
Sprite Preparation
Sprite Sheet Organization
Well-organized sprite sheets make animation setup much easier:
Recommended Sprite Sheet Layout:
Row 1: Idle_Down, Idle_Down, Idle_Down, Idle_Down
Row 2: Idle_Up, Idle_Up, Idle_Up, Idle_Up
Row 3: Idle_Left, Idle_Left, Idle_Left, Idle_Left
Row 4: Idle_Right, Idle_Right, Idle_Right, Idle_Right
Row 5: Walk_Down, Walk_Down, Walk_Down, Walk_Down
Row 6: Walk_Up, Walk_Up, Walk_Up, Walk_Up
Row 7: Walk_Left, Walk_Left, Walk_Left, Walk_Left
Row 8: Walk_Right, Walk_Right, Walk_Right, Walk_Right
Sprite Creation Tips:
- Consistent Frame Size: All frames should be the same dimensions
- Proper Spacing: Consistent spacing between frames if using padding
- Direction Consistency: Characters should face the correct direction
- Animation Timing: Consider the intended playback speed when creating frames
- Loop Considerations: First and last frames should connect smoothly for looping animations
Individual Sprite Workflow
If you prefer working with individual sprite files:
Recommended Naming Convention:
Character_AnimationType_Direction_Frame
Examples:
- Hero_Idle_Down_01.png
- Hero_Idle_Down_02.png
- Hero_Walk_Left_01.png
- Hero_Walk_Left_02.png
- Hero_Attack_Up_01.png
Using the Animation Editor
Step 1: Open the Animation Editor
Access the Character 2D Animation Editor through the Unity menu:
- Go to
RPG Tools → Character 2D Animation Editor - The editor window will open with all the necessary tools
- Dock the window wherever convenient in your workspace
Step 2: Character Selection
Configure your character in the editor:
- Character Prefab: Drag your character GameObject into the field
- Direction Type: Choose from:
- Four Directional: Down, Up, Left, Right
- Eight Directional: Adds diagonal directions
- Single Direction: For side-scrolling characters
4-Directional
Best for: Top-down RPGs, simple movement
Up
Left
Right
Down
8-Directional
Best for: Isometric games, smooth movement
Up-Left
Up
Up-Right
Left
Right
Down-Left
Down
Down-Right
Sprite Import Methods
Method 1: Individual Sprite Import
Import sprites one by one for maximum control:
- Select the Animation Type (Idle, Walk, Run, etc.)
- Choose the Direction
- Drag sprites into the frame slots
- Use "Add Frame" to add more slots
- Use "Remove" to delete unwanted frames
Individual Import Tips:
- Sprites are automatically sorted by name when imported
- You can reorder frames by dragging them
- Empty frames will be skipped during animation creation
- Each direction needs to be set up separately
Method 2: Sprite Sheet Extraction
Extract frames automatically from sprite sheets:
- Drag your sprite sheet into the Sprite Sheet field
- Configure the extraction settings:
- Frame Size: Width and height of each frame
- Start Frame: Which frame to start from (0-based)
- Frame Count: How many frames to extract
- Frames Per Row: How many frames are in each row
- Select the target Animation Type and Direction
- Click "Extract Frames from Sprite Sheet"
1"comment">// Example sprite sheet configuration "keyword">for a 32x32 character:
2"comment">// Frame Size: Width=32, Height=32
3"comment">// For a 4-frame walk cycle starting at frame 8:
4"comment">// Start Frame: 8
5"comment">// Frame Count: 4
6"comment">// Frames Per Row: 4 ("keyword">if your sheet has 4 frames per row)
7
8"comment">// This will extract frames 8, 9, 10, 11 from the sprite sheet
9"comment">// and assign them to the selected animation and direction
Sprite Sheet Extraction Example:
Selected frames (8-11) will be extracted for the current animation/direction
Animation Configuration
Speed and Loop Settings
Fine-tune your animations for the perfect feel:
| Animation Type | Recommended Speed | Loop Setting | Notes |
|---|---|---|---|
| Idle | 0.3 - 0.5 | Loop | Slow, subtle movement |
| Walk | 0.6 - 1.0 | Loop | Moderate speed for natural walking |
| Run | 1.0 - 1.5 | Loop | Faster than walk, energetic |
| Jump | 1.0 - 1.2 | No Loop | Quick, snappy action |
| Attack | 1.2 - 2.0 | No Loop | Fast, impactful action |
Custom Animation Types
Create custom animations for specific needs:
- Select "Custom" from the Animation Type dropdown
- Enter a name for your custom animation (e.g., "Spellcast", "Death", "Victory")
- Configure sprites and settings as normal
- The custom animation will be included in the generated animator controller
Custom Animation Examples:
- Spellcast: Character casting magic spells
- Death: Character falling or dying
- Victory: Character celebrating success
- Interact: Character interacting with objects
- Crouch: Character crouching or hiding
Preview & Testing
Real-Time Animation Preview
The Animation Editor includes a built-in preview system:
Preview Controls:
- Play/Pause: Start or stop animation playback
- Next Frame: Advance to the next frame manually
- Previous Frame: Go back to the previous frame
- Animation/Direction Selection: Choose what to preview
Testing Best Practices
Ensure your animations look great:
Animation Testing Checklist:
- □ All directions have consistent frame counts
- □ Animation speeds feel natural and responsive
- □ Looping animations connect smoothly
- □ Character faces the correct direction
- □ Sprite pivot points are consistent
- □ No flickering or visual artifacts
- □ Timing matches intended game feel
Animator Controller Generation
Export Configuration
Set up the export settings before generating your animator:
- Save Path: Choose where to save animation files (default: Assets/Animations)
- Controller Name: Name for your animator controller (e.g., "PlayerAnimator")
- Click "Create & Assign Everything" for a complete setup
Generated Animator Structure
The tool creates a sophisticated animator controller with:
Animator Components:
- Parameters:
- Horizontal (Float) - Current horizontal input
- Vertical (Float) - Current vertical input
- LastHorizontal (Float) - Last movement direction X
- LastVertical (Float) - Last movement direction Y
- Speed (Float) - Current movement speed
- IsMoving (Bool) - Whether character is moving
- Attack (Trigger) - Trigger attack animations
- States:
- Idle (Blend Tree) - Directional idle animations
- Movement (Blend Tree) - Directional walk/run animations
- Attack States - Individual attack animations per direction
- Transitions:
- Smooth transitions between idle and movement
- Proper attack state handling
- Direction-based blend tree navigation
Blend Tree Configuration
The generated blend trees provide smooth directional animation:
Blend Tree Structure:
Script Integration
Basic Movement Controller
Integrate the generated animator with your movement scripts:
1"keyword">using UnityEngine;
2
3"keyword">public "keyword">class Character2DController : MonoBehaviour
4{
5 [Header("Movement")]
6 "keyword">public "keyword">float moveSpeed = 5f;
7
8 [Header("Components")]
9 "keyword">private Animator animator;
10 "keyword">private Rigidbody2D rb;
11
12 "comment">// Input values
13 "keyword">private Vector2 movement;
14 "keyword">private Vector2 lastMovement;
15
16 "keyword">void Start()
17 {
18 animator = GetComponent<Animator>();
19 rb = GetComponent<Rigidbody2D>();
20
21 "comment">// Initialize last movement to face down
22 lastMovement = Vector2.down;
23 UpdateAnimatorParameters();
24 }
25
26 "keyword">void Update()
27 {
28 "comment">// Get input
29 movement.x = Input.GetAxis("Horizontal");
30 movement.y = Input.GetAxis("Vertical");
31
32 "comment">// Update last movement direction when moving
33 "keyword">if (movement.magnitude > 0.1f)
34 {
35 lastMovement = movement.normalized;
36 }
37
38 "comment">// Update animator parameters
39 UpdateAnimatorParameters();
40 }
41
42 "keyword">void FixedUpdate()
43 {
44 "comment">// Apply movement
45 rb.velocity = movement * moveSpeed;
46 }
47
48 "keyword">void UpdateAnimatorParameters()
49 {
50 "comment">// Current movement
51 animator.SetFloat("Horizontal", movement.x);
52 animator.SetFloat("Vertical", movement.y);
53
54 "comment">// Last movement direction ("keyword">for idle facing)
55 animator.SetFloat("LastHorizontal", lastMovement.x);
56 animator.SetFloat("LastVertical", lastMovement.y);
57
58 "comment">// Movement speed and state
59 "keyword">float speed = movement.magnitude;
60 animator.SetFloat("Speed", speed);
61 animator.SetBool("IsMoving", speed > 0.1f);
62 }
63
64 "comment">// Call "keyword">this method to trigger attack animation
65 "keyword">public "keyword">void Attack()
66 {
67 animator.SetTrigger("Attack");
68 }
69}
Advanced Features
Add more sophisticated behavior to your character:
1"keyword">public "keyword">class AdvancedCharacterController : MonoBehaviour
2{
3 [Header("Animation")]
4 "keyword">public "keyword">float walkSpeed = 3f;
5 "keyword">public "keyword">float runSpeed = 6f;
6 "keyword">public "keyword">bool canRun = true;
7
8 "keyword">private Animator animator;
9 "keyword">private "keyword">bool isRunning;
10
11 "keyword">void Update()
12 {
13 HandleInput();
14 UpdateAnimations();
15 }
16
17 "keyword">void HandleInput()
18 {
19 "comment">// Basic movement
20 movement.x = Input.GetAxis("Horizontal");
21 movement.y = Input.GetAxis("Vertical");
22
23 "comment">// Run input
24 isRunning = canRun && Input.GetKey(KeyCode.LeftShift);
25
26 "comment">// Attack input
27 "keyword">if (Input.GetKeyDown(KeyCode.Space))
28 {
29 Attack();
30 }
31
32 "comment">// Custom animation triggers
33 "keyword">if (Input.GetKeyDown(KeyCode.E))
34 {
35 TriggerCustomAnimation("Interact");
36 }
37 }
38
39 "keyword">void UpdateAnimations()
40 {
41 "comment">// Determine current speed
42 "keyword">float currentSpeed = isRunning ? runSpeed : walkSpeed;
43 Vector2 velocity = movement * currentSpeed;
44
45 "comment">// Update animator with appropriate values
46 animator.SetFloat("Horizontal", movement.x);
47 animator.SetFloat("Vertical", movement.y);
48 animator.SetFloat("Speed", velocity.magnitude);
49 animator.SetBool("IsMoving", velocity.magnitude > 0.1f);
50 animator.SetBool("IsRunning", isRunning && velocity.magnitude > 0.1f);
51
52 "comment">// Update last movement direction
53 "keyword">if (movement.magnitude > 0.1f)
54 {
55 animator.SetFloat("LastHorizontal", movement.x);
56 animator.SetFloat("LastVertical", movement.y);
57 }
58 }
59
60 "keyword">public "keyword">void TriggerCustomAnimation("keyword">string animationName)
61 {
62 animator.SetTrigger(animationName);
63 }
64
65 "comment">// Animation Events - called from animation clips
66 "keyword">public "keyword">void OnAttackComplete()
67 {
68 "comment">// Attack animation finished
69 Debug.Log("Attack complete
70 }
71
72 ">public ">void OnFootstep()
73 {
74 ">// Play footstep sound
75 AudioManager.Instance?.PlaySFX("Footstep");
76 }
77}
Animation Events
Add animation events for precise timing of actions:
1"keyword">public "keyword">class AnimationEventHandler : MonoBehaviour
2{
3 [Header("Audio")]
4 "keyword">public AudioClip[] footstepSounds;
5 "keyword">public AudioClip attackSound;
6
7 [Header("Effects")]
8 "keyword">public GameObject attackEffect;
9 "keyword">public Transform effectSpawnPoint;
10
11 "keyword">private AudioSource audioSource;
12
13 "keyword">void Start()
14 {
15 audioSource = GetComponent<AudioSource>();
16 }
17
18 "comment">// Called by animation event in footstep frames
19 "keyword">public "keyword">void OnFootstep()
20 {
21 "keyword">if (footstepSounds.Length > 0)
22 {
23 AudioClip clip = footstepSounds[Random.Range(0, footstepSounds.Length)];
24 audioSource.PlayOneShot(clip);
25 }
26
27 "comment">// Create dust effect at feet
28 CreateFootstepEffect();
29 }
30
31 "comment">// Called at the moment of attack impact
32 "keyword">public "keyword">void OnAttackImpact()
33 {
34 "comment">// Play attack sound
35 "keyword">if (attackSound != null)
36 {
37 audioSource.PlayOneShot(attackSound);
38 }
39
40 "comment">// Spawn attack effect
41 "keyword">if (attackEffect != null && effectSpawnPoint != null)
42 {
43 GameObject effect = Instantiate(attackEffect, effectSpawnPoint.position, effectSpawnPoint.rotation);
44 Destroy(effect, 2f); "comment">// Clean up after 2 seconds
45 }
46
47 "comment">// Check "keyword">for enemies in attack range
48 CheckAttackHit();
49 }
50
51 "comment">// Called when attack animation completes
52 "keyword">public "keyword">void OnAttackComplete()
53 {
54 "comment">// Re-enable movement or other systems
55 GetComponent<Character2DController>().enabled = true;
56 }
57
58 "keyword">void CreateFootstepEffect()
59 {
60 "comment">// Example: Create small dust cloud at character feet
61 Vector3 feetPosition = transform.position + Vector3.down * 0.5f;
62 "comment">// ParticleSystem or simple effect instantiation
63 }
64
65 "keyword">void CheckAttackHit()
66 {
67 "comment">// Simple attack range check
68 Collider2D[] hitEnemies = Physics2D.OverlapCircleAll(
69 effectSpawnPoint.position,
70 1f,
71 LayerMask.GetMask("Enemies")
72 );
73
74 "keyword">foreach (Collider2D enemy in hitEnemies)
75 {
76 "comment">// Apply damage or effects to enemy
77 enemy.GetComponent<Enemy>()?.TakeDamage(25);
78 }
79 }
80}
State Machine Behaviors
Create custom state machine behaviors for advanced animation control:
1"keyword">using UnityEngine;
2
3"comment">// Custom StateMachineBehaviour "keyword">for attack states
4"keyword">public "keyword">class AttackStateBehaviour : StateMachineBehaviour
5{
6 [Header("Attack Settings")]
7 "keyword">public "keyword">bool disableMovementDuringAttack = true;
8 "keyword">public "keyword">float attackDamage = 25f;
9 "keyword">public "keyword">float attackRange = 1.5f;
10
11 "keyword">private Character2DController controller;
12
13 "keyword">override "keyword">public "keyword">void OnStateEnter(Animator animator, AnimatorStateInfo stateInfo, "keyword">int layerIndex)
14 {
15 "comment">// Get controller reference
16 controller = animator.GetComponent<Character2DController>();
17
18 "comment">// Disable movement during attack
19 "keyword">if (disableMovementDuringAttack && controller != null)
20 {
21 controller.enabled = false;
22 }
23
24 "comment">// Face the last movement direction
25 Vector2 lastMovement = "keyword">new Vector2(
26 animator.GetFloat("LastHorizontal"),
27 animator.GetFloat("LastVertical")
28 );
29
30 "comment">// Additional attack setup logic
31 Debug.Log($"Starting attack in direction: {lastMovement}");
32 }
33
34 "keyword">override "keyword">public "keyword">void OnStateUpdate(Animator animator, AnimatorStateInfo stateInfo, "keyword">int layerIndex)
35 {
36 "comment">// Attack state update logic
37 "comment">// Could check "keyword">for input cancellation, combo attacks, etc.
38 }
39
40 "keyword">override "keyword">public "keyword">void OnStateExit(Animator animator, AnimatorStateInfo stateInfo, "keyword">int layerIndex)
41 {
42 "comment">// Re-enable movement
43 "keyword">if (controller != null)
44 {
45 controller.enabled = true;
46 }
47
48 "comment">// Reset any attack-specific states
49 Debug.Log("Attack completed");
50 }
51}
52
53"comment">// Custom behaviour "keyword">for movement states
54"keyword">public "keyword">class MovementStateBehaviour : StateMachineBehaviour
55{
56 [Header("Movement Effects")]
57 "keyword">public "keyword">float footstepInterval = 0.5f;
58
59 "keyword">private "keyword">float footstepTimer;
60
61 "keyword">override "keyword">public "keyword">void OnStateEnter(Animator animator, AnimatorStateInfo stateInfo, "keyword">int layerIndex)
62 {
63 footstepTimer = 0f;
64 }
65
66 "keyword">override "keyword">public "keyword">void OnStateUpdate(Animator animator, AnimatorStateInfo stateInfo, "keyword">int layerIndex)
67 {
68 "comment">// Handle footstep timing
69 "keyword">float speed = animator.GetFloat("Speed");
70
71 "keyword">if (speed > 0.1f)
72 {
73 footstepTimer += Time.deltaTime;
74
75 "keyword">if (footstepTimer >= footstepInterval)
76 {
77 "comment">// Trigger footstep event
78 var eventHandler = animator.GetComponent<AnimationEventHandler>();
79 eventHandler?.OnFootstep();
80
81 footstepTimer = 0f;
82 }
83 }
84 }
85}
Troubleshooting Common Issues
❌ Animation Not Playing
✅ Solutions:
- Check that Animator component has the controller assigned
- Verify animation parameters are being set correctly
- Ensure animation clips were created successfully
- Check that sprite references in animation clips are not missing
❌ Character Facing Wrong Direction
✅ Solutions:
- Verify sprite directions match your coordinate system
- Check LastHorizontal/LastVertical parameter values
- Ensure blend tree positions are set correctly
- Test with manual parameter adjustment in Animator window
❌ Jerky or Stuttering Animation
✅ Solutions:
- Adjust animation speed settings
- Check transition duration settings
- Ensure consistent frame timing
- Verify sprite pivot points are consistent
❌ Missing Sprites in Animation
✅ Solutions:
- Re-import sprite assets
- Check sprite slice settings
- Verify animation clip references
- Recreate animation clips if necessary
Animation Best Practices
🎨 Sprite Quality
- Use consistent frame sizes
- Maintain pixel-perfect alignment
- Keep pivot points consistent
- Use appropriate compression settings
⚡ Performance
- Optimize sprite atlases
- Use appropriate texture sizes
- Avoid excessive animation states
- Pool particle effects
🎮 Game Feel
- Match animation speed to gameplay
- Add anticipation frames
- Use proper easing curves
- Test on target devices
🔧 Workflow
- Name assets consistently
- Organize sprites logically
- Version control animation files
- Document custom animations