UNPKG

7.05 kBJavaScriptView Raw
1"use strict";
2
3/**
4 * The base in-game object, it supports a location and velocity.
5 * Entities are boxes, consisting of an x,y coordinate along with a width and height.
6 * Entities have basic collision detection and resolution.
7 * @constructor
8 * @alias Splat.Entity
9 * @param {number} x The top-left x coordinate
10 * @param {number} y The top-left y coordinate
11 * @param {number} width The width on the x-axis
12 * @param {number} height The height on the y-axis
13 */
14function Entity(x, y, width, height) {
15 /**
16 * Leftmost position along the x-axis.
17 * @member {number}
18 */
19 this.x = x;
20 /**
21 * Topmost position along the y-axis.
22 * @member {number}
23 */
24 this.y = y;
25 /**
26 * Width of the Entity, extending to the right of {@link Splat.Entity#x}.
27 * @member {number}
28 */
29 this.width = width;
30 /**
31 * Height of the Entity, extending downward from {@link Splat.Entity#y}.
32 * @member {number}
33 */
34 this.height = height;
35 /**
36 * Velocity along the x-axis in pixels/millisecond.
37 * @member {number}
38 */
39 this.vx = 0;
40 /**
41 * Velocity along the y-axis in pixels/millisecond.
42 * @member {number}
43 */
44 this.vy = 0;
45 /**
46 * The value of {@link Splat.Entity#x} in the previous frame.
47 * @member {number}
48 * @readonly
49 */
50 this.lastX = x;
51 /**
52 * The value of {@link Splat.Entity#y} in the previous frame.
53 * @member {number}
54 * @readonly
55 */
56 this.lastY = y;
57 /**
58 * A multiplier on {@link Splat.Entity#vx}. Can be used to implement basic friction.
59 * @member {number}
60 * @private
61 */
62 this.frictionX = 1;
63 /**
64 * A multiplier on {@link Splat.Entity#vy}. Can be used to implement basic friction.
65 * @member {number}
66 * @private
67 */
68 this.frictionY = 1;
69}
70/**
71 * Simulate movement since the previous frame, changing {@link Splat.Entity#x} and {@link Splat.Entity#y} as necessary.
72 * @param {number} elapsedMillis The number of milliseconds since the previous frame.
73 */
74Entity.prototype.move = function(elapsedMillis) {
75 this.lastX = this.x;
76 this.lastY = this.y;
77 this.x += elapsedMillis * this.vx;
78 this.y += elapsedMillis * this.vy;
79 this.vx *= this.frictionX;
80 this.vy *= this.frictionY;
81};
82/**
83 * Test if this Entity horizontally overlaps another.
84 * @param {Splat.Entity} other The Entity to test for overlap with
85 * @returns {boolean}
86 */
87Entity.prototype.overlapsHoriz = function(other) {
88 return this.x + this.width >= other.x && this.x <= other.x + other.width;
89};
90/**
91 * Test if this Entity vertically overlaps another.
92 * @param {Splat.Entity} other The Entity to test for overlap with
93 * @returns {boolean}
94 */
95Entity.prototype.overlapsVert = function(other) {
96 return this.y + this.height >= other.y && this.y <= other.y + other.height;
97};
98/**
99 * Test if this Entity is currently colliding with another.
100 * @param {Splat.Entity} other The Entity to test for collision with
101 * @returns {boolean}
102 */
103Entity.prototype.collides = function(other) {
104 return this.overlapsHoriz(other) && this.overlapsVert(other);
105};
106
107/**
108 * Test if this Entity horizontally overlapped another in the previous frame.
109 * @param {Splat.Entity} other The Entity to test for overlap with
110 * @returns {boolean}
111 */
112Entity.prototype.didOverlapHoriz = function(other) {
113 return this.lastX + this.width >= other.lastX && this.lastX <= other.lastX + other.width;
114};
115/**
116 * Test if this Entity vertically overlapped another in the previous frame.
117 * @param {Splat.Entity} other The Entity to test for overlap with
118 * @returns {boolean}
119 */
120Entity.prototype.didOverlapVert = function(other) {
121 return this.lastY + this.height >= other.lastY && this.lastY <= other.lastY + other.height;
122};
123
124/**
125 * Test if this Entity was above another in the previous frame.
126 * @param {Splat.Entity} other The Entity to test for above-ness with
127 * @returns {boolean}
128 */
129Entity.prototype.wasAbove = function(other) {
130 return this.lastY + this.height <= other.lastY;
131};
132/**
133 * Test if this Entity was below another in the previous frame.
134 * @param {Splat.Entity} other The Entity to test for below-ness with
135 * @returns {boolean}
136 */
137Entity.prototype.wasBelow = function(other) {
138 return this.lastY >= other.lastY + other.height;
139};
140/**
141 * Test if this Entity was to the left of another in the previous frame.
142 * @param {Splat.Entity} other The Entity to test for left-ness with
143 * @returns {boolean}
144 */
145Entity.prototype.wasLeft = function(other) {
146 return this.lastX + this.width <= other.lastX;
147};
148/**
149 * Test if this Entity was to the right of another in the previous frame.
150 * @param {Splat.Entity} other The Entity to test for right-ness with
151 * @returns {boolean}
152 */
153Entity.prototype.wasRight = function(other) {
154 return this.lastX >= other.lastX + other.width;
155};
156
157/**
158 * Test if this Entity has changed position since the previous frame.
159 * @returns {boolean}
160 */
161Entity.prototype.moved = function() {
162 var x = this.x|0;
163 var lastX = this.lastX|0;
164 var y = this.y|0;
165 var lastY = this.lastY|0;
166 return (x !== lastX) || (y !== lastY);
167};
168
169Entity.prototype.draw = function() {
170 // draw bounding boxes
171 // context.strokeStyle = "#ff0000";
172 // context.strokeRect(this.x, this.y, this.width, this.height);
173};
174
175/**
176 * Adjust the Entity's position so its bottom edge does not penetrate the other Entity's top edge.
177 * {@link Splat.Entity#vy} is also zeroed.
178 * @param {Splat.Entity} other
179 */
180Entity.prototype.resolveBottomCollisionWith = function(other) {
181 if (this.didOverlapHoriz(other) && this.wasAbove(other)) {
182 this.y = other.y - this.height;
183 this.vy = 0;
184 }
185};
186/**
187 * Adjust the Entity's position so its top edge does not penetrate the other Entity's bottom edge.
188 * {@link Splat.Entity#vy} is also zeroed.
189 * @param {Splat.Entity} other
190 */
191Entity.prototype.resolveTopCollisionWith = function(other) {
192 if (this.didOverlapHoriz(other) && this.wasBelow(other)) {
193 this.y = other.y + other.height;
194 this.vy = 0;
195 }
196};
197/**
198 * Adjust the Entity's position so its right edge does not penetrate the other Entity's left edge.
199 * {@link Splat.Entity#vx} is also zeroed.
200 * @param {Splat.Entity} other
201 */
202Entity.prototype.resolveRightCollisionWith = function(other) {
203 if (this.didOverlapVert(other) && this.wasLeft(other)) {
204 this.x = other.x - this.width;
205 this.vx = 0;
206 }
207};
208/**
209 * Adjust the Entity's position so its left edge does not penetrate the other Entity's right edge.
210 * {@link Splat.Entity#vx} is also zeroed.
211 * @param {Splat.Entity} other
212 */
213Entity.prototype.resolveLeftCollisionWith = function(other) {
214 if (this.didOverlapVert(other) && this.wasRight(other)) {
215 this.x = other.x + other.width;
216 this.vx = 0;
217 }
218};
219/**
220 * Adjust the Entity's position so it does not penetrate the other Entity.
221 * {@link Splat.Entity#vx} will be zeroed if {@link Splat.Entity#x} was adjusted, and {@link Splat.Entity#vy} will be zeroed if {@link Splat.Entity#y} was adjusted.
222 * @param {Splat.Entity} other
223 */
224Entity.prototype.resolveCollisionWith = function(other) {
225 this.resolveBottomCollisionWith(other);
226 this.resolveTopCollisionWith(other);
227 this.resolveRightCollisionWith(other);
228 this.resolveLeftCollisionWith(other);
229};
230
231module.exports = Entity;