/**** * Plugins ****/ var tween = LK.import("@upit/tween.v1"); /**** * Classes ****/ var Obstacle = Container.expand(function (type) { var self = Container.call(this); self.type = type; var assetName = type === 'spike' ? 'spike' : type === 'cube' ? 'cubeEnemy' : 'barrier'; var obstacleGraphics = self.attachAsset(assetName, { anchorX: 0.5, anchorY: 0.5 }); self.speed = gameSpeed; self.update = function () { self.y += self.speed; }; return self; }); var PowerUp = Container.expand(function () { var self = Container.call(this); var powerupGraphics = self.attachAsset('powerup', { anchorX: 0.5, anchorY: 0.5 }); self.speed = gameSpeed; self.collected = false; self.update = function () { self.y += self.speed; // Pulsing effect to make it stand out powerupGraphics.scaleX = 1 + Math.sin(LK.ticks * 0.1) * 0.2; powerupGraphics.scaleY = 1 + Math.sin(LK.ticks * 0.1) * 0.2; powerupGraphics.rotation += 0.05; }; return self; }); var Ring = Container.expand(function () { var self = Container.call(this); var ringGraphics = self.attachAsset('ring', { anchorX: 0.5, anchorY: 0.5 }); self.speed = gameSpeed; self.collected = false; self.update = function () { self.y += self.speed; ringGraphics.rotation += 0.1; }; return self; }); var SonicCharacter = Container.expand(function () { var self = Container.call(this); var characterGraphics = self.attachAsset('sonicCharacter', { anchorX: 0.5, anchorY: 0.5 }); self.currentLane = 1; // 0 = left, 1 = center, 2 = right self.isJumping = false; self.isSliding = false; self.jumpStartY = 0; self.baseY = 0; self.isInvincible = false; self.invincibilityTimer = 0; self.activateInvincibility = function () { self.isInvincible = true; self.invincibilityTimer = LK.ticks + 300; // 5 seconds at 60fps // Visual effect - golden tint tween(characterGraphics, { tint: 0xFFD700 }, { duration: 200 }); // Pulsing effect during invincibility self.invincibilityPulse(); }; self.invincibilityPulse = function () { if (self.isInvincible) { tween(characterGraphics, { alpha: 0.5 }, { duration: 250, easing: tween.easeInOut, onFinish: function onFinish() { if (self.isInvincible) { tween(characterGraphics, { alpha: 1 }, { duration: 250, easing: tween.easeInOut, onFinish: function onFinish() { self.invincibilityPulse(); } }); } } }); } }; self.deactivateInvincibility = function () { self.isInvincible = false; // Remove visual effects tween.stop(characterGraphics, { alpha: true }); tween(characterGraphics, { tint: 0xFFFFFF, alpha: 1 }, { duration: 200 }); }; self.update = function () { // Check if invincibility should end if (self.isInvincible && LK.ticks >= self.invincibilityTimer) { self.deactivateInvincibility(); } }; self.moveTo = function (lane) { if (lane < 0 || lane > 2) return; self.currentLane = lane; var targetX = lanePositions[lane]; tween(self, { x: targetX }, { duration: 200, easing: tween.easeOut }); }; self.jump = function () { if (self.isJumping || self.isSliding) return; self.isJumping = true; self.jumpStartY = self.y; LK.getSound('jump').play(); tween(self, { y: self.jumpStartY - 150 }, { duration: 300, easing: tween.easeOut, onFinish: function onFinish() { tween(self, { y: self.jumpStartY }, { duration: 300, easing: tween.easeIn, onFinish: function onFinish() { self.isJumping = false; } }); } }); }; self.slide = function () { if (self.isJumping || self.isSliding) return; self.isSliding = true; var originalScale = characterGraphics.scaleY; characterGraphics.scaleY = 0.5; LK.setTimeout(function () { characterGraphics.scaleY = originalScale; self.isSliding = false; }, 500); }; return self; }); /**** * Initialize Game ****/ var game = new LK.Game({ backgroundColor: 0x87CEEB }); /**** * Game Code ****/ // Game variables var gameSpeed = 8; var speedIncrement = 0.02; var lanePositions = [2048 * 0.25, 2048 * 0.5, 2048 * 0.75]; var obstacles = []; var rings = []; var powerups = []; var lastObstacleSpawn = 0; var lastRingSpawn = 0; var lastPowerupSpawn = 0; var ringCount = 0; var gameDistance = 0; // Create lanes visual for (var i = 0; i < 3; i++) { var lane = LK.getAsset('lane', { anchorX: 0.5, anchorY: 0.5, alpha: 0.3, x: lanePositions[i], y: 2732 * 0.8 }); game.addChild(lane); } // Create character var sonic = game.addChild(new SonicCharacter()); sonic.x = lanePositions[1]; sonic.y = 2732 * 0.7; sonic.baseY = sonic.y; // Create UI var scoreText = new Text2('Rings: 0', { size: 80, fill: 0xFFFFFF }); scoreText.anchor.set(0.5, 0); LK.gui.top.addChild(scoreText); var distanceText = new Text2('Distance: 0m', { size: 60, fill: 0xFFFFFF }); distanceText.anchor.set(0, 0); distanceText.x = 50; distanceText.y = 50; LK.gui.topLeft.addChild(distanceText); // Touch controls var touchStartX = 0; var touchStartY = 0; var minSwipeDistance = 50; game.down = function (x, y, obj) { touchStartX = x; touchStartY = y; }; game.up = function (x, y, obj) { var deltaX = x - touchStartX; var deltaY = y - touchStartY; if (Math.abs(deltaX) > Math.abs(deltaY)) { // Horizontal swipe if (Math.abs(deltaX) > minSwipeDistance) { if (deltaX > 0) { // Swipe right sonic.moveTo(sonic.currentLane + 1); } else { // Swipe left sonic.moveTo(sonic.currentLane - 1); } } } else { // Vertical swipe if (Math.abs(deltaY) > minSwipeDistance) { if (deltaY < 0) { // Swipe up - jump sonic.jump(); } else { // Swipe down - slide sonic.slide(); } } } }; function spawnObstacle() { var obstacleTypes = ['spike', 'cube', 'barrier']; var type = obstacleTypes[Math.floor(Math.random() * obstacleTypes.length)]; var lane = Math.floor(Math.random() * 3); var obstacle = new Obstacle(type); obstacle.x = lanePositions[lane]; obstacle.y = -100; obstacle.speed = gameSpeed; obstacles.push(obstacle); game.addChild(obstacle); } function spawnRing() { var lane = Math.floor(Math.random() * 3); var ring = new Ring(); ring.x = lanePositions[lane]; ring.y = -100; ring.speed = gameSpeed; rings.push(ring); game.addChild(ring); } function spawnPowerup() { var lane = Math.floor(Math.random() * 3); var powerup = new PowerUp(); powerup.x = lanePositions[lane]; powerup.y = -100; powerup.speed = gameSpeed; powerups.push(powerup); game.addChild(powerup); } function checkCollisions() { // Check ring collection for (var i = rings.length - 1; i >= 0; i--) { var ring = rings[i]; if (!ring.collected && ring.intersects(sonic)) { ring.collected = true; ringCount++; LK.setScore(ringCount); scoreText.setText('Rings: ' + ringCount); LK.getSound('collect').play(); // Visual effect tween(ring, { alpha: 0, scaleX: 2, scaleY: 2 }, { duration: 300, onFinish: function onFinish() { ring.destroy(); } }); rings.splice(i, 1); } } // Check power-up collection for (var i = powerups.length - 1; i >= 0; i--) { var powerup = powerups[i]; if (!powerup.collected && powerup.intersects(sonic)) { powerup.collected = true; sonic.activateInvincibility(); LK.getSound('powerup').play(); // Visual effect tween(powerup, { alpha: 0, scaleX: 3, scaleY: 3 }, { duration: 400, onFinish: function onFinish() { powerup.destroy(); } }); powerups.splice(i, 1); } } // Check obstacle collisions for (var i = 0; i < obstacles.length; i++) { var obstacle = obstacles[i]; if (obstacle.intersects(sonic)) { // Check if player can avoid obstacle var canAvoid = false; if (obstacle.type === 'spike' && sonic.isJumping) { canAvoid = true; } else if (obstacle.type === 'barrier' && sonic.isSliding) { canAvoid = true; } else if (obstacle.type === 'cube' && (sonic.isJumping || sonic.isSliding)) { canAvoid = true; } if (!canAvoid && !sonic.isInvincible) { // Game over LK.effects.flashScreen(0xFF0000, 1000); LK.showGameOver(); return; } } } } function updateGameObjects() { // Update obstacles for (var i = obstacles.length - 1; i >= 0; i--) { var obstacle = obstacles[i]; obstacle.speed = gameSpeed; if (obstacle.y > 2732 + 100) { obstacle.destroy(); obstacles.splice(i, 1); } } // Update rings for (var i = rings.length - 1; i >= 0; i--) { var ring = rings[i]; ring.speed = gameSpeed; if (ring.y > 2732 + 100) { ring.destroy(); rings.splice(i, 1); } } // Update power-ups for (var i = powerups.length - 1; i >= 0; i--) { var powerup = powerups[i]; powerup.speed = gameSpeed; if (powerup.y > 2732 + 100) { powerup.destroy(); powerups.splice(i, 1); } } // Increase game speed gradually gameSpeed += speedIncrement; // Update distance gameDistance += gameSpeed * 0.1; distanceText.setText('Distance: ' + Math.floor(gameDistance) + 'm'); } // Start background music LK.playMusic('bgmusic'); game.update = function () { // Spawn obstacles if (LK.ticks - lastObstacleSpawn > 120 - Math.min(gameSpeed * 2, 60)) { spawnObstacle(); lastObstacleSpawn = LK.ticks; } // Spawn rings if (LK.ticks - lastRingSpawn > 80) { if (Math.random() < 0.7) { spawnRing(); } lastRingSpawn = LK.ticks; } // Spawn power-ups (less frequent than rings) if (LK.ticks - lastPowerupSpawn > 600) { // Every 10 seconds if (Math.random() < 0.3) { // 30% chance spawnPowerup(); } lastPowerupSpawn = LK.ticks; } checkCollisions(); updateGameObjects(); };
/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
/****
* Classes
****/
var Obstacle = Container.expand(function (type) {
var self = Container.call(this);
self.type = type;
var assetName = type === 'spike' ? 'spike' : type === 'cube' ? 'cubeEnemy' : 'barrier';
var obstacleGraphics = self.attachAsset(assetName, {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = gameSpeed;
self.update = function () {
self.y += self.speed;
};
return self;
});
var PowerUp = Container.expand(function () {
var self = Container.call(this);
var powerupGraphics = self.attachAsset('powerup', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = gameSpeed;
self.collected = false;
self.update = function () {
self.y += self.speed;
// Pulsing effect to make it stand out
powerupGraphics.scaleX = 1 + Math.sin(LK.ticks * 0.1) * 0.2;
powerupGraphics.scaleY = 1 + Math.sin(LK.ticks * 0.1) * 0.2;
powerupGraphics.rotation += 0.05;
};
return self;
});
var Ring = Container.expand(function () {
var self = Container.call(this);
var ringGraphics = self.attachAsset('ring', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = gameSpeed;
self.collected = false;
self.update = function () {
self.y += self.speed;
ringGraphics.rotation += 0.1;
};
return self;
});
var SonicCharacter = Container.expand(function () {
var self = Container.call(this);
var characterGraphics = self.attachAsset('sonicCharacter', {
anchorX: 0.5,
anchorY: 0.5
});
self.currentLane = 1; // 0 = left, 1 = center, 2 = right
self.isJumping = false;
self.isSliding = false;
self.jumpStartY = 0;
self.baseY = 0;
self.isInvincible = false;
self.invincibilityTimer = 0;
self.activateInvincibility = function () {
self.isInvincible = true;
self.invincibilityTimer = LK.ticks + 300; // 5 seconds at 60fps
// Visual effect - golden tint
tween(characterGraphics, {
tint: 0xFFD700
}, {
duration: 200
});
// Pulsing effect during invincibility
self.invincibilityPulse();
};
self.invincibilityPulse = function () {
if (self.isInvincible) {
tween(characterGraphics, {
alpha: 0.5
}, {
duration: 250,
easing: tween.easeInOut,
onFinish: function onFinish() {
if (self.isInvincible) {
tween(characterGraphics, {
alpha: 1
}, {
duration: 250,
easing: tween.easeInOut,
onFinish: function onFinish() {
self.invincibilityPulse();
}
});
}
}
});
}
};
self.deactivateInvincibility = function () {
self.isInvincible = false;
// Remove visual effects
tween.stop(characterGraphics, {
alpha: true
});
tween(characterGraphics, {
tint: 0xFFFFFF,
alpha: 1
}, {
duration: 200
});
};
self.update = function () {
// Check if invincibility should end
if (self.isInvincible && LK.ticks >= self.invincibilityTimer) {
self.deactivateInvincibility();
}
};
self.moveTo = function (lane) {
if (lane < 0 || lane > 2) return;
self.currentLane = lane;
var targetX = lanePositions[lane];
tween(self, {
x: targetX
}, {
duration: 200,
easing: tween.easeOut
});
};
self.jump = function () {
if (self.isJumping || self.isSliding) return;
self.isJumping = true;
self.jumpStartY = self.y;
LK.getSound('jump').play();
tween(self, {
y: self.jumpStartY - 150
}, {
duration: 300,
easing: tween.easeOut,
onFinish: function onFinish() {
tween(self, {
y: self.jumpStartY
}, {
duration: 300,
easing: tween.easeIn,
onFinish: function onFinish() {
self.isJumping = false;
}
});
}
});
};
self.slide = function () {
if (self.isJumping || self.isSliding) return;
self.isSliding = true;
var originalScale = characterGraphics.scaleY;
characterGraphics.scaleY = 0.5;
LK.setTimeout(function () {
characterGraphics.scaleY = originalScale;
self.isSliding = false;
}, 500);
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x87CEEB
});
/****
* Game Code
****/
// Game variables
var gameSpeed = 8;
var speedIncrement = 0.02;
var lanePositions = [2048 * 0.25, 2048 * 0.5, 2048 * 0.75];
var obstacles = [];
var rings = [];
var powerups = [];
var lastObstacleSpawn = 0;
var lastRingSpawn = 0;
var lastPowerupSpawn = 0;
var ringCount = 0;
var gameDistance = 0;
// Create lanes visual
for (var i = 0; i < 3; i++) {
var lane = LK.getAsset('lane', {
anchorX: 0.5,
anchorY: 0.5,
alpha: 0.3,
x: lanePositions[i],
y: 2732 * 0.8
});
game.addChild(lane);
}
// Create character
var sonic = game.addChild(new SonicCharacter());
sonic.x = lanePositions[1];
sonic.y = 2732 * 0.7;
sonic.baseY = sonic.y;
// Create UI
var scoreText = new Text2('Rings: 0', {
size: 80,
fill: 0xFFFFFF
});
scoreText.anchor.set(0.5, 0);
LK.gui.top.addChild(scoreText);
var distanceText = new Text2('Distance: 0m', {
size: 60,
fill: 0xFFFFFF
});
distanceText.anchor.set(0, 0);
distanceText.x = 50;
distanceText.y = 50;
LK.gui.topLeft.addChild(distanceText);
// Touch controls
var touchStartX = 0;
var touchStartY = 0;
var minSwipeDistance = 50;
game.down = function (x, y, obj) {
touchStartX = x;
touchStartY = y;
};
game.up = function (x, y, obj) {
var deltaX = x - touchStartX;
var deltaY = y - touchStartY;
if (Math.abs(deltaX) > Math.abs(deltaY)) {
// Horizontal swipe
if (Math.abs(deltaX) > minSwipeDistance) {
if (deltaX > 0) {
// Swipe right
sonic.moveTo(sonic.currentLane + 1);
} else {
// Swipe left
sonic.moveTo(sonic.currentLane - 1);
}
}
} else {
// Vertical swipe
if (Math.abs(deltaY) > minSwipeDistance) {
if (deltaY < 0) {
// Swipe up - jump
sonic.jump();
} else {
// Swipe down - slide
sonic.slide();
}
}
}
};
function spawnObstacle() {
var obstacleTypes = ['spike', 'cube', 'barrier'];
var type = obstacleTypes[Math.floor(Math.random() * obstacleTypes.length)];
var lane = Math.floor(Math.random() * 3);
var obstacle = new Obstacle(type);
obstacle.x = lanePositions[lane];
obstacle.y = -100;
obstacle.speed = gameSpeed;
obstacles.push(obstacle);
game.addChild(obstacle);
}
function spawnRing() {
var lane = Math.floor(Math.random() * 3);
var ring = new Ring();
ring.x = lanePositions[lane];
ring.y = -100;
ring.speed = gameSpeed;
rings.push(ring);
game.addChild(ring);
}
function spawnPowerup() {
var lane = Math.floor(Math.random() * 3);
var powerup = new PowerUp();
powerup.x = lanePositions[lane];
powerup.y = -100;
powerup.speed = gameSpeed;
powerups.push(powerup);
game.addChild(powerup);
}
function checkCollisions() {
// Check ring collection
for (var i = rings.length - 1; i >= 0; i--) {
var ring = rings[i];
if (!ring.collected && ring.intersects(sonic)) {
ring.collected = true;
ringCount++;
LK.setScore(ringCount);
scoreText.setText('Rings: ' + ringCount);
LK.getSound('collect').play();
// Visual effect
tween(ring, {
alpha: 0,
scaleX: 2,
scaleY: 2
}, {
duration: 300,
onFinish: function onFinish() {
ring.destroy();
}
});
rings.splice(i, 1);
}
}
// Check power-up collection
for (var i = powerups.length - 1; i >= 0; i--) {
var powerup = powerups[i];
if (!powerup.collected && powerup.intersects(sonic)) {
powerup.collected = true;
sonic.activateInvincibility();
LK.getSound('powerup').play();
// Visual effect
tween(powerup, {
alpha: 0,
scaleX: 3,
scaleY: 3
}, {
duration: 400,
onFinish: function onFinish() {
powerup.destroy();
}
});
powerups.splice(i, 1);
}
}
// Check obstacle collisions
for (var i = 0; i < obstacles.length; i++) {
var obstacle = obstacles[i];
if (obstacle.intersects(sonic)) {
// Check if player can avoid obstacle
var canAvoid = false;
if (obstacle.type === 'spike' && sonic.isJumping) {
canAvoid = true;
} else if (obstacle.type === 'barrier' && sonic.isSliding) {
canAvoid = true;
} else if (obstacle.type === 'cube' && (sonic.isJumping || sonic.isSliding)) {
canAvoid = true;
}
if (!canAvoid && !sonic.isInvincible) {
// Game over
LK.effects.flashScreen(0xFF0000, 1000);
LK.showGameOver();
return;
}
}
}
}
function updateGameObjects() {
// Update obstacles
for (var i = obstacles.length - 1; i >= 0; i--) {
var obstacle = obstacles[i];
obstacle.speed = gameSpeed;
if (obstacle.y > 2732 + 100) {
obstacle.destroy();
obstacles.splice(i, 1);
}
}
// Update rings
for (var i = rings.length - 1; i >= 0; i--) {
var ring = rings[i];
ring.speed = gameSpeed;
if (ring.y > 2732 + 100) {
ring.destroy();
rings.splice(i, 1);
}
}
// Update power-ups
for (var i = powerups.length - 1; i >= 0; i--) {
var powerup = powerups[i];
powerup.speed = gameSpeed;
if (powerup.y > 2732 + 100) {
powerup.destroy();
powerups.splice(i, 1);
}
}
// Increase game speed gradually
gameSpeed += speedIncrement;
// Update distance
gameDistance += gameSpeed * 0.1;
distanceText.setText('Distance: ' + Math.floor(gameDistance) + 'm');
}
// Start background music
LK.playMusic('bgmusic');
game.update = function () {
// Spawn obstacles
if (LK.ticks - lastObstacleSpawn > 120 - Math.min(gameSpeed * 2, 60)) {
spawnObstacle();
lastObstacleSpawn = LK.ticks;
}
// Spawn rings
if (LK.ticks - lastRingSpawn > 80) {
if (Math.random() < 0.7) {
spawnRing();
}
lastRingSpawn = LK.ticks;
}
// Spawn power-ups (less frequent than rings)
if (LK.ticks - lastPowerupSpawn > 600) {
// Every 10 seconds
if (Math.random() < 0.3) {
// 30% chance
spawnPowerup();
}
lastPowerupSpawn = LK.ticks;
}
checkCollisions();
updateGameObjects();
};
Make Sonic run but with the camera above. In-Game asset. High contrast. No shadows
make sonic's enemy doctor eggman. In-Game asset. High contrast. No shadows
beam to sonic's ring. In-Game asset. High contrast. No shadows
barrel. In-Game asset. High contrast. No shadows
hot dog. In-Game asset. High contrast. No shadows
make a cactus. In-Game asset. High contrast. No shadows
make sand. In-Game asset. High contrast. No shadows