malc-game-engine 1.0.1 → 1.0.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/malc.js +1065 -1040
- package/malc.min.js +299 -0
- package/package.json +1 -1
package/malc.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* MALC Game Engine Library
|
|
3
|
-
* Version: 1.0.
|
|
3
|
+
* Version: 1.0.3
|
|
4
4
|
* Description: A comprehensive 2D game engine for p5.js
|
|
5
5
|
*/
|
|
6
6
|
|
|
@@ -17,6 +17,9 @@
|
|
|
17
17
|
}
|
|
18
18
|
}(typeof self !== 'undefined' ? self : this, function(p5) {
|
|
19
19
|
|
|
20
|
+
// Store reference to p5 instance
|
|
21
|
+
const _p5 = p5;
|
|
22
|
+
|
|
20
23
|
// ========== GLOBAL ARRAYS ==========
|
|
21
24
|
const MALCgameObjects = [];
|
|
22
25
|
const MALCbuttons = [];
|
|
@@ -37,1121 +40,1213 @@ function generateId(prefix) {
|
|
|
37
40
|
return `${prefix}_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
|
|
38
41
|
}
|
|
39
42
|
|
|
40
|
-
// ==========
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
43
|
+
// ========== COLORED TEXT FUNCTIONS (SAFE VERSION) ==========
|
|
44
|
+
function parseColoredLine(str) {
|
|
45
|
+
const regex = /\\([^|\\\n]+)\|([^|]+)\|/g;
|
|
46
|
+
const parts = [];
|
|
47
|
+
let lastIndex = 0;
|
|
48
|
+
let match;
|
|
46
49
|
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
+
while ((match = regex.exec(str)) !== null) {
|
|
51
|
+
if (match.index > lastIndex) {
|
|
52
|
+
parts.push({
|
|
53
|
+
text: str.substring(lastIndex, match.index),
|
|
54
|
+
color: null
|
|
55
|
+
});
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
parts.push({
|
|
59
|
+
text: match[2],
|
|
60
|
+
color: match[1]
|
|
50
61
|
});
|
|
62
|
+
|
|
63
|
+
lastIndex = match.index + match[0].length;
|
|
51
64
|
}
|
|
52
65
|
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
// Update all active objects
|
|
58
|
-
MALCgameObjects.forEach(o => {
|
|
59
|
-
if (o.active) o.update();
|
|
66
|
+
if (lastIndex < str.length) {
|
|
67
|
+
parts.push({
|
|
68
|
+
text: str.substring(lastIndex),
|
|
69
|
+
color: null
|
|
60
70
|
});
|
|
61
71
|
}
|
|
72
|
+
|
|
73
|
+
return parts.length ? parts : [{ text: str, color: null }];
|
|
74
|
+
}
|
|
62
75
|
|
|
63
|
-
|
|
64
|
-
|
|
76
|
+
function parseColoredText(str) {
|
|
77
|
+
const lines = str.split('\n');
|
|
78
|
+
const result = [];
|
|
79
|
+
|
|
80
|
+
for (let i = 0; i < lines.length; i++) {
|
|
81
|
+
const line = lines[i];
|
|
82
|
+
const parts = parseColoredLine(line);
|
|
65
83
|
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
84
|
+
result.push(...parts);
|
|
85
|
+
|
|
86
|
+
if (i < lines.length - 1) {
|
|
87
|
+
result.push({
|
|
88
|
+
text: '\n',
|
|
89
|
+
color: null,
|
|
90
|
+
isNewline: true
|
|
73
91
|
});
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
return result;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
function renderColoredText(p, str, x, y, horizontal, vertical, maxWidth) {
|
|
99
|
+
const parts = parseColoredText(str);
|
|
100
|
+
let currentX = x;
|
|
101
|
+
let currentY = y;
|
|
102
|
+
|
|
103
|
+
p.push();
|
|
104
|
+
p.textAlign(horizontal, vertical);
|
|
105
|
+
|
|
106
|
+
for (const part of parts) {
|
|
107
|
+
if (part.isNewline) {
|
|
108
|
+
currentX = x;
|
|
109
|
+
currentY += p.textLeading() || p.textSize() * 1.2;
|
|
110
|
+
continue;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
if (part.color) {
|
|
114
|
+
try {
|
|
115
|
+
p.fill(part.color);
|
|
116
|
+
} catch (e) {
|
|
117
|
+
p.fill(255);
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
p.text(part.text, currentX, currentY, maxWidth);
|
|
122
|
+
currentX += p.textWidth(part.text);
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
p.pop();
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
// ========== SCENE CLASS (DEFINED FIRST) ==========
|
|
129
|
+
class Scene {
|
|
130
|
+
static scenes = [];
|
|
131
|
+
static activeScene = "blank";
|
|
132
|
+
static started = false;
|
|
133
|
+
static sceneHistory = [];
|
|
134
|
+
static historyLimit = 10;
|
|
135
|
+
|
|
136
|
+
static update() {
|
|
137
|
+
this.started = true;
|
|
138
|
+
this.scenes = MALCScene;
|
|
139
|
+
|
|
140
|
+
let activeSceneFound = false;
|
|
141
|
+
|
|
142
|
+
this.scenes.forEach(S => {
|
|
143
|
+
if (S.id == this.activeScene) {
|
|
144
|
+
activeSceneFound = true;
|
|
145
|
+
|
|
146
|
+
this.scenes.forEach(s => {
|
|
147
|
+
if (s != S) {
|
|
148
|
+
s._active = false;
|
|
149
|
+
s.active = false;
|
|
150
|
+
|
|
151
|
+
s.objects.forEach(o => {
|
|
152
|
+
if (o && typeof o.active !== 'undefined') o.active = false;
|
|
153
|
+
});
|
|
154
|
+
}
|
|
155
|
+
});
|
|
156
|
+
|
|
157
|
+
S.active = true;
|
|
158
|
+
|
|
159
|
+
if (!S._active) {
|
|
160
|
+
S.activated = MALC.time.getTime();
|
|
161
|
+
if (typeof S.onActivate == 'function') S.onActivate();
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
S._active = true;
|
|
165
|
+
S.timeActive = MALC.time.getTime() - S.activated;
|
|
166
|
+
|
|
167
|
+
S.objects.forEach(o => {
|
|
168
|
+
if (o && typeof o.active !== 'undefined') o.active = true;
|
|
169
|
+
});
|
|
170
|
+
|
|
171
|
+
_p5.prototype.push();
|
|
172
|
+
if (window.camera && typeof window.camera.render == 'function') {
|
|
173
|
+
window.camera.render();
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
S.render();
|
|
177
|
+
|
|
178
|
+
_p5.prototype.pop();
|
|
179
|
+
}
|
|
74
180
|
});
|
|
181
|
+
|
|
182
|
+
if (!activeSceneFound && this.activeScene != "blank") {
|
|
183
|
+
console.warn(`Scene "${this.activeScene}" not found, switching to blank`);
|
|
184
|
+
this.activeScene = "blank";
|
|
185
|
+
}
|
|
75
186
|
}
|
|
76
187
|
|
|
77
|
-
static
|
|
78
|
-
return
|
|
188
|
+
static getSceneById(id) {
|
|
189
|
+
return MALCScene.find(scene => scene.id == id) || null;
|
|
79
190
|
}
|
|
80
191
|
|
|
81
|
-
static
|
|
82
|
-
return
|
|
192
|
+
static getActiveScene() {
|
|
193
|
+
return this.getSceneById(this.activeScene);
|
|
83
194
|
}
|
|
84
195
|
|
|
85
|
-
static
|
|
86
|
-
let scene =
|
|
87
|
-
|
|
196
|
+
static switchToScene(id, addToHistory = true) {
|
|
197
|
+
let scene = this.getSceneById(id);
|
|
198
|
+
if (scene) {
|
|
199
|
+
if (addToHistory && this.activeScene) {
|
|
200
|
+
this.sceneHistory.push(this.activeScene);
|
|
201
|
+
if (this.sceneHistory.length > this.historyLimit) {
|
|
202
|
+
this.sceneHistory.shift();
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
this.activeScene = id;
|
|
206
|
+
} else {
|
|
207
|
+
console.error(`Cannot switch to scene "${id}" - not found`);
|
|
208
|
+
}
|
|
88
209
|
}
|
|
89
210
|
|
|
90
|
-
static
|
|
91
|
-
this.
|
|
211
|
+
static goBack() {
|
|
212
|
+
if (this.sceneHistory.length > 0) {
|
|
213
|
+
let previousScene = this.sceneHistory.pop();
|
|
214
|
+
this.switchToScene(previousScene, false);
|
|
215
|
+
return true;
|
|
216
|
+
}
|
|
217
|
+
return false;
|
|
92
218
|
}
|
|
93
219
|
|
|
94
|
-
static
|
|
95
|
-
return
|
|
220
|
+
static getAllScenes() {
|
|
221
|
+
return [...MALCScene];
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
static getScenesWithObject(object) {
|
|
225
|
+
return MALCScene.filter(scene => scene.objects.includes(object));
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
static getScenesByTag(tag) {
|
|
229
|
+
return MALCScene.filter(scene => scene.hasTag(tag));
|
|
96
230
|
}
|
|
97
231
|
|
|
98
|
-
constructor(
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
this.rotation = 0;
|
|
105
|
-
this.rotationMode = "degrees";
|
|
106
|
-
this.velocity = [0, 0];
|
|
107
|
-
this.velocityMatrix = [0, 0];
|
|
108
|
-
this.velocityMode = "polar";
|
|
109
|
-
this.rvm = "unlinked";
|
|
110
|
-
|
|
111
|
-
// Gravity properties
|
|
112
|
-
this.gravity = {
|
|
113
|
-
enabled: false,
|
|
114
|
-
velocity: 0,
|
|
115
|
-
grounded: false,
|
|
116
|
-
groundTolerance: 1, // pixels
|
|
117
|
-
mass: 1,
|
|
118
|
-
bounce: 0, // 0 = no bounce, 1 = full bounce
|
|
119
|
-
friction: 0.1 // ground friction
|
|
120
|
-
};
|
|
232
|
+
constructor(id, backgroundColor, ...scripts) {
|
|
233
|
+
MALCScene.forEach(s => {
|
|
234
|
+
if (s.id == id || typeof id != "string") {
|
|
235
|
+
throw new Error(`Scenes must have unique IDs and be strings. Duplicate/Invalid ID: "${id}"`);
|
|
236
|
+
}
|
|
237
|
+
});
|
|
121
238
|
|
|
122
|
-
this.
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
};
|
|
239
|
+
this.id = id;
|
|
240
|
+
this.backColor = backgroundColor;
|
|
241
|
+
this.scripts = scripts;
|
|
126
242
|
|
|
127
|
-
this.
|
|
243
|
+
this.objects = [];
|
|
244
|
+
this.uiPlanes = [];
|
|
128
245
|
|
|
129
|
-
this.scripts = [];
|
|
130
|
-
this.scenes = scenes.length < 1 ? ["blank"] : [...new Set(scenes)];
|
|
131
246
|
this.active = false;
|
|
132
|
-
this.
|
|
133
|
-
this.
|
|
134
|
-
|
|
135
|
-
this.debug = false;
|
|
136
|
-
this.hitbox = {
|
|
137
|
-
x: 0,
|
|
138
|
-
y: 0,
|
|
139
|
-
width: 0,
|
|
140
|
-
height: 0,
|
|
141
|
-
rotation: 0,
|
|
142
|
-
parts: null,
|
|
143
|
-
outline: 1,
|
|
144
|
-
};
|
|
247
|
+
this._active = false;
|
|
248
|
+
this.activated = 0;
|
|
249
|
+
this.timeActive = -1;
|
|
145
250
|
|
|
146
|
-
this.
|
|
147
|
-
this.
|
|
251
|
+
this.tags = [];
|
|
252
|
+
this.paused = false;
|
|
253
|
+
this.transition = null;
|
|
254
|
+
this.onActivateCallbacks = [];
|
|
255
|
+
this.onDeactivateCallbacks = [];
|
|
256
|
+
this.onUpdateCallbacks = [];
|
|
148
257
|
|
|
149
|
-
|
|
258
|
+
this.sceneInstance = MALCScene.length;
|
|
259
|
+
MALCScene.push(this);
|
|
150
260
|
}
|
|
151
261
|
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
this.gravity.enabled = true;
|
|
155
|
-
return this;
|
|
156
|
-
}
|
|
157
|
-
|
|
158
|
-
// Disable gravity for this object
|
|
159
|
-
disableGravity() {
|
|
160
|
-
this.gravity.enabled = false;
|
|
161
|
-
this.gravity.velocity = 0;
|
|
162
|
-
return this;
|
|
163
|
-
}
|
|
164
|
-
|
|
165
|
-
// Set gravity parameters
|
|
166
|
-
setGravity(options = {}) {
|
|
167
|
-
if (options.enabled !== undefined) this.gravity.enabled = options.enabled;
|
|
168
|
-
if (options.mass !== undefined) this.gravity.mass = Math.max(0.1, options.mass);
|
|
169
|
-
if (options.bounce !== undefined) this.gravity.bounce = Math.min(1, Math.max(0, options.bounce));
|
|
170
|
-
if (options.friction !== undefined) this.gravity.friction = Math.min(1, Math.max(0, options.friction));
|
|
171
|
-
if (options.groundTolerance !== undefined) this.gravity.groundTolerance = options.groundTolerance;
|
|
172
|
-
return this;
|
|
173
|
-
}
|
|
174
|
-
|
|
175
|
-
// Apply gravity to this object
|
|
176
|
-
applyGravity() {
|
|
177
|
-
if (!this.gravity.enabled) return;
|
|
178
|
-
|
|
179
|
-
// Apply gravity acceleration (scaled by mass)
|
|
180
|
-
this.gravity.velocity += gameObject.gravity * this.gravity.mass;
|
|
262
|
+
render() {
|
|
263
|
+
if (this.paused) return;
|
|
181
264
|
|
|
182
|
-
|
|
183
|
-
|
|
265
|
+
if (this.transition) {
|
|
266
|
+
this.applyTransition();
|
|
267
|
+
}
|
|
184
268
|
|
|
185
|
-
|
|
186
|
-
let lastY = this.y;
|
|
269
|
+
_p5.prototype.background(this.backColor);
|
|
187
270
|
|
|
188
|
-
|
|
189
|
-
|
|
271
|
+
this.scripts.forEach(exe => {
|
|
272
|
+
if (typeof exe == "function") exe(this);
|
|
273
|
+
});
|
|
190
274
|
|
|
191
|
-
|
|
192
|
-
|
|
275
|
+
this.onUpdateCallbacks.forEach(cb => {
|
|
276
|
+
if (typeof cb == "function") cb(this);
|
|
277
|
+
});
|
|
193
278
|
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
// Apply ground friction to horizontal movement
|
|
199
|
-
if (this.gravity.friction > 0 && this.velocityMode === "polar") {
|
|
200
|
-
this.velocity[0] *= (1 - this.gravity.friction);
|
|
201
|
-
if (Math.abs(this.velocity[0]) < 0.01) this.velocity[0] = 0;
|
|
279
|
+
this.objects.forEach(o => {
|
|
280
|
+
if (o && typeof o.update == "function") {
|
|
281
|
+
o.update(true);
|
|
202
282
|
}
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
checkGroundCollision() {
|
|
208
|
-
if (!this.collition || !this.gravity.enabled) return;
|
|
209
|
-
|
|
210
|
-
let wasGrounded = this.gravity.grounded;
|
|
211
|
-
this.gravity.grounded = false;
|
|
283
|
+
if (o && typeof o.render == "function") {
|
|
284
|
+
o.render();
|
|
285
|
+
}
|
|
286
|
+
});
|
|
212
287
|
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
if (other.id === this.id || !other.active) return;
|
|
218
|
-
|
|
219
|
-
// Only check if gravity is enabled on this object and we're moving downward
|
|
220
|
-
if (this.gravity.velocity <= 0) return;
|
|
221
|
-
|
|
222
|
-
// Check if other object is below this one
|
|
223
|
-
let verticalDistance = (other.y - other.height/2) - (this.y + this.height/2);
|
|
224
|
-
|
|
225
|
-
// If within ground tolerance and horizontally overlapping
|
|
226
|
-
if (Math.abs(verticalDistance) <= this.gravity.groundTolerance &&
|
|
227
|
-
this.x + this.width/2 > other.x - other.width/2 &&
|
|
228
|
-
this.x - this.width/2 < other.x + other.width/2) {
|
|
229
|
-
|
|
230
|
-
this.gravity.grounded = true;
|
|
231
|
-
this.lastGroundY = other.y - other.height/2 - this.height/2;
|
|
232
|
-
|
|
233
|
-
// Apply bounce if enabled
|
|
234
|
-
if (this.gravity.bounce > 0 && wasGrounded === false) {
|
|
235
|
-
this.gravity.velocity = -this.gravity.velocity * this.gravity.bounce;
|
|
236
|
-
|
|
237
|
-
// If bounce velocity is very small, just set to zero
|
|
238
|
-
if (Math.abs(this.gravity.velocity) < 0.1) {
|
|
239
|
-
this.gravity.velocity = 0;
|
|
240
|
-
}
|
|
241
|
-
} else {
|
|
242
|
-
// Position exactly on ground
|
|
243
|
-
this.y = this.lastGroundY;
|
|
244
|
-
}
|
|
288
|
+
if (typeof UIPlanes !== 'undefined' && UIPlanes.length > 0) {
|
|
289
|
+
UIPlanes.forEach(ui => {
|
|
290
|
+
if (ui && typeof ui.belongsToScene == "function" && ui.belongsToScene(this.id)) {
|
|
291
|
+
ui.render();
|
|
245
292
|
}
|
|
246
293
|
});
|
|
247
294
|
}
|
|
248
|
-
}
|
|
249
|
-
|
|
250
|
-
update() {
|
|
251
|
-
if (!this.active) return;
|
|
252
|
-
|
|
253
|
-
// Apply gravity if enabled
|
|
254
|
-
this.applyGravity();
|
|
255
295
|
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
if (this.velocityMode == "polar") {
|
|
260
|
-
let linked = false;
|
|
261
|
-
if (!/unlinked/i.test(this.rvm) && /linked/i.test(this.rvm)) {
|
|
262
|
-
this.velocity[1] = this.rotation;
|
|
263
|
-
linked = true;
|
|
264
|
-
}
|
|
265
|
-
|
|
266
|
-
let rot = linked ?
|
|
267
|
-
(this.rotationMode == "degrees" ? (this.rotation) : radians(this.rotation)) :
|
|
268
|
-
(this.rotationMode == "degrees" ? (this.velocity[1]) : (this.velocity[1]));
|
|
269
|
-
|
|
270
|
-
if(isNaN(rot)){
|
|
271
|
-
vel = 0;
|
|
272
|
-
rot = 0;
|
|
273
|
-
}
|
|
274
|
-
|
|
275
|
-
let vx = vel * cos(rot);
|
|
276
|
-
let vy = vel * sin(rot);
|
|
277
|
-
|
|
278
|
-
this.velocityMatrix = [vx, vy];
|
|
279
|
-
|
|
280
|
-
// Don't apply horizontal movement if gravity is enabled and we're grounded with friction
|
|
281
|
-
if (!(this.gravity.enabled && this.gravity.grounded && this.gravity.friction > 0)) {
|
|
282
|
-
this.x += vx;
|
|
283
|
-
}
|
|
284
|
-
|
|
285
|
-
// Vertical movement is handled by gravity when enabled
|
|
286
|
-
if (!this.gravity.enabled) {
|
|
287
|
-
this.y += vy;
|
|
288
|
-
}
|
|
289
|
-
} else {
|
|
290
|
-
// Cartesian velocity mode
|
|
291
|
-
if (!(this.gravity.enabled && this.gravity.grounded && this.gravity.friction > 0)) {
|
|
292
|
-
this.x += vel;
|
|
293
|
-
}
|
|
294
|
-
if (!this.gravity.enabled) {
|
|
295
|
-
this.y += angle;
|
|
296
|
+
this.uiPlanes.forEach(ui => {
|
|
297
|
+
if (ui && typeof ui.render == "function") {
|
|
298
|
+
ui.render();
|
|
296
299
|
}
|
|
297
|
-
}
|
|
298
|
-
|
|
299
|
-
// Update parent scene reference
|
|
300
|
-
this.updateParentScene();
|
|
300
|
+
});
|
|
301
301
|
|
|
302
|
-
|
|
302
|
+
MALCScene[this.sceneInstance] = this;
|
|
303
303
|
}
|
|
304
304
|
|
|
305
|
-
|
|
306
|
-
if (!this.active) return;
|
|
307
|
-
|
|
308
|
-
this.scripts.forEach(s => {
|
|
309
|
-
if(typeof s == "function")s(this);
|
|
310
|
-
});
|
|
305
|
+
applyTransition() {
|
|
306
|
+
if (!this.transition || !this.transition.active) return;
|
|
311
307
|
|
|
312
|
-
|
|
313
|
-
let hb = this.hitbox;
|
|
308
|
+
this.transition.progress += 1/60;
|
|
314
309
|
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
rectMode(CENTER);
|
|
320
|
-
if (this.rotationMode == "degrees") angleMode(DEGREES);
|
|
321
|
-
rotate(this.rotation + hb.rotation);
|
|
322
|
-
|
|
323
|
-
stroke("#00FF27");
|
|
324
|
-
strokeWeight(hb.outline);
|
|
325
|
-
noFill();
|
|
326
|
-
rect(hb.x, hb.y, this.width + hb.width, this.height + hb.height);
|
|
327
|
-
|
|
328
|
-
// Draw gravity indicator if enabled
|
|
329
|
-
if (this.gravity.enabled) {
|
|
330
|
-
stroke(0, 255, 0, 100);
|
|
331
|
-
line(0, 0, 0, this.gravity.velocity * 5);
|
|
332
|
-
}
|
|
333
|
-
|
|
334
|
-
pop();
|
|
310
|
+
if (this.transition.progress >= this.transition.duration) {
|
|
311
|
+
this.transition.active = false;
|
|
312
|
+
this.transition = null;
|
|
313
|
+
return;
|
|
335
314
|
}
|
|
336
315
|
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
push();
|
|
340
|
-
translate(this.x, this.y);
|
|
341
|
-
rectMode(CENTER);
|
|
342
|
-
if (this.rotationMode == "degrees") angleMode(DEGREES);
|
|
343
|
-
rotate(this.rotation);
|
|
316
|
+
let t = this.transition.progress / this.transition.duration;
|
|
344
317
|
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
318
|
+
_p5.prototype.push();
|
|
319
|
+
switch(this.transition.type) {
|
|
320
|
+
case "fade":
|
|
321
|
+
_p5.prototype.fill(0, 255 * (1 - t));
|
|
322
|
+
_p5.prototype.rect(0, 0, _p5.prototype.width, _p5.prototype.height);
|
|
323
|
+
break;
|
|
324
|
+
case "slide":
|
|
325
|
+
_p5.prototype.translate(_p5.prototype.width * (1 - t), 0);
|
|
326
|
+
break;
|
|
350
327
|
}
|
|
351
|
-
|
|
352
|
-
fill(this.formatting.color);
|
|
353
|
-
rect(0, 0, this.width, this.height);
|
|
354
|
-
pop();
|
|
355
|
-
}
|
|
356
|
-
|
|
357
|
-
// ========== HELPFUL METHODS ==========
|
|
358
|
-
|
|
359
|
-
belongsToScene(sceneId) {
|
|
360
|
-
return this.scenes.includes(sceneId);
|
|
328
|
+
_p5.prototype.pop();
|
|
361
329
|
}
|
|
362
330
|
|
|
363
|
-
|
|
364
|
-
if (!this.
|
|
365
|
-
this.
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
scene.objects.push(this);
|
|
331
|
+
addObject(object) {
|
|
332
|
+
if (object && !this.objects.includes(object)) {
|
|
333
|
+
this.objects.push(object);
|
|
334
|
+
if (typeof object.addToScene == "function") {
|
|
335
|
+
object.addToScene(this.id);
|
|
369
336
|
}
|
|
370
337
|
}
|
|
371
338
|
return this;
|
|
372
339
|
}
|
|
373
340
|
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
341
|
+
addObjects(objects) {
|
|
342
|
+
objects.forEach(obj => this.addObject(obj));
|
|
343
|
+
return this;
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
removeObject(object) {
|
|
347
|
+
this.objects = this.objects.filter(obj => obj != object);
|
|
348
|
+
if (object && typeof object.removeFromScene == "function") {
|
|
349
|
+
object.removeFromScene(this.id);
|
|
379
350
|
}
|
|
380
351
|
return this;
|
|
381
352
|
}
|
|
382
353
|
|
|
383
|
-
|
|
384
|
-
this.
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
scene.objects = scene.objects.filter(obj => obj != this);
|
|
354
|
+
clearObjects() {
|
|
355
|
+
this.objects.forEach(obj => {
|
|
356
|
+
if (obj && typeof obj.removeFromScene == "function") {
|
|
357
|
+
obj.removeFromScene(this.id);
|
|
388
358
|
}
|
|
389
359
|
});
|
|
390
|
-
this.
|
|
360
|
+
this.objects = [];
|
|
391
361
|
return this;
|
|
392
362
|
}
|
|
393
363
|
|
|
394
|
-
|
|
395
|
-
if (
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
364
|
+
getObjects(filter) {
|
|
365
|
+
if (typeof filter == "function") {
|
|
366
|
+
return this.objects.filter(filter);
|
|
367
|
+
} else if (filter == "button") {
|
|
368
|
+
return this.objects.filter(obj => obj instanceof Button);
|
|
369
|
+
} else if (filter == "gameObject") {
|
|
370
|
+
return this.objects.filter(obj => obj instanceof gameObject);
|
|
400
371
|
}
|
|
372
|
+
return this.objects;
|
|
401
373
|
}
|
|
402
374
|
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
let dy = target.y !== undefined ? target.y - this.y : target[1] - this.y;
|
|
406
|
-
return Math.sqrt(dx * dx + dy * dy);
|
|
375
|
+
getObjectById(id) {
|
|
376
|
+
return this.objects.find(obj => obj && obj.id == id);
|
|
407
377
|
}
|
|
408
378
|
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
379
|
+
addUIPlane(uiPlane) {
|
|
380
|
+
if (uiPlane && !this.uiPlanes.includes(uiPlane)) {
|
|
381
|
+
this.uiPlanes.push(uiPlane);
|
|
382
|
+
if (typeof uiPlane.addToScene == "function") {
|
|
383
|
+
uiPlane.addToScene(this.id);
|
|
384
|
+
}
|
|
385
|
+
}
|
|
386
|
+
return this;
|
|
414
387
|
}
|
|
415
388
|
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
(
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
let da = (Math.atan(pa[1]/pa[0])*180)/Math.PI;
|
|
430
|
-
|
|
431
|
-
if((pa[1] > -err && pa[1] < err) && (pa[0] > -err && pa[0] < err)){
|
|
432
|
-
angle = NaN;
|
|
433
|
-
} else if(quads[0]){
|
|
434
|
-
angle = da+180;
|
|
435
|
-
} else if(quads[1]){
|
|
436
|
-
angle = da+180;
|
|
437
|
-
} else if(quads[2]){
|
|
438
|
-
angle = da;
|
|
439
|
-
} else if(quads[3]){
|
|
440
|
-
angle = da;
|
|
441
|
-
} else if(quads[4]){
|
|
442
|
-
if(pa[1] < -err) {
|
|
443
|
-
angle = -90;
|
|
444
|
-
} else if(pa[1] > err) {
|
|
445
|
-
angle = 90;
|
|
446
|
-
}
|
|
447
|
-
} else if(quads[5]){
|
|
448
|
-
if(pa[0] < -err) {
|
|
449
|
-
angle = 180;
|
|
450
|
-
} else if(pa[0] > err) {
|
|
451
|
-
angle = 0;
|
|
389
|
+
removeUIPlane(uiPlane) {
|
|
390
|
+
this.uiPlanes = this.uiPlanes.filter(ui => ui != uiPlane);
|
|
391
|
+
if (uiPlane && typeof uiPlane.removeFromScene == "function") {
|
|
392
|
+
uiPlane.removeFromScene(this.id);
|
|
393
|
+
}
|
|
394
|
+
return this;
|
|
395
|
+
}
|
|
396
|
+
|
|
397
|
+
clearUIPlanes() {
|
|
398
|
+
this.uiPlanes.forEach(ui => {
|
|
399
|
+
if (ui && typeof ui.removeFromScene == "function") {
|
|
400
|
+
ui.removeFromScene(this.id);
|
|
452
401
|
}
|
|
402
|
+
});
|
|
403
|
+
this.uiPlanes = [];
|
|
404
|
+
return this;
|
|
405
|
+
}
|
|
406
|
+
|
|
407
|
+
addScript(script) {
|
|
408
|
+
if (typeof script == "function" && !this.scripts.includes(script)) {
|
|
409
|
+
this.scripts.push(script);
|
|
453
410
|
}
|
|
454
|
-
|
|
455
|
-
return angle;
|
|
411
|
+
return this;
|
|
456
412
|
}
|
|
457
413
|
|
|
458
|
-
|
|
459
|
-
this.
|
|
414
|
+
removeScript(script) {
|
|
415
|
+
this.scripts = this.scripts.filter(s => s != script);
|
|
460
416
|
return this;
|
|
461
417
|
}
|
|
462
418
|
|
|
463
|
-
|
|
464
|
-
this.
|
|
465
|
-
this.y = y;
|
|
419
|
+
clearScripts() {
|
|
420
|
+
this.scripts = [];
|
|
466
421
|
return this;
|
|
467
422
|
}
|
|
468
423
|
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
424
|
+
onActivate(callback) {
|
|
425
|
+
if (typeof callback == "function") {
|
|
426
|
+
this.onActivateCallbacks.push(callback);
|
|
427
|
+
}
|
|
472
428
|
return this;
|
|
473
429
|
}
|
|
474
430
|
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
if(isNaN(angle)){
|
|
479
|
-
angle = 0;
|
|
480
|
-
speed = 0;
|
|
431
|
+
onDeactivate(callback) {
|
|
432
|
+
if (typeof callback == "function") {
|
|
433
|
+
this.onDeactivateCallbacks.push(callback);
|
|
481
434
|
}
|
|
482
|
-
|
|
483
|
-
this.velocity = [speed, angle];
|
|
484
|
-
return this.velocity;
|
|
435
|
+
return this;
|
|
485
436
|
}
|
|
486
437
|
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
if (index > -1) {
|
|
491
|
-
MALCgameObjects.splice(index, 1);
|
|
438
|
+
onUpdate(callback) {
|
|
439
|
+
if (typeof callback == "function") {
|
|
440
|
+
this.onUpdateCallbacks.push(callback);
|
|
492
441
|
}
|
|
442
|
+
return this;
|
|
493
443
|
}
|
|
494
444
|
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
clone.rotationMode = this.rotationMode;
|
|
499
|
-
clone.velocity = [...this.velocity];
|
|
500
|
-
clone.velocityMode = this.velocityMode;
|
|
501
|
-
clone.rvm = this.rvm;
|
|
502
|
-
clone.formatting = JSON.parse(JSON.stringify(this.formatting));
|
|
503
|
-
clone.gravity = JSON.parse(JSON.stringify(this.gravity));
|
|
504
|
-
clone.debug = this.debug;
|
|
505
|
-
clone.hitbox = JSON.parse(JSON.stringify(this.hitbox));
|
|
506
|
-
return clone;
|
|
445
|
+
pause() {
|
|
446
|
+
this.paused = true;
|
|
447
|
+
return this;
|
|
507
448
|
}
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
449
|
+
|
|
450
|
+
resume() {
|
|
451
|
+
this.paused = false;
|
|
452
|
+
return this;
|
|
453
|
+
}
|
|
454
|
+
|
|
455
|
+
setTransition(type, duration = 1.0) {
|
|
456
|
+
this.transition = {
|
|
457
|
+
type: type,
|
|
458
|
+
duration: duration,
|
|
459
|
+
progress: 0,
|
|
460
|
+
active: true
|
|
461
|
+
};
|
|
462
|
+
return this;
|
|
463
|
+
}
|
|
464
|
+
|
|
465
|
+
addTag(tag) {
|
|
466
|
+
if (!this.tags.includes(tag)) {
|
|
467
|
+
this.tags.push(tag);
|
|
512
468
|
}
|
|
513
|
-
return
|
|
469
|
+
return this;
|
|
514
470
|
}
|
|
515
471
|
|
|
516
|
-
|
|
517
|
-
|
|
472
|
+
removeTag(tag) {
|
|
473
|
+
this.tags = this.tags.filter(t => t != tag);
|
|
474
|
+
return this;
|
|
475
|
+
}
|
|
476
|
+
|
|
477
|
+
hasTag(tag) {
|
|
478
|
+
return this.tags.includes(tag);
|
|
479
|
+
}
|
|
480
|
+
|
|
481
|
+
reset() {
|
|
482
|
+
this.clearObjects();
|
|
483
|
+
this.clearUIPlanes();
|
|
484
|
+
this.clearScripts();
|
|
485
|
+
this.onActivateCallbacks = [];
|
|
486
|
+
this.onDeactivateCallbacks = [];
|
|
487
|
+
this.onUpdateCallbacks = [];
|
|
488
|
+
this.tags = [];
|
|
489
|
+
this.paused = false;
|
|
490
|
+
this.transition = null;
|
|
491
|
+
this.timeActive = 0;
|
|
492
|
+
return this;
|
|
493
|
+
}
|
|
494
|
+
|
|
495
|
+
destroy() {
|
|
496
|
+
let index = MALCScene.indexOf(this);
|
|
497
|
+
if (index > -1) {
|
|
498
|
+
MALCScene.splice(index, 1);
|
|
499
|
+
}
|
|
518
500
|
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
let screenBottom = cameraPos[1] + camera.height;
|
|
501
|
+
this.clearObjects();
|
|
502
|
+
this.clearUIPlanes();
|
|
522
503
|
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
504
|
+
if (Scene.activeScene == this.id) {
|
|
505
|
+
Scene.activeScene = "blank";
|
|
506
|
+
}
|
|
507
|
+
}
|
|
508
|
+
|
|
509
|
+
clone(newId) {
|
|
510
|
+
let clone = new Scene(newId || this.id + "_copy", this.backColor, ...this.scripts);
|
|
511
|
+
clone.objects = [...this.objects];
|
|
512
|
+
clone.uiPlanes = [...this.uiPlanes];
|
|
513
|
+
clone.tags = [...this.tags];
|
|
514
|
+
return clone;
|
|
515
|
+
}
|
|
516
|
+
|
|
517
|
+
getInfo() {
|
|
518
|
+
return {
|
|
519
|
+
id: this.id,
|
|
520
|
+
active: this.active,
|
|
521
|
+
timeActive: this.timeActive,
|
|
522
|
+
objectCount: this.objects.length,
|
|
523
|
+
uiPlaneCount: this.uiPlanes.length,
|
|
524
|
+
scriptCount: this.scripts.length,
|
|
525
|
+
tags: this.tags,
|
|
526
|
+
paused: this.paused
|
|
527
|
+
};
|
|
527
528
|
}
|
|
528
529
|
}
|
|
529
530
|
|
|
530
|
-
// ==========
|
|
531
|
-
class
|
|
532
|
-
static
|
|
531
|
+
// ========== GAME OBJECT CLASS WITH GRAVITY ==========
|
|
532
|
+
class gameObject {
|
|
533
|
+
static objects = [];
|
|
534
|
+
static started = false;
|
|
535
|
+
static gravity = GRAVITY;
|
|
536
|
+
static terminalVelocity = TERMINAL_VELOCITY;
|
|
533
537
|
|
|
534
|
-
static
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
this.buttons.forEach(b => {
|
|
539
|
-
if (!b.active) return;
|
|
540
|
-
|
|
541
|
-
b.isHovered = b.events.hover();
|
|
542
|
-
|
|
543
|
-
if (MALCbuttons.every(b => !b.events.hover())) {
|
|
544
|
-
cursor();
|
|
545
|
-
} else if (b.isHovered) {
|
|
546
|
-
cursor(b.cursor);
|
|
547
|
-
}
|
|
538
|
+
static render() {
|
|
539
|
+
MALCgameObjects.forEach(o => {
|
|
540
|
+
if (o.active) o.render();
|
|
548
541
|
});
|
|
549
542
|
}
|
|
550
543
|
|
|
551
|
-
static
|
|
552
|
-
|
|
544
|
+
static update() {
|
|
545
|
+
this.started = true;
|
|
546
|
+
this.objects = MALCgameObjects;
|
|
547
|
+
|
|
548
|
+
// Update all active objects
|
|
549
|
+
MALCgameObjects.forEach(o => {
|
|
550
|
+
if (o.active) o.update();
|
|
551
|
+
});
|
|
552
|
+
}
|
|
553
|
+
|
|
554
|
+
static initialize() {
|
|
555
|
+
console.log("MALC gameObjects initialized");
|
|
556
|
+
|
|
557
|
+
// Add objects to their scenes
|
|
558
|
+
MALCgameObjects.forEach(o => {
|
|
559
|
+
o.scenes.forEach(sceneId => {
|
|
560
|
+
let scene = Scene.getSceneById(sceneId);
|
|
561
|
+
if (scene && !scene.objects.includes(o)) {
|
|
562
|
+
scene.objects.push(o);
|
|
563
|
+
}
|
|
564
|
+
});
|
|
565
|
+
});
|
|
553
566
|
}
|
|
554
567
|
|
|
555
|
-
static
|
|
556
|
-
return
|
|
568
|
+
static getObjectByIndex(index) {
|
|
569
|
+
return MALCgameObjects[index] || null;
|
|
557
570
|
}
|
|
558
571
|
|
|
559
|
-
static
|
|
560
|
-
return
|
|
572
|
+
static getActiveObjects() {
|
|
573
|
+
return MALCgameObjects.filter(o => o.active);
|
|
561
574
|
}
|
|
562
575
|
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
this.formatting.button = {
|
|
567
|
-
hover: 220,
|
|
568
|
-
clicked: 190,
|
|
569
|
-
text: {
|
|
570
|
-
color: 0,
|
|
571
|
-
size: 14,
|
|
572
|
-
style:"normal",
|
|
573
|
-
display: displayText,
|
|
574
|
-
},
|
|
575
|
-
colors: {
|
|
576
|
-
normal: 255,
|
|
577
|
-
hover: 220,
|
|
578
|
-
pressed: 190,
|
|
579
|
-
disabled: 150
|
|
580
|
-
}
|
|
581
|
-
};
|
|
582
|
-
|
|
583
|
-
this.cursor = "pointer";
|
|
584
|
-
this.isHovered = false;
|
|
585
|
-
this.isPressed = false;
|
|
586
|
-
this.isDisabled = false;
|
|
587
|
-
this.clickCooldown = 100;
|
|
588
|
-
this.lastClickTime = 0;
|
|
589
|
-
this.cooldownActive = false;
|
|
590
|
-
|
|
591
|
-
this.events = {
|
|
592
|
-
hover: (err = 0) => {
|
|
593
|
-
return !this.isDisabled && (
|
|
594
|
-
mouse.x < this.x + this.width / 2 + err &&
|
|
595
|
-
mouse.x > this.x - (this.width / 2 + err) &&
|
|
596
|
-
mouse.y < this.y + this.height / 2 + err &&
|
|
597
|
-
mouse.y > this.y - (this.height / 2 + err)
|
|
598
|
-
);
|
|
599
|
-
},
|
|
600
|
-
pressed: () => {
|
|
601
|
-
return this.events.hover() && mouse.down;
|
|
602
|
-
},
|
|
603
|
-
clicked: () => {
|
|
604
|
-
let wasPressed = this.wasPressed;
|
|
605
|
-
let isHovering = this.events.hover();
|
|
606
|
-
let mouseReleased = !mouse.down && wasPressed;
|
|
607
|
-
|
|
608
|
-
this.wasPressed = mouse.down && isHovering;
|
|
609
|
-
|
|
610
|
-
return mouseReleased && isHovering;
|
|
611
|
-
}
|
|
612
|
-
};
|
|
613
|
-
|
|
614
|
-
this.wasPressed = false;
|
|
615
|
-
this.onClick = null;
|
|
616
|
-
|
|
617
|
-
this.buttonIndex = MALCbuttons.length;
|
|
618
|
-
MALCbuttons.push(this);
|
|
576
|
+
static getObjectsInScene(sceneId) {
|
|
577
|
+
let scene = Scene.getSceneById(sceneId);
|
|
578
|
+
return scene ? scene.objects : [];
|
|
619
579
|
}
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
this.cooldownActive = false;
|
|
628
|
-
}
|
|
629
|
-
}
|
|
630
|
-
|
|
631
|
-
this.isHovered = this.events.hover();
|
|
632
|
-
this.isPressed = this.events.pressed();
|
|
633
|
-
|
|
634
|
-
if (this.events.clicked() && this.onClick && !this.isDisabled && !this.cooldownActive) {
|
|
635
|
-
this.onClick(this);
|
|
636
|
-
this.lastClickTime = Date.now();
|
|
637
|
-
this.cooldownActive = true;
|
|
638
|
-
}
|
|
639
|
-
|
|
640
|
-
MALCbuttons[this.buttonIndex] = this;
|
|
580
|
+
|
|
581
|
+
static setGlobalGravity(value) {
|
|
582
|
+
this.gravity = value;
|
|
583
|
+
}
|
|
584
|
+
|
|
585
|
+
static getGlobalGravity() {
|
|
586
|
+
return this.gravity;
|
|
641
587
|
}
|
|
642
588
|
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
589
|
+
constructor(x = 0, y = 0, w = 20, h = 20, ...scenes) {
|
|
590
|
+
this.id = generateId('gameObject');
|
|
591
|
+
this.x = x;
|
|
592
|
+
this.y = y;
|
|
593
|
+
this.width = w;
|
|
594
|
+
this.height = h;
|
|
595
|
+
this.rotation = 0;
|
|
596
|
+
this.rotationMode = "degrees";
|
|
597
|
+
this.velocity = [0, 0];
|
|
598
|
+
this.velocityMatrix = [0, 0];
|
|
599
|
+
this.velocityMode = "polar";
|
|
600
|
+
this.rvm = "unlinked";
|
|
648
601
|
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
602
|
+
// Gravity properties
|
|
603
|
+
this.gravity = {
|
|
604
|
+
enabled: false,
|
|
605
|
+
velocity: 0,
|
|
606
|
+
grounded: false,
|
|
607
|
+
groundTolerance: 1, // pixels
|
|
608
|
+
mass: 1,
|
|
609
|
+
bounce: 0, // 0 = no bounce, 1 = full bounce
|
|
610
|
+
friction: 0.1 // ground friction
|
|
611
|
+
};
|
|
658
612
|
|
|
659
|
-
|
|
660
|
-
|
|
613
|
+
this.formatting = {
|
|
614
|
+
outline: [false, 0, "black"],
|
|
615
|
+
color: "white",
|
|
616
|
+
};
|
|
661
617
|
|
|
662
|
-
|
|
618
|
+
this.collition = true;
|
|
663
619
|
|
|
664
|
-
|
|
620
|
+
this.scripts = [];
|
|
621
|
+
this.scenes = scenes.length < 1 ? ["blank"] : [...new Set(scenes)];
|
|
622
|
+
this.active = false;
|
|
623
|
+
this.visible = true;
|
|
624
|
+
this.parentScene = null;
|
|
665
625
|
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
626
|
+
this.debug = false;
|
|
627
|
+
this.hitbox = {
|
|
628
|
+
x: 0,
|
|
629
|
+
y: 0,
|
|
630
|
+
width: 0,
|
|
631
|
+
height: 0,
|
|
632
|
+
rotation: 0,
|
|
633
|
+
parts: null,
|
|
634
|
+
outline: 1,
|
|
635
|
+
};
|
|
670
636
|
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
fill(btnFormat.text.color);
|
|
674
|
-
coloredText(btnFormat.text.display, 0, 0, CENTER, CENTER);
|
|
675
|
-
pop();
|
|
637
|
+
this.objectInstance = MALCgameObjects.length;
|
|
638
|
+
this.lastGroundY = y;
|
|
676
639
|
|
|
677
|
-
this
|
|
640
|
+
MALCgameObjects.push(this);
|
|
678
641
|
}
|
|
679
642
|
|
|
680
|
-
//
|
|
643
|
+
// Enable gravity for this object
|
|
644
|
+
enableGravity() {
|
|
645
|
+
this.gravity.enabled = true;
|
|
646
|
+
return this;
|
|
647
|
+
}
|
|
681
648
|
|
|
682
|
-
|
|
683
|
-
|
|
649
|
+
// Disable gravity for this object
|
|
650
|
+
disableGravity() {
|
|
651
|
+
this.gravity.enabled = false;
|
|
652
|
+
this.gravity.velocity = 0;
|
|
684
653
|
return this;
|
|
685
654
|
}
|
|
686
655
|
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
656
|
+
// Set gravity parameters
|
|
657
|
+
setGravity(options = {}) {
|
|
658
|
+
if (options.enabled !== undefined) this.gravity.enabled = options.enabled;
|
|
659
|
+
if (options.mass !== undefined) this.gravity.mass = Math.max(0.1, options.mass);
|
|
660
|
+
if (options.bounce !== undefined) this.gravity.bounce = Math.min(1, Math.max(0, options.bounce));
|
|
661
|
+
if (options.friction !== undefined) this.gravity.friction = Math.min(1, Math.max(0, options.friction));
|
|
662
|
+
if (options.groundTolerance !== undefined) this.gravity.groundTolerance = options.groundTolerance;
|
|
663
|
+
return this;
|
|
690
664
|
}
|
|
691
665
|
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
666
|
+
// Apply gravity to this object
|
|
667
|
+
applyGravity() {
|
|
668
|
+
if (!this.gravity.enabled) return;
|
|
669
|
+
|
|
670
|
+
// Apply gravity acceleration (scaled by mass)
|
|
671
|
+
this.gravity.velocity += gameObject.gravity * this.gravity.mass;
|
|
672
|
+
|
|
673
|
+
// Limit to terminal velocity
|
|
674
|
+
this.gravity.velocity = Math.min(this.gravity.velocity, gameObject.terminalVelocity);
|
|
675
|
+
|
|
676
|
+
// Store last position before moving
|
|
677
|
+
let lastY = this.y;
|
|
678
|
+
|
|
679
|
+
// Apply vertical movement
|
|
680
|
+
this.y += this.gravity.velocity;
|
|
681
|
+
|
|
682
|
+
// Check for ground collision with other objects
|
|
683
|
+
this.checkGroundCollision();
|
|
684
|
+
|
|
685
|
+
// If we just landed, stop downward velocity
|
|
686
|
+
if (this.gravity.grounded) {
|
|
687
|
+
this.gravity.velocity = 0;
|
|
688
|
+
|
|
689
|
+
// Apply ground friction to horizontal movement
|
|
690
|
+
if (this.gravity.friction > 0 && this.velocityMode === "polar") {
|
|
691
|
+
this.velocity[0] *= (1 - this.gravity.friction);
|
|
692
|
+
if (Math.abs(this.velocity[0]) < 0.01) this.velocity[0] = 0;
|
|
693
|
+
}
|
|
694
|
+
}
|
|
695
695
|
}
|
|
696
696
|
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
697
|
+
// Check if this object is standing on another object
|
|
698
|
+
checkGroundCollision() {
|
|
699
|
+
if (!this.collition || !this.gravity.enabled) return;
|
|
700
|
+
|
|
701
|
+
let wasGrounded = this.gravity.grounded;
|
|
702
|
+
this.gravity.grounded = false;
|
|
703
|
+
|
|
704
|
+
// Check collision with other objects in the same scene
|
|
705
|
+
if (this.parentScene && this.parentScene.objects) {
|
|
706
|
+
this.parentScene.objects.forEach(other => {
|
|
707
|
+
// Skip self and inactive objects
|
|
708
|
+
if (other.id === this.id || !other.active) return;
|
|
709
|
+
|
|
710
|
+
// Only check if gravity is enabled on this object and we're moving downward
|
|
711
|
+
if (this.gravity.velocity <= 0) return;
|
|
712
|
+
|
|
713
|
+
// Check if other object is below this one
|
|
714
|
+
let verticalDistance = (other.y - other.height/2) - (this.y + this.height/2);
|
|
715
|
+
|
|
716
|
+
// If within ground tolerance and horizontally overlapping
|
|
717
|
+
if (Math.abs(verticalDistance) <= this.gravity.groundTolerance &&
|
|
718
|
+
this.x + this.width/2 > other.x - other.width/2 &&
|
|
719
|
+
this.x - this.width/2 < other.x + other.width/2) {
|
|
720
|
+
|
|
721
|
+
this.gravity.grounded = true;
|
|
722
|
+
this.lastGroundY = other.y - other.height/2 - this.height/2;
|
|
723
|
+
|
|
724
|
+
// Apply bounce if enabled
|
|
725
|
+
if (this.gravity.bounce > 0 && wasGrounded === false) {
|
|
726
|
+
this.gravity.velocity = -this.gravity.velocity * this.gravity.bounce;
|
|
727
|
+
|
|
728
|
+
// If bounce velocity is very small, just set to zero
|
|
729
|
+
if (Math.abs(this.gravity.velocity) < 0.1) {
|
|
730
|
+
this.gravity.velocity = 0;
|
|
731
|
+
}
|
|
732
|
+
} else {
|
|
733
|
+
// Position exactly on ground
|
|
734
|
+
this.y = this.lastGroundY;
|
|
735
|
+
}
|
|
736
|
+
}
|
|
737
|
+
});
|
|
738
|
+
}
|
|
701
739
|
}
|
|
702
740
|
|
|
703
|
-
|
|
704
|
-
if (
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
741
|
+
update() {
|
|
742
|
+
if (!this.active) return;
|
|
743
|
+
|
|
744
|
+
// Apply gravity if enabled
|
|
745
|
+
this.applyGravity();
|
|
746
|
+
|
|
747
|
+
let vel = this.velocity[0];
|
|
748
|
+
let angle = this.velocity[1];
|
|
749
|
+
|
|
750
|
+
if (this.velocityMode == "polar") {
|
|
751
|
+
let linked = false;
|
|
752
|
+
if (!/unlinked/i.test(this.rvm) && /linked/i.test(this.rvm)) {
|
|
753
|
+
this.velocity[1] = this.rotation;
|
|
754
|
+
linked = true;
|
|
755
|
+
}
|
|
756
|
+
|
|
757
|
+
let rot = linked ?
|
|
758
|
+
(this.rotationMode == "degrees" ? (this.rotation) : _p5.prototype.radians(this.rotation)) :
|
|
759
|
+
(this.rotationMode == "degrees" ? (this.velocity[1]) : (this.velocity[1]));
|
|
708
760
|
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
761
|
+
if(isNaN(rot)){
|
|
762
|
+
vel = 0;
|
|
763
|
+
rot = 0;
|
|
764
|
+
}
|
|
712
765
|
|
|
713
|
-
let
|
|
714
|
-
let
|
|
766
|
+
let vx = vel * _p5.prototype.cos(rot);
|
|
767
|
+
let vy = vel * _p5.prototype.sin(rot);
|
|
768
|
+
|
|
769
|
+
this.velocityMatrix = [vx, vy];
|
|
715
770
|
|
|
716
|
-
|
|
717
|
-
|
|
771
|
+
// Don't apply horizontal movement if gravity is enabled and we're grounded with friction
|
|
772
|
+
if (!(this.gravity.enabled && this.gravity.grounded && this.gravity.friction > 0)) {
|
|
773
|
+
this.x += vx;
|
|
774
|
+
}
|
|
775
|
+
|
|
776
|
+
// Vertical movement is handled by gravity when enabled
|
|
777
|
+
if (!this.gravity.enabled) {
|
|
778
|
+
this.y += vy;
|
|
779
|
+
}
|
|
718
780
|
} else {
|
|
719
|
-
|
|
720
|
-
|
|
781
|
+
// Cartesian velocity mode
|
|
782
|
+
if (!(this.gravity.enabled && this.gravity.grounded && this.gravity.friction > 0)) {
|
|
783
|
+
this.x += vel;
|
|
784
|
+
}
|
|
785
|
+
if (!this.gravity.enabled) {
|
|
786
|
+
this.y += angle;
|
|
787
|
+
}
|
|
721
788
|
}
|
|
722
789
|
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
this.formatting.button.colors.normal = normalColor;
|
|
727
|
-
this.formatting.button.colors.hover = hover;
|
|
728
|
-
this.formatting.button.colors.pressed = pressed;
|
|
729
|
-
if (disabledColor !== null) {
|
|
730
|
-
this.formatting.button.colors.disabled = disabledColor;
|
|
731
|
-
}
|
|
790
|
+
// Update parent scene reference
|
|
791
|
+
this.updateParentScene();
|
|
732
792
|
|
|
733
|
-
|
|
734
|
-
}
|
|
735
|
-
|
|
736
|
-
textStyle(color, size) {
|
|
737
|
-
if (color !== undefined) this.formatting.button.text.color = color;
|
|
738
|
-
if (size !== undefined) this.formatting.button.text.size = size;
|
|
739
|
-
return this;
|
|
740
|
-
}
|
|
741
|
-
|
|
742
|
-
Disable(disabled = true) {
|
|
743
|
-
this.isDisabled = disabled;
|
|
744
|
-
return this;
|
|
793
|
+
MALCgameObjects[this.objectInstance] = this;
|
|
745
794
|
}
|
|
746
795
|
|
|
747
|
-
|
|
748
|
-
if(
|
|
749
|
-
call();
|
|
750
|
-
}
|
|
751
|
-
return this.events.clicked();
|
|
752
|
-
}
|
|
753
|
-
}
|
|
754
|
-
|
|
755
|
-
// ========== SCENE CLASS ==========
|
|
756
|
-
class Scene {
|
|
757
|
-
static scenes = [];
|
|
758
|
-
static activeScene = "blank";
|
|
759
|
-
static started = false;
|
|
760
|
-
static sceneHistory = [];
|
|
761
|
-
static historyLimit = 10;
|
|
762
|
-
|
|
763
|
-
static update() {
|
|
764
|
-
this.started = true;
|
|
765
|
-
this.scenes = MALCScene;
|
|
796
|
+
render() {
|
|
797
|
+
if (!this.active) return;
|
|
766
798
|
|
|
767
|
-
|
|
799
|
+
this.scripts.forEach(s => {
|
|
800
|
+
if(typeof s == "function")s(this);
|
|
801
|
+
});
|
|
768
802
|
|
|
769
|
-
this.
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
}
|
|
790
|
-
|
|
791
|
-
S._active = true;
|
|
792
|
-
S.timeActive = MALC.time.getTime() - S.activated;
|
|
793
|
-
|
|
794
|
-
S.objects.forEach(o => {
|
|
795
|
-
if (o && typeof o.active !== 'undefined') o.active = true;
|
|
796
|
-
});
|
|
797
|
-
|
|
798
|
-
push();
|
|
799
|
-
if (window.camera && typeof camera.render == 'function') {
|
|
800
|
-
camera.render();
|
|
801
|
-
}
|
|
802
|
-
|
|
803
|
-
S.render();
|
|
804
|
-
|
|
805
|
-
pop();
|
|
803
|
+
let outline = this.formatting.outline;
|
|
804
|
+
let hb = this.hitbox;
|
|
805
|
+
|
|
806
|
+
// Draw debug hitbox if enabled
|
|
807
|
+
if (this.debug) {
|
|
808
|
+
_p5.prototype.push();
|
|
809
|
+
_p5.prototype.translate(this.x, this.y);
|
|
810
|
+
_p5.prototype.rectMode(_p5.prototype.CENTER);
|
|
811
|
+
if (this.rotationMode == "degrees") _p5.prototype.angleMode(_p5.prototype.DEGREES);
|
|
812
|
+
_p5.prototype.rotate(this.rotation + hb.rotation);
|
|
813
|
+
|
|
814
|
+
_p5.prototype.stroke("#00FF27");
|
|
815
|
+
_p5.prototype.strokeWeight(hb.outline);
|
|
816
|
+
_p5.prototype.noFill();
|
|
817
|
+
_p5.prototype.rect(hb.x, hb.y, this.width + hb.width, this.height + hb.height);
|
|
818
|
+
|
|
819
|
+
// Draw gravity indicator if enabled
|
|
820
|
+
if (this.gravity.enabled) {
|
|
821
|
+
_p5.prototype.stroke(0, 255, 0, 100);
|
|
822
|
+
_p5.prototype.line(0, 0, 0, this.gravity.velocity * 5);
|
|
806
823
|
}
|
|
807
|
-
|
|
824
|
+
|
|
825
|
+
_p5.prototype.pop();
|
|
826
|
+
}
|
|
808
827
|
|
|
809
|
-
if (!
|
|
810
|
-
|
|
811
|
-
|
|
828
|
+
if (!this.visible) return;
|
|
829
|
+
|
|
830
|
+
_p5.prototype.push();
|
|
831
|
+
_p5.prototype.translate(this.x, this.y);
|
|
832
|
+
_p5.prototype.rectMode(_p5.prototype.CENTER);
|
|
833
|
+
if (this.rotationMode == "degrees") _p5.prototype.angleMode(_p5.prototype.DEGREES);
|
|
834
|
+
_p5.prototype.rotate(this.rotation);
|
|
835
|
+
|
|
836
|
+
if (outline[0]) {
|
|
837
|
+
_p5.prototype.strokeWeight(outline[1]);
|
|
838
|
+
_p5.prototype.stroke(outline[2]);
|
|
839
|
+
} else {
|
|
840
|
+
_p5.prototype.noStroke();
|
|
812
841
|
}
|
|
842
|
+
|
|
843
|
+
_p5.prototype.fill(this.formatting.color);
|
|
844
|
+
_p5.prototype.rect(0, 0, this.width, this.height);
|
|
845
|
+
_p5.prototype.pop();
|
|
813
846
|
}
|
|
847
|
+
|
|
848
|
+
// ========== HELPFUL METHODS ==========
|
|
814
849
|
|
|
815
|
-
|
|
816
|
-
return
|
|
817
|
-
}
|
|
818
|
-
|
|
819
|
-
static getActiveScene() {
|
|
820
|
-
return this.getSceneById(this.activeScene);
|
|
850
|
+
belongsToScene(sceneId) {
|
|
851
|
+
return this.scenes.includes(sceneId);
|
|
821
852
|
}
|
|
822
853
|
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
this.sceneHistory.shift();
|
|
830
|
-
}
|
|
854
|
+
addToScene(sceneId) {
|
|
855
|
+
if (!this.scenes.includes(sceneId)) {
|
|
856
|
+
this.scenes.push(sceneId);
|
|
857
|
+
let scene = Scene.getSceneById(sceneId);
|
|
858
|
+
if (scene && !scene.objects.includes(this)) {
|
|
859
|
+
scene.objects.push(this);
|
|
831
860
|
}
|
|
832
|
-
this.activeScene = id;
|
|
833
|
-
} else {
|
|
834
|
-
console.error(`Cannot switch to scene "${id}" - not found`);
|
|
835
861
|
}
|
|
862
|
+
return this;
|
|
836
863
|
}
|
|
837
864
|
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
865
|
+
removeFromScene(sceneId) {
|
|
866
|
+
this.scenes = this.scenes.filter(id => id != sceneId);
|
|
867
|
+
let scene = Scene.getSceneById(sceneId);
|
|
868
|
+
if (scene) {
|
|
869
|
+
scene.objects = scene.objects.filter(obj => obj != this);
|
|
843
870
|
}
|
|
844
|
-
return
|
|
845
|
-
}
|
|
846
|
-
|
|
847
|
-
static getAllScenes() {
|
|
848
|
-
return [...MALCScene];
|
|
849
|
-
}
|
|
850
|
-
|
|
851
|
-
static getScenesWithObject(object) {
|
|
852
|
-
return MALCScene.filter(scene => scene.objects.includes(object));
|
|
871
|
+
return this;
|
|
853
872
|
}
|
|
854
873
|
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
MALCScene.forEach(s => {
|
|
861
|
-
if (s.id == id || typeof id != "string") {
|
|
862
|
-
throw new Error(`Scenes must have unique IDs and be strings. Duplicate/Invalid ID: "${id}"`);
|
|
874
|
+
removeFromAllScenes() {
|
|
875
|
+
this.scenes.forEach(sceneId => {
|
|
876
|
+
let scene = Scene.getSceneById(sceneId);
|
|
877
|
+
if (scene) {
|
|
878
|
+
scene.objects = scene.objects.filter(obj => obj != this);
|
|
863
879
|
}
|
|
864
880
|
});
|
|
865
|
-
|
|
866
|
-
this
|
|
867
|
-
this.backColor = backgroundColor;
|
|
868
|
-
this.scripts = scripts;
|
|
869
|
-
|
|
870
|
-
this.objects = [];
|
|
871
|
-
this.uiPlanes = [];
|
|
872
|
-
|
|
873
|
-
this.active = false;
|
|
874
|
-
this._active = false;
|
|
875
|
-
this.activated = 0;
|
|
876
|
-
this.timeActive = -1;
|
|
877
|
-
|
|
878
|
-
this.tags = [];
|
|
879
|
-
this.paused = false;
|
|
880
|
-
this.transition = null;
|
|
881
|
-
this.onActivateCallbacks = [];
|
|
882
|
-
this.onDeactivateCallbacks = [];
|
|
883
|
-
this.onUpdateCallbacks = [];
|
|
884
|
-
|
|
885
|
-
this.sceneInstance = MALCScene.length;
|
|
886
|
-
MALCScene.push(this);
|
|
881
|
+
this.scenes = [];
|
|
882
|
+
return this;
|
|
887
883
|
}
|
|
888
884
|
|
|
889
|
-
|
|
890
|
-
if (
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
}
|
|
895
|
-
|
|
896
|
-
background(this.backColor);
|
|
897
|
-
|
|
898
|
-
this.scripts.forEach(exe => {
|
|
899
|
-
if (typeof exe == "function") exe(this);
|
|
900
|
-
});
|
|
901
|
-
|
|
902
|
-
this.onUpdateCallbacks.forEach(cb => {
|
|
903
|
-
if (typeof cb == "function") cb(this);
|
|
904
|
-
});
|
|
905
|
-
|
|
906
|
-
this.objects.forEach(o => {
|
|
907
|
-
if (o && typeof o.update == "function") {
|
|
908
|
-
o.update(true);
|
|
909
|
-
}
|
|
910
|
-
if (o && typeof o.render == "function") {
|
|
911
|
-
o.render();
|
|
912
|
-
}
|
|
913
|
-
});
|
|
914
|
-
|
|
915
|
-
if (typeof UIPlanes !== 'undefined' && UIPlanes.length > 0) {
|
|
916
|
-
UIPlanes.forEach(ui => {
|
|
917
|
-
if (ui && typeof ui.belongsToScene == "function" && ui.belongsToScene(this.id)) {
|
|
918
|
-
ui.render();
|
|
919
|
-
}
|
|
920
|
-
});
|
|
921
|
-
}
|
|
922
|
-
|
|
923
|
-
this.uiPlanes.forEach(ui => {
|
|
924
|
-
if (ui && typeof ui.render == "function") {
|
|
925
|
-
ui.render();
|
|
885
|
+
updateParentScene() {
|
|
886
|
+
if (Scene.activeScene) {
|
|
887
|
+
let activeScene = Scene.getSceneById(Scene.activeScene);
|
|
888
|
+
if (activeScene && this.belongsToScene(activeScene.id)) {
|
|
889
|
+
this.parentScene = activeScene;
|
|
926
890
|
}
|
|
927
|
-
}
|
|
928
|
-
|
|
929
|
-
MALCScene[this.sceneInstance] = this;
|
|
891
|
+
}
|
|
930
892
|
}
|
|
931
893
|
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
894
|
+
distanceTo(target) {
|
|
895
|
+
let dx = target.x !== undefined ? target.x - this.x : target[0] - this.x;
|
|
896
|
+
let dy = target.y !== undefined ? target.y - this.y : target[1] - this.y;
|
|
897
|
+
return Math.sqrt(dx * dx + dy * dy);
|
|
898
|
+
}
|
|
899
|
+
|
|
900
|
+
collidesWith(other) {
|
|
901
|
+
return (this.x < other.x + other.width &&
|
|
902
|
+
this.x + this.width > other.x &&
|
|
903
|
+
this.y < other.y + other.height &&
|
|
904
|
+
this.y + this.height > other.y);
|
|
905
|
+
}
|
|
906
|
+
|
|
907
|
+
directionTo(x, y, err = 0.5) {
|
|
908
|
+
let pa = [x - this.x, y - this.y];
|
|
936
909
|
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
910
|
+
let angle = (x && y) ? _p5.prototype.atan(pa[1]/pa[0]) : this.rotation;
|
|
911
|
+
var quads = [
|
|
912
|
+
pa[0] < -err && pa[1] > err,
|
|
913
|
+
pa[0] < -err && pa[1] < -err,
|
|
914
|
+
pa[0] > err && pa[1] > err,
|
|
915
|
+
pa[0] > err && pa[1] < -err,
|
|
916
|
+
(pa[0] < err && pa[0] > -err),
|
|
917
|
+
(pa[1] < err && pa[1] > -err),
|
|
918
|
+
];
|
|
942
919
|
|
|
943
|
-
let
|
|
920
|
+
let da = (_p5.prototype.atan(pa[1]/pa[0]) * 180)/Math.PI;
|
|
944
921
|
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
922
|
+
if((pa[1] > -err && pa[1] < err) && (pa[0] > -err && pa[0] < err)){
|
|
923
|
+
angle = NaN;
|
|
924
|
+
} else if(quads[0]){
|
|
925
|
+
angle = da+180;
|
|
926
|
+
} else if(quads[1]){
|
|
927
|
+
angle = da+180;
|
|
928
|
+
} else if(quads[2]){
|
|
929
|
+
angle = da;
|
|
930
|
+
} else if(quads[3]){
|
|
931
|
+
angle = da;
|
|
932
|
+
} else if(quads[4]){
|
|
933
|
+
if(pa[1] < -err) {
|
|
934
|
+
angle = -90;
|
|
935
|
+
} else if(pa[1] > err) {
|
|
936
|
+
angle = 90;
|
|
937
|
+
}
|
|
938
|
+
} else if(quads[5]){
|
|
939
|
+
if(pa[0] < -err) {
|
|
940
|
+
angle = 180;
|
|
941
|
+
} else if(pa[0] > err) {
|
|
942
|
+
angle = 0;
|
|
963
943
|
}
|
|
964
944
|
}
|
|
965
|
-
|
|
945
|
+
|
|
946
|
+
return angle;
|
|
966
947
|
}
|
|
967
948
|
|
|
968
|
-
|
|
969
|
-
|
|
949
|
+
pointTo(target) {
|
|
950
|
+
this.rotation = this.directionTo(target);
|
|
970
951
|
return this;
|
|
971
952
|
}
|
|
972
953
|
|
|
973
|
-
|
|
974
|
-
this.
|
|
975
|
-
|
|
976
|
-
object.removeFromScene(this.id);
|
|
977
|
-
}
|
|
954
|
+
setPosition(x, y) {
|
|
955
|
+
this.x = x;
|
|
956
|
+
this.y = y;
|
|
978
957
|
return this;
|
|
979
958
|
}
|
|
980
959
|
|
|
981
|
-
|
|
982
|
-
this.
|
|
983
|
-
|
|
984
|
-
obj.removeFromScene(this.id);
|
|
985
|
-
}
|
|
986
|
-
});
|
|
987
|
-
this.objects = [];
|
|
960
|
+
move(dx, dy) {
|
|
961
|
+
this.x += dx;
|
|
962
|
+
this.y += dy;
|
|
988
963
|
return this;
|
|
989
964
|
}
|
|
990
965
|
|
|
991
|
-
|
|
992
|
-
|
|
993
|
-
|
|
994
|
-
|
|
995
|
-
|
|
996
|
-
|
|
997
|
-
return this.objects.filter(obj => obj instanceof gameObject);
|
|
966
|
+
setVelocity(speed, x, y, err = 0.5){
|
|
967
|
+
let angle = this.directionTo(x,y,err);
|
|
968
|
+
|
|
969
|
+
if(isNaN(angle)){
|
|
970
|
+
angle = 0;
|
|
971
|
+
speed = 0;
|
|
998
972
|
}
|
|
999
|
-
|
|
973
|
+
|
|
974
|
+
this.velocity = [speed, angle];
|
|
975
|
+
return this.velocity;
|
|
1000
976
|
}
|
|
1001
977
|
|
|
1002
|
-
|
|
1003
|
-
|
|
978
|
+
destroy() {
|
|
979
|
+
this.removeFromAllScenes();
|
|
980
|
+
let index = MALCgameObjects.indexOf(this);
|
|
981
|
+
if (index > -1) {
|
|
982
|
+
MALCgameObjects.splice(index, 1);
|
|
983
|
+
}
|
|
1004
984
|
}
|
|
1005
985
|
|
|
1006
|
-
|
|
1007
|
-
|
|
1008
|
-
|
|
1009
|
-
|
|
1010
|
-
|
|
1011
|
-
|
|
986
|
+
clone() {
|
|
987
|
+
let clone = new gameObject(this.x, this.y, this.width, this.height, ...this.scenes);
|
|
988
|
+
clone.rotation = this.rotation;
|
|
989
|
+
clone.rotationMode = this.rotationMode;
|
|
990
|
+
clone.velocity = [...this.velocity];
|
|
991
|
+
clone.velocityMode = this.velocityMode;
|
|
992
|
+
clone.rvm = this.rvm;
|
|
993
|
+
clone.formatting = JSON.parse(JSON.stringify(this.formatting));
|
|
994
|
+
clone.gravity = JSON.parse(JSON.stringify(this.gravity));
|
|
995
|
+
clone.debug = this.debug;
|
|
996
|
+
clone.hitbox = JSON.parse(JSON.stringify(this.hitbox));
|
|
997
|
+
return clone;
|
|
998
|
+
}
|
|
999
|
+
|
|
1000
|
+
screenToWorld(screenX, screenY) {
|
|
1001
|
+
if (window.camera && typeof window.camera.screenToWorld == "function") {
|
|
1002
|
+
return window.camera.screenToWorld(screenX, screenY);
|
|
1012
1003
|
}
|
|
1013
|
-
return
|
|
1004
|
+
return { x: screenX, y: screenY };
|
|
1014
1005
|
}
|
|
1015
1006
|
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
|
|
1020
|
-
|
|
1021
|
-
|
|
1007
|
+
isOnScreen() {
|
|
1008
|
+
if (!window.camera) return true;
|
|
1009
|
+
|
|
1010
|
+
let cameraPos = window.camera.getOrientation();
|
|
1011
|
+
let screenRight = cameraPos[0] + window.camera.width;
|
|
1012
|
+
let screenBottom = cameraPos[1] + window.camera.height;
|
|
1013
|
+
|
|
1014
|
+
return (this.x + this.width/2 > cameraPos[0] &&
|
|
1015
|
+
this.x - this.width/2 < screenRight &&
|
|
1016
|
+
this.y + this.height/2 > cameraPos[1] &&
|
|
1017
|
+
this.y - this.height/2 < screenBottom);
|
|
1022
1018
|
}
|
|
1019
|
+
}
|
|
1020
|
+
|
|
1021
|
+
// ========== BUTTON CLASS ==========
|
|
1022
|
+
class Button extends gameObject {
|
|
1023
|
+
static buttons = [];
|
|
1023
1024
|
|
|
1024
|
-
|
|
1025
|
-
this.
|
|
1026
|
-
|
|
1027
|
-
|
|
1025
|
+
static updateButton() {
|
|
1026
|
+
this.startedButtons = true;
|
|
1027
|
+
this.buttons = MALCbuttons;
|
|
1028
|
+
|
|
1029
|
+
this.buttons.forEach(b => {
|
|
1030
|
+
if (!b.active) return;
|
|
1031
|
+
|
|
1032
|
+
b.isHovered = b.events.hover();
|
|
1033
|
+
|
|
1034
|
+
if (MALCbuttons.every(b => !b.events.hover())) {
|
|
1035
|
+
_p5.prototype.cursor();
|
|
1036
|
+
} else if (b.isHovered) {
|
|
1037
|
+
_p5.prototype.cursor(b.cursor);
|
|
1028
1038
|
}
|
|
1029
1039
|
});
|
|
1030
|
-
this.uiPlanes = [];
|
|
1031
|
-
return this;
|
|
1032
1040
|
}
|
|
1033
1041
|
|
|
1034
|
-
|
|
1035
|
-
|
|
1036
|
-
this.scripts.push(script);
|
|
1037
|
-
}
|
|
1038
|
-
return this;
|
|
1042
|
+
static getButtonByIndex(index) {
|
|
1043
|
+
return MALCbuttons[index] || null;
|
|
1039
1044
|
}
|
|
1040
1045
|
|
|
1041
|
-
|
|
1042
|
-
|
|
1043
|
-
return this;
|
|
1046
|
+
static getHoveredButton() {
|
|
1047
|
+
return MALCbuttons.find(b => b.active && b.events.hover());
|
|
1044
1048
|
}
|
|
1045
1049
|
|
|
1046
|
-
|
|
1047
|
-
|
|
1048
|
-
return this;
|
|
1050
|
+
static getPressedButton() {
|
|
1051
|
+
return MALCbuttons.find(b => b.active && b.events.pressed());
|
|
1049
1052
|
}
|
|
1050
1053
|
|
|
1051
|
-
|
|
1052
|
-
|
|
1053
|
-
|
|
1054
|
+
constructor(x = 0, y = 0, w = 20, h = 20, displayText = "Button", ...scenes) {
|
|
1055
|
+
super(x, y, w, h, ...scenes);
|
|
1056
|
+
|
|
1057
|
+
this.formatting.button = {
|
|
1058
|
+
hover: 220,
|
|
1059
|
+
clicked: 190,
|
|
1060
|
+
text: {
|
|
1061
|
+
color: 0,
|
|
1062
|
+
size: 14,
|
|
1063
|
+
style:"normal",
|
|
1064
|
+
display: displayText,
|
|
1065
|
+
},
|
|
1066
|
+
colors: {
|
|
1067
|
+
normal: 255,
|
|
1068
|
+
hover: 220,
|
|
1069
|
+
pressed: 190,
|
|
1070
|
+
disabled: 150
|
|
1071
|
+
}
|
|
1072
|
+
};
|
|
1073
|
+
|
|
1074
|
+
this.cursor = "pointer";
|
|
1075
|
+
this.isHovered = false;
|
|
1076
|
+
this.isPressed = false;
|
|
1077
|
+
this.isDisabled = false;
|
|
1078
|
+
this.clickCooldown = 100;
|
|
1079
|
+
this.lastClickTime = 0;
|
|
1080
|
+
this.cooldownActive = false;
|
|
1081
|
+
|
|
1082
|
+
this.events = {
|
|
1083
|
+
hover: (err = 0) => {
|
|
1084
|
+
return !this.isDisabled && (
|
|
1085
|
+
window.mouse.x < this.x + this.width / 2 + err &&
|
|
1086
|
+
window.mouse.x > this.x - (this.width / 2 + err) &&
|
|
1087
|
+
window.mouse.y < this.y + this.height / 2 + err &&
|
|
1088
|
+
window.mouse.y > this.y - (this.height / 2 + err)
|
|
1089
|
+
);
|
|
1090
|
+
},
|
|
1091
|
+
pressed: () => {
|
|
1092
|
+
return this.events.hover() && window.mouse.down;
|
|
1093
|
+
},
|
|
1094
|
+
clicked: () => {
|
|
1095
|
+
let wasPressed = this.wasPressed;
|
|
1096
|
+
let isHovering = this.events.hover();
|
|
1097
|
+
let mouseReleased = !window.mouse.down && wasPressed;
|
|
1098
|
+
|
|
1099
|
+
this.wasPressed = window.mouse.down && isHovering;
|
|
1100
|
+
|
|
1101
|
+
return mouseReleased && isHovering;
|
|
1102
|
+
}
|
|
1103
|
+
};
|
|
1104
|
+
|
|
1105
|
+
this.wasPressed = false;
|
|
1106
|
+
this.onClick = null;
|
|
1107
|
+
|
|
1108
|
+
this.buttonIndex = MALCbuttons.length;
|
|
1109
|
+
MALCbuttons.push(this);
|
|
1110
|
+
}
|
|
1111
|
+
|
|
1112
|
+
update(boolean) {
|
|
1113
|
+
super.update(boolean);
|
|
1114
|
+
|
|
1115
|
+
if (this.cooldownActive) {
|
|
1116
|
+
let currentTime = Date.now();
|
|
1117
|
+
if (currentTime - this.lastClickTime >= this.clickCooldown) {
|
|
1118
|
+
this.cooldownActive = false;
|
|
1119
|
+
}
|
|
1054
1120
|
}
|
|
1055
|
-
|
|
1121
|
+
|
|
1122
|
+
this.isHovered = this.events.hover();
|
|
1123
|
+
this.isPressed = this.events.pressed();
|
|
1124
|
+
|
|
1125
|
+
if (this.events.clicked() && this.onClick && !this.isDisabled && !this.cooldownActive) {
|
|
1126
|
+
this.onClick(this);
|
|
1127
|
+
this.lastClickTime = Date.now();
|
|
1128
|
+
this.cooldownActive = true;
|
|
1129
|
+
}
|
|
1130
|
+
|
|
1131
|
+
MALCbuttons[this.buttonIndex] = this;
|
|
1056
1132
|
}
|
|
1057
|
-
|
|
1058
|
-
|
|
1059
|
-
if (
|
|
1060
|
-
|
|
1133
|
+
|
|
1134
|
+
render() {
|
|
1135
|
+
if (!this.active) return;
|
|
1136
|
+
|
|
1137
|
+
let btnFormat = this.formatting.button;
|
|
1138
|
+
let buttonColor;
|
|
1139
|
+
|
|
1140
|
+
if (this.isDisabled) {
|
|
1141
|
+
buttonColor = btnFormat.colors.disabled;
|
|
1142
|
+
} else if (this.isPressed) {
|
|
1143
|
+
buttonColor = btnFormat.colors.pressed;
|
|
1144
|
+
} else if (this.isHovered) {
|
|
1145
|
+
buttonColor = btnFormat.colors.hover;
|
|
1146
|
+
} else {
|
|
1147
|
+
buttonColor = btnFormat.colors.normal;
|
|
1061
1148
|
}
|
|
1062
|
-
|
|
1149
|
+
|
|
1150
|
+
let originalColor = this.formatting.color;
|
|
1151
|
+
this.formatting.color = buttonColor;
|
|
1152
|
+
|
|
1153
|
+
super.render();
|
|
1154
|
+
|
|
1155
|
+
if(!this.visible) return;
|
|
1156
|
+
|
|
1157
|
+
_p5.prototype.push();
|
|
1158
|
+
_p5.prototype.translate(this.x, this.y);
|
|
1159
|
+
if (this.rotationMode == "degrees") _p5.prototype.angleMode(_p5.prototype.DEGREES);
|
|
1160
|
+
_p5.prototype.rotate(this.rotation);
|
|
1161
|
+
|
|
1162
|
+
_p5.prototype.textStyle(btnFormat.text.style);
|
|
1163
|
+
_p5.prototype.textSize(btnFormat.text.size);
|
|
1164
|
+
_p5.prototype.fill(btnFormat.text.color);
|
|
1165
|
+
|
|
1166
|
+
// Use colored text if available, otherwise use normal text
|
|
1167
|
+
if (_p5.prototype.coloredText) {
|
|
1168
|
+
_p5.prototype.coloredText(btnFormat.text.display, 0, 0, _p5.prototype.CENTER, _p5.prototype.CENTER);
|
|
1169
|
+
} else {
|
|
1170
|
+
_p5.prototype.text(btnFormat.text.display, 0, 0);
|
|
1171
|
+
}
|
|
1172
|
+
|
|
1173
|
+
_p5.prototype.pop();
|
|
1174
|
+
|
|
1175
|
+
this.formatting.color = originalColor;
|
|
1063
1176
|
}
|
|
1064
1177
|
|
|
1065
|
-
|
|
1066
|
-
|
|
1067
|
-
|
|
1068
|
-
|
|
1178
|
+
// ========== BUTTON-SPECIFIC HELPER METHODS ==========
|
|
1179
|
+
|
|
1180
|
+
setText(text) {
|
|
1181
|
+
this.formatting.button.text.display = text;
|
|
1069
1182
|
return this;
|
|
1070
1183
|
}
|
|
1071
1184
|
|
|
1072
|
-
|
|
1073
|
-
|
|
1074
|
-
return
|
|
1185
|
+
getRGBFromColor(colorInput) {
|
|
1186
|
+
let c = _p5.prototype.color(colorInput);
|
|
1187
|
+
return [_p5.prototype.red(c), _p5.prototype.green(c), _p5.prototype.blue(c)];
|
|
1075
1188
|
}
|
|
1076
1189
|
|
|
1077
|
-
|
|
1078
|
-
|
|
1079
|
-
return
|
|
1190
|
+
getBrightness(colorInput) {
|
|
1191
|
+
let rgb = this.getRGBFromColor(colorInput);
|
|
1192
|
+
return 0.299 * rgb[0] + 0.587 * rgb[1] + 0.114 * rgb[2];
|
|
1080
1193
|
}
|
|
1081
1194
|
|
|
1082
|
-
|
|
1083
|
-
|
|
1084
|
-
|
|
1085
|
-
|
|
1086
|
-
progress: 0,
|
|
1087
|
-
active: true
|
|
1088
|
-
};
|
|
1089
|
-
return this;
|
|
1195
|
+
scaleColor(baseColor, scaleFactor) {
|
|
1196
|
+
let rgb = this.getRGBFromColor(baseColor);
|
|
1197
|
+
let scaledRGB = rgb.map(val => _p5.prototype.constrain(val * scaleFactor, 0, 255));
|
|
1198
|
+
return _p5.prototype.color(scaledRGB);
|
|
1090
1199
|
}
|
|
1091
1200
|
|
|
1092
|
-
|
|
1093
|
-
if (
|
|
1094
|
-
this.
|
|
1201
|
+
setColors(normal, hover = null, pressed = null, disabled = null) {
|
|
1202
|
+
if (hover === null && pressed === null) {
|
|
1203
|
+
let originalNormal = this.formatting.button.colors.normal;
|
|
1204
|
+
let originalHover = this.formatting.button.colors.hover;
|
|
1205
|
+
let originalPressed = this.formatting.button.colors.pressed;
|
|
1206
|
+
|
|
1207
|
+
let normalBrightness = this.getBrightness(originalNormal);
|
|
1208
|
+
let hoverBrightness = this.getBrightness(originalHover);
|
|
1209
|
+
let pressedBrightness = this.getBrightness(originalPressed);
|
|
1210
|
+
|
|
1211
|
+
let hoverScale = normalBrightness !== 0 ? hoverBrightness / normalBrightness : 0.86;
|
|
1212
|
+
let pressedScale = normalBrightness !== 0 ? pressedBrightness / normalBrightness : 0.75;
|
|
1213
|
+
|
|
1214
|
+
hover = this.scaleColor(normal, hoverScale);
|
|
1215
|
+
pressed = this.scaleColor(normal, pressedScale);
|
|
1216
|
+
} else {
|
|
1217
|
+
hover = _p5.prototype.color(hover);
|
|
1218
|
+
pressed = _p5.prototype.color(pressed);
|
|
1219
|
+
}
|
|
1220
|
+
|
|
1221
|
+
let normalColor = _p5.prototype.color(normal);
|
|
1222
|
+
let disabledColor = disabled !== null ? _p5.prototype.color(disabled) : null;
|
|
1223
|
+
|
|
1224
|
+
this.formatting.button.colors.normal = normalColor;
|
|
1225
|
+
this.formatting.button.colors.hover = hover;
|
|
1226
|
+
this.formatting.button.colors.pressed = pressed;
|
|
1227
|
+
if (disabledColor !== null) {
|
|
1228
|
+
this.formatting.button.colors.disabled = disabledColor;
|
|
1095
1229
|
}
|
|
1230
|
+
|
|
1096
1231
|
return this;
|
|
1097
1232
|
}
|
|
1098
1233
|
|
|
1099
|
-
|
|
1100
|
-
|
|
1234
|
+
textStyle(color, size) {
|
|
1235
|
+
if (color !== undefined) this.formatting.button.text.color = color;
|
|
1236
|
+
if (size !== undefined) this.formatting.button.text.size = size;
|
|
1101
1237
|
return this;
|
|
1102
1238
|
}
|
|
1103
1239
|
|
|
1104
|
-
|
|
1105
|
-
|
|
1106
|
-
}
|
|
1107
|
-
|
|
1108
|
-
reset() {
|
|
1109
|
-
this.clearObjects();
|
|
1110
|
-
this.clearUIPlanes();
|
|
1111
|
-
this.clearScripts();
|
|
1112
|
-
this.onActivateCallbacks = [];
|
|
1113
|
-
this.onDeactivateCallbacks = [];
|
|
1114
|
-
this.onUpdateCallbacks = [];
|
|
1115
|
-
this.tags = [];
|
|
1116
|
-
this.paused = false;
|
|
1117
|
-
this.transition = null;
|
|
1118
|
-
this.timeActive = 0;
|
|
1240
|
+
Disable(disabled = true) {
|
|
1241
|
+
this.isDisabled = disabled;
|
|
1119
1242
|
return this;
|
|
1120
1243
|
}
|
|
1121
1244
|
|
|
1122
|
-
|
|
1123
|
-
|
|
1124
|
-
|
|
1125
|
-
MALCScene.splice(index, 1);
|
|
1126
|
-
}
|
|
1127
|
-
|
|
1128
|
-
this.clearObjects();
|
|
1129
|
-
this.clearUIPlanes();
|
|
1130
|
-
|
|
1131
|
-
if (Scene.activeScene == this.id) {
|
|
1132
|
-
Scene.activeScene = "blank";
|
|
1245
|
+
click(call) {
|
|
1246
|
+
if(typeof call == "function" && this.events.pressed()){
|
|
1247
|
+
call();
|
|
1133
1248
|
}
|
|
1134
|
-
|
|
1135
|
-
|
|
1136
|
-
clone(newId) {
|
|
1137
|
-
let clone = new Scene(newId || this.id + "_copy", this.backColor, ...this.scripts);
|
|
1138
|
-
clone.objects = [...this.objects];
|
|
1139
|
-
clone.uiPlanes = [...this.uiPlanes];
|
|
1140
|
-
clone.tags = [...this.tags];
|
|
1141
|
-
return clone;
|
|
1142
|
-
}
|
|
1143
|
-
|
|
1144
|
-
getInfo() {
|
|
1145
|
-
return {
|
|
1146
|
-
id: this.id,
|
|
1147
|
-
active: this.active,
|
|
1148
|
-
timeActive: this.timeActive,
|
|
1149
|
-
objectCount: this.objects.length,
|
|
1150
|
-
uiPlaneCount: this.uiPlanes.length,
|
|
1151
|
-
scriptCount: this.scripts.length,
|
|
1152
|
-
tags: this.tags,
|
|
1153
|
-
paused: this.paused
|
|
1154
|
-
};
|
|
1249
|
+
return this.events.clicked();
|
|
1155
1250
|
}
|
|
1156
1251
|
}
|
|
1157
1252
|
|
|
@@ -1351,20 +1446,20 @@ class UIPlane {
|
|
|
1351
1446
|
}
|
|
1352
1447
|
|
|
1353
1448
|
render() {
|
|
1354
|
-
push();
|
|
1449
|
+
_p5.prototype.push();
|
|
1355
1450
|
|
|
1356
1451
|
this.applyOrientation();
|
|
1357
1452
|
this.applyTextFormatting();
|
|
1358
1453
|
|
|
1359
1454
|
if (this.formatting.objectScale !== 1) {
|
|
1360
|
-
scale(this.formatting.objectScale);
|
|
1455
|
+
_p5.prototype.scale(this.formatting.objectScale);
|
|
1361
1456
|
}
|
|
1362
1457
|
|
|
1363
1458
|
if (typeof this.executable == "function") {
|
|
1364
1459
|
this.executable(this);
|
|
1365
1460
|
}
|
|
1366
1461
|
|
|
1367
|
-
pop();
|
|
1462
|
+
_p5.prototype.pop();
|
|
1368
1463
|
}
|
|
1369
1464
|
|
|
1370
1465
|
applyOrientation() {
|
|
@@ -1378,21 +1473,21 @@ class UIPlane {
|
|
|
1378
1473
|
} else {
|
|
1379
1474
|
cameraPos = [window.camera.x || 0, window.camera.y || 0];
|
|
1380
1475
|
}
|
|
1381
|
-
translate(cameraPos[0] + offsetX, cameraPos[1] + offsetY);
|
|
1476
|
+
_p5.prototype.translate(cameraPos[0] + offsetX, cameraPos[1] + offsetY);
|
|
1382
1477
|
} else {
|
|
1383
|
-
translate(offsetX, offsetY);
|
|
1478
|
+
_p5.prototype.translate(offsetX, offsetY);
|
|
1384
1479
|
}
|
|
1385
1480
|
} else if (mode.toLowerCase() == "screen") {
|
|
1386
|
-
translate(offsetX, offsetY);
|
|
1481
|
+
_p5.prototype.translate(offsetX, offsetY);
|
|
1387
1482
|
} else if (mode.includes(",")) {
|
|
1388
1483
|
try {
|
|
1389
1484
|
let coords = mode.split(",").map(Number);
|
|
1390
1485
|
if (coords.length >= 2) {
|
|
1391
1486
|
if (window.camera && typeof window.camera.worldToScreen == "function") {
|
|
1392
1487
|
let screenPos = window.camera.worldToScreen(coords[0], coords[1]);
|
|
1393
|
-
translate(screenPos.x + offsetX, screenPos.y + offsetY);
|
|
1488
|
+
_p5.prototype.translate(screenPos.x + offsetX, screenPos.y + offsetY);
|
|
1394
1489
|
} else {
|
|
1395
|
-
translate(coords[0] + offsetX, coords[1] + offsetY);
|
|
1490
|
+
_p5.prototype.translate(coords[0] + offsetX, coords[1] + offsetY);
|
|
1396
1491
|
}
|
|
1397
1492
|
}
|
|
1398
1493
|
} catch (e) {
|
|
@@ -1402,46 +1497,46 @@ class UIPlane {
|
|
|
1402
1497
|
}
|
|
1403
1498
|
|
|
1404
1499
|
applyTextFormatting() {
|
|
1405
|
-
textSize(this.formatting.txt.base);
|
|
1406
|
-
fill(this.formatting.txt.color);
|
|
1407
|
-
textAlign(LEFT, TOP);
|
|
1500
|
+
_p5.prototype.textSize(this.formatting.txt.base);
|
|
1501
|
+
_p5.prototype.fill(this.formatting.txt.color);
|
|
1502
|
+
_p5.prototype.textAlign(_p5.prototype.LEFT, _p5.prototype.TOP);
|
|
1408
1503
|
}
|
|
1409
1504
|
|
|
1410
1505
|
drawText(str, x, y, hAlign = LEFT, vAlign = TOP) {
|
|
1411
|
-
push();
|
|
1506
|
+
_p5.prototype.push();
|
|
1412
1507
|
|
|
1413
1508
|
if (str.startsWith("[title]")) {
|
|
1414
|
-
textSize(this.formatting.txt.title);
|
|
1509
|
+
_p5.prototype.textSize(this.formatting.txt.title);
|
|
1415
1510
|
str = str.replace("[title]", "");
|
|
1416
1511
|
} else if (str.startsWith("[heading]")) {
|
|
1417
|
-
textSize(this.formatting.txt.heading);
|
|
1512
|
+
_p5.prototype.textSize(this.formatting.txt.heading);
|
|
1418
1513
|
str = str.replace("[heading]", "");
|
|
1419
1514
|
} else if (str.startsWith("[subtitle]")) {
|
|
1420
|
-
textSize(this.formatting.txt.subtitle);
|
|
1515
|
+
_p5.prototype.textSize(this.formatting.txt.subtitle);
|
|
1421
1516
|
str = str.replace("[subtitle]", "");
|
|
1422
1517
|
} else {
|
|
1423
|
-
textSize(this.formatting.txt.base);
|
|
1518
|
+
_p5.prototype.textSize(this.formatting.txt.base);
|
|
1424
1519
|
}
|
|
1425
1520
|
|
|
1426
|
-
fill(this.formatting.txt.color);
|
|
1427
|
-
textAlign(hAlign, vAlign);
|
|
1428
|
-
text(str, x, y);
|
|
1521
|
+
_p5.prototype.fill(this.formatting.txt.color);
|
|
1522
|
+
_p5.prototype.textAlign(hAlign, vAlign);
|
|
1523
|
+
_p5.prototype.text(str, x, y);
|
|
1429
1524
|
|
|
1430
|
-
pop();
|
|
1525
|
+
_p5.prototype.pop();
|
|
1431
1526
|
}
|
|
1432
1527
|
|
|
1433
1528
|
drawButton(button, x, y) {
|
|
1434
|
-
push();
|
|
1529
|
+
_p5.prototype.push();
|
|
1435
1530
|
|
|
1436
1531
|
if (this.formatting.objectScale !== 1) {
|
|
1437
|
-
scale(this.formatting.objectScale);
|
|
1532
|
+
_p5.prototype.scale(this.formatting.objectScale);
|
|
1438
1533
|
}
|
|
1439
1534
|
|
|
1440
1535
|
if (button && typeof button.render == "function") {
|
|
1441
1536
|
button.render();
|
|
1442
1537
|
}
|
|
1443
1538
|
|
|
1444
|
-
pop();
|
|
1539
|
+
_p5.prototype.pop();
|
|
1445
1540
|
}
|
|
1446
1541
|
|
|
1447
1542
|
belongsToScene(sceneId) {
|
|
@@ -1591,7 +1686,7 @@ class Camera {
|
|
|
1591
1686
|
}
|
|
1592
1687
|
|
|
1593
1688
|
let [translateX, translateY] = this.getOrientation();
|
|
1594
|
-
translate(-translateX, -translateY);
|
|
1689
|
+
_p5.prototype.translate(-translateX, -translateY);
|
|
1595
1690
|
}
|
|
1596
1691
|
|
|
1597
1692
|
unlink() {
|
|
@@ -2130,14 +2225,14 @@ class GameController {
|
|
|
2130
2225
|
back: null,
|
|
2131
2226
|
primary: null,
|
|
2132
2227
|
secondary: null,
|
|
2133
|
-
leftbumber: null,
|
|
2134
|
-
rightbumber: null,
|
|
2135
|
-
lefttrigger: null,
|
|
2136
|
-
righttrigger: null,
|
|
2228
|
+
leftbumber: null,
|
|
2229
|
+
rightbumber: null,
|
|
2230
|
+
lefttrigger: null,
|
|
2231
|
+
righttrigger: null,
|
|
2137
2232
|
view: null,
|
|
2138
2233
|
menu: null,
|
|
2139
|
-
leftstick: null,
|
|
2140
|
-
rightstick: null,
|
|
2234
|
+
leftstick: null,
|
|
2235
|
+
rightstick: null,
|
|
2141
2236
|
up: null,
|
|
2142
2237
|
down: null,
|
|
2143
2238
|
left: null,
|
|
@@ -2262,100 +2357,6 @@ function refreshLoop() {
|
|
|
2262
2357
|
});
|
|
2263
2358
|
}
|
|
2264
2359
|
|
|
2265
|
-
// ========== COLORED TEXT FUNCTION ==========
|
|
2266
|
-
p5.prototype._parseColoredText = function(str) {
|
|
2267
|
-
const lines = str.split('\n');
|
|
2268
|
-
const result = [];
|
|
2269
|
-
|
|
2270
|
-
for (let i = 0; i < lines.length; i++) {
|
|
2271
|
-
const line = lines[i];
|
|
2272
|
-
const parts = this._parseColoredLine(line);
|
|
2273
|
-
|
|
2274
|
-
result.push(...parts);
|
|
2275
|
-
|
|
2276
|
-
if (i < lines.length - 1) {
|
|
2277
|
-
result.push({
|
|
2278
|
-
text: '\n',
|
|
2279
|
-
color: null,
|
|
2280
|
-
isNewline: true
|
|
2281
|
-
});
|
|
2282
|
-
}
|
|
2283
|
-
}
|
|
2284
|
-
|
|
2285
|
-
return result;
|
|
2286
|
-
};
|
|
2287
|
-
|
|
2288
|
-
p5.prototype._parseColoredLine = function(str) {
|
|
2289
|
-
const regex = /\\([^|\\\n]+)\|([^|]+)\|/g;
|
|
2290
|
-
const parts = [];
|
|
2291
|
-
let lastIndex = 0;
|
|
2292
|
-
let match;
|
|
2293
|
-
|
|
2294
|
-
while ((match = regex.exec(str)) !== null) {
|
|
2295
|
-
if (match.index > lastIndex) {
|
|
2296
|
-
parts.push({
|
|
2297
|
-
text: str.substring(lastIndex, match.index),
|
|
2298
|
-
color: null
|
|
2299
|
-
});
|
|
2300
|
-
}
|
|
2301
|
-
|
|
2302
|
-
parts.push({
|
|
2303
|
-
text: match[2],
|
|
2304
|
-
color: match[1]
|
|
2305
|
-
});
|
|
2306
|
-
|
|
2307
|
-
lastIndex = match.index + match[0].length;
|
|
2308
|
-
}
|
|
2309
|
-
|
|
2310
|
-
if (lastIndex < str.length) {
|
|
2311
|
-
parts.push({
|
|
2312
|
-
text: str.substring(lastIndex),
|
|
2313
|
-
color: null
|
|
2314
|
-
});
|
|
2315
|
-
}
|
|
2316
|
-
|
|
2317
|
-
return parts.length ? parts : [{ text: str, color: null }];
|
|
2318
|
-
};
|
|
2319
|
-
|
|
2320
|
-
p5.prototype.coloredText = function(str, x, y, horizontal = LEFT, vertical = BASELINE, maxWidth) {
|
|
2321
|
-
const parts = this._parseColoredText(str);
|
|
2322
|
-
let currentX = x;
|
|
2323
|
-
let currentY = y;
|
|
2324
|
-
|
|
2325
|
-
const originalFill = this.drawingContext.fillStyle;
|
|
2326
|
-
const originalAlign = this.drawingContext.textAlign;
|
|
2327
|
-
const originalBaseline = this.drawingContext.textBaseline;
|
|
2328
|
-
|
|
2329
|
-
this.textAlign(horizontal, vertical);
|
|
2330
|
-
|
|
2331
|
-
for (const part of parts) {
|
|
2332
|
-
if (part.isNewline) {
|
|
2333
|
-
currentX = x;
|
|
2334
|
-
currentY += this.textLeading() || this.textSize() * 1.2;
|
|
2335
|
-
continue;
|
|
2336
|
-
}
|
|
2337
|
-
|
|
2338
|
-
if (part.color) {
|
|
2339
|
-
try {
|
|
2340
|
-
this.fill(part.color);
|
|
2341
|
-
} catch (e) {
|
|
2342
|
-
this.fill(originalFill);
|
|
2343
|
-
}
|
|
2344
|
-
}
|
|
2345
|
-
|
|
2346
|
-
this.text(part.text, currentX, currentY, maxWidth);
|
|
2347
|
-
currentX += this.textWidth(part.text);
|
|
2348
|
-
}
|
|
2349
|
-
|
|
2350
|
-
this.fill(originalFill);
|
|
2351
|
-
if (originalAlign && originalBaseline) {
|
|
2352
|
-
this.drawingContext.textAlign = originalAlign;
|
|
2353
|
-
this.drawingContext.textBaseline = originalBaseline;
|
|
2354
|
-
}
|
|
2355
|
-
|
|
2356
|
-
return this;
|
|
2357
|
-
};
|
|
2358
|
-
|
|
2359
2360
|
// ========== FPS ACCESSOR ==========
|
|
2360
2361
|
function getFPS() {
|
|
2361
2362
|
return fps;
|
|
@@ -2366,7 +2367,7 @@ const helpDocs = {
|
|
|
2366
2367
|
// Game Engine Overview
|
|
2367
2368
|
overview: `
|
|
2368
2369
|
MALC Game Engine - A comprehensive 2D game engine for p5.js
|
|
2369
|
-
Version: 1.0.
|
|
2370
|
+
Version: 1.0.3
|
|
2370
2371
|
|
|
2371
2372
|
Core Features:
|
|
2372
2373
|
- Scene management system
|
|
@@ -2520,8 +2521,8 @@ const helpDocs = {
|
|
|
2520
2521
|
isButtonPressed: "Check button by index",
|
|
2521
2522
|
getButtonValue: "Get analog button value"
|
|
2522
2523
|
},
|
|
2523
|
-
buttonNames: ["select", "back", "primary", "secondary", "
|
|
2524
|
-
"
|
|
2524
|
+
buttonNames: ["select", "back", "primary", "secondary", "leftbumber", "rightbumber",
|
|
2525
|
+
"lefttrigger", "righttrigger", "view", "menu", "leftstick", "rightstick",
|
|
2525
2526
|
"up", "down", "left", "right", "home"]
|
|
2526
2527
|
}
|
|
2527
2528
|
},
|
|
@@ -2542,10 +2543,10 @@ const helpDocs = {
|
|
|
2542
2543
|
}
|
|
2543
2544
|
|
|
2544
2545
|
// 2. Create a scene
|
|
2545
|
-
let gameScene = new Scene("game", 220);
|
|
2546
|
+
let gameScene = new MALC.Scene("game", 220);
|
|
2546
2547
|
|
|
2547
2548
|
// 3. Create a game object with gravity
|
|
2548
|
-
let player = new gameObject(100, 100, 50, 50, "game")
|
|
2549
|
+
let player = new MALC.gameObject(100, 100, 50, 50, "game")
|
|
2549
2550
|
.enableGravity()
|
|
2550
2551
|
.setGravity({ mass: 1, bounce: 0.3 });
|
|
2551
2552
|
|
|
@@ -2558,7 +2559,7 @@ const helpDocs = {
|
|
|
2558
2559
|
|
|
2559
2560
|
// ========== MALC MAIN OBJECT ==========
|
|
2560
2561
|
const MALC = {
|
|
2561
|
-
version: "1.0.
|
|
2562
|
+
version: "1.0.3",
|
|
2562
2563
|
|
|
2563
2564
|
// Core classes
|
|
2564
2565
|
gameObject: gameObject,
|
|
@@ -2675,7 +2676,7 @@ const MALC = {
|
|
|
2675
2676
|
|
|
2676
2677
|
// Initialize the engine
|
|
2677
2678
|
init: function(canvasX, canvasY) {
|
|
2678
|
-
createCanvas(canvasX, canvasY);
|
|
2679
|
+
_p5.prototype.createCanvas(canvasX, canvasY);
|
|
2679
2680
|
|
|
2680
2681
|
this.time = new Date();
|
|
2681
2682
|
this.startTime = this.time.getTime();
|
|
@@ -2687,25 +2688,49 @@ const MALC = {
|
|
|
2687
2688
|
this.mouse = new MouseHandler();
|
|
2688
2689
|
window.mouse = this.mouse;
|
|
2689
2690
|
|
|
2691
|
+
// Add coloredText method to p5 instance safely
|
|
2692
|
+
if (!_p5.prototype.coloredText) {
|
|
2693
|
+
_p5.prototype.coloredText = function(str, x, y, horizontal, vertical, maxWidth) {
|
|
2694
|
+
renderColoredText(this, str, x, y, horizontal || LEFT, vertical || BASELINE, maxWidth);
|
|
2695
|
+
return this;
|
|
2696
|
+
};
|
|
2697
|
+
}
|
|
2698
|
+
|
|
2690
2699
|
// Start FPS tracking
|
|
2691
2700
|
refreshLoop();
|
|
2692
2701
|
|
|
2693
2702
|
// Create default scenes
|
|
2694
2703
|
new Scene("blank", 70);
|
|
2695
2704
|
new Scene("loading", 50, function(self) {
|
|
2696
|
-
|
|
2697
|
-
|
|
2698
|
-
|
|
2699
|
-
|
|
2700
|
-
|
|
2701
|
-
|
|
2702
|
-
|
|
2703
|
-
|
|
2704
|
-
|
|
2705
|
-
|
|
2706
|
-
|
|
2707
|
-
|
|
2708
|
-
|
|
2705
|
+
try {
|
|
2706
|
+
_p5.prototype.textSize(24);
|
|
2707
|
+
let timed = (self.timeActive / 250 % 4);
|
|
2708
|
+
let dots = "";
|
|
2709
|
+
|
|
2710
|
+
if (timed < 1) dots = ".";
|
|
2711
|
+
else if (timed < 2) dots = "..";
|
|
2712
|
+
else if (timed < 3) dots = "...";
|
|
2713
|
+
|
|
2714
|
+
if (_p5.prototype.coloredText) {
|
|
2715
|
+
_p5.prototype.coloredText(`\\lime|Loading Game${dots}| `, 120, 200, _p5.prototype.LEFT, _p5.prototype.CENTER);
|
|
2716
|
+
} else {
|
|
2717
|
+
_p5.prototype.text(`Loading Game${dots}`, 120, 200);
|
|
2718
|
+
}
|
|
2719
|
+
|
|
2720
|
+
_p5.prototype.textSize(16);
|
|
2721
|
+
|
|
2722
|
+
let num = (Math.floor(self.timeActive / 100) / 10);
|
|
2723
|
+
let percentText = `${ Math.round((10 - num) * 10) / 10 + ((num + "").length < 2 ? ".0" : "")}`;
|
|
2724
|
+
|
|
2725
|
+
if (_p5.prototype.coloredText) {
|
|
2726
|
+
_p5.prototype.coloredText(`\\red|${percentText}|`, 200, 225, _p5.prototype.CENTER, _p5.prototype.CENTER);
|
|
2727
|
+
} else {
|
|
2728
|
+
_p5.prototype.text(percentText, 200, 225);
|
|
2729
|
+
}
|
|
2730
|
+
} catch (e) {
|
|
2731
|
+
// Fallback if coloredText fails
|
|
2732
|
+
_p5.prototype.text(`Loading Game...`, 120, 200);
|
|
2733
|
+
}
|
|
2709
2734
|
});
|
|
2710
2735
|
|
|
2711
2736
|
Scene.activeScene = "loading";
|
|
@@ -2720,11 +2745,11 @@ const MALC = {
|
|
|
2720
2745
|
this.timer = this.time - this.startTime;
|
|
2721
2746
|
|
|
2722
2747
|
if (this.mouse) {
|
|
2723
|
-
this.mouse.rawX = mouseX;
|
|
2724
|
-
this.mouse.rawY = mouseY;
|
|
2725
|
-
this.mouse.x = this.mouse.rawX + camera.getOrientation()[0];
|
|
2726
|
-
this.mouse.y = this.mouse.rawY + camera.getOrientation()[1];
|
|
2727
|
-
this.mouse.down = mouseIsPressed;
|
|
2748
|
+
this.mouse.rawX = _p5.prototype.mouseX;
|
|
2749
|
+
this.mouse.rawY = _p5.prototype.mouseY;
|
|
2750
|
+
this.mouse.x = this.mouse.rawX + window.camera.getOrientation()[0];
|
|
2751
|
+
this.mouse.y = this.mouse.rawY + window.camera.getOrientation()[1];
|
|
2752
|
+
this.mouse.down = _p5.prototype.mouseIsPressed;
|
|
2728
2753
|
}
|
|
2729
2754
|
|
|
2730
2755
|
controller.update();
|
|
@@ -2734,8 +2759,8 @@ const MALC = {
|
|
|
2734
2759
|
|
|
2735
2760
|
this.fps = fps;
|
|
2736
2761
|
|
|
2737
|
-
if (typeof camera.render == "function") {
|
|
2738
|
-
camera.render();
|
|
2762
|
+
if (typeof window.camera.render == "function") {
|
|
2763
|
+
window.camera.render();
|
|
2739
2764
|
}
|
|
2740
2765
|
Scene.update();
|
|
2741
2766
|
}
|