User prompt
Remove block puzzle and add tetris
User prompt
Please fix the bug: 'ReferenceError: Can't find variable: updateBlockPuzzleGame' in or related to this line: 'updateBlockPuzzleGame();' Line Number: 2781
User prompt
Please fix the bug: 'ReferenceError: Can't find variable: updateBlockPuzzleGame' in or related to this line: 'updateBlockPuzzleGame();' Line Number: 2781
User prompt
Please fix the bug: 'ReferenceError: Can't find variable: updateBlockPuzzleGame' in or related to this line: 'updateBlockPuzzleGame();' Line Number: 2782
User prompt
Fix the bug in line number 2714
User prompt
Add a new puzzle game
User prompt
Please fix the bug: 'ReferenceError: Can't find variable: updateFlyingCatGame' in or related to this line: 'updateFlyingCatGame();' Line Number: 2529
User prompt
Add a new game mode named flying cat
User prompt
Please fix the bug: 'Script error.' in or related to this line: 'if (dashPlayer.gameMode === 'cube') {' Line Number: 2226
User prompt
Fix the game cards
User prompt
Put the tools category at the bottom and not half offscreen
User prompt
No move it more to the left
User prompt
Can you move it
User prompt
Add the multiplayer catagory to bottom screen
User prompt
Please fix the bug: 'Script error.' in or related to this line: 'var localPos = self.toLocal(obj.parent.toGlobal(obj.position));' Line Number: 1283
User prompt
Undo that
User prompt
Add the categories off screen to bottom screen
User prompt
Add a settings ↪💡 Consider importing and using the following plugins: @upit/storage.v1
User prompt
Add a game called flappy bird
User prompt
Add a game called multiplayer mode
User prompt
Fix the game cards
/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
var storage = LK.import("@upit/storage.v1");
/****
* Classes
****/
var Ball = Container.expand(function () {
var self = Container.call(this);
var graphic = self.attachAsset('ball', {
anchorX: 0.5,
anchorY: 0.5
});
self.speedX = 5;
self.speedY = -5;
self.update = function () {
self.x += self.speedX;
self.y += self.speedY;
// Bounce off walls
if (self.x < 20 || self.x > 2028) {
self.speedX = -self.speedX;
LK.getSound('bounce').play();
}
if (self.y < 20) {
self.speedY = -self.speedY;
LK.getSound('bounce').play();
}
// Game over if ball goes below paddle
if (self.y > 2732) {
endCurrentGame();
}
// Bounce off paddle
if (paddle && self.intersects(paddle) && self.speedY > 0) {
self.speedY = -self.speedY;
LK.getSound('bounce').play();
}
};
return self;
});
var Brick = Container.expand(function () {
var self = Container.call(this);
var graphic = self.attachAsset('brick', {
anchorX: 0.5,
anchorY: 0.5
});
return self;
});
var CategoryButton = Container.expand(function (categoryName, isActive) {
var self = Container.call(this);
var buttonBg = self.attachAsset('categoryButton', {
anchorX: 0.5,
anchorY: 0.5
});
if (isActive) {
buttonBg.tint = 0x0984e3; // Darker blue for active state
}
var buttonText = new Text2(categoryName, {
size: 32,
fill: 0xFFFFFF
});
buttonText.anchor.set(0.5, 0.5);
self.addChild(buttonText);
self.categoryName = categoryName;
self.isActive = isActive;
self.setActive = function (active) {
self.isActive = active;
buttonBg.tint = active ? 0x0984e3 : 0x74b9ff;
};
self.down = function (x, y, obj) {
tween(buttonBg, {
scaleX: 0.95,
scaleY: 0.95
}, {
duration: 100
});
LK.getSound('tap').play();
};
self.up = function (x, y, obj) {
tween(buttonBg, {
scaleX: 1,
scaleY: 1
}, {
duration: 100
});
filterGamesByCategory(self.categoryName);
};
return self;
});
var Circle = Container.expand(function () {
var self = Container.call(this);
var graphic = self.attachAsset('circle', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 2 + Math.random() * 3;
self.direction = Math.random() * Math.PI * 2;
self.lifetime = 180; // 3 seconds at 60fps
self.maxLifetime = self.lifetime;
self.update = function () {
self.x += Math.cos(self.direction) * self.speed;
self.y += Math.sin(self.direction) * self.speed;
// Bounce off walls
if (self.x < 60 || self.x > 1988) {
self.direction = Math.PI - self.direction;
}
if (self.y < 60 || self.y > 2672) {
self.direction = -self.direction;
}
self.lifetime--;
var alpha = self.lifetime / self.maxLifetime;
graphic.alpha = alpha;
if (self.lifetime <= 0) {
self.shouldRemove = true;
}
};
self.down = function (x, y, obj) {
LK.getSound('tap').play();
LK.setScore(LK.getScore() + 10);
updateScoreDisplay();
self.shouldRemove = true;
};
return self;
});
var Coin = Container.expand(function () {
var self = Container.call(this);
var graphic = self.attachAsset('coin', {
anchorX: 0.5,
anchorY: 0.5
});
self.bobOffset = Math.random() * Math.PI * 2;
self.startY = 0;
self.update = function () {
self.y = self.startY + Math.sin(LK.ticks * 0.1 + self.bobOffset) * 10;
};
return self;
});
var DashObstacle = Container.expand(function (type) {
var self = Container.call(this);
self.obstacleType = type || 'block';
var assetName = 'dashObstacle';
if (type === 'spike') assetName = 'dashSpike';else if (type === 'ground') assetName = 'dashGround';
var graphic = self.attachAsset(assetName, {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = -8;
self.update = function () {
self.x += self.speed;
if (self.x < -100) {
self.shouldRemove = true;
}
};
return self;
});
var DashPlayer = Container.expand(function () {
var self = Container.call(this);
var graphic = self.attachAsset('dashPlayer', {
anchorX: 0.5,
anchorY: 0.5
});
self.velocityY = 0;
self.gravity = 1.2;
self.jumpPower = -18;
self.isGrounded = false;
self.isDead = false;
self.lastY = 0;
self.gameMode = 'cube'; // cube, ship, ball, wave
self.update = function () {
if (self.isDead) return;
self.lastY = self.y;
// Apply gravity for cube mode
if (self.gameMode === 'cube') {
self.velocityY += self.gravity;
if (self.velocityY > 15) self.velocityY = 15;
} else if (self.gameMode === 'ship') {
// Ship mode - controlled flight
if (self.isHolding) {
self.velocityY -= 1.5;
if (self.velocityY < -12) self.velocityY = -12;
} else {
self.velocityY += 1.2;
if (self.velocityY > 12) self.velocityY = 12;
}
}
self.y += self.velocityY;
self.isGrounded = false;
// Simple rotation based on velocity
if (self.gameMode === 'cube') {
graphic.rotation = 0;
} else if (self.gameMode === 'ship') {
graphic.rotation = self.velocityY * 0.1;
}
};
self.jump = function () {
if (self.gameMode === 'cube' && self.isGrounded) {
self.velocityY = self.jumpPower;
self.isGrounded = false;
LK.getSound('jump').play();
}
};
self.hold = function () {
self.isHolding = true;
};
self.release = function () {
self.isHolding = false;
};
self.die = function () {
if (self.isDead) return;
self.isDead = true;
// Flash red death effect
tween(graphic, {
tint: 0xff0000
}, {
duration: 200,
onFinish: function onFinish() {
tween(graphic, {
tint: 0xffffff
}, {
duration: 200
});
}
});
LK.setTimeout(function () {
endCurrentGame();
}, 500);
};
self.changeMode = function (newMode) {
self.gameMode = newMode;
if (newMode === 'ship') {
graphic.tint = 0x3498db;
} else if (newMode === 'ball') {
graphic.tint = 0xe67e22;
} else if (newMode === 'wave') {
graphic.tint = 0x9b59b6;
} else {
graphic.tint = 0xf39c12;
}
};
return self;
});
var DashPortal = Container.expand(function (portalType) {
var self = Container.call(this);
var graphic = self.attachAsset('dashPortal', {
anchorX: 0.5,
anchorY: 0.5
});
self.portalType = portalType || 'cube';
self.speed = -8;
// Color portals based on type
if (portalType === 'ship') {
graphic.tint = 0x3498db;
} else if (portalType === 'ball') {
graphic.tint = 0xe67e22;
} else if (portalType === 'wave') {
graphic.tint = 0x9b59b6;
} else {
graphic.tint = 0xf39c12;
}
self.update = function () {
self.x += self.speed;
if (self.x < -100) {
self.shouldRemove = true;
}
// Rotating effect
graphic.rotation += 0.1;
};
return self;
});
var Food = Container.expand(function () {
var self = Container.call(this);
var graphic = self.attachAsset('food', {
anchorX: 0.5,
anchorY: 0.5
});
self.x = 100 + Math.random() * 1848;
self.y = 100 + Math.random() * 2532;
return self;
});
var GameCard = Container.expand(function (gameInfo) {
var self = Container.call(this);
var isLocked = gameInfo.locked || false;
var cardBg = self.attachAsset(isLocked ? 'gameCardLocked' : 'gameCard', {
anchorX: 0.5,
anchorY: 0.5
});
// Add border effect
cardBg.tint = isLocked ? 0x34495e : 0x2c3e50;
if (isLocked) {
var lock = self.attachAsset('lockIcon', {
anchorX: 0.5,
anchorY: 0.5,
y: -20
});
}
var titleText = new Text2(gameInfo.title, {
size: 36,
fill: isLocked ? "#999999" : "#ffffff"
});
titleText.anchor.set(0.5, 0.5);
titleText.y = isLocked ? 30 : -40;
self.addChild(titleText);
var categoryText = new Text2(gameInfo.category, {
size: 24,
fill: isLocked ? "#666666" : "#74b9ff"
});
categoryText.anchor.set(0.5, 0.5);
categoryText.y = isLocked ? 60 : -10;
self.addChild(categoryText);
var scoreText = new Text2('Best: ' + (gameInfo.bestScore || 0), {
size: 28,
fill: isLocked ? "#555555" : "#00b894"
});
scoreText.anchor.set(0.5, 0.5);
scoreText.y = isLocked ? 90 : 30;
self.addChild(scoreText);
self.gameInfo = gameInfo;
self.isLocked = isLocked;
self.down = function (x, y, obj) {
if (!self.isLocked) {
tween(cardBg, {
scaleX: 0.95,
scaleY: 0.95
}, {
duration: 100
});
LK.getSound('tap').play();
}
};
self.up = function (x, y, obj) {
if (!self.isLocked) {
tween(cardBg, {
scaleX: 1,
scaleY: 1
}, {
duration: 100
});
currentGame = self.gameInfo.id;
switchToGame(currentGame);
}
};
self.updateScore = function (newScore) {
gameInfo.bestScore = newScore;
scoreText.setText('Best: ' + newScore);
};
self.unlock = function () {
self.isLocked = false;
gameInfo.locked = false;
cardBg.tint = 0x16213e;
titleText.tint = 0xffffff;
scoreText.tint = 0xcccccc;
if (lock) {
lock.visible = false;
}
};
return self;
});
var GameCreator = Container.expand(function () {
var self = Container.call(this);
self.mode = 'place'; // 'place', 'delete', 'color', 'resize', 'copy'
self.currentColor = 0x00b894;
self.currentObjectType = 'box'; // 'box', 'circle', 'platform', 'spike', 'goal', 'enemy'
self.gridSize = 40;
self.snapToGrid = true;
self.createdObjects = [];
self.clipboard = null;
self.selectedObject = null;
self.createToolbar = function () {
var toolbar = new Container();
// Row 1 - Main tools
var tools = [{
name: 'Place',
x: 150,
y: 80
}, {
name: 'Delete',
x: 300,
y: 80
}, {
name: 'Copy',
x: 450,
y: 80
}, {
name: 'Resize',
x: 600,
y: 80
}, {
name: 'Grid',
x: 750,
y: 80
}, {
name: 'Color',
x: 900,
y: 80
}, {
name: 'Play',
x: 1200,
y: 80
}, {
name: 'Save',
x: 1350,
y: 80
}, {
name: 'Load',
x: 1500,
y: 80
}, {
name: 'Clear',
x: 1650,
y: 80
}];
for (var i = 0; i < tools.length; i++) {
var tool = tools[i];
var btn = toolbar.addChild(LK.getAsset('toolButton', {
anchorX: 0.5,
anchorY: 0.5,
x: tool.x,
y: tool.y,
scaleX: 0.7,
scaleY: 0.7
}));
var text = new Text2(tool.name, {
size: 24,
fill: 0xFFFFFF
});
text.anchor.set(0.5, 0.5);
text.x = tool.x;
text.y = tool.y;
toolbar.addChild(text);
}
// Row 2 - Object types
var objectTypes = [{
name: 'Box',
type: 'box',
x: 150,
y: 150
}, {
name: 'Circle',
type: 'circle',
x: 300,
y: 150
}, {
name: 'Platform',
type: 'platform',
x: 450,
y: 150
}, {
name: 'Spike',
type: 'spike',
x: 600,
y: 150
}, {
name: 'Goal',
type: 'goal',
x: 750,
y: 150
}, {
name: 'Enemy',
type: 'enemy',
x: 900,
y: 150
}];
for (var i = 0; i < objectTypes.length; i++) {
var objType = objectTypes[i];
var btn = toolbar.addChild(LK.getAsset('categoryButton', {
anchorX: 0.5,
anchorY: 0.5,
x: objType.x,
y: objType.y,
scaleX: 0.6,
scaleY: 0.6
}));
var text = new Text2(objType.name, {
size: 20,
fill: 0xFFFFFF
});
text.anchor.set(0.5, 0.5);
text.x = objType.x;
text.y = objType.y;
toolbar.addChild(text);
}
// Create grid overlay
self.createGrid();
return toolbar;
};
self.createGrid = function () {
self.gridContainer = new Container();
game.addChild(self.gridContainer);
// Create grid dots
for (var x = 0; x < 2048; x += self.gridSize) {
for (var y = 200; y < 2732; y += self.gridSize) {
var dot = self.gridContainer.addChild(LK.getAsset('gridDot', {
anchorX: 0.5,
anchorY: 0.5,
x: x,
y: y
}));
dot.alpha = 0.3;
}
}
self.gridContainer.visible = self.snapToGrid;
};
self.snapToGridPosition = function (x, y) {
if (!self.snapToGrid) return {
x: x,
y: y
};
return {
x: Math.round(x / self.gridSize) * self.gridSize,
y: Math.round(y / self.gridSize) * self.gridSize
};
};
self.getAssetNameForType = function (type) {
switch (type) {
case 'circle':
return 'customCircle';
case 'platform':
return 'customPlatform';
case 'spike':
return 'customSpike';
case 'goal':
return 'customGoal';
case 'enemy':
return 'customEnemy';
default:
return 'customShape';
}
};
self.handleToolClick = function (x, y) {
// Row 1 - Main tools
if (y >= 50 && y <= 110) {
if (x >= 100 && x <= 200) self.mode = 'place';else if (x >= 250 && x <= 350) self.mode = 'delete';else if (x >= 400 && x <= 500) self.mode = 'copy';else if (x >= 550 && x <= 650) self.mode = 'resize';else if (x >= 700 && x <= 800) {
self.snapToGrid = !self.snapToGrid;
if (self.gridContainer) self.gridContainer.visible = self.snapToGrid;
} else if (x >= 850 && x <= 950) {
self.mode = 'color';
self.currentColor = [0xff7675, 0x74b9ff, 0x00b894, 0xfdcb6e, 0xe17055, 0x6c5ce7][Math.floor(Math.random() * 6)];
} else if (x >= 1150 && x <= 1250) {
self.mode = 'play';
self.startCustomGame();
} else if (x >= 1300 && x <= 1400) self.saveLevel();else if (x >= 1450 && x <= 1550) self.loadLevel();else if (x >= 1600 && x <= 1700) self.clearAll();
}
// Row 2 - Object types
else if (y >= 120 && y <= 180) {
if (x >= 100 && x <= 200) self.currentObjectType = 'box';else if (x >= 250 && x <= 350) self.currentObjectType = 'circle';else if (x >= 400 && x <= 500) self.currentObjectType = 'platform';else if (x >= 550 && x <= 650) self.currentObjectType = 'spike';else if (x >= 700 && x <= 800) self.currentObjectType = 'goal';else if (x >= 850 && x <= 950) self.currentObjectType = 'enemy';
}
};
self.handleCanvasClick = function (x, y) {
if (y < 200) return; // Don't place in toolbar area
var snappedPos = self.snapToGridPosition(x, y);
x = snappedPos.x;
y = snappedPos.y;
if (self.mode === 'place') {
var assetName = self.getAssetNameForType(self.currentObjectType);
var newObj = game.addChild(LK.getAsset(assetName, {
anchorX: 0.5,
anchorY: 0.5,
x: x,
y: y
}));
newObj.tint = self.currentColor;
newObj.isCustomObject = true;
newObj.objectType = self.currentObjectType;
newObj.customSize = 1.0;
self.createdObjects.push(newObj);
LK.getSound('tap').play();
} else if (self.mode === 'delete') {
self.deleteObjectAt(x, y);
} else if (self.mode === 'copy') {
var foundObj = self.findObjectAt(x, y);
if (foundObj) {
self.clipboard = {
type: foundObj.objectType,
color: foundObj.tint,
size: foundObj.customSize
};
LK.getSound('tap').play();
}
} else if (self.mode === 'resize') {
var foundObj = self.findObjectAt(x, y);
if (foundObj) {
foundObj.customSize = foundObj.customSize === 1.0 ? 1.5 : foundObj.customSize === 1.5 ? 0.5 : 1.0;
foundObj.scaleX = foundObj.customSize;
foundObj.scaleY = foundObj.customSize;
LK.getSound('tap').play();
}
} else if (self.mode === 'color') {
var foundObj = self.findObjectAt(x, y);
if (foundObj) {
foundObj.tint = self.currentColor;
LK.getSound('tap').play();
}
}
};
self.findObjectAt = function (x, y) {
for (var i = self.createdObjects.length - 1; i >= 0; i--) {
var obj = self.createdObjects[i];
var dx = obj.x - x;
var dy = obj.y - y;
var size = (obj.width || 80) * (obj.customSize || 1.0) / 2;
if (Math.sqrt(dx * dx + dy * dy) < size) {
return obj;
}
}
return null;
};
self.deleteObjectAt = function (x, y) {
for (var i = self.createdObjects.length - 1; i >= 0; i--) {
var obj = self.createdObjects[i];
var dx = obj.x - x;
var dy = obj.y - y;
var size = (obj.width || 80) * (obj.customSize || 1.0) / 2;
if (Math.sqrt(dx * dx + dy * dy) < size) {
obj.destroy();
self.createdObjects.splice(i, 1);
LK.getSound('tap').play();
break;
}
}
};
self.saveLevel = function () {
var levelData = [];
for (var i = 0; i < self.createdObjects.length; i++) {
var obj = self.createdObjects[i];
levelData.push({
type: obj.objectType,
x: obj.x,
y: obj.y,
color: obj.tint,
size: obj.customSize || 1.0
});
}
storage.customLevel = levelData;
LK.getSound('collect').play();
};
self.loadLevel = function () {
if (storage.customLevel) {
self.clearAll();
var levelData = storage.customLevel;
for (var i = 0; i < levelData.length; i++) {
var data = levelData[i];
var assetName = self.getAssetNameForType(data.type);
var newObj = game.addChild(LK.getAsset(assetName, {
anchorX: 0.5,
anchorY: 0.5,
x: data.x,
y: data.y
}));
newObj.tint = data.color;
newObj.isCustomObject = true;
newObj.objectType = data.type;
newObj.customSize = data.size;
newObj.scaleX = data.size;
newObj.scaleY = data.size;
self.createdObjects.push(newObj);
}
LK.getSound('collect').play();
}
};
self.clearAll = function () {
for (var i = 0; i < self.createdObjects.length; i++) {
self.createdObjects[i].destroy();
}
self.createdObjects = [];
if (self.gridContainer) {
self.gridContainer.destroy();
self.createGrid();
}
};
self.startCustomGame = function () {
if (self.createdObjects.length === 0) return;
currentGame = 'customGame';
customGameObjects = self.createdObjects.slice(); // Copy array
LK.setScore(0);
updateScoreDisplay();
};
return self;
});
var MazePlayer = Container.expand(function () {
var self = Container.call(this);
var graphic = self.attachAsset('mazePlayer', {
anchorX: 0.5,
anchorY: 0.5
});
self.gridX = 0;
self.gridY = 0;
self.cellSize = 80;
self.moveToGrid = function (gridX, gridY) {
self.gridX = gridX;
self.gridY = gridY;
self.x = gridX * self.cellSize + self.cellSize / 2;
self.y = gridY * self.cellSize + self.cellSize / 2 + 200;
};
return self;
});
var MazeWall = Container.expand(function () {
var self = Container.call(this);
var graphic = self.attachAsset('mazeWall', {
anchorX: 0.5,
anchorY: 0.5
});
return self;
});
var MovingPlatform = Container.expand(function (width, startX, endX) {
var self = Container.call(this);
var graphic = self.attachAsset('platform', {
anchorX: 0.5,
anchorY: 0.5
});
if (width) {
graphic.scaleX = width / 200;
}
graphic.tint = 0x74b9ff; // Blue tint for moving platforms
self.startX = startX;
self.endX = endX;
self.speed = 2;
self.direction = 1;
self.update = function () {
self.x += self.speed * self.direction;
if (self.x >= self.endX || self.x <= self.startX) {
self.direction *= -1;
}
};
return self;
});
var Paddle = Container.expand(function () {
var self = Container.call(this);
var graphic = self.attachAsset('paddle', {
anchorX: 0.5,
anchorY: 0.5
});
self.x = 1024;
self.y = 2600;
return self;
});
var Platform = Container.expand(function () {
var self = Container.call(this);
var graphic = self.attachAsset('platform', {
anchorX: 0.5,
anchorY: 0.5
});
return self;
});
var PlatformPlayer = Container.expand(function () {
var self = Container.call(this);
var graphic = self.attachAsset('platformPlayer', {
anchorX: 0.5,
anchorY: 0.5
});
self.velocityX = 0;
self.velocityY = 0;
self.gravity = 0.8;
self.jumpPower = -15;
self.speed = 6;
self.maxSpeed = 8;
self.onGround = false;
self.lastY = 0;
self.lastX = 0;
self.width = 60;
self.height = 80;
self.update = function () {
self.lastY = self.y;
self.lastX = self.x;
// Apply gravity
self.velocityY += self.gravity;
if (self.velocityY > 20) self.velocityY = 20; // Terminal velocity
// Apply horizontal velocity
self.x += self.velocityX;
// Check horizontal platform collisions
for (var i = 0; i < platforms.length; i++) {
var platform = platforms[i];
if (self.intersects(platform)) {
// Push player out horizontally
if (self.velocityX > 0) {
// Moving right, hit left side of platform
self.x = platform.x - platform.width * platform.scaleX / 2 - self.width / 2;
} else if (self.velocityX < 0) {
// Moving left, hit right side of platform
self.x = platform.x + platform.width * platform.scaleX / 2 + self.width / 2;
}
self.velocityX = 0;
break;
}
}
// Apply vertical velocity
self.y += self.velocityY;
// Friction
self.velocityX *= 0.85;
// Keep player on screen horizontally
if (self.x < 30) {
self.x = 30;
self.velocityX = 0;
}
if (self.x > 2018) {
self.x = 2018;
self.velocityX = 0;
}
// Reset if player falls off screen
if (self.y > 2800) {
self.x = 200;
self.y = 2000;
self.velocityX = 0;
self.velocityY = 0;
}
self.onGround = false;
};
self.jump = function () {
if (self.onGround) {
self.velocityY = self.jumpPower;
self.onGround = false;
LK.getSound('jump').play();
}
};
self.moveLeft = function () {
self.velocityX -= self.speed;
if (self.velocityX < -self.maxSpeed) self.velocityX = -self.maxSpeed;
};
self.moveRight = function () {
self.velocityX += self.speed;
if (self.velocityX > self.maxSpeed) self.velocityX = self.maxSpeed;
};
return self;
});
var ScrollBar = Container.expand(function () {
var self = Container.call(this);
self.scrollPosition = 0;
self.maxScroll = 0;
self.contentHeight = 0;
self.viewHeight = 2000;
// Create scroll bar background
var scrollBg = self.attachAsset('scrollBar', {
anchorX: 0.5,
anchorY: 0
});
// Create scroll thumb
var scrollThumb = self.attachAsset('scrollThumb', {
anchorX: 0.5,
anchorY: 0
});
// Create up button
var upBtn = self.attachAsset('scrollUpBtn', {
anchorX: 0.5,
anchorY: 0.5,
y: -50
});
// Create down button
var downBtn = self.attachAsset('scrollDownBtn', {
anchorX: 0.5,
anchorY: 0.5,
y: 450
});
// Add up/down arrows as text
var upText = new Text2('▲', {
size: 24,
fill: 0xFFFFFF
});
upText.anchor.set(0.5, 0.5);
upText.y = -50;
self.addChild(upText);
var downText = new Text2('▼', {
size: 24,
fill: 0xFFFFFF
});
downText.anchor.set(0.5, 0.5);
downText.y = 450;
self.addChild(downText);
self.setContentHeight = function (height) {
self.contentHeight = height;
self.maxScroll = Math.max(0, height - self.viewHeight);
self.updateThumb();
};
self.updateThumb = function () {
if (self.maxScroll > 0) {
var thumbRatio = self.viewHeight / self.contentHeight;
var thumbHeight = Math.max(30, scrollBg.height * thumbRatio);
scrollThumb.scaleY = thumbHeight / 60;
var thumbPosition = self.scrollPosition / self.maxScroll * (scrollBg.height - thumbHeight);
scrollThumb.y = thumbPosition;
} else {
scrollThumb.y = 0;
}
};
self.scroll = function (delta) {
self.scrollPosition = Math.max(0, Math.min(self.maxScroll, self.scrollPosition + delta));
self.updateThumb();
return self.scrollPosition;
};
self.down = function (x, y, obj) {
var localY = y - self.y;
if (localY >= -75 && localY <= -25) {
// Up button clicked
self.scroll(-200);
LK.getSound('tap').play();
} else if (localY >= 425 && localY <= 475) {
// Down button clicked
self.scroll(200);
LK.getSound('tap').play();
}
};
return self;
});
var Snake = Container.expand(function () {
var self = Container.call(this);
var graphic = self.attachAsset('snake', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 4;
self.direction = {
x: 0,
y: -1
};
self.bodySegments = []; // Array to store body segments
self.segmentSize = 80; // Size of each body segment
self.moveCounter = 0; // Counter to control movement timing
self.update = function () {
self.moveCounter++;
// Only move every few frames to make it more manageable
if (self.moveCounter >= 15) {
self.moveCounter = 0;
// Store previous position for body segments to follow
var previousPositions = [{
x: self.x,
y: self.y
}];
for (var i = 0; i < self.bodySegments.length; i++) {
previousPositions.push({
x: self.bodySegments[i].x,
y: self.bodySegments[i].y
});
}
// Move head
self.x += self.direction.x * self.segmentSize;
self.y += self.direction.y * self.segmentSize;
// Move body segments to follow the segment in front
for (var i = 0; i < self.bodySegments.length; i++) {
self.bodySegments[i].x = previousPositions[i].x;
self.bodySegments[i].y = previousPositions[i].y;
}
}
// Wrap around screen
if (self.x < 0) self.x = 2048;
if (self.x > 2048) self.x = 0;
if (self.y < 0) self.y = 2732;
if (self.y > 2732) self.y = 0;
};
self.grow = function () {
// Create a new body segment
var newSegment = game.addChild(LK.getAsset('snake', {
anchorX: 0.5,
anchorY: 0.5
}));
// Position it at the tail (or at head if no body exists)
if (self.bodySegments.length > 0) {
var lastSegment = self.bodySegments[self.bodySegments.length - 1];
newSegment.x = lastSegment.x;
newSegment.y = lastSegment.y;
} else {
newSegment.x = self.x;
newSegment.y = self.y;
}
// Make it slightly different color to distinguish from head
newSegment.tint = 0x95a5a6;
self.bodySegments.push(newSegment);
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x1a1a2e
});
/****
* Game Code
****/
// Game state management
var currentGame = null;
var gameContainer = null;
var hubContainer = null;
var scoreText = null;
var backButton = null;
// Game data
var games = [{
id: 'snake',
title: 'Snake',
category: 'Classic',
locked: false,
bestScore: storage.snakeBest || 0
}, {
id: 'circle',
title: 'Circle Tap',
category: 'Arcade',
locked: false,
bestScore: storage.circleBest || 0
}, {
id: 'breakout',
title: 'Breakout',
category: 'Classic',
locked: false,
bestScore: storage.breakoutBest || 0
}, {
id: 'platform',
title: 'Platformer',
category: 'Adventure',
locked: false,
bestScore: storage.platformBest || 0
}, {
id: 'maze',
title: 'Maze Runner',
category: 'Puzzle',
locked: false,
bestScore: storage.mazeBest || 0
}, {
id: 'dash',
title: 'Geometry Dash',
category: 'Arcade',
locked: false,
bestScore: storage.dashBest || 0
}, {
id: 'creator',
title: 'Level Creator',
category: 'Tools',
locked: false,
bestScore: 0
}];
var categories = ['All', 'Classic', 'Arcade', 'Adventure', 'Puzzle', 'Tools'];
var currentCategory = 'All';
var gameCards = [];
var categoryButtons = [];
// Game variables
var snake = null;
var food = null;
var circles = [];
var ball = null;
var paddle = null;
var bricks = [];
var platforms = [];
var platformPlayer = null;
var maze = null;
var mazePlayer = null;
var coins = [];
var dashPlayer = null;
var dashObstacles = [];
var dashPortals = [];
var dashGameSpeed = 8;
var dashScore = 0;
var dashCameraX = 0;
var dashGroundY = 2400;
var gameCreator = null;
var customGameObjects = [];
var scrollBar = null;
function initializeHub() {
hubContainer = new Container();
game.addChild(hubContainer);
// Add background
var bg = hubContainer.addChild(LK.getAsset('hubBackground', {
anchorX: 0,
anchorY: 0,
x: 0,
y: 0
}));
// Title
var titleText = new Text2('FRVR Games Hub', {
size: 80,
fill: 0xFFFFFF
});
titleText.anchor.set(0.5, 0.5);
titleText.x = 1024;
titleText.y = 150;
hubContainer.addChild(titleText);
// Create category buttons
createCategoryButtons();
// Create scroll bar
scrollBar = hubContainer.addChild(new ScrollBar());
scrollBar.x = 1900;
scrollBar.y = 400;
// Create game cards
createGameCards();
// Update scroll content
updateScrollContent();
}
function createCategoryButtons() {
categoryButtons = [];
for (var i = 0; i < categories.length; i++) {
var category = categories[i];
var isActive = category === currentCategory;
var btn = hubContainer.addChild(new CategoryButton(category, isActive));
btn.x = 150 + i * 320;
btn.y = 250;
categoryButtons.push(btn);
}
}
function createGameCards() {
gameCards = [];
for (var i = 0; i < games.length; i++) {
var gameInfo = games[i];
var card = hubContainer.addChild(new GameCard(gameInfo));
gameCards.push(card);
}
updateGameCardPositions();
}
function updateGameCardPositions() {
var visibleGames = getFilteredGames();
var cardsPerRow = 4;
var cardSpacing = 450;
var rowSpacing = 380;
var startX = 300;
var startY = 450;
// Hide all cards first
for (var i = 0; i < gameCards.length; i++) {
gameCards[i].visible = false;
}
// Position visible cards
for (var i = 0; i < visibleGames.length; i++) {
var gameInfo = visibleGames[i];
var card = findGameCard(gameInfo.id);
if (card) {
card.visible = true;
var row = Math.floor(i / cardsPerRow);
var col = i % cardsPerRow;
card.x = startX + col * cardSpacing;
card.y = startY + row * rowSpacing - scrollBar.scrollPosition;
// Ensure cards stay within view bounds
if (card.y < 300 || card.y > 2500) {
card.visible = false;
}
}
}
}
function findGameCard(gameId) {
for (var i = 0; i < gameCards.length; i++) {
if (gameCards[i].gameInfo.id === gameId) {
return gameCards[i];
}
}
return null;
}
function getFilteredGames() {
if (currentCategory === 'All') {
return games;
}
var filtered = [];
for (var i = 0; i < games.length; i++) {
if (games[i].category === currentCategory) {
filtered.push(games[i]);
}
}
return filtered;
}
function filterGamesByCategory(category) {
currentCategory = category;
// Update category button states
for (var i = 0; i < categoryButtons.length; i++) {
categoryButtons[i].setActive(categoryButtons[i].categoryName === category);
}
updateGameCardPositions();
updateScrollContent();
}
function updateScrollContent() {
var visibleGames = getFilteredGames();
var cardsPerRow = 4;
var rows = Math.ceil(visibleGames.length / cardsPerRow);
var contentHeight = rows * 380 + 600;
scrollBar.setContentHeight(contentHeight);
}
function switchToGame(gameId) {
currentGame = gameId;
// Hide hub
if (hubContainer) {
hubContainer.visible = false;
}
// Create game container
gameContainer = new Container();
game.addChild(gameContainer);
// Create back button
createBackButton();
// Initialize specific game
if (gameId === 'snake') {
initializeSnakeGame();
} else if (gameId === 'circle') {
initializeCircleGame();
} else if (gameId === 'breakout') {
initializeBreakoutGame();
} else if (gameId === 'platform') {
initializePlatformGame();
} else if (gameId === 'maze') {
initializeMazeGame();
} else if (gameId === 'dash') {
initializeDashGame();
} else if (gameId === 'creator') {
initializeCreatorGame();
}
// Create score display
createScoreDisplay();
}
function createBackButton() {
backButton = LK.gui.topRight.addChild(LK.getAsset('categoryButton', {
anchorX: 1,
anchorY: 0,
x: -20,
y: 20,
scaleX: 0.6,
scaleY: 0.6
}));
var backText = new Text2('Hub', {
size: 28,
fill: 0xFFFFFF
});
backText.anchor.set(0.5, 0.5);
backText.x = backButton.x - backButton.width * 0.3;
backText.y = backButton.y + backButton.height * 0.3;
LK.gui.topRight.addChild(backText);
backButton.down = function () {
tween(backButton, {
scaleX: 0.55,
scaleY: 0.55
}, {
duration: 100
});
LK.getSound('tap').play();
};
backButton.up = function () {
tween(backButton, {
scaleX: 0.6,
scaleY: 0.6
}, {
duration: 100
});
returnToHub();
};
}
function createScoreDisplay() {
scoreText = new Text2('Score: 0', {
size: 48,
fill: 0xFFFFFF
});
scoreText.anchor.set(0.5, 0);
LK.gui.top.addChild(scoreText);
}
function updateScoreDisplay() {
if (scoreText) {
scoreText.setText('Score: ' + LK.getScore());
}
}
function returnToHub() {
// Clean up current game
endCurrentGame();
// Show hub
if (hubContainer) {
hubContainer.visible = true;
}
// Remove back button and score
if (backButton) {
backButton.destroy();
backButton = null;
}
if (scoreText) {
scoreText.destroy();
scoreText = null;
}
currentGame = null;
}
function endCurrentGame() {
// Save high score
saveHighScore();
// Clean up game objects
cleanupGameObjects();
// Remove game container
if (gameContainer) {
gameContainer.destroy();
gameContainer = null;
}
// Reset score
LK.setScore(0);
}
function saveHighScore() {
if (!currentGame) return;
var currentScore = LK.getScore();
var gameInfo = findGameInfo(currentGame);
if (gameInfo && currentScore > gameInfo.bestScore) {
gameInfo.bestScore = currentScore;
storage[currentGame + 'Best'] = currentScore;
// Update game card
var card = findGameCard(currentGame);
if (card) {
card.updateScore(currentScore);
}
}
}
function findGameInfo(gameId) {
for (var i = 0; i < games.length; i++) {
if (games[i].id === gameId) {
return games[i];
}
}
return null;
}
function cleanupGameObjects() {
// Reset all game variables
snake = null;
food = null;
circles = [];
ball = null;
paddle = null;
bricks = [];
platforms = [];
platformPlayer = null;
maze = null;
mazePlayer = null;
coins = [];
dashPlayer = null;
dashObstacles = [];
dashPortals = [];
gameCreator = null;
customGameObjects = [];
}
// Game initialization functions
function initializeSnakeGame() {
game.setBackgroundColor(0x2c3e50);
snake = gameContainer.addChild(new Snake());
snake.x = 1024;
snake.y = 1366;
food = gameContainer.addChild(new Food());
LK.setScore(0);
updateScoreDisplay();
}
function initializeCircleGame() {
game.setBackgroundColor(0x2d3436);
circles = [];
LK.setScore(0);
updateScoreDisplay();
}
function initializeBreakoutGame() {
game.setBackgroundColor(0x000000);
// Create paddle
paddle = gameContainer.addChild(new Paddle());
// Create ball
ball = gameContainer.addChild(new Ball());
ball.x = 1024;
ball.y = 2500;
// Create bricks
bricks = [];
for (var row = 0; row < 6; row++) {
for (var col = 0; col < 10; col++) {
var brick = gameContainer.addChild(new Brick());
brick.x = 200 + col * 165;
brick.y = 300 + row * 80;
bricks.push(brick);
}
}
LK.setScore(0);
updateScoreDisplay();
}
function initializePlatformGame() {
var bg = gameContainer.addChild(LK.getAsset('gameBackground1', {
anchorX: 0,
anchorY: 0,
x: 0,
y: 0
}));
// Create platforms
platforms = [];
var platformData = [{
x: 300,
y: 2600,
width: 400
}, {
x: 800,
y: 2400,
width: 200
}, {
x: 1200,
y: 2200,
width: 300
}, {
x: 400,
y: 2000,
width: 250
}, {
x: 1000,
y: 1800,
width: 200
}, {
x: 600,
y: 1600,
width: 350
}];
for (var i = 0; i < platformData.length; i++) {
var data = platformData[i];
var platform = gameContainer.addChild(new Platform());
platform.x = data.x;
platform.y = data.y;
if (data.width) {
platform.scaleX = data.width / 200;
}
platforms.push(platform);
}
// Create coins
coins = [];
var coinPositions = [{
x: 800,
y: 2300
}, {
x: 1200,
y: 2100
}, {
x: 400,
y: 1900
}, {
x: 1000,
y: 1700
}, {
x: 600,
y: 1500
}];
for (var i = 0; i < coinPositions.length; i++) {
var pos = coinPositions[i];
var coin = gameContainer.addChild(new Coin());
coin.x = pos.x;
coin.y = pos.y;
coin.startY = pos.y;
coins.push(coin);
}
// Create player
platformPlayer = gameContainer.addChild(new PlatformPlayer());
platformPlayer.x = 300;
platformPlayer.y = 2500;
LK.setScore(0);
updateScoreDisplay();
}
function initializeMazeGame() {
game.setBackgroundColor(0x34495e);
// Create simple maze layout
var mazeLayout = [[1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1], [1, 0, 1, 0, 1, 0, 1, 1, 1, 0, 1, 0, 1, 1, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 1], [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1], [1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 1, 1, 0, 1, 1, 1, 0, 1, 0, 1, 1, 1, 1, 1], [1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 1], [1, 0, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 1], [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1], [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]];
maze = mazeLayout;
// Create walls
for (var row = 0; row < maze.length; row++) {
for (var col = 0; col < maze[row].length; col++) {
if (maze[row][col] === 1) {
var wall = gameContainer.addChild(new MazeWall());
wall.x = col * 80 + 40;
wall.y = row * 80 + 40 + 200;
}
}
}
// Create exit
var exit = gameContainer.addChild(LK.getAsset('mazeExit', {
anchorX: 0.5,
anchorY: 0.5,
x: 23 * 80 + 40,
y: 7 * 80 + 40 + 200
}));
// Create player
mazePlayer = gameContainer.addChild(new MazePlayer());
mazePlayer.moveToGrid(1, 1);
LK.setScore(0);
updateScoreDisplay();
}
function initializeDashGame() {
var bg = gameContainer.addChild(LK.getAsset('gameBackground2', {
anchorX: 0,
anchorY: 0,
x: 0,
y: 0
}));
// Create player
dashPlayer = gameContainer.addChild(new DashPlayer());
dashPlayer.x = 300;
dashPlayer.y = dashGroundY - 100;
// Initialize game variables
dashObstacles = [];
dashPortals = [];
dashScore = 0;
dashCameraX = 0;
LK.setScore(0);
updateScoreDisplay();
}
function initializeCreatorGame() {
var bg = gameContainer.addChild(LK.getAsset('creatorBackground', {
anchorX: 0,
anchorY: 0,
x: 0,
y: 0
}));
gameCreator = new GameCreator();
var toolbar = gameCreator.createToolbar();
gameContainer.addChild(toolbar);
LK.setScore(0);
updateScoreDisplay();
}
// Initialize the hub
initializeHub();
// Event handlers
game.down = function (x, y, obj) {
if (!currentGame) {
// Hub navigation
if (scrollBar && scrollBar.visible) {
scrollBar.down(x, y, obj);
updateGameCardPositions();
}
} else {
// Game-specific controls
if (currentGame === 'snake') {
// Touch controls for snake direction
var dx = x - snake.x;
var dy = y - snake.y;
if (Math.abs(dx) > Math.abs(dy)) {
snake.direction = dx > 0 ? {
x: 1,
y: 0
} : {
x: -1,
y: 0
};
} else {
snake.direction = dy > 0 ? {
x: 0,
y: 1
} : {
x: 0,
y: -1
};
}
} else if (currentGame === 'platform') {
// Touch controls for platformer
if (x < 1024) {
platformPlayer.moveLeft();
} else {
platformPlayer.moveRight();
}
if (y > 2000) {
platformPlayer.jump();
}
} else if (currentGame === 'maze') {
// Touch controls for maze
var dx = x - mazePlayer.x;
var dy = y - mazePlayer.y;
var newGridX = mazePlayer.gridX;
var newGridY = mazePlayer.gridY;
if (Math.abs(dx) > Math.abs(dy)) {
newGridX += dx > 0 ? 1 : -1;
} else {
newGridY += dy > 0 ? 1 : -1;
}
if (newGridX >= 0 && newGridX < maze[0].length && newGridY >= 0 && newGridY < maze.length && maze[newGridY][newGridX] === 0) {
mazePlayer.moveToGrid(newGridX, newGridY);
}
} else if (currentGame === 'dash') {
if (dashPlayer.gameMode === 'cube') {
dashPlayer.jump();
} else if (dashPlayer.gameMode === 'ship') {
dashPlayer.hold();
}
} else if (currentGame === 'creator') {
gameCreator.handleToolClick(x, y);
gameCreator.handleCanvasClick(x, y);
}
}
LK.getSound('tap').play();
};
game.up = function (x, y, obj) {
if (currentGame === 'dash' && dashPlayer && dashPlayer.gameMode === 'ship') {
dashPlayer.release();
}
};
game.move = function (x, y, obj) {
if (currentGame === 'breakout' && paddle) {
paddle.x = x;
if (paddle.x < 100) paddle.x = 100;
if (paddle.x > 1948) paddle.x = 1948;
}
};
game.update = function () {
if (!currentGame) {
// Hub update
return;
}
// Game-specific updates
if (currentGame === 'snake') {
updateSnakeGame();
} else if (currentGame === 'circle') {
updateCircleGame();
} else if (currentGame === 'breakout') {
updateBreakoutGame();
} else if (currentGame === 'platform') {
updatePlatformGame();
} else if (currentGame === 'maze') {
updateMazeGame();
} else if (currentGame === 'dash') {
updateDashGame();
}
};
function updateSnakeGame() {
// Check food collision
if (snake && food && snake.intersects(food)) {
LK.setScore(LK.getScore() + 10);
updateScoreDisplay();
snake.grow();
food.destroy();
food = gameContainer.addChild(new Food());
LK.getSound('collect').play();
}
}
function updateCircleGame() {
// Spawn circles
if (LK.ticks % 90 === 0) {
var circle = gameContainer.addChild(new Circle());
circle.x = 100 + Math.random() * 1848;
circle.y = 100 + Math.random() * 2532;
circles.push(circle);
}
// Remove expired circles
for (var i = circles.length - 1; i >= 0; i--) {
if (circles[i].shouldRemove) {
circles[i].destroy();
circles.splice(i, 1);
}
}
}
function updateBreakoutGame() {
// Check brick collisions
for (var i = bricks.length - 1; i >= 0; i--) {
if (ball && ball.intersects(bricks[i])) {
ball.speedY = -ball.speedY;
bricks[i].destroy();
bricks.splice(i, 1);
LK.setScore(LK.getScore() + 10);
updateScoreDisplay();
LK.getSound('collect').play();
if (bricks.length === 0) {
LK.showYouWin();
}
}
}
}
function updatePlatformGame() {
// Check platform collisions for player
if (platformPlayer) {
platformPlayer.onGround = false;
for (var i = 0; i < platforms.length; i++) {
var platform = platforms[i];
if (platformPlayer.intersects(platform) && platformPlayer.lastY <= platform.y - platform.height * platform.scaleY / 2 && platformPlayer.velocityY > 0) {
platformPlayer.y = platform.y - platform.height * platform.scaleY / 2 - platformPlayer.height / 2;
platformPlayer.velocityY = 0;
platformPlayer.onGround = true;
break;
}
}
// Check coin collisions
for (var i = coins.length - 1; i >= 0; i--) {
var coin = coins[i];
if (platformPlayer.intersects(coin)) {
LK.setScore(LK.getScore() + 100);
updateScoreDisplay();
coin.destroy();
coins.splice(i, 1);
LK.getSound('collect').play();
if (coins.length === 0) {
LK.showYouWin();
}
}
}
}
}
function updateMazeGame() {
if (mazePlayer) {
// Check if reached exit
if (mazePlayer.gridX === 23 && mazePlayer.gridY === 7) {
LK.setScore(LK.getScore() + 1000);
updateScoreDisplay();
LK.showYouWin();
}
}
}
function updateDashGame() {
if (!dashPlayer || dashPlayer.isDead) return;
dashScore++;
LK.setScore(Math.floor(dashScore / 10));
updateScoreDisplay();
// Spawn obstacles
if (LK.ticks % 60 === 0) {
var obstacleType = Math.random() < 0.7 ? 'block' : 'spike';
var obstacle = gameContainer.addChild(new DashObstacle(obstacleType));
obstacle.x = 2200;
obstacle.y = dashGroundY - 40;
dashObstacles.push(obstacle);
}
// Spawn portals occasionally
if (LK.ticks % 300 === 0) {
var portalTypes = ['cube', 'ship', 'ball', 'wave'];
var portalType = portalTypes[Math.floor(Math.random() * portalTypes.length)];
var portal = gameContainer.addChild(new DashPortal(portalType));
portal.x = 2200;
portal.y = dashGroundY - 100;
dashPortals.push(portal);
}
// Check obstacle collisions
for (var i = 0; i < dashObstacles.length; i++) {
var obstacle = dashObstacles[i];
if (dashPlayer.intersects(obstacle)) {
dashPlayer.die();
break;
}
}
// Check portal collisions
for (var i = dashPortals.length - 1; i >= 0; i--) {
var portal = dashPortals[i];
if (dashPlayer.intersects(portal)) {
dashPlayer.changeMode(portal.portalType);
portal.destroy();
dashPortals.splice(i, 1);
LK.getSound('collect').play();
}
}
// Ground collision for cube mode
if (dashPlayer.gameMode === 'cube' && dashPlayer.y >= dashGroundY - 30) {
dashPlayer.y = dashGroundY - 30;
dashPlayer.velocityY = 0;
dashPlayer.isGrounded = true;
}
// Remove off-screen obstacles
for (var i = dashObstacles.length - 1; i >= 0; i--) {
if (dashObstacles[i].shouldRemove) {
dashObstacles[i].destroy();
dashObstacles.splice(i, 1);
}
}
for (var i = dashPortals.length - 1; i >= 0; i--) {
if (dashPortals[i].shouldRemove) {
dashPortals[i].destroy();
dashPortals.splice(i, 1);
}
}
}
LK.playMusic('bgMusic'); /****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
var storage = LK.import("@upit/storage.v1");
/****
* Classes
****/
var Ball = Container.expand(function () {
var self = Container.call(this);
var graphic = self.attachAsset('ball', {
anchorX: 0.5,
anchorY: 0.5
});
self.speedX = 5;
self.speedY = -5;
self.update = function () {
self.x += self.speedX;
self.y += self.speedY;
// Bounce off walls
if (self.x < 20 || self.x > 2028) {
self.speedX = -self.speedX;
LK.getSound('bounce').play();
}
if (self.y < 20) {
self.speedY = -self.speedY;
LK.getSound('bounce').play();
}
// Game over if ball goes below paddle
if (self.y > 2732) {
endCurrentGame();
}
// Bounce off paddle
if (paddle && self.intersects(paddle) && self.speedY > 0) {
self.speedY = -self.speedY;
LK.getSound('bounce').play();
}
};
return self;
});
var Brick = Container.expand(function () {
var self = Container.call(this);
var graphic = self.attachAsset('brick', {
anchorX: 0.5,
anchorY: 0.5
});
return self;
});
var CategoryButton = Container.expand(function (categoryName, isActive) {
var self = Container.call(this);
var buttonBg = self.attachAsset('categoryButton', {
anchorX: 0.5,
anchorY: 0.5
});
if (isActive) {
buttonBg.tint = 0x0984e3; // Darker blue for active state
}
var buttonText = new Text2(categoryName, {
size: 32,
fill: 0xFFFFFF
});
buttonText.anchor.set(0.5, 0.5);
self.addChild(buttonText);
self.categoryName = categoryName;
self.isActive = isActive;
self.setActive = function (active) {
self.isActive = active;
buttonBg.tint = active ? 0x0984e3 : 0x74b9ff;
};
self.down = function (x, y, obj) {
tween(buttonBg, {
scaleX: 0.95,
scaleY: 0.95
}, {
duration: 100
});
LK.getSound('tap').play();
};
self.up = function (x, y, obj) {
tween(buttonBg, {
scaleX: 1,
scaleY: 1
}, {
duration: 100
});
filterGamesByCategory(self.categoryName);
};
return self;
});
var Circle = Container.expand(function () {
var self = Container.call(this);
var graphic = self.attachAsset('circle', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 2 + Math.random() * 3;
self.direction = Math.random() * Math.PI * 2;
self.lifetime = 180; // 3 seconds at 60fps
self.maxLifetime = self.lifetime;
self.update = function () {
self.x += Math.cos(self.direction) * self.speed;
self.y += Math.sin(self.direction) * self.speed;
// Bounce off walls
if (self.x < 60 || self.x > 1988) {
self.direction = Math.PI - self.direction;
}
if (self.y < 60 || self.y > 2672) {
self.direction = -self.direction;
}
self.lifetime--;
var alpha = self.lifetime / self.maxLifetime;
graphic.alpha = alpha;
if (self.lifetime <= 0) {
self.shouldRemove = true;
}
};
self.down = function (x, y, obj) {
LK.getSound('tap').play();
LK.setScore(LK.getScore() + 10);
updateScoreDisplay();
self.shouldRemove = true;
};
return self;
});
var Coin = Container.expand(function () {
var self = Container.call(this);
var graphic = self.attachAsset('coin', {
anchorX: 0.5,
anchorY: 0.5
});
self.bobOffset = Math.random() * Math.PI * 2;
self.startY = 0;
self.update = function () {
self.y = self.startY + Math.sin(LK.ticks * 0.1 + self.bobOffset) * 10;
};
return self;
});
var DashObstacle = Container.expand(function (type) {
var self = Container.call(this);
self.obstacleType = type || 'block';
var assetName = 'dashObstacle';
if (type === 'spike') assetName = 'dashSpike';else if (type === 'ground') assetName = 'dashGround';
var graphic = self.attachAsset(assetName, {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = -8;
self.update = function () {
self.x += self.speed;
if (self.x < -100) {
self.shouldRemove = true;
}
};
return self;
});
var DashPlayer = Container.expand(function () {
var self = Container.call(this);
var graphic = self.attachAsset('dashPlayer', {
anchorX: 0.5,
anchorY: 0.5
});
self.velocityY = 0;
self.gravity = 1.2;
self.jumpPower = -18;
self.isGrounded = false;
self.isDead = false;
self.lastY = 0;
self.gameMode = 'cube'; // cube, ship, ball, wave
self.update = function () {
if (self.isDead) return;
self.lastY = self.y;
// Apply gravity for cube mode
if (self.gameMode === 'cube') {
self.velocityY += self.gravity;
if (self.velocityY > 15) self.velocityY = 15;
} else if (self.gameMode === 'ship') {
// Ship mode - controlled flight
if (self.isHolding) {
self.velocityY -= 1.5;
if (self.velocityY < -12) self.velocityY = -12;
} else {
self.velocityY += 1.2;
if (self.velocityY > 12) self.velocityY = 12;
}
}
self.y += self.velocityY;
self.isGrounded = false;
// Simple rotation based on velocity
if (self.gameMode === 'cube') {
graphic.rotation = 0;
} else if (self.gameMode === 'ship') {
graphic.rotation = self.velocityY * 0.1;
}
};
self.jump = function () {
if (self.gameMode === 'cube' && self.isGrounded) {
self.velocityY = self.jumpPower;
self.isGrounded = false;
LK.getSound('jump').play();
}
};
self.hold = function () {
self.isHolding = true;
};
self.release = function () {
self.isHolding = false;
};
self.die = function () {
if (self.isDead) return;
self.isDead = true;
// Flash red death effect
tween(graphic, {
tint: 0xff0000
}, {
duration: 200,
onFinish: function onFinish() {
tween(graphic, {
tint: 0xffffff
}, {
duration: 200
});
}
});
LK.setTimeout(function () {
endCurrentGame();
}, 500);
};
self.changeMode = function (newMode) {
self.gameMode = newMode;
if (newMode === 'ship') {
graphic.tint = 0x3498db;
} else if (newMode === 'ball') {
graphic.tint = 0xe67e22;
} else if (newMode === 'wave') {
graphic.tint = 0x9b59b6;
} else {
graphic.tint = 0xf39c12;
}
};
return self;
});
var DashPortal = Container.expand(function (portalType) {
var self = Container.call(this);
var graphic = self.attachAsset('dashPortal', {
anchorX: 0.5,
anchorY: 0.5
});
self.portalType = portalType || 'cube';
self.speed = -8;
// Color portals based on type
if (portalType === 'ship') {
graphic.tint = 0x3498db;
} else if (portalType === 'ball') {
graphic.tint = 0xe67e22;
} else if (portalType === 'wave') {
graphic.tint = 0x9b59b6;
} else {
graphic.tint = 0xf39c12;
}
self.update = function () {
self.x += self.speed;
if (self.x < -100) {
self.shouldRemove = true;
}
// Rotating effect
graphic.rotation += 0.1;
};
return self;
});
var Food = Container.expand(function () {
var self = Container.call(this);
var graphic = self.attachAsset('food', {
anchorX: 0.5,
anchorY: 0.5
});
self.x = 100 + Math.random() * 1848;
self.y = 100 + Math.random() * 2532;
return self;
});
var GameCard = Container.expand(function (gameInfo) {
var self = Container.call(this);
var isLocked = gameInfo.locked || false;
var cardBg = self.attachAsset(isLocked ? 'gameCardLocked' : 'gameCard', {
anchorX: 0.5,
anchorY: 0.5
});
// Add border effect
cardBg.tint = isLocked ? 0x34495e : 0x2c3e50;
if (isLocked) {
var lock = self.attachAsset('lockIcon', {
anchorX: 0.5,
anchorY: 0.5,
y: -20
});
}
var titleText = new Text2(gameInfo.title, {
size: 36,
fill: isLocked ? "#999999" : "#ffffff"
});
titleText.anchor.set(0.5, 0.5);
titleText.y = isLocked ? 30 : -40;
self.addChild(titleText);
var categoryText = new Text2(gameInfo.category, {
size: 24,
fill: isLocked ? "#666666" : "#74b9ff"
});
categoryText.anchor.set(0.5, 0.5);
categoryText.y = isLocked ? 60 : -10;
self.addChild(categoryText);
var scoreText = new Text2('Best: ' + (gameInfo.bestScore || 0), {
size: 28,
fill: isLocked ? "#555555" : "#00b894"
});
scoreText.anchor.set(0.5, 0.5);
scoreText.y = isLocked ? 90 : 30;
self.addChild(scoreText);
self.gameInfo = gameInfo;
self.isLocked = isLocked;
self.down = function (x, y, obj) {
if (!self.isLocked) {
tween(cardBg, {
scaleX: 0.95,
scaleY: 0.95
}, {
duration: 100
});
LK.getSound('tap').play();
}
};
self.up = function (x, y, obj) {
if (!self.isLocked) {
tween(cardBg, {
scaleX: 1,
scaleY: 1
}, {
duration: 100
});
currentGame = self.gameInfo.id;
switchToGame(currentGame);
}
};
self.updateScore = function (newScore) {
gameInfo.bestScore = newScore;
scoreText.setText('Best: ' + newScore);
};
self.unlock = function () {
self.isLocked = false;
gameInfo.locked = false;
cardBg.tint = 0x16213e;
titleText.tint = 0xffffff;
scoreText.tint = 0xcccccc;
if (lock) {
lock.visible = false;
}
};
return self;
});
var GameCreator = Container.expand(function () {
var self = Container.call(this);
self.mode = 'place'; // 'place', 'delete', 'color', 'resize', 'copy'
self.currentColor = 0x00b894;
self.currentObjectType = 'box'; // 'box', 'circle', 'platform', 'spike', 'goal', 'enemy'
self.gridSize = 40;
self.snapToGrid = true;
self.createdObjects = [];
self.clipboard = null;
self.selectedObject = null;
self.createToolbar = function () {
var toolbar = new Container();
// Row 1 - Main tools
var tools = [{
name: 'Place',
x: 150,
y: 80
}, {
name: 'Delete',
x: 300,
y: 80
}, {
name: 'Copy',
x: 450,
y: 80
}, {
name: 'Resize',
x: 600,
y: 80
}, {
name: 'Grid',
x: 750,
y: 80
}, {
name: 'Color',
x: 900,
y: 80
}, {
name: 'Play',
x: 1200,
y: 80
}, {
name: 'Save',
x: 1350,
y: 80
}, {
name: 'Load',
x: 1500,
y: 80
}, {
name: 'Clear',
x: 1650,
y: 80
}];
for (var i = 0; i < tools.length; i++) {
var tool = tools[i];
var btn = toolbar.addChild(LK.getAsset('toolButton', {
anchorX: 0.5,
anchorY: 0.5,
x: tool.x,
y: tool.y,
scaleX: 0.7,
scaleY: 0.7
}));
var text = new Text2(tool.name, {
size: 24,
fill: 0xFFFFFF
});
text.anchor.set(0.5, 0.5);
text.x = tool.x;
text.y = tool.y;
toolbar.addChild(text);
}
// Row 2 - Object types
var objectTypes = [{
name: 'Box',
type: 'box',
x: 150,
y: 150
}, {
name: 'Circle',
type: 'circle',
x: 300,
y: 150
}, {
name: 'Platform',
type: 'platform',
x: 450,
y: 150
}, {
name: 'Spike',
type: 'spike',
x: 600,
y: 150
}, {
name: 'Goal',
type: 'goal',
x: 750,
y: 150
}, {
name: 'Enemy',
type: 'enemy',
x: 900,
y: 150
}];
for (var i = 0; i < objectTypes.length; i++) {
var objType = objectTypes[i];
var btn = toolbar.addChild(LK.getAsset('categoryButton', {
anchorX: 0.5,
anchorY: 0.5,
x: objType.x,
y: objType.y,
scaleX: 0.6,
scaleY: 0.6
}));
var text = new Text2(objType.name, {
size: 20,
fill: 0xFFFFFF
});
text.anchor.set(0.5, 0.5);
text.x = objType.x;
text.y = objType.y;
toolbar.addChild(text);
}
// Create grid overlay
self.createGrid();
return toolbar;
};
self.createGrid = function () {
self.gridContainer = new Container();
game.addChild(self.gridContainer);
// Create grid dots
for (var x = 0; x < 2048; x += self.gridSize) {
for (var y = 200; y < 2732; y += self.gridSize) {
var dot = self.gridContainer.addChild(LK.getAsset('gridDot', {
anchorX: 0.5,
anchorY: 0.5,
x: x,
y: y
}));
dot.alpha = 0.3;
}
}
self.gridContainer.visible = self.snapToGrid;
};
self.snapToGridPosition = function (x, y) {
if (!self.snapToGrid) return {
x: x,
y: y
};
return {
x: Math.round(x / self.gridSize) * self.gridSize,
y: Math.round(y / self.gridSize) * self.gridSize
};
};
self.getAssetNameForType = function (type) {
switch (type) {
case 'circle':
return 'customCircle';
case 'platform':
return 'customPlatform';
case 'spike':
return 'customSpike';
case 'goal':
return 'customGoal';
case 'enemy':
return 'customEnemy';
default:
return 'customShape';
}
};
self.handleToolClick = function (x, y) {
// Row 1 - Main tools
if (y >= 50 && y <= 110) {
if (x >= 100 && x <= 200) self.mode = 'place';else if (x >= 250 && x <= 350) self.mode = 'delete';else if (x >= 400 && x <= 500) self.mode = 'copy';else if (x >= 550 && x <= 650) self.mode = 'resize';else if (x >= 700 && x <= 800) {
self.snapToGrid = !self.snapToGrid;
if (self.gridContainer) self.gridContainer.visible = self.snapToGrid;
} else if (x >= 850 && x <= 950) {
self.mode = 'color';
self.currentColor = [0xff7675, 0x74b9ff, 0x00b894, 0xfdcb6e, 0xe17055, 0x6c5ce7][Math.floor(Math.random() * 6)];
} else if (x >= 1150 && x <= 1250) {
self.mode = 'play';
self.startCustomGame();
} else if (x >= 1300 && x <= 1400) self.saveLevel();else if (x >= 1450 && x <= 1550) self.loadLevel();else if (x >= 1600 && x <= 1700) self.clearAll();
}
// Row 2 - Object types
else if (y >= 120 && y <= 180) {
if (x >= 100 && x <= 200) self.currentObjectType = 'box';else if (x >= 250 && x <= 350) self.currentObjectType = 'circle';else if (x >= 400 && x <= 500) self.currentObjectType = 'platform';else if (x >= 550 && x <= 650) self.currentObjectType = 'spike';else if (x >= 700 && x <= 800) self.currentObjectType = 'goal';else if (x >= 850 && x <= 950) self.currentObjectType = 'enemy';
}
};
self.handleCanvasClick = function (x, y) {
if (y < 200) return; // Don't place in toolbar area
var snappedPos = self.snapToGridPosition(x, y);
x = snappedPos.x;
y = snappedPos.y;
if (self.mode === 'place') {
var assetName = self.getAssetNameForType(self.currentObjectType);
var newObj = game.addChild(LK.getAsset(assetName, {
anchorX: 0.5,
anchorY: 0.5,
x: x,
y: y
}));
newObj.tint = self.currentColor;
newObj.isCustomObject = true;
newObj.objectType = self.currentObjectType;
newObj.customSize = 1.0;
self.createdObjects.push(newObj);
LK.getSound('tap').play();
} else if (self.mode === 'delete') {
self.deleteObjectAt(x, y);
} else if (self.mode === 'copy') {
var foundObj = self.findObjectAt(x, y);
if (foundObj) {
self.clipboard = {
type: foundObj.objectType,
color: foundObj.tint,
size: foundObj.customSize
};
LK.getSound('tap').play();
}
} else if (self.mode === 'resize') {
var foundObj = self.findObjectAt(x, y);
if (foundObj) {
foundObj.customSize = foundObj.customSize === 1.0 ? 1.5 : foundObj.customSize === 1.5 ? 0.5 : 1.0;
foundObj.scaleX = foundObj.customSize;
foundObj.scaleY = foundObj.customSize;
LK.getSound('tap').play();
}
} else if (self.mode === 'color') {
var foundObj = self.findObjectAt(x, y);
if (foundObj) {
foundObj.tint = self.currentColor;
LK.getSound('tap').play();
}
}
};
self.findObjectAt = function (x, y) {
for (var i = self.createdObjects.length - 1; i >= 0; i--) {
var obj = self.createdObjects[i];
var dx = obj.x - x;
var dy = obj.y - y;
var size = (obj.width || 80) * (obj.customSize || 1.0) / 2;
if (Math.sqrt(dx * dx + dy * dy) < size) {
return obj;
}
}
return null;
};
self.deleteObjectAt = function (x, y) {
for (var i = self.createdObjects.length - 1; i >= 0; i--) {
var obj = self.createdObjects[i];
var dx = obj.x - x;
var dy = obj.y - y;
var size = (obj.width || 80) * (obj.customSize || 1.0) / 2;
if (Math.sqrt(dx * dx + dy * dy) < size) {
obj.destroy();
self.createdObjects.splice(i, 1);
LK.getSound('tap').play();
break;
}
}
};
self.saveLevel = function () {
var levelData = [];
for (var i = 0; i < self.createdObjects.length; i++) {
var obj = self.createdObjects[i];
levelData.push({
type: obj.objectType,
x: obj.x,
y: obj.y,
color: obj.tint,
size: obj.customSize || 1.0
});
}
storage.customLevel = levelData;
LK.getSound('collect').play();
};
self.loadLevel = function () {
if (storage.customLevel) {
self.clearAll();
var levelData = storage.customLevel;
for (var i = 0; i < levelData.length; i++) {
var data = levelData[i];
var assetName = self.getAssetNameForType(data.type);
var newObj = game.addChild(LK.getAsset(assetName, {
anchorX: 0.5,
anchorY: 0.5,
x: data.x,
y: data.y
}));
newObj.tint = data.color;
newObj.isCustomObject = true;
newObj.objectType = data.type;
newObj.customSize = data.size;
newObj.scaleX = data.size;
newObj.scaleY = data.size;
self.createdObjects.push(newObj);
}
LK.getSound('collect').play();
}
};
self.clearAll = function () {
for (var i = 0; i < self.createdObjects.length; i++) {
self.createdObjects[i].destroy();
}
self.createdObjects = [];
if (self.gridContainer) {
self.gridContainer.destroy();
self.createGrid();
}
};
self.startCustomGame = function () {
if (self.createdObjects.length === 0) return;
currentGame = 'customGame';
customGameObjects = self.createdObjects.slice(); // Copy array
LK.setScore(0);
updateScoreDisplay();
};
return self;
});
var MazePlayer = Container.expand(function () {
var self = Container.call(this);
var graphic = self.attachAsset('mazePlayer', {
anchorX: 0.5,
anchorY: 0.5
});
self.gridX = 0;
self.gridY = 0;
self.cellSize = 80;
self.moveToGrid = function (gridX, gridY) {
self.gridX = gridX;
self.gridY = gridY;
self.x = gridX * self.cellSize + self.cellSize / 2;
self.y = gridY * self.cellSize + self.cellSize / 2 + 200;
};
return self;
});
var MazeWall = Container.expand(function () {
var self = Container.call(this);
var graphic = self.attachAsset('mazeWall', {
anchorX: 0.5,
anchorY: 0.5
});
return self;
});
var MovingPlatform = Container.expand(function (width, startX, endX) {
var self = Container.call(this);
var graphic = self.attachAsset('platform', {
anchorX: 0.5,
anchorY: 0.5
});
if (width) {
graphic.scaleX = width / 200;
}
graphic.tint = 0x74b9ff; // Blue tint for moving platforms
self.startX = startX;
self.endX = endX;
self.speed = 2;
self.direction = 1;
self.update = function () {
self.x += self.speed * self.direction;
if (self.x >= self.endX || self.x <= self.startX) {
self.direction *= -1;
}
};
return self;
});
var Paddle = Container.expand(function () {
var self = Container.call(this);
var graphic = self.attachAsset('paddle', {
anchorX: 0.5,
anchorY: 0.5
});
self.x = 1024;
self.y = 2600;
return self;
});
var Platform = Container.expand(function () {
var self = Container.call(this);
var graphic = self.attachAsset('platform', {
anchorX: 0.5,
anchorY: 0.5
});
return self;
});
var PlatformPlayer = Container.expand(function () {
var self = Container.call(this);
var graphic = self.attachAsset('platformPlayer', {
anchorX: 0.5,
anchorY: 0.5
});
self.velocityX = 0;
self.velocityY = 0;
self.gravity = 0.8;
self.jumpPower = -15;
self.speed = 6;
self.maxSpeed = 8;
self.onGround = false;
self.lastY = 0;
self.lastX = 0;
self.width = 60;
self.height = 80;
self.update = function () {
self.lastY = self.y;
self.lastX = self.x;
// Apply gravity
self.velocityY += self.gravity;
if (self.velocityY > 20) self.velocityY = 20; // Terminal velocity
// Apply horizontal velocity
self.x += self.velocityX;
// Check horizontal platform collisions
for (var i = 0; i < platforms.length; i++) {
var platform = platforms[i];
if (self.intersects(platform)) {
// Push player out horizontally
if (self.velocityX > 0) {
// Moving right, hit left side of platform
self.x = platform.x - platform.width * platform.scaleX / 2 - self.width / 2;
} else if (self.velocityX < 0) {
// Moving left, hit right side of platform
self.x = platform.x + platform.width * platform.scaleX / 2 + self.width / 2;
}
self.velocityX = 0;
break;
}
}
// Apply vertical velocity
self.y += self.velocityY;
// Friction
self.velocityX *= 0.85;
// Keep player on screen horizontally
if (self.x < 30) {
self.x = 30;
self.velocityX = 0;
}
if (self.x > 2018) {
self.x = 2018;
self.velocityX = 0;
}
// Reset if player falls off screen
if (self.y > 2800) {
self.x = 200;
self.y = 2000;
self.velocityX = 0;
self.velocityY = 0;
}
self.onGround = false;
};
self.jump = function () {
if (self.onGround) {
self.velocityY = self.jumpPower;
self.onGround = false;
LK.getSound('jump').play();
}
};
self.moveLeft = function () {
self.velocityX -= self.speed;
if (self.velocityX < -self.maxSpeed) self.velocityX = -self.maxSpeed;
};
self.moveRight = function () {
self.velocityX += self.speed;
if (self.velocityX > self.maxSpeed) self.velocityX = self.maxSpeed;
};
return self;
});
var ScrollBar = Container.expand(function () {
var self = Container.call(this);
self.scrollPosition = 0;
self.maxScroll = 0;
self.contentHeight = 0;
self.viewHeight = 2000;
// Create scroll bar background
var scrollBg = self.attachAsset('scrollBar', {
anchorX: 0.5,
anchorY: 0
});
// Create scroll thumb
var scrollThumb = self.attachAsset('scrollThumb', {
anchorX: 0.5,
anchorY: 0
});
// Create up button
var upBtn = self.attachAsset('scrollUpBtn', {
anchorX: 0.5,
anchorY: 0.5,
y: -50
});
// Create down button
var downBtn = self.attachAsset('scrollDownBtn', {
anchorX: 0.5,
anchorY: 0.5,
y: 450
});
// Add up/down arrows as text
var upText = new Text2('▲', {
size: 24,
fill: 0xFFFFFF
});
upText.anchor.set(0.5, 0.5);
upText.y = -50;
self.addChild(upText);
var downText = new Text2('▼', {
size: 24,
fill: 0xFFFFFF
});
downText.anchor.set(0.5, 0.5);
downText.y = 450;
self.addChild(downText);
self.setContentHeight = function (height) {
self.contentHeight = height;
self.maxScroll = Math.max(0, height - self.viewHeight);
self.updateThumb();
};
self.updateThumb = function () {
if (self.maxScroll > 0) {
var thumbRatio = self.viewHeight / self.contentHeight;
var thumbHeight = Math.max(30, scrollBg.height * thumbRatio);
scrollThumb.scaleY = thumbHeight / 60;
var thumbPosition = self.scrollPosition / self.maxScroll * (scrollBg.height - thumbHeight);
scrollThumb.y = thumbPosition;
} else {
scrollThumb.y = 0;
}
};
self.scroll = function (delta) {
self.scrollPosition = Math.max(0, Math.min(self.maxScroll, self.scrollPosition + delta));
self.updateThumb();
return self.scrollPosition;
};
self.down = function (x, y, obj) {
var localY = y - self.y;
if (localY >= -75 && localY <= -25) {
// Up button clicked
self.scroll(-200);
LK.getSound('tap').play();
} else if (localY >= 425 && localY <= 475) {
// Down button clicked
self.scroll(200);
LK.getSound('tap').play();
}
};
return self;
});
var Snake = Container.expand(function () {
var self = Container.call(this);
var graphic = self.attachAsset('snake', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 4;
self.direction = {
x: 0,
y: -1
};
self.bodySegments = []; // Array to store body segments
self.segmentSize = 80; // Size of each body segment
self.moveCounter = 0; // Counter to control movement timing
self.update = function () {
self.moveCounter++;
// Only move every few frames to make it more manageable
if (self.moveCounter >= 15) {
self.moveCounter = 0;
// Store previous position for body segments to follow
var previousPositions = [{
x: self.x,
y: self.y
}];
for (var i = 0; i < self.bodySegments.length; i++) {
previousPositions.push({
x: self.bodySegments[i].x,
y: self.bodySegments[i].y
});
}
// Move head
self.x += self.direction.x * self.segmentSize;
self.y += self.direction.y * self.segmentSize;
// Move body segments to follow the segment in front
for (var i = 0; i < self.bodySegments.length; i++) {
self.bodySegments[i].x = previousPositions[i].x;
self.bodySegments[i].y = previousPositions[i].y;
}
}
// Wrap around screen
if (self.x < 0) self.x = 2048;
if (self.x > 2048) self.x = 0;
if (self.y < 0) self.y = 2732;
if (self.y > 2732) self.y = 0;
};
self.grow = function () {
// Create a new body segment
var newSegment = game.addChild(LK.getAsset('snake', {
anchorX: 0.5,
anchorY: 0.5
}));
// Position it at the tail (or at head if no body exists)
if (self.bodySegments.length > 0) {
var lastSegment = self.bodySegments[self.bodySegments.length - 1];
newSegment.x = lastSegment.x;
newSegment.y = lastSegment.y;
} else {
newSegment.x = self.x;
newSegment.y = self.y;
}
// Make it slightly different color to distinguish from head
newSegment.tint = 0x95a5a6;
self.bodySegments.push(newSegment);
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x1a1a2e
});
/****
* Game Code
****/
// Game state management
var currentGame = null;
var gameContainer = null;
var hubContainer = null;
var scoreText = null;
var backButton = null;
// Game data
var games = [{
id: 'snake',
title: 'Snake',
category: 'Classic',
locked: false,
bestScore: storage.snakeBest || 0
}, {
id: 'circle',
title: 'Circle Tap',
category: 'Arcade',
locked: false,
bestScore: storage.circleBest || 0
}, {
id: 'breakout',
title: 'Breakout',
category: 'Classic',
locked: false,
bestScore: storage.breakoutBest || 0
}, {
id: 'platform',
title: 'Platformer',
category: 'Adventure',
locked: false,
bestScore: storage.platformBest || 0
}, {
id: 'maze',
title: 'Maze Runner',
category: 'Puzzle',
locked: false,
bestScore: storage.mazeBest || 0
}, {
id: 'dash',
title: 'Geometry Dash',
category: 'Arcade',
locked: false,
bestScore: storage.dashBest || 0
}, {
id: 'creator',
title: 'Level Creator',
category: 'Tools',
locked: false,
bestScore: 0
}];
var categories = ['All', 'Classic', 'Arcade', 'Adventure', 'Puzzle', 'Tools'];
var currentCategory = 'All';
var gameCards = [];
var categoryButtons = [];
// Game variables
var snake = null;
var food = null;
var circles = [];
var ball = null;
var paddle = null;
var bricks = [];
var platforms = [];
var platformPlayer = null;
var maze = null;
var mazePlayer = null;
var coins = [];
var dashPlayer = null;
var dashObstacles = [];
var dashPortals = [];
var dashGameSpeed = 8;
var dashScore = 0;
var dashCameraX = 0;
var dashGroundY = 2400;
var gameCreator = null;
var customGameObjects = [];
var scrollBar = null;
function initializeHub() {
hubContainer = new Container();
game.addChild(hubContainer);
// Add background
var bg = hubContainer.addChild(LK.getAsset('hubBackground', {
anchorX: 0,
anchorY: 0,
x: 0,
y: 0
}));
// Title
var titleText = new Text2('FRVR Games Hub', {
size: 80,
fill: 0xFFFFFF
});
titleText.anchor.set(0.5, 0.5);
titleText.x = 1024;
titleText.y = 150;
hubContainer.addChild(titleText);
// Create category buttons
createCategoryButtons();
// Create scroll bar
scrollBar = hubContainer.addChild(new ScrollBar());
scrollBar.x = 1900;
scrollBar.y = 400;
// Create game cards
createGameCards();
// Update scroll content
updateScrollContent();
}
function createCategoryButtons() {
categoryButtons = [];
for (var i = 0; i < categories.length; i++) {
var category = categories[i];
var isActive = category === currentCategory;
var btn = hubContainer.addChild(new CategoryButton(category, isActive));
btn.x = 150 + i * 320;
btn.y = 250;
categoryButtons.push(btn);
}
}
function createGameCards() {
gameCards = [];
for (var i = 0; i < games.length; i++) {
var gameInfo = games[i];
var card = hubContainer.addChild(new GameCard(gameInfo));
gameCards.push(card);
}
updateGameCardPositions();
}
function updateGameCardPositions() {
var visibleGames = getFilteredGames();
var cardsPerRow = 4;
var cardSpacing = 450;
var rowSpacing = 380;
var startX = 300;
var startY = 450;
// Hide all cards first
for (var i = 0; i < gameCards.length; i++) {
gameCards[i].visible = false;
}
// Position visible cards
for (var i = 0; i < visibleGames.length; i++) {
var gameInfo = visibleGames[i];
var card = findGameCard(gameInfo.id);
if (card) {
card.visible = true;
var row = Math.floor(i / cardsPerRow);
var col = i % cardsPerRow;
card.x = startX + col * cardSpacing;
card.y = startY + row * rowSpacing - scrollBar.scrollPosition;
// Ensure cards stay within view bounds
if (card.y < 300 || card.y > 2500) {
card.visible = false;
}
}
}
}
function findGameCard(gameId) {
for (var i = 0; i < gameCards.length; i++) {
if (gameCards[i].gameInfo.id === gameId) {
return gameCards[i];
}
}
return null;
}
function getFilteredGames() {
if (currentCategory === 'All') {
return games;
}
var filtered = [];
for (var i = 0; i < games.length; i++) {
if (games[i].category === currentCategory) {
filtered.push(games[i]);
}
}
return filtered;
}
function filterGamesByCategory(category) {
currentCategory = category;
// Update category button states
for (var i = 0; i < categoryButtons.length; i++) {
categoryButtons[i].setActive(categoryButtons[i].categoryName === category);
}
updateGameCardPositions();
updateScrollContent();
}
function updateScrollContent() {
var visibleGames = getFilteredGames();
var cardsPerRow = 4;
var rows = Math.ceil(visibleGames.length / cardsPerRow);
var contentHeight = rows * 380 + 600;
scrollBar.setContentHeight(contentHeight);
}
function switchToGame(gameId) {
currentGame = gameId;
// Hide hub
if (hubContainer) {
hubContainer.visible = false;
}
// Create game container
gameContainer = new Container();
game.addChild(gameContainer);
// Create back button
createBackButton();
// Initialize specific game
if (gameId === 'snake') {
initializeSnakeGame();
} else if (gameId === 'circle') {
initializeCircleGame();
} else if (gameId === 'breakout') {
initializeBreakoutGame();
} else if (gameId === 'platform') {
initializePlatformGame();
} else if (gameId === 'maze') {
initializeMazeGame();
} else if (gameId === 'dash') {
initializeDashGame();
} else if (gameId === 'creator') {
initializeCreatorGame();
}
// Create score display
createScoreDisplay();
}
function createBackButton() {
backButton = LK.gui.topRight.addChild(LK.getAsset('categoryButton', {
anchorX: 1,
anchorY: 0,
x: -20,
y: 20,
scaleX: 0.6,
scaleY: 0.6
}));
var backText = new Text2('Hub', {
size: 28,
fill: 0xFFFFFF
});
backText.anchor.set(0.5, 0.5);
backText.x = backButton.x - backButton.width * 0.3;
backText.y = backButton.y + backButton.height * 0.3;
LK.gui.topRight.addChild(backText);
backButton.down = function () {
tween(backButton, {
scaleX: 0.55,
scaleY: 0.55
}, {
duration: 100
});
LK.getSound('tap').play();
};
backButton.up = function () {
tween(backButton, {
scaleX: 0.6,
scaleY: 0.6
}, {
duration: 100
});
returnToHub();
};
}
function createScoreDisplay() {
scoreText = new Text2('Score: 0', {
size: 48,
fill: 0xFFFFFF
});
scoreText.anchor.set(0.5, 0);
LK.gui.top.addChild(scoreText);
}
function updateScoreDisplay() {
if (scoreText) {
scoreText.setText('Score: ' + LK.getScore());
}
}
function returnToHub() {
// Clean up current game
endCurrentGame();
// Show hub
if (hubContainer) {
hubContainer.visible = true;
}
// Remove back button and score
if (backButton) {
backButton.destroy();
backButton = null;
}
if (scoreText) {
scoreText.destroy();
scoreText = null;
}
currentGame = null;
}
function endCurrentGame() {
// Save high score
saveHighScore();
// Clean up game objects
cleanupGameObjects();
// Remove game container
if (gameContainer) {
gameContainer.destroy();
gameContainer = null;
}
// Reset score
LK.setScore(0);
}
function saveHighScore() {
if (!currentGame) return;
var currentScore = LK.getScore();
var gameInfo = findGameInfo(currentGame);
if (gameInfo && currentScore > gameInfo.bestScore) {
gameInfo.bestScore = currentScore;
storage[currentGame + 'Best'] = currentScore;
// Update game card
var card = findGameCard(currentGame);
if (card) {
card.updateScore(currentScore);
}
}
}
function findGameInfo(gameId) {
for (var i = 0; i < games.length; i++) {
if (games[i].id === gameId) {
return games[i];
}
}
return null;
}
function cleanupGameObjects() {
// Reset all game variables
snake = null;
food = null;
circles = [];
ball = null;
paddle = null;
bricks = [];
platforms = [];
platformPlayer = null;
maze = null;
mazePlayer = null;
coins = [];
dashPlayer = null;
dashObstacles = [];
dashPortals = [];
gameCreator = null;
customGameObjects = [];
}
// Game initialization functions
function initializeSnakeGame() {
game.setBackgroundColor(0x2c3e50);
snake = gameContainer.addChild(new Snake());
snake.x = 1024;
snake.y = 1366;
food = gameContainer.addChild(new Food());
LK.setScore(0);
updateScoreDisplay();
}
function initializeCircleGame() {
game.setBackgroundColor(0x2d3436);
circles = [];
LK.setScore(0);
updateScoreDisplay();
}
function initializeBreakoutGame() {
game.setBackgroundColor(0x000000);
// Create paddle
paddle = gameContainer.addChild(new Paddle());
// Create ball
ball = gameContainer.addChild(new Ball());
ball.x = 1024;
ball.y = 2500;
// Create bricks
bricks = [];
for (var row = 0; row < 6; row++) {
for (var col = 0; col < 10; col++) {
var brick = gameContainer.addChild(new Brick());
brick.x = 200 + col * 165;
brick.y = 300 + row * 80;
bricks.push(brick);
}
}
LK.setScore(0);
updateScoreDisplay();
}
function initializePlatformGame() {
var bg = gameContainer.addChild(LK.getAsset('gameBackground1', {
anchorX: 0,
anchorY: 0,
x: 0,
y: 0
}));
// Create platforms
platforms = [];
var platformData = [{
x: 300,
y: 2600,
width: 400
}, {
x: 800,
y: 2400,
width: 200
}, {
x: 1200,
y: 2200,
width: 300
}, {
x: 400,
y: 2000,
width: 250
}, {
x: 1000,
y: 1800,
width: 200
}, {
x: 600,
y: 1600,
width: 350
}];
for (var i = 0; i < platformData.length; i++) {
var data = platformData[i];
var platform = gameContainer.addChild(new Platform());
platform.x = data.x;
platform.y = data.y;
if (data.width) {
platform.scaleX = data.width / 200;
}
platforms.push(platform);
}
// Create coins
coins = [];
var coinPositions = [{
x: 800,
y: 2300
}, {
x: 1200,
y: 2100
}, {
x: 400,
y: 1900
}, {
x: 1000,
y: 1700
}, {
x: 600,
y: 1500
}];
for (var i = 0; i < coinPositions.length; i++) {
var pos = coinPositions[i];
var coin = gameContainer.addChild(new Coin());
coin.x = pos.x;
coin.y = pos.y;
coin.startY = pos.y;
coins.push(coin);
}
// Create player
platformPlayer = gameContainer.addChild(new PlatformPlayer());
platformPlayer.x = 300;
platformPlayer.y = 2500;
LK.setScore(0);
updateScoreDisplay();
}
function initializeMazeGame() {
game.setBackgroundColor(0x34495e);
// Create simple maze layout
var mazeLayout = [[1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1], [1, 0, 1, 0, 1, 0, 1, 1, 1, 0, 1, 0, 1, 1, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 1], [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1], [1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 1, 1, 0, 1, 1, 1, 0, 1, 0, 1, 1, 1, 1, 1], [1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 1], [1, 0, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 1], [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1], [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]];
maze = mazeLayout;
// Create walls
for (var row = 0; row < maze.length; row++) {
for (var col = 0; col < maze[row].length; col++) {
if (maze[row][col] === 1) {
var wall = gameContainer.addChild(new MazeWall());
wall.x = col * 80 + 40;
wall.y = row * 80 + 40 + 200;
}
}
}
// Create exit
var exit = gameContainer.addChild(LK.getAsset('mazeExit', {
anchorX: 0.5,
anchorY: 0.5,
x: 23 * 80 + 40,
y: 7 * 80 + 40 + 200
}));
// Create player
mazePlayer = gameContainer.addChild(new MazePlayer());
mazePlayer.moveToGrid(1, 1);
LK.setScore(0);
updateScoreDisplay();
}
function initializeDashGame() {
var bg = gameContainer.addChild(LK.getAsset('gameBackground2', {
anchorX: 0,
anchorY: 0,
x: 0,
y: 0
}));
// Create player
dashPlayer = gameContainer.addChild(new DashPlayer());
dashPlayer.x = 300;
dashPlayer.y = dashGroundY - 100;
// Initialize game variables
dashObstacles = [];
dashPortals = [];
dashScore = 0;
dashCameraX = 0;
LK.setScore(0);
updateScoreDisplay();
}
function initializeCreatorGame() {
var bg = gameContainer.addChild(LK.getAsset('creatorBackground', {
anchorX: 0,
anchorY: 0,
x: 0,
y: 0
}));
gameCreator = new GameCreator();
var toolbar = gameCreator.createToolbar();
gameContainer.addChild(toolbar);
LK.setScore(0);
updateScoreDisplay();
}
// Initialize the hub
initializeHub();
// Event handlers
game.down = function (x, y, obj) {
if (!currentGame) {
// Hub navigation
if (scrollBar && scrollBar.visible) {
scrollBar.down(x, y, obj);
updateGameCardPositions();
}
} else {
// Game-specific controls
if (currentGame === 'snake') {
// Touch controls for snake direction
var dx = x - snake.x;
var dy = y - snake.y;
if (Math.abs(dx) > Math.abs(dy)) {
snake.direction = dx > 0 ? {
x: 1,
y: 0
} : {
x: -1,
y: 0
};
} else {
snake.direction = dy > 0 ? {
x: 0,
y: 1
} : {
x: 0,
y: -1
};
}
} else if (currentGame === 'platform') {
// Touch controls for platformer
if (x < 1024) {
platformPlayer.moveLeft();
} else {
platformPlayer.moveRight();
}
if (y > 2000) {
platformPlayer.jump();
}
} else if (currentGame === 'maze') {
// Touch controls for maze
var dx = x - mazePlayer.x;
var dy = y - mazePlayer.y;
var newGridX = mazePlayer.gridX;
var newGridY = mazePlayer.gridY;
if (Math.abs(dx) > Math.abs(dy)) {
newGridX += dx > 0 ? 1 : -1;
} else {
newGridY += dy > 0 ? 1 : -1;
}
if (newGridX >= 0 && newGridX < maze[0].length && newGridY >= 0 && newGridY < maze.length && maze[newGridY][newGridX] === 0) {
mazePlayer.moveToGrid(newGridX, newGridY);
}
} else if (currentGame === 'dash') {
if (dashPlayer.gameMode === 'cube') {
dashPlayer.jump();
} else if (dashPlayer.gameMode === 'ship') {
dashPlayer.hold();
}
} else if (currentGame === 'creator') {
gameCreator.handleToolClick(x, y);
gameCreator.handleCanvasClick(x, y);
}
}
LK.getSound('tap').play();
};
game.up = function (x, y, obj) {
if (currentGame === 'dash' && dashPlayer && dashPlayer.gameMode === 'ship') {
dashPlayer.release();
}
};
game.move = function (x, y, obj) {
if (currentGame === 'breakout' && paddle) {
paddle.x = x;
if (paddle.x < 100) paddle.x = 100;
if (paddle.x > 1948) paddle.x = 1948;
}
};
game.update = function () {
if (!currentGame) {
// Hub update
return;
}
// Game-specific updates
if (currentGame === 'snake') {
updateSnakeGame();
} else if (currentGame === 'circle') {
updateCircleGame();
} else if (currentGame === 'breakout') {
updateBreakoutGame();
} else if (currentGame === 'platform') {
updatePlatformGame();
} else if (currentGame === 'maze') {
updateMazeGame();
} else if (currentGame === 'dash') {
updateDashGame();
}
};
function updateSnakeGame() {
// Check food collision
if (snake && food && snake.intersects(food)) {
LK.setScore(LK.getScore() + 10);
updateScoreDisplay();
snake.grow();
food.destroy();
food = gameContainer.addChild(new Food());
LK.getSound('collect').play();
}
}
function updateCircleGame() {
// Spawn circles
if (LK.ticks % 90 === 0) {
var circle = gameContainer.addChild(new Circle());
circle.x = 100 + Math.random() * 1848;
circle.y = 100 + Math.random() * 2532;
circles.push(circle);
}
// Remove expired circles
for (var i = circles.length - 1; i >= 0; i--) {
if (circles[i].shouldRemove) {
circles[i].destroy();
circles.splice(i, 1);
}
}
}
function updateBreakoutGame() {
// Check brick collisions
for (var i = bricks.length - 1; i >= 0; i--) {
if (ball && ball.intersects(bricks[i])) {
ball.speedY = -ball.speedY;
bricks[i].destroy();
bricks.splice(i, 1);
LK.setScore(LK.getScore() + 10);
updateScoreDisplay();
LK.getSound('collect').play();
if (bricks.length === 0) {
LK.showYouWin();
}
}
}
}
function updatePlatformGame() {
// Check platform collisions for player
if (platformPlayer) {
platformPlayer.onGround = false;
for (var i = 0; i < platforms.length; i++) {
var platform = platforms[i];
if (platformPlayer.intersects(platform) && platformPlayer.lastY <= platform.y - platform.height * platform.scaleY / 2 && platformPlayer.velocityY > 0) {
platformPlayer.y = platform.y - platform.height * platform.scaleY / 2 - platformPlayer.height / 2;
platformPlayer.velocityY = 0;
platformPlayer.onGround = true;
break;
}
}
// Check coin collisions
for (var i = coins.length - 1; i >= 0; i--) {
var coin = coins[i];
if (platformPlayer.intersects(coin)) {
LK.setScore(LK.getScore() + 100);
updateScoreDisplay();
coin.destroy();
coins.splice(i, 1);
LK.getSound('collect').play();
if (coins.length === 0) {
LK.showYouWin();
}
}
}
}
}
function updateMazeGame() {
if (mazePlayer) {
// Check if reached exit
if (mazePlayer.gridX === 23 && mazePlayer.gridY === 7) {
LK.setScore(LK.getScore() + 1000);
updateScoreDisplay();
LK.showYouWin();
}
}
}
function updateDashGame() {
if (!dashPlayer || dashPlayer.isDead) return;
dashScore++;
LK.setScore(Math.floor(dashScore / 10));
updateScoreDisplay();
// Spawn obstacles
if (LK.ticks % 60 === 0) {
var obstacleType = Math.random() < 0.7 ? 'block' : 'spike';
var obstacle = gameContainer.addChild(new DashObstacle(obstacleType));
obstacle.x = 2200;
obstacle.y = dashGroundY - 40;
dashObstacles.push(obstacle);
}
// Spawn portals occasionally
if (LK.ticks % 300 === 0) {
var portalTypes = ['cube', 'ship', 'ball', 'wave'];
var portalType = portalTypes[Math.floor(Math.random() * portalTypes.length)];
var portal = gameContainer.addChild(new DashPortal(portalType));
portal.x = 2200;
portal.y = dashGroundY - 100;
dashPortals.push(portal);
}
// Check obstacle collisions
for (var i = 0; i < dashObstacles.length; i++) {
var obstacle = dashObstacles[i];
if (dashPlayer.intersects(obstacle)) {
dashPlayer.die();
break;
}
}
// Check portal collisions
for (var i = dashPortals.length - 1; i >= 0; i--) {
var portal = dashPortals[i];
if (dashPlayer.intersects(portal)) {
dashPlayer.changeMode(portal.portalType);
portal.destroy();
dashPortals.splice(i, 1);
LK.getSound('collect').play();
}
}
// Ground collision for cube mode
if (dashPlayer.gameMode === 'cube' && dashPlayer.y >= dashGroundY - 30) {
dashPlayer.y = dashGroundY - 30;
dashPlayer.velocityY = 0;
dashPlayer.isGrounded = true;
}
// Remove off-screen obstacles
for (var i = dashObstacles.length - 1; i >= 0; i--) {
if (dashObstacles[i].shouldRemove) {
dashObstacles[i].destroy();
dashObstacles.splice(i, 1);
}
}
for (var i = dashPortals.length - 1; i >= 0; i--) {
if (dashPortals[i].shouldRemove) {
dashPortals[i].destroy();
dashPortals.splice(i, 1);
}
}
}
LK.playMusic('bgMusic');
Lock. No background. Transparent background. Blank background. No shadows. 2d. In-Game asset. flat
Bricks and sky. In-Game asset. 2d. High contrast. No shadows
Stars. In-Game asset. 2d. High contrast. No shadows
Paddle. In-Game asset. 2d. High contrast. No shadows
Brick. In-Game asset. 2d. High contrast. No shadows
A Roblox noob. In-Game asset. 2d. High contrast. No shadows
Platform. In-Game asset. 2d. High contrast. No shadows
Coin. In-Game asset. 2d. High contrast. No shadows
Wall. In-Game asset. 2d. High contrast. No shadows
Game hub. In-Game asset. 2d. High contrast. No shadows
Snake. In-Game asset. 2d. High contrast. No shadows
Ball. In-Game asset. 2d. High contrast. No shadows
Paint brush. In-Game asset. 2d. High contrast. No shadows
Dash. In-Game asset. 2d. High contrast. No shadows
Robot. In-Game asset. 2d. High contrast. No shadows
Game hub with a black background. In-Game asset. 2d. High contrast. No shadows
Flappy bird. No background. Transparent background. Blank background. No shadows. 2d. In-Game asset. flat
Enemy. No background. Transparent background. Blank background. No shadows. 2d. In-Game asset. flat