This tutorial will explain the overall structure and implementation mechanisms of the bullet hell system example game BulletHellSample.
◆ Game Overview
This is a game where the player defeats a Boss with 500 HP that fires bullet patterns using shooting and bombs. Since this is a sample project, the game ends immediately after the Boss is defeated.
Controls
- Arrow keys: Move
- Z key: Shoot
- X key: Bomb
Common bullet hell mechanics such as Graze and Bomb Bullet Clearance are implemented.
Game Scene Structure
The game uses only one scene: test_scene.tscn. There is no scene switching.
Object Structure
Player
player.tscn is the scene for the player character.
Its child nodes include:
GrazeObject.tscn: Used for graze detectionplayer_hit_checker.tscn: Used for hit detection
Enemy
enemy.tscn is the scene for the enemy (Boss).
Its child nodes include:
damage_checker.tscn: Used for hit detection
Implementation Details of Each Feature
Enemy Bullet Patterns
The enemy uses a simple implementation: firing bullet patterns at fixed time intervals.
The bullet patterns include:
- Accelerating omnidirectional bullets
- Shotgun-style patterns combined with enemy movement
- Splitting bullets fired from the stage edges, targeting the player
- Flower-shaped patterns composed of omnidirectional bullets
- Simple geometric shapes drawn using homing bullets
Since bullet patterns require repeated sound effects, AnimationPlayer nodes trigger AudioStreamPlayer to play sounds.
Currently, due to the lack of suitable sound assets, this implementation is used. Ideally, each bullet pattern should have its own dedicated sound effect, played directly when the pattern is fired.
- The current bullet system lacks a stop mechanism. Therefore, even after the enemy is defeated, already-generated bullet patterns continue firing. This issue is planned to be resolved in future updates by adding a bullet pattern stop feature. For now, it can be avoided by avoiding repeated processing and instead splitting states and manually implementing loop logic.
Player Standard Shooting Patterns
The player simultaneously fires four different bullet patterns within the same state.
Currently, rapid-fire bullet patterns cannot directly specify firing direction. Therefore, direction is simulated by firing toward very distant global coordinates.
- Future updates plan to support direct direction specification for firing.
Graze Handling
Graze functionality is implemented by attaching GrazeObject.tscn as a child node of the player.
This object has a collision area larger than the player’s hit detection area. When it contacts enemy bullets:
- Plays graze particle effects
- Increases score
Damage Handling
Both player and enemy damage handling are implemented via separate child objects.
The main reasons are:
- Avoid interrupting the currently executing state due to damage
- Clearly distinguish between graze detection and hit detection
- In ACTION GAME MAKER, HitArea2D detects collisions for all HitArea nodes under the root node, including child nodes. This issue can be avoided by generating the object as a child object rather than a child node. However, for easier visual confirmation of detection positions, this example uses child nodes.
Bullet Layer Structure
Layer settings are as follows:
- Player: Layer 1
- Enemy: Layer 2
- Graze Detection: Layer 3
Bullet layers:
- Enemy Bullets: Layers 1, 3
- Player Bullets: Layer 2
Bomb Implementation
Bombs are not implemented as part of the bullet system but as regular projectiles.
bomb.tscn is the scene for bombs.
Features:
-
Sets a collision area covering the entire screen
-
Clears hit bullets
-
Converts cleared bullets into score items with a 10% probability
-
Simultaneously deals damage to the enemy
-
Converting bullets into score items involves object instantiation, which is a relatively heavy operation. Setting the conversion probability to 100% would cause performance degradation. Optimization solutions for this issue are under separate investigation.
Score Items
To reduce performance overhead from object instantiation, score items are implemented using GDScript.
- Scene:
score_test.tscn - Behavior:
- Moves toward the player
- Disappears when close enough
- Modifies specified variable values
The following parameters can be customized in the Score node’s Inspector:
- PickUpRadius: Pickup detection distance
- PullSpeed: Movement speed
- Group: Target group to approach
- Project Variable: Name of the project variable to modify
- Variable Add: Value to add