Reputation: 11
I have a game engine type thing and I'm tring to make it so the users can have multiple 'poopengine-window' elements and specify a Javascript file for that specific game window to use. However I cannot figure out how to comunicate between these two files properly without using window variable. Here is the older version on github. Currently I get this error:
Uncaught (in promise) ReferenceError: poopengine is not defined
<anonymous> http://127.0.0.1:5500/poopengine.mjs line 408 > eval:1
attributeChangedCallback http://127.0.0.1:5500/poopengine.mjs:408
promise callback*attributeChangedCallback/< http://127.0.0.1:5500/poopengine.mjs:403
promise callback*attributeChangedCallback http://127.0.0.1:5500/poopengine.mjs:403
<anonymous> http://127.0.0.1:5500/poopengine.mjs:413
Here is the code:
index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<script src="../poopengine.mjs" type="module"></script>
<style>
body {
padding: 0;
margin: 0;
overflow: hidden;
}
</style>
</head>
<body>
<poopengine-window script="./main.js"></poopengine-window>
</body>
</html>
main.js
const originalStart = poopengine.start;
poopengine.start = function () {
originalStart.apply(this);
const box = poopengine.object({
width: 50,
height: 50,
x: 0,
y: 0,
colour: 'blue'
});
}
const originalUpdate = poopengine.update;
poopengine.update = function () {
originalUpdate.apply(this);
// Code goes here:
}
poopengine.resize = function () {
// Code goes here:
}
poopengine.start();
poopengine.mjs
class poopengine_class {
constructor(canvas) {
this.canvas = canvas;
this.display = { width: 300, height: 200 };
this.context = null;
this.objects = [];
this.input = new class input {
constructor() {
this.keydown = null;
this.keypressed = null;
this.keyup = null;
this.click = null;
this.mousedown = null;
this.mouseup = null;
this.mouse_pos = { x: null, y: null };
this.hovering = function (object) {
if (this.mouse_pos.x != null) {
const index = poopengine.objects.indexOf(object);
const array = poopengine.objects.slice(index + 1);
for (let i = 0; i < array.length; i++) {
if (
this.mouse_pos.x >= array[i].x &&
this.mouse_pos.x <= array[i].x + array[i].width &&
this.mouse_pos.y >= array[i].y &&
this.mouse_pos.y <= array[i].y + array[i].height
) {
return false;
}
}
if (
this.mouse_pos.x >= object.x &&
this.mouse_pos.x <= object.x + object.width &&
this.mouse_pos.y >= object.y &&
this.mouse_pos.y <= object.y + object.height
) {
return true;
} else {
return false;
}
}
}
}
}
this.fps = 0;
this.deltaTime = 1;
this.times = [];
this.start = function () {
if (!this.canvas) {
console.error("Canvas is not initialized yet.");
return;
}
this.canvas.click();
this.canvas.width = this.display.width;
this.canvas.height = this.display.height;
this.context = this.canvas.getContext("2d");
// Event listeners
window.onresize = () => {
this.resize();
};
// Mouse input
window.addEventListener("mousedown", () => {
this.input.mousedown = true;
});
window.addEventListener("click", () => {
if (this.input.click == null) {
this.input.click = true;
setTimeout(() => {
this.input.click = null;
}, 10);
}
});
window.addEventListener("mouseup", () => {
this.input.mouseup = true;
this.input.mousedown = null;
setTimeout(() => {
this.input.mouseup = null;
}, 10);
});
window.addEventListener("mousemove", (event) => {
this.input.mouse_pos = { x: event.clientX, y: event.clientY };
});
// Input
window.addEventListener("keydown", (event) => {
this.input.keydown = event.key;
});
window.addEventListener("keypress", (event) => {
if (this.input.keypressed == null) {
this.input.keypressed = event.key;
setTimeout(() => {
this.input.keypressed = null;
}, 10);
}
});
window.addEventListener("keyup", (event) => {
this.input.keyup = event.key;
this.input.keydown = null;
setTimeout(() => {
this.input.keyup = null;
}, 10);
});
window.requestAnimationFrame(() => this.update());
};
this.update = function () {
this.context.reset()
window.requestAnimationFrame(() => this.update());
this.context.clearRect(0, 0, this.display.width, this.display.height);
// Fps and delta calculation
const now = performance.now();
if (this.times.length > 0) {
this.deltaTime = now - this.times[this.times.length - 1];
}
while (this.times.length > 0 && this.times[0] <= now - 1000) {
this.times.shift();
}
this.times.push(now);
this.fps = this.times.length;
// Update object drawing
for (let i = 0; i < this.objects.length; i++) {
this.objects[i].update();
}
};
// Utitlty functions
this.object = function ({
width,
height,
x,
y,
colour,
image,
tile,
image_alpha,
text,
text_size,
font,
word_wrap,
line_height,
text_align,
}) {
this.width = width;
this.height = height;
this.x = x;
this.y = y;
this.colour = colour;
let ctx = poopengine.context;
// Image logic
if (image != undefined) {
this.image = new Image();
this.image.src = image;
this.image_alpha = image_alpha;
if (this.image_alpha != undefined) {
ctx.globalAlpha = this.image_alpha;
}
if (tile == undefined || tile == false) {
ctx.drawImage(this.image, this.x, this.y, this.width, this.height);
} else {
this.pattern = ctx.createPattern(this.image, "repeat");
ctx.fillStyle = this.pattern;
ctx.fillRect(this.x, this.y, this.width, this.height);
}
}
// Text logic
else if (text != undefined) {
ctx.fillStyle = this.colour;
this.text = text;
this.text_size = text_size;
if (font != undefined) {
this.font = font;
ctx.font = String(text_size + "px " + font);
} else {
ctx.font = String(text_size + "px Arial");
}
if (text_align != undefined) {
ctx.textAlign = text_align;
}
ctx.fillText(this.text, this.x, this.text_size + this.y, this.width);
}
// Box logic
else {
ctx.fillStyle = this.colour;
ctx.fillRect(this.x, this.y, this.width, this.height);
}
this.update = function () {
// Image logic
if (image != undefined) {
if (this.image_alpha != undefined) {
ctx.globalAlpha = this.image_alpha;
}
if (tile == undefined || tile == false) {
ctx.drawImage(this.image, this.x, this.y, this.width, this.height);
} else {
this.pattern = ctx.createPattern(this.image, "repeat");
ctx.fillStyle = this.pattern;
ctx.fillRect(this.x, this.y, this.width, this.height);
}
}
// Text logic
else if (text != undefined) {
ctx.fillStyle = this.colour;
if (this.font != undefined) {
ctx.font = String(this.text_size + "px " + this.font);
} else {
ctx.font = String(this.text_size + "px Arial");
}
if (word_wrap == true) {
this.line_height = line_height;
const words = this.text.split(" ");
let currentLine = words[0];
let lineCount = 0;
for (let i = 1; i < words.length; i++) {
const word = words[i];
const width = ctx.measureText(currentLine + " " + word).width;
if (width < this.width) {
currentLine += " " + word;
} else {
ctx.fillText(
currentLine,
this.x,
this.y + this.line_height * lineCount++ + this.text_size
);
currentLine = word;
}
}
ctx.fillText(
currentLine,
this.x,
this.y + this.line_height * lineCount + this.text_size
);
} else {
ctx.fillText(this.text, this.x, this.y + this.text_size, this.width);
}
}
// Box logic
else {
ctx.fillStyle = this.colour;
ctx.fillRect(this.x, this.y, this.width, this.height);
}
};
this.destroy = function () {
const index = poopengine.objects.indexOf(this);
poopengine.objects.splice(index, 1);
};
poopengine.objects.push(this);
this.index = poopengine.objects.indexOf(this);
ctx.reset();
};
// TODO: fix audio
/* this.audio = function (src) {
this.sound = document.createElement("audio");
this.sound.src = src;
this.sound.setAttribute("preload", "auto");
this.sound.setAttribute("controls", "none");
this.sound.style.display = "none";
document.body.appendChild(this.sound);
this.play = function () {
this.sound.play();
};
this.stop = function () {
this.sound.pause();
this.sound.currentTime = 0;
};
this.pause = function () {
this.sound.pause();
};
this.loop = function (option) {
this.sound.loop = option;
};
}, */
// Z index logic
this.move_to_top = function (object) {
const index = this.objects.indexOf(object);
if (index !== -1) {
this.objects.splice(index, 1);
}
this.objects.push(object);
};
this.send_to_back_bg = function (object) {
const index = this.objects.indexOf(object);
if (index !== -1) {
this.objects.splice(index, 1);
this.objects.splice(1, 0, object);
}
};
this.send_to_back = function (object) {
const index = this.objects.indexOf(object);
if (index !== -1) {
this.objects.splice(index, 1);
}
this.objects.unshift(object);
};
this.change_index = function (object, change) {
const index = this.objects.indexOf(object);
const new_index = index + change;
if (index !== -1) {
this.objects.splice(index, 1);
this.objects.splice(new_index, 0, object);
}
};
this.set_index = function (object, new_index) {
const index = this.objects.indexOf(object);
if (index !== -1) {
this.objects.splice(index, new_index);
this.objects.splice(new_index, 0, object);
}
};
this.revert_index = function (object) {
const currentIndex = this.objects.indexOf(object);
if (currentIndex !== -1 && typeof object.index === "number") {
this.objects.splice(currentIndex, 1);
this.objects.splice(object.index, 0, object);
}
};
this.resize= function () {};
// Animation
this.animating_vals = []
this.animate_value = function (id, val, increase, speed, until, callback, finish) {
let isBigger;
if (val < until) {
isBigger = true;
} else {
isBigger = false;
}
if (!this.animating_vals.includes(id)) {
this.animating_vals.push(id);
const inter = setInterval(() => {
val += increase;
if (val >= until && isBigger) {
if (finish != undefined) {
finsish()
}
clearInterval(inter);
val = until;
} else if (val <= until && !isBigger) {
if (finish != undefined) {
finsish()
}
clearInterval(inter);
val = until;
}
callback(val);
}, speed);
}
}
}
}
class poopengine_component extends HTMLElement {
static observedAttributes = ['script'];
constructor() {
super();
}
attributeChangedCallback(name, _oldValue, newValue) {
fetch(newValue).then(res => res.text().then(scr => {
const shadowRoot = this.attachShadow({ mode: 'open' });
const canvas = document.createElement('canvas');
shadowRoot.append(canvas);
const localPoopengine = new poopengine_class(canvas);
eval(scr);
}));
}
}
customElements.define("poopengine-window", poopengine_component);
I've searched everywhere and can't find a solution. Any help would be greatly appreciated. 😀
Edit: Just though I would go into a bit more detail. It runs the functions properly in main.js. However the poopengine.object doesn't run and is the part where poopengine is not defined.
Upvotes: 1
Views: 45
Reputation: 11
The issue was that in my poopengine class I was calling poopengine itself instead of this. There was nothing wrong with my eval however I am now using Function instead. Thanks for the help. 😁
Upvotes: 0
Reputation: 36
Somehow my answer got turned into a comment...
I believe this relates to your problem: Access imported functions from evaled code
Here is the annotation to the eval()
function from the MDN documentation:
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/eval#script
"It will be parsed as a script, so import declarations (which can only exist in modules) are not allowed."
Upvotes: 0