Improve UI
This commit is contained in:
parent
793d9a81e8
commit
3848e460cd
5 changed files with 289 additions and 5 deletions
105
frontend/src/scripts/tutorial.ts
Normal file
105
frontend/src/scripts/tutorial.ts
Normal file
|
|
@ -0,0 +1,105 @@
|
|||
import { vec2 } from 'gl-matrix';
|
||||
import {
|
||||
CharacterTeam,
|
||||
CommandExecutors,
|
||||
CommandReceiver,
|
||||
Id,
|
||||
MoveActionCommand,
|
||||
PrimaryActionCommand,
|
||||
} from 'shared';
|
||||
import { GameObjectContainer } from './objects/game-object-container';
|
||||
import { PlanetView } from './objects/types/planet-view';
|
||||
|
||||
type StageTrigger = 'move' | 'shoot' | 'capture';
|
||||
|
||||
const stages: ReadonlyArray<{ hint: string; clearsOn: StageTrigger }> = [
|
||||
{ hint: 'WASD / drag to walk', clearsOn: 'move' },
|
||||
{ hint: 'Click / tap to shoot', clearsOn: 'shoot' },
|
||||
{ hint: 'Stand on a planet to capture it', clearsOn: 'capture' },
|
||||
];
|
||||
|
||||
const captureProgressThreshold = 0.05;
|
||||
|
||||
const standingSlack = 200;
|
||||
|
||||
export class Tutorial extends CommandReceiver {
|
||||
private stage = 0;
|
||||
private element = document.createElement('div');
|
||||
|
||||
private characterId?: Id;
|
||||
|
||||
private standingPlanet?: PlanetView;
|
||||
private standingBaseline = 0;
|
||||
|
||||
protected commandExecutors: CommandExecutors = {
|
||||
[MoveActionCommand.type]: (c: MoveActionCommand) => {
|
||||
if (this.clearsOn() === 'move' && vec2.length(c.direction) > 0) {
|
||||
this.advance();
|
||||
}
|
||||
},
|
||||
[PrimaryActionCommand.type]: () => {
|
||||
if (this.clearsOn() === 'shoot') {
|
||||
this.advance();
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
constructor(overlay: HTMLElement) {
|
||||
super();
|
||||
this.element.className = 'tutorial-hint';
|
||||
this.element.innerText = stages[0].hint;
|
||||
overlay.appendChild(this.element);
|
||||
}
|
||||
|
||||
private clearsOn(): StageTrigger | undefined {
|
||||
return stages[this.stage]?.clearsOn;
|
||||
}
|
||||
|
||||
private advance() {
|
||||
this.setStage(this.stage + 1);
|
||||
}
|
||||
|
||||
public step(gameObjects: GameObjectContainer) {
|
||||
if (this.stage >= stages.length) {
|
||||
return;
|
||||
}
|
||||
|
||||
const player = gameObjects.player;
|
||||
if (!player) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.characterId === undefined) {
|
||||
this.characterId = player.id;
|
||||
} else if (player.id !== this.characterId) {
|
||||
this.finish();
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.clearsOn() === 'capture') {
|
||||
const standing = gameObjects.planets.find(
|
||||
(p) => vec2.distance(p.center, player.bodyCenter) < p.radius + standingSlack,
|
||||
);
|
||||
if (standing !== this.standingPlanet) {
|
||||
this.standingPlanet = standing;
|
||||
this.standingBaseline = standing?.ownership ?? 0;
|
||||
}
|
||||
if (standing) {
|
||||
const drift = standing.ownership - this.standingBaseline;
|
||||
const progress = player.team === CharacterTeam.decla ? -drift : drift;
|
||||
if (progress > captureProgressThreshold) {
|
||||
this.finish();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private finish() {
|
||||
this.setStage(stages.length);
|
||||
}
|
||||
|
||||
private setStage(stage: number) {
|
||||
this.stage = stage;
|
||||
this.element.innerText = stages[stage]?.hint ?? '';
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue