summaryrefslogtreecommitdiff
path: root/engine/entities/Player.ts
blob: 2786b8a2979cd7f6023f4e9256fbc83f784fcfcb (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
import { Entity, EntityNames } from '.';
import { IMAGES, SPRITE_SPECS, Sprites, type SpriteSpec } from '../config';
import {
  Jump,
  FacingDirection,
  BoundingBox,
  Sprite,
  Velocity,
  Gravity,
  WallBounded,
  Forces,
  Collide,
  Mass,
  Moment,
  ComponentNames,
  Control
} from '../components';
import { Direction } from '../interfaces';

export class Player extends Entity {
  private static MASS: number = 10;
  private static MOI: number = 100;

  private static spriteSpec: SpriteSpec = SPRITE_SPECS.get(
    Sprites.COFFEE
  ) as SpriteSpec;

  constructor() {
    super(EntityNames.Player);

    this.addComponent(
      new BoundingBox(
        {
          x: 0,
          y: 0
        },
        { width: Player.spriteSpec.width, height: Player.spriteSpec.height },
        0
      )
    );

    this.addComponent(
      new Velocity({ dCartesian: { dx: 0, dy: 0 }, dTheta: 0 })
    );

    this.addComponent(new Mass(Player.MASS));
    this.addComponent(new Moment(Player.MOI));
    this.addComponent(new Forces());
    this.addComponent(new Gravity());

    this.addComponent(new Jump());

    this.addComponent(new Collide());
    this.addComponent(new WallBounded());

    this.addFacingDirectionComponents();
  }

  private addFacingDirectionComponents() {
    const [leftSprite, rightSprite] = [Direction.LEFT, Direction.RIGHT].map(
      (direction) =>
        new Sprite(
          IMAGES.get(Player.spriteSpec.states!.get(direction)!.sheet!)!,
          { x: 0, y: 0 },
          { width: Player.spriteSpec.width, height: Player.spriteSpec.height },
          Player.spriteSpec.msPerFrame,
          Player.spriteSpec.frames
        )
    );

    this.addComponent(new FacingDirection(leftSprite, rightSprite));
    this.addComponent(leftSprite); // face left by default
  }

  public serialize(): Record<string, any> {
    return {
      control: this.getComponent<Control>(ComponentNames.Control),
      boundingBox: this.getComponent<BoundingBox>(ComponentNames.BoundingBox),
      velocity: this.getComponent<Velocity>(ComponentNames.Velocity),
      forces: this.getComponent<Forces>(ComponentNames.Forces)
    };
  }

  public setFrom(args: Record<string, any>) {
    const { control, forces, velocity, boundingBox } = args;

    let center = boundingBox.center;

    const myCenter = this.getComponent<BoundingBox>(
      ComponentNames.BoundingBox
    ).center;
    const distance = Math.sqrt(
      Math.pow(center.y - myCenter.y, 2) + Math.pow(center.x - myCenter.x, 2)
    );
    const clientServerPredictionCenterThreshold = 15;
    if (distance < clientServerPredictionCenterThreshold) center = myCenter;

    [
      Object.assign(new Control(control.controllableBy), control),
      new Velocity(velocity.velocity),
      new Forces(forces.forces),
      new BoundingBox(center, boundingBox.dimension, boundingBox.rotation)
    ].forEach((component) => this.addComponent(component));
  }
}