Skip to content

Commit c36010b

Browse files
committed
history is not working well but idc
1 parent f117025 commit c36010b

File tree

5 files changed

+118
-70
lines changed

5 files changed

+118
-70
lines changed

src/ability.ts

Lines changed: 69 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import { get } from "svelte/store";
22
import { Block, Facing } from "./constants.ts";
3+
import { printCells } from "./grid.ts";
34
import { createSnapshot } from "./history.ts";
45
import type { Player } from "./player.ts";
56
import type {
@@ -44,6 +45,12 @@ export class AbilityControl {
4445
e.preventDefault();
4546
if (this.usage.paste > 0) this.paste(cx, parent.facing);
4647
});
48+
const ss = createSnapshot(cx);
49+
const cfg = get(cx.config);
50+
ss.playerX = cfg.initialPlayerX;
51+
ss.playerY = cfg.initialPlayerY;
52+
console.log(ss);
53+
this.pushHistory(cx, ss);
4754
}
4855
setInventory(cx: Context, inventory: MovableObject | null) {
4956
this.inventory = structuredClone(inventory);
@@ -96,7 +103,7 @@ export class AbilityControl {
96103
paste(cx: Context, facing: Facing) {
97104
const state = get(cx.state);
98105
if (!this.focused) return;
99-
if (!this.inventory /*|| this.inventory === Block.air*/) return;
106+
if (!this.inventory) return;
100107

101108
// 左向きのときにブロックを配置する位置を変更するのに使用
102109
const width =
@@ -134,6 +141,7 @@ export class AbilityControl {
134141
paste: --this.usage.paste,
135142
}));
136143

144+
printCells(createSnapshot(cx).game.cells, "paste");
137145
this.pushHistory(cx, createSnapshot(cx));
138146
}
139147
cut(cx: Context) {
@@ -145,90 +153,103 @@ export class AbilityControl {
145153
const target = cx.grid.getBlock(x, y);
146154
// removable 以外はカットできない
147155
if (!target || target !== Block.movable) return;
148-
const prevInventory = this.inventory;
149156
const movableObject = cx.grid.getMovableObject(x, y);
150157
if (!movableObject) return;
151158

152-
this.pushHistory(cx, createSnapshot(cx)); // TODO: snapshot current state
153-
159+
this.pushHistory(cx, createSnapshot(cx));
154160
this.setInventory(cx, movableObject);
155161

156162
cx.grid.update(cx, (prev) =>
157163
prev.objectId === movableObject.objectId ? { block: Block.air } : prev,
158164
);
159-
const prevEnabled = { ...this.usage };
160165
cx.uiContext.update((prev) => ({
161166
...prev,
162167
cut: --this.usage.cut,
163168
}));
164169

170+
printCells(createSnapshot(cx).game.cells, "cut");
165171
this.pushHistory(cx, createSnapshot(cx));
166172
}
167173

168174
// History については、 `docs/history-stack.png` を参照のこと
169175
pushHistory(cx: Context, h: StateSnapshot) {
176+
printCells(h.game.cells, "pushHistory");
170177
cx.history.update((prev) => {
171-
prev.tree = prev.tree.slice(0, prev.index + 1);
178+
if (prev.tree.length > prev.index + 1) {
179+
// redo した後に undo した場合、履歴を切り詰める
180+
prev.tree.length = prev.index + 1;
181+
}
172182
prev.tree.push(h);
173-
prev.index++;
183+
prev.index = prev.tree.length - 1;
174184
return prev;
175185
});
176186
}
177-
undo(cx: Context) {
178-
cx.history.update((prev) => {
179-
const history = prev;
180-
const grid = cx.grid;
181-
if (history.index <= 0) return history;
182-
history.index--;
183-
const snapshot = history.tree[history.index];
187+
undo(cx: Context): { x: number; y: number } | undefined {
188+
const history = get(cx.history);
189+
if (history.index <= 0) return undefined;
190+
const grid = cx.grid;
191+
history.index--;
192+
const snapshot = history.tree[history.index];
193+
printCells(snapshot.game.cells);
184194

185-
// オブジェクトを配置
186-
this.setInventory(cx, snapshot.game.inventory);
187-
grid.diffAndUpdateTo(snapshot.game.cells);
195+
// オブジェクトを配置
196+
this.setInventory(cx, snapshot.game.inventory);
197+
grid.diffAndUpdateTo(cx, snapshot.game.cells);
198+
printCells(snapshot.game.cells, "undo");
199+
this.usage = snapshot.game.usage;
200+
cx.uiContext.update((ui) => ({
201+
...ui,
202+
...this.usage,
203+
undo: history.index,
204+
redo: history.tree.length - history.index,
205+
}));
188206

189-
this.usage = snapshot.game.usage;
190-
cx.uiContext.update((prev) => ({
191-
...prev,
192-
...this.usage,
193-
undo: history.index,
194-
redo: history.tree.length - history.index,
195-
}));
207+
cx.history.set(history);
196208

197-
console.log(`history: ${history.index} / ${history.tree.length}`);
198-
return prev;
199-
});
209+
console.log(`history: ${history.index} / ${history.tree.length - 1}`);
210+
return {
211+
x: history.tree[history.index].playerX,
212+
y: history.tree[history.index].playerY,
213+
};
200214
}
201-
redo(cx: Context, history: GameHistory) {
202-
if (history.index >= history.tree.length) return;
215+
redo(cx: Context): { x: number; y: number } | undefined {
216+
// TODO: プレイヤーの座標の履歴を「いい感じ」にするため、 history を二重管理する
217+
const history = get(cx.history);
218+
if (history.index >= history.tree.length - 1) return undefined;
203219
const snapshot = history.tree[history.index];
220+
printCells(snapshot.game.cells, "redo");
204221
history.index++; // redo は、巻き戻し前の index
205222
const grid = cx.grid;
206223

207-
// オブジェクトを配置
208-
grid.diffAndUpdateTo(snapshot.game.cells);
209-
224+
// 状態を巻き戻す
225+
grid.diffAndUpdateTo(cx, snapshot.game.cells);
210226
this.setInventory(cx, snapshot.game.inventory);
211227

212228
this.usage = snapshot.game.usage;
213-
cx.uiContext.update((prev) => ({
214-
...prev,
229+
cx.uiContext.update((ui) => ({
230+
...ui,
215231
...this.usage,
216232
undo: history.index,
217233
redo: history.tree.length - history.index,
218234
}));
219235

220-
console.log(`history: ${history.index} / ${history.tree.length}`);
236+
console.log(`history: ${history.index} / ${history.tree.length - 1}`);
237+
cx.history.set(history);
238+
return {
239+
x: history.tree[history.index].playerX,
240+
y: history.tree[history.index].playerY,
241+
};
221242
}
222243
handleKeyDown(
223244
cx: Context,
224245
e: KeyboardEvent,
225246
onGround: boolean,
226247
facing: Facing,
227-
history: GameHistory,
228248
playerAt: Coords,
229-
) {
249+
): { x: number; y: number } | undefined {
230250
if (!(e.ctrlKey || e.metaKey)) return undefined;
231251

252+
e.preventDefault();
232253
if (this.usage.paste > 0 && onGround && e.key === "v") {
233254
this.paste(cx, facing);
234255
}
@@ -237,24 +258,14 @@ export class AbilityControl {
237258
}
238259
if (this.usage.cut > 0 && onGround && e.key === "x") {
239260
this.cut(cx);
261+
return undefined;
240262
}
241263
if (e.key === "z") {
242-
console.log(history);
243-
this.undo(cx);
244-
e.preventDefault();
245-
return {
246-
x: history.tree[history.index].playerX,
247-
y: history.tree[history.index].playerY,
248-
};
264+
return this.undo(cx);
249265
}
250266
if (e.key === "y") {
251-
this.redo(cx, history);
252267
e.preventDefault();
253-
if (history.index >= history.tree.length) return;
254-
return {
255-
x: history.tree[history.index].playerX,
256-
y: history.tree[history.index].playerY,
257-
};
268+
return this.redo(cx);
258269
}
259270
}
260271
}
@@ -263,11 +274,11 @@ function placeMovableObject(
263274
cx: Context,
264275
x: number,
265276
y: number,
266-
movableObject: MovableObject,
277+
object: MovableObject,
267278
) {
268279
const grid = cx.grid;
269280

270-
for (const i of movableObject.relativePositions) {
281+
for (const i of object.relativePositions) {
271282
const positionX = x + i.x;
272283
const positionY = y + i.y;
273284
const target = grid.getBlock(positionX, positionY);
@@ -276,12 +287,12 @@ function placeMovableObject(
276287
return;
277288
}
278289
}
279-
for (const i of movableObject.relativePositions) {
280-
const positionX = x + i.x;
281-
const positionY = y + i.y;
282-
grid.setBlock(cx, x, y, {
283-
block: movableObject.block,
284-
objectId: movableObject.objectId,
290+
for (const rel of object.relativePositions) {
291+
const positionX = x + rel.x;
292+
const positionY = y + rel.y;
293+
grid.setBlock(cx, positionX, positionY, {
294+
block: object.block,
295+
objectId: object.objectId,
285296
});
286297
}
287298
}

src/grid.ts

Lines changed: 42 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -95,9 +95,16 @@ export class Grid {
9595

9696
this.initOOBSprites(cellSize);
9797
}
98-
diffAndUpdateTo(newGrid: GridCell[][]) {
99-
// TODO
100-
console.log("TODO: implement diffing alg");
98+
diffAndUpdateTo(cx: Context, newGrid: GridCell[][]) {
99+
for (let y = 0; y < this.cells.length; y++) {
100+
for (let x = 0; x < this.cells[y].length; x++) {
101+
const cell = this.cells[y][x];
102+
const newCell = newGrid[y][x];
103+
if (cell.block !== newCell.block) {
104+
this.setBlock(cx, x, y, newCell);
105+
}
106+
}
107+
}
101108
}
102109
update(cx: Context, fn: (cell: GridCell, x: number, y: number) => GridCell) {
103110
const { blockSize } = get(cx.config);
@@ -112,7 +119,6 @@ export class Grid {
112119
}
113120
}
114121
snapshot(): GridCell[][] {
115-
console.log(this.cells);
116122
return structuredClone(this.cells);
117123
}
118124
initOOBSprites(cellSize: number) {
@@ -174,9 +180,10 @@ export class Grid {
174180
const objectId = cell.objectId;
175181
const retrievedBlocks: { x: number; y: number }[] = [];
176182
for (let y = 0; y < this.cells.length; y++) {
177-
for (let x = 0; x < this.cells[y].length; x++) {}
178-
if (this.cells[y][x].objectId === cell.objectId) {
179-
retrievedBlocks.push({ x, y });
183+
for (let x = 0; x < this.cells[y].length; x++) {
184+
if (this.cells[y][x].objectId === cell.objectId) {
185+
retrievedBlocks.push({ x, y });
186+
}
180187
}
181188
}
182189
const retrievedObject: MovableObject = {
@@ -190,13 +197,11 @@ export class Grid {
190197
return retrievedObject;
191198
}
192199
setBlock(cx: Context, x: number, y: number, cell: GridCell) {
193-
console.log("setBlock called at", x, y);
194200
const prevSprite = this.sprites[y][x];
195201
const { blockSize, marginY } = get(cx.config);
196202
const prev = this.cells[y][x];
197203
if (prev.block === cell.block) return;
198204
if (prevSprite.sprite) {
199-
console.log("removing child at", x, y);
200205
cx._stage.removeChild(prevSprite.sprite);
201206
}
202207
if (prev.block === Block.air && prevSprite.sprite) {
@@ -252,6 +257,10 @@ export class Grid {
252257
default:
253258
cell satisfies never;
254259
}
260+
cx.state.update((prev) => ({
261+
...prev,
262+
cells: this.cells,
263+
}));
255264
}
256265
}
257266

@@ -291,3 +300,27 @@ function updateSprite(
291300
sprite.x = x * blockSize;
292301
sprite.y = y * blockSize + marginY;
293302
}
303+
304+
export function printCells(cells: GridCell[][], context?: string) {
305+
console.log(
306+
`${context ? context : "Grid"}:
307+
${cells
308+
.map((row) =>
309+
row
310+
.map((cell) => {
311+
switch (cell.block) {
312+
case Block.air:
313+
return ".";
314+
case Block.block:
315+
return "b";
316+
case Block.movable:
317+
return "m";
318+
default:
319+
cell satisfies never;
320+
}
321+
})
322+
.join(""),
323+
)
324+
.join("\n")}`,
325+
);
326+
}

src/history.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ export function createSnapshot(cx: Context): StateSnapshot {
77
const playerY = cx.dynamic.playerY;
88
const playerFacing = cx.dynamic.playerFacing;
99
return {
10-
game,
10+
game: structuredClone(game),
1111
playerX,
1212
playerY,
1313
playerFacing,

src/main.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,7 @@ export async function setup(
8181
initialPlayerY: stageDefinition.initialPlayerY,
8282
}),
8383
history: writable({
84-
index: 0,
84+
index: -1,
8585
tree: [],
8686
}),
8787
elapsed: writable(0),

src/player.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -95,7 +95,6 @@ export class Player {
9595
event,
9696
this.onGround,
9797
this.facing,
98-
get(_cx.history),
9998
{ x: this.x, y: this.y },
10099
);
101100
if (playerPosition) {
@@ -244,6 +243,11 @@ export class Player {
244243
this.x += this.vx * ticker.deltaTime;
245244
this.y += this.vy * ticker.deltaTime;
246245
this.vy += consts.gravity * blockSize * ticker.deltaTime;
246+
247+
cx.dynamic.playerX = this.x;
248+
cx.dynamic.playerY = this.y;
249+
cx.dynamic.playerFacing = this.facing;
250+
cx.dynamic.focus = this.getCoords(cx); // TODO: これをやると、focusがplayerの位置に移動してしまう。修正する。
247251
}
248252
resize(cx: Context) {
249253
const state = get(cx.state);

0 commit comments

Comments
 (0)