Add detailed documentation for memory mapping, quest flow, and sprite creation
- Created MemoryMap.md to outline WRAM and SRAM structures, including key variables and custom regions. - Added QuestFlow.md to document main quest progression and major side-quests, detailing triggers, events, rewards, and flags. - Introduced SpriteCreationGuide.md to provide a comprehensive guide for creating custom sprites, including file setup, properties, main structure, initialization, logic, and drawing routines. - Updated oracle.org to include new documentation links and improve project organization with infrastructure suggestions.
This commit is contained in:
145
Docs/SpriteCreationGuide.md
Normal file
145
Docs/SpriteCreationGuide.md
Normal file
@@ -0,0 +1,145 @@
|
||||
# Sprite Creation Guide
|
||||
|
||||
This guide provides a step-by-step walkthrough for creating a new custom sprite in Oracle of Secrets using the project's modern sprite system.
|
||||
|
||||
## 1. File Setup
|
||||
|
||||
1. **Create the Sprite File:** Create a new `.asm` file for your sprite in the appropriate subdirectory of `Sprites/` (e.g., `Sprites/Enemies/MyNewEnemy.asm`).
|
||||
2. **Include the File:** Open `Sprites/all_sprites.asm` and add an `incsrc` directive to include your new file. Make sure to place it in the correct bank section (e.g., Bank 30, 31, or 32) to ensure it gets compiled into the ROM.
|
||||
|
||||
```asm
|
||||
; In Sprites/all_sprites.asm
|
||||
org $318000 ; Bank 31
|
||||
...
|
||||
incsrc "Sprites/Enemies/MyNewEnemy.asm"
|
||||
```
|
||||
|
||||
## 2. Sprite Properties
|
||||
|
||||
At the top of your new sprite file, define its core properties using the provided template. These `!` constants are used by the `%Set_Sprite_Properties` macro to automatically configure the sprite's behavior and integrate it into the game.
|
||||
|
||||
```asm
|
||||
; Properties for MyNewEnemy
|
||||
!SPRID = $XX ; CHOOSE AN UNUSED SPRITE ID!
|
||||
!NbrTiles = 02 ; Number of 8x8 tiles used in the largest frame
|
||||
!Health = 10 ; Health points
|
||||
!Damage = 04 ; Damage dealt to Link on contact (04 = half a heart)
|
||||
!Harmless = 00 ; 00 = Harmful, 01 = Harmless
|
||||
!Hitbox = 08 ; Hitbox size (0-31)
|
||||
!ImperviousAll = 00 ; 01 = All attacks clink harmlessly
|
||||
!Statue = 00 ; 01 = Behaves like a solid statue
|
||||
!Prize = 01 ; Prize pack dropped on death (0-15)
|
||||
; ... and so on for all properties ...
|
||||
|
||||
; This macro MUST be called after the properties
|
||||
%Set_Sprite_Properties(Sprite_MyNewEnemy_Prep, Sprite_MyNewEnemy_Long)
|
||||
```
|
||||
|
||||
## 3. Main Structure (`_Long` routine)
|
||||
|
||||
This is the main entry point for your sprite, called by the game engine every frame. Its primary job is to call the drawing and logic routines.
|
||||
|
||||
```asm
|
||||
Sprite_MyNewEnemy_Long:
|
||||
{
|
||||
PHB : PHK : PLB ; Set up bank registers
|
||||
JSR Sprite_MyNewEnemy_Draw
|
||||
JSL Sprite_DrawShadow ; Optional: Draw a shadow
|
||||
|
||||
JSL Sprite_CheckActive : BCC .SpriteIsNotActive ; Only run logic if active
|
||||
JSR Sprite_MyNewEnemy_Main
|
||||
.SpriteIsNotActive
|
||||
|
||||
PLB ; Restore bank register
|
||||
RTL ; Return from long routine
|
||||
}
|
||||
```
|
||||
|
||||
## 4. Initialization (`_Prep` routine)
|
||||
|
||||
This routine runs *once* when the sprite is first spawned. Use it to set initial values for timers, its action state, and any other properties.
|
||||
|
||||
```asm
|
||||
Sprite_MyNewEnemy_Prep:
|
||||
{
|
||||
PHB : PHK : PLB
|
||||
%GotoAction(0) ; Set the initial state to the first one in the jump table
|
||||
%SetTimerA(120) ; Set a general-purpose timer to 120 frames (2 seconds)
|
||||
PLB
|
||||
RTL
|
||||
}
|
||||
```
|
||||
|
||||
## 5. Main Logic & State Machine (`_Main` routine)
|
||||
|
||||
This is the heart of your sprite. Use the `%SpriteJumpTable` macro to create a state machine. The sprite's current state is stored in `SprAction, X`.
|
||||
|
||||
```asm
|
||||
Sprite_MyNewEnemy_Main:
|
||||
{
|
||||
%SpriteJumpTable(State_Idle, State_Attacking, State_Hurt)
|
||||
|
||||
State_Idle:
|
||||
{
|
||||
%PlayAnimation(0, 1, 15) ; Animate between frames 0 and 1 every 15 game frames
|
||||
|
||||
; Check distance to player. If less than 80 pixels, switch to attacking state.
|
||||
JSL GetDistance8bit_Long : CMP.b #$50 : BCS .player_is_far
|
||||
%GotoAction(1) ; Switch to State_Attacking
|
||||
.player_is_far
|
||||
RTS
|
||||
}
|
||||
|
||||
State_Attacking:
|
||||
{
|
||||
%PlayAnimation(2, 3, 8)
|
||||
%MoveTowardPlayer(12) ; Move toward the player with speed 12
|
||||
%DoDamageToPlayerSameLayerOnContact()
|
||||
|
||||
; Check if the player has hit the sprite
|
||||
JSL Sprite_CheckDamageFromPlayer : BCC .no_damage
|
||||
%GotoAction(2) ; Switch to State_Hurt
|
||||
.no_damage
|
||||
RTS
|
||||
}
|
||||
|
||||
State_Hurt:
|
||||
{
|
||||
; Sprite was hit, flash and get knocked back
|
||||
JSL Sprite_DamageFlash_Long
|
||||
RTS
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 6. Drawing (`_Draw` routine)
|
||||
|
||||
This routine renders your sprite's graphics. The easiest method is to use the `%DrawSprite()` macro, which reads from a set of data tables you define.
|
||||
|
||||
```asm
|
||||
Sprite_MyNewEnemy_Draw:
|
||||
{
|
||||
%DrawSprite()
|
||||
|
||||
; --- OAM Data Tables ---
|
||||
.start_index ; Starting index in the tables for each animation frame
|
||||
db $00, $02, $04, $06
|
||||
.nbr_of_tiles ; Number of tiles to draw for each frame (minus 1)
|
||||
db 1, 1, 1, 1
|
||||
|
||||
.x_offsets ; X-position offset for each tile
|
||||
dw -8, 8, -8, 8, -8, 8, -8, 8
|
||||
.y_offsets ; Y-position offset for each tile
|
||||
dw -8, -8, -8, -8, -8, -8, -8, -8
|
||||
.chr ; The character (tile) number from the graphics sheet
|
||||
db $C0, $C2, $C4, $C6, $C8, $CA, $CC, $CE
|
||||
.properties ; OAM properties (palette, priority, flips)
|
||||
db $3B, $7B, $3B, $7B, $3B, $7B, $3B, $7B
|
||||
.sizes ; Size of each tile (e.g., $02 for 16x16)
|
||||
db $02, $02, $02, $02, $02, $02, $02, $02
|
||||
}
|
||||
```
|
||||
|
||||
## 7. Final Integration
|
||||
|
||||
The `%Set_Sprite_Properties()` macro you added in Step 2 handles the final integration. It automatically adds your sprite's `_Prep` and `_Long` routines to the game's sprite tables in `Core/sprite_new_table.asm`. Your sprite is now ready to be placed in the game world!
|
||||
Reference in New Issue
Block a user