Code edit (3 edits merged)
Please save this source code
Code edit (9 edits merged)
Please save this source code
User prompt
Please fix the bug: 'ReferenceError: isDragging is not defined' in or related to this line: 'if (!isDragging) {' Line Number: 405
Code edit (3 edits merged)
Please save this source code
User prompt
before creating the screen, ask the player if they want low or high resolution.
User prompt
Optimize this
Code edit (1 edits merged)
Please save this source code
User prompt
flip the y axis control when upside down
User prompt
flip the y axis control when upside down
Code edit (1 edits merged)
Please save this source code
User prompt
Draw lines on each edges
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0
});
/****
* Game Code
****/
// Game constants for the screen
var SELECTED_RESOLUTION = null;
var resolutionSelected = false;
// Cache children array reference
var screen = game.children;
// Pre-allocate reusable arrays to avoid garbage collection
var tempRotatedTriangle = [0, 0, 0, 0, 0, 0, 0, 0, 0];
var tempCenteredTriangle = [0, 0, 0, 0, 0, 0, 0, 0, 0];
var tempProjectedTriangle = [0, 0, 0, 0, 0, 0];
var tempVertex1 = [0, 0, 0];
var tempVertex2 = [0, 0, 0];
var tempVertex3 = [0, 0, 0];
// Optimized screen clearing - only clear visible pixels
var visiblePixels = [];
function clearScreen() {
var len = visiblePixels.length;
for (var i = 0; i < len; i++) {
visiblePixels[i].tint = 0;
}
visiblePixels.length = 0;
}
function putPixel(x, y, color) {
if (x >= 0 && x < SCREEN_SIZE && y >= 0 && y < SCREEN_SIZE) {
var pixel = screen[x + y * SCREEN_SIZE];
pixel.tint = color;
visiblePixels.push(pixel);
}
}
// 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;
// Resolution selection UI
var resolutionTitle = new Text2('Choose Resolution', {
size: 120,
fill: 0xFFFFFF
});
resolutionTitle.anchor.set(0.5, 0.5);
resolutionTitle.x = 2048 / 2;
resolutionTitle.y = 2732 / 2 - 300;
game.addChild(resolutionTitle);
var lowResText = new Text2('Low Resolution (64x64)', {
size: 80,
fill: 0x00FF00
});
lowResText.anchor.set(0.5, 0.5);
lowResText.x = 2048 / 2;
lowResText.y = 2732 / 2 - 100;
game.addChild(lowResText);
var highResText = new Text2('High Resolution (96x96)', {
size: 80,
fill: 0x0066FF
});
highResText.anchor.set(0.5, 0.5);
highResText.x = 2048 / 2;
highResText.y = 2732 / 2 + 100;
game.addChild(highResText);
// Add touch handlers for resolution selection
lowResText.down = function (x, y, obj) {
SELECTED_RESOLUTION = 'low';
SCREEN_SIZE = 64;
PIXEL_SIZE = 2048 / SCREEN_SIZE;
var offset = 2732 / 2 - SCREEN_SIZE * PIXEL_SIZE / 2;
resolutionSelected = true;
// Remove UI elements
game.removeChild(resolutionTitle);
game.removeChild(lowResText);
game.removeChild(highResText);
// 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);
}
}
};
highResText.down = function (x, y, obj) {
SELECTED_RESOLUTION = 'high';
SCREEN_SIZE = 96;
PIXEL_SIZE = 2048 / SCREEN_SIZE;
var offset = 2732 / 2 - SCREEN_SIZE * PIXEL_SIZE / 2;
resolutionSelected = true;
// Remove UI elements
game.removeChild(resolutionTitle);
game.removeChild(lowResText);
game.removeChild(highResText);
// Create the screen of pixels using high res asset
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('pixelHighRes', {
x: x * PIXEL_SIZE,
y: y * PIXEL_SIZE + offset,
tint: 0
});
game.addChild(pixel);
}
}
};
function translateTriangle(triangle, dx, dy, dz, result) {
// triangle: [x1, y1, z1, x2, y2, z2, x3, y3, z3]
// Translate each vertex by dx, dy, dz - use provided result array
for (var i = 0; i < 9; i += 3) {
result[i] = triangle[i] + dx;
result[i + 1] = triangle[i + 1] + dy;
result[i + 2] = triangle[i + 2] + dz;
}
return result;
}
function rotateTriangle(triangle, angleX, angleY, angleZ, result) {
// triangle: [x1, y1, z1, x2, y2, z2, x3, y3, z3]
// angleX, angleY, angleZ in radians
// 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);
// Inline rotation for better performance - rotate each vertex directly
for (var i = 0; i < 9; i += 3) {
var x = triangle[i];
var y = triangle[i + 1];
var z = triangle[i + 2];
// 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;
result[i] = x3;
result[i + 1] = y3;
result[i + 2] = z2;
}
return result;
}
function projectTriangle(triangle, result) {
// 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;
// Inline projection for better performance
for (var i = 0; i < 9; i += 3) {
var x = triangle[i];
var y = triangle[i + 1];
var z = triangle[i + 2];
// Avoid division by zero
var zz = z === 0 ? 0.0001 : z;
var projIdx = i / 3 * 2;
result[projIdx] = Math.round(cx + (x - cx) * (fov / (fov + zz)));
result[projIdx + 1] = Math.round(cy + (y - cy) * (fov / (fov + zz)));
}
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;
}
// Drag variables
var isDragging = false;
var dragStartX = 0;
var dragStartY = 0;
var dragStartAngleX = 0;
var dragStartAngleY = 0;
var angleX = Math.PI / 4;
var angleY = Math.PI / 4;
var momentumX = 0;
var momentumY = 0;
var lastAngleX = 0;
var lastAngleY = 0;
// Initialize cube rendering after resolution is selected
function initializeCubeRendering() {
// Touch/mouse down: start drag
game.down = function (x, y, obj) {
if (!resolutionSelected) {
return;
}
dragStartX = x;
dragStartAngleY = angleY;
dragStartY = y;
dragStartAngleX = angleX;
isDragging = true;
};
// Touch/mouse up: end drag
game.up = function (x, y, obj) {
if (!resolutionSelected) {
return;
}
isDragging = false;
};
// Touch/mouse move: update angles if dragging
game.move = function (x, y, obj) {
if (!resolutionSelected) {
return;
}
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);
}
};
game.update = function () {
if (!resolutionSelected) {
return;
}
// 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
if (SELECTED_RESOLUTION == 'high') {
var triangles = [[-24, -24, -24, 24, -24, -24, -24, 24, -24], [-24, 24, -24, 24, -24, -24, 24, 24, -24], [24, -24, -24, 24, -24, 24, 24, 24, -24], [24, 24, -24, 24, -24, 24, 24, 24, 24], [-24, -24, 24, -24, 24, 24, 24, -24, 24], [-24, 24, 24, 24, 24, 24, 24, -24, 24], [-24, -24, 24, -24, -24, -24, -24, 24, 24], [-24, 24, 24, -24, -24, -24, -24, 24, -24], [24, -24, 24, 24, -24, -24, -24, -24, -24], [-24, -24, -24, -24, -24, 24, 24, -24, 24], [-24, 24, -24, 24, 24, 24, -24, 24, 24], [24, 24, 24, -24, 24, -24, 24, 24, -24]];
} else {
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();
for (var i = 0; i < triangles.length; i++) {
var triangle = triangles[i];
rotateTriangle(triangle, angleX, angleY, 0, tempRotatedTriangle);
translateTriangle(tempRotatedTriangle, centerX, centerY, centerZ, tempCenteredTriangle);
projectTriangle(tempCenteredTriangle, tempProjectedTriangle);
// Only draw triangle if it's not backfacing
if (!isBackfacing(tempProjectedTriangle)) {
var shadedColor = shadeTriangleColor(tempRotatedTriangle, COLOR_ARRAY[Math.floor(i / 2)]);
drawTriangle(tempProjectedTriangle, shadedColor);
drawTriangle(tempProjectedTriangle, 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;
};
}
// Initialize cube rendering immediately
initializeCubeRendering(); ===================================================================
--- original.js
+++ change.js
@@ -380,10 +380,10 @@
}
// Center the cube by translating to the middle of the screen
var centerX = SCREEN_SIZE / 2;
var centerY = SCREEN_SIZE / 2;
- var centerZ = 8; // Move slightly back for better perspective
- if (resolutionSelected == 'high') {
+ var centerZ = 16; // Move slightly back for better perspective
+ if (SELECTED_RESOLUTION == 'high') {
var triangles = [[-24, -24, -24, 24, -24, -24, -24, 24, -24], [-24, 24, -24, 24, -24, -24, 24, 24, -24], [24, -24, -24, 24, -24, 24, 24, 24, -24], [24, 24, -24, 24, -24, 24, 24, 24, 24], [-24, -24, 24, -24, 24, 24, 24, -24, 24], [-24, 24, 24, 24, 24, 24, 24, -24, 24], [-24, -24, 24, -24, -24, -24, -24, 24, 24], [-24, 24, 24, -24, -24, -24, -24, 24, -24], [24, -24, 24, 24, -24, -24, -24, -24, -24], [-24, -24, -24, -24, -24, 24, 24, -24, 24], [-24, 24, -24, 24, 24, 24, -24, 24, 24], [24, 24, 24, -24, 24, -24, 24, 24, -24]];
} else {
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]];
}