Skip to content

Commit 1169dc3

Browse files
committed
feat: fish follows you
1 parent e70e252 commit 1169dc3

14 files changed

Lines changed: 348 additions & 211 deletions

File tree

game/field.ts

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -106,8 +106,17 @@ export class FieldItems implements IStepper, ILoader {
106106
return item
107107
}
108108

109-
step(_field: IField) {
110-
// some items might need updates in the future
109+
step(field: IField) {
110+
for (const item of this.#items) {
111+
const key = `${item.i}.${item.j}`
112+
item.step(field)
113+
const keyAfter = `${item.i}.${item.j}`
114+
if (key !== keyAfter) {
115+
// The item has moved
116+
delete this.#coordMap[key]
117+
this.#coordMap[keyAfter] = item
118+
}
119+
}
111120
}
112121

113122
async loadAssets(options: LoadOptions): Promise<void> {

model/action-queue.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
import type { Dir, IEntity, IField, MoveAction } from "./types.ts"
22
import { splashColor } from "../game/field.ts"
33
import { EffectLine1, linePattern0 } from "./effect.ts"
4-
import { UP } from "../util/dir.ts"
54
import { CELL_SIZE } from "../util/constants.ts"
65

76
type CommonAction = {
@@ -38,6 +37,10 @@ export type PropAction =
3837
| { type: "break"; dir: Dir; cb?: (motion: Motion) => void }
3938
| { type: "remove" }
4039

40+
export type ItemAction =
41+
| CommonAction
42+
| MoveAction & { readonly type: "go" }
43+
4144
export type ActorAction =
4245
| CommonAction
4346
| MoveAction

model/actor.ts

Lines changed: 25 additions & 160 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,19 @@
11
import {
22
DIRS,
33
DOWN,
4-
LEFT,
54
nextGrid,
65
opposite,
7-
RIGHT,
86
turnLeft,
97
turnRight,
10-
UP,
118
} from "../util/dir.ts"
129
import { CELL_SIZE } from "../util/constants.ts"
1310
import { seed } from "../util/random.ts"
1411
import 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"
2522
import { ActionQueue, type ActorAction } from "./action-queue.ts"
2623
import { ActorSpawnInfo } from "./field-block.ts"
2724
import { linePattern0 } from "./effect.ts"
25+
import { MoveBounce, MoveGo, MoveJump } from "./move.ts"
2826

2927
const 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

668533
export interface MoveEndDelegate {

0 commit comments

Comments
 (0)