Code edit (9 edits merged)
Please save this source code
User prompt
Can you fix that?
User prompt
Sort the triangles to draw back to front
Code edit (2 edits merged)
Please save this source code
User prompt
wirefrsmeMode never gets toggles
User prompt
when tap the screen toggle `wireframeMode`
Code edit (3 edits merged)
Please save this source code
User prompt
when tap the screen and not dragging, toggle `wireframeMode`
Code edit (3 edits merged)
Please save this source code
User prompt
Fix that
User prompt
The y axis gets inverted when upside
Code edit (1 edits merged)
Please save this source code
Code edit (8 edits merged)
Please save this source code
User prompt
Please fix the bug: 'ReferenceError: rotatedTriangle is not defined' in or related to this line: 'var v1 = rotatedTriangle.slice(0, 3);' Line Number: 244
Code edit (1 edits merged)
Please save this source code
User prompt
Make the triangle color darker when it's faces away from the camera.
Code edit (12 edits merged)
Please save this source code
User prompt
Put the colors of the rainbow in COLOR_ARRAY
Code edit (1 edits merged)
Please save this source code
Code edit (1 edits merged)
Please save this source code
User prompt
properly calculate the momentum
Code edit (1 edits merged)
Please save this source code
User prompt
Add momentum to the rotate by the distance between the last frame rotation
Code edit (1 edits merged)
Please save this source code
User prompt
properly calculate the momentum
/****
* 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 in radians
// Reuse pre-allocated array for result
if (!rotateTriangle.result) {
rotateTriangle.result = [0, 0, 0, 0, 0, 0, 0, 0, 0];
}
var result = rotateTriangle.result;
// Precompute sines and cosines
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);
// Helper to rotate a single point
function rotate(x, y, z) {
// Rotate around Y axis (Yaw)
var x1 = x * cosY + z * sinY;
var z1 = -x * sinY + z * cosY;
// Rotate around X axis (Pitch)
var y2 = y * cosX - z1 * sinX;
var z2 = y * sinX + z1 * cosX;
// Rotate around Z axis (Roll)
var x3 = x1 * cosZ - y2 * sinZ;
var y3 = x1 * sinZ + y2 * cosZ;
return [x3, y3, z2];
}
// Rotate each vertex
var p1 = rotate(triangle[0], triangle[1], triangle[2]);
var p2 = rotate(triangle[3], triangle[4], triangle[5]);
var p3 = rotate(triangle[6], triangle[7], triangle[8]);
result[0] = p1[0];
result[1] = p1[1];
result[2] = p1[2];
result[3] = p2[0];
result[4] = p2[1];
result[5] = p2[2];
result[6] = p3[0];
result[7] = p3[1];
result[8] = p3[2];
return result;
}
function projectTriangle(triangle) {
// triangle: [x1, y1, z1, x2, y2, z2, x3, y3, z3]
// Perspective projection parameters
var fov = 80; // 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;
}
function shadeTriangleColor(triangle, baseColor) {
// Calculate face normal in view space (after rotation, before projection)
// Get the three vertices in view space
var v1 = triangle.slice(0, 3);
var v2 = triangle.slice(3, 6);
var v3 = triangle.slice(6, 9);
// Compute vectors
var ax = v2[0] - v1[0],
ay = v2[1] - v1[1],
az = v2[2] - v1[2];
var bx = v3[0] - v1[0],
by = v3[1] - v1[1],
bz = v3[2] - v1[2];
// Cross product (normal)
var nx = ay * bz - az * by;
var ny = az * bx - ax * bz;
var nz = ax * by - ay * bx;
// Normalize normal
var nlen = Math.sqrt(nx * nx + ny * ny + nz * nz);
if (nlen > 0) {
nx /= nlen;
ny /= nlen;
nz /= nlen;
}
// Camera looks down -Z, so light direction is (0,0,-1)
var dot = nz; // dot(normal, [0,0,-1]) = nz
// Clamp dot to [0,1] for brightness (facing camera = 1, edge = 0)
var brightness = dot + 0.25;
if (brightness < 0) {
brightness = 0;
}
if (brightness > 1) {
brightness = 1;
}
// Darken color by brightness (simple shading)
var r = (baseColor >> 16 & 0xFF) * brightness;
var g = (baseColor >> 8 & 0xFF) * brightness;
var b = (baseColor & 0xFF) * brightness;
return Math.round(r) << 16 | Math.round(g) << 8 | Math.round(b);
}
function isBackfacing(projectedTriangle) {
// Check winding order using cross product of projected triangle
// projectedTriangle: [x1, y1, x2, y2, x3, y3]
var x1 = projectedTriangle[0];
var y1 = projectedTriangle[1];
var x2 = projectedTriangle[2];
var y2 = projectedTriangle[3];
var x3 = projectedTriangle[4];
var y3 = projectedTriangle[5];
// Calculate cross product to determine winding order
var crossProduct = (x2 - x1) * (y3 - y1) - (y2 - y1) * (x3 - x1);
// If cross product is negative, triangle is clockwise (backfacing)
return crossProduct < 0;
}
// Center the cube by translating to the middle of the screen
var centerX = SCREEN_SIZE / 2;
var centerY = SCREEN_SIZE / 2;
var centerZ = 16; // Move slightly back for better perspective
// Wireframe mode toggle
var wireframeMode = false;
// This is the part where the cube is drawn
// TODO: add dk water music
var angleX = Math.PI / 4;
var angleY = Math.PI / 4;
var angleZ = 0;
// Momentum variables
var momentumX = 0;
var momentumY = 0;
var lastAngleX = 0;
var lastAngleY = 0;
// Drag state for rotation
var dragStartX = null;
var dragStartAngleY = null;
var dragStartY = null;
var dragStartAngleX = null;
var isDragging = false;
// Touch/mouse down: start drag
game.down = function (x, y, obj) {
dragStartX = x;
dragStartAngleY = angleY;
dragStartY = y;
dragStartAngleX = angleX;
isDragging = true;
};
// Touch/mouse up: end drag
game.up = function (x, y, obj) {
// If not dragging (i.e. tap), toggle wireframeMode
if (!isDragging) {
wireframeMode = !wireframeMode;
}
isDragging = false;
};
// Touch/mouse move: update angles if dragging
game.move = function (x, y, obj) {
if (isDragging) {
// Horizontal drag for Y-axis rotation
var dx = x - dragStartX;
angleY = dragStartAngleY - dx / 2048 * (2 * Math.PI);
// Vertical drag for X-axis rotation
var dy = y - dragStartY;
angleX = dragStartAngleX + dy / 2732 * (2 * Math.PI);
}
};
LK.setTimeout(function () {
game.update = function () {
var triangles = [[-16, -16, -16, 16, -16, -16, -16, 16, -16], [-16, 16, -16, 16, -16, -16, 16, 16, -16], [16, -16, -16, 16, -16, 16, 16, 16, -16], [16, 16, -16, 16, -16, 16, 16, 16, 16], [-16, -16, 16, -16, 16, 16, 16, -16, 16], [-16, 16, 16, 16, 16, 16, 16, -16, 16], [-16, -16, 16, -16, -16, -16, -16, 16, 16], [-16, 16, 16, -16, -16, -16, -16, 16, -16], [16, -16, 16, 16, -16, -16, -16, -16, -16], [-16, -16, -16, -16, -16, 16, 16, -16, 16], [-16, 16, -16, 16, 16, 16, -16, 16, 16], [16, 16, 16, -16, 16, -16, 16, 16, -16]];
var COLOR_ARRAY = [0xFF0000,
// Red
0xFF7F00,
// Orange
0xFFFF00,
// Yellow
0x00FF00,
// Green
0x0000FF,
// Blue
0x4B0082
// Indigo
];
// If not dragging, apply momentum to angles
if (!isDragging) {
angleX += momentumX;
angleY += momentumY;
// Apply friction to slow down over time
momentumX *= 0.96;
momentumY *= 0.96;
// Clamp very small values to zero to avoid drift
if (Math.abs(momentumX) < 0.00001) {
momentumX = 0;
}
if (Math.abs(momentumY) < 0.00001) {
momentumY = 0;
}
}
//Start of the 3d renderer
clearScreen();
triangles.forEach(function (triangle, i) {
var rotatedTriangle = rotateTriangle(triangle, angleX, angleY, 0);
var centeredTriangle = translateTriangle(rotatedTriangle, centerX, centerY, centerZ);
var projectedTriangle = projectTriangle(centeredTriangle);
// Only draw triangle if it's not backfacing
if (!isBackfacing(projectedTriangle)) {
var shadedColor = shadeTriangleColor(rotatedTriangle, COLOR_ARRAY[Math.floor(i / 2)]);
drawTriangle(projectedTriangle, shadedColor);
if (wireframeMode) drawTriangle(projectedTriangle, 0, true);
}
});
// Update momentum based on last frame's angle change
if (isDragging) {
var deltaX = angleX - lastAngleX;
var deltaY = angleY - lastAngleY;
// Smooth momentum using an exponential moving average for a more natural feel.
momentumX = momentumX * 0.5 + deltaX * 0.5;
momentumY = momentumY * 0.5 + deltaY * 0.5;
}
lastAngleX = angleX;
lastAngleY = angleY;
};
}, 2500); ===================================================================
--- original.js
+++ change.js
@@ -290,8 +290,10 @@
// Center the cube by translating to the middle of the screen
var centerX = SCREEN_SIZE / 2;
var centerY = SCREEN_SIZE / 2;
var centerZ = 16; // Move slightly back for better perspective
+// Wireframe mode toggle
+var wireframeMode = false;
// This is the part where the cube is drawn
// TODO: add dk water music
var angleX = Math.PI / 4;
var angleY = Math.PI / 4;
@@ -316,8 +318,12 @@
isDragging = true;
};
// Touch/mouse up: end drag
game.up = function (x, y, obj) {
+ // If not dragging (i.e. tap), toggle wireframeMode
+ if (!isDragging) {
+ wireframeMode = !wireframeMode;
+ }
isDragging = false;
};
// Touch/mouse move: update angles if dragging
game.move = function (x, y, obj) {
@@ -370,9 +376,9 @@
// Only draw triangle if it's not backfacing
if (!isBackfacing(projectedTriangle)) {
var shadedColor = shadeTriangleColor(rotatedTriangle, COLOR_ARRAY[Math.floor(i / 2)]);
drawTriangle(projectedTriangle, shadedColor);
- drawTriangle(projectedTriangle, 0, true);
+ if (wireframeMode) drawTriangle(projectedTriangle, 0, true);
}
});
// Update momentum based on last frame's angle change
if (isDragging) {