1 | ;
|
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 | */
|
14 | function 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 | */
|
74 | Entity.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 | */
|
87 | Entity.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 | */
|
95 | Entity.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 | */
|
103 | Entity.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 | */
|
112 | Entity.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 | */
|
120 | Entity.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 | */
|
129 | Entity.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 | */
|
137 | Entity.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 | */
|
145 | Entity.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 | */
|
153 | Entity.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 | */
|
161 | Entity.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 |
|
169 | Entity.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 | */
|
180 | Entity.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 | */
|
191 | Entity.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 | */
|
202 | Entity.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 | */
|
213 | Entity.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 | */
|
224 | Entity.prototype.resolveCollisionWith = function(other) {
|
225 | this.resolveBottomCollisionWith(other);
|
226 | this.resolveTopCollisionWith(other);
|
227 | this.resolveRightCollisionWith(other);
|
228 | this.resolveLeftCollisionWith(other);
|
229 | };
|
230 |
|
231 | module.exports = Entity;
|