The core of HarmonyOS game development is not the render loop, but the design of the rule system. ArkUI has already taken over much of the UI and rendering work, the Engine has been reduced to a scheduler, and the System layer handles the real behavior such as combat, AI, and loot. Keywords: HarmonyOS, ArkUI, System.
Technical Specification Snapshot
| Parameter | Description |
|---|---|
| Language | ArkTS / TypeScript-style pseudocode |
| UI Paradigm | ArkUI declarative UI |
| Architecture Core | Engine + System + Store + UI |
| Runtime Model | State-driven, system-scheduled, auto-rendered |
| License | Originally marked as CC 4.0 BY-SA |
| Star Count | Not provided in the original source |
| Core Dependencies | HarmonyOS, ArkUI, state management model |
This article redefines what “engine” means in HarmonyOS games
Many developers enter HarmonyOS game development and instinctively look for a Unity-style GameEngine. That instinct comes from the traditional game industry, where the engine usually owns rendering, animation, physics, and lifecycle management.
But inside HarmonyOS and the ArkUI model, that assumption does not hold. Declarative UI and state-driven updates have already absorbed a large portion of the responsibilities that traditional engines used to own.
AI Visual Insight: This image introduces the article’s main theme and emphasizes that the discussion of HarmonyOS game architecture happens in the core content area. For technical readers, it functions more like a section cover, signaling that the article will approach the topic from an architectural perspective rather than from specific APIs.
AI Visual Insight: This animated image is typically used to show interface or interaction changes, making it a good visual match for the core argument that state changes drive view updates. Its technical meaning is this: visual results are not directly pushed by a handwritten render loop, but are triggered indirectly by state transitions.
A minimal traditional Engine implementation looks like this
class GameEngine {
update(store: GameStore) {
// Only schedule systems in sequence here
battleSystem.update(store)
aiSystem.update(store)
dropSystem.update(store)
}
}
The purpose of this code is to compress the Engine into a scheduling container rather than a carrier of business rules.
In the HarmonyOS context, what really matters is how state changes
The strength of a traditional engine is controlling how the screen moves. Native HarmonyOS games care more about why the state changes. Since the framework already owns most UI refresh work, the developer’s core job becomes defining rules.
In other words, the Engine answers when to execute, while the System answers what to execute. The latter is what truly determines how the game world operates.
The System layer is the real rule-dense layer
class BattleSystem {
update(store: GameStore) {
// Process attack resolution
this.handleAttack(store)
// Process damage and death
this.handleDamage(store)
// Trigger loot drops after kills
this.handleDrop(store)
}
}
The purpose of this code is to centralize combat rules inside a single boundary and prevent logic from being scattered across the UI or the Engine.
As logic grows more complex, a thin Engine becomes more stable
At the start of a project, many developers put HP deduction, AI, and skill checks directly into engine.update. That may feel fast at first, but once state branches grow, the Engine quickly bloats into an untestable giant entry point.
A more reasonable approach is to let the Engine maintain only scheduling order and delegate behavior to multiple Systems. In that model, each System behaves like a micro-engine responsible for one class of stable rules.
Comparing two architectural styles
// Anti-pattern: logic is hardcoded in the Engine
engine.update = () => {
player.hp -= 10 // Direct state mutation creates tight coupling
enemy.hp -= 5 // Rules cannot be reused
}
// Good pattern: the Engine only dispatches work
engine.update = (store) => {
battleSystem.update(store) // Combat rules stay independent
}
The purpose of this code is to show that once state changes are extracted from the Engine, extensibility and maintainability improve significantly.
The System layer feels like the engine because it has three core capabilities
First, the System defines rules. Attack formulas, Buff stacking, level-up thresholds, and AI decisions should all form closed loops inside Systems rather than being scattered across click events or helper functions.
Second, the System drives state. The Store itself is only a state container and has no business initiative. Only after a System executes does the state tree change in a trustworthy way.
Third, Systems are naturally composable. BattleSystem, AISystem, DropSystem, and QuestSystem can coexist side by side without consuming each other’s responsibilities.
A recommended system interface design looks like this
interface GameSystem {
update(store: GameStore): void
}
class AISystem implements GameSystem {
update(store: GameStore): void {
// Generate an AI decision based on the current situation
store.enemyAction = this.decide(store)
}
private decide(store: GameStore) {
// Return only the decision result here, without operating on the UI directly
return store.enemyHp < 20 ? 'escape' : 'attack'
}
}
The purpose of this code is to standardize System boundaries and input/output behavior, making composition and unit testing easier.
This layered structure aligns naturally with the ArkUI model
ArkUI is fundamentally a declarative UI framework. Developers do not need to handwrite a complex render loop, and they should not let the UI become the center of business logic. The best role for the UI is to consume state, not produce rules.
Therefore, a flow that better matches the HarmonyOS paradigm is: input enters the System, the System modifies the Store, and the Store triggers automatic UI updates. The entire chain is one-way and stable.
A recommended data flow can be implemented like this
function dispatchPlayerAction(action: PlayerAction, store: GameStore) {
// Send input to the system layer instead of mutating UI state directly
actionSystem.handle(action, store)
// After state changes, the ArkUI view responds automatically
}
The purpose of this code is to establish a one-way data flow: input -> System -> Store -> UI.
Common misconceptions are fundamentally responsibility mismatches
The first misconception is over-designing the Engine by stuffing rendering, animation, physics, and rules into one super-core. In native HarmonyOS scenarios, that usually means reinventing the wheel.
The second misconception is downgrading Systems into a collection of utility functions. Without object boundaries, state context, and a unified entry point, later expansion becomes painful.
The third misconception is letting the UI drive everything. Directly mutating state, writing conditions, and triggering side effects inside onClick may save time in the short term, but it inevitably becomes unmanageable over time.
A more reasonable directory structure looks like this
src/
engine/
GameEngine.ts
systems/
BattleSystem.ts
AISystem.ts
DropSystem.ts
store/
GameStore.ts
ui/
pages/
components/
The purpose of this code is to separate scheduling, rules, state, and presentation into four explicit layers, reducing collaboration costs in multi-developer projects.
The final conclusion is that HarmonyOS games are closer to compositions of rule systems
Under this architecture, a game no longer depends on a single all-powerful engine. Instead, multiple replaceable, testable, and extensible Systems jointly form the runtime core.
The Engine is the timeline, the Store is the state snapshot, the UI is the projection of results, and the System is the law of the world. The layer that defines the rules is the layer that deserves to be called the real engine.
FAQ
1. Do HarmonyOS games still need a GameEngine?
Yes, but it should stay extremely thin. Its main role is to schedule Systems and maintain execution order and lifecycle boundaries. It should not carry a large amount of business logic.
2. What is the essential difference between a System and ordinary utility functions?
A System has a clear responsibility boundary, unified input and output, and an evolvable structure. Utility functions are usually just a loose collection of helpers without state context or long-term extensibility.
3. Why is it not recommended to write game logic directly inside ArkUI events?
Because the UI event layer is good at receiving input, not at accumulating rules. If you place logic in events, state, view, and side effects become tightly coupled, which eventually makes the code difficult to maintain and test.
Core Summary
This article reframes the core architectural mindset for HarmonyOS games: under ArkUI’s state-driven model, the traditional Engine is compressed into a scheduling layer, while the System layer truly determines game rules, state transitions, and extensibility. This approach is well suited for building maintainable, testable, and composable HarmonyOS game codebases.