mirror of
https://gitlab.com/lecarore/breakout71.git
synced 2025-04-20 04:05:06 -04:00
wip
This commit is contained in:
parent
b0d8827e09
commit
4fb4c97734
15 changed files with 4190 additions and 3754 deletions
|
@ -134,6 +134,11 @@ There's also an easy mode for kids (slower ball).
|
|||
- [colin] wormhole - the puck sometimes don't bounce the ball back up but teleports it to the top of the screen as if it fell through from bottom to top. higher levels reduce the times it takes to reload that effect
|
||||
- [colin] hitman - hit the marked brick for +5 combo. each level increases the combo you get for it.
|
||||
- [colin] sweet spot - place your puck directly below a moving spot at the top of the level to increase your combo
|
||||
- ball attracted by bricks of the color of the ball
|
||||
- ball avoids brick of wrong color
|
||||
- coins avoid ball of different color
|
||||
- colored coins only (coins should be of the color of the ball to count)
|
||||
|
||||
|
||||
# Balancing ideas
|
||||
|
||||
|
|
1256
dist/index.html
vendored
1256
dist/index.html
vendored
File diff suppressed because one or more lines are too long
269
dist/levels_editor.ef3c2e1a.js
vendored
269
dist/levels_editor.ef3c2e1a.js
vendored
File diff suppressed because one or more lines are too long
2
dist/levels_editor.ef3c2e1a.js.map
vendored
2
dist/levels_editor.ef3c2e1a.js.map
vendored
File diff suppressed because one or more lines are too long
7
jest.config.js
Normal file
7
jest.config.js
Normal file
|
@ -0,0 +1,7 @@
|
|||
/** @type {import('ts-jest').JestConfigWithTsJest} **/
|
||||
module.exports = {
|
||||
testEnvironment: "node",
|
||||
transform: {
|
||||
"^.+\.tsx?$": ["ts-jest",{}],
|
||||
},
|
||||
};
|
550
package-lock.json
generated
550
package-lock.json
generated
File diff suppressed because it is too large
Load diff
12
package.json
12
package.json
|
@ -6,8 +6,8 @@
|
|||
"start": "rm -rf .parcel-cache && run-p dev:*",
|
||||
"dev:game-fe": "parcel src/*.html --lazy --no-hmr",
|
||||
"dev:editor-be": "nodemon editserver.js --watch editserver.js",
|
||||
"dev:watch-tests": "jest watch",
|
||||
"build": "rm -f dist/* && parcel build src/index.html"
|
||||
"test": "jest --watch",
|
||||
"build": "npx jest && rm -f dist/* && parcel build src/index.html"
|
||||
},
|
||||
"browserslist": "since 2009",
|
||||
"author": "Renan LE CARO",
|
||||
|
@ -18,7 +18,7 @@
|
|||
"@types/react-dom": "^19.0.4",
|
||||
"body-parser": "^1.20.3",
|
||||
"express": "^4.21.2",
|
||||
"http-server": "^14.1.1",
|
||||
"http-server": "^14.1.1",
|
||||
"nodemon": "^3.1.9",
|
||||
"npm-run-all": "^4.1.5",
|
||||
"parcel": "^2.13.3",
|
||||
|
@ -26,5 +26,11 @@
|
|||
"react": "^19.0.0",
|
||||
"react-dom": "^19.0.0",
|
||||
"svgo": "^3.3.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/jest": "^29.5.14",
|
||||
"jest": "^29.7.0",
|
||||
"ts-jest": "^29.2.6",
|
||||
"typescript": "^5.8.2"
|
||||
}
|
||||
}
|
||||
|
|
5356
src/game.ts
5356
src/game.ts
File diff suppressed because it is too large
Load diff
19
src/game_utils.ts
Normal file
19
src/game_utils.ts
Normal file
|
@ -0,0 +1,19 @@
|
|||
|
||||
|
||||
export function getMajorityValue(arr: string[]): string {
|
||||
const count: { [k: string]: number } = {};
|
||||
arr.forEach((v) => (count[v] = (count[v] || 0) + 1));
|
||||
// Object.values inline polyfill
|
||||
const max = Math.max(...Object.keys(count).map((k) => count[k]));
|
||||
return sample(Object.keys(count).filter((k) => count[k] == max));
|
||||
}
|
||||
|
||||
|
||||
export function sample<T>(arr: T[]): T {
|
||||
return arr[Math.floor(arr.length * Math.random())];
|
||||
}
|
||||
|
||||
export function sumOfKeys(obj:{[key:string]:number} | undefined | null){
|
||||
if(!obj) return 0
|
||||
return Object.values(obj)?.reduce((a,b)=>a+b,0) ||0
|
||||
}
|
|
@ -1,12 +1,47 @@
|
|||
import {resizeLevel} from "./levels_editor_util";
|
||||
import {moveLevel, resizeLevel, setBrick} from "./levels_editor_util";
|
||||
|
||||
test('resizeLevel',()=>{
|
||||
const baseLevel = {
|
||||
name: '',
|
||||
bricks: 'AAAA',
|
||||
size: 2,
|
||||
svg: null,
|
||||
color: ''
|
||||
}
|
||||
describe('resizeLevel', () => {
|
||||
it('should expand levels', () => {
|
||||
expect(resizeLevel(baseLevel, 1)).toStrictEqual({bricks: 'AA_AA____', size: 3});
|
||||
})
|
||||
it('should shrink levels', () => {
|
||||
expect(resizeLevel(baseLevel, -1)).toStrictEqual({bricks: 'A', size: 1});
|
||||
})
|
||||
})
|
||||
|
||||
expect(resizeLevel({
|
||||
name:'',
|
||||
bricks:'AAAA',
|
||||
size:2,
|
||||
svg:null,
|
||||
color:''
|
||||
}, 1)).toBe({bricks:'AA_AA____',size:3});
|
||||
})
|
||||
describe('moveLevel', () => {
|
||||
|
||||
it('should do nothing when coords are 0/0', () => {
|
||||
expect(moveLevel(baseLevel, 0, 0)).toStrictEqual({bricks: 'AAAA'});
|
||||
})
|
||||
it('should move right', () => {
|
||||
expect(moveLevel(baseLevel, 1, 0)).toStrictEqual({bricks: '_A_A'});
|
||||
})
|
||||
it('should move left', () => {
|
||||
expect(moveLevel(baseLevel, -1, 0)).toStrictEqual({bricks: 'A_A_'});
|
||||
})
|
||||
it('should move up', () => {
|
||||
expect(moveLevel(baseLevel, 0, -1)).toStrictEqual({bricks: 'AA__'});
|
||||
})
|
||||
it('should move down', () => {
|
||||
expect(moveLevel(baseLevel, 0, 1)).toStrictEqual({bricks: '__AA'});
|
||||
})
|
||||
|
||||
})
|
||||
|
||||
|
||||
describe('setBrick', () => {
|
||||
it('should set the first brick', () => {
|
||||
expect(setBrick(baseLevel, 0, 'C')).toStrictEqual({bricks: 'CAAA'});
|
||||
})
|
||||
it('should any brick', () => {
|
||||
expect(setBrick(baseLevel, 2, 'C')).toStrictEqual({bricks: 'AACA'});
|
||||
})
|
||||
})
|
||||
|
|
|
@ -4,7 +4,7 @@ import _palette from './palette.json'
|
|||
import _allLevels from './levels.json'
|
||||
import {getLevelBackground, hashCode} from "./getLevelBackground";
|
||||
import {createRoot} from 'react-dom/client';
|
||||
import {useCallback, useState} from "react";
|
||||
import {useCallback, useEffect, useState} from "react";
|
||||
import {moveLevel, resizeLevel, setBrick} from "./levels_editor_util";
|
||||
|
||||
const backgrounds = _backgrounds as string[];
|
||||
|
@ -14,17 +14,6 @@ const palette = _palette as Palette;
|
|||
let allLevels = _allLevels as RawLevel[];
|
||||
|
||||
|
||||
function save() {
|
||||
return fetch('http://localhost:4400/src/levels.json', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'text/plain'
|
||||
},
|
||||
body: JSON.stringify(allLevels, null, 2)
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
function App() {
|
||||
|
||||
const [selected, setSelected] = useState('W')
|
||||
|
@ -33,12 +22,29 @@ function App() {
|
|||
const updateLevel = useCallback((index: number, change: Partial<RawLevel>) => {
|
||||
setLevels(list => list.map((l, li) => li === index ? {...l, ...change} : l))
|
||||
}, []);
|
||||
|
||||
const deleteLevel = useCallback((li: number) => {
|
||||
if (confirm('Delete level')) {
|
||||
allLevels = allLevels.filter((l, i) => i !== li)
|
||||
setLevels(allLevels.filter((l, i) => i !== li))
|
||||
}
|
||||
}, [])
|
||||
|
||||
useEffect(()=>{
|
||||
const timoutId= setTimeout(()=>{
|
||||
return fetch('http://localhost:4400/src/levels.json', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'text/plain'
|
||||
},
|
||||
body: JSON.stringify(levels, null, 2)
|
||||
});
|
||||
|
||||
},500)
|
||||
return ()=>clearTimeout(timoutId)
|
||||
},[levels])
|
||||
|
||||
|
||||
|
||||
return <div onMouseUp={() => setApplying('')} onMouseLeave={() => setApplying('')}>
|
||||
<div id={"levels"}>
|
||||
{
|
||||
|
|
|
@ -3,10 +3,10 @@ import {RawLevel} from "./types";
|
|||
export function resizeLevel(level: RawLevel, sizeDelta: number) {
|
||||
const {size, bricks} = level
|
||||
const newSize = Math.max(1, size + sizeDelta)
|
||||
const newBricks = new Array(newSize * newSize).fill('_')
|
||||
for (let x = 0; x < Math.min(size, newSize); x++) {
|
||||
for (let y = 0; y < Math.min(size, newSize); y++) {
|
||||
newBricks[y * newSize + x] = bricks.split('')[y * size + x] || '_'
|
||||
const newBricks = []
|
||||
for (let x = 0; x < newSize; x++) {
|
||||
for (let y = 0; y < newSize; y++) {
|
||||
newBricks[y * newSize + x] = brickAt(level, x, y )
|
||||
}
|
||||
}
|
||||
return {
|
||||
|
@ -15,12 +15,16 @@ export function resizeLevel(level: RawLevel, sizeDelta: number) {
|
|||
}
|
||||
}
|
||||
|
||||
export function brickAt(level:RawLevel, x:number,y:number){
|
||||
return x>=0 && x < level.size && y>= 0 && y< level.size && level.bricks.split('')[y * level.size + x] || '_'
|
||||
}
|
||||
|
||||
export function moveLevel(level: RawLevel, dx: number, dy: number) {
|
||||
const {size, bricks} = level
|
||||
const {size} = level
|
||||
const newBricks = new Array(size * size).fill('_')
|
||||
for (let x = 0; x < size; x++) {
|
||||
for (let y = 0; y < size; y++) {
|
||||
newBricks[y * size + x] = bricks.split('')[(y - dy) * size + (x - dx)] || '_'
|
||||
newBricks[y * size + x] = brickAt(level, x - dx, y - dy)
|
||||
}
|
||||
}
|
||||
return {
|
||||
|
@ -29,12 +33,15 @@ export function moveLevel(level: RawLevel, dx: number, dy: number) {
|
|||
}
|
||||
|
||||
export function setBrick(level: RawLevel, index: number, colorCode: string) {
|
||||
let bricksString = level.bricks.slice(0, level.size * level.size)
|
||||
|
||||
if (bricksString.length < level.size * level.size) {
|
||||
bricksString += '_'.repeat(level.size * level.size - bricksString.length)
|
||||
const {size} = level
|
||||
const newBricks=[]
|
||||
for (let x = 0; x < size; x++) {
|
||||
for (let y = 0; y < size; y++) {
|
||||
const brickIndex=y * size + x
|
||||
newBricks[brickIndex] = (brickIndex === index && colorCode ) || brickAt(level, x , y)
|
||||
}
|
||||
}
|
||||
return {
|
||||
bricks: newBricks.join('')
|
||||
}
|
||||
const bricks = bricksString.split('')
|
||||
bricks[index] = colorCode
|
||||
return {bricks: bricks.join('')}
|
||||
}
|
58
src/resetBalls.ts
Normal file
58
src/resetBalls.ts
Normal file
|
@ -0,0 +1,58 @@
|
|||
import {GameState} from "./types";
|
||||
import {getMajorityValue} from "./game_utils";
|
||||
|
||||
export function resetBalls(gameState: GameState) {
|
||||
const count = 1 + (gameState.perks?.multiball || 0);
|
||||
const perBall = gameState.puckWidth / (count + 1);
|
||||
gameState.balls = [];
|
||||
gameState.ballsColor = "#FFF";
|
||||
if (gameState.perks.picky_eater || gameState.perks.pierce_color) {
|
||||
gameState.ballsColor = getMajorityValue(gameState.bricks.filter((i) => i)) || "#FFF";
|
||||
}
|
||||
for (let i = 0; i < count; i++) {
|
||||
const x = gameState.puckPosition - gameState.puckWidth / 2 + perBall * (i + 1);
|
||||
const vx = Math.random() > 0.5 ? gameState.baseSpeed : -gameState.baseSpeed;
|
||||
|
||||
gameState.balls.push({
|
||||
x,
|
||||
previousX: x,
|
||||
y: gameState.gameZoneHeight - 1.5 * gameState.ballSize,
|
||||
previousY: gameState.gameZoneHeight - 1.5 * gameState.ballSize,
|
||||
vx,
|
||||
previousVX: vx,
|
||||
vy: -gameState.baseSpeed,
|
||||
previousVY: -gameState.baseSpeed,
|
||||
|
||||
sx: 0,
|
||||
sy: 0,
|
||||
sparks: 0,
|
||||
piercedSinceBounce: 0,
|
||||
hitSinceBounce: 0,
|
||||
hitItem: [],
|
||||
bouncesList: [],
|
||||
sapperUses: 0,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export function putBallsAtPuck(gameState: GameState) {
|
||||
// This reset could be abused to cheat quite easily
|
||||
const count = gameState.balls.length;
|
||||
const perBall = gameState.puckWidth / (count + 1);
|
||||
gameState.balls.forEach((ball, i) => {
|
||||
const x = gameState.puckPosition - gameState.puckWidth / 2 + perBall * (i + 1);
|
||||
ball.x = x;
|
||||
ball.previousX = x;
|
||||
ball.y = gameState.gameZoneHeight - 1.5 * gameState.ballSize;
|
||||
ball.previousY = ball.y;
|
||||
ball.vx = Math.random() > 0.5 ? gameState.baseSpeed : -gameState.baseSpeed;
|
||||
ball.previousVX = ball.vx;
|
||||
ball.vy = -gameState.baseSpeed;
|
||||
ball.previousVY = ball.vy;
|
||||
ball.sx = 0;
|
||||
ball.sy = 0;
|
||||
ball.hitItem = [];
|
||||
ball.hitSinceBounce = 0;
|
||||
ball.piercedSinceBounce = 0;
|
||||
});
|
||||
}
|
|
@ -1,8 +1,6 @@
|
|||
import {
|
||||
gameZoneWidthRoundedUp,
|
||||
gameState,
|
||||
isSettingOn,
|
||||
offsetX,
|
||||
offsetXRoundedDown,
|
||||
} from "./game";
|
||||
|
||||
export const sounds = {
|
||||
|
@ -160,7 +158,7 @@ function createExplosionSound(pan = 0.5) {
|
|||
function pixelsToPan(pan: number) {
|
||||
return Math.max(
|
||||
0,
|
||||
Math.min(1, (pan - offsetXRoundedDown) / gameZoneWidthRoundedUp),
|
||||
Math.min(1, (pan - gameState.offsetXRoundedDown) / gameState.gameZoneWidthRoundedUp),
|
||||
);
|
||||
}
|
||||
|
||||
|
|
284
src/types.d.ts
vendored
284
src/types.d.ts
vendored
|
@ -1,153 +1,231 @@
|
|||
import { rawUpgrades } from "./rawUpgrades";
|
||||
import {rawUpgrades} from "./rawUpgrades";
|
||||
|
||||
export type colorString = string;
|
||||
|
||||
export type RawLevel = {
|
||||
name: string;
|
||||
size: number;
|
||||
bricks: string;
|
||||
svg: number | null;
|
||||
color: string;
|
||||
name: string;
|
||||
size: number;
|
||||
bricks: string;
|
||||
svg: number | null;
|
||||
color: string;
|
||||
};
|
||||
export type Level = {
|
||||
name: string;
|
||||
size: number;
|
||||
bricks: colorString[];
|
||||
svg: string;
|
||||
color: string;
|
||||
threshold: number;
|
||||
sortKey: number;
|
||||
name: string;
|
||||
size: number;
|
||||
bricks: colorString[];
|
||||
svg: string;
|
||||
color: string;
|
||||
threshold: number;
|
||||
sortKey: number;
|
||||
};
|
||||
|
||||
export type Palette = { [k: string]: string };
|
||||
|
||||
export type Upgrade = {
|
||||
threshold: number;
|
||||
giftable: boolean;
|
||||
id: PerkId;
|
||||
name: string;
|
||||
icon: string;
|
||||
max: number;
|
||||
help: (lvl: number) => string;
|
||||
fullHelp: string;
|
||||
requires: PerkId | "";
|
||||
threshold: number;
|
||||
giftable: boolean;
|
||||
id: PerkId;
|
||||
name: string;
|
||||
icon: string;
|
||||
max: number;
|
||||
help: (lvl: number) => string;
|
||||
fullHelp: string;
|
||||
requires: PerkId | "";
|
||||
};
|
||||
|
||||
export type PerkId = (typeof rawUpgrades)[number]["id"];
|
||||
|
||||
declare global {
|
||||
interface Window {
|
||||
webkitAudioContext?: typeof AudioContext;
|
||||
}
|
||||
interface Window {
|
||||
webkitAudioContext?: typeof AudioContext;
|
||||
}
|
||||
|
||||
interface Document {
|
||||
webkitFullscreenEnabled?: boolean;
|
||||
webkitCancelFullScreen?: () => void;
|
||||
}
|
||||
interface Document {
|
||||
webkitFullscreenEnabled?: boolean;
|
||||
webkitCancelFullScreen?: () => void;
|
||||
}
|
||||
|
||||
interface Element {
|
||||
webkitRequestFullscreen: typeof Element.requestFullscreen;
|
||||
}
|
||||
interface Element {
|
||||
webkitRequestFullscreen: typeof Element.requestFullscreen;
|
||||
}
|
||||
|
||||
interface MediaStream {
|
||||
// https://devdoc.net/web/developer.mozilla.org/en-US/docs/Web/API/CanvasCaptureMediaStream.html
|
||||
// On firefox, the capture stream has the requestFrame option
|
||||
// instead of the track, go figure
|
||||
requestFrame?: () => void;
|
||||
}
|
||||
interface MediaStream {
|
||||
// https://devdoc.net/web/developer.mozilla.org/en-US/docs/Web/API/CanvasCaptureMediaStream.html
|
||||
// On firefox, the capture stream has the requestFrame option
|
||||
// instead of the track, go figure
|
||||
requestFrame?: () => void;
|
||||
}
|
||||
}
|
||||
|
||||
export type BallLike = {
|
||||
x: number;
|
||||
y: number;
|
||||
vx?: number;
|
||||
vy?: number;
|
||||
x: number;
|
||||
y: number;
|
||||
vx?: number;
|
||||
vy?: number;
|
||||
};
|
||||
|
||||
export type Coin = {
|
||||
points: number;
|
||||
color: colorString;
|
||||
x: number;
|
||||
y: number;
|
||||
previousX: number;
|
||||
previousY: number;
|
||||
vx: number;
|
||||
vy: number;
|
||||
sx: number;
|
||||
sy: number;
|
||||
a: number;
|
||||
sa: number;
|
||||
weight: number;
|
||||
destroyed?: boolean;
|
||||
coloredABrick?: boolean;
|
||||
points: number;
|
||||
color: colorString;
|
||||
x: number;
|
||||
y: number;
|
||||
previousX: number;
|
||||
previousY: number;
|
||||
vx: number;
|
||||
vy: number;
|
||||
sx: number;
|
||||
sy: number;
|
||||
a: number;
|
||||
sa: number;
|
||||
weight: number;
|
||||
destroyed?: boolean;
|
||||
coloredABrick?: boolean;
|
||||
};
|
||||
export type Ball = {
|
||||
x: number;
|
||||
previousX: number;
|
||||
y: number;
|
||||
previousY: number;
|
||||
vx: number;
|
||||
vy: number;
|
||||
previousVX: number;
|
||||
previousVY: number;
|
||||
sx: number;
|
||||
sy: number;
|
||||
sparks: number;
|
||||
piercedSinceBounce: number;
|
||||
hitSinceBounce: number;
|
||||
hitItem: { index: number; color: string }[];
|
||||
bouncesList: { x: number; y: number }[];
|
||||
sapperUses: number;
|
||||
destroyed?: boolean;
|
||||
x: number;
|
||||
previousX: number;
|
||||
y: number;
|
||||
previousY: number;
|
||||
vx: number;
|
||||
vy: number;
|
||||
previousVX: number;
|
||||
previousVY: number;
|
||||
sx: number;
|
||||
sy: number;
|
||||
sparks: number;
|
||||
piercedSinceBounce: number;
|
||||
hitSinceBounce: number;
|
||||
hitItem: { index: number; color: string }[];
|
||||
bouncesList: { x: number; y: number }[];
|
||||
sapperUses: number;
|
||||
destroyed?: boolean;
|
||||
};
|
||||
|
||||
interface BaseFlash {
|
||||
time: number;
|
||||
color: colorString;
|
||||
duration: number;
|
||||
size: number;
|
||||
destroyed?: boolean;
|
||||
x: number;
|
||||
y: number;
|
||||
time: number;
|
||||
color: colorString;
|
||||
duration: number;
|
||||
size: number;
|
||||
destroyed?: boolean;
|
||||
x: number;
|
||||
y: number;
|
||||
}
|
||||
|
||||
interface ParticleFlash extends BaseFlash {
|
||||
type: "particle";
|
||||
vx: number;
|
||||
vy: number;
|
||||
ethereal: boolean;
|
||||
type: "particle";
|
||||
vx: number;
|
||||
vy: number;
|
||||
ethereal: boolean;
|
||||
}
|
||||
|
||||
interface TextFlash extends BaseFlash {
|
||||
type: "text";
|
||||
text: string;
|
||||
type: "text";
|
||||
text: string;
|
||||
}
|
||||
|
||||
interface BallFlash extends BaseFlash {
|
||||
type: "ball";
|
||||
type: "ball";
|
||||
}
|
||||
|
||||
export type Flash = ParticleFlash | TextFlash | BallFlash;
|
||||
|
||||
export type RunStats = {
|
||||
started: number;
|
||||
levelsPlayed: number;
|
||||
runTime: number;
|
||||
coins_spawned: number;
|
||||
score: number;
|
||||
bricks_broken: number;
|
||||
misses: number;
|
||||
balls_lost: number;
|
||||
puck_bounces: number;
|
||||
upgrades_picked: number;
|
||||
max_combo: number;
|
||||
max_level: number;
|
||||
started: number;
|
||||
levelsPlayed: number;
|
||||
runTime: number;
|
||||
coins_spawned: number;
|
||||
score: number;
|
||||
bricks_broken: number;
|
||||
misses: number;
|
||||
balls_lost: number;
|
||||
puck_bounces: number;
|
||||
upgrades_picked: number;
|
||||
max_combo: number;
|
||||
max_level: number;
|
||||
};
|
||||
|
||||
export type PerksMap = {
|
||||
[k in PerkId]: number;
|
||||
[k in PerkId]: number;
|
||||
};
|
||||
|
||||
export type RunHistoryItem = RunStats & {
|
||||
perks?: PerksMap;
|
||||
appVersion?: string;
|
||||
perks?: PerksMap;
|
||||
appVersion?: string;
|
||||
};
|
||||
export type GameState = {
|
||||
// Width of the canvas element in pixels
|
||||
canvasWidth: number;
|
||||
// Height of the canvas element in pixels
|
||||
canvasHeight: number;
|
||||
// Distance between the left of the canvas and the left of the leftmost brick, in pixels
|
||||
offsetX: number;
|
||||
// Distance between the left of the canvas and the left border of the game area, in pixels.
|
||||
// Can be 0 when no border is shown
|
||||
offsetXRoundedDown: number;
|
||||
// Width of the bricks area, in pixels
|
||||
gameZoneWidth: number;
|
||||
// Width of the game area between the left and right borders, in pixels
|
||||
gameZoneWidthRoundedUp: number;
|
||||
// Height of the play area, between the top of the canvas and the bottom of the puck.
|
||||
// Does not include the finger zone on mobile.
|
||||
gameZoneHeight: number;
|
||||
// Size of one brick in pixels
|
||||
brickWidth: number;
|
||||
// Size of the current level's grid
|
||||
gridSize: number;
|
||||
// 0 based index of the current level in the run (level X / 7)
|
||||
currentLevel: number;
|
||||
|
||||
// 10 levels selected randomly at start for the run
|
||||
runLevels: Level[];
|
||||
// Width of the puck in pixels, changed by some perks and resizes
|
||||
puckWidth: number;
|
||||
// perks the user currently has
|
||||
perks: PerksMap;
|
||||
// Base speed of the ball in pixels/tick
|
||||
baseSpeed: number;
|
||||
// Score multiplier
|
||||
combo: number;
|
||||
// Whether the game is running or paused
|
||||
running: boolean;
|
||||
// Position of the center of the puck on the canvas in pixels, from the left of the canvas.
|
||||
puckPosition: number;
|
||||
// Will be set if the game is about to be paused. Game pause is delayed by a few milliseconds if you pause a few times in a run,
|
||||
// to avoid abuse of the "release to pause" feature on mobile.
|
||||
pauseTimeout: NodeJS.Timeout | null;
|
||||
// Whether the game should be rendered at the next tick, even if the game is paused
|
||||
needsRender: boolean;
|
||||
// Current run score
|
||||
score: number;
|
||||
// levelTime of the last explosion, for screen shake
|
||||
lastExplosion: number;
|
||||
// High score at the beginning of the run
|
||||
highScore: number;
|
||||
// Balls currently in game, game over if it's empty
|
||||
balls: Ball[];
|
||||
// Color of the balls, can be changed by some perks
|
||||
ballsColor: colorString;
|
||||
// Array of bricks to display. 'black' means bomb. '' means no brick.
|
||||
bricks: colorString[];
|
||||
|
||||
flashes: Flash[];
|
||||
coins: Coin[];
|
||||
levelStartScore: number;
|
||||
levelMisses: number;
|
||||
levelSpawnedCoins: number;
|
||||
lastPlayedCoinGrab: number;
|
||||
|
||||
MAX_COINS: number;
|
||||
MAX_PARTICLES: number;
|
||||
puckColor: colorString;
|
||||
ballSize: number;
|
||||
coinSize: number;
|
||||
puckHeight: number;
|
||||
totalScoreAtRunStart: number;
|
||||
}
|
||||
|
||||
export type RunParams={
|
||||
level?: string;
|
||||
levelToAvoid?:string;
|
||||
perks?:Partial<PerksMap>
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue