Overview
This genre pack targets action games in the Mario / Celeste / Hollow Knight mould: a character defined by tight movement attributes, a variable-height jump, power-ups that change form and grant abilities, and a movement state machine — grounded, airborne, coyote time — that has to stay consistent while abilities, physics, and power-ups all read and write it.
It is the practical, copy-and-extend companion to the Platformer (Mario-style) case study in
the core specification (Section 15.1). Where the case study sketches the
movement attribute set, the variable-height GA_Jump, and power-up effects, this pack ships the
matching schema-conformant Attributes, Tags, Abilities, and Effects in entities/, plus a worked
hero in entities/gameplay_controller.yaml.
Platforming is the concrete seed, but the same pieces generalize to the wider Action / Action-Adventure family — hack-and-slash, stealth, Metroidvania — which layer combat, exploration, and progression on top of this movement-and-ability core.
Relationship to the core specification
This document is additive. It defines genre-specific Attributes, Tags, Abilities, and Effects on top of the core Universal Gameplay Ability System specification.
-
It MUST NOT redefine, override, or contradict any concept in the core spec.
-
All entities in
entities/validate against the sameschemas/*.jsonas the core. -
It reuses the core lifecycle tags (
State.Alive,State.Combat,State.Dead) by reference, and adds the platformer movement states (State.Grounded,State.InAir, …) introduced by the §15.1 case study. -
Movement state is mutated only through Effects (core spec §3.1) — abilities never write tags directly — and the size/speed power-up stacking is the core modifier
Channelmechanism (core spec §5.3), not a new construct.
Genre Attributes
Defined in entities/attribute_set.yaml as the PlatformerMovementSet set.
| Attribute | Category | Role |
|---|---|---|
|
Statistic |
Multiplier on world gravity; raised by |
|
Statistic |
Upward impulse applied by |
|
Statistic |
Fraction of ground control retained while airborne; clamped to |
|
Statistic |
Ground run speed; raised while the invincibility star is active. |
|
Statistic |
Forgiveness windows that make the jump feel responsive. |
|
Statistic |
Jumps allowed before landing; raise to |
|
Meta |
Live vertical velocity kept in sync by the physics avatar; read by |
|
Statistic |
Character size; doubled by the Super power-up. |
|
Statistic / Resource |
|
|
Resource |
Remaining lives; game over at 0. |
The movement state machine (the core action mechanic)
A platformer lives or dies on game feel, and in UGAS that feel is a small tag-driven state machine whose transitions are owned by whichever system is responsible for them.
Tag ownership follows responsibility
| State tag | Owner | How it changes |
|---|---|---|
|
Physics subsystem |
Applied via |
|
|
Granted via |
|
Physics / movement |
A short grace window after leaving a ledge. |
|
Input layer |
A jump pressed just before landing is queued. |
No system writes another’s tag, and no system mutates tags directly — every transition goes
through an Effect (core spec §3.1). This is why GA_Jump does not toggle State.Grounded; it only
grants and later removes its own GE_InAir.
Variable-height jump
GA_Jump (entities/ability_jump.yaml) is gated by State.Grounded or Status.CoyoteTime
(an OR evaluated in activation logic, since tag lists are ANDed). On activation it grants
GE_InAir and applies the JumpVelocity impulse, then waits on input release: a short press
applies GE_JumpCut, which raises GravityScale so the character falls sooner. On Event.Landed
both effects are removed.
GE_JumpCut stacks its gravity multiplier in the JumpControl channel, where modifiers are
additive within the channel: \(1 + 1.5 = 2.5\), i.e. GravityScale becomes
\(1.0 \times 2.5 = 2.5\) while the cut is active.
Power-ups change attributes and grant tags
Power-ups are Effects that grant a State.PowerUp.* tag and modify attributes. Percentage changes
use named channels (additive within, multiplicative across), so Value: 1.0 in the SizeBonuses
channel reads as +100%.
entities/gameplay_controller.yaml)A hero who has grabbed a Super Mushroom (GE_SuperMushroom active):
-
Scale: base \(1.0 \times (1 + 1.0) = 2.0\) (theSizeBonuseschannel) -
Health: base \(1 + 1 = 2\) (a flatAdd)
These are exactly the CurrentValue entries recorded for the example hero.
Genre Tags
Defined in entities/tag_registry.yaml (additive only):
-
Movement states —
State.Grounded,State.InAir,Status.CoyoteTime,Status.JumpBuffered. -
Power-up states —
State.PowerUp.Super|Fire|Invincible. -
Ability types —
Ability.Type.Movement|Attack. -
Hazards & combat —
DamageType.Contact|Pit,Immunity.Contact.
Genre Abilities
-
entities/ability_jump.yaml—GA_Jump: the signature variable-height jump. GrantsGE_InAir, applies the jump impulse, appliesGE_JumpCuton early release, and cleans up both on landing. -
entities/ability_ground_pound.yaml—GA_GroundPound: an airborne slam. RequiresState.InAir, blocked whileState.Grounded, and onEvent.LandedappliesGE_ContactDamageto every enemy in radius — skippingImmunity.Contacttargets. Models the §15.3 radius/tag-query pattern for action.
Genre Effects
-
entities/effect_grounded.yaml—GE_Grounded: infinite; grantsState.Grounded(applied/removed by the physics subsystem). -
entities/effect_in_air.yaml—GE_InAir: infinite; grantsState.InAir(owned byGA_Jump). -
entities/effect_jump_cut.yaml—GE_JumpCut: infinite-until-landing;+150%GravityScalein theJumpControlchannel for a shorter jump. -
entities/effect_super_mushroom.yaml—GE_SuperMushroom: infinite; doublesScale(SizeBonuseschannel) and grants+1Health; grantsState.PowerUp.Super. -
entities/effect_invincibility_star.yaml—GE_InvincibilityStar:HasDuration;+30%HorizontalSpeedand grantsState.PowerUp.Invincible+Immunity.Contact. -
entities/effect_contact_damage.yaml—GE_ContactDamage: instant;-1Health. Used by hazards against the player and byGA_GroundPoundagainst enemies.
Using this pack
-
Copy
genres/action/into your project (or loadentities/directly via theugas-schema-authorskill). -
Keep, rename, or extend the
PlatformerMovementSet; tune the jump-feel attributes first — they carry most of the game feel. -
Add new states as
State.*tags granted by Effects (never mutate tags directly), and new power-ups/attacks as Effects + Abilities. -
Validate with
python scripts/validate_schema_examples.pybefore committing.