Guide 8 — Stardust
Marcelo Diaz
What you're building
A 2D action platformer where you dash, jump and attack through levels. The core mechanic is comboing — the more consecutive hits you land, the more damage you do.
Yours is the most complete action-game build in the class: melee, projectiles, dash, wall-sliding, a combo system and a boss. If another student wants to see everything the combat kit can do, they should read your guide.
Your title is a placeholder, which is fine — nothing here depends on the name.
Time: about three hours.
1. Before you start
- Finish Guide 0.
- Read Guide B §B1 (player) and §B4 (enemy).
- One new input action:
Dash. See section 5.
2. Scripts you'll use
Core — Guide B §B1, §B2
PlayerController2D · PlayerAnimatorBridge · Health · DamageOnContact · Checkpoint · RespawnManager · CameraTargetAssigner · SceneLoader · GameManager · AudioManager · HUDController · MovingPlatform · ParallaxBackground
Combat (Tier 2)
Team · Hurtbox · Hitbox · Knockback · ComboCounter · MeleeAttack · Projectile · ProjectileShooter · EnemyPatrol · BossController · BossArenaTrigger
Movement (Tier 3)
Dash · WallSlideJump
Level (Tier 4)
SpikeTrap · Breakable · KillZone
3. How the combo system works
Worth understanding before you build, because it touches three components.
ComboCounter sits on the player. Every time one of your attacks lands, the counter goes up. Your damage multiplier is:
multiplier = 1 + (combo × Damage Per Hit), capped at Max Multiplier
At the default 0.1 per hit, ten consecutive hits means double damage. The combo resets if you go 2 seconds without landing a hit, or if you take damage.
The important part: Hitbox reads the multiplier automatically from the ComboCounter on its parent. You don't wire that. What you do wire is RegisterHit, so the counter knows a hit landed.
Projectiles are different. A projectile fired by a
ProjectileShooteron the same object as theComboCounterregisters its own hits automatically. Don't wire those or they'll count twice.
4. Build the player
Follow Guide B §B1, then set:
| Component | Setting | Value |
|---|---|---|
Health | Max Health | 5 |
| Invulnerability Time | 0.8 | |
PlayerController2D | Move Speed | 9 |
| Acceleration | 70 — snappy | |
| Deceleration | 90 | |
| Jump Force | 15 | |
| Coyote Time | 0.1 | |
| Jump Buffer Time | 0.12 |
Add Knockback (Stun Duration 0.2, Resistance 0) and ComboCounter:
| Field | Value |
|---|---|
| Combo Window | 2 — seconds between hits before it drops |
| Damage Per Hit | 0.1 |
| Max Multiplier | 3 |
The children
Hurtbox — trigger collider smaller than the sprite, Hurtbox (Team = Player), layer Hurtbox.
AttackHitbox — trigger collider in front, Hitbox:
| Field | Value |
|---|---|
| Target Team | Enemy |
| Damage | 1 |
| Knockback Force | 6 |
| Knockback Upward | 2 |
Layer Hitbox, GameObject unticked (starts disabled).
WallCheck — an empty child at chest height on the right side of the sprite. One is enough; it flips with the player.
GroundCheck — at the feet, per Guide B.
5. Add the movement modules
First: the Dash input action
Open your input actions asset:
- Player map → + → name it exactly
Dash - Action Type Button
- Add Binding → Path → Listen → press Left Shift
- Save Asset
MeleeAttack
On Player:
| Field | Value |
|---|---|
| Player Controlled | ✓ |
| Hitbox | drag AttackHitbox |
| Windup | 0.06 |
| Active | 0.1 |
| Recovery | 0.14 |
| Use Animation Events | ✗ |
| Stop While Attacking | ✓ |
| Animator Trigger | Attack |
| Sfx Name | swing |
Total: 0.3 seconds. That's fast, which is what a combo game needs — a slow attack makes chaining hits impossible. When you animate, match the clip to 0.3 or adjust these.
Dash
| Field | Value |
|---|---|
| Dash Speed | 22 |
| Dash Duration | 0.15 |
| Cooldown | 0.5 |
| Direction | Facing (EightWay if you want Celeste-style) |
| Air Dashes | 1 |
| Invulnerable During Dash | ✓ |
| Keep Velocity After | 0 |
| Use Sprint Action | ✗ |
| Animator Trigger | Dash |
| Sfx Name | dash |
WallSlideJump
| Field | Value |
|---|---|
| Wall Check | drag the WallCheck child |
| Check Distance | 0.2 |
| Wall Layer | Ground |
| Slide Speed | 2 |
| Require Pushing Into Wall | ✓ |
| Wall Jump Force | (10, 14) |
| Lock Time | 0.15 |
| Refill Jumps | ✓ |
6. Build enemies
Basic enemy
Guide B §B4, with:
| Setting | Value |
|---|---|
Health Max | 3 · Destroy On Death ✓ · Invulnerability 0 |
Knockback Resistance | 0 |
EnemyPatrol Speed | 2, Sensors mode, Ground Layer Ground |
Children: WallCheck, LedgeCheck, Hurtbox (Team Enemy), BodyHitbox (Target Player, Damage 1, Repeat Delay 1, enabled).
Invulnerability 0 on enemies is important for you
Your game is about chaining hits. If enemies have i-frames, your combo stalls while you wait for them to become hittable again. Set it to 0 and let the attack's own cooldown pace the fight.
A tougher enemy
Duplicate, raise Health to 6, lower Speed to 1.5, change the sprite. Variety in how long something takes to kill is what makes a combo meter meaningful — a 6-health enemy is where your multiplier starts paying off.
7. Optional: give the player a projectile
If you want a ranged attack (your Mega Man ZX reference suggests you might):
- Bullet prefab: Sprite + Rigidbody2D (Gravity Scale 0) + Circle Collider 2D (trigger) + Projectile:
| Field | Value |
|---|---|
| Damage | 1 |
| Speed | 14 |
| Lifetime | 2 |
| Pierce | 0 |
| Blocking Layers | Ground |
FirePointempty child on the player, in front.- ProjectileShooter on the player root:
| Field | Value |
|---|---|
| Projectile Prefab | your bullet |
| Fire Point | the child |
| Team | Player |
| Mode | Manual ← see warning |
| Aim | Facing |
| Fire Rate | 0.25 |
⚠️
MeleeAttackandProjectileShooterboth listen to theAttackaction. If you set the shooter toPlayerInputmode, you'll melee and shoot on every press. Set it to Manual and add a separateShootaction, or just skip the projectile — melee alone is a complete game.If you want both: add a
Shootaction to your input asset, then ask your instructor for the two-line script that callsFire()from it. It's genuinely two lines.
8. Build the level
- Ground on the
Groundlayer with colliders — include some tall vertical walls so wall-sliding has somewhere to happen KillZoneunder everythingSpikeTraps (Guide 1 §6e is the recipe) — Timed mode, Instant Kill ✗ with Damage 1 (you have 5 health; instant death doesn't suit a combat game)Breakablecrates: Sprite + Rigidbody2D + collider +Health(2) +Breakable+ aHurtboxchild with Team = NeutralCheckpoints, aLevelExit, camera per Guide B §B3
Design your level around the moves
You have dash, double-height wall jumps, and a fast attack. A level of flat corridors wastes all three. Build:
- Gaps that need a dash
- Vertical shafts with walls on both sides
- Enemy clusters where a combo can build
9. The HUD
- Canvas → a Slider named
HealthBar(delete the handle, Interactable ✗, Min 0 Max 5). - A TMP text
ComboText, centre-right, initially empty. - Empty child
HUDwith HUDController; dragHealthBarinto Health Bar.
Making the combo readable
The combo counter is your whole identity as a game, so it needs to be felt. Cheap upgrades in order of value:
- Show the number and multiplier:
12 HITS ×2.2 - Scale the text up as the combo climbs
- Change colour at thresholds — white → yellow → orange → red
- Shake or flash it when it breaks
You can do 1 with wiring alone. The rest need a small helper script — worth asking for once the game plays well.
10. Wire it up
| On this object | Event | Drag in | Choose |
|---|---|---|---|
Player → Health | On Died | RespawnManager | RespawnManager.OnPlayerDied |
Player → Health | On Health Changed | HUD | HUDController.UpdateHealth (Dynamic) |
AttackHitbox → Hitbox | On Hit | Player | ComboCounter.RegisterHit |
Player → Health | On Damaged | Player | ComboCounter.ResetCombo |
Player → ComboCounter | On Combo Broken | AudioManager | PlaySFX (string) → combo_break |
Player → Dash | On Dash Started | AudioManager | PlaySFX (string) → dash |
Player → PlayerController2D | On Jumped | AudioManager | PlaySFX (string) → jump |
Boss → BossController | On Boss Defeated | GameManager | GameManager.LevelComplete |
Rows 3 and 4 are your game. Without row 3 the combo never counts. Without row 4 it never resets, so it climbs forever and the multiplier becomes meaningless.
For row 3, note the event is on the child
AttackHitbox, and you drag the parentPlayerinto the slot. That trips people up.
11. First playtest
Build a room with three basic enemies and a wall.
- Run, jump, attack.
- Three hits kill a basic enemy.
- Dash works and has a cooldown. Left Shift.
- Air dash works once, then not again until you land.
- You're invulnerable mid-dash — dash through an enemy and take no damage.
- Wall slide: jump at a wall while holding toward it. You should slow down.
- Wall jump: press Jump while sliding. You should launch away and flip.
- Hit three enemies in a row and the combo climbs. Add a temporary TMP text wired to
OnComboChangedif you need to see it. - Stop hitting for 2 seconds — the combo resets.
- Take a hit — the combo resets.
- A 10-hit combo does noticeably more damage — test on the 6-health enemy.
Steps 8–11 are the whole point. Get them working before you build any level.
12. Then add
- Level design built around dash and wall-jump.
- Animation — Guide B §B6, plus
Attack,Dash,IsWallSliding. Yours needs the most animator work of the first eight guides. - A boss — Guide 7 §9 has the full recipe; give him Resistance 1 and two phases.
- Combo UI polish — the scaling, colouring text.
- Hit-stop: a two-frame freeze on impact makes hits feel heavy. Ask about it once combat is working; it's a small script and it's the single biggest "game feel" upgrade available to you.
- Sound: distinct hit sounds per combo tier, if you want to get fancy.
13. Design notes for your game specifically
Your combo window is a difficulty dial. Two seconds is generous — the player can reposition between hits. Drop it to 1.2 and they have to keep pressure on constantly, which makes the game much more aggressive. Try both; the right answer depends on how densely you place enemies.
Enemies need to be killable in different numbers of hits. If everything dies in three, the multiplier never gets a chance to matter. A mix of 2, 3 and 6 health means the combo you built on the weak ones pays off on the tough one — that's the loop your mechanic wants.
Getting hit should hurt twice. It costs health and your combo. That's already wired (rows 3 and 4), and it's the reason dashing through danger rather than fighting through it is a real choice. Lean into it — invulnerable dashes plus combo-on-hit-taken means skilled play looks like continuous motion.
Don't add a block or a parry. You have dash-invulnerability, which does the same job while keeping the player moving. A block button would slow the game down and fight against everything else you've built.
Match your animation length to MeleeAttack's timings. 0.06 + 0.1 + 0.14 = 0.3 seconds. This is the single most common thing that makes a combat game feel wrong — a swing animation that outlasts its hitbox. When you get to animation, either trim the clip or switch on Use Animation Events and place EnableHitbox() / DisableHitbox() on the actual frames. The second option is how professionals do it and it's easier to tune.
14. Common problems
| What you see | What's wrong |
|---|---|
| Attack does nothing | Hitbox not assigned, or not disabled at start, or teams the same |
| Attack hits through walls | Hitbox child not on the Hitbox layer |
| Combo never goes up | Row 3 not wired — AttackHitbox.OnHit → ComboCounter.RegisterHit |
| Combo never resets | Row 4 not wired |
| Combo counts double | You wired RegisterHit for a projectile as well — projectiles do it themselves |
| Multiplier doesn't seem to apply | It does — test on a 6-health enemy. On a 3-health enemy the extra damage is invisible |
| Dash doesn't work | Dash action missing from the input asset, or you're on cooldown |
| Can air dash forever | Air Dashes set too high |
| Take damage while dashing | Invulnerable During Dash unticked |
| No wall slide | WallCheck not assigned, Wall Layer unset, or you're not holding toward the wall (Require Pushing Into Wall ✓) |
| Wall jump goes the wrong way | That's correct — it pushes away from the wall and flips you |
| Wall jump immediately re-grabs | Lock Time too short — raise to 0.2 |
| Enemy stalls between hits | Enemy Invulnerability Time isn't 0 |
| Melee and shoot both fire | ProjectileShooter is in PlayerInput mode — set it to Manual |