User prompt
add move command
User prompt
Let the ball be a little slower
User prompt
ortada yuvarlak olsun
User prompt
çizgiler ekle
User prompt
make the background more realistic
Code edit (1 edits merged)
Please save this source code
User prompt
Please fix the bug: 'Cannot read properties of undefined (reading 'length')' in or related to this line: 'self.attachAsset(self.assetId, {' Line Number: 22
Code edit (1 edits merged)
Please save this source code
User prompt
Neon Table Hockey Sparkle
Initial prompt
Create a table hockey game against an AI opponent with colorful neon lights, and have the puck sparkle whenever it bounces to the left or right.
/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
/****
* Classes
****/
// Paddle class (for both player and AI)
var Paddle = Container.expand(function () {
var self = Container.call(this);
self.radius = 130; // for collision
// Set a default assetId if not set before instantiation
if (!self.assetId) {
self.assetId = 'paddlePlayer';
}
self.attachAsset(self.assetId, {
anchorX: 0.5,
anchorY: 0.5
});
return self;
});
// Puck class
var Puck = Container.expand(function () {
var self = Container.call(this);
var puckGfx = self.attachAsset('puck', {
anchorX: 0.5,
anchorY: 0.5
});
self.radius = 40;
self.vx = 0;
self.vy = 0;
self.maxSpeed = 38;
self.minSpeed = 18;
self.update = function () {
self.x += self.vx;
self.y += self.vy;
// Clamp speed
var speed = Math.sqrt(self.vx * self.vx + self.vy * self.vy);
if (speed > self.maxSpeed) {
self.vx *= self.maxSpeed / speed;
self.vy *= self.maxSpeed / speed;
}
if (speed < self.minSpeed && speed > 0) {
self.vx *= self.minSpeed / speed;
self.vy *= self.minSpeed / speed;
}
};
return self;
});
// Sparkle effect class
var Sparkle = Container.expand(function () {
var self = Container.call(this);
var sparkleGfx = self.attachAsset('sparkle', {
anchorX: 0.5,
anchorY: 0.5
});
self.life = 18 + Math.floor(Math.random() * 10);
self.vx = (Math.random() - 0.5) * 12;
self.vy = (Math.random() - 0.5) * 32;
self.update = function () {
self.x += self.vx;
self.y += self.vy;
self.life--;
self.alpha = self.life / 24;
if (self.life <= 0) {
self.destroy();
}
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x0a0020
});
/****
* Game Code
****/
// Add a neon gradient background using a large, semi-transparent ellipse for realism
var neonBg = LK.getAsset('centerCircle', {
anchorX: 0.5,
anchorY: 0.5,
x: 2048 / 2,
y: 2732 / 2,
scaleX: 16,
scaleY: 8,
tint: 0x0a0020,
alpha: 0.32
});
game.addChild(neonBg);
// Add a second, smaller neon ellipse for a layered glow effect
var neonGlow = LK.getAsset('centerCircle', {
anchorX: 0.5,
anchorY: 0.5,
x: 2048 / 2,
y: 2732 / 2,
scaleX: 8,
scaleY: 3.5,
tint: 0x00fff7,
alpha: 0.13
});
game.addChild(neonGlow);
// Neon paddles and puck, sparkles, and goal lines
// Add neon center line
var centerLine = LK.getAsset('goalLine', {
anchorX: 0.5,
anchorY: 0.5,
x: 2048 / 2,
y: 2732 / 2,
scaleY: 2,
tint: 0x00fff7,
alpha: 0.18
});
game.addChild(centerLine);
// Add neon left side line
var leftLine = LK.getAsset('goalLine', {
anchorX: 0.5,
anchorY: 0.5,
x: 0 + 6,
y: 2732 / 2,
rotation: Math.PI / 2,
scaleY: 1.1,
tint: 0x00fff7,
alpha: 0.13
});
game.addChild(leftLine);
// Add neon right side line
var rightLine = LK.getAsset('goalLine', {
anchorX: 0.5,
anchorY: 0.5,
x: 2048 - 6,
y: 2732 / 2,
rotation: Math.PI / 2,
scaleY: 1.1,
tint: 0x00fff7,
alpha: 0.13
});
game.addChild(rightLine);
// Game constants
var FIELD_WIDTH = 2048;
var FIELD_HEIGHT = 2732;
var GOAL_HEIGHT = 32;
var PADDLE_Y_OFFSET = 220;
var AI_Y = FIELD_HEIGHT - PADDLE_Y_OFFSET;
var PLAYER_Y = PADDLE_Y_OFFSET;
var PUCK_START_Y = FIELD_HEIGHT / 2;
var PUCK_START_X = FIELD_WIDTH / 2;
var GOAL_LINE_Y_TOP = GOAL_HEIGHT;
var GOAL_LINE_Y_BOT = FIELD_HEIGHT - GOAL_HEIGHT;
// Game state
var playerScore = 0;
var aiScore = 0;
var maxScore = 7;
var dragging = false;
var dragOffsetX = 0,
dragOffsetY = 0;
var lastTouchX = 0,
lastTouchY = 0;
var sparkles = [];
var lastGoal = null;
// Make sure background ellipses are rendered behind all gameplay elements
game.setChildIndex(neonBg, 0);
game.setChildIndex(neonGlow, 1);
// Create paddles
var playerPaddle = new Paddle();
playerPaddle.assetId = 'paddlePlayer';
playerPaddle.x = FIELD_WIDTH / 2;
playerPaddle.y = PLAYER_Y;
game.addChild(playerPaddle);
var aiPaddle = new Paddle();
aiPaddle.assetId = 'paddleAI';
aiPaddle.x = FIELD_WIDTH / 2;
aiPaddle.y = AI_Y;
game.addChild(aiPaddle);
// Create puck
var puck = new Puck();
puck.x = PUCK_START_X;
puck.y = PUCK_START_Y;
resetPuck();
game.addChild(puck);
// Goal lines
var goalLineTop = LK.getAsset('goalLine', {
anchorX: 0.5,
anchorY: 0.5,
x: FIELD_WIDTH / 2,
y: GOAL_LINE_Y_TOP
});
game.addChild(goalLineTop);
var goalLineBot = LK.getAsset('goalLine', {
anchorX: 0.5,
anchorY: 0.5,
x: FIELD_WIDTH / 2,
y: GOAL_LINE_Y_BOT
});
game.addChild(goalLineBot);
// Score display
var scoreTxt = new Text2('0 : 0', {
size: 120,
fill: 0x00FFF7
});
scoreTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(scoreTxt);
// Helper: reset puck to center, random direction
function resetPuck(scoredBy) {
puck.x = PUCK_START_X;
puck.y = PUCK_START_Y;
var angle = Math.random() * Math.PI * 2;
// If scoredBy, send puck toward the other player
if (scoredBy === 'player') {
angle = Math.PI / 2 + (Math.random() - 0.5) * 0.7;
} else if (scoredBy === 'ai') {
angle = -Math.PI / 2 + (Math.random() - 0.5) * 0.7;
}
var speed = 24 + Math.random() * 8;
puck.vx = Math.cos(angle) * speed;
puck.vy = Math.sin(angle) * speed;
}
// Helper: clamp paddle inside field
function clampPaddle(paddle, isPlayer) {
var minX = paddle.radius + 12;
var maxX = FIELD_WIDTH - paddle.radius - 12;
var minY = isPlayer ? GOAL_LINE_Y_TOP + paddle.radius + 12 : FIELD_HEIGHT / 2 + paddle.radius + 12;
var maxY = isPlayer ? FIELD_HEIGHT / 2 - paddle.radius - 12 : GOAL_LINE_Y_BOT - paddle.radius - 12;
if (paddle.x < minX) {
paddle.x = minX;
}
if (paddle.x > maxX) {
paddle.x = maxX;
}
if (paddle.y < minY) {
paddle.y = minY;
}
if (paddle.y > maxY) {
paddle.y = maxY;
}
}
// Helper: paddle-puck collision
function checkPaddleCollision(paddle) {
var dx = puck.x - paddle.x;
var dy = puck.y - paddle.y;
var dist = Math.sqrt(dx * dx + dy * dy);
var minDist = paddle.radius + puck.radius;
if (dist < minDist) {
// Move puck out of paddle
var overlap = minDist - dist + 2;
var nx = dx / (dist || 1);
var ny = dy / (dist || 1);
puck.x += nx * overlap;
puck.y += ny * overlap;
// Reflect puck velocity
var dot = puck.vx * nx + puck.vy * ny;
puck.vx = puck.vx - 2 * dot * nx;
puck.vy = puck.vy - 2 * dot * ny;
// Add paddle movement to puck
if (paddle === playerPaddle && dragging) {
puck.vx += (paddle.x - lastTouchX) * 0.4;
puck.vy += (paddle.y - lastTouchY) * 0.4;
}
// Clamp puck speed
var speed = Math.sqrt(puck.vx * puck.vx + puck.vy * puck.vy);
if (speed < puck.minSpeed) {
puck.vx *= puck.minSpeed / (speed || 1);
puck.vy *= puck.minSpeed / (speed || 1);
}
// Neon flash effect
LK.effects.flashObject(paddle, 0xffffff, 120);
}
}
// Helper: wall collision and sparkle
function checkWallCollision() {
// Left/right walls
if (puck.x - puck.radius < 0) {
puck.x = puck.radius + 2;
puck.vx = -puck.vx;
spawnSparkles(puck.x, puck.y, 1);
}
if (puck.x + puck.radius > FIELD_WIDTH) {
puck.x = FIELD_WIDTH - puck.radius - 2;
puck.vx = -puck.vx;
spawnSparkles(puck.x, puck.y, 1);
}
// Top/bottom: check for goals
if (puck.y - puck.radius < GOAL_LINE_Y_TOP) {
// AI scores
if (puck.x > FIELD_WIDTH * 0.25 && puck.x < FIELD_WIDTH * 0.75) {
aiScore++;
updateScore();
LK.effects.flashScreen(0xff00e1, 400);
lastGoal = 'ai';
if (aiScore >= maxScore) {
LK.showGameOver();
return;
}
resetPuck('ai');
} else {
puck.y = GOAL_LINE_Y_TOP + puck.radius + 2;
puck.vy = -puck.vy;
}
}
if (puck.y + puck.radius > GOAL_LINE_Y_BOT) {
// Player scores
if (puck.x > FIELD_WIDTH * 0.25 && puck.x < FIELD_WIDTH * 0.75) {
playerScore++;
updateScore();
LK.effects.flashScreen(0x00fff7, 400);
lastGoal = 'player';
if (playerScore >= maxScore) {
LK.showYouWin();
return;
}
resetPuck('player');
} else {
puck.y = GOAL_LINE_Y_BOT - puck.radius - 2;
puck.vy = -puck.vy;
}
}
}
// Helper: update score text
function updateScore() {
scoreTxt.setText(playerScore + ' : ' + aiScore);
}
// Helper: spawn sparkles at (x, y)
function spawnSparkles(x, y, count) {
for (var i = 0; i < 8 + Math.floor(Math.random() * 4); i++) {
var s = new Sparkle();
s.x = x;
s.y = y;
s.alpha = 1;
sparkles.push(s);
game.addChild(s);
// Animate color
tween(s, {
tint: Math.random() > 0.5 ? 0x00fff7 : 0xff00e1
}, {
duration: 200
});
}
}
// AI logic
function aiMove() {
// Only move if puck is on AI's side or moving toward AI
var targetX = puck.x;
var targetY = AI_Y;
// Defensive: if puck is coming toward AI, track it
if (puck.vy > 0 && puck.y > FIELD_HEIGHT / 2 - 200) {
targetX = puck.x;
} else {
// Center
targetX = FIELD_WIDTH / 2;
}
// Add some reaction delay and error
var dx = targetX - aiPaddle.x;
var maxMove = 32 + Math.random() * 12;
if (Math.abs(dx) > maxMove) {
dx = maxMove * (dx > 0 ? 1 : -1);
}
aiPaddle.x += dx * 0.18;
clampPaddle(aiPaddle, false);
}
// Touch/mouse controls for player paddle
game.down = function (x, y, obj) {
// Only allow drag if touch is on player's half
if (y < FIELD_HEIGHT / 2) {
return;
}
// Check if touch is on paddle
var dx = x - playerPaddle.x;
var dy = y - playerPaddle.y;
if (dx * dx + dy * dy < playerPaddle.radius * playerPaddle.radius * 1.2) {
dragging = true;
dragOffsetX = playerPaddle.x - x;
dragOffsetY = playerPaddle.y - y;
lastTouchX = playerPaddle.x;
lastTouchY = playerPaddle.y;
}
};
game.move = function (x, y, obj) {
if (dragging) {
// Only allow paddle in player's half
playerPaddle.x = x + dragOffsetX;
playerPaddle.y = y + dragOffsetY;
clampPaddle(playerPaddle, true);
}
};
game.up = function (x, y, obj) {
dragging = false;
};
// Main update loop
game.update = function () {
// Update puck
puck.update();
// Update sparkles
for (var i = sparkles.length - 1; i >= 0; i--) {
var s = sparkles[i];
if (s.parent) {
s.update();
}
if (!s.parent) {
sparkles.splice(i, 1);
}
}
// AI move
aiMove();
// Paddle collision
checkPaddleCollision(playerPaddle);
checkPaddleCollision(aiPaddle);
// Wall and goal collision
checkWallCollision();
// Clamp paddles
clampPaddle(playerPaddle, true);
clampPaddle(aiPaddle, false);
// Save last touch for paddle velocity
if (dragging) {
lastTouchX = playerPaddle.x;
lastTouchY = playerPaddle.y;
}
};
// Set background color to deep neon blue
game.setBackgroundColor(0x0a0020); ===================================================================
--- original.js
+++ change.js
@@ -104,8 +104,43 @@
alpha: 0.13
});
game.addChild(neonGlow);
// Neon paddles and puck, sparkles, and goal lines
+// Add neon center line
+var centerLine = LK.getAsset('goalLine', {
+ anchorX: 0.5,
+ anchorY: 0.5,
+ x: 2048 / 2,
+ y: 2732 / 2,
+ scaleY: 2,
+ tint: 0x00fff7,
+ alpha: 0.18
+});
+game.addChild(centerLine);
+// Add neon left side line
+var leftLine = LK.getAsset('goalLine', {
+ anchorX: 0.5,
+ anchorY: 0.5,
+ x: 0 + 6,
+ y: 2732 / 2,
+ rotation: Math.PI / 2,
+ scaleY: 1.1,
+ tint: 0x00fff7,
+ alpha: 0.13
+});
+game.addChild(leftLine);
+// Add neon right side line
+var rightLine = LK.getAsset('goalLine', {
+ anchorX: 0.5,
+ anchorY: 0.5,
+ x: 2048 - 6,
+ y: 2732 / 2,
+ rotation: Math.PI / 2,
+ scaleY: 1.1,
+ tint: 0x00fff7,
+ alpha: 0.13
+});
+game.addChild(rightLine);
// Game constants
var FIELD_WIDTH = 2048;
var FIELD_HEIGHT = 2732;
var GOAL_HEIGHT = 32;