caixanegra 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,310 @@
1
+ window.Sabertooth = {
2
+ TARGET_FPS: 30,
3
+ UPSCALE_FACTOR: 2,
4
+ Utils: {
5
+ generateOId: () => { return Math.floor((1 + Math.random()) * 0x100000000).toString(16).substring(1); }
6
+ },
7
+
8
+ Vector2: class {
9
+ x;
10
+ y;
11
+
12
+ constructor(x, y) {
13
+ this.x = x;
14
+ this.y = y;
15
+ }
16
+
17
+ add(vector) {
18
+ const resultVector = Sabertooth.Vector2.add(this, vector);
19
+ this.x = resultVector.x;
20
+ this.y = resultVector.y;
21
+ }
22
+
23
+ subtract(vector) {
24
+ const resultVector = Sabertooth.Vector2.subtract(this, vector);
25
+ this.x = resultVector.x;
26
+ this.y = resultVector.y;
27
+ }
28
+
29
+ clone() {
30
+ return new Sabertooth.Vector2(this.x, this.y);
31
+ }
32
+
33
+ toAnonObject() {
34
+ return { x: this.x, y: this.y };
35
+ }
36
+
37
+ static add(vectorA, vectorB) {
38
+ return new Sabertooth.Vector2(vectorA.x + vectorB.x, vectorA.y + vectorB.y);
39
+ }
40
+
41
+ static subtract(vectorA, vectorB) {
42
+ return new Sabertooth.Vector2(vectorA.x - vectorB.x, vectorA.y - vectorB.y);
43
+ }
44
+ },
45
+
46
+ Rectangle: class {
47
+ position;
48
+ size;
49
+
50
+ constructor(position, size) {
51
+ this.position = position;
52
+ this.size = size;
53
+ }
54
+
55
+ edges() {
56
+ return {
57
+ top: this.position.y,
58
+ bottom: this.position.y + this.size.y,
59
+ right: this.position.x + this.size.x,
60
+ left: this.position.x
61
+ };
62
+ }
63
+
64
+ intersectionPoint(point) {
65
+ const checks = {
66
+ horizontal: point.x >= this.position.x && point.x <= this.position.x + this.size.x,
67
+ vertical: point.y >= this.position.y && point.y <= this.position.y + this.size.y,
68
+ };
69
+
70
+ if (checks.horizontal && checks.vertical) {
71
+ return new Sabertooth.Vector2(point.x - this.position.x, point.y - this.position.y);
72
+ }
73
+
74
+ return false;
75
+ }
76
+ },
77
+
78
+ ElapsedTime: class {
79
+ #startDate;
80
+
81
+ start() {
82
+ this.#startDate = new Date();
83
+ }
84
+
85
+ end() {
86
+ return new Date() - this.#startDate;
87
+ }
88
+ },
89
+
90
+ Object: class {
91
+ oid;
92
+ position;
93
+ size;
94
+ zIndex = 0;
95
+
96
+ constructor(params = {}) {
97
+ this.oid = params.oid || Sabertooth.Utils.generateOId();
98
+ this.position = params.position || new Sabertooth.Vector2(0, 0);
99
+ this.size = params.size || new Sabertooth.Vector2(0, 0);
100
+ this.zIndex = params.zIndex;
101
+ }
102
+
103
+ getPosition(referential) {
104
+ return Sabertooth.Vector2.add(referential, this.position);
105
+ }
106
+
107
+ getRectangle() {
108
+ return new Sabertooth.Rectangle(this.position, this.size);
109
+ }
110
+
111
+ getCenter(referential) {
112
+ return Sabertooth.Vector2.add(
113
+ this.getPosition(referential),
114
+ new Sabertooth.Vector2(this.size.x / 2, this.size.y / 2)
115
+ );
116
+ }
117
+
118
+ update() {}
119
+ draw() {}
120
+ },
121
+
122
+ Engine: class {
123
+ #objects;
124
+ ctx;
125
+ running;
126
+ debugging = false;
127
+ worldCenter;
128
+ #lastFrame;
129
+ #mouse;
130
+ drawPasses;
131
+
132
+ constructor(drawSurface) {
133
+ this.drawPasses = ["base"];
134
+ this.#lastFrame = { moment: new Date(), lastSecond: new Date(), frameCount: 0, fps: 0 };
135
+ this.#objects = new Array();
136
+ this.#mouse = {};
137
+ this.ctx = drawSurface.getContext("2d", {alpha: false});
138
+ this.worldCenter = new Sabertooth.Vector2(0, 0);
139
+ drawSurface.addEventListener("mousedown", this.#mouseHandler.bind(this));
140
+ drawSurface.addEventListener("mouseup", this.#mouseHandler.bind(this));
141
+ drawSurface.addEventListener("mousemove", this.#mouseHandler.bind(this));
142
+ this.enable();
143
+ }
144
+
145
+ clear() {
146
+ this.#objects = [];
147
+ }
148
+
149
+ enable() {
150
+ this.running = true;
151
+ this.#requestFrame();
152
+ }
153
+
154
+ disable() { this.running = false; }
155
+
156
+ addObject(object) {
157
+ object.initialize(this.engineContext());
158
+
159
+ this.#objects.push(object);
160
+
161
+ this.#objects.sort((oA, oB) => {
162
+ return oA.zIndex - oB.zIndex;
163
+ });
164
+ }
165
+
166
+ removeObject(oid) {
167
+ const killIndex = this.#objects.findIndex((object) => {return object.oid === oid});
168
+ this.#objects.splice(killIndex, 1);
169
+ }
170
+
171
+ engineContext() {
172
+ return {
173
+ context2d: this.ctx,
174
+ referential: this.worldCenter,
175
+ objects: this.#objects,
176
+ canvas: {
177
+ height: this.ctx.canvas.clientHeight * Sabertooth.UPSCALE_FACTOR,
178
+ width: this.ctx.canvas.clientWidth * Sabertooth.UPSCALE_FACTOR
179
+ },
180
+ mouse: this.#mouse
181
+ };
182
+ }
183
+
184
+ #update() {
185
+ const event = new CustomEvent("update_start", { detail: this.engineContext() });
186
+ this.ctx.canvas.dispatchEvent(event);
187
+
188
+ for (let oidx = 0; oidx < this.#objects.length; oidx++) {
189
+ this.#objects[oidx].update(this.engineContext());
190
+ }
191
+ }
192
+
193
+ #draw() {
194
+ const eCtx = this.engineContext();
195
+ this.ctx.clearRect(0, 0, eCtx.canvas.width, eCtx.canvas.height);
196
+ this.ctx.fillStyle = "#333";
197
+ this.ctx.fillRect(0, 0, eCtx.canvas.width, eCtx.canvas.height);
198
+
199
+ this.drawPasses.forEach((pass) => {
200
+ for (let oidx = 0; oidx < this.#objects.length; oidx++) {
201
+ this.#objects[oidx].draw(eCtx, pass);
202
+ }
203
+ });
204
+ }
205
+
206
+ #requestFrame() {
207
+ if (!this.running) return;
208
+
209
+ requestAnimationFrame(this.#frame.bind(this));
210
+ setTimeout(this.#requestFrame.bind(this), 1000 / Sabertooth.TARGET_FPS);
211
+ }
212
+
213
+ #frame() {
214
+ const perfValues = {};
215
+ const et = new Sabertooth.ElapsedTime();
216
+
217
+ et.start();
218
+ this.#update();
219
+ perfValues.update = et.end();
220
+ et.start();
221
+ this.#draw();
222
+ perfValues.draw = et.end();
223
+
224
+ const endMoment = new Date();
225
+ perfValues.frame = endMoment - this.#lastFrame.moment;
226
+ this.#lastFrame.frameCount += 1;
227
+ if ((endMoment - this.#lastFrame.lastSecond) > 1000) {
228
+ this.#lastFrame.fps = this.#lastFrame.frameCount;
229
+ this.#lastFrame.frameCount = 1;
230
+ this.#lastFrame.lastSecond = endMoment;
231
+ }
232
+
233
+ if (this.debugging) {
234
+ this.ctx.fillStyle = "#FFF";
235
+ this.ctx.font = "20px monospace";
236
+ this.ctx.textAlign = "left";
237
+ this.ctx.textBaseline = "top";
238
+ this.ctx.fillText(`U: ${perfValues.update}ms | D: ${perfValues.update}ms | F: ${perfValues.update}ms | FPS: ${this.#lastFrame.fps}`, 5, 5);
239
+ }
240
+
241
+ this.#lastFrame.moment = endMoment;
242
+ }
243
+
244
+ #mouseHandler(evt) {
245
+ const interactionSnapshot = {
246
+ button: evt.which,
247
+ x: evt.x * Sabertooth.UPSCALE_FACTOR - this.worldCenter.x,
248
+ y: evt.y * Sabertooth.UPSCALE_FACTOR - this.worldCenter.y,
249
+ internal_x: evt.x * Sabertooth.UPSCALE_FACTOR,
250
+ internal_y: evt.y * Sabertooth.UPSCALE_FACTOR,
251
+ referential: new Sabertooth.Vector2(this.worldCenter.x, this.worldCenter.y),
252
+ cursorAt: null
253
+ }
254
+
255
+ const objectAtPointer = this.#objectAt(
256
+ interactionSnapshot.x, interactionSnapshot.y
257
+ );
258
+ if (objectAtPointer) {
259
+ interactionSnapshot.cursorAt = {
260
+ object: objectAtPointer,
261
+ intersection: objectAtPointer.getRectangle().intersectionPoint(
262
+ new Sabertooth.Vector2(interactionSnapshot.x, interactionSnapshot.y)
263
+ )
264
+ }
265
+ }
266
+
267
+ switch(evt.type) {
268
+ case "mousedown":
269
+ this.#mouse.down = interactionSnapshot;
270
+ break;
271
+ case "mouseup":
272
+ this.#mouse.up = interactionSnapshot;
273
+
274
+ const event = new CustomEvent(
275
+ ( this.#mouse.up.x === this.#mouse.down.x &&
276
+ this.#mouse.up.y === this.#mouse.down.y) ? "clicked" : "drag_finished", {
277
+ detail: {
278
+ start: this.#mouse.down,
279
+ end: this.#mouse.up
280
+ }
281
+ });
282
+ this.ctx.canvas.dispatchEvent(event);
283
+
284
+ delete this.#mouse.down;
285
+ delete this.#mouse.move;
286
+ break;
287
+ case "mousemove":
288
+ this.#mouse.move = interactionSnapshot;
289
+ break;
290
+ }
291
+ }
292
+
293
+ #objectAt(x, y) {
294
+ let objectFound = null;
295
+
296
+ for (let oidx = 0; oidx < this.#objects.length; oidx++) {
297
+ const currentObject = this.#objects[oidx];
298
+ if (currentObject.getRectangle().intersectionPoint(new Sabertooth.Vector2(x, y))) {
299
+ if (objectFound === null) {
300
+ objectFound = currentObject;
301
+ } else if (objectFound.zIndex < currentObject.zIndex) {
302
+ objectFound = currentObject;
303
+ }
304
+ }
305
+ }
306
+
307
+ return objectFound;
308
+ }
309
+ }
310
+ }
@@ -0,0 +1,15 @@
1
+ /*
2
+ * This is a manifest file that'll be compiled into application.css, which will include all the files
3
+ * listed below.
4
+ *
5
+ * Any CSS and SCSS file within this directory, lib/assets/stylesheets, vendor/assets/stylesheets,
6
+ * or any plugin's vendor/assets/stylesheets directory can be referenced here using a relative path.
7
+ *
8
+ * You're free to add application-wide styles to this file and they'll appear at the bottom of the
9
+ * compiled file so the styles you add here take precedence over styles defined in any other CSS/SCSS
10
+ * files in this directory. Styles in this file should be added after the last require_* statement.
11
+ * It is generally better to create a new file per style scope.
12
+ *
13
+ *= require_tree .
14
+ *= require_self
15
+ */