Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
pret
GitHub Repository: pret/pokered
Path: blob/master/engine/overworld/sprite_collisions.asm
1271 views
1
_UpdateSprites::
2
ld h, HIGH(wSpriteStateData1)
3
inc h
4
ld a, SPRITESTATEDATA2_IMAGEBASEOFFSET
5
.spriteLoop
6
ld l, a
7
sub SPRITESTATEDATA2_IMAGEBASEOFFSET
8
ld c, a
9
ldh [hCurrentSpriteOffset], a
10
ld a, [hl]
11
and a
12
jr z, .skipSprite ; tests SPRITESTATEDATA2_IMAGEBASEOFFSET
13
push hl
14
push de
15
push bc
16
call .updateCurrentSprite
17
pop bc
18
pop de
19
pop hl
20
.skipSprite
21
ld a, l
22
add $10 ; move to next sprite
23
cp SPRITESTATEDATA2_IMAGEBASEOFFSET ; test for overflow (back at beginning)
24
jr nz, .spriteLoop
25
ret
26
.updateCurrentSprite
27
cp $1
28
jp nz, UpdateNonPlayerSprite
29
jp UpdatePlayerSprite
30
31
UpdateNonPlayerSprite:
32
dec a
33
swap a
34
ldh [hTilePlayerStandingOn], a ; $10 * sprite#
35
ld a, [wNPCMovementScriptSpriteOffset] ; some sprite offset?
36
ld b, a
37
ldh a, [hCurrentSpriteOffset]
38
cp b
39
jr nz, .unequal
40
jp DoScriptedNPCMovement
41
.unequal
42
jp UpdateNPCSprite
43
44
; This detects if the current sprite (whose offset is at hCurrentSpriteOffset)
45
; is going to collide with another sprite by looping over the other sprites.
46
; The current sprite's offset will be labelled with i (e.g. i#SPRITESTATEDATA1_PICTUREID).
47
; The loop sprite's offset will labelled with j (e.g. j#SPRITESTATEDATA1_PICTUREID).
48
;
49
; Note that the Y coordinate of the sprite (in [k#SPRITESTATEDATA1_YPIXELS])
50
; is one of the following 9 values when the sprite is aligned with the grid:
51
; $fc, $0c, $1c, $2c, ..., $7c.
52
; The reason that 4 is added below to the coordinate is to make it align with a
53
; multiple of $10 to make comparisons easier.
54
DetectCollisionBetweenSprites:
55
nop
56
57
ld h, HIGH(wSpriteStateData1)
58
ldh a, [hCurrentSpriteOffset]
59
add LOW(wSpriteStateData1)
60
ld l, a
61
62
ld a, [hl] ; a = [i#SPRITESTATEDATA1_PICTUREID] (0 if slot is unused)
63
and a ; is this sprite slot slot used?
64
ret z ; return if not used
65
66
ld a, l
67
add 3
68
ld l, a
69
70
ld a, [hli] ; a = [i#SPRITESTATEDATA1_YSTEPVECTOR] (-1, 0, or 1)
71
call SetSpriteCollisionValues
72
73
ld a, [hli] ; a = [i#SPRITESTATEDATA1_YPIXELS]
74
add 4 ; align with multiple of $10
75
76
; The effect of the following 3 lines is to
77
; add 7 to a if moving south or
78
; subtract 7 from a if moving north.
79
add b
80
and $f0
81
or c
82
83
ldh [hCollidingSpriteTempYValue], a ; y adjusted for direction of movement
84
85
ld a, [hli] ; a = [i#SPRITESTATEDATA1_XSTEPVECTOR] (-1, 0, or 1)
86
call SetSpriteCollisionValues
87
ld a, [hl] ; a = [i#SPRITESTATEDATA1_XPIXELS]
88
89
; The effect of the following 3 lines is to
90
; add 7 to a if moving east or
91
; subtract 7 from a if moving west.
92
add b
93
and $f0
94
or c
95
96
ldh [hCollidingSpriteTempXValue], a ; x adjusted for direction of movement
97
98
ld a, l
99
add 7
100
ld l, a
101
102
xor a
103
ld [hld], a ; zero [i#SPRITESTATEDATA1_0D] XXX what's this for?
104
ld [hld], a ; zero [i#SPRITESTATEDATA1_COLLISIONDATA]
105
106
ldh a, [hCollidingSpriteTempXValue]
107
ld [hld], a ; [i#SPRITESTATEDATA1_XADJUSTED]
108
ldh a, [hCollidingSpriteTempYValue]
109
ld [hl], a ; [i#SPRITESTATEDATA1_YADJUSTED]
110
111
xor a ; zero the loop counter
112
113
.loop
114
ldh [hCollidingSpriteOffset], a
115
swap a
116
ld e, a
117
ldh a, [hCurrentSpriteOffset]
118
cp e ; does the loop sprite match the current sprite?
119
jp z, .next ; go to the next sprite if they match
120
121
ld d, h
122
ld a, [de] ; a = [j#SPRITESTATEDATA1_PICTUREID] (0 if slot is unused)
123
and a ; is this sprite slot slot used?
124
jp z, .next ; go the next sprite if not used
125
126
inc e
127
inc e
128
ld a, [de] ; a = [j#SPRITESTATEDATA1_IMAGEINDEX] ($ff means the sprite is offscreen)
129
inc a
130
jp z, .next ; go the next sprite if offscreen
131
132
ldh a, [hCurrentSpriteOffset]
133
add 10
134
ld l, a
135
136
inc e
137
ld a, [de] ; a = [j#SPRITESTATEDATA1_YSTEPVECTOR]
138
call SetSpriteCollisionValues
139
140
inc e
141
ld a, [de] ; a = [j#SPRITESTATEDATA1_YPIXELS]
142
add 4 ; align with multiple of $10
143
144
; The effect of the following 3 lines is to
145
; add 7 to a if moving south or
146
; subtract 7 from a if moving north.
147
add b
148
and $f0
149
or c
150
151
sub [hl] ; subtract [i#SPRITESTATEDATA1_YADJUSTED] from [j#SPRITESTATEDATA1_YADJUSTED]
152
153
; calculate the absolute value of the difference to get the distance
154
jr nc, .noCarry1
155
cpl
156
inc a
157
.noCarry1
158
ldh [hCollidingSpriteTempYValue], a ; store the distance between the two sprites' adjusted Y values
159
160
; Use the carry flag set by the above subtraction to determine which sprite's
161
; Y coordinate is larger. This information is used later to set
162
; [i#SPRITESTATEDATA1_COLLISIONDATA].
163
; The following 5 lines set the lowest 2 bits of c, which are later shifted left by 2.
164
; If sprite i's Y is larger, set lowest 2 bits of c to 10.
165
; If sprite j's Y is larger or both are equal, set lowest 2 bits of c to 01.
166
push af
167
rl c
168
pop af
169
ccf
170
rl c
171
172
; If sprite i's delta Y is 0, then b = 7, else b = 9.
173
ld b, 7
174
ld a, [hl] ; a = [i#SPRITESTATEDATA1_YADJUSTED]
175
and $f
176
jr z, .next1
177
ld b, 9
178
179
.next1
180
ldh a, [hCollidingSpriteTempYValue] ; a = distance between adjusted Y coordinates
181
sub b
182
ldh [hCollidingSpriteAdjustedDistance], a
183
ld a, b
184
ldh [hCollidingSpriteTempYValue], a ; store 7 or 9 depending on sprite i's delta Y
185
jr c, .checkXDistance
186
187
; If sprite j's delta Y is 0, then b = 7, else b = 9.
188
ld b, 7
189
dec e
190
ld a, [de] ; a = [j#SPRITESTATEDATA1_YSTEPVECTOR]
191
inc e
192
and a
193
jr z, .next2
194
ld b, 9
195
196
.next2
197
ldh a, [hCollidingSpriteAdjustedDistance]
198
sub b ; adjust distance using sprite j's direction
199
jr z, .checkXDistance
200
jr nc, .next ; go to next sprite if distance is still positive after both adjustments
201
202
.checkXDistance
203
inc e
204
inc l
205
ld a, [de] ; a = [j#SPRITESTATEDATA1_XSTEPVECTOR]
206
207
push bc
208
209
call SetSpriteCollisionValues
210
inc e
211
ld a, [de] ; a = [j#SPRITESTATEDATA1_XPIXELS]
212
213
; The effect of the following 3 lines is to
214
; add 7 to a if moving east or
215
; subtract 7 from a if moving west.
216
add b
217
and $f0
218
or c
219
220
pop bc
221
222
sub [hl] ; subtract [i#SPRITESTATEDATA1_XADJUSTED] from [j#SPRITESTATEDATA1_XADJUSTED]
223
224
; calculate the absolute value of the difference to get the distance
225
jr nc, .noCarry2
226
cpl
227
inc a
228
.noCarry2
229
ldh [hCollidingSpriteTempXValue], a ; store the distance between the two sprites' adjusted X values
230
231
; Use the carry flag set by the above subtraction to determine which sprite's
232
; X coordinate is larger. This information is used later to set
233
; [i#SPRITESTATEDATA1_COLLISIONDATA].
234
; The following 5 lines set the lowest 2 bits of c.
235
; If sprite i's X is larger, set lowest 2 bits of c to 10.
236
; If sprite j's X is larger or both are equal, set lowest 2 bits of c to 01.
237
push af
238
rl c
239
pop af
240
ccf
241
rl c
242
243
; If sprite i's delta X is 0, then b = 7, else b = 9.
244
ld b, 7
245
ld a, [hl] ; a = [i#SPRITESTATEDATA1_XADJUSTED]
246
and $f
247
jr z, .next3
248
ld b, 9
249
250
.next3
251
ldh a, [hCollidingSpriteTempXValue] ; a = distance between adjusted X coordinates
252
sub b
253
ldh [hCollidingSpriteAdjustedDistance], a
254
ld a, b
255
ldh [hCollidingSpriteTempXValue], a ; store 7 or 9 depending on sprite i's delta X
256
jr c, .collision
257
258
; If sprite j's delta X is 0, then b = 7, else b = 9.
259
ld b, 7
260
dec e
261
ld a, [de] ; a = [j#SPRITESTATEDATA1_XSTEPVECTOR]
262
inc e
263
and a
264
jr z, .next4
265
ld b, 9
266
267
.next4
268
ldh a, [hCollidingSpriteAdjustedDistance]
269
sub b ; adjust distance using sprite j's direction
270
jr z, .collision
271
jr nc, .next ; go to next sprite if distance is still positive after both adjustments
272
273
.collision
274
ldh a, [hCollidingSpriteTempXValue] ; a = 7 or 9 depending on sprite i's delta X
275
ld b, a
276
ldh a, [hCollidingSpriteTempYValue] ; a = 7 or 9 depending on sprite i's delta Y
277
inc l
278
279
; If delta X isn't 0 and delta Y is 0, then b = %0011, else b = %1100.
280
; (note that normally if delta X isn't 0, then delta Y must be 0 and vice versa)
281
cp b
282
jr c, .next5
283
ld b, %1100
284
jr .next6
285
.next5
286
ld b, %0011
287
288
.next6
289
ld a, c ; c has 2 bits set (one of bits 0-1 is set for the X axis and one of bits 2-3 for the Y axis)
290
and b ; we select either the bit in bits 0-1 or bits 2-3 based on the calculation immediately above
291
or [hl] ; or with existing collision direction bits in [i#SPRITESTATEDATA1_COLLISIONDATA]
292
ld [hl], a ; store new value
293
ld a, c ; useless code because a is overwritten before being used again
294
295
; set bit in [i#SPRITESTATEDATA1_0E] or [i#SPRITESTATEDATA1_0F]
296
; to indicate which sprite the collision occurred with
297
inc l
298
inc l
299
ldh a, [hCollidingSpriteOffset]
300
ld de, SpriteCollisionBitTable
301
add a
302
add e
303
ld e, a
304
jr nc, .noCarry3
305
inc d
306
.noCarry3
307
ld a, [de]
308
or [hl]
309
ld [hli], a
310
inc de
311
ld a, [de]
312
or [hl]
313
ld [hl], a
314
315
.next
316
ldh a, [hCollidingSpriteOffset]
317
inc a
318
cp $10
319
jp nz, .loop
320
ret
321
322
; takes delta X or delta Y in a
323
; b = delta X/Y
324
; c = 0 if delta X/Y is 0
325
; c = 7 if delta X/Y is 1
326
; c = 9 if delta X/Y is -1
327
SetSpriteCollisionValues:
328
and a
329
ld b, 0
330
ld c, 0
331
jr z, .done
332
ld c, 9
333
cp -1
334
jr z, .ok
335
ld c, 7
336
ld a, 0
337
.ok
338
ld b, a
339
.done
340
ret
341
342
SpriteCollisionBitTable:
343
FOR n, $10
344
bigdw 1 << n
345
ENDR
346
347