11import {
22 DIRS ,
33 DOWN ,
4- LEFT ,
54 nextGrid ,
65 opposite ,
7- RIGHT ,
86 turnLeft ,
97 turnRight ,
10- UP ,
118} from "../util/dir.ts"
129import { CELL_SIZE } from "../util/constants.ts"
1310import { seed } from "../util/random.ts"
1411import type {
1512 Action ,
16- CommonMove ,
1713 Dir ,
1814 IActor ,
1915 IField ,
16+ IFollower ,
2017 LoadOptions ,
2118 Move ,
2219 PushedEvent ,
@@ -25,6 +22,7 @@ import { ActorDefinition } from "./catalog.ts"
2522import { ActionQueue , type ActorAction } from "./action-queue.ts"
2623import { ActorSpawnInfo } from "./field-block.ts"
2724import { linePattern0 } from "./effect.ts"
25+ import { MoveBounce , MoveGo , MoveJump } from "./move.ts"
2826
2927const fallbackImagePhase0 = await fetch (
3028 "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAADdJREFUOE9jZMAE/9GEGNH4KPLokiC1Q9AAkpzMwMCA4m0QZxgYgJ4SSPLSaDqAJAqSAm3wJSQApTMgCUQZ7FoAAAAASUVORK5CYII=" ,
@@ -79,159 +77,6 @@ export function spawnActor(
7977 return new Actor ( i , j , def , id , dir , speed , moveEnd , idle )
8078}
8179
82- export class MoveGo implements CommonMove {
83- #phase: number = 0
84- #speed: number = 1
85- #dir: Dir
86-
87- type = "move" as const
88- cb ?: ( move : Move ) => void
89-
90- constructor ( speed : 1 | 2 | 4 | 8 | 16 , dir : Dir ) {
91- this . #speed = speed
92- this . #dir = dir
93- }
94-
95- step ( ) {
96- this . #phase += this . #speed
97- }
98-
99- get x ( ) : number {
100- if ( this . #dir === LEFT ) {
101- return 16 - this . #phase
102- } else if ( this . #dir === RIGHT ) {
103- return this . #phase - 16
104- }
105- return 0
106- }
107-
108- get y ( ) : number {
109- if ( this . #dir === UP ) {
110- return 16 - this . #phase
111- } else if ( this . #dir === DOWN ) {
112- return this . #phase - 16
113- }
114- return 0
115- }
116-
117- get finished ( ) : boolean {
118- return this . #phase >= 16
119- }
120-
121- get dir ( ) : Dir {
122- return this . #dir
123- }
124-
125- get halfPassed ( ) : boolean {
126- return this . #phase >= 8
127- }
128- }
129-
130- export class MoveBounce implements CommonMove {
131- #phase: number = 0
132- #dir: Dir
133- #pushedActors: boolean
134- #d = 0
135- #speed: 1 | 2 | 4 | 8 | 16
136-
137- type = "bounce" as const
138- cb ?: ( move : Move ) => void
139-
140- constructor ( dir : Dir , pushedActors : boolean , speed : 1 | 2 | 4 | 8 | 16 ) {
141- this . #dir = dir
142- this . #pushedActors = pushedActors
143- this . #speed = speed
144- }
145-
146- step ( ) {
147- this . #phase += this . #speed
148- if ( this . #phase <= 8 ) {
149- this . #d += this . #speed
150- } else {
151- this . #d -= this . #speed
152- }
153- }
154-
155- get x ( ) : number {
156- if ( this . #dir === LEFT ) {
157- return - this . #d
158- } else if ( this . #dir === RIGHT ) {
159- return this . #d
160- }
161- return 0
162- }
163-
164- get y ( ) : number {
165- if ( this . #dir === UP ) {
166- return - this . #d
167- } else if ( this . #dir === DOWN ) {
168- return this . #d
169- }
170- return 0
171- }
172-
173- get finished ( ) : boolean {
174- return this . #phase >= 16
175- }
176-
177- get pushedActors ( ) : boolean {
178- return this . #pushedActors
179- }
180-
181- get dir ( ) : Dir {
182- return this . #dir
183- }
184-
185- get halfPassed ( ) : boolean {
186- return this . #phase >= 8
187- }
188- }
189-
190- export class MoveJump implements CommonMove {
191- #phase: number = 0
192- #y: number = 0
193-
194- type = "jump" as const
195- cb ?: ( move : Move ) => void
196-
197- get x ( ) : number {
198- return 0
199- }
200-
201- get y ( ) : number {
202- return this . #y
203- }
204-
205- step ( ) {
206- this . #phase += 1
207- if ( this . #phase <= 2 ) {
208- this . #y -= 6
209- } else if ( this . #phase <= 4 ) {
210- this . #y -= 4
211- } else if ( this . #phase <= 6 ) {
212- this . #y -= 2
213- } else if ( this . #phase <= 8 ) {
214- this . #y -= 1
215- } else if ( this . #phase <= 10 ) {
216- this . #y += 1
217- } else if ( this . #phase <= 12 ) {
218- this . #y += 2
219- } else if ( this . #phase <= 14 ) {
220- this . #y += 4
221- } else {
222- this . #y += 6
223- }
224- }
225-
226- get finished ( ) : boolean {
227- return this . #phase >= 16
228- }
229-
230- get halfPassed ( ) : boolean {
231- return this . #phase >= 8
232- }
233- }
234-
23580/**
23681 * The actor class
23782 */
@@ -260,12 +105,16 @@ export class Actor implements IActor {
260105 #speedUpCb?: ( ) => void
261106 /** The move of the actor */
262107 #move: Move | null = null
108+ /** The last move dir */
109+ #lastMoveDir: Dir | null = null
263110 /** MoveEnd delegate */
264111 #moveEnd: MoveEndDelegate | null
265112 /** Idle delegate */
266113 #idle: IdleDelegate | null
267114 /** buff labels */
268115 buff : Record < string , unknown > = { __proto__ : null }
116+ /** The follower */
117+ #follower: IFollower | null = null
269118
270119 /** The queue of actions to be performed */
271120 #actionQueue: ActionQueue < Actor , ActorAction > = new ActionQueue (
@@ -348,12 +197,10 @@ export class Actor implements IActor {
348197 return "end"
349198 }
350199 case "add-buff" : {
351- console . trace ( "add-buff" )
352200 this . buff [ action . buff ] = "value" in action ? action . value : true
353201 return "next"
354202 }
355203 case "remove-buff" : {
356- console . trace ( "remove-buff" )
357204 delete this . buff [ action . buff ]
358205 return "next"
359206 }
@@ -402,8 +249,19 @@ export class Actor implements IActor {
402249 if ( type === "go" ) this . setDir ( dir )
403250 if ( this . canGo ( dir , field ) ) {
404251 this . #move = new MoveGo ( this . #speed, dir )
405- const [ nextI , nextJ ] = this . nextGrid ( dir )
252+ if (
253+ this . #follower && this . #lastMoveDir &&
254+ ( this . #i !== this . #follower. i || this . #j !== this . #follower. j )
255+ ) {
256+ this . #follower. enqueueActions ( {
257+ type : "go" ,
258+ dir : this . #lastMoveDir,
259+ speed : this . #speed,
260+ } )
261+ }
262+
406263 // actor position moves to the next grid immediately (the animation catches it up in 16 frames)
264+ const [ nextI , nextJ ] = this . nextGrid ( dir )
407265 this . #i = nextI
408266 this . #j = nextJ
409267 this . #physicalGridKey = this . #calcPhysicalGridKey( )
@@ -484,6 +342,9 @@ export class Actor implements IActor {
484342 if ( this . #move. finished ) {
485343 this . #move. cb ?.( this . #move)
486344 this . #moveEnd?. onMoveEnd ( this , field , this . #move)
345+ if ( this . #move. type === "move" ) {
346+ this . #lastMoveDir = this . #move. dir
347+ }
487348 this . #move = null
488349 }
489350 } else {
@@ -663,6 +524,10 @@ export class Actor implements IActor {
663524 this . enqueueActions ( { type : "slide" , dir : event . dir } )
664525 }
665526 }
527+
528+ setFollower ( follower : IFollower ) {
529+ this . #follower = follower
530+ }
666531}
667532
668533export interface MoveEndDelegate {
0 commit comments