User prompt
Some obstacles are fake oil and when it comes to it, it will be destroyed in a short time โช๐ก Consider importing and using the following plugins: @upit/tween.v1
User prompt
increase the number of obstacles
User prompt
Make character walking animation โช๐ก Consider importing and using the following plugins: @upit/tween.v1
User prompt
Singer Away loops playing the audio file named song
User prompt
create an audio file that plays on loop while the singer is looking up
User prompt
The place of the obstacles in between should be random
User prompt
obstacles appear randomly when the game ends
User prompt
Limit the distance a character can travel in one move
User prompt
move the winning line under the singer
User prompt
add a second image to the singer, a separate image for the top of the screen, a separate image for when looking at the bottom of the screen
Code edit (1 edits merged)
Please save this source code
User prompt
Green Light, Red Light
Initial prompt
Game Title: Green Light, Red Light (AI Description) This game is a digital adaptation of the classic "Red Light, Green Light" children's game. Core Mechanics: Objective: The player's goal is to reach a designated win line located near the top of the screen, close to the "singer" character. Player Control: The player character moves by touching the screen. However, there's a deliberate 0.25-second delay between the touch input and the character's movement, increasing the game's difficulty. The "Singer" (AI Opponent): A girl character acts as the "singer" and is positioned at the top of the screen, facing away from the player. She sings continuously with her back turned. At random intervals, the singing stops, and she quickly turns around to face the player. If the player character is moving at the exact moment the singer turns around, the player takes damage. If the player character is motionless when the singer turns around, the singer turns back to continue singing, allowing the player to resume movement. Obstacles: Various obstacles are placed on the game path, requiring the player to navigate around them to reach the win line. Winning Condition: The player wins by successfully reaching the win line without being caught moving by the singer. AI Considerations: The "singer" character's behavior is crucial for the game's core challenge. Key aspects for an AI to manage include: Randomized Stop Duration: The time the singer spends with her back turned should be unpredictable, ranging within a defined minimum and maximum to prevent players from easily anticipating her turns. Instantaneous Turnaround: The visual transition from singing to looking back should be immediate to provide a brief window for player reaction. Damage Trigger Logic: The AI needs to accurately detect if the player's input (and thus character movement) is active during the exact frames the singer is facing the player. Win Line Detection: The AI must recognize when the player character has crossed the designated win line.
/**** * Plugins ****/ var tween = LK.import("@upit/tween.v1"); /**** * Classes ****/ var Obstacle = Container.expand(function () { var self = Container.call(this); var obstacleGraphics = self.attachAsset('obstacle', { anchorX: 0.5, anchorY: 0.5 }); self.isFakeOil = false; self.destructionTimer = 0; self.maxDestructionTime = 180; // 3 seconds at 60fps self.isDestroying = false; self.makeFakeOil = function () { self.isFakeOil = true; // Tint fake oil obstacles slightly darker to indicate they're different obstacleGraphics.tint = 0x888888; }; self.startDestruction = function () { if (self.isFakeOil && !self.isDestroying) { self.isDestroying = true; // Animate destruction with scaling and fading tween(obstacleGraphics, { scaleX: 0, scaleY: 0, alpha: 0 }, { duration: 500, easing: tween.easeInOut, onFinish: function onFinish() { self.destroy(); } }); } }; self.update = function () { if (self.isFakeOil && !self.isDestroying) { self.destructionTimer++; if (self.destructionTimer >= self.maxDestructionTime) { self.startDestruction(); } } }; return self; }); var Player = Container.expand(function () { var self = Container.call(this); var playerGraphics = self.attachAsset('player', { anchorX: 0.5, anchorY: 0.5 }); self.targetX = 0; self.targetY = 0; self.isMoving = false; self.health = 3; self.moveTo = function (x, y) { // Calculate distance from current position var dx = x - self.x; var dy = y - self.y; var distance = Math.sqrt(dx * dx + dy * dy); // Limit maximum movement distance to 200 pixels var maxDistance = 200; if (distance > maxDistance) { // Scale down the movement to fit within max distance var scale = maxDistance / distance; x = self.x + dx * scale; y = self.y + dy * scale; } self.targetX = x; self.targetY = y; self.isMoving = true; // Add walking animation - slight scaling and rotation tween(playerGraphics, { scaleX: 0.9, scaleY: 1.1, rotation: 0.1 }, { duration: 150, easing: tween.easeInOut }); tween(self, { x: x, y: y }, { duration: 300, easing: tween.easeOut, onFinish: function onFinish() { self.isMoving = false; // Reset player graphics to normal state after movement tween(playerGraphics, { scaleX: 1, scaleY: 1, rotation: 0 }, { duration: 150, easing: tween.easeOut }); } }); }; self.takeDamage = function () { self.health--; LK.effects.flashObject(self, 0xFF0000, 500); LK.getSound('caught').play(); if (self.health <= 0) { LK.showGameOver(); } }; return self; }); var Singer = Container.expand(function () { var self = Container.call(this); var singerAwayGraphics = self.attachAsset('singerAway', { anchorX: 0.5, anchorY: 0.5 }); var singerLookingGraphics = self.attachAsset('singerLooking', { anchorX: 0.5, anchorY: 0.5 }); singerLookingGraphics.visible = false; // Start with looking image hidden self.facingAway = true; self.turnTimer = 0; self.nextTurnTime = 180; // 3 seconds at 60fps self.lookingTime = 0; self.maxLookingTime = 120; // 2 seconds looking self.update = function () { self.turnTimer++; if (self.facingAway) { // Singer is facing away, count down to turn around if (self.turnTimer >= self.nextTurnTime) { self.turnAround(); } } else { // Singer is looking, count down to face away again self.lookingTime++; if (self.lookingTime >= self.maxLookingTime) { self.faceAway(); } } }; self.turnAround = function () { self.facingAway = false; self.lookingTime = 0; // Switch to looking image singerAwayGraphics.visible = false; singerLookingGraphics.visible = true; LK.getSound('turn').play(); // Start playing looping music when looking up LK.playMusic('singerLookingMusic'); // Check if player is moving and apply damage if (player.isMoving) { player.takeDamage(); } }; self.faceAway = function () { self.facingAway = true; self.turnTimer = 0; self.nextTurnTime = Math.random() * 180 + 120; // Random 2-5 seconds // Switch to away image singerAwayGraphics.visible = true; singerLookingGraphics.visible = false; // Stop music when facing away LK.stopMusic(); // Play 'song' audio file on loop when facing away LK.getSound('song').play(); }; return self; }); /**** * Initialize Game ****/ var game = new LK.Game({ backgroundColor: 0x87CEEB }); /**** * Game Code ****/ // Create win line at top var winLine = game.addChild(LK.getAsset('winLine', { anchorX: 0.5, anchorY: 0.5 })); winLine.x = 2048 / 2; winLine.y = 450; // Create singer at top var singer = game.addChild(new Singer()); singer.x = 2048 / 2; singer.y = 300; // Start playing 'song' audio since singer starts facing away LK.getSound('song').play(); // Create player at bottom var player = game.addChild(new Player()); player.x = 2048 / 2; player.y = 2400; player.targetX = player.x; player.targetY = player.y; // Create obstacles var obstacles = []; // Generate 12 obstacles at random positions for (var i = 0; i < 12; i++) { var obstacle = game.addChild(new Obstacle()); // Random x position between 200 and 1800 (avoiding edges) obstacle.x = Math.random() * 1600 + 200; // Random y position between 600 and 2200 (between singer area and player start) obstacle.y = Math.random() * 1600 + 600; // 30% chance to make obstacle fake oil if (Math.random() < 0.3) { obstacle.makeFakeOil(); } obstacles.push(obstacle); } // Create health display var healthTxt = new Text2('Health: 3', { size: 60, fill: 0xFFFFFF }); healthTxt.anchor.set(0, 0); LK.gui.topRight.addChild(healthTxt); // Game state var pendingMove = null; var moveDelay = 15; // 0.25 seconds at 60fps var delayTimer = 0; // Touch input with delay game.down = function (x, y, obj) { // Only allow movement if not already moving and singer is facing away if (!player.isMoving && singer.facingAway) { pendingMove = { x: x, y: y }; delayTimer = moveDelay; } }; // Track game over state var gameEnded = false; var lastGameEndedState = false; game.update = function () { // Handle delayed movement if (pendingMove && delayTimer > 0) { delayTimer--; if (delayTimer <= 0) { // Check if target position is valid (not inside obstacles) var validMove = true; for (var i = 0; i < obstacles.length; i++) { var obstacle = obstacles[i]; var dx = pendingMove.x - obstacle.x; var dy = pendingMove.y - obstacle.y; var distance = Math.sqrt(dx * dx + dy * dy); if (distance < 100) { // Collision detection validMove = false; break; } } if (validMove) { player.moveTo(pendingMove.x, pendingMove.y); } pendingMove = null; } } // Update health display healthTxt.setText('Health: ' + player.health); // Check for game end state transitions var currentGameEnded = player.health <= 0 || player.y <= winLine.y + 50; if (!lastGameEndedState && currentGameEnded) { // Game just ended, spawn random obstacles for (var j = 0; j < 8; j++) { var newObstacle = game.addChild(new Obstacle()); newObstacle.x = Math.random() * 1800 + 200; // Random x between 200 and 2000 newObstacle.y = Math.random() * 1800 + 600; // Random y between 600 and 2400 obstacles.push(newObstacle); } } lastGameEndedState = currentGameEnded; // Check win condition if (player.y <= winLine.y + 50) { LK.showYouWin(); } // Clean up destroyed fake oil obstacles for (var k = obstacles.length - 1; k >= 0; k--) { var obstacle = obstacles[k]; if (obstacle.isFakeOil && obstacle.isDestroying && obstacle.alpha <= 0) { obstacles.splice(k, 1); } } // Check if player is caught moving when singer turns if (!singer.facingAway && player.isMoving) { // This is handled in the singer's turnAround method // but we also check continuously in case of timing issues if (LK.ticks % 30 === 0) { // Check every half second player.takeDamage(); } } };
===================================================================
--- original.js
+++ change.js
@@ -11,8 +11,42 @@
var obstacleGraphics = self.attachAsset('obstacle', {
anchorX: 0.5,
anchorY: 0.5
});
+ self.isFakeOil = false;
+ self.destructionTimer = 0;
+ self.maxDestructionTime = 180; // 3 seconds at 60fps
+ self.isDestroying = false;
+ self.makeFakeOil = function () {
+ self.isFakeOil = true;
+ // Tint fake oil obstacles slightly darker to indicate they're different
+ obstacleGraphics.tint = 0x888888;
+ };
+ self.startDestruction = function () {
+ if (self.isFakeOil && !self.isDestroying) {
+ self.isDestroying = true;
+ // Animate destruction with scaling and fading
+ tween(obstacleGraphics, {
+ scaleX: 0,
+ scaleY: 0,
+ alpha: 0
+ }, {
+ duration: 500,
+ easing: tween.easeInOut,
+ onFinish: function onFinish() {
+ self.destroy();
+ }
+ });
+ }
+ };
+ self.update = function () {
+ if (self.isFakeOil && !self.isDestroying) {
+ self.destructionTimer++;
+ if (self.destructionTimer >= self.maxDestructionTime) {
+ self.startDestruction();
+ }
+ }
+ };
return self;
});
var Player = Container.expand(function () {
var self = Container.call(this);
@@ -176,8 +210,12 @@
// Random x position between 200 and 1800 (avoiding edges)
obstacle.x = Math.random() * 1600 + 200;
// Random y position between 600 and 2200 (between singer area and player start)
obstacle.y = Math.random() * 1600 + 600;
+ // 30% chance to make obstacle fake oil
+ if (Math.random() < 0.3) {
+ obstacle.makeFakeOil();
+ }
obstacles.push(obstacle);
}
// Create health display
var healthTxt = new Text2('Health: 3', {
@@ -245,8 +283,15 @@
// Check win condition
if (player.y <= winLine.y + 50) {
LK.showYouWin();
}
+ // Clean up destroyed fake oil obstacles
+ for (var k = obstacles.length - 1; k >= 0; k--) {
+ var obstacle = obstacles[k];
+ if (obstacle.isFakeOil && obstacle.isDestroying && obstacle.alpha <= 0) {
+ obstacles.splice(k, 1);
+ }
+ }
// Check if player is caught moving when singer turns
if (!singer.facingAway && player.isMoving) {
// This is handled in the singer's turnAround method
// but we also check continuously in case of timing issues
evil little girl looking down. In-Game asset. 2d. High contrast. No shadows
downward looking devil little girl turned back
Cat with 456 written on its back. In-Game asset. 2d. High contrast. No shadows
fence. In-Game asset
hedgerow. In-Game asset
tree. In-Game asset
mud and stone. In-Game asset
mud and stone front view. In-Game asset
mold fungus. In-Game asset
robot monkey. In-Game asset
outgoing gas infrastructure system. In-Game asset
outgoing gasoline infrastructure system. In-Game asset