Improve gameplay and design
This commit is contained in:
parent
af616042f3
commit
1d1bc6655c
15 changed files with 163 additions and 74 deletions
|
|
@ -155,20 +155,13 @@ export class PlayerCharacterPhysical
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const start = vec2.clone(this.center);
|
const direction = vec2.subtract(vec2.create(), position, this.center);
|
||||||
const direction = vec2.subtract(vec2.create(), position, start);
|
|
||||||
vec2.normalize(direction, direction);
|
vec2.normalize(direction, direction);
|
||||||
vec2.add(
|
|
||||||
start,
|
|
||||||
start,
|
|
||||||
vec2.scale(vec2.create(), direction, settings.projectileStartOffset),
|
|
||||||
);
|
|
||||||
const velocity = vec2.scale(direction, direction, settings.projectileSpeed);
|
const velocity = vec2.scale(direction, direction, settings.projectileSpeed);
|
||||||
vec2.add(velocity, velocity, this.velocity);
|
|
||||||
const strength = this.projectileStrength / 2;
|
const strength = this.projectileStrength / 2;
|
||||||
this.projectileStrength -= strength;
|
this.projectileStrength -= strength;
|
||||||
const projectile = new ProjectilePhysical(
|
const projectile = new ProjectilePhysical(
|
||||||
start,
|
vec2.clone(this.center),
|
||||||
20,
|
20,
|
||||||
this.colorIndex,
|
this.colorIndex,
|
||||||
strength,
|
strength,
|
||||||
|
|
@ -192,10 +185,6 @@ export class PlayerCharacterPhysical
|
||||||
return this.head.center;
|
return this.head.center;
|
||||||
}
|
}
|
||||||
|
|
||||||
public get velocity(): vec2 {
|
|
||||||
return this.head.velocity;
|
|
||||||
}
|
|
||||||
|
|
||||||
public distance(target: vec2): number {
|
public distance(target: vec2): number {
|
||||||
return (
|
return (
|
||||||
Math.min(
|
Math.min(
|
||||||
|
|
@ -272,17 +261,18 @@ export class PlayerCharacterPhysical
|
||||||
} else {
|
} else {
|
||||||
const leftFootGravity = this.currentPlanet!.getForce(this.leftFoot.center);
|
const leftFootGravity = this.currentPlanet!.getForce(this.leftFoot.center);
|
||||||
const rightFootGravity = this.currentPlanet!.getForce(this.rightFoot.center);
|
const rightFootGravity = this.currentPlanet!.getForce(this.rightFoot.center);
|
||||||
if (movementForce.y > settings.maxAcceleration / 4) {
|
|
||||||
|
if (this.lastMovementWasRelative) {
|
||||||
|
vec2.rotate(movementForce, movementForce, vec2.create(), this.direction);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (vec2.dot(movementForce, actualGravity) < -vec2.length(movementForce) * 0.8) {
|
||||||
vec2.scale(leftFootGravity, leftFootGravity, 0.35);
|
vec2.scale(leftFootGravity, leftFootGravity, 0.35);
|
||||||
vec2.scale(rightFootGravity, rightFootGravity, 0.35);
|
vec2.scale(rightFootGravity, rightFootGravity, 0.35);
|
||||||
}
|
}
|
||||||
this.applyForce(this.leftFoot, leftFootGravity, deltaTime);
|
this.applyForce(this.leftFoot, leftFootGravity, deltaTime);
|
||||||
this.applyForce(this.rightFoot, rightFootGravity, deltaTime);
|
this.applyForce(this.rightFoot, rightFootGravity, deltaTime);
|
||||||
|
|
||||||
if (this.lastMovementWasRelative) {
|
|
||||||
vec2.rotate(movementForce, movementForce, vec2.create(), this.direction);
|
|
||||||
}
|
|
||||||
|
|
||||||
const headGravity = this.currentPlanet!.getForce(this.head.center);
|
const headGravity = this.currentPlanet!.getForce(this.head.center);
|
||||||
|
|
||||||
if (vec2.length(headGravity) < vec2.length(actualGravity) / 2) {
|
if (vec2.length(headGravity) < vec2.length(actualGravity) / 2) {
|
||||||
|
|
|
||||||
|
|
@ -16,6 +16,7 @@ import { ReactsToCollision } from '../physics/physicals/reacts-to-collision';
|
||||||
import { UpdateObjectMessage } from 'shared/lib/src/objects/update-object-message';
|
import { UpdateObjectMessage } from 'shared/lib/src/objects/update-object-message';
|
||||||
import { UpdateGameObjectMessage } from '../update-game-object-message';
|
import { UpdateGameObjectMessage } from '../update-game-object-message';
|
||||||
import { PlayerCharacterPhysical } from './player-character-physical';
|
import { PlayerCharacterPhysical } from './player-character-physical';
|
||||||
|
import { moveCircle } from '../physics/functions/move-circle';
|
||||||
|
|
||||||
@serializesTo(ProjectileBase)
|
@serializesTo(ProjectileBase)
|
||||||
export class ProjectilePhysical
|
export class ProjectilePhysical
|
||||||
|
|
@ -41,6 +42,26 @@ export class ProjectilePhysical
|
||||||
) {
|
) {
|
||||||
super(id(), center, radius, colorIndex, strength);
|
super(id(), center, radius, colorIndex, strength);
|
||||||
this.object = new CirclePhysical(center, radius, this, container, 0.9);
|
this.object = new CirclePhysical(center, radius, this, container, 0.9);
|
||||||
|
|
||||||
|
this.moveOutsideOfObject();
|
||||||
|
}
|
||||||
|
|
||||||
|
private moveOutsideOfObject() {
|
||||||
|
let wasCollision = true;
|
||||||
|
const delta = vec2.scale(
|
||||||
|
vec2.create(),
|
||||||
|
vec2.normalize(vec2.create(), this.velocity),
|
||||||
|
10,
|
||||||
|
);
|
||||||
|
while (wasCollision) {
|
||||||
|
const intersecting = this.container
|
||||||
|
.findIntersecting(this.boundingBox)
|
||||||
|
.filter((g) => g instanceof PlayerCharacterPhysical && g.team === this.team);
|
||||||
|
const { hitSurface } = moveCircle(this.object, delta, intersecting, true);
|
||||||
|
wasCollision = hitSurface;
|
||||||
|
}
|
||||||
|
vec2.add(this.center, this.center, delta);
|
||||||
|
vec2.add(this.center, this.center, delta);
|
||||||
}
|
}
|
||||||
|
|
||||||
public calculateUpdates(): UpdateObjectMessage {
|
public calculateUpdates(): UpdateObjectMessage {
|
||||||
|
|
|
||||||
|
|
@ -4,4 +4,4 @@ import { PhysicalBase } from '../physicals/physical-base';
|
||||||
export const evaluateSdf = (target: vec2, objects: Array<PhysicalBase>) =>
|
export const evaluateSdf = (target: vec2, objects: Array<PhysicalBase>) =>
|
||||||
objects
|
objects
|
||||||
.filter((i) => i.canCollide)
|
.filter((i) => i.canCollide)
|
||||||
.reduce((min, i) => (min = Math.min(min, i.distance(target))), 1000);
|
.reduce((min, i) => (min = Math.min(min, i.distance(target))), 1000000);
|
||||||
|
|
|
||||||
|
|
@ -9,6 +9,7 @@ export const moveCircle = (
|
||||||
circle: CirclePhysical,
|
circle: CirclePhysical,
|
||||||
delta: vec2,
|
delta: vec2,
|
||||||
possibleIntersectors: Array<Physical>,
|
possibleIntersectors: Array<Physical>,
|
||||||
|
ignoreCollision = false,
|
||||||
): {
|
): {
|
||||||
realDelta: vec2;
|
realDelta: vec2;
|
||||||
hitSurface: boolean;
|
hitSurface: boolean;
|
||||||
|
|
@ -38,6 +39,9 @@ export const moveCircle = (
|
||||||
(i) => i.distance(nextCircle.center) <= circle.radius,
|
(i) => i.distance(nextCircle.center) <= circle.radius,
|
||||||
)!;
|
)!;
|
||||||
|
|
||||||
|
if (ignoreCollision) {
|
||||||
|
circle.center = vec2.add(circle.center, circle.center, delta);
|
||||||
|
} else {
|
||||||
if (reactsToCollision(intersecting)) {
|
if (reactsToCollision(intersecting)) {
|
||||||
intersecting.onCollision(circle.gameObject);
|
intersecting.onCollision(circle.gameObject);
|
||||||
}
|
}
|
||||||
|
|
@ -45,6 +49,7 @@ export const moveCircle = (
|
||||||
if (reactsToCollision(circle)) {
|
if (reactsToCollision(circle)) {
|
||||||
circle.onCollision(intersecting.gameObject);
|
circle.onCollision(intersecting.gameObject);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const dx =
|
const dx =
|
||||||
evaluateSdf(vec2.add(vec2.create(), nextCircle.center, vec2.fromValues(0.01, 0)), [
|
evaluateSdf(vec2.add(vec2.create(), nextCircle.center, vec2.fromValues(0.01, 0)), [
|
||||||
|
|
|
||||||
|
|
@ -28,7 +28,6 @@ import { PhysicalContainer } from '../physics/containers/physical-container';
|
||||||
import { getBoundingBoxOfCircle } from '../physics/functions/get-bounding-box-of-circle';
|
import { getBoundingBoxOfCircle } from '../physics/functions/get-bounding-box-of-circle';
|
||||||
import { isCircleIntersecting } from '../physics/functions/is-circle-intersecting';
|
import { isCircleIntersecting } from '../physics/functions/is-circle-intersecting';
|
||||||
import { PlayerCharacterPhysical } from '../objects/player-character-physical';
|
import { PlayerCharacterPhysical } from '../objects/player-character-physical';
|
||||||
import { Physical } from '../physics/physicals/physical';
|
|
||||||
import { freeTeam, requestTeam } from './player-team-service';
|
import { freeTeam, requestTeam } from './player-team-service';
|
||||||
import { PlanetPhysical } from '../objects/planet-physical';
|
import { PlanetPhysical } from '../objects/planet-physical';
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -50,25 +50,43 @@
|
||||||
<section id="settings">
|
<section id="settings">
|
||||||
<label for="enable-relative-movement">
|
<label for="enable-relative-movement">
|
||||||
<input id="enable-relative-movement" type="checkbox" />
|
<input id="enable-relative-movement" type="checkbox" />
|
||||||
<img alt="a dashed circle" src="../static/circle.svg" />
|
<img
|
||||||
|
title="Make movement be relative to the gravitational field"
|
||||||
|
alt="a dashed circle"
|
||||||
|
src="../static/circle.svg"
|
||||||
|
/>
|
||||||
</label>
|
</label>
|
||||||
|
|
||||||
<label for="enable-vibration">
|
<label for="enable-vibration">
|
||||||
<input id="enable-vibration" type="checkbox" />
|
<input id="enable-vibration" type="checkbox" />
|
||||||
<img alt="vibrating mobile" src="../static/vibrate.svg" />
|
<img
|
||||||
|
title="Enable vibration on mobile"
|
||||||
|
alt="vibrating mobile"
|
||||||
|
src="../static/vibrate.svg"
|
||||||
|
/>
|
||||||
</label>
|
</label>
|
||||||
|
|
||||||
<label for="enable-sounds">
|
<label for="enable-sounds">
|
||||||
<input id="enable-sounds" type="checkbox" />
|
<input id="enable-sounds" type="checkbox" />
|
||||||
<img alt="speaker with sound waves" src="../static/volume.svg" />
|
<img
|
||||||
|
title="Enable sounds"
|
||||||
|
alt="speaker with sound waves"
|
||||||
|
src="../static/volume.svg"
|
||||||
|
/>
|
||||||
</label>
|
</label>
|
||||||
|
|
||||||
<img id="logout" alt="logout" src="../static/logout.svg" />
|
<img
|
||||||
|
title="Exit from current game"
|
||||||
|
id="logout"
|
||||||
|
alt="logout"
|
||||||
|
src="../static/logout.svg"
|
||||||
|
/>
|
||||||
</section>
|
</section>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div id="toggle-settings-container">
|
<div id="toggle-settings-container">
|
||||||
<img
|
<img
|
||||||
|
title="Toggle settings"
|
||||||
id="toggle-settings"
|
id="toggle-settings"
|
||||||
class="icon"
|
class="icon"
|
||||||
alt="toggle-settings"
|
alt="toggle-settings"
|
||||||
|
|
|
||||||
|
|
@ -94,21 +94,58 @@ body {
|
||||||
}
|
}
|
||||||
|
|
||||||
.player-tag {
|
.player-tag {
|
||||||
font-size: 1.3rem;
|
|
||||||
position: absolute;
|
position: absolute;
|
||||||
transform: translateX(-50%) translateY(-50%) rotate(-15deg);
|
transform: translateX(-50%) translateY(-50%) rotate(-15deg);
|
||||||
transition: left 200ms, top 200ms;
|
transition: left 200ms, top 200ms;
|
||||||
|
border-radius: 1000px;
|
||||||
|
|
||||||
|
&.decla {
|
||||||
|
color: $bright-decla;
|
||||||
|
|
||||||
div {
|
div {
|
||||||
height: 3px;
|
background-color: $bright-decla;
|
||||||
background-color: rebeccapurple;
|
&:before {
|
||||||
|
background-color: $bright-decla;
|
||||||
|
opacity: 0.3;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&.red {
|
||||||
|
color: $bright-red;
|
||||||
|
div {
|
||||||
|
background-color: $bright-red;
|
||||||
|
&:before {
|
||||||
|
background-color: $bright-red;
|
||||||
|
opacity: 0.4;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
div {
|
||||||
|
position: relative;
|
||||||
|
height: 5px;
|
||||||
|
border-radius: 1000px;
|
||||||
|
|
||||||
|
&:before {
|
||||||
|
content: '';
|
||||||
|
position: absolute;
|
||||||
|
height: 5px;
|
||||||
|
width: 50px;
|
||||||
|
box-sizing: border-box;
|
||||||
|
border-radius: 1000px;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.ownership {
|
.ownership {
|
||||||
font-size: 1.3rem;
|
|
||||||
position: absolute;
|
position: absolute;
|
||||||
|
font-size: 0;
|
||||||
transform: translateX(-50%) translateY(-50%);
|
transform: translateX(-50%) translateY(-50%);
|
||||||
|
|
||||||
|
@include square(50px);
|
||||||
|
border-radius: 1000px;
|
||||||
|
mask: url('../static/mask.svg');
|
||||||
}
|
}
|
||||||
|
|
||||||
.planet-progress {
|
.planet-progress {
|
||||||
|
|
@ -122,21 +159,24 @@ body {
|
||||||
height: $height;
|
height: $height;
|
||||||
|
|
||||||
border-radius: 4px;
|
border-radius: 4px;
|
||||||
|
z-index: 100;
|
||||||
|
|
||||||
div {
|
div {
|
||||||
height: $height;
|
height: $height;
|
||||||
}
|
}
|
||||||
|
|
||||||
div:nth-child(1) {
|
div:nth-child(1) {
|
||||||
background: rebeccapurple;
|
border-radius: 100px 0 0 100px;
|
||||||
|
background: $bright-decla;
|
||||||
}
|
}
|
||||||
|
|
||||||
div:nth-child(2) {
|
div:nth-child(2) {
|
||||||
background: gray;
|
background: $bright-neutral;
|
||||||
}
|
}
|
||||||
|
|
||||||
div:nth-child(3) {
|
div:nth-child(3) {
|
||||||
background: red;
|
border-radius: 0 100px 100px 0;
|
||||||
|
background: $bright-red;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,6 @@ import { vec2 } from 'gl-matrix';
|
||||||
import {
|
import {
|
||||||
CircleLight,
|
CircleLight,
|
||||||
ColorfulCircle,
|
ColorfulCircle,
|
||||||
compile,
|
|
||||||
FilteringOptions,
|
FilteringOptions,
|
||||||
Flashlight,
|
Flashlight,
|
||||||
Renderer,
|
Renderer,
|
||||||
|
|
@ -17,7 +16,6 @@ import {
|
||||||
settings,
|
settings,
|
||||||
TransportEvents,
|
TransportEvents,
|
||||||
SetAspectRatioActionCommand,
|
SetAspectRatioActionCommand,
|
||||||
rgb,
|
|
||||||
PlayerInformation,
|
PlayerInformation,
|
||||||
PlayerDiedCommand,
|
PlayerDiedCommand,
|
||||||
UpdatePlanetOwnershipCommand,
|
UpdatePlanetOwnershipCommand,
|
||||||
|
|
@ -66,6 +64,8 @@ export class Game {
|
||||||
this.socket.io.opts.transports = ['polling', 'websocket'];
|
this.socket.io.opts.transports = ['polling', 'websocket'];
|
||||||
});
|
});
|
||||||
|
|
||||||
|
this.socket.on('disconnect', this.destroy.bind(this));
|
||||||
|
|
||||||
this.socket.on(TransportEvents.ServerToPlayer, (serialized: string) => {
|
this.socket.on(TransportEvents.ServerToPlayer, (serialized: string) => {
|
||||||
const command = deserialize(serialized);
|
const command = deserialize(serialized);
|
||||||
if (command instanceof PlayerDiedCommand) {
|
if (command instanceof PlayerDiedCommand) {
|
||||||
|
|
@ -145,7 +145,6 @@ export class Game {
|
||||||
//enableStopwatch: true,
|
//enableStopwatch: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
ambientLight: rgb(0.45, 0.4, 0.45),
|
|
||||||
colorPalette: settings.palette,
|
colorPalette: settings.palette,
|
||||||
enableHighDpiRendering: true,
|
enableHighDpiRendering: true,
|
||||||
lightCutoffDistance: settings.lightCutoffDistance,
|
lightCutoffDistance: settings.lightCutoffDistance,
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
import { vec2 } from 'gl-matrix';
|
import { vec2 } from 'gl-matrix';
|
||||||
import { Renderer } from 'sdf-2d';
|
import { Renderer } from 'sdf-2d';
|
||||||
import { calculateViewArea, GameObject, mixRgb, settings, UpdateMessage } from 'shared';
|
import { calculateViewArea, GameObject, mixRgb, settings } from 'shared';
|
||||||
|
|
||||||
import { Game } from '../game';
|
import { Game } from '../game';
|
||||||
import { ViewObject } from './view-object';
|
import { ViewObject } from './view-object';
|
||||||
|
|
@ -32,8 +32,7 @@ export class Camera extends GameObject implements ViewObject {
|
||||||
ambientLight: mixRgb(
|
ambientLight: mixRgb(
|
||||||
settings.backgroundGradient[0],
|
settings.backgroundGradient[0],
|
||||||
settings.backgroundGradient[1],
|
settings.backgroundGradient[1],
|
||||||
(this.center.x - settings.worldLeftEdge) /
|
vec2.length(this.center) / settings.worldRadius,
|
||||||
(Math.abs(settings.worldLeftEdge) + Math.abs(settings.worldRightEdge)),
|
|
||||||
),
|
),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,13 +1,6 @@
|
||||||
import { vec2 } from 'gl-matrix';
|
import { vec2 } from 'gl-matrix';
|
||||||
import { Drawable, Renderer } from 'sdf-2d';
|
import { Renderer } from 'sdf-2d';
|
||||||
import {
|
import { CommandExecutors, Id, Random, PlanetBase } from 'shared';
|
||||||
CommandExecutors,
|
|
||||||
Id,
|
|
||||||
Random,
|
|
||||||
PlanetBase,
|
|
||||||
UpdateMessage,
|
|
||||||
settings,
|
|
||||||
} from 'shared';
|
|
||||||
import { RenderCommand } from '../commands/types/render';
|
import { RenderCommand } from '../commands/types/render';
|
||||||
import { PlanetShape } from '../shapes/planet-shape';
|
import { PlanetShape } from '../shapes/planet-shape';
|
||||||
import { ViewObject } from './view-object';
|
import { ViewObject } from './view-object';
|
||||||
|
|
@ -32,18 +25,19 @@ export class PlanetView extends PlanetBase implements ViewObject {
|
||||||
public step(deltaTimeInMilliseconds: number): void {
|
public step(deltaTimeInMilliseconds: number): void {
|
||||||
this.shape.randomOffset += deltaTimeInMilliseconds / 4000;
|
this.shape.randomOffset += deltaTimeInMilliseconds / 4000;
|
||||||
this.shape.colorMixQ = this.ownership;
|
this.shape.colorMixQ = this.ownership;
|
||||||
let teamName = 'Neutral';
|
|
||||||
if (this.ownership < 0.5 - settings.planetControlThreshold) {
|
|
||||||
teamName = 'Decla';
|
|
||||||
} else if (this.ownership > 0.5 + settings.planetControlThreshold) {
|
|
||||||
teamName = 'Red';
|
|
||||||
}
|
}
|
||||||
|
|
||||||
this.ownershipProgess.innerText = `${teamName} ${Math.round(
|
private getGradient(): string {
|
||||||
(Math.abs(this.ownership - 0.5) / 0.5) * 100,
|
const sideDecla = this.ownership < 0.5;
|
||||||
)}%`;
|
const sidePercent = (Math.abs(this.ownership - 0.5) / 0.5) * 100;
|
||||||
|
const color = sideDecla ? 'var(--bright-decla)' : 'var(--bright-red)';
|
||||||
|
return `conic-gradient(
|
||||||
|
${color} ${sidePercent}%,
|
||||||
|
${color} ${sidePercent}%,
|
||||||
|
var(--bright-neutral) ${sidePercent}%,
|
||||||
|
var(--bright-neutral) 100%
|
||||||
|
)`;
|
||||||
}
|
}
|
||||||
|
|
||||||
public beforeDestroy(): void {
|
public beforeDestroy(): void {
|
||||||
this.ownershipProgess.parentElement?.removeChild(this.ownershipProgess);
|
this.ownershipProgess.parentElement?.removeChild(this.ownershipProgess);
|
||||||
}
|
}
|
||||||
|
|
@ -56,6 +50,7 @@ export class PlanetView extends PlanetBase implements ViewObject {
|
||||||
const screenPosition = renderer.worldToDisplayCoordinates(this.center);
|
const screenPosition = renderer.worldToDisplayCoordinates(this.center);
|
||||||
this.ownershipProgess.style.left = screenPosition.x + 'px';
|
this.ownershipProgess.style.left = screenPosition.x + 'px';
|
||||||
this.ownershipProgess.style.top = screenPosition.y + 'px';
|
this.ownershipProgess.style.top = screenPosition.y + 'px';
|
||||||
|
this.ownershipProgess.style.background = this.getGradient();
|
||||||
|
|
||||||
renderer.addDrawable(this.shape);
|
renderer.addDrawable(this.shape);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,13 +1,6 @@
|
||||||
import { vec2 } from 'gl-matrix';
|
import { vec2 } from 'gl-matrix';
|
||||||
import { Renderer } from 'sdf-2d';
|
import { Renderer } from 'sdf-2d';
|
||||||
import {
|
import { Circle, Id, PlayerCharacterBase, CharacterTeam, settings } from 'shared';
|
||||||
Circle,
|
|
||||||
Id,
|
|
||||||
PlayerCharacterBase,
|
|
||||||
UpdateMessage,
|
|
||||||
CharacterTeam,
|
|
||||||
settings,
|
|
||||||
} from 'shared';
|
|
||||||
import { OptionsHandler } from '../options-handler';
|
import { OptionsHandler } from '../options-handler';
|
||||||
|
|
||||||
import { BlobShape } from '../shapes/blob-shape';
|
import { BlobShape } from '../shapes/blob-shape';
|
||||||
|
|
@ -35,7 +28,7 @@ export class PlayerCharacterView extends PlayerCharacterBase implements ViewObje
|
||||||
|
|
||||||
this.previousHealth = this.health;
|
this.previousHealth = this.health;
|
||||||
this.nameElement = document.createElement('div');
|
this.nameElement = document.createElement('div');
|
||||||
this.nameElement.className = 'player-tag';
|
this.nameElement.className = 'player-tag ' + this.team;
|
||||||
this.nameElement.innerText = this.name;
|
this.nameElement.innerText = this.name;
|
||||||
this.healthElement = document.createElement('div');
|
this.healthElement = document.createElement('div');
|
||||||
this.nameElement.appendChild(this.healthElement);
|
this.nameElement.appendChild(this.healthElement);
|
||||||
|
|
@ -47,7 +40,7 @@ export class PlayerCharacterView extends PlayerCharacterBase implements ViewObje
|
||||||
|
|
||||||
public step(deltaTimeInMilliseconds: number): void {
|
public step(deltaTimeInMilliseconds: number): void {
|
||||||
this.timeSinceLastNameElementUpdate += deltaTimeInMilliseconds;
|
this.timeSinceLastNameElementUpdate += deltaTimeInMilliseconds;
|
||||||
this.healthElement.style.width = this.health + '%';
|
this.healthElement.style.width = (50 * this.health) / settings.playerMaxHealth + 'px';
|
||||||
if (this.previousHealth > this.health) {
|
if (this.previousHealth > this.health) {
|
||||||
this.previousHealth = this.health;
|
this.previousHealth = this.health;
|
||||||
if (OptionsHandler.options.vibrationEnabled) {
|
if (OptionsHandler.options.vibrationEnabled) {
|
||||||
|
|
@ -89,7 +82,7 @@ export class PlayerCharacterView extends PlayerCharacterBase implements ViewObje
|
||||||
|
|
||||||
const headFeetDelta = vec2.subtract(footAverage, this.head!.center, footAverage);
|
const headFeetDelta = vec2.subtract(footAverage, this.head!.center, footAverage);
|
||||||
vec2.normalize(headFeetDelta, headFeetDelta);
|
vec2.normalize(headFeetDelta, headFeetDelta);
|
||||||
const textOffset = vec2.scale(headFeetDelta, headFeetDelta, this.head!.radius + 50);
|
const textOffset = vec2.scale(headFeetDelta, headFeetDelta, this.head!.radius + 60);
|
||||||
return vec2.add(textOffset, this.head!.center, textOffset);
|
return vec2.add(textOffset, this.head!.center, textOffset);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -96,7 +96,8 @@ form {
|
||||||
padding: $small-padding;
|
padding: $small-padding;
|
||||||
border: $border;
|
border: $border;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
margin: $border-width-focused - $border-width $small-padding / 2;
|
margin: $border-width-focused - $border-width $border-width-focused -
|
||||||
|
$border-width + $small-padding / 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
&:focus {
|
&:focus {
|
||||||
|
|
@ -107,7 +108,7 @@ form {
|
||||||
&:checked + label {
|
&:checked + label {
|
||||||
border-color: $accent;
|
border-color: $accent;
|
||||||
border-width: $border-width-focused;
|
border-width: $border-width-focused;
|
||||||
margin-right: 0 $small-padding / 2;
|
margin: 0 $small-padding / 2;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -8,14 +8,22 @@
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
top: 0;
|
top: 0;
|
||||||
right: 0;
|
right: 0;
|
||||||
|
font-size: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
#toggle-settings-container {
|
#toggle-settings-container {
|
||||||
padding: $medium-padding;
|
padding: $medium-padding;
|
||||||
|
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
|
|
||||||
|
padding: $medium-padding $medium-padding 0 $medium-padding;
|
||||||
|
@media (max-width: $breakpoint) {
|
||||||
|
padding: $medium-padding $medium-padding $medium-padding 0;
|
||||||
|
}
|
||||||
|
|
||||||
#toggle-settings {
|
#toggle-settings {
|
||||||
animation: spin 32s linear infinite;
|
animation: spin 32s linear infinite;
|
||||||
|
|
||||||
@keyframes spin {
|
@keyframes spin {
|
||||||
100% {
|
100% {
|
||||||
transform: rotate(360deg);
|
transform: rotate(360deg);
|
||||||
|
|
@ -53,9 +61,11 @@
|
||||||
opacity: 0;
|
opacity: 0;
|
||||||
transition: transform $animation-time, opacity $animation-time;
|
transition: transform $animation-time, opacity $animation-time;
|
||||||
|
|
||||||
|
pointer-events: none;
|
||||||
&.open {
|
&.open {
|
||||||
transform: none;
|
transform: none;
|
||||||
opacity: 1;
|
opacity: 1;
|
||||||
|
pointer-events: inherit;
|
||||||
}
|
}
|
||||||
|
|
||||||
img,
|
img,
|
||||||
|
|
|
||||||
|
|
@ -13,3 +13,12 @@ $breakpoint: 700px;
|
||||||
$height-breakpoint: 500px;
|
$height-breakpoint: 500px;
|
||||||
$large-icon: 48px;
|
$large-icon: 48px;
|
||||||
$small-icon: 32px;
|
$small-icon: 32px;
|
||||||
|
$bright-decla: #4069a5;
|
||||||
|
$bright-red: #d15652;
|
||||||
|
$bright-neutral: #88888877;
|
||||||
|
|
||||||
|
:root {
|
||||||
|
--bright-decla: #{$bright-decla};
|
||||||
|
--bright-red: #{$bright-red};
|
||||||
|
--bright-neutral: #{$bright-neutral};
|
||||||
|
}
|
||||||
|
|
|
||||||
10
frontend/static/mask.svg
Normal file
10
frontend/static/mask.svg
Normal file
|
|
@ -0,0 +1,10 @@
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100" fill="000000" >
|
||||||
|
<defs>
|
||||||
|
<mask id="hole">
|
||||||
|
<rect width="100%" height="100%" fill="white"/>
|
||||||
|
<circle r="20" cx="50" cy="50" fill="black"/>
|
||||||
|
</mask>
|
||||||
|
</defs>
|
||||||
|
|
||||||
|
<rect width="100%" height="100%" fill="black" mask="url(#hole)"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 311 B |
Loading…
Add table
Add a link
Reference in a new issue