Skip to content

Commit 028925b

Browse files
committed
feat: jump chars
1 parent 511290b commit 028925b

4 files changed

Lines changed: 53 additions & 9 deletions

File tree

model/character.ts

Lines changed: 44 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,9 @@ export function spawnCharacter(
9494
throw new Error(`Unknown character type: ${type}`)
9595
}
9696

97+
type MoveType = "linear" | "bounce" | "jump"
98+
type NextState = Dir | "jump" | undefined
99+
97100
/** The abstract character class
98101
* The parent class of MainCharacter and NPC.
99102
*/
@@ -117,7 +120,7 @@ export abstract class Character implements IChar {
117120
/** The counter of the idle state */
118121
#idleCounter: number = 0
119122
/** Type of the move */
120-
#moveType: "linear" | "bounce" = "linear"
123+
#moveType: MoveType = "linear"
121124
/** The key of the physical grid, which is used for collision detection */
122125
#physicalGridKey: string
123126
/** The prefix of assets */
@@ -190,14 +193,14 @@ export abstract class Character implements IChar {
190193
_input: typeof Input,
191194
_fieldTester: IFieldTester,
192195
_collisionChecker: CollisionChecker,
193-
): Dir | undefined {
196+
): NextState {
194197
return undefined
195198
}
196199

197200
onMoveEnd(
198201
_fieldTester: IFieldTester,
199202
_itemContainer: ItemContainer,
200-
_moveType: "linear" | "bounce",
203+
_moveType: MoveType,
201204
): void {}
202205

203206
step(
@@ -208,7 +211,10 @@ export abstract class Character implements IChar {
208211
) {
209212
if (this.#movePhase === 0) {
210213
const nextState = this.getNextState(input, fieldTester, collisionChecker)
211-
if (nextState) {
214+
if (
215+
nextState === "up" || nextState === "down" ||
216+
nextState === "left" || nextState === "right"
217+
) {
212218
this.setDir(nextState)
213219
this.#isMoving = true
214220
this.#idleCounter = 0
@@ -218,6 +224,11 @@ export abstract class Character implements IChar {
218224
} else {
219225
this.#moveType = "bounce"
220226
}
227+
} else if (nextState === "jump") {
228+
this.#isMoving = true
229+
this.#idleCounter = 0
230+
this.#moveType = "jump"
231+
// Jumping is always allowed.
221232
}
222233
}
223234

@@ -253,6 +264,19 @@ export abstract class Character implements IChar {
253264
this.#d = 0
254265
this.onMoveEnd(fieldTester, itemContainer, this.#moveType)
255266
}
267+
} else if (this.#moveType === "jump") {
268+
this.#movePhase += this.#speed
269+
if (this.#movePhase < 4) {
270+
this.#d += this.#speed * 2
271+
} else {
272+
this.#d -= this.#speed * 2
273+
}
274+
if (this.#movePhase == 8) {
275+
this.#movePhase = 0
276+
this.#isMoving = false
277+
this.#d = 0
278+
this.onMoveEnd(fieldTester, itemContainer, this.#moveType)
279+
}
256280
}
257281
} else {
258282
this.#idleCounter += 1
@@ -291,6 +315,10 @@ export abstract class Character implements IChar {
291315

292316
/** Gets the x of the world coordinates */
293317
get x(): number {
318+
if (this.#isMoving && this.#moveType === "jump") {
319+
return this.#i * CELL_SIZE
320+
}
321+
294322
if (this.#dir === LEFT) {
295323
return this.#i * CELL_SIZE - this.#d
296324
} else if (this.#dir === RIGHT) {
@@ -306,6 +334,10 @@ export abstract class Character implements IChar {
306334

307335
/** Gets the y of the world coordinates */
308336
get y(): number {
337+
if (this.#isMoving && this.#moveType === "jump") {
338+
return this.#j * CELL_SIZE - this.#d
339+
}
340+
309341
if (this.#dir === UP) {
310342
return this.#j * CELL_SIZE - this.#d
311343
} else if (this.#dir === DOWN) {
@@ -417,7 +449,7 @@ export class MainCharacter extends Character {
417449
input: typeof Input,
418450
_fieldTester: IFieldTester,
419451
_collisionChecker: CollisionChecker,
420-
): Dir | undefined {
452+
): NextState {
421453
if (input.up) {
422454
return UP
423455
} else if (input.down) {
@@ -426,6 +458,8 @@ export class MainCharacter extends Character {
426458
return LEFT
427459
} else if (input.right) {
428460
return RIGHT
461+
} else if (input.space) {
462+
return "jump"
429463
}
430464
return undefined
431465
}
@@ -462,18 +496,21 @@ export class RandomWalkNPC extends Character {
462496
_input: typeof Input,
463497
fieldTester: IFieldTester,
464498
collisionChecker: CollisionChecker,
465-
): Dir | undefined {
499+
): NextState {
466500
this.#counter -= 1
467501
if (this.#counter <= 0) {
468502
this.#counter = randomInt(8) + 4
469503
// If the character can keep going in the current direction,
470-
// it will keep going with 80% probability.
504+
// it will keep going with 96% probability.
471505
if (
472506
this.canEnter(this.dir, fieldTester, collisionChecker) &&
473507
Math.random() < 0.96
474508
) {
475509
return this.dir
476510
}
511+
if (randomInt(2) === 0) {
512+
return "jump"
513+
}
477514
const nextCandidate = [UP, DOWN, LEFT, RIGHT] as Dir[]
478515
return choice(nextCandidate.filter((d) => {
479516
return this.canEnter(d, fieldTester, collisionChecker)

model/field-block.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -202,7 +202,7 @@ export class BlockMap {
202202
}
203203
}
204204

205-
/** {@linkcode FieldBlock} represents a block of a field */
205+
/** {@linkcode FieldBlock} represents a {@linkcode BLOCK_SIZE} x {@linkcode BLOCK_SIZE} block of a field */
206206
export class FieldBlock {
207207
#x: number
208208
#y: number

player/ui/key-monitor.ts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,10 +26,13 @@ export function KeyMonitor({ on }: Context) {
2626
} else if (KEY_RIGHT.has(e.key)) {
2727
e.preventDefault()
2828
Input.right = true
29+
} else if (e.key === " ") {
30+
console.log("Space key pressed, marking Input.space as true")
31+
e.preventDefault()
32+
Input.space = true
2933
}
3034
})
3135
on("keyup", (e) => {
32-
console.log("keyup", e.key)
3336
if (KEY_UP.has(e.key)) {
3437
Input.up = false
3538
} else if (KEY_DOWN.has(e.key)) {
@@ -38,6 +41,8 @@ export function KeyMonitor({ on }: Context) {
3841
Input.left = false
3942
} else if (KEY_RIGHT.has(e.key)) {
4043
Input.right = false
44+
} else if (e.key === " ") {
45+
Input.space = false
4146
}
4247
})
4348
}

util/dir.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,11 +18,13 @@ export const Input = {
1818
down: false,
1919
left: false,
2020
right: false,
21+
space: false,
2122
}
2223

2324
/** Clear the current direction input state */
2425
export function clearInput() {
2526
for (const dir of DIRS) {
2627
Input[dir] = false
2728
}
29+
Input.space = false
2830
}

0 commit comments

Comments
 (0)