save/load to localStorage
This commit is contained in:
parent
83f7154665
commit
9af9c7867a
|
|
@ -1,24 +1,44 @@
|
||||||
import { makeAutoObservable } from 'mobx';
|
import { makeAutoObservable } from 'mobx';
|
||||||
import { school } from './school';
|
import { Progress, ProgressDto } from './progress';
|
||||||
import { Progress } from './progress';
|
import { game } from './game';
|
||||||
|
|
||||||
|
export type CalendarDto = {
|
||||||
|
day: number,
|
||||||
|
progress: ProgressDto,
|
||||||
|
}
|
||||||
|
|
||||||
export class Calendar {
|
export class Calendar {
|
||||||
|
|
||||||
public day: number = 1;
|
public day: number = 1;
|
||||||
|
|
||||||
public progress = new Progress(24, 1, true, () => this.handleProgress());
|
public progress = new Progress(24, 1, true, this.handleProgress.bind(this));
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
makeAutoObservable(this);
|
makeAutoObservable(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
private handleProgress(): boolean {
|
private handleProgress(times: number): boolean {
|
||||||
this.day++;
|
this.day += times;
|
||||||
school.collectStudentGold();
|
game.school.collectStudentGold(times);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public get dayFraction(): number {
|
public get dayFraction(): number {
|
||||||
return Math.floor(this.progress.value);
|
return Math.floor(this.progress.value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public serialize(): CalendarDto {
|
||||||
|
return {
|
||||||
|
day: this.day,
|
||||||
|
progress: this.progress.serialize(),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public static deserialize(data: CalendarDto): Calendar {
|
||||||
|
const calendar = new Calendar();
|
||||||
|
|
||||||
|
calendar.progress = Progress.deserialize(data.progress, true, calendar.handleProgress.bind(calendar));
|
||||||
|
|
||||||
|
return calendar;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -0,0 +1,28 @@
|
||||||
|
import { makeAutoObservable } from 'mobx';
|
||||||
|
import { School, SchoolDto } from './school';
|
||||||
|
import { GameClock } from '../utils/gameClock';
|
||||||
|
|
||||||
|
export class Game {
|
||||||
|
|
||||||
|
public school = new School();
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
makeAutoObservable(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
public save(): void {
|
||||||
|
const data = this.school.serialize();
|
||||||
|
localStorage.setItem('save', JSON.stringify(data))
|
||||||
|
}
|
||||||
|
|
||||||
|
public load(): void {
|
||||||
|
const json = localStorage.getItem('save');
|
||||||
|
if (!json)
|
||||||
|
return;
|
||||||
|
|
||||||
|
const data: SchoolDto = JSON.parse(json);
|
||||||
|
this.school = School.deserialize(data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export const game = new Game();
|
||||||
|
|
@ -1,21 +1,39 @@
|
||||||
import { Progress } from './progress';
|
import { game } from './game';
|
||||||
import { school } from './school';
|
import { Progress, ProgressDto } from './progress';
|
||||||
import { IUnit } from './unit';
|
import { IUnit } from '../types/unit';
|
||||||
import { makeAutoObservable } from 'mobx';
|
import { makeAutoObservable } from 'mobx';
|
||||||
|
|
||||||
|
export type OwnerDto = {
|
||||||
|
progress: ProgressDto,
|
||||||
|
}
|
||||||
|
|
||||||
export class Owner implements IUnit {
|
export class Owner implements IUnit {
|
||||||
|
|
||||||
public readonly id = 'owner';
|
public readonly id = 'owner';
|
||||||
|
|
||||||
public progress = new Progress(2, 1, false, () => this.handleProgress());
|
public progress = new Progress(2, 1, false, this.handleProgress.bind(this));
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
makeAutoObservable(this);
|
makeAutoObservable(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
private handleProgress(): boolean {
|
private handleProgress(times: number): boolean {
|
||||||
school.addReputation(1);
|
game.school.addReputation(times);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public serialize(): OwnerDto {
|
||||||
|
return {
|
||||||
|
progress: this.progress.serialize(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static deserialize(data: OwnerDto): Owner {
|
||||||
|
const owner = new Owner();
|
||||||
|
|
||||||
|
owner.progress = Progress.deserialize(data.progress, false, owner.handleProgress.bind(owner));
|
||||||
|
|
||||||
|
return owner;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,11 @@
|
||||||
import { makeAutoObservable } from 'mobx';
|
import { makeAutoObservable } from 'mobx';
|
||||||
|
|
||||||
|
export type ProgressDto = {
|
||||||
|
length: number;
|
||||||
|
speed: number;
|
||||||
|
value: number;
|
||||||
|
}
|
||||||
|
|
||||||
export class Progress {
|
export class Progress {
|
||||||
|
|
||||||
public value: number = 0;
|
public value: number = 0;
|
||||||
|
|
@ -8,7 +14,7 @@ export class Progress {
|
||||||
public length: number,
|
public length: number,
|
||||||
public speed: number,
|
public speed: number,
|
||||||
public readonly autoRun: boolean,
|
public readonly autoRun: boolean,
|
||||||
private callback: () => boolean,
|
private callback: (times: number) => void,
|
||||||
) {
|
) {
|
||||||
makeAutoObservable(this);
|
makeAutoObservable(this);
|
||||||
}
|
}
|
||||||
|
|
@ -26,19 +32,49 @@ export class Progress {
|
||||||
}
|
}
|
||||||
|
|
||||||
public tick(time: number): void {
|
public tick(time: number): void {
|
||||||
if (this.isFull && this.autoRun) {
|
const newValue = this.value + time / this.speed;
|
||||||
this.run();
|
|
||||||
}
|
|
||||||
|
|
||||||
this.value = Math.min(this.length, this.value + time / this.speed);
|
if (this.autoRun) {
|
||||||
if (this.autoRun)
|
const rem = newValue % this.length;
|
||||||
this.run();
|
const times = (newValue - rem) / this.length;
|
||||||
|
this.value = rem;
|
||||||
|
|
||||||
|
if (times > 0)
|
||||||
|
this.run(times);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
this.value = Math.min(this.length, newValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
public run(): void {
|
private run(times: number): void {
|
||||||
|
this.callback(times)
|
||||||
|
}
|
||||||
|
|
||||||
|
public manualRun(): void {
|
||||||
|
if (this.autoRun)
|
||||||
|
return;
|
||||||
|
|
||||||
if (this.isFull) {
|
if (this.isFull) {
|
||||||
if (this.callback())
|
this.run(1)
|
||||||
this.reset();
|
this.reset();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public serialize(): ProgressDto {
|
||||||
|
return {
|
||||||
|
length: this.length,
|
||||||
|
speed: this.speed,
|
||||||
|
value: this.value,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public static deserialize(
|
||||||
|
data: ProgressDto,
|
||||||
|
autoRun: boolean,
|
||||||
|
callback: (times: number) => void,
|
||||||
|
): Progress {
|
||||||
|
const inst = new Progress(data.length, data.speed, autoRun, callback);
|
||||||
|
inst.value = data.value;
|
||||||
|
return inst;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,22 +1,34 @@
|
||||||
import { makeAutoObservable } from 'mobx';
|
import { makeAutoObservable } from 'mobx';
|
||||||
import { Owner } from './owner';
|
import { Owner, OwnerDto } from './owner';
|
||||||
import { Student } from './student';
|
import { Student, StudentDto } from './student';
|
||||||
import { IUnit } from './unit';
|
import { IUnit } from '../types/unit';
|
||||||
import { Upgrades } from './upgrades';
|
import { Upgrades } from './upgrades';
|
||||||
import { PartialResourceSet, ResourceSet } from '../types/resources';
|
import { PartialResourceSet, ResourceSet } from '../types/resources';
|
||||||
import { addResourceSets, fullResourceSet, mapResourceSet, multiplyResourceSet, roundResourceSet, subtractResourceSets } from '../utils/resources';
|
import { addResourceSets, fullResourceSet, multiplyResourceSet, roundResourceSet, subtractResourceSets } from '../utils/resources';
|
||||||
import { v7 as uuid } from 'uuid';
|
import { v7 as uuid } from 'uuid';
|
||||||
import { GameClock } from '../utils/gameClock';
|
import { GameClock } from '../utils/gameClock';
|
||||||
import { Calendar } from './calendar';
|
import { Calendar, CalendarDto } from './calendar';
|
||||||
import { getRandomHumanName } from '../utils/humanNames';
|
import { getRandomHumanName } from '../utils/humanNames';
|
||||||
|
import { Time as Time } from './time';
|
||||||
|
import { UpgradeDto } from './upgrade';
|
||||||
|
|
||||||
const resourceScale = 100;
|
const resourceScale = 100;
|
||||||
|
|
||||||
export class School {
|
export type SchoolDto = {
|
||||||
|
lastTime: number,
|
||||||
|
calendar: CalendarDto,
|
||||||
|
resources: ResourceSet,
|
||||||
|
units: {
|
||||||
|
owner: OwnerDto,
|
||||||
|
students: StudentDto[],
|
||||||
|
},
|
||||||
|
upgrades: UpgradeDto[],
|
||||||
|
}
|
||||||
|
|
||||||
public timeScale: number = 1;
|
export class School {
|
||||||
public tps: number = 0;
|
public tps: number = 0;
|
||||||
|
|
||||||
|
public time = new Time();
|
||||||
public calendar = new Calendar();
|
public calendar = new Calendar();
|
||||||
|
|
||||||
// units
|
// units
|
||||||
|
|
@ -38,7 +50,7 @@ export class School {
|
||||||
}
|
}
|
||||||
|
|
||||||
public tick(time: number) {
|
public tick(time: number) {
|
||||||
const scaledTime = time * this.timeScale;
|
const scaledTime = time;
|
||||||
|
|
||||||
this.calendar.progress.tick(scaledTime);
|
this.calendar.progress.tick(scaledTime);
|
||||||
|
|
||||||
|
|
@ -48,10 +60,6 @@ export class School {
|
||||||
this.tps = GameClock.tps;
|
this.tps = GameClock.tps;
|
||||||
}
|
}
|
||||||
|
|
||||||
public setTimeScale(value: number) {
|
|
||||||
this.timeScale = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
public get units(): IUnit[] {
|
public get units(): IUnit[] {
|
||||||
return [this.owner, ...this.students]
|
return [this.owner, ...this.students]
|
||||||
}
|
}
|
||||||
|
|
@ -81,9 +89,43 @@ export class School {
|
||||||
this.scaledResources = subtractResourceSets(this.scaledResources, multiplyResourceSet(resources, resourceScale));
|
this.scaledResources = subtractResourceSets(this.scaledResources, multiplyResourceSet(resources, resourceScale));
|
||||||
}
|
}
|
||||||
|
|
||||||
public collectStudentGold(): void {
|
public collectStudentGold(times: number): void {
|
||||||
this.addGold(this.students.length);
|
this.addGold(this.students.length * times);
|
||||||
|
}
|
||||||
|
|
||||||
|
public serialize(): SchoolDto {
|
||||||
|
return {
|
||||||
|
lastTime: GameClock.lastTime,
|
||||||
|
|
||||||
|
calendar: this.calendar.serialize(),
|
||||||
|
resources: this.scaledResources,
|
||||||
|
|
||||||
|
units: {
|
||||||
|
owner: this.owner.serialize(),
|
||||||
|
students: this.students.map((s) => s.serialize()),
|
||||||
|
},
|
||||||
|
|
||||||
|
upgrades: this.upgrades.allItems.map((up) => up.serialize()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static deserialize(data: SchoolDto): School {
|
||||||
|
const inst = new School();
|
||||||
|
|
||||||
|
GameClock.lastTime = data.lastTime;
|
||||||
|
|
||||||
|
inst.calendar = Calendar.deserialize(data.calendar);
|
||||||
|
inst.scaledResources = data.resources;
|
||||||
|
|
||||||
|
inst.owner = Owner.deserialize(data.units.owner);
|
||||||
|
inst.students = data.units.students.map((s) => Student.deserialize(s));
|
||||||
|
|
||||||
|
for (let up of inst.upgrades.allItems) {
|
||||||
|
let upgradeData = data.upgrades.find((u) => u.id === up.id);
|
||||||
|
if (upgradeData)
|
||||||
|
up.deserialize(upgradeData);
|
||||||
|
}
|
||||||
|
|
||||||
|
return inst;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export const school = new School();
|
|
||||||
|
|
|
||||||
|
|
@ -1,11 +1,18 @@
|
||||||
import { Progress } from './progress';
|
import { game } from './game';
|
||||||
import { school } from './school';
|
import { Progress, ProgressDto } from './progress';
|
||||||
import { IUnit } from './unit';
|
import { School } from './school';
|
||||||
|
import { IUnit } from '../types/unit';
|
||||||
import { makeAutoObservable } from 'mobx';
|
import { makeAutoObservable } from 'mobx';
|
||||||
|
|
||||||
|
export type StudentDto = {
|
||||||
|
id: string,
|
||||||
|
name: string,
|
||||||
|
progress: ProgressDto,
|
||||||
|
}
|
||||||
|
|
||||||
export class Student implements IUnit {
|
export class Student implements IUnit {
|
||||||
|
|
||||||
public progress = new Progress(10, 1, true, () => this.handleProgress());
|
public progress = new Progress(10, 1, true, this.handleProgress.bind(this));
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
public readonly id: string,
|
public readonly id: string,
|
||||||
|
|
@ -14,9 +21,25 @@ export class Student implements IUnit {
|
||||||
makeAutoObservable(this);
|
makeAutoObservable(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
private handleProgress(): boolean {
|
private handleProgress(times: number): boolean {
|
||||||
school.addReputation(0.1);
|
game.school.addReputation(0.1 * times);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public serialize(): StudentDto {
|
||||||
|
return {
|
||||||
|
id: this.id,
|
||||||
|
name: this.name,
|
||||||
|
progress: this.progress.serialize(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static deserialize(data: StudentDto): Student {
|
||||||
|
const student = new Student(data.id, data.name);
|
||||||
|
|
||||||
|
student.progress = Progress.deserialize(data.progress, true, student.handleProgress.bind(student));
|
||||||
|
|
||||||
|
return student;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,28 @@
|
||||||
|
import { makeAutoObservable } from 'mobx';
|
||||||
|
import { GameClock } from '../utils/gameClock';
|
||||||
|
|
||||||
|
export class Time {
|
||||||
|
|
||||||
|
public timeScale: number = 1;
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
makeAutoObservable(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
public setTimeScale(value: number) {
|
||||||
|
this.timeScale = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public get paused(): boolean {
|
||||||
|
GameClock.pausedSignal.reportObserved();
|
||||||
|
return GameClock.paused;
|
||||||
|
}
|
||||||
|
|
||||||
|
public pause() {
|
||||||
|
GameClock.pause();
|
||||||
|
}
|
||||||
|
|
||||||
|
public resume() {
|
||||||
|
GameClock.resume();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,9 +1,14 @@
|
||||||
import { UpgradePrefab } from "../prefabs/upgrades";
|
import { UpgradePrefab, upgrades } from "../prefabs/upgrades";
|
||||||
import { addResourceSets, fullResourceSet, isResourceSetGte } from "../utils/resources";
|
import { addResourceSets, fullResourceSet, isResourceSetGte } from "../utils/resources";
|
||||||
import { evalLevelValue } from "../utils/upgrades";
|
import { evalLevelValue } from "../utils/upgrades";
|
||||||
import { school } from "./school";
|
|
||||||
import { ResourceSet } from "../types/resources";
|
import { ResourceSet } from "../types/resources";
|
||||||
import { makeAutoObservable } from "mobx";
|
import { makeAutoObservable } from "mobx";
|
||||||
|
import { game } from "./game";
|
||||||
|
|
||||||
|
export type UpgradeDto = {
|
||||||
|
id: string,
|
||||||
|
level: number,
|
||||||
|
}
|
||||||
|
|
||||||
export class Upgrade {
|
export class Upgrade {
|
||||||
public readonly id: string;
|
public readonly id: string;
|
||||||
|
|
@ -83,20 +88,32 @@ export class Upgrade {
|
||||||
let cost = this.costToBuy;
|
let cost = this.costToBuy;
|
||||||
|
|
||||||
this.prefab.execute(this.level);
|
this.prefab.execute(this.level);
|
||||||
school.removeResources(cost);
|
game.school.removeResources(cost);
|
||||||
|
|
||||||
this.increaseLevel();
|
this.increaseLevel();
|
||||||
}
|
}
|
||||||
|
|
||||||
public isVisible(): boolean {
|
public isVisible(): boolean {
|
||||||
return isResourceSetGte(school.resources, this.costToView);
|
return isResourceSetGte(game.school.resources, this.costToView);
|
||||||
}
|
}
|
||||||
|
|
||||||
public isOpen(): boolean {
|
public isOpen(): boolean {
|
||||||
return isResourceSetGte(school.resources, this.costToOpen);
|
return isResourceSetGte(game.school.resources, this.costToOpen);
|
||||||
}
|
}
|
||||||
|
|
||||||
public isAffordable(): boolean {
|
public isAffordable(): boolean {
|
||||||
return isResourceSetGte(school.resources, this.costToBuy);
|
return isResourceSetGte(game.school.resources, this.costToBuy);
|
||||||
|
}
|
||||||
|
|
||||||
|
public serialize(): UpgradeDto {
|
||||||
|
return {
|
||||||
|
id: this.id,
|
||||||
|
level: this.level,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public deserialize(data: UpgradeDto): void {
|
||||||
|
|
||||||
|
this.level = data.level;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
import { school } from "../model/school";
|
import { game } from "../model/game";
|
||||||
import { PartialResourceSet, Resource } from "../types/resources";
|
import { PartialResourceSet, Resource } from "../types/resources";
|
||||||
import { LevelValue, MaybeLevelValue } from "../types/upgrades";
|
import { LevelValue, MaybeLevelValue } from "../types/upgrades";
|
||||||
import { fullResourceSet } from "../utils/resources";
|
import { fullResourceSet } from "../utils/resources";
|
||||||
|
|
@ -23,7 +23,7 @@ export const upgrades: UpgradePrefab[] = [
|
||||||
costToOpen: (level) => ({ reputation: 20 * (level / 10 + 1) }),
|
costToOpen: (level) => ({ reputation: 20 * (level / 10 + 1) }),
|
||||||
costToBuy: (level) => ({ gold: 10 }),
|
costToBuy: (level) => ({ gold: 10 }),
|
||||||
execute: (level) => {
|
execute: (level) => {
|
||||||
school.increaseStudentCount();
|
game.school.increaseStudentCount();
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
import { makeAutoObservable } from 'mobx';
|
import { makeAutoObservable } from 'mobx';
|
||||||
import { Progress } from './progress';
|
import { Progress } from '../model/progress';
|
||||||
|
|
||||||
export interface IUnit {
|
export interface IUnit {
|
||||||
get id(): string;
|
get id(): string;
|
||||||
|
|
@ -1,8 +1,13 @@
|
||||||
import { school } from "../model/school";
|
import { game } from "../model/game";
|
||||||
|
import { ExternalSignal } from "./mobx/externalSignal";
|
||||||
|
|
||||||
export class GameClock {
|
export class GameClock {
|
||||||
|
|
||||||
|
public static lastTime = 0;
|
||||||
private static frames = new Array<number>();
|
private static frames = new Array<number>();
|
||||||
|
public static paused: boolean = false;
|
||||||
|
|
||||||
|
public static readonly pausedSignal = new ExternalSignal('GameClock.paused');
|
||||||
|
|
||||||
// public static async start(): Promise<void> {
|
// public static async start(): Promise<void> {
|
||||||
// let lastTime = performance.now();
|
// let lastTime = performance.now();
|
||||||
|
|
@ -18,17 +23,18 @@ export class GameClock {
|
||||||
// }
|
// }
|
||||||
|
|
||||||
public static start(): void {
|
public static start(): void {
|
||||||
let lastTime = performance.now();
|
|
||||||
|
|
||||||
const loop = (now: number) => {
|
const loop = (now: number) => {
|
||||||
const delta = now - lastTime;
|
let delta = now - GameClock.lastTime;
|
||||||
lastTime = now;
|
GameClock.lastTime = now;
|
||||||
|
|
||||||
GameClock.frames.push(lastTime);
|
if (GameClock.paused)
|
||||||
while (GameClock.frames[0] < lastTime - 1000)
|
delta *= 0;
|
||||||
|
|
||||||
|
GameClock.frames.push(now);
|
||||||
|
while (GameClock.frames[0] < now - 1000)
|
||||||
GameClock.frames.shift();
|
GameClock.frames.shift();
|
||||||
|
|
||||||
school.tick(delta / 1000);
|
GameClock.tick(delta / 1000 * game.school.time.timeScale);
|
||||||
|
|
||||||
requestAnimationFrame(loop);
|
requestAnimationFrame(loop);
|
||||||
};
|
};
|
||||||
|
|
@ -36,6 +42,10 @@ export class GameClock {
|
||||||
requestAnimationFrame(loop);
|
requestAnimationFrame(loop);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static tick(time: number): void {
|
||||||
|
game.school.tick(time);
|
||||||
|
}
|
||||||
|
|
||||||
public static get tps(): number {
|
public static get tps(): number {
|
||||||
if (GameClock.frames.length < 2)
|
if (GameClock.frames.length < 2)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
@ -44,4 +54,21 @@ export class GameClock {
|
||||||
|
|
||||||
return Math.round(GameClock.frames.length / timeSpan * 1000);
|
return Math.round(GameClock.frames.length / timeSpan * 1000);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static skipTime(skipTime: number) {
|
||||||
|
if (skipTime < 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
GameClock.tick(skipTime);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static pause() {
|
||||||
|
GameClock.paused = true;
|
||||||
|
GameClock.pausedSignal.trigger();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static resume() {
|
||||||
|
GameClock.paused = false;
|
||||||
|
GameClock.pausedSignal.trigger();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,21 @@
|
||||||
|
import { createAtom, IAtom } from "mobx";
|
||||||
|
|
||||||
|
export class ExternalSignal {
|
||||||
|
private readonly atom: IAtom;
|
||||||
|
|
||||||
|
constructor(name: string) {
|
||||||
|
this.atom = createAtom(
|
||||||
|
name,
|
||||||
|
() => { }, // onBecomeObserved
|
||||||
|
() => { } // onBecomeUnobserved
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
reportObserved() {
|
||||||
|
this.atom.reportObserved();
|
||||||
|
}
|
||||||
|
|
||||||
|
trigger() {
|
||||||
|
this.atom.reportChanged();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,22 @@
|
||||||
|
import { observer } from "mobx-react-lite";
|
||||||
|
import { school } from "../model/school";
|
||||||
|
import { Student } from "../model/student";
|
||||||
|
import { Owner } from "../model/owner";
|
||||||
|
import { OwnerUnitView } from "./OwnerUnitView";
|
||||||
|
import { IUnit } from "../types/unit";
|
||||||
|
|
||||||
|
export const UnitListView = observer(function () {
|
||||||
|
|
||||||
|
function renderUnit(unit: IUnit) {
|
||||||
|
if (unit instanceof Owner)
|
||||||
|
return <OwnerUnitView unit={unit} />
|
||||||
|
// // else if (unit instanceof Student)
|
||||||
|
// // return StudentView({ unit });
|
||||||
|
else
|
||||||
|
return '???';
|
||||||
|
}
|
||||||
|
|
||||||
|
return <ul>{
|
||||||
|
school.units.map((unit) => <li className="unit" key={unit.id}>{renderUnit(unit)}</li>)
|
||||||
|
}</ul>
|
||||||
|
});
|
||||||
|
|
@ -1,27 +1,65 @@
|
||||||
import { observer } from "mobx-react-lite";
|
import { observer } from "mobx-react-lite";
|
||||||
import { school } from "../model/school";
|
import { ChangeEvent, useState } from "react";
|
||||||
import { ChangeEvent } from "react";
|
import { GameClock } from "../utils/gameClock";
|
||||||
|
import { game } from "../model/game";
|
||||||
|
|
||||||
export const DebugView = observer(function () {
|
export const DebugView = observer(function () {
|
||||||
|
|
||||||
|
const [skipTime, setSkipTime] = useState<number>(5);
|
||||||
|
|
||||||
function handleTimeScaleChange(event: ChangeEvent<HTMLInputElement>): void {
|
function handleTimeScaleChange(event: ChangeEvent<HTMLInputElement>): void {
|
||||||
school.setTimeScale(Number(event.target.value));
|
game.school.time.setTimeScale(Number(event.target.value));
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleSkipTime(): void {
|
||||||
|
GameClock.skipTime(skipTime);
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleSaveClick(): void {
|
||||||
|
game.save();
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleLoadClick(): void {
|
||||||
|
game.school.time.pause();
|
||||||
|
game.load();
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleTickClick(): void {
|
||||||
|
GameClock.pause();
|
||||||
|
GameClock.tick(0.1);
|
||||||
}
|
}
|
||||||
|
|
||||||
return <div className="debug">
|
return <div className="debug">
|
||||||
<div className="timeScale">
|
<div>
|
||||||
Масштаб времени
|
Время
|
||||||
<input
|
<div className="timeScale">
|
||||||
type="range"
|
Масштаб
|
||||||
min={0}
|
<input
|
||||||
max={1}
|
type="range"
|
||||||
step={0.1}
|
min={1}
|
||||||
value={school.timeScale}
|
max={100}
|
||||||
onChange={handleTimeScaleChange}
|
step={1}
|
||||||
style={{width: '100%'}}
|
value={game.school.time.timeScale}
|
||||||
/>
|
onChange={handleTimeScaleChange}
|
||||||
x{school.timeScale}
|
style={{ width: '100%' }}
|
||||||
|
/>
|
||||||
|
x{game.school.time.timeScale}
|
||||||
|
</div>
|
||||||
|
{
|
||||||
|
game.school.time.paused
|
||||||
|
? <button onClick={() => game.school.time.resume()}>|></button>
|
||||||
|
: <button onClick={() => game.school.time.pause()}>||</button>
|
||||||
|
}
|
||||||
|
<button onClick={handleSkipTime}>
|
||||||
|
<input type="number" value={skipTime} onChange={(e) => setSkipTime(Number(e.target.value))}></input>
|
||||||
|
Пропустить
|
||||||
|
</button>
|
||||||
|
<button onClick={handleTickClick}>Tick</button>
|
||||||
</div>
|
</div>
|
||||||
<div className="tps">TPS: {school.tps}</div>
|
<div>
|
||||||
|
<button onClick={handleSaveClick}>Save</button>
|
||||||
|
<button onClick={handleLoadClick}>Load</button>
|
||||||
|
</div>
|
||||||
|
<div className="tps">TPS: {game.school.tps}</div>
|
||||||
</div>
|
</div>
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,5 @@
|
||||||
import { observer } from "mobx-react-lite";
|
import { observer } from "mobx-react-lite";
|
||||||
import { Owner } from "../model/owner";
|
import { Owner } from "../model/owner";
|
||||||
import { school } from "../model/school";
|
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
unit: Owner;
|
unit: Owner;
|
||||||
|
|
@ -9,7 +8,7 @@ type Props = {
|
||||||
export const OwnerUnitView = observer(function ({ unit }: Props) {
|
export const OwnerUnitView = observer(function ({ unit }: Props) {
|
||||||
function handleButtonClick(): void {
|
function handleButtonClick(): void {
|
||||||
if (unit.progress.isFull) {
|
if (unit.progress.isFull) {
|
||||||
unit.progress.run();
|
unit.progress.manualRun();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,11 +1,11 @@
|
||||||
import { observer } from "mobx-react-lite";
|
import { observer } from "mobx-react-lite";
|
||||||
import { school } from "../model/school";
|
|
||||||
import { ResourceStringView } from "./ResourceStringView";
|
import { ResourceStringView } from "./ResourceStringView";
|
||||||
|
import { game } from "../model/game";
|
||||||
|
|
||||||
export const StatsView = observer(function () {
|
export const StatsView = observer(function () {
|
||||||
|
|
||||||
return <div className="stats">
|
return <div className="stats">
|
||||||
<ResourceStringView resources={school.resources} partial={false} />
|
<ResourceStringView resources={game.school.resources} partial={false} />
|
||||||
<div className="time">День {school.calendar.day} : { school.calendar.dayFraction }</div>
|
<div className="time">День {game.school.calendar.day} : { game.school.calendar.dayFraction }</div>
|
||||||
</div>
|
</div>
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,10 @@
|
||||||
import { observer } from "mobx-react-lite";
|
import { observer } from "mobx-react-lite";
|
||||||
import { school } from "../model/school";
|
|
||||||
import { Student } from "../model/student";
|
import { Student } from "../model/student";
|
||||||
import { Owner } from "../model/owner";
|
import { Owner } from "../model/owner";
|
||||||
import { OwnerUnitView } from "./OwnerUnitView";
|
import { OwnerUnitView } from "./OwnerUnitView";
|
||||||
import { IUnit } from "../model/unit";
|
import { IUnit } from "../types/unit";
|
||||||
import { StudentUnitView } from "./StudentUnitView";
|
import { StudentUnitView } from "./StudentUnitView";
|
||||||
|
import { game } from "../model/game";
|
||||||
|
|
||||||
export const UnitListView = observer(function () {
|
export const UnitListView = observer(function () {
|
||||||
|
|
||||||
|
|
@ -19,10 +19,10 @@ export const UnitListView = observer(function () {
|
||||||
|
|
||||||
return <div className="units">
|
return <div className="units">
|
||||||
<div className="owner">
|
<div className="owner">
|
||||||
<OwnerUnitView unit={school.owner} />
|
<OwnerUnitView unit={game.school.owner} />
|
||||||
</div>
|
</div>
|
||||||
<div className="students">
|
<div className="students">
|
||||||
{school.students.map((unit) => <StudentUnitView key={unit.id} unit={unit} />)}
|
{game.school.students.map((unit) => <StudentUnitView key={unit.id} unit={unit} />)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,10 @@
|
||||||
import { observer } from "mobx-react-lite";
|
import { observer } from "mobx-react-lite";
|
||||||
import { school } from "../model/school";
|
|
||||||
import { UpgradeView } from "./UpgradeView";
|
import { UpgradeView } from "./UpgradeView";
|
||||||
|
import { game } from "../model/game";
|
||||||
|
|
||||||
export const UpgradeListView = observer(function () {
|
export const UpgradeListView = observer(function () {
|
||||||
|
|
||||||
return <div className="upgrades">{
|
return <div className="upgrades">{
|
||||||
school.upgrades.visibleItems.map((upgrade) => <UpgradeView key={upgrade.id} upgrade={upgrade} />)
|
game.school.upgrades.visibleItems.map((upgrade) => <UpgradeView key={upgrade.id} upgrade={upgrade} />)
|
||||||
}</div>;
|
}</div>;
|
||||||
});
|
});
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue