User prompt
what we have put "brick programs" should not just start one but all of them
User prompt
there should be a white cube at the bottom where can see the finished game
User prompt
there should be no levels
Code edit (1 edits merged)
Please save this source code
User prompt
BlockCode Builder
Initial prompt
Make a game that has infinite "brick programs" and can make a game with these "brick programs"
/**** * Plugins ****/ var tween = LK.import("@upit/tween.v1"); var storage = LK.import("@upit/storage.v1"); /**** * Classes ****/ var BlockPalette = Container.expand(function (width, height) { var self = Container.call(this); self.paletteWidth = width || 400; self.paletteHeight = height || 2732; // Create background self.background = self.addChild(LK.getAsset('codeBlock', { anchorX: 0, anchorY: 0, width: self.paletteWidth, height: self.paletteHeight, alpha: 0.3, tint: 0x333333 })); // Add title self.title = new Text2("Block Palette", { size: 40, fill: 0xFFFFFF }); self.title.anchor.set(0.5, 0); self.title.x = self.paletteWidth / 2; self.title.y = 30; self.addChild(self.title); // Add blocks to palette self.addBlockToPalette = function (type, text, x, y) { var block = new CodeBlock(type, text); block.x = x; block.y = y; // This is a template block - when dragged, it creates a new instance block.down = function (x, y, obj) { // Create a new block when this template is clicked var newBlock = new CodeBlock(type, text); newBlock.x = block.x; newBlock.y = block.y; // Convert to global position var globalPos = self.parent.toGlobal({ x: block.x, y: block.y }); newBlock.x = globalPos.x; newBlock.y = globalPos.y; // Add to game's blocks array blocks.push(newBlock); // Add to game game.addChild(newBlock); // Start dragging the new block newBlock.startDragX = newBlock.x; newBlock.startDragY = newBlock.y; newBlock.isDragging = true; draggedBlock = newBlock; }; self.addChild(block); return block; }; return self; }); var Button = Container.expand(function (text, width, height, color) { var self = Container.call(this); self.buttonWidth = width || 200; self.buttonHeight = height || 80; self.buttonColor = color || 0x4287f5; // Create button background self.background = self.addChild(LK.getAsset('codeBlock', { anchorX: 0.5, anchorY: 0.5, width: self.buttonWidth, height: self.buttonHeight, tint: self.buttonColor })); // Add text self.label = new Text2(text, { size: 30, fill: 0xFFFFFF }); self.label.anchor.set(0.5, 0.5); self.addChild(self.label); // Handle down event self.down = function (x, y, obj) { // Visual feedback tween(self.background, { scaleX: 0.95, scaleY: 0.95 }, { duration: 100 }); }; // Handle up event self.up = function (x, y, obj) { // Reset scale tween(self.background, { scaleX: 1, scaleY: 1 }, { duration: 100, onFinish: function onFinish() { // Call the button's action if (self.action) { self.action(); } } }); }; return self; }); var CodeArea = Container.expand(function (width, height) { var self = Container.call(this); self.areaWidth = width || 1200; self.areaHeight = height || 1500; // Create background self.background = self.addChild(LK.getAsset('codeBlock', { anchorX: 0, anchorY: 0, width: self.areaWidth, height: self.areaHeight, alpha: 0.2, tint: 0x222222 })); // Method to check if a point is inside the code area self.isPointInside = function (x, y) { var globalPos = game.toLocal({ x: x, y: y }, self.parent); return globalPos.x >= self.x && globalPos.x <= self.x + self.areaWidth && globalPos.y >= self.y && globalPos.y <= self.y + self.areaHeight; }; return self; }); var CodeBlock = Container.expand(function (type, text) { var self = Container.call(this); self.type = type || 'default'; self.text = text || ''; self.connections = { top: null, bottom: null, left: null, right: null }; self.canConnect = true; self.isExecuting = false; // Select the correct asset based on type var assetId = 'codeBlock'; if (self.type === 'variable') { assetId = 'codeBlockVar'; } else if (self.type === 'loop') { assetId = 'codeBlockLoop'; } else if (self.type === 'condition') { assetId = 'codeBlockCondition'; } else if (self.type === 'function') { assetId = 'codeBlockFunction'; } // Create main block self.blockGraphics = self.attachAsset(assetId, { anchorX: 0.5, anchorY: 0.5 }); // Add connection points self.connectionPoints = {}; // Top connection self.connectionPoints.top = self.addChild(LK.getAsset('connectionPoint', { anchorX: 0.5, anchorY: 0.5, x: 0, y: -self.blockGraphics.height / 2 })); // Bottom connection self.connectionPoints.bottom = self.addChild(LK.getAsset('connectionPoint', { anchorX: 0.5, anchorY: 0.5, x: 0, y: self.blockGraphics.height / 2 })); // Left connection (only for condition and loop types) if (self.type === 'condition' || self.type === 'loop') { self.connectionPoints.left = self.addChild(LK.getAsset('connectionPoint', { anchorX: 0.5, anchorY: 0.5, x: -self.blockGraphics.width / 2, y: 0 })); } // Right connection (only for condition type) if (self.type === 'condition') { self.connectionPoints.right = self.addChild(LK.getAsset('connectionPoint', { anchorX: 0.5, anchorY: 0.5, x: self.blockGraphics.width / 2, y: 0 })); } // Add text label self.label = new Text2(self.text, { size: 24, fill: 0xFFFFFF }); self.label.anchor.set(0.5, 0.5); self.addChild(self.label); // Execution highlight (initially invisible) self.highlight = self.addChild(LK.getAsset('executionHighlight', { anchorX: 0.5, anchorY: 0.5, alpha: 0 })); // Handle interaction events self.down = function (x, y, obj) { if (!programIsRunning) { self.startDragX = self.x; self.startDragY = self.y; self.isDragging = true; draggedBlock = self; // Bring to front if (self.parent) { var parent = self.parent; parent.removeChild(self); parent.addChild(self); } } }; self.move = function (x, y, obj) { // Movement handled by game's move handler }; self.up = function (x, y, obj) { if (self.isDragging) { self.isDragging = false; draggedBlock = null; // Check if we're close to another block's connection point var connected = false; for (var i = 0; i < blocks.length; i++) { var otherBlock = blocks[i]; if (otherBlock !== self && otherBlock.canConnect) { connected = self.tryConnectTo(otherBlock); if (connected) { break; } } } if (!connected && codeArea.isPointInside(self.x, self.y)) { // Snap to grid if in code area self.x = Math.round(self.x / grid.cellSize) * grid.cellSize; self.y = Math.round(self.y / grid.cellSize) * grid.cellSize; } else if (!connected && !codeArea.isPointInside(self.x, self.y)) { // Return to palette area if not connected and outside code area self.x = self.startDragX; self.y = self.startDragY; } } }; self.tryConnectTo = function (otherBlock) { if (!otherBlock || otherBlock === self) { return false; } // Check proximity to connection points var connectionThreshold = 50; var myPoints = self.connectionPoints; var otherPoints = otherBlock.connectionPoints; // Check all possible connections for (var myPos in myPoints) { if (!myPoints[myPos]) { continue; } var myGlobalPos = self.parent.toGlobal(myPoints[myPos].position); for (var otherPos in otherPoints) { if (!otherPoints[otherPos]) { continue; } // Skip if this connection is already occupied if (otherBlock.connections[otherPos]) { continue; } var otherGlobalPos = otherBlock.parent.toGlobal(otherPoints[otherPos].position); var distance = Math.sqrt(Math.pow(myGlobalPos.x - otherGlobalPos.x, 2) + Math.pow(myGlobalPos.y - otherGlobalPos.y, 2)); // If close enough, connect if (distance < connectionThreshold) { // Connect based on valid combinations var validConnection = false; // Top to bottom connections if (myPos === 'bottom' && otherPos === 'top' || myPos === 'top' && otherPos === 'bottom') { validConnection = true; } // Left/right connections for condition/loop blocks if ((self.type === 'condition' || self.type === 'loop') && otherBlock.type !== 'condition' && otherBlock.type !== 'loop') { if (myPos === 'left' && otherPos === 'top' || myPos === 'right' && otherPos === 'top') { validConnection = true; } } if (validConnection) { self.connectTo(otherBlock, myPos, otherPos); return true; } } } } return false; }; self.connectTo = function (otherBlock, myPos, otherPos) { // Position calculation if (myPos === 'bottom' && otherPos === 'top') { // Align other block below this one otherBlock.x = self.x; otherBlock.y = self.y + self.blockGraphics.height; // Update connections self.connections.bottom = otherBlock; otherBlock.connections.top = self; } else if (myPos === 'top' && otherPos === 'bottom') { // Align this block below other one self.x = otherBlock.x; self.y = otherBlock.y + otherBlock.blockGraphics.height; // Update connections self.connections.top = otherBlock; otherBlock.connections.bottom = self; } else if (myPos === 'left' && otherPos === 'top') { // Align other block to the left of this one otherBlock.x = self.x - self.blockGraphics.width / 2; otherBlock.y = self.y; // Update connections self.connections.left = otherBlock; otherBlock.connections.top = self; } else if (myPos === 'right' && otherPos === 'top') { // Align other block to the right of this one otherBlock.x = self.x + self.blockGraphics.width / 2; otherBlock.y = self.y; // Update connections self.connections.right = otherBlock; otherBlock.connections.top = self; } // Play connection sound LK.getSound('connect').play(); }; self.execute = function (callback) { self.isExecuting = true; // Show execution highlight self.highlight.alpha = 0.5; // Play execution sound LK.getSound('execute').play(); // Execute block action based on type var executionTime = 800; // Default execution time switch (self.type) { case 'variable': // Variable assignment executionLog.push("Set variable: " + self.text); break; case 'loop': // Loop block execution executionLog.push("Loop: " + self.text); // For loops, we need to execute differently executionTime = 1000; break; case 'condition': // Condition evaluation executionLog.push("If condition: " + self.text); break; case 'function': // Function call executionLog.push("Call function: " + self.text); break; default: // Default block executionLog.push("Execute: " + self.text); break; } // Update execution log display updateExecutionLog(); // After execution, continue to next block LK.setTimeout(function () { self.highlight.alpha = 0; self.isExecuting = false; if (callback) { callback(); } }, executionTime); }; return self; }); /**** * Initialize Game ****/ var game = new LK.Game({ backgroundColor: 0x1a1a24 }); /**** * Game Code ****/ // Grid settings var grid = { cellSize: 100 }; // Game state var currentLevel = storage.currentLevel || 1; var highestCompletedLevel = storage.highestCompletedLevel || 0; var programIsRunning = false; var draggedBlock = null; var blocks = []; var executionLog = []; // Function to update the execution log display function updateExecutionLog() { var logText = "Execution Log:\n"; for (var i = 0; i < executionLog.length; i++) { logText += "- " + executionLog[i] + "\n"; } executionLogText.setText(logText); } // Create the code area var codeArea = new CodeArea(1200, 1500); codeArea.x = 424; // Offset from left edge codeArea.y = 150; // Offset from top game.addChild(codeArea); // Create block palette var blockPalette = new BlockPalette(400, 2732); blockPalette.x = 20; // Left edge blockPalette.y = 0; // Top edge game.addChild(blockPalette); // Add blocks to palette var yOffset = 100; var blockSpacing = 120; blockPalette.addBlockToPalette('default', "Print 'Hello World'", blockPalette.paletteWidth / 2, yOffset + blockSpacing); blockPalette.addBlockToPalette('variable', "x = 5", blockPalette.paletteWidth / 2, yOffset + blockSpacing * 2); blockPalette.addBlockToPalette('variable', "y = 10", blockPalette.paletteWidth / 2, yOffset + blockSpacing * 3); blockPalette.addBlockToPalette('loop', "Repeat 3 times", blockPalette.paletteWidth / 2, yOffset + blockSpacing * 4); blockPalette.addBlockToPalette('condition', "If x > 0", blockPalette.paletteWidth / 2, yOffset + blockSpacing * 5); blockPalette.addBlockToPalette('function', "Calculate Sum", blockPalette.paletteWidth / 2, yOffset + blockSpacing * 6); blockPalette.addBlockToPalette('default', "Draw Shape", blockPalette.paletteWidth / 2, yOffset + blockSpacing * 7); blockPalette.addBlockToPalette('default', "Move Forward", blockPalette.paletteWidth / 2, yOffset + blockSpacing * 8); blockPalette.addBlockToPalette('default', "Turn Right", blockPalette.paletteWidth / 2, yOffset + blockSpacing * 9); blockPalette.addBlockToPalette('default', "Turn Left", blockPalette.paletteWidth / 2, yOffset + blockSpacing * 10); // Create level display var levelText = new Text2("Level " + currentLevel, { size: 50, fill: 0xFFFFFF }); levelText.anchor.set(0.5, 0); levelText.x = codeArea.x + codeArea.areaWidth / 2; levelText.y = 50; game.addChild(levelText); // Create challenge text var challengeText = new Text2("Challenge: Create a program that prints 'Hello World' 3 times", { size: 30, fill: 0xFFFFFF, wordWrap: true, wordWrapWidth: 1100 }); challengeText.anchor.set(0.5, 0); challengeText.x = codeArea.x + codeArea.areaWidth / 2; challengeText.y = 110; game.addChild(challengeText); // Execution log var executionLogText = new Text2("Execution Log:\n", { size: 24, fill: 0xFFFFFF, wordWrap: true, wordWrapWidth: 1100 }); executionLogText.anchor.set(0, 0); executionLogText.x = codeArea.x + 50; executionLogText.y = codeArea.y + codeArea.areaHeight + 20; game.addChild(executionLogText); // Create run button var runButton = new Button("Run Program", 200, 80, 0x4CAF50); runButton.x = codeArea.x + codeArea.areaWidth - 150; runButton.y = codeArea.y + codeArea.areaHeight + 50; runButton.action = function () { if (!programIsRunning) { runProgram(); } }; game.addChild(runButton); // Create reset button var resetButton = new Button("Reset", 150, 80, 0xF44336); resetButton.x = codeArea.x + 100; resetButton.y = codeArea.y + codeArea.areaHeight + 50; resetButton.action = function () { resetProgram(); }; game.addChild(resetButton); // Create score display var scoreText = new Text2("Score: 0", { size: 40, fill: 0xFFFFFF }); scoreText.anchor.set(1, 0); scoreText.x = 2048 - 50; scoreText.y = 50; game.addChild(scoreText); // Function to find the start block (top-most block in code area) function findStartBlock() { for (var i = 0; i < blocks.length; i++) { var block = blocks[i]; if (codeArea.isPointInside(block.x, block.y) && !block.connections.top) { return block; } } return null; } // Function to run the program function runProgram() { // Clear execution log executionLog = []; updateExecutionLog(); // Find the start block var startBlock = findStartBlock(); if (!startBlock) { executionLog.push("No starting block found!"); updateExecutionLog(); return; } programIsRunning = true; executeBlock(startBlock, function () { programIsRunning = false; // Check if level completed checkLevelCompletion(); }); } // Function to execute a block and its connected blocks function executeBlock(block, callback) { if (!block) { if (callback) { callback(); } return; } block.execute(function () { // After execution, continue to next block based on type if (block.type === 'condition') { // For condition, randomly go left or right branch var randomBranch = Math.random() > 0.5 ? 'left' : 'right'; if (block.connections[randomBranch]) { executeBlock(block.connections[randomBranch], function () { // After branch execution, continue with bottom block if any executeBlock(block.connections.bottom, callback); }); } else { // No branch, go to bottom executeBlock(block.connections.bottom, callback); } } else if (block.type === 'loop') { // For loop, execute left branch twice, then continue if (block.connections.left) { executeBlock(block.connections.left, function () { // Execute loop content again if (block.connections.left) { executeBlock(block.connections.left, function () { // Then continue with bottom block executeBlock(block.connections.bottom, callback); }); } else { executeBlock(block.connections.bottom, callback); } }); } else { // No loop content, go to bottom executeBlock(block.connections.bottom, callback); } } else { // For other blocks, just go to bottom executeBlock(block.connections.bottom, callback); } }); } // Function to reset the program function resetProgram() { // Clear blocks in the code area for (var i = blocks.length - 1; i >= 0; i--) { var block = blocks[i]; if (codeArea.isPointInside(block.x, block.y)) { block.destroy(); blocks.splice(i, 1); } } // Clear execution log executionLog = []; updateExecutionLog(); } // Function to check level completion function checkLevelCompletion() { // For the first level, check if we have the right sequence if (currentLevel === 1) { var correctSequence = false; var printCount = 0; var hasLoop = false; // Count prints and check for loop for (var i = 0; i < executionLog.length; i++) { if (executionLog[i].includes("Print 'Hello World'")) { printCount++; } if (executionLog[i].includes("Loop")) { hasLoop = true; } } // Level 1 is complete if we printed Hello World 3 times and used a loop correctSequence = printCount >= 3 && hasLoop; if (correctSequence) { LK.getSound('complete').play(); // Level complete! LK.setScore(LK.getScore() + 100); scoreText.setText("Score: " + LK.getScore()); // Update level progress currentLevel++; highestCompletedLevel = Math.max(highestCompletedLevel, currentLevel - 1); // Save progress storage.currentLevel = currentLevel; storage.highestCompletedLevel = highestCompletedLevel; // Update level display levelText.setText("Level " + currentLevel); // Update challenge text if (currentLevel === 2) { challengeText.setText("Challenge: Create a program that uses an if condition to check if x > 0"); } else { challengeText.setText("Challenge: Create your own working program using the available blocks"); } // Show win screen if we're past level 3 if (currentLevel > 3) { LK.showYouWin(); } } } else if (currentLevel === 2) { // Level 2: Check if we used a condition block var hasCondition = false; for (var i = 0; i < executionLog.length; i++) { if (executionLog[i].includes("If condition")) { hasCondition = true; break; } } if (hasCondition) { LK.getSound('complete').play(); // Level complete! LK.setScore(LK.getScore() + 150); scoreText.setText("Score: " + LK.getScore()); // Update level progress currentLevel++; highestCompletedLevel = Math.max(highestCompletedLevel, currentLevel - 1); // Save progress storage.currentLevel = currentLevel; storage.highestCompletedLevel = highestCompletedLevel; // Update level display levelText.setText("Level " + currentLevel); // Update challenge text challengeText.setText("Challenge: Create a program that uses variables, loops, and functions"); } } else if (currentLevel === 3) { // Level 3: Check if we used variables, loops and functions var hasVariable = false; var hasLoop = false; var hasFunction = false; for (var i = 0; i < executionLog.length; i++) { if (executionLog[i].includes("Set variable")) { hasVariable = true; } if (executionLog[i].includes("Loop")) { hasLoop = true; } if (executionLog[i].includes("Call function")) { hasFunction = true; } } if (hasVariable && hasLoop && hasFunction) { LK.getSound('complete').play(); // Level complete! LK.setScore(LK.getScore() + 200); scoreText.setText("Score: " + LK.getScore()); // Win the game LK.showYouWin(); } } } // Handle game events game.move = function (x, y, obj) { if (draggedBlock && draggedBlock.isDragging) { draggedBlock.x = x; draggedBlock.y = y; } }; game.down = function (x, y, obj) { // Default handler, individual objects have their own handlers }; game.up = function (x, y, obj) { // Default handler, individual objects have their own handlers }; // Start background music LK.playMusic('bgmusic');
===================================================================
--- original.js
+++ change.js
@@ -1,6 +1,688 @@
-/****
+/****
+* Plugins
+****/
+var tween = LK.import("@upit/tween.v1");
+var storage = LK.import("@upit/storage.v1");
+
+/****
+* Classes
+****/
+var BlockPalette = Container.expand(function (width, height) {
+ var self = Container.call(this);
+ self.paletteWidth = width || 400;
+ self.paletteHeight = height || 2732;
+ // Create background
+ self.background = self.addChild(LK.getAsset('codeBlock', {
+ anchorX: 0,
+ anchorY: 0,
+ width: self.paletteWidth,
+ height: self.paletteHeight,
+ alpha: 0.3,
+ tint: 0x333333
+ }));
+ // Add title
+ self.title = new Text2("Block Palette", {
+ size: 40,
+ fill: 0xFFFFFF
+ });
+ self.title.anchor.set(0.5, 0);
+ self.title.x = self.paletteWidth / 2;
+ self.title.y = 30;
+ self.addChild(self.title);
+ // Add blocks to palette
+ self.addBlockToPalette = function (type, text, x, y) {
+ var block = new CodeBlock(type, text);
+ block.x = x;
+ block.y = y;
+ // This is a template block - when dragged, it creates a new instance
+ block.down = function (x, y, obj) {
+ // Create a new block when this template is clicked
+ var newBlock = new CodeBlock(type, text);
+ newBlock.x = block.x;
+ newBlock.y = block.y;
+ // Convert to global position
+ var globalPos = self.parent.toGlobal({
+ x: block.x,
+ y: block.y
+ });
+ newBlock.x = globalPos.x;
+ newBlock.y = globalPos.y;
+ // Add to game's blocks array
+ blocks.push(newBlock);
+ // Add to game
+ game.addChild(newBlock);
+ // Start dragging the new block
+ newBlock.startDragX = newBlock.x;
+ newBlock.startDragY = newBlock.y;
+ newBlock.isDragging = true;
+ draggedBlock = newBlock;
+ };
+ self.addChild(block);
+ return block;
+ };
+ return self;
+});
+var Button = Container.expand(function (text, width, height, color) {
+ var self = Container.call(this);
+ self.buttonWidth = width || 200;
+ self.buttonHeight = height || 80;
+ self.buttonColor = color || 0x4287f5;
+ // Create button background
+ self.background = self.addChild(LK.getAsset('codeBlock', {
+ anchorX: 0.5,
+ anchorY: 0.5,
+ width: self.buttonWidth,
+ height: self.buttonHeight,
+ tint: self.buttonColor
+ }));
+ // Add text
+ self.label = new Text2(text, {
+ size: 30,
+ fill: 0xFFFFFF
+ });
+ self.label.anchor.set(0.5, 0.5);
+ self.addChild(self.label);
+ // Handle down event
+ self.down = function (x, y, obj) {
+ // Visual feedback
+ tween(self.background, {
+ scaleX: 0.95,
+ scaleY: 0.95
+ }, {
+ duration: 100
+ });
+ };
+ // Handle up event
+ self.up = function (x, y, obj) {
+ // Reset scale
+ tween(self.background, {
+ scaleX: 1,
+ scaleY: 1
+ }, {
+ duration: 100,
+ onFinish: function onFinish() {
+ // Call the button's action
+ if (self.action) {
+ self.action();
+ }
+ }
+ });
+ };
+ return self;
+});
+var CodeArea = Container.expand(function (width, height) {
+ var self = Container.call(this);
+ self.areaWidth = width || 1200;
+ self.areaHeight = height || 1500;
+ // Create background
+ self.background = self.addChild(LK.getAsset('codeBlock', {
+ anchorX: 0,
+ anchorY: 0,
+ width: self.areaWidth,
+ height: self.areaHeight,
+ alpha: 0.2,
+ tint: 0x222222
+ }));
+ // Method to check if a point is inside the code area
+ self.isPointInside = function (x, y) {
+ var globalPos = game.toLocal({
+ x: x,
+ y: y
+ }, self.parent);
+ return globalPos.x >= self.x && globalPos.x <= self.x + self.areaWidth && globalPos.y >= self.y && globalPos.y <= self.y + self.areaHeight;
+ };
+ return self;
+});
+var CodeBlock = Container.expand(function (type, text) {
+ var self = Container.call(this);
+ self.type = type || 'default';
+ self.text = text || '';
+ self.connections = {
+ top: null,
+ bottom: null,
+ left: null,
+ right: null
+ };
+ self.canConnect = true;
+ self.isExecuting = false;
+ // Select the correct asset based on type
+ var assetId = 'codeBlock';
+ if (self.type === 'variable') {
+ assetId = 'codeBlockVar';
+ } else if (self.type === 'loop') {
+ assetId = 'codeBlockLoop';
+ } else if (self.type === 'condition') {
+ assetId = 'codeBlockCondition';
+ } else if (self.type === 'function') {
+ assetId = 'codeBlockFunction';
+ }
+ // Create main block
+ self.blockGraphics = self.attachAsset(assetId, {
+ anchorX: 0.5,
+ anchorY: 0.5
+ });
+ // Add connection points
+ self.connectionPoints = {};
+ // Top connection
+ self.connectionPoints.top = self.addChild(LK.getAsset('connectionPoint', {
+ anchorX: 0.5,
+ anchorY: 0.5,
+ x: 0,
+ y: -self.blockGraphics.height / 2
+ }));
+ // Bottom connection
+ self.connectionPoints.bottom = self.addChild(LK.getAsset('connectionPoint', {
+ anchorX: 0.5,
+ anchorY: 0.5,
+ x: 0,
+ y: self.blockGraphics.height / 2
+ }));
+ // Left connection (only for condition and loop types)
+ if (self.type === 'condition' || self.type === 'loop') {
+ self.connectionPoints.left = self.addChild(LK.getAsset('connectionPoint', {
+ anchorX: 0.5,
+ anchorY: 0.5,
+ x: -self.blockGraphics.width / 2,
+ y: 0
+ }));
+ }
+ // Right connection (only for condition type)
+ if (self.type === 'condition') {
+ self.connectionPoints.right = self.addChild(LK.getAsset('connectionPoint', {
+ anchorX: 0.5,
+ anchorY: 0.5,
+ x: self.blockGraphics.width / 2,
+ y: 0
+ }));
+ }
+ // Add text label
+ self.label = new Text2(self.text, {
+ size: 24,
+ fill: 0xFFFFFF
+ });
+ self.label.anchor.set(0.5, 0.5);
+ self.addChild(self.label);
+ // Execution highlight (initially invisible)
+ self.highlight = self.addChild(LK.getAsset('executionHighlight', {
+ anchorX: 0.5,
+ anchorY: 0.5,
+ alpha: 0
+ }));
+ // Handle interaction events
+ self.down = function (x, y, obj) {
+ if (!programIsRunning) {
+ self.startDragX = self.x;
+ self.startDragY = self.y;
+ self.isDragging = true;
+ draggedBlock = self;
+ // Bring to front
+ if (self.parent) {
+ var parent = self.parent;
+ parent.removeChild(self);
+ parent.addChild(self);
+ }
+ }
+ };
+ self.move = function (x, y, obj) {
+ // Movement handled by game's move handler
+ };
+ self.up = function (x, y, obj) {
+ if (self.isDragging) {
+ self.isDragging = false;
+ draggedBlock = null;
+ // Check if we're close to another block's connection point
+ var connected = false;
+ for (var i = 0; i < blocks.length; i++) {
+ var otherBlock = blocks[i];
+ if (otherBlock !== self && otherBlock.canConnect) {
+ connected = self.tryConnectTo(otherBlock);
+ if (connected) {
+ break;
+ }
+ }
+ }
+ if (!connected && codeArea.isPointInside(self.x, self.y)) {
+ // Snap to grid if in code area
+ self.x = Math.round(self.x / grid.cellSize) * grid.cellSize;
+ self.y = Math.round(self.y / grid.cellSize) * grid.cellSize;
+ } else if (!connected && !codeArea.isPointInside(self.x, self.y)) {
+ // Return to palette area if not connected and outside code area
+ self.x = self.startDragX;
+ self.y = self.startDragY;
+ }
+ }
+ };
+ self.tryConnectTo = function (otherBlock) {
+ if (!otherBlock || otherBlock === self) {
+ return false;
+ }
+ // Check proximity to connection points
+ var connectionThreshold = 50;
+ var myPoints = self.connectionPoints;
+ var otherPoints = otherBlock.connectionPoints;
+ // Check all possible connections
+ for (var myPos in myPoints) {
+ if (!myPoints[myPos]) {
+ continue;
+ }
+ var myGlobalPos = self.parent.toGlobal(myPoints[myPos].position);
+ for (var otherPos in otherPoints) {
+ if (!otherPoints[otherPos]) {
+ continue;
+ }
+ // Skip if this connection is already occupied
+ if (otherBlock.connections[otherPos]) {
+ continue;
+ }
+ var otherGlobalPos = otherBlock.parent.toGlobal(otherPoints[otherPos].position);
+ var distance = Math.sqrt(Math.pow(myGlobalPos.x - otherGlobalPos.x, 2) + Math.pow(myGlobalPos.y - otherGlobalPos.y, 2));
+ // If close enough, connect
+ if (distance < connectionThreshold) {
+ // Connect based on valid combinations
+ var validConnection = false;
+ // Top to bottom connections
+ if (myPos === 'bottom' && otherPos === 'top' || myPos === 'top' && otherPos === 'bottom') {
+ validConnection = true;
+ }
+ // Left/right connections for condition/loop blocks
+ if ((self.type === 'condition' || self.type === 'loop') && otherBlock.type !== 'condition' && otherBlock.type !== 'loop') {
+ if (myPos === 'left' && otherPos === 'top' || myPos === 'right' && otherPos === 'top') {
+ validConnection = true;
+ }
+ }
+ if (validConnection) {
+ self.connectTo(otherBlock, myPos, otherPos);
+ return true;
+ }
+ }
+ }
+ }
+ return false;
+ };
+ self.connectTo = function (otherBlock, myPos, otherPos) {
+ // Position calculation
+ if (myPos === 'bottom' && otherPos === 'top') {
+ // Align other block below this one
+ otherBlock.x = self.x;
+ otherBlock.y = self.y + self.blockGraphics.height;
+ // Update connections
+ self.connections.bottom = otherBlock;
+ otherBlock.connections.top = self;
+ } else if (myPos === 'top' && otherPos === 'bottom') {
+ // Align this block below other one
+ self.x = otherBlock.x;
+ self.y = otherBlock.y + otherBlock.blockGraphics.height;
+ // Update connections
+ self.connections.top = otherBlock;
+ otherBlock.connections.bottom = self;
+ } else if (myPos === 'left' && otherPos === 'top') {
+ // Align other block to the left of this one
+ otherBlock.x = self.x - self.blockGraphics.width / 2;
+ otherBlock.y = self.y;
+ // Update connections
+ self.connections.left = otherBlock;
+ otherBlock.connections.top = self;
+ } else if (myPos === 'right' && otherPos === 'top') {
+ // Align other block to the right of this one
+ otherBlock.x = self.x + self.blockGraphics.width / 2;
+ otherBlock.y = self.y;
+ // Update connections
+ self.connections.right = otherBlock;
+ otherBlock.connections.top = self;
+ }
+ // Play connection sound
+ LK.getSound('connect').play();
+ };
+ self.execute = function (callback) {
+ self.isExecuting = true;
+ // Show execution highlight
+ self.highlight.alpha = 0.5;
+ // Play execution sound
+ LK.getSound('execute').play();
+ // Execute block action based on type
+ var executionTime = 800; // Default execution time
+ switch (self.type) {
+ case 'variable':
+ // Variable assignment
+ executionLog.push("Set variable: " + self.text);
+ break;
+ case 'loop':
+ // Loop block execution
+ executionLog.push("Loop: " + self.text);
+ // For loops, we need to execute differently
+ executionTime = 1000;
+ break;
+ case 'condition':
+ // Condition evaluation
+ executionLog.push("If condition: " + self.text);
+ break;
+ case 'function':
+ // Function call
+ executionLog.push("Call function: " + self.text);
+ break;
+ default:
+ // Default block
+ executionLog.push("Execute: " + self.text);
+ break;
+ }
+ // Update execution log display
+ updateExecutionLog();
+ // After execution, continue to next block
+ LK.setTimeout(function () {
+ self.highlight.alpha = 0;
+ self.isExecuting = false;
+ if (callback) {
+ callback();
+ }
+ }, executionTime);
+ };
+ return self;
+});
+
+/****
* Initialize Game
-****/
+****/
var game = new LK.Game({
- backgroundColor: 0x000000
-});
\ No newline at end of file
+ backgroundColor: 0x1a1a24
+});
+
+/****
+* Game Code
+****/
+// Grid settings
+var grid = {
+ cellSize: 100
+};
+// Game state
+var currentLevel = storage.currentLevel || 1;
+var highestCompletedLevel = storage.highestCompletedLevel || 0;
+var programIsRunning = false;
+var draggedBlock = null;
+var blocks = [];
+var executionLog = [];
+// Function to update the execution log display
+function updateExecutionLog() {
+ var logText = "Execution Log:\n";
+ for (var i = 0; i < executionLog.length; i++) {
+ logText += "- " + executionLog[i] + "\n";
+ }
+ executionLogText.setText(logText);
+}
+// Create the code area
+var codeArea = new CodeArea(1200, 1500);
+codeArea.x = 424; // Offset from left edge
+codeArea.y = 150; // Offset from top
+game.addChild(codeArea);
+// Create block palette
+var blockPalette = new BlockPalette(400, 2732);
+blockPalette.x = 20; // Left edge
+blockPalette.y = 0; // Top edge
+game.addChild(blockPalette);
+// Add blocks to palette
+var yOffset = 100;
+var blockSpacing = 120;
+blockPalette.addBlockToPalette('default', "Print 'Hello World'", blockPalette.paletteWidth / 2, yOffset + blockSpacing);
+blockPalette.addBlockToPalette('variable', "x = 5", blockPalette.paletteWidth / 2, yOffset + blockSpacing * 2);
+blockPalette.addBlockToPalette('variable', "y = 10", blockPalette.paletteWidth / 2, yOffset + blockSpacing * 3);
+blockPalette.addBlockToPalette('loop', "Repeat 3 times", blockPalette.paletteWidth / 2, yOffset + blockSpacing * 4);
+blockPalette.addBlockToPalette('condition', "If x > 0", blockPalette.paletteWidth / 2, yOffset + blockSpacing * 5);
+blockPalette.addBlockToPalette('function', "Calculate Sum", blockPalette.paletteWidth / 2, yOffset + blockSpacing * 6);
+blockPalette.addBlockToPalette('default', "Draw Shape", blockPalette.paletteWidth / 2, yOffset + blockSpacing * 7);
+blockPalette.addBlockToPalette('default', "Move Forward", blockPalette.paletteWidth / 2, yOffset + blockSpacing * 8);
+blockPalette.addBlockToPalette('default', "Turn Right", blockPalette.paletteWidth / 2, yOffset + blockSpacing * 9);
+blockPalette.addBlockToPalette('default', "Turn Left", blockPalette.paletteWidth / 2, yOffset + blockSpacing * 10);
+// Create level display
+var levelText = new Text2("Level " + currentLevel, {
+ size: 50,
+ fill: 0xFFFFFF
+});
+levelText.anchor.set(0.5, 0);
+levelText.x = codeArea.x + codeArea.areaWidth / 2;
+levelText.y = 50;
+game.addChild(levelText);
+// Create challenge text
+var challengeText = new Text2("Challenge: Create a program that prints 'Hello World' 3 times", {
+ size: 30,
+ fill: 0xFFFFFF,
+ wordWrap: true,
+ wordWrapWidth: 1100
+});
+challengeText.anchor.set(0.5, 0);
+challengeText.x = codeArea.x + codeArea.areaWidth / 2;
+challengeText.y = 110;
+game.addChild(challengeText);
+// Execution log
+var executionLogText = new Text2("Execution Log:\n", {
+ size: 24,
+ fill: 0xFFFFFF,
+ wordWrap: true,
+ wordWrapWidth: 1100
+});
+executionLogText.anchor.set(0, 0);
+executionLogText.x = codeArea.x + 50;
+executionLogText.y = codeArea.y + codeArea.areaHeight + 20;
+game.addChild(executionLogText);
+// Create run button
+var runButton = new Button("Run Program", 200, 80, 0x4CAF50);
+runButton.x = codeArea.x + codeArea.areaWidth - 150;
+runButton.y = codeArea.y + codeArea.areaHeight + 50;
+runButton.action = function () {
+ if (!programIsRunning) {
+ runProgram();
+ }
+};
+game.addChild(runButton);
+// Create reset button
+var resetButton = new Button("Reset", 150, 80, 0xF44336);
+resetButton.x = codeArea.x + 100;
+resetButton.y = codeArea.y + codeArea.areaHeight + 50;
+resetButton.action = function () {
+ resetProgram();
+};
+game.addChild(resetButton);
+// Create score display
+var scoreText = new Text2("Score: 0", {
+ size: 40,
+ fill: 0xFFFFFF
+});
+scoreText.anchor.set(1, 0);
+scoreText.x = 2048 - 50;
+scoreText.y = 50;
+game.addChild(scoreText);
+// Function to find the start block (top-most block in code area)
+function findStartBlock() {
+ for (var i = 0; i < blocks.length; i++) {
+ var block = blocks[i];
+ if (codeArea.isPointInside(block.x, block.y) && !block.connections.top) {
+ return block;
+ }
+ }
+ return null;
+}
+// Function to run the program
+function runProgram() {
+ // Clear execution log
+ executionLog = [];
+ updateExecutionLog();
+ // Find the start block
+ var startBlock = findStartBlock();
+ if (!startBlock) {
+ executionLog.push("No starting block found!");
+ updateExecutionLog();
+ return;
+ }
+ programIsRunning = true;
+ executeBlock(startBlock, function () {
+ programIsRunning = false;
+ // Check if level completed
+ checkLevelCompletion();
+ });
+}
+// Function to execute a block and its connected blocks
+function executeBlock(block, callback) {
+ if (!block) {
+ if (callback) {
+ callback();
+ }
+ return;
+ }
+ block.execute(function () {
+ // After execution, continue to next block based on type
+ if (block.type === 'condition') {
+ // For condition, randomly go left or right branch
+ var randomBranch = Math.random() > 0.5 ? 'left' : 'right';
+ if (block.connections[randomBranch]) {
+ executeBlock(block.connections[randomBranch], function () {
+ // After branch execution, continue with bottom block if any
+ executeBlock(block.connections.bottom, callback);
+ });
+ } else {
+ // No branch, go to bottom
+ executeBlock(block.connections.bottom, callback);
+ }
+ } else if (block.type === 'loop') {
+ // For loop, execute left branch twice, then continue
+ if (block.connections.left) {
+ executeBlock(block.connections.left, function () {
+ // Execute loop content again
+ if (block.connections.left) {
+ executeBlock(block.connections.left, function () {
+ // Then continue with bottom block
+ executeBlock(block.connections.bottom, callback);
+ });
+ } else {
+ executeBlock(block.connections.bottom, callback);
+ }
+ });
+ } else {
+ // No loop content, go to bottom
+ executeBlock(block.connections.bottom, callback);
+ }
+ } else {
+ // For other blocks, just go to bottom
+ executeBlock(block.connections.bottom, callback);
+ }
+ });
+}
+// Function to reset the program
+function resetProgram() {
+ // Clear blocks in the code area
+ for (var i = blocks.length - 1; i >= 0; i--) {
+ var block = blocks[i];
+ if (codeArea.isPointInside(block.x, block.y)) {
+ block.destroy();
+ blocks.splice(i, 1);
+ }
+ }
+ // Clear execution log
+ executionLog = [];
+ updateExecutionLog();
+}
+// Function to check level completion
+function checkLevelCompletion() {
+ // For the first level, check if we have the right sequence
+ if (currentLevel === 1) {
+ var correctSequence = false;
+ var printCount = 0;
+ var hasLoop = false;
+ // Count prints and check for loop
+ for (var i = 0; i < executionLog.length; i++) {
+ if (executionLog[i].includes("Print 'Hello World'")) {
+ printCount++;
+ }
+ if (executionLog[i].includes("Loop")) {
+ hasLoop = true;
+ }
+ }
+ // Level 1 is complete if we printed Hello World 3 times and used a loop
+ correctSequence = printCount >= 3 && hasLoop;
+ if (correctSequence) {
+ LK.getSound('complete').play();
+ // Level complete!
+ LK.setScore(LK.getScore() + 100);
+ scoreText.setText("Score: " + LK.getScore());
+ // Update level progress
+ currentLevel++;
+ highestCompletedLevel = Math.max(highestCompletedLevel, currentLevel - 1);
+ // Save progress
+ storage.currentLevel = currentLevel;
+ storage.highestCompletedLevel = highestCompletedLevel;
+ // Update level display
+ levelText.setText("Level " + currentLevel);
+ // Update challenge text
+ if (currentLevel === 2) {
+ challengeText.setText("Challenge: Create a program that uses an if condition to check if x > 0");
+ } else {
+ challengeText.setText("Challenge: Create your own working program using the available blocks");
+ }
+ // Show win screen if we're past level 3
+ if (currentLevel > 3) {
+ LK.showYouWin();
+ }
+ }
+ } else if (currentLevel === 2) {
+ // Level 2: Check if we used a condition block
+ var hasCondition = false;
+ for (var i = 0; i < executionLog.length; i++) {
+ if (executionLog[i].includes("If condition")) {
+ hasCondition = true;
+ break;
+ }
+ }
+ if (hasCondition) {
+ LK.getSound('complete').play();
+ // Level complete!
+ LK.setScore(LK.getScore() + 150);
+ scoreText.setText("Score: " + LK.getScore());
+ // Update level progress
+ currentLevel++;
+ highestCompletedLevel = Math.max(highestCompletedLevel, currentLevel - 1);
+ // Save progress
+ storage.currentLevel = currentLevel;
+ storage.highestCompletedLevel = highestCompletedLevel;
+ // Update level display
+ levelText.setText("Level " + currentLevel);
+ // Update challenge text
+ challengeText.setText("Challenge: Create a program that uses variables, loops, and functions");
+ }
+ } else if (currentLevel === 3) {
+ // Level 3: Check if we used variables, loops and functions
+ var hasVariable = false;
+ var hasLoop = false;
+ var hasFunction = false;
+ for (var i = 0; i < executionLog.length; i++) {
+ if (executionLog[i].includes("Set variable")) {
+ hasVariable = true;
+ }
+ if (executionLog[i].includes("Loop")) {
+ hasLoop = true;
+ }
+ if (executionLog[i].includes("Call function")) {
+ hasFunction = true;
+ }
+ }
+ if (hasVariable && hasLoop && hasFunction) {
+ LK.getSound('complete').play();
+ // Level complete!
+ LK.setScore(LK.getScore() + 200);
+ scoreText.setText("Score: " + LK.getScore());
+ // Win the game
+ LK.showYouWin();
+ }
+ }
+}
+// Handle game events
+game.move = function (x, y, obj) {
+ if (draggedBlock && draggedBlock.isDragging) {
+ draggedBlock.x = x;
+ draggedBlock.y = y;
+ }
+};
+game.down = function (x, y, obj) {
+ // Default handler, individual objects have their own handlers
+};
+game.up = function (x, y, obj) {
+ // Default handler, individual objects have their own handlers
+};
+// Start background music
+LK.playMusic('bgmusic');
\ No newline at end of file