This commit is contained in:
schmelczerandras 2020-08-04 22:07:39 +02:00
parent 24cc572e47
commit 345e183e34
30 changed files with 628 additions and 187 deletions

View file

@ -1,33 +1,16 @@
import { vec2 } from 'gl-matrix';
import { Command } from '../commands/command';
import { CommandReceiver } from '../commands/command-receiver';
import { IdentityManager } from '../identity/identity-manager';
import { Objects } from './objects';
import { Physics } from '../physics/physics';
export abstract class GameObject implements CommandReceiver {
public readonly id = IdentityManager.generateId();
protected _position = vec2.create();
public get position(): vec2 {
return this._position;
}
protected _boundingBoxSize = vec2.create();
public get boundingBoxSize(): vec2 {
return this._boundingBoxSize;
}
private commandExecutors: {
[commandType: string]: (e: Command) => void;
} = {};
// can only be called inside the constructor
protected addCommandExecutor<T extends Command>(
commandType: new () => T,
handler: (command: T) => void
) {
this.commandExecutors[new commandType().type] = handler;
}
public reactsToCommand(commandType: string): boolean {
return this.commandExecutors.hasOwnProperty(commandType);
}
@ -39,4 +22,12 @@ export abstract class GameObject implements CommandReceiver {
this.commandExecutors[commandType](command);
}
}
// can only be called inside the constructor
protected addCommandExecutor<T extends Command>(
commandType: new () => T,
handler: (command: T) => void
) {
this.commandExecutors[new commandType().type] = handler;
}
}

View file

@ -3,7 +3,7 @@ import { CommandReceiver } from '../commands/command-receiver';
import { Id } from '../identity/identity';
import { GameObject } from './game-object';
export class ObjectContainer implements CommandReceiver {
export class Objects implements CommandReceiver {
private objects: Map<Id, GameObject> = new Map();
private objectsGroupedByAbilities: Map<string, Array<GameObject>> = new Map();

View file

@ -5,14 +5,20 @@ import { GameObject } from '../game-object';
import { Lamp } from './lamp';
import { ZoomCommand } from '../../input/commands/zoom';
import { MoveToCommand } from '../../physics/commands/move-to';
import { BoundingBox } from '../../physics/containers/bounding-box';
import { Physics } from '../../physics/physics';
export class Camera extends GameObject {
private inViewArea = 1920 * 1080 * 5;
private cursorPosition = vec2.create();
private boundingBox: BoundingBox;
constructor(private light: Lamp) {
constructor(physics: Physics, private light: Lamp) {
super();
this.boundingBox = new BoundingBox(null);
physics.addDynamicBoundingBox(this.boundingBox);
this.addCommandExecutor(BeforeRenderCommand, this.draw.bind(this));
this.addCommandExecutor(MoveToCommand, this.moveTo.bind(this));
this.addCommandExecutor(
@ -22,20 +28,27 @@ export class Camera extends GameObject {
this.addCommandExecutor(ZoomCommand, this.zoom.bind(this));
}
public get viewAreaSize(): vec2 {
return this.boundingBox.size;
}
private draw(c: BeforeRenderCommand) {
c.renderer.setCameraPosition(this.position);
console.log('camera', this.boundingBox.topLeft);
c.renderer.setCameraPosition(this.boundingBox.topLeft);
c.renderer.setCursorPosition(this.cursorPosition);
this._boundingBoxSize = c.renderer.setInViewArea(this.inViewArea);
this.boundingBox.size = c.renderer.setInViewArea(this.inViewArea);
}
private moveTo(c: MoveToCommand) {
this._position = c.position;
console.log('camera', c.position);
this.boundingBox.topLeft = c.position;
this.light.sendCommand(
new MoveToCommand(
vec2.add(
vec2.create(),
c.position,
vec2.scale(vec2.create(), this.boundingBoxSize, 0.5)
vec2.scale(vec2.create(), this.boundingBox.size, 0.5)
)
)
);

View file

@ -1,37 +1,80 @@
import { vec2 } from 'gl-matrix';
import { GameObject } from '../game-object';
import { Camera } from './camera';
import { StepCommand } from '../../physics/commands/step';
import { Circle } from '../../drawing/drawables/primitives/circle';
import { KeyDownCommand } from '../../input/commands/key-down';
import { KeyUpCommand } from '../../input/commands/key-up';
import { SwipeCommand } from '../../input/commands/swipe';
import { MoveToCommand } from '../../physics/commands/move-to';
import { StepCommand } from '../../physics/commands/step';
import { TeleportToCommand } from '../../physics/commands/teleport-to';
import { BoundingBox } from '../../physics/containers/bounding-box';
import { Physics } from '../../physics/physics';
import { GameObject } from '../game-object';
import { Camera } from './camera';
export class Character extends GameObject {
private keysDown: Set<string> = new Set();
private static speed = 0.5;
private primitive: Circle;
private static speed = 1.5;
constructor(private camera: Camera) {
constructor(private physics: Physics, private camera: Camera) {
super();
this.primitive = new Circle(this);
this.primitive.radius = 20;
this.addCommandExecutor(StepCommand, this.stepHandler.bind(this));
this.addCommandExecutor(TeleportToCommand, (c) =>
this.setPosition(c.position)
);
this.addCommandExecutor(KeyDownCommand, (c) => this.keysDown.add(c.key));
this.addCommandExecutor(KeyUpCommand, (c) => this.keysDown.delete(c.key));
this.addCommandExecutor(SwipeCommand, (c) =>
this.setPosition(
this.checkAndSetPosition(
vec2.add(
vec2.create(),
this.position,
vec2.multiply(vec2.create(), c.delta, this.camera.boundingBoxSize)
this.primitive.center,
vec2.multiply(vec2.create(), c.delta, this.camera.viewAreaSize)
)
)
);
}
private checkAndSetPosition(value: vec2) {
const size = this.camera.viewAreaSize;
const realCenter = vec2.fromValues(
value.x + size.x / 2,
value.y + size.y / 2
);
const targetBoundingBox = new BoundingBox(
null,
value.x + size.x / 2,
value.x + size.x / 2 + 10,
value.y + size.y / 2,
value.y + size.y / 2 + 10
);
console.log(
this.physics
.findIntersecting(targetBoundingBox)
.map((b) => b.value.distance(realCenter))
);
if (
this.physics
.findIntersecting(targetBoundingBox)
.map((b) => b.value.distance(realCenter))
.find((d) => d < 0) !== undefined
) {
this.setPosition(value);
}
}
private setPosition(value: vec2) {
this._position = value;
this.camera.sendCommand(new MoveToCommand(this.position));
console.log('character', value);
this.primitive.center = value;
this.camera.sendCommand(new MoveToCommand(this.primitive.center));
}
public stepHandler(c: StepCommand) {
@ -44,16 +87,11 @@ export class Character extends GameObject {
const movementVector = vec2.fromValues(right - left, up - down);
if (movementVector.length > 0) {
this.setPosition(
vec2.add(
vec2.create(),
this.position,
vec2.scale(
vec2.create(),
vec2.normalize(movementVector, movementVector),
Character.speed * deltaTime
)
)
vec2.normalize(movementVector, movementVector);
vec2.scale(movementVector, movementVector, Character.speed * deltaTime);
this.checkAndSetPosition(
vec2.add(vec2.create(), this.primitive.center, movementVector)
);
}
}

View file

@ -10,7 +10,7 @@ export class Lamp extends GameObject {
constructor(center: vec2, radius: number, color: vec3, lightness: number) {
super();
this.light = new CircleLight(center, radius, color, lightness);
this.light = new CircleLight(this, center, radius, color, lightness);
this.addCommandExecutor(RenderCommand, this.draw.bind(this));
this.addCommandExecutor(MoveToCommand, this.moveTo.bind(this));

View file

@ -1,16 +1,25 @@
import { vec2 } from 'gl-matrix';
import { TunnelShape } from '../../drawing/drawables/primitives/tunnel-shape';
import { GameObject } from '../game-object';
import { RenderCommand } from '../../drawing/commands/render';
import { Physics } from '../../physics/physics';
import { TunnelShape } from '../../drawing/drawables/primitives/tunnel-shape';
export interface Line {}
export class Tunnel extends GameObject {
private primitive: TunnelShape;
constructor(from: vec2, to: vec2, fromRadius: number, toRadius: number) {
constructor(
physics: Physics,
public readonly from: vec2,
to: vec2,
fromRadius: number,
toRadius: number
) {
super();
this.primitive = new TunnelShape(from, to, fromRadius, toRadius);
this.primitive = new TunnelShape(this, from, to, fromRadius, toRadius);
physics.addStaticBoundingBox(this.primitive.boundingBox);
this.addCommandExecutor(RenderCommand, this.draw.bind(this));
}

View file

@ -1,10 +1,15 @@
import { vec2, vec3 } from 'gl-matrix';
import { ObjectContainer } from '../object-container';
import { Objects } from '../objects';
import { Camera } from '../types/camera';
import { Character } from '../types/character';
import { Lamp } from '../types/lamp';
import { Physics } from '../../physics/physics';
import { GameObject } from '../game-object';
export const createCharacter = (objects: ObjectContainer) => {
export const createCharacter = (
objects: Objects,
physics: Physics
): GameObject => {
const light = new Lamp(
vec2.create(),
40,
@ -12,8 +17,11 @@ export const createCharacter = (objects: ObjectContainer) => {
2
);
const camera = new Camera(light);
const camera = new Camera(physics, light);
const character = new Character(physics, camera);
objects.addObject(light);
objects.addObject(camera);
objects.addObject(new Character(camera));
objects.addObject(character);
return character;
};

View file

@ -1,22 +1,35 @@
import { vec2, vec3 } from 'gl-matrix';
import { ObjectContainer } from '../object-container';
import { Lamp } from '../types/lamp';
import { Objects } from '../objects';
import { Tunnel } from '../types/tunnel';
import { Physics } from '../../physics/physics';
import { GameObject } from '../game-object';
export const createDungeon = (objects: ObjectContainer) => {
export const createDungeon = (objects: Objects, physics: Physics): Tunnel => {
let previousRadius = 350;
let previousEnd = vec2.create();
for (let i = 0; i < 500000; i += 500) {
let first: Tunnel;
for (let i = 0; i < 1; i += 500) {
const deltaHeight = (Math.random() - 0.5) * 2000;
const height = previousEnd.y + deltaHeight;
const currentEnd = vec2.fromValues(i, height);
const currentToRadius = Math.random() * 300 + 150;
objects.addObject(
new Tunnel(previousEnd, currentEnd, previousRadius, currentToRadius)
const tunnel = new Tunnel(
physics,
previousEnd,
currentEnd,
previousRadius,
currentToRadius
);
if (!first) {
first = tunnel;
}
objects.addObject(tunnel);
/*if (deltaHeight > 0 && Math.random() > 0.8) {
objects.addObject(
new Lamp(
@ -35,4 +48,6 @@ export const createDungeon = (objects: ObjectContainer) => {
previousEnd = currentEnd;
previousRadius = currentToRadius;
}
return first;
};