Code edit (20 edits merged)
Please save this source code
User prompt
Please fix the bug: 'LK.timeout is not a function' in or related to this line: 'LK.timeout(function () {' Line Number: 249
Code edit (1 edits merged)
Please save this source code
Code edit (10 edits merged)
Please save this source code
User prompt
Make a rotation matrix in the rotateTriangle function.
User prompt
Make a rotation matrix in the rotateTriangle function.
Code edit (3 edits merged)
Please save this source code
User prompt
optimise the code for speed
Code edit (1 edits merged)
Please save this source code
User prompt
Please fix the bug: 'setTimeout is not a function' in or related to this line: 'setTimeout(clearScreen, 3000);' Line Number: 174
Code edit (5 edits merged)
Please save this source code
User prompt
Make a translateTriangle function and centre the cube with the translateTriangle function.
Code edit (2 edits merged)
Please save this source code
User prompt
Please fix the bug: 'Cannot read properties of undefined (reading '0')' in or related to this line: 'var p1 = project(triangle[0], triangle[1], triangle[2]);' Line Number: 144
User prompt
In the projectTriangle function, use perspective project on the 3 points array in the triangle parameter, and return a 2 point array to draw.
Code edit (1 edits merged)
Please save this source code
Code edit (5 edits merged)
Please save this source code
User prompt
make an arg for wireframes on the drawTri function, default false.
Code edit (2 edits merged)
Please save this source code
User prompt
In the drawTri function, fill in the triangles using the scanline rendering algorithm.
User prompt
Fill in the triangles using the scanline rendering algorithm.
Code edit (2 edits merged)
Please save this source code
User prompt
Create a class "Cube" and store the triangles for now.
Code edit (1 edits merged)
Please save this source code
User prompt
optimise the code for speed
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0
});
/****
* Game Code
****/
// Game constants for the screen
var SCREEN_SIZE = 64;
var PIXEL_SIZE = 2048 / SCREEN_SIZE;
// Cache children array reference
var screen = game.children;
function clearScreen() {
var len = screen.length;
for (var i = 0; i < len; i++) {
screen[i].tint = 0;
}
}
function putPixel(x, y, color) {
if (x >= 0 && x < SCREEN_SIZE && y >= 0 && y < SCREEN_SIZE) {
screen[x + y * SCREEN_SIZE].tint = color;
}
}
// Line drawing function using Bresenham's line algorithm
function drawLine(x0, y0, x1, y1, color) {
var dx = x1 - x0;
var dy = y1 - y0;
var adx = dx < 0 ? -dx : dx;
var ady = dy < 0 ? -dy : dy;
var sx = dx < 0 ? -1 : 1;
var sy = dy < 0 ? -1 : 1;
var err = adx - ady;
var x = x0;
var y = y0;
while (true) {
putPixel(x, y, color);
if (x === x1 && y === y1) {
break;
}
var e2 = 2 * err;
if (e2 > -ady) {
err -= ady;
x += sx;
}
if (e2 < adx) {
err += adx;
y += sy;
}
}
}
function drawTriangle(triangle, color, wireframe) {
if (wireframe === undefined) {
wireframe = false;
}
// Extract triangle vertices
var x1 = triangle[0];
var y1 = triangle[1];
var x2 = triangle[2];
var y2 = triangle[3];
var x3 = triangle[4];
var y3 = triangle[5];
// Draw the three sides of the triangle only if wireframe is true
if (wireframe) {
drawLine(x1, y1, x2, y2, color); // Side 1-2
drawLine(x2, y2, x3, y3, color); // Side 2-3
drawLine(x3, y3, x1, y1, color); // Side 3-1
} else {
// Helper to interpolate x between two points at a given y
// Sort vertices by y (ascending) - reuse pre-allocated array
if (!drawTriangle.verts) {
drawTriangle.verts = [{
x: 0,
y: 0
}, {
x: 0,
y: 0
}, {
x: 0,
y: 0
}];
}
var verts = drawTriangle.verts;
verts[0].x = x1;
verts[0].y = y1;
verts[1].x = x2;
verts[1].y = y2;
verts[2].x = x3;
verts[2].y = y3;
var interpX = function interpX(y, x0, y0, x1, y1) {
if (y1 === y0) {
return x0;
}
return x0 + (x1 - x0) * (y - y0) / (y1 - y0);
}; // Fill bottom flat triangle (v0, v1, v2) if v1.y != v0.y
verts.sort(function (a, b) {
return a.y - b.y;
});
var v0 = verts[0];
var v1 = verts[1];
var v2 = verts[2];
if (v1.y !== v0.y) {
var yStart = Math.ceil(v0.y);
var yEnd = Math.ceil(v1.y);
for (var y = yStart; y < yEnd; y++) {
var xA = interpX(y, v0.x, v0.y, v2.x, v2.y);
var xB = interpX(y, v0.x, v0.y, v1.x, v1.y);
var xStart = xA < xB ? Math.ceil(xA) : Math.ceil(xB);
var xEnd = xA > xB ? Math.floor(xA) : Math.floor(xB);
for (var x = xStart; x <= xEnd; x++) {
putPixel(x, y, color);
}
}
}
// Fill top flat triangle (v1, v2, v0) if v2.y != v1.y
if (v2.y !== v1.y) {
var yStart = Math.ceil(v1.y);
var yEnd = Math.ceil(v2.y);
for (var y = yStart; y < yEnd; y++) {
var xA = interpX(y, v0.x, v0.y, v2.x, v2.y);
var xB = interpX(y, v1.x, v1.y, v2.x, v2.y);
var xStart = xA < xB ? Math.ceil(xA) : Math.ceil(xB);
var xEnd = xA > xB ? Math.floor(xA) : Math.floor(xB);
for (var x = xStart; x <= xEnd; x++) {
putPixel(x, y, color);
}
}
}
}
}
var colorIndex = 0;
var offset = 2732 / 2 - SCREEN_SIZE * PIXEL_SIZE / 2;
// Create the screen of pixels
for (var y = 0; y < SCREEN_SIZE; y++) {
for (var x = 0; x < SCREEN_SIZE; x++) {
// Get an instance of our pixel asset
var pixel = LK.getAsset('pixel', {
x: x * PIXEL_SIZE,
y: y * PIXEL_SIZE + offset,
tint: 0
});
game.addChild(pixel);
}
}
function translateTriangle(triangle, dx, dy, dz) {
// triangle: [x1, y1, z1, x2, y2, z2, x3, y3, z3]
// Translate each vertex by dx, dy, dz - reuse pre-allocated array
if (!translateTriangle.result) {
translateTriangle.result = [0, 0, 0, 0, 0, 0, 0, 0, 0];
}
var result = translateTriangle.result;
result[0] = triangle[0] + dx;
result[1] = triangle[1] + dy;
result[2] = triangle[2] + dz;
result[3] = triangle[3] + dx;
result[4] = triangle[4] + dy;
result[5] = triangle[5] + dz;
result[6] = triangle[6] + dx;
result[7] = triangle[7] + dy;
result[8] = triangle[8] + dz;
return result;
}
function rotateTriangle(triangle, angleX, angleY, angleZ) {
// triangle: [x1, y1, z1, x2, y2, z2, x3, y3, z3]
// angleX, angleY, angleZ: rotation angles in radians
// Default angles to 0 if not provided
angleX = angleX || 0;
angleY = angleY || 0;
angleZ = angleZ || 0;
// Pre-calculate trigonometric values
var cosX = Math.cos(angleX),
sinX = Math.sin(angleX);
var cosY = Math.cos(angleY),
sinY = Math.sin(angleY);
var cosZ = Math.cos(angleZ),
sinZ = Math.sin(angleZ);
// Combined rotation matrix elements (ZYX order)
var m00 = cosY * cosZ;
var m01 = -cosY * sinZ;
var m02 = sinY;
var m10 = sinX * sinY * cosZ + cosX * sinZ;
var m11 = -sinX * sinY * sinZ + cosX * cosZ;
var m12 = -sinX * cosY;
var m20 = -cosX * sinY * cosZ + sinX * sinZ;
var m21 = cosX * sinY * sinZ + sinX * cosZ;
var m22 = cosX * cosY;
// Reuse pre-allocated array for result
if (!rotateTriangle.result) {
rotateTriangle.result = [0, 0, 0, 0, 0, 0, 0, 0, 0];
}
var result = rotateTriangle.result;
// Apply rotation to each vertex
for (var i = 0; i < 9; i += 3) {
var x = triangle[i];
var y = triangle[i + 1];
var z = triangle[i + 2];
// Apply rotation matrix
result[i] = m00 * x + m01 * y + m02 * z;
result[i + 1] = m10 * x + m11 * y + m12 * z;
result[i + 2] = m20 * x + m21 * y + m22 * z;
}
return result;
}
function projectTriangle(triangle) {
// triangle: [x1, y1, z1, x2, y2, z2, x3, y3, z3]
// Perspective projection parameters
var fov = 100; // Focal length (distance from camera to projection plane)
var cx = SCREEN_SIZE / 2;
var cy = SCREEN_SIZE / 2;
function project(x, y, z) {
// Avoid division by zero
var zz = z === 0 ? 0.0001 : z;
return [Math.round(cx + (x - cx) * (fov / (fov + zz))), Math.round(cy + (y - cy) * (fov / (fov + zz)))];
}
// Reuse pre-allocated arrays for projection results
if (!projectTriangle.result) {
projectTriangle.result = [0, 0, 0, 0, 0, 0];
}
var result = projectTriangle.result;
var p1 = project(triangle[0], triangle[1], triangle[2]);
var p2 = project(triangle[3], triangle[4], triangle[5]);
var p3 = project(triangle[6], triangle[7], triangle[8]);
// Fill result array directly
result[0] = p1[0];
result[1] = p1[1];
result[2] = p2[0];
result[3] = p2[1];
result[4] = p3[0];
result[5] = p3[1];
return result;
}
//Start of the 3d renderer
var triangles = [[0, 0, 0, 32, 0, 0, 0, 32, 0], [0, 32, 0, 32, 0, 0, 32, 32, 0], [32, 0, 0, 32, 0, 32, 32, 32, 0], [32, 32, 0, 32, 0, 32, 32, 32, 32], [0, 0, 32, 0, 32, 32, 32, 0, 32], [0, 32, 32, 32, 32, 32, 32, 0, 32], [0, 0, 32, 0, 0, 0, 0, 32, 32], [0, 32, 32, 0, 0, 0, 0, 32, 0]];
// Center the cube by translating to the middle of the screen
var centerX = SCREEN_SIZE / 2 - 16; // Center minus half cube size
var centerY = SCREEN_SIZE / 2 - 16;
var centerZ = -16; // Move slightly back for better perspective
// This is the part where the cube is drawn
var start = Date.now();
triangles.forEach(function (triangle, i) {
var centeredTriangle = translateTriangle(triangle, centerX, centerY, centerZ);
drawTriangle(projectTriangle(centeredTriangle), 0xFFFFFF, true);
});
console.log("Time: " + String(Date.now() - start)); ===================================================================
--- original.js
+++ change.js
@@ -7,16 +7,22 @@
/****
* Game Code
****/
-// Game constants for the grid
-var GRID_SIZE = 64;
-var PIXEL_SIZE = 2048 / GRID_SIZE;
+// Game constants for the screen
+var SCREEN_SIZE = 64;
+var PIXEL_SIZE = 2048 / SCREEN_SIZE;
// Cache children array reference
var screen = game.children;
+function clearScreen() {
+ var len = screen.length;
+ for (var i = 0; i < len; i++) {
+ screen[i].tint = 0;
+ }
+}
function putPixel(x, y, color) {
- if (x >= 0 && x < GRID_SIZE && y >= 0 && y < GRID_SIZE) {
- screen[x + y * GRID_SIZE].tint = color;
+ if (x >= 0 && x < SCREEN_SIZE && y >= 0 && y < SCREEN_SIZE) {
+ screen[x + y * SCREEN_SIZE].tint = color;
}
}
// Line drawing function using Bresenham's line algorithm
function drawLine(x0, y0, x1, y1, color) {
@@ -62,61 +68,74 @@
drawLine(x2, y2, x3, y3, color); // Side 2-3
drawLine(x3, y3, x1, y1, color); // Side 3-1
} else {
// Helper to interpolate x between two points at a given y
+ // Sort vertices by y (ascending) - reuse pre-allocated array
+ if (!drawTriangle.verts) {
+ drawTriangle.verts = [{
+ x: 0,
+ y: 0
+ }, {
+ x: 0,
+ y: 0
+ }, {
+ x: 0,
+ y: 0
+ }];
+ }
+ var verts = drawTriangle.verts;
+ verts[0].x = x1;
+ verts[0].y = y1;
+ verts[1].x = x2;
+ verts[1].y = y2;
+ verts[2].x = x3;
+ verts[2].y = y3;
var interpX = function interpX(y, x0, y0, x1, y1) {
if (y1 === y0) {
return x0;
}
return x0 + (x1 - x0) * (y - y0) / (y1 - y0);
}; // Fill bottom flat triangle (v0, v1, v2) if v1.y != v0.y
- // Sort vertices by y (ascending)
- var verts = [{
- x: x1,
- y: y1
- }, {
- x: x2,
- y: y2
- }, {
- x: x3,
- y: y3
- }];
verts.sort(function (a, b) {
return a.y - b.y;
});
var v0 = verts[0];
var v1 = verts[1];
var v2 = verts[2];
if (v1.y !== v0.y) {
- for (var y = Math.ceil(v0.y); y < Math.ceil(v1.y); y++) {
+ var yStart = Math.ceil(v0.y);
+ var yEnd = Math.ceil(v1.y);
+ for (var y = yStart; y < yEnd; y++) {
var xA = interpX(y, v0.x, v0.y, v2.x, v2.y);
var xB = interpX(y, v0.x, v0.y, v1.x, v1.y);
- var xStart = Math.ceil(Math.min(xA, xB));
- var xEnd = Math.floor(Math.max(xA, xB));
+ var xStart = xA < xB ? Math.ceil(xA) : Math.ceil(xB);
+ var xEnd = xA > xB ? Math.floor(xA) : Math.floor(xB);
for (var x = xStart; x <= xEnd; x++) {
putPixel(x, y, color);
}
}
}
// Fill top flat triangle (v1, v2, v0) if v2.y != v1.y
if (v2.y !== v1.y) {
- for (var y = Math.ceil(v1.y); y < Math.ceil(v2.y); y++) {
+ var yStart = Math.ceil(v1.y);
+ var yEnd = Math.ceil(v2.y);
+ for (var y = yStart; y < yEnd; y++) {
var xA = interpX(y, v0.x, v0.y, v2.x, v2.y);
var xB = interpX(y, v1.x, v1.y, v2.x, v2.y);
- var xStart = Math.ceil(Math.min(xA, xB));
- var xEnd = Math.floor(Math.max(xA, xB));
+ var xStart = xA < xB ? Math.ceil(xA) : Math.ceil(xB);
+ var xEnd = xA > xB ? Math.floor(xA) : Math.floor(xB);
for (var x = xStart; x <= xEnd; x++) {
putPixel(x, y, color);
}
}
}
}
}
var colorIndex = 0;
-var offset = 2732 / 2 - GRID_SIZE * PIXEL_SIZE / 2;
-// Create the grid of pixels
-for (var y = 0; y < GRID_SIZE; y++) {
- for (var x = 0; x < GRID_SIZE; x++) {
+var offset = 2732 / 2 - SCREEN_SIZE * PIXEL_SIZE / 2;
+// Create the screen of pixels
+for (var y = 0; y < SCREEN_SIZE; y++) {
+ for (var x = 0; x < SCREEN_SIZE; x++) {
// Get an instance of our pixel asset
var pixel = LK.getAsset('pixel', {
x: x * PIXEL_SIZE,
y: y * PIXEL_SIZE + offset,
@@ -126,40 +145,102 @@
}
}
function translateTriangle(triangle, dx, dy, dz) {
// triangle: [x1, y1, z1, x2, y2, z2, x3, y3, z3]
- // Translate each vertex by dx, dy, dz
- return [triangle[0] + dx, triangle[1] + dy, triangle[2] + dz, triangle[3] + dx, triangle[4] + dy, triangle[5] + dz, triangle[6] + dx, triangle[7] + dy, triangle[8] + dz];
+ // Translate each vertex by dx, dy, dz - reuse pre-allocated array
+ if (!translateTriangle.result) {
+ translateTriangle.result = [0, 0, 0, 0, 0, 0, 0, 0, 0];
+ }
+ var result = translateTriangle.result;
+ result[0] = triangle[0] + dx;
+ result[1] = triangle[1] + dy;
+ result[2] = triangle[2] + dz;
+ result[3] = triangle[3] + dx;
+ result[4] = triangle[4] + dy;
+ result[5] = triangle[5] + dz;
+ result[6] = triangle[6] + dx;
+ result[7] = triangle[7] + dy;
+ result[8] = triangle[8] + dz;
+ return result;
}
+function rotateTriangle(triangle, angleX, angleY, angleZ) {
+ // triangle: [x1, y1, z1, x2, y2, z2, x3, y3, z3]
+ // angleX, angleY, angleZ: rotation angles in radians
+ // Default angles to 0 if not provided
+ angleX = angleX || 0;
+ angleY = angleY || 0;
+ angleZ = angleZ || 0;
+ // Pre-calculate trigonometric values
+ var cosX = Math.cos(angleX),
+ sinX = Math.sin(angleX);
+ var cosY = Math.cos(angleY),
+ sinY = Math.sin(angleY);
+ var cosZ = Math.cos(angleZ),
+ sinZ = Math.sin(angleZ);
+ // Combined rotation matrix elements (ZYX order)
+ var m00 = cosY * cosZ;
+ var m01 = -cosY * sinZ;
+ var m02 = sinY;
+ var m10 = sinX * sinY * cosZ + cosX * sinZ;
+ var m11 = -sinX * sinY * sinZ + cosX * cosZ;
+ var m12 = -sinX * cosY;
+ var m20 = -cosX * sinY * cosZ + sinX * sinZ;
+ var m21 = cosX * sinY * sinZ + sinX * cosZ;
+ var m22 = cosX * cosY;
+ // Reuse pre-allocated array for result
+ if (!rotateTriangle.result) {
+ rotateTriangle.result = [0, 0, 0, 0, 0, 0, 0, 0, 0];
+ }
+ var result = rotateTriangle.result;
+ // Apply rotation to each vertex
+ for (var i = 0; i < 9; i += 3) {
+ var x = triangle[i];
+ var y = triangle[i + 1];
+ var z = triangle[i + 2];
+ // Apply rotation matrix
+ result[i] = m00 * x + m01 * y + m02 * z;
+ result[i + 1] = m10 * x + m11 * y + m12 * z;
+ result[i + 2] = m20 * x + m21 * y + m22 * z;
+ }
+ return result;
+}
function projectTriangle(triangle) {
// triangle: [x1, y1, z1, x2, y2, z2, x3, y3, z3]
// Perspective projection parameters
var fov = 100; // Focal length (distance from camera to projection plane)
- var cx = GRID_SIZE / 2;
- var cy = GRID_SIZE / 2;
+ var cx = SCREEN_SIZE / 2;
+ var cy = SCREEN_SIZE / 2;
function project(x, y, z) {
// Avoid division by zero
var zz = z === 0 ? 0.0001 : z;
return [Math.round(cx + (x - cx) * (fov / (fov + zz))), Math.round(cy + (y - cy) * (fov / (fov + zz)))];
}
+ // Reuse pre-allocated arrays for projection results
+ if (!projectTriangle.result) {
+ projectTriangle.result = [0, 0, 0, 0, 0, 0];
+ }
+ var result = projectTriangle.result;
var p1 = project(triangle[0], triangle[1], triangle[2]);
var p2 = project(triangle[3], triangle[4], triangle[5]);
var p3 = project(triangle[6], triangle[7], triangle[8]);
- // Return as flat array for drawTriangle: [x1, y1, x2, y2, x3, y3]
- return [p1[0], p1[1], p2[0], p2[1], p3[0], p3[1]];
+ // Fill result array directly
+ result[0] = p1[0];
+ result[1] = p1[1];
+ result[2] = p2[0];
+ result[3] = p2[1];
+ result[4] = p3[0];
+ result[5] = p3[1];
+ return result;
}
-;
//Start of the 3d renderer
-// 3 points
var triangles = [[0, 0, 0, 32, 0, 0, 0, 32, 0], [0, 32, 0, 32, 0, 0, 32, 32, 0], [32, 0, 0, 32, 0, 32, 32, 32, 0], [32, 32, 0, 32, 0, 32, 32, 32, 32], [0, 0, 32, 0, 32, 32, 32, 0, 32], [0, 32, 32, 32, 32, 32, 32, 0, 32], [0, 0, 32, 0, 0, 0, 0, 32, 32], [0, 32, 32, 0, 0, 0, 0, 32, 0]];
-var start = Date.now();
-// Center the cube by translating to the middle of the grid
-var centerX = GRID_SIZE / 2 - 16; // Center minus half cube size
-var centerY = GRID_SIZE / 2 - 16;
+// Center the cube by translating to the middle of the screen
+var centerX = SCREEN_SIZE / 2 - 16; // Center minus half cube size
+var centerY = SCREEN_SIZE / 2 - 16;
var centerZ = -16; // Move slightly back for better perspective
// This is the part where the cube is drawn
+var start = Date.now();
triangles.forEach(function (triangle, i) {
var centeredTriangle = translateTriangle(triangle, centerX, centerY, centerZ);
drawTriangle(projectTriangle(centeredTriangle), 0xFFFFFF, true);
});
-console.log("Time: " + String(Date.now() - start));
-;
\ No newline at end of file
+console.log("Time: " + String(Date.now() - start));
\ No newline at end of file