claude
This commit is contained in:
parent
47603c058e
commit
c074bc2645
15 changed files with 178 additions and 148 deletions
|
|
@ -1,5 +1,5 @@
|
|||
import { chargeHeldSince } from 'shared';
|
||||
import { pointer } from './helper/pointer';
|
||||
import { getDisplayPosition } from './helper/pointer';
|
||||
|
||||
let element: HTMLElement | undefined;
|
||||
let heldSince = 0;
|
||||
|
|
@ -42,7 +42,7 @@ function updateChargeIndicator() {
|
|||
element.classList.toggle('full', charge >= 1);
|
||||
|
||||
if (isFollowingPointer) {
|
||||
const cursor = pointer.displayPosition;
|
||||
const cursor = getDisplayPosition();
|
||||
if (cursor) {
|
||||
element.style.left = `${cursor[0]}px`;
|
||||
element.style.top = `${cursor[1]}px`;
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ import {
|
|||
localCharacterPredictor,
|
||||
} from '../helper/prediction/local-character-predictor';
|
||||
|
||||
export abstract class InputGenerator {
|
||||
export class InputGenerator {
|
||||
constructor(protected readonly onCommand: (command: Command) => void) {}
|
||||
|
||||
protected sendMove(direction: vec2) {
|
||||
|
|
|
|||
|
|
@ -1,10 +1,11 @@
|
|||
import { vec2 } from 'gl-matrix';
|
||||
import type { Command } from 'shared';
|
||||
import { InputGenerator } from './input-generator';
|
||||
|
||||
export class KeyboardListener extends InputGenerator {
|
||||
private keysDown: Set<string> = new Set();
|
||||
|
||||
constructor(onCommand: ConstructorParameters<typeof InputGenerator>[0]) {
|
||||
constructor(onCommand: (command: Command) => void) {
|
||||
super(onCommand);
|
||||
addEventListener('keydown', this.keyDownListener);
|
||||
addEventListener('keyup', this.keyUpListener);
|
||||
|
|
|
|||
|
|
@ -1,8 +1,9 @@
|
|||
import { vec2 } from 'gl-matrix';
|
||||
import { chargeHeldSince, Command } from 'shared';
|
||||
import { Game } from '../game';
|
||||
import { chargeHeldSince } from 'shared';
|
||||
import type { Command } from 'shared';
|
||||
import type { Game } from '../game';
|
||||
import { ChargeIndicator } from '../charge-indicator';
|
||||
import { pointer } from '../helper/pointer';
|
||||
import { setDisplayPosition } from '../helper/pointer';
|
||||
import { InputGenerator } from './input-generator';
|
||||
|
||||
export class MouseListener extends InputGenerator {
|
||||
|
|
@ -22,7 +23,7 @@ export class MouseListener extends InputGenerator {
|
|||
}
|
||||
|
||||
private mouseMoveListener = (event: MouseEvent) => {
|
||||
pointer.displayPosition = vec2.fromValues(event.clientX, event.clientY);
|
||||
setDisplayPosition(vec2.fromValues(event.clientX, event.clientY));
|
||||
};
|
||||
|
||||
private mouseDownListener = (event: MouseEvent) => {
|
||||
|
|
|
|||
|
|
@ -1,7 +1,9 @@
|
|||
import { vec2 } from 'gl-matrix';
|
||||
import { chargeHeldSince, Command, settings } from 'shared';
|
||||
import { Game } from '../game';
|
||||
import { chargeHeldSince, settings } from 'shared';
|
||||
import type { Command } from 'shared';
|
||||
import type { Game } from '../game';
|
||||
import { ChargeIndicator } from '../charge-indicator';
|
||||
import { centeredTransform } from '../helper/centered-transform';
|
||||
import { InputGenerator } from './input-generator';
|
||||
|
||||
const deadZone = 8;
|
||||
|
|
@ -104,11 +106,14 @@ export class TouchListener extends InputGenerator {
|
|||
this.primaryDownAt = null;
|
||||
ChargeIndicator.end();
|
||||
this.overlay.appendChild(this.joystick);
|
||||
this.joystick.style.transform = `translateX(${this.touchStartPosition[0]}px) translateY(${this.touchStartPosition[1]}px) translateX(-50%) translateY(-50%)`;
|
||||
this.joystick.style.transform = centeredTransform(
|
||||
this.touchStartPosition[0],
|
||||
this.touchStartPosition[1],
|
||||
);
|
||||
}
|
||||
|
||||
vec2.scale(delta, delta, Math.min(1, joystickMaxLength / deltaLength));
|
||||
this.joystickButton.style.transform = `translateX(${delta[0]}px) translateY(${delta[1]}px) translateX(-50%) translateY(-50%)`;
|
||||
this.joystickButton.style.transform = centeredTransform(delta[0], delta[1]);
|
||||
|
||||
if (deltaLength > deadZone) {
|
||||
vec2.set(delta, delta[0], -delta[1]);
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import { settings } from 'shared';
|
||||
import { pointer } from './helper/pointer';
|
||||
import { getDisplayPosition } from './helper/pointer';
|
||||
|
||||
let root: HTMLElement | undefined;
|
||||
let killfeed: HTMLElement | undefined;
|
||||
|
|
@ -20,7 +20,7 @@ function ensureRoot(): { root: HTMLElement; killfeed: HTMLElement } {
|
|||
}
|
||||
|
||||
function focusPoint(): { x: number; y: number } {
|
||||
const cursor = pointer.displayPosition;
|
||||
const cursor = getDisplayPosition();
|
||||
if (cursor) {
|
||||
return { x: cursor[0], y: cursor[1] };
|
||||
}
|
||||
|
|
|
|||
|
|
@ -34,6 +34,7 @@ import parser from 'socket.io-msgpack-parser';
|
|||
import { CharacterShape } from './shapes/character-shape';
|
||||
import { PlanetShape } from './shapes/planet-shape';
|
||||
import { serverTimeline } from './helper/server-timeline';
|
||||
import { centeredTransform } from './helper/centered-transform';
|
||||
import {
|
||||
localCharacterPredictor,
|
||||
setFrameTimeMs,
|
||||
|
|
@ -79,21 +80,21 @@ export class Game extends CommandReceiver {
|
|||
private framesSinceLastLayoutUpdate = 0;
|
||||
|
||||
protected commandExecutors: CommandExecutors = {
|
||||
[ServerAnnouncement.type]: (c: ServerAnnouncement) => {
|
||||
[ServerAnnouncement.name]: (c: ServerAnnouncement) => {
|
||||
this.lastAnnouncementText = c.text;
|
||||
this.timeSinceLastAnnouncement = 0;
|
||||
},
|
||||
[UpdateGameState.type]: (c: UpdateGameState) => (this.lastGameState = c),
|
||||
[InputAcknowledgement.type]: (c: InputAcknowledgement) =>
|
||||
[UpdateGameState.name]: (c: UpdateGameState) => (this.lastGameState = c),
|
||||
[InputAcknowledgement.name]: (c: InputAcknowledgement) =>
|
||||
localCharacterPredictor.acknowledge(
|
||||
c.clientTimeMs,
|
||||
c.movement,
|
||||
c.lastLeapClientTimeMs,
|
||||
c.ackAgeMs,
|
||||
),
|
||||
[GameEndCommand.type]: () => (this.isEnding = true),
|
||||
[UpdateMinimap.type]: (c: UpdateMinimap) => (this.lastMinimap = c),
|
||||
[GameStartCommand.type]: () => this.initialize(),
|
||||
[GameEndCommand.name]: () => (this.isEnding = true),
|
||||
[UpdateMinimap.name]: (c: UpdateMinimap) => (this.lastMinimap = c),
|
||||
[GameStartCommand.name]: () => this.initialize(),
|
||||
};
|
||||
|
||||
constructor(
|
||||
|
|
@ -220,6 +221,7 @@ export class Game extends CommandReceiver {
|
|||
|
||||
public async start(): Promise<void> {
|
||||
this.initialize();
|
||||
this.resolveStarted();
|
||||
const noiseTexture = await renderNoise([256, 256], 2, 1);
|
||||
|
||||
await runAnimation(
|
||||
|
|
@ -311,7 +313,6 @@ export class Game extends CommandReceiver {
|
|||
deltaTime: DOMHighResTimeStamp,
|
||||
): boolean {
|
||||
this.renderer = renderer;
|
||||
this.resolveStarted();
|
||||
// The frame timestamp, not performance.now(): dispatch jitter would land in the replay window.
|
||||
setFrameTimeMs(currentTime);
|
||||
deltaTime /= 1000;
|
||||
|
|
@ -408,6 +409,10 @@ export class Game extends CommandReceiver {
|
|||
deltaX = (deltaY * dx) / dy;
|
||||
}
|
||||
|
||||
this.keystoneArrow.style.transform = `translateX(${width / 2 + deltaX}px) translateY(${height / 2 + deltaY}px) translateX(-50%) translateY(-50%) rotate(${angle + Math.PI / 2}rad)`;
|
||||
this.keystoneArrow.style.transform = centeredTransform(
|
||||
width / 2 + deltaX,
|
||||
height / 2 + deltaY,
|
||||
` rotate(${angle + Math.PI / 2}rad)`,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
2
frontend/src/scripts/helper/centered-transform.ts
Normal file
2
frontend/src/scripts/helper/centered-transform.ts
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
export const centeredTransform = (x: number, y: number, extra = ''): string =>
|
||||
`translateX(${x}px) translateY(${y}px) translateX(-50%) translateY(-50%)${extra}`;
|
||||
|
|
@ -1,3 +1,9 @@
|
|||
import { vec2 } from 'gl-matrix';
|
||||
|
||||
export const pointer = { displayPosition: null as vec2 | null };
|
||||
let displayPosition: vec2 | null = null;
|
||||
|
||||
export const setDisplayPosition = (position: vec2): void => {
|
||||
displayPosition = position;
|
||||
};
|
||||
|
||||
export const getDisplayPosition = (): vec2 | null => displayPosition;
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ import {
|
|||
headRadius,
|
||||
} from 'shared';
|
||||
import { ClientCharacterWorld } from './client-character-world';
|
||||
import { PlanetView } from '../../objects/types/planet-view';
|
||||
import type { PlanetView } from '../../objects/types/planet-view';
|
||||
import { InputHistory } from './input-history';
|
||||
|
||||
const stepSeconds = settings.targetPhysicsDeltaTimeInSeconds;
|
||||
|
|
@ -32,7 +32,7 @@ const makeBody = (center: vec2, radius: number, normal: vec2): PhysicsBody => ({
|
|||
center: vec2.clone(center),
|
||||
radius,
|
||||
velocity: vec2.create(),
|
||||
lastNormal: vec2.fromValues(normal[0], normal[1]),
|
||||
lastNormal: vec2.clone(normal),
|
||||
restitution: 0,
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@ import {
|
|||
UpdatePropertyCommand,
|
||||
} from 'shared';
|
||||
import { FeedbackHud } from '../feedback-hud';
|
||||
import { Game } from '../game';
|
||||
import type { Game } from '../game';
|
||||
import { serverTimeline } from '../helper/server-timeline';
|
||||
import { localCharacterPredictor } from '../helper/prediction/local-character-predictor';
|
||||
import { Camera } from './types/camera';
|
||||
|
|
@ -36,7 +36,7 @@ export class GameObjectContainer extends CommandReceiver {
|
|||
private awaitingDeleteStamp: Array<Id> = [];
|
||||
|
||||
protected commandExecutors: CommandExecutors = {
|
||||
[CreatePlayerCommand.type]: (c: CreatePlayerCommand) => {
|
||||
[CreatePlayerCommand.name]: (c: CreatePlayerCommand) => {
|
||||
this.player = c.character as CharacterView;
|
||||
this.player.isMainCharacter = true;
|
||||
this.addObject(this.player);
|
||||
|
|
@ -45,18 +45,18 @@ export class GameObjectContainer extends CommandReceiver {
|
|||
this.wasLocalPlayerAlive = true;
|
||||
},
|
||||
|
||||
[CreateObjectsCommand.type]: (c: CreateObjectsCommand) =>
|
||||
[CreateObjectsCommand.name]: (c: CreateObjectsCommand) =>
|
||||
c.objects.forEach((o) => {
|
||||
this.addObject(o as View);
|
||||
this.awaitingCreateStamp.push(o.id);
|
||||
}),
|
||||
|
||||
[RemoteCallsForObjects.type]: (c: RemoteCallsForObjects) =>
|
||||
[RemoteCallsForObjects.name]: (c: RemoteCallsForObjects) =>
|
||||
c.callsForObjects.forEach((c) =>
|
||||
this.objects.get(c.id)?.processRemoteCalls(c.calls),
|
||||
),
|
||||
|
||||
[PropertyUpdatesForObjects.type]: (c: PropertyUpdatesForObjects) => {
|
||||
[PropertyUpdatesForObjects.name]: (c: PropertyUpdatesForObjects) => {
|
||||
serverTimeline.onSnapshot(c.timestamp);
|
||||
this.stampPending(c.timestamp);
|
||||
c.updates.forEach((u) => {
|
||||
|
|
@ -68,7 +68,7 @@ export class GameObjectContainer extends CommandReceiver {
|
|||
});
|
||||
},
|
||||
|
||||
[DeleteObjectsCommand.type]: (c: DeleteObjectsCommand) =>
|
||||
[DeleteObjectsCommand.name]: (c: DeleteObjectsCommand) =>
|
||||
c.ids.forEach((id: Id) => this.awaitingDeleteStamp.push(id)),
|
||||
};
|
||||
|
||||
|
|
@ -80,6 +80,7 @@ export class GameObjectContainer extends CommandReceiver {
|
|||
public reset() {
|
||||
this.objects.forEach((o) => o.beforeDestroy?.());
|
||||
this.objects.clear();
|
||||
this.player = undefined;
|
||||
this.planets = [];
|
||||
this.visibleFrom.clear();
|
||||
this.deleteAt.clear();
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
import { vec2 } from 'gl-matrix';
|
||||
import { Renderer } from 'sdf-2d';
|
||||
import { calculateViewArea, followVec2, mixRgb, settings } from 'shared';
|
||||
import { Game } from '../../game';
|
||||
import type { Game } from '../../game';
|
||||
import { ScreenShake } from '../../screen-shake';
|
||||
|
||||
const followSeconds = 0.08;
|
||||
|
|
|
|||
|
|
@ -13,9 +13,10 @@ import {
|
|||
strengthToCharge,
|
||||
UpdatePropertyCommand,
|
||||
} from 'shared';
|
||||
import { centeredTransform } from '../../helper/centered-transform';
|
||||
import { CircleInterpolator } from '../../helper/interpolators/circle-interpolator';
|
||||
import { LinearInterpolator } from '../../helper/interpolators/linear-interpolator';
|
||||
import { pointer } from '../../helper/pointer';
|
||||
import { getDisplayPosition } from '../../helper/pointer';
|
||||
import { CharacterShape } from '../../shapes/character-shape';
|
||||
import { SoundHandler, Sounds } from '../../sound-handler';
|
||||
import { VibrationHandler } from '../../vibration-handler';
|
||||
|
|
@ -264,7 +265,11 @@ export class CharacterView extends CharacterBase implements View {
|
|||
this.head.radius + 80,
|
||||
),
|
||||
);
|
||||
this.nameElement.style.transform = `translateX(${screenPosition[0]}px) translateY(${screenPosition[1]}px) translateX(-50%) translateY(-50%) rotate(-15deg)`;
|
||||
this.nameElement.style.transform = centeredTransform(
|
||||
screenPosition[0],
|
||||
screenPosition[1],
|
||||
' rotate(-15deg)',
|
||||
);
|
||||
this.healthElement.style.width =
|
||||
(50 * this.health) / settings.playerMaxHealth + 'px';
|
||||
this.chargeElement.style.width =
|
||||
|
|
@ -287,7 +292,7 @@ export class CharacterView extends CharacterBase implements View {
|
|||
}
|
||||
|
||||
private calculateGazeTarget(renderer: Renderer): vec2 {
|
||||
const cursor = pointer.displayPosition;
|
||||
const cursor = getDisplayPosition();
|
||||
if (this.isMainCharacter && cursor) {
|
||||
return renderer.displayToWorldCoordinates(cursor);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ import {
|
|||
CharacterTeam,
|
||||
settings,
|
||||
} from 'shared';
|
||||
import { centeredTransform } from '../../helper/centered-transform';
|
||||
import { LinearInterpolator } from '../../helper/interpolators/linear-interpolator';
|
||||
import { PlanetShape } from '../../shapes/planet-shape';
|
||||
import { View } from '../view';
|
||||
|
|
@ -118,7 +119,10 @@ export class PlanetView extends PlanetBase implements View {
|
|||
}
|
||||
|
||||
const screenPosition = renderer.worldToDisplayCoordinates(this.center);
|
||||
this.ownershipProgress.style.transform = `translateX(${screenPosition[0]}px) translateY(${screenPosition[1]}px) translateX(-50%) translateY(-50%)`;
|
||||
this.ownershipProgress.style.transform = centeredTransform(
|
||||
screenPosition[0],
|
||||
screenPosition[1],
|
||||
);
|
||||
|
||||
const gradient = this.getGradient();
|
||||
if (gradient !== this.lastGradient) {
|
||||
|
|
|
|||
|
|
@ -34,17 +34,17 @@ export class Tutorial extends CommandReceiver {
|
|||
private standingBaseline = 0;
|
||||
|
||||
protected commandExecutors: CommandExecutors = {
|
||||
[MoveActionCommand.type]: (c: MoveActionCommand) => {
|
||||
[MoveActionCommand.name]: (c: MoveActionCommand) => {
|
||||
if (this.clearsOn() === 'move' && vec2.length(c.direction) > 0) {
|
||||
this.advance();
|
||||
}
|
||||
},
|
||||
[PrimaryActionCommand.type]: () => {
|
||||
[PrimaryActionCommand.name]: () => {
|
||||
if (this.clearsOn() === 'shoot') {
|
||||
this.advance();
|
||||
}
|
||||
},
|
||||
[LeapActionCommand.type]: () => {
|
||||
[LeapActionCommand.name]: () => {
|
||||
if (this.clearsOn() === 'leap') {
|
||||
this.advance();
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue