Improve gameplay

This commit is contained in:
schmelczerandras 2020-10-20 08:56:38 +02:00
parent e02a5b264c
commit 7c76b16d13
53 changed files with 1084 additions and 404 deletions

View file

@ -14,13 +14,11 @@ export class Camera extends GameObject implements ViewObject {
super(null);
}
public update(updates: Array<UpdateMessage>) {
throw new Error();
}
public beforeDestroy(): void {}
public step(deltaTimeInMilliseconds: number): void {}
public draw(renderer: Renderer) {
public draw(renderer: Renderer, overlay: HTMLElement) {
const canvasAspectRatio = renderer.canvasSize.x / renderer.canvasSize.y;
if (canvasAspectRatio !== this.aspectRatio) {
this.aspectRatio = canvasAspectRatio;

View file

@ -1,6 +1,6 @@
import { vec2 } from 'gl-matrix';
import { Renderer } from 'sdf-2d';
import { CharacterBase, Circle, Id, UpdateMessage } from 'shared';
import { CharacterBase, CharacterTeam, Circle, Id, UpdateMessage } from 'shared';
import { BlobShape } from '../shapes/blob-shape';
import { ViewObject } from './view-object';
@ -11,25 +11,25 @@ export class CharacterView extends CharacterBase implements ViewObject {
constructor(
id: Id,
colorIndex: number,
team: CharacterTeam,
health: number,
head?: Circle,
leftFoot?: Circle,
rightFoot?: Circle,
) {
super(id, colorIndex, head, leftFoot, rightFoot);
super(id, colorIndex, team, health, head, leftFoot, rightFoot);
this.shape = new BlobShape(colorIndex);
}
public update(updates: Array<UpdateMessage>) {
updates.forEach((u) => ((this as any)[u.key] = u.value));
}
public get position(): vec2 {
return this.head!.center;
}
public beforeDestroy(): void {}
public step(deltaTimeInMilliseconds: number): void {}
public draw(renderer: Renderer): void {
public draw(renderer: Renderer, overlay: HTMLElement): void {
this.shape.setCircles([this.head!, this.leftFoot!, this.rightFoot!]);
renderer.addDrawable(this.shape);
}

View file

@ -22,6 +22,7 @@ export class GameObjectContainer extends CommandReceiver {
protected commandExecutors: CommandExecutors = {
[CreatePlayerCommand.type]: (c: CreatePlayerCommand) => {
this.player = c.character as PlayerCharacterView;
console.log(c.character);
this.camera = new Camera(this.game);
this.addObject(this.player);
this.addObject(this.camera);
@ -31,7 +32,7 @@ export class GameObjectContainer extends CommandReceiver {
c.objects.forEach((o) => this.addObject(o as ViewObject)),
[DeleteObjectsCommand.type]: (c: DeleteObjectsCommand) =>
c.ids.forEach((id: Id) => this.objects.delete(id)),
c.ids.forEach((id: Id) => this.deleteObject(id)),
[UpdateObjectsCommand.type]: (c: UpdateObjectsCommand) => {
c.updates.forEach((u) => this.objects.get(u.id)?.update(u.updates));
@ -50,11 +51,17 @@ export class GameObjectContainer extends CommandReceiver {
this.objects.forEach((o) => o.step(delta));
}
public drawObjects(renderer: Renderer) {
this.objects.forEach((o) => o.draw(renderer));
public drawObjects(renderer: Renderer, overlay: HTMLElement) {
this.objects.forEach((o) => o.draw(renderer, overlay));
}
private addObject(object: ViewObject) {
this.objects.set(object.id, object);
}
private deleteObject(id: Id) {
const object = this.objects.get(id);
object?.beforeDestroy();
this.objects.delete(id);
}
}

View file

@ -16,13 +16,11 @@ export class LampView extends LampBase implements ViewObject {
this.light = new CircleLight(center, color, lightness);
}
public update(message: Array<UpdateMessage>): void {
throw new Error('Method not implemented.');
}
public step(deltaTimeInMilliseconds: number): void {}
public draw(renderer: Renderer): void {
public beforeDestroy(): void {}
public draw(renderer: Renderer, overlay: HTMLElement): void {
renderer.addDrawable(this.light);
}
}

View file

@ -1,32 +1,62 @@
import { vec2 } from 'gl-matrix';
import { Drawable, Renderer } from 'sdf-2d';
import { CommandExecutors, Id, Random, PlanetBase, UpdateMessage } from 'shared';
import {
CommandExecutors,
Id,
Random,
PlanetBase,
UpdateMessage,
settings,
} from 'shared';
import { RenderCommand } from '../commands/types/render';
import { Polygon } from '../shapes/polygon';
import { PlanetShape } from '../shapes/planet-shape';
import { ViewObject } from './view-object';
export class PlanetView extends PlanetBase implements ViewObject {
private shape: Drawable;
private shape: PlanetShape;
private ownershipProgess: HTMLElement;
protected commandExecutors: CommandExecutors = {
[RenderCommand.type]: (c: RenderCommand) => c.renderer.addDrawable(this.shape),
};
constructor(id: Id, vertices: Array<vec2>) {
constructor(id: Id, vertices: Array<vec2>, ownership: number) {
super(id, vertices);
this.shape = new Polygon(vertices);
this.shape = new PlanetShape(vertices, ownership);
(this.shape as any).randomOffset = Random.getRandom();
}
public update(message: Array<UpdateMessage>): void {
throw new Error('Method not implemented.');
this.ownershipProgess = document.createElement('div');
this.ownershipProgess.className = 'ownership';
}
public step(deltaTimeInMilliseconds: number): void {
(this.shape as any).randomOffset += deltaTimeInMilliseconds / 4000;
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,
)}%`;
}
public draw(renderer: Renderer): void {
public beforeDestroy(): void {
this.ownershipProgess.parentElement?.removeChild(this.ownershipProgess);
}
public draw(renderer: Renderer, overlay: HTMLElement): void {
if (!this.ownershipProgess.parentElement) {
overlay.appendChild(this.ownershipProgess);
}
const screenPosition = renderer.worldToDisplayCoordinates(this.center);
this.ownershipProgess.style.left = screenPosition.x + 'px';
this.ownershipProgess.style.top = screenPosition.y + 'px';
renderer.addDrawable(this.shape);
}
}

View file

@ -1,37 +1,84 @@
import { vec2 } from 'gl-matrix';
import { Renderer } from 'sdf-2d';
import { Circle, Id, PlayerCharacterBase, UpdateMessage } from 'shared';
import { Circle, Id, PlayerCharacterBase, UpdateMessage, CharacterTeam } from 'shared';
import { BlobShape } from '../shapes/blob-shape';
import { ViewObject } from './view-object';
export class PlayerCharacterView extends PlayerCharacterBase implements ViewObject {
private shape: BlobShape;
private nameElement: HTMLElement;
private healthElement: HTMLElement;
private timeSinceLastNameElementUpdate = 0;
constructor(
id: Id,
name: string,
colorIndex: number,
team: CharacterTeam,
health: number,
head?: Circle,
leftFoot?: Circle,
rightFoot?: Circle,
) {
super(id, name, colorIndex, head, leftFoot, rightFoot);
super(id, name, colorIndex, team, health, head, leftFoot, rightFoot);
this.shape = new BlobShape(colorIndex);
}
public update(updates: Array<UpdateMessage>) {
updates.forEach((u) => ((this as any)[u.key] = u.value));
console.log(this.id, 'created');
this.nameElement = document.createElement('div');
this.nameElement.className = 'player-tag';
this.nameElement.innerText = this.name;
this.healthElement = document.createElement('div');
this.nameElement.appendChild(this.healthElement);
}
public get position(): vec2 {
return this.head!.center;
}
public step(deltaTimeInMilliseconds: number): void {}
public step(deltaTimeInMilliseconds: number): void {
this.timeSinceLastNameElementUpdate += deltaTimeInMilliseconds;
this.healthElement.style.width = this.health + '%';
}
public beforeDestroy(): void {
console.log(this.id, 'destroyes');
this.nameElement.parentElement?.removeChild(this.nameElement);
}
private elementAdded = false;
public draw(renderer: Renderer, overlay: HTMLElement): void {
if (!this.elementAdded) {
this.elementAdded = true;
console.log(this.id, 'add', this.nameElement, this.nameElement.parentElement);
overlay.appendChild(this.nameElement);
}
if (this.timeSinceLastNameElementUpdate > 0.15) {
const screenPosition = renderer.worldToDisplayCoordinates(
this.calculateTextPosition(),
);
this.nameElement.style.left = screenPosition.x + 'px';
this.nameElement.style.top = screenPosition.y + 'px';
this.timeSinceLastNameElementUpdate = 0;
}
public draw(renderer: Renderer): void {
this.shape.setCircles([this.head!, this.leftFoot!, this.rightFoot!]);
renderer.addDrawable(this.shape);
}
private calculateTextPosition(): vec2 {
const footAverage = vec2.add(
vec2.create(),
this.leftFoot!.center,
this.rightFoot!.center,
);
vec2.scale(footAverage, footAverage, 0.5);
const headFeetDelta = vec2.subtract(footAverage, this.head!.center, footAverage);
vec2.normalize(headFeetDelta, headFeetDelta);
const textOffset = vec2.scale(headFeetDelta, headFeetDelta, this.head!.radius + 50);
return vec2.add(textOffset, this.head!.center, textOffset);
}
}

View file

@ -1,29 +1,33 @@
import { vec2 } from 'gl-matrix';
import { CircleLight, Renderer } from 'sdf-2d';
import { Id, ProjectileBase, rgb, UpdateMessage } from 'shared';
import { CircleLight, ColorfulCircle, Renderer } from 'sdf-2d';
import { Id, ProjectileBase, settings, UpdateMessage } from 'shared';
import { ViewObject } from './view-object';
import { Circle } from '../shapes/circle';
export class ProjectileView extends ProjectileBase implements ViewObject {
private circle: InstanceType<typeof Circle>;
private circle: ColorfulCircle;
private light: CircleLight;
constructor(id: Id, center: vec2, radius: number) {
super(id, center, radius);
this.circle = new Circle(center, radius / 2);
this.light = new CircleLight(center, rgb(1, 0.5, 0), 0.15);
}
update(updates: Array<UpdateMessage>): void {
updates.forEach((u) => ((this as any)[u.key] = u.value));
constructor(
id: Id,
center: vec2,
radius: number,
colorIndex: number,
strength: number,
) {
super(id, center, radius, colorIndex, strength);
this.circle = new ColorfulCircle(center, radius / 2, colorIndex);
this.light = new CircleLight(center, settings.palette[colorIndex], 0);
}
public step(deltaTimeInMilliseconds: number): void {
this.circle.center = this.center;
this.light.center = this.center;
this.light.intensity = (0.15 * this.strength) / settings.projectileMaxStrength;
}
public draw(renderer: Renderer): void {
public beforeDestroy(): void {}
public draw(renderer: Renderer, overlay: HTMLElement): void {
renderer.addDrawable(this.circle);
renderer.addDrawable(this.light);
}

View file

@ -2,7 +2,7 @@ import { Renderer } from 'sdf-2d';
import { GameObject, UpdateMessage } from 'shared';
export interface ViewObject extends GameObject {
update(updates: Array<UpdateMessage>): void;
step(deltaTimeInMilliseconds: number): void;
draw(renderer: Renderer): void;
draw(renderer: Renderer, overlay: HTMLElement): void;
beforeDestroy(): void;
}