From 1d1bc6655c9051fb0ff05a279779e8a80e54d79b Mon Sep 17 00:00:00 2001 From: schmelczerandras Date: Thu, 22 Oct 2020 21:50:39 +0200 Subject: [PATCH] Improve gameplay and design --- .../src/objects/player-character-physical.ts | 26 +++------ backend/src/objects/projectile-physical.ts | 21 ++++++++ backend/src/physics/functions/evaluate-sdf.ts | 2 +- backend/src/physics/functions/move-circle.ts | 15 ++++-- backend/src/players/player.ts | 1 - frontend/src/index.html | 26 +++++++-- frontend/src/main.scss | 54 ++++++++++++++++--- frontend/src/scripts/game.ts | 5 +- frontend/src/scripts/objects/camera.ts | 5 +- frontend/src/scripts/objects/planet-view.ts | 33 +++++------- .../scripts/objects/player-character-view.ts | 15 ++---- frontend/src/styles/form.scss | 5 +- frontend/src/styles/settings.scss | 10 ++++ frontend/src/styles/vars.scss | 9 ++++ frontend/static/mask.svg | 10 ++++ 15 files changed, 163 insertions(+), 74 deletions(-) create mode 100644 frontend/static/mask.svg diff --git a/backend/src/objects/player-character-physical.ts b/backend/src/objects/player-character-physical.ts index 43955cd..47fe473 100644 --- a/backend/src/objects/player-character-physical.ts +++ b/backend/src/objects/player-character-physical.ts @@ -155,20 +155,13 @@ export class PlayerCharacterPhysical return; } - const start = vec2.clone(this.center); - const direction = vec2.subtract(vec2.create(), position, start); + const direction = vec2.subtract(vec2.create(), position, this.center); vec2.normalize(direction, direction); - vec2.add( - start, - start, - vec2.scale(vec2.create(), direction, settings.projectileStartOffset), - ); const velocity = vec2.scale(direction, direction, settings.projectileSpeed); - vec2.add(velocity, velocity, this.velocity); const strength = this.projectileStrength / 2; this.projectileStrength -= strength; const projectile = new ProjectilePhysical( - start, + vec2.clone(this.center), 20, this.colorIndex, strength, @@ -192,10 +185,6 @@ export class PlayerCharacterPhysical return this.head.center; } - public get velocity(): vec2 { - return this.head.velocity; - } - public distance(target: vec2): number { return ( Math.min( @@ -272,17 +261,18 @@ export class PlayerCharacterPhysical } else { const leftFootGravity = this.currentPlanet!.getForce(this.leftFoot.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(rightFootGravity, rightFootGravity, 0.35); } this.applyForce(this.leftFoot, leftFootGravity, 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); if (vec2.length(headGravity) < vec2.length(actualGravity) / 2) { diff --git a/backend/src/objects/projectile-physical.ts b/backend/src/objects/projectile-physical.ts index e7d6886..bded869 100644 --- a/backend/src/objects/projectile-physical.ts +++ b/backend/src/objects/projectile-physical.ts @@ -16,6 +16,7 @@ import { ReactsToCollision } from '../physics/physicals/reacts-to-collision'; import { UpdateObjectMessage } from 'shared/lib/src/objects/update-object-message'; import { UpdateGameObjectMessage } from '../update-game-object-message'; import { PlayerCharacterPhysical } from './player-character-physical'; +import { moveCircle } from '../physics/functions/move-circle'; @serializesTo(ProjectileBase) export class ProjectilePhysical @@ -41,6 +42,26 @@ export class ProjectilePhysical ) { super(id(), center, radius, colorIndex, strength); 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 { diff --git a/backend/src/physics/functions/evaluate-sdf.ts b/backend/src/physics/functions/evaluate-sdf.ts index 69d0d6d..16bc96c 100644 --- a/backend/src/physics/functions/evaluate-sdf.ts +++ b/backend/src/physics/functions/evaluate-sdf.ts @@ -4,4 +4,4 @@ import { PhysicalBase } from '../physicals/physical-base'; export const evaluateSdf = (target: vec2, objects: Array) => objects .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); diff --git a/backend/src/physics/functions/move-circle.ts b/backend/src/physics/functions/move-circle.ts index 9f80bd5..4500985 100644 --- a/backend/src/physics/functions/move-circle.ts +++ b/backend/src/physics/functions/move-circle.ts @@ -9,6 +9,7 @@ export const moveCircle = ( circle: CirclePhysical, delta: vec2, possibleIntersectors: Array, + ignoreCollision = false, ): { realDelta: vec2; hitSurface: boolean; @@ -38,12 +39,16 @@ export const moveCircle = ( (i) => i.distance(nextCircle.center) <= circle.radius, )!; - if (reactsToCollision(intersecting)) { - intersecting.onCollision(circle.gameObject); - } + if (ignoreCollision) { + circle.center = vec2.add(circle.center, circle.center, delta); + } else { + if (reactsToCollision(intersecting)) { + intersecting.onCollision(circle.gameObject); + } - if (reactsToCollision(circle)) { - circle.onCollision(intersecting.gameObject); + if (reactsToCollision(circle)) { + circle.onCollision(intersecting.gameObject); + } } const dx = diff --git a/backend/src/players/player.ts b/backend/src/players/player.ts index efafb49..9e9da6d 100644 --- a/backend/src/players/player.ts +++ b/backend/src/players/player.ts @@ -28,7 +28,6 @@ import { PhysicalContainer } from '../physics/containers/physical-container'; import { getBoundingBoxOfCircle } from '../physics/functions/get-bounding-box-of-circle'; import { isCircleIntersecting } from '../physics/functions/is-circle-intersecting'; import { PlayerCharacterPhysical } from '../objects/player-character-physical'; -import { Physical } from '../physics/physicals/physical'; import { freeTeam, requestTeam } from './player-team-service'; import { PlanetPhysical } from '../objects/planet-physical'; diff --git a/frontend/src/index.html b/frontend/src/index.html index 285926e..97a4d7e 100644 --- a/frontend/src/index.html +++ b/frontend/src/index.html @@ -50,25 +50,43 @@
- logout + logout
toggle-settings { const command = deserialize(serialized); if (command instanceof PlayerDiedCommand) { @@ -145,7 +145,6 @@ export class Game { //enableStopwatch: true, }, { - ambientLight: rgb(0.45, 0.4, 0.45), colorPalette: settings.palette, enableHighDpiRendering: true, lightCutoffDistance: settings.lightCutoffDistance, diff --git a/frontend/src/scripts/objects/camera.ts b/frontend/src/scripts/objects/camera.ts index 2e28612..27d932f 100644 --- a/frontend/src/scripts/objects/camera.ts +++ b/frontend/src/scripts/objects/camera.ts @@ -1,6 +1,6 @@ import { vec2 } from 'gl-matrix'; 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 { ViewObject } from './view-object'; @@ -32,8 +32,7 @@ export class Camera extends GameObject implements ViewObject { ambientLight: mixRgb( settings.backgroundGradient[0], settings.backgroundGradient[1], - (this.center.x - settings.worldLeftEdge) / - (Math.abs(settings.worldLeftEdge) + Math.abs(settings.worldRightEdge)), + vec2.length(this.center) / settings.worldRadius, ), }); } diff --git a/frontend/src/scripts/objects/planet-view.ts b/frontend/src/scripts/objects/planet-view.ts index 316fc9f..b1c120b 100644 --- a/frontend/src/scripts/objects/planet-view.ts +++ b/frontend/src/scripts/objects/planet-view.ts @@ -1,13 +1,6 @@ import { vec2 } from 'gl-matrix'; -import { Drawable, Renderer } from 'sdf-2d'; -import { - CommandExecutors, - Id, - Random, - PlanetBase, - UpdateMessage, - settings, -} from 'shared'; +import { Renderer } from 'sdf-2d'; +import { CommandExecutors, Id, Random, PlanetBase } from 'shared'; import { RenderCommand } from '../commands/types/render'; import { PlanetShape } from '../shapes/planet-shape'; import { ViewObject } from './view-object'; @@ -32,18 +25,19 @@ export class PlanetView extends PlanetBase implements ViewObject { public step(deltaTimeInMilliseconds: number): void { this.shape.randomOffset += deltaTimeInMilliseconds / 4000; 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( - (Math.abs(this.ownership - 0.5) / 0.5) * 100, - )}%`; } + private getGradient(): string { + 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 { this.ownershipProgess.parentElement?.removeChild(this.ownershipProgess); } @@ -56,6 +50,7 @@ export class PlanetView extends PlanetBase implements ViewObject { const screenPosition = renderer.worldToDisplayCoordinates(this.center); this.ownershipProgess.style.left = screenPosition.x + 'px'; this.ownershipProgess.style.top = screenPosition.y + 'px'; + this.ownershipProgess.style.background = this.getGradient(); renderer.addDrawable(this.shape); } diff --git a/frontend/src/scripts/objects/player-character-view.ts b/frontend/src/scripts/objects/player-character-view.ts index 64aa55a..be6ca0c 100644 --- a/frontend/src/scripts/objects/player-character-view.ts +++ b/frontend/src/scripts/objects/player-character-view.ts @@ -1,13 +1,6 @@ import { vec2 } from 'gl-matrix'; import { Renderer } from 'sdf-2d'; -import { - Circle, - Id, - PlayerCharacterBase, - UpdateMessage, - CharacterTeam, - settings, -} from 'shared'; +import { Circle, Id, PlayerCharacterBase, CharacterTeam, settings } from 'shared'; import { OptionsHandler } from '../options-handler'; import { BlobShape } from '../shapes/blob-shape'; @@ -35,7 +28,7 @@ export class PlayerCharacterView extends PlayerCharacterBase implements ViewObje this.previousHealth = this.health; this.nameElement = document.createElement('div'); - this.nameElement.className = 'player-tag'; + this.nameElement.className = 'player-tag ' + this.team; this.nameElement.innerText = this.name; this.healthElement = document.createElement('div'); this.nameElement.appendChild(this.healthElement); @@ -47,7 +40,7 @@ export class PlayerCharacterView extends PlayerCharacterBase implements ViewObje public step(deltaTimeInMilliseconds: number): void { this.timeSinceLastNameElementUpdate += deltaTimeInMilliseconds; - this.healthElement.style.width = this.health + '%'; + this.healthElement.style.width = (50 * this.health) / settings.playerMaxHealth + 'px'; if (this.previousHealth > this.health) { this.previousHealth = this.health; if (OptionsHandler.options.vibrationEnabled) { @@ -89,7 +82,7 @@ export class PlayerCharacterView extends PlayerCharacterBase implements ViewObje const headFeetDelta = vec2.subtract(footAverage, this.head!.center, footAverage); 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); } } diff --git a/frontend/src/styles/form.scss b/frontend/src/styles/form.scss index 2bf153f..cc8df56 100644 --- a/frontend/src/styles/form.scss +++ b/frontend/src/styles/form.scss @@ -96,7 +96,8 @@ form { padding: $small-padding; border: $border; 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 { @@ -107,7 +108,7 @@ form { &:checked + label { border-color: $accent; border-width: $border-width-focused; - margin-right: 0 $small-padding / 2; + margin: 0 $small-padding / 2; } } } diff --git a/frontend/src/styles/settings.scss b/frontend/src/styles/settings.scss index 1dd5520..d9d744b 100644 --- a/frontend/src/styles/settings.scss +++ b/frontend/src/styles/settings.scss @@ -8,14 +8,22 @@ justify-content: center; top: 0; right: 0; + font-size: 0; } #toggle-settings-container { padding: $medium-padding; + cursor: pointer; + padding: $medium-padding $medium-padding 0 $medium-padding; + @media (max-width: $breakpoint) { + padding: $medium-padding $medium-padding $medium-padding 0; + } + #toggle-settings { animation: spin 32s linear infinite; + @keyframes spin { 100% { transform: rotate(360deg); @@ -53,9 +61,11 @@ opacity: 0; transition: transform $animation-time, opacity $animation-time; + pointer-events: none; &.open { transform: none; opacity: 1; + pointer-events: inherit; } img, diff --git a/frontend/src/styles/vars.scss b/frontend/src/styles/vars.scss index 7c583fb..14affc2 100644 --- a/frontend/src/styles/vars.scss +++ b/frontend/src/styles/vars.scss @@ -13,3 +13,12 @@ $breakpoint: 700px; $height-breakpoint: 500px; $large-icon: 48px; $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}; +} diff --git a/frontend/static/mask.svg b/frontend/static/mask.svg new file mode 100644 index 0000000..8c7ecbf --- /dev/null +++ b/frontend/static/mask.svg @@ -0,0 +1,10 @@ + + + + + + + + + + \ No newline at end of file