Skip to content

Commit c49bfc6

Browse files
committed
✨ better game rules
1 parent 3e79a68 commit c49bfc6

File tree

3 files changed

+49
-30
lines changed

3 files changed

+49
-30
lines changed

src/game/state.ts

Lines changed: 37 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,10 @@
11
import * as CANNON from "cannon-es";
22
import { clamp } from "three/src/math/MathUtils";
3-
import { type Category, isScoreSheetFinished } from "../gameRules/types";
3+
import {
4+
type Category,
5+
isDiceValue,
6+
isScoreSheetFinished,
7+
} from "../gameRules/types";
48
import { stepSpring } from "./spring";
59
import { getDiceUpFace, isBodySleeping, isDiceFlat } from "./getDiceUpFace";
610
import { getCrumbledCubes } from "./getCrumbledCubes";
@@ -53,7 +57,7 @@ export const createGameWorld = () => {
5357
//
5458

5559
const state = {
56-
game: createRGame(),
60+
game: createRGame(nDice),
5761
throw: { x: 0, v: 0, target: 0 },
5862
pull: { x: 1, v: 0, target: 1 },
5963
camera: new CANNON.Transform(),
@@ -66,23 +70,30 @@ export const createGameWorld = () => {
6670
};
6771

6872
const crumbled = getCrumbledCubes({ n: nDice });
69-
for (let i = nDice; i--; ) {
70-
copyTransform(crumbled[i], state.dices[i].crumbled);
71-
state.dices[i].crumbled.position.y += -2;
72-
state.dices[i].crumbled.position.z += -3;
73-
74-
state.dices[i].thrown.position.set(
75-
state.dices[i].crumbled.position.x * 1.6,
76-
state.dices[i].crumbled.position.y * 1.1 + 0.6,
77-
state.dices[i].crumbled.position.z - 4
78-
);
79-
state.dices[i].thrown.quaternion
73+
const assignCrumbledPosition = () => {
74+
const tr = new CANNON.Transform();
75+
tr.quaternion
8076
.set(Math.random(), Math.random(), Math.random(), 1)
8177
.normalize();
82-
}
78+
for (let i = nDice; i--;) {
79+
composeTransform(tr, crumbled[i], state.dices[i].crumbled);
80+
state.dices[i].crumbled.position.y += -2;
81+
state.dices[i].crumbled.position.z += -3;
82+
83+
state.dices[i].thrown.position.set(
84+
state.dices[i].crumbled.position.x * 1.6,
85+
state.dices[i].crumbled.position.y * 1.1 + 0.6,
86+
state.dices[i].crumbled.position.z - 4
87+
);
88+
state.dices[i].thrown.quaternion
89+
.set(Math.random(), Math.random(), Math.random(), 1)
90+
.normalize();
91+
}
92+
};
93+
assignCrumbledPosition();
8394

8495
const throwDices = () => {
85-
for (let i = nDice; i--; ) {
96+
for (let i = nDice; i--;) {
8697
const body = state.dices[i].physical;
8798

8899
if (!state.game.pickedDice[i]) {
@@ -120,8 +131,8 @@ export const createGameWorld = () => {
120131
body.applyImpulse(force, impulsePoint);
121132
}
122133

123-
// TODO: reset crumbled position
124-
// or actually just rotate, because it's costly to recompute
134+
// generate new crumbled position (kind of)
135+
assignCrumbledPosition();
125136

126137
state.pull.x = state.pull.v = state.pull.target = 0;
127138
state.throw.x = state.throw.v = state.throw.target = 0;
@@ -163,16 +174,21 @@ export const createGameWorld = () => {
163174

164175
const step = (dt: number) => {
165176
if (!state.game.roll.some(isBlank)) {
166-
world.step(PHYSIC_DT);
177+
world.step(dt * 5);
167178

168179
for (const o of state.dices) {
169180
if (!isBodySleeping(o.physical)) o.stepSinceImmobile = 0;
170181
else o.stepSinceImmobile++;
171182
}
172183

173-
const roll = state.dices.map(({ physical, stepSinceImmobile }) =>
174-
stepSinceImmobile > 6 ? getDiceUpFace(physical.quaternion) : "rolling"
175-
);
184+
const roll = state.dices.map(({ physical, stepSinceImmobile }, i) => {
185+
if (stepSinceImmobile < 6) {
186+
if (isDiceValue(state.game.roll[i])) return state.game.roll[i];
187+
return "rolling";
188+
}
189+
190+
return getDiceUpFace(physical.quaternion);
191+
});
176192

177193
state.game = setRoll(state.game, roll);
178194
}

src/gameRules/__tests__/game.spec.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import {
88
import { it, expect } from "bun:test";
99

1010
it("should play game", () => {
11-
let game = createEmptyGame();
11+
let game = createEmptyGame(5);
1212
expect(game.roll).toEqual(["blank", "blank", "blank", "blank", "blank"]);
1313

1414
game = startRolling(game);
@@ -27,6 +27,6 @@ it("should play game", () => {
2727
});
2828

2929
it("should guard against rolling if nothing is picked", () => {
30-
const game = setRoll(createEmptyGame(), [1, 2, 3, 2, 4]);
30+
const game = setRoll(createEmptyGame(5), [1, 2, 3, 2, 4]);
3131
expect(game).toBe(startRolling(game));
3232
});

src/gameRules/game.ts

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -29,9 +29,14 @@ export const isBlank = (d: DiceValue | "rolling" | "blank"): d is "blank" =>
2929
export const isRollReady = (roll: Game["roll"]) => roll.every(isDiceValue);
3030

3131
export const setRoll = (game: Game, roll: (DiceValue | "rolling")[]): Game => {
32-
if (!arrayEquals(game.roll, roll)) return { ...game, roll };
33-
return game;
32+
if (game.roll.some(isBlank)) return game;
33+
if (game.roll.some((dice, i) => isDiceValue(dice) && isRolling(roll[i])))
34+
return game;
35+
36+
if (arrayEquals(game.roll, roll)) return game;
37+
return { ...game, roll };
3438
};
39+
3540
export const togglePickedDice = (game: Game, diceIndex: number): Game => {
3641
// forbid to pick a dice without value
3742
if (!isDiceValue(game.roll[diceIndex])) return game;
@@ -68,12 +73,10 @@ export const selectCategoryForDiceRoll = (
6873

6974
return {
7075
...game,
71-
pickedDice: Object.fromEntries(
72-
Array.from({ length: nDice }, (_, i) => [i, true])
73-
),
76+
pickedDice: Object.fromEntries(game.roll.map((_, i) => [i, true])),
7477
scoreSheet,
7578
remainingReRoll: nReroll,
76-
roll: Array.from({ length: nDice }, () => "blank"),
79+
roll: game.roll.map(() => "blank"),
7780
};
7881
};
7982

@@ -98,7 +101,7 @@ export const startRolling = (game: Game): Game => {
98101
return { ...game, pickedDice: {}, roll };
99102
};
100103

101-
export const createEmptyGame = (): Game => ({
104+
export const createEmptyGame = (nDice: number): Game => ({
102105
scoreSheet: createEmptyScoreSheet(),
103106
pickedDice: Object.fromEntries(
104107
Array.from({ length: nDice }, (_, i) => [i, true])

0 commit comments

Comments
 (0)