1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
|
;;;
;; This is similar to the basics/sprite.s example, but it expands a bit on it
;; by:
;; - The ship can be moved:
;; - The movement is done through subpixels for a smoother experience.
;; - The ship's sprites are updated accordingly: resting, acceleration, full
;; speed.
;; - The ship can shoot
;;
;; The subpixel movement is largely based on:
;; https://github.com/NesHacker/PlatformerMovement.
;;;
.segment "HEADER"
.byte 'N', 'E', 'S', $1A
;; 2x PRG-ROM; 1x CHR-ROM
.byte $02
.byte $01
;; Horizontal mirroring, no special mapper.
.byte $00
.byte $00
.segment "VECTORS"
.addr nmi, reset, irq
.segment "CHARS"
.incbin "../assets/space.chr"
.segment "STARTUP"
.segment "CODE"
.include "../include/apu.s"
.include "../include/oam.s"
.include "../include/ppu.s"
.include "../include/joypad.s"
.include "states/game.s"
.include "states/player.s"
.include "states/bullets.s"
.include "vectors/reset.s"
.include "vectors/nmi.s"
.include "vectors/irq.s"
;;;
;; This is our main subroutine, the reset procedure will call at the very end of
;; initializing the hardware.
;;;
.proc main
;; Before starting the game loop proper we initialize all our assets: load
;; the palettes, nametables and sprites for this game.
jsr init_palettes
jsr init_nametable
jsr Player::init
jsr Bullets::init
cli
;; 7: allow NMI; 5: sprite size is 8x16; 4: background pattern table starts
;; at $1000.
lda #%10110000
sta PPU::CONTROL
;; 4: show sprites; 3: show background; 2: show sprites in leftmost pixels
;; on the screen; 1: same as 2 but for background.
lda #%00011110
sta PPU::MASK
@main_game_loop:
jsr Joypad::read
jsr Player::Movement::update
jsr Player::Sprite::update
jsr Bullets::update
;; This is a hand-shake between the code on `main` and the code on the
;; `nmi`. See Game::flags for more.
SET_RENDER_FLAG
@wait_for_render:
bit Game::flags
bmi @wait_for_render
;; Rendering is done, we can perform another iteration of the loop!
jmp @main_game_loop
.endproc
;; init_palettes copies all the palettes for our game into the proper PPU
;; address.
.proc init_palettes
PPU_ADDR $3F00
ldx #0
@load_palettes_loop:
lda palettes, x
sta PPU::DATA
inx
cpx #$20
bne @load_palettes_loop
rts
palettes:
;; Background
.byte $0F, $12, $22, $32
.byte $0F, $00, $28, $30
.byte $0F, $28, $16, $2D
.byte $0F, $28, $16, $2D
;; Foreground
.byte $0F, $00, $05, $30
.byte $0F, $00, $00, $00
.byte $0F, $00, $00, $00
.byte $0F, $00, $00, $00
.endproc
;; init_nametable loads the relevant data to the nametable that is then going to
;; be used in order to build up the background.
.proc init_nametable
bit PPU::STATUS
;; Big stars.
WRITE_PPU_DATA $20C8, $02
WRITE_PPU_DATA $227A, $02
;; Small stars.
WRITE_PPU_DATA $20B9, $04
WRITE_PPU_DATA $21CE, $04
WRITE_PPU_DATA $21BA, $04
WRITE_PPU_DATA $22B8, $04
WRITE_PPU_DATA $22E7, $04
;; Select palette 1 for one of the small stars, giving it a red-ish look.
WRITE_PPU_DATA $23CE, %00000001
rts
.endproc
|