User prompt
Move the hearts up by 400 pixels.
User prompt
the player final explosion should use its own sprite.
User prompt
When the player loses their last life replace them with a new explosion sprite that grows in size and gets transparent over 1.5 seconds. After the 1.5 seconds show the game over screen. Stop the scrolling during this time. āŖš” Consider importing and using the following plugins: @upit/tween.v1
Code edit (1 edits merged)
Please save this source code
User prompt
Add a sound that triggers when the bomb is ready
User prompt
Use a different sound for when an enemy is hit than the player
User prompt
Add randomness to missile spawn positions with a range between player max jump height and lower limit
User prompt
Remove the missile rotation
User prompt
Make the missiles spawn at least 200 pixels higher
User prompt
make the player bomb and the missile use different sprites
User prompt
When the player hits 1500 points have missiles start launching from the right side of the screen. They should spawn at least 300 pixels above the player's character but no higher than their maximum jump height. The missiles should have a warning indicator appear at the right edge of the screen at the y position that the missile is about to launch from. After 1 second the indicator goes away and the missile launches. The missile should travel from right to left at 1.5x the scroll speed
User prompt
Please fix the bug: 'TypeError: Cannot set properties of undefined (setting 'fill')' in or related to this line: 'self.bombReadyText.style.fill = 0xFF0000;' Line Number: 347
User prompt
For the bomb, make an indicator at the bottom of the screen to show the bomb is ready. After a bomb is launched it should take 4 seconds to reload.
User prompt
When an enemy is destroyed play a sound effect
User prompt
When the enemy is hit by a bomb use that same explosion.
User prompt
The explosion that spawns when the enemy is hit should be a different image than the other explosion and it should scroll at the same rate as the background
User prompt
If the player hits the enemy destroy the enemy and spawn an explosion graphic for 1 second where they were āŖš” Consider importing and using the following plugins: @upit/tween.v1
User prompt
If the player hits the jump button again mid-jump it should drop a bomb that falls to the ground and explodes. If it hits and enemy it destroys the enemy for 500 points. The player can only launch one bomb while in the air, it resets when they hit the ground.
User prompt
Add a sound for when the player loses a life
User prompt
Don't spawn any enemies for 5 seconds at the start of the game
User prompt
Take the hearts and make them bigger and have them fixed in the middle of the screen near the bottom
User prompt
Play a sound when the player jumps
User prompt
Add a variable for floor level (Y position) and have the enemies and the player both spawn at that point
User prompt
The enemies should have their own sprite
User prompt
Add an enemy that moves at the same speed as the background scroll and spawns on the right edge of the screen at the same y coordinate as the player. When it hits the player take away one heart. If it hits the left edge of the screen add 100 to the player score.
/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
/****
* Classes
****/
// Define a class for scrolling backgrounds
var Background = Container.expand(function () {
var self = Container.call(this);
self.speed = 3;
self.asset = null;
self.init = function (assetName, startX) {
self.asset = self.attachAsset(assetName, {
anchorX: 0,
anchorY: 0
});
self.x = startX;
self.y = 0;
};
self.update = function () {
self.x -= gameSpeed;
// If background has moved completely off screen to the left, reposition it to the right
if (self.x <= -1366) {
self.x = 1366 * 2;
}
};
return self;
});
// Define a class for bombs dropped by player
var Bomb = Container.expand(function () {
var self = Container.call(this);
// Create bomb graphic
var bombGraphics = self.attachAsset('bomb', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 1.2,
scaleY: 1.2
});
// Track last position and explosion state
self.lastY = 0;
self.hasExploded = false;
self.velocityY = 10;
// Update bomb position and check for ground collision
self.update = function () {
// Store last position before updating
self.lastY = self.y;
// Apply gravity
self.velocityY += 0.8;
self.y += self.velocityY;
// Check if bomb hits the ground
if (self.lastY < floorLevel && self.y >= floorLevel) {
self.explode();
}
};
// Handle explosion effect and enemy destruction
self.explode = function () {
if (self.hasExploded) {
return;
}
self.hasExploded = true;
// Play explosion sound
LK.getSound('explosion').play();
// Create explosion graphic
var explosion = LK.getAsset('explosion', {
anchorX: 0.5,
anchorY: 0.5,
alpha: 0.8
});
explosion.x = self.x;
explosion.y = floorLevel;
game.addChild(explosion);
// Check for enemies in explosion radius
var enemyHit = false;
var children = game.children.slice();
for (var i = 0; i < children.length; i++) {
if (children[i] instanceof Enemy) {
var enemy = children[i];
// Simple distance check for explosion radius
var dx = enemy.x - self.x;
var dy = enemy.y - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance < 150) {
// Explosion radius
// Create player hit explosion at enemy's position using playerHitExplosion asset
var enemyExplosion = new Container();
var enemyExplosionGraphic = enemyExplosion.attachAsset('playerHitExplosion', {
anchorX: 0.5,
anchorY: 0.5,
alpha: 0.9,
scaleX: 0.1,
scaleY: 0.1
});
enemyExplosion.x = enemy.x;
enemyExplosion.y = enemy.y;
enemyExplosion.scrollSpeed = gameSpeed; // Store the current game speed
enemyExplosion.update = function () {
// Make explosion scroll with background
enemyExplosion.x -= enemyExplosion.scrollSpeed;
};
game.addChild(enemyExplosion);
// Animate explosion growing and fading out
tween(enemyExplosionGraphic, {
alpha: 0,
scaleX: 1.5,
scaleY: 1.5
}, {
duration: 1000,
onFinish: function onFinish() {
game.removeChild(enemyExplosion);
}
});
// Remove enemy
game.removeChild(enemy);
enemyHit = true;
// Play enemy hit sound when enemy is destroyed
LK.getSound('enemyHit').play();
// Add 500 points for destroying enemy with bomb
LK.setScore(LK.getScore() + 500);
scoreText.setText('Score: ' + LK.getScore());
}
}
}
// Remove bomb
game.removeChild(self);
// Fade out and remove explosion after 500ms
tween(explosion, {
alpha: 0,
scaleX: 2,
scaleY: 2
}, {
duration: 500,
onFinish: function onFinish() {
game.removeChild(explosion);
}
});
};
return self;
});
// Define a class for enemies
var Enemy = Container.expand(function () {
var self = Container.call(this);
// Create enemy using proper enemy sprite
var enemyGraphics = self.attachAsset('enemy', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.5,
scaleY: 0.5
});
// Track last position and collision state
self.lastX = 0;
self.lastCollided = false;
self.update = function () {
// Store last position before updating
self.lastX = self.x;
// Move at the same speed as background
self.x -= gameSpeed;
// Check if enemy hits left edge of screen
if (self.lastX > 0 && self.x <= 0) {
// Add 100 to score
LK.setScore(LK.getScore() + 100);
scoreText.setText('Score: ' + LK.getScore());
// Remove this enemy
self.parent.removeChild(self);
}
// Check collision with player if not previously collided
if (!self.lastCollided && self.intersects(player)) {
// Set collision flag to prevent multiple hits
self.lastCollided = true;
// Create player hit explosion at enemy's position using different asset
var explosion = new Container();
var explosionGraphic = explosion.attachAsset('playerHitExplosion', {
anchorX: 0.5,
anchorY: 0.5,
alpha: 0.9,
scaleX: 0.1,
scaleY: 0.1
});
explosion.x = self.x;
explosion.y = self.y;
explosion.scrollSpeed = gameSpeed; // Store the current game speed
explosion.update = function () {
// Make explosion scroll with background
explosion.x -= explosion.scrollSpeed;
};
game.addChild(explosion);
// Play explosion sound when player is hit
LK.getSound('explosion').play();
// Animate explosion growing and fading out
tween(explosionGraphic, {
alpha: 0,
scaleX: 1.5,
scaleY: 1.5
}, {
duration: 1000,
onFinish: function onFinish() {
game.removeChild(explosion);
}
});
// Remove enemy from game
self.parent.removeChild(self);
// Reduce player lives
if (player.lives > 0) {
player.lives--;
// Play sound when life is lost
LK.getSound('lifeLost').play();
// Update heart display
if (player.hearts.length > 0 && player.hearts[player.lives]) {
game.removeChild(player.hearts[player.lives]);
player.hearts.splice(player.lives, 1);
}
// Flash player to indicate damage
LK.effects.flashObject(player, 0xFF0000, 500);
// Game over if no lives left
if (player.lives <= 0) {
// Hide player
player.visible = false;
// Create explosion where player was
var finalExplosion = new Container();
var finalExplosionGraphic = finalExplosion.attachAsset('playerExplosion', {
anchorX: 0.5,
anchorY: 0.5,
alpha: 1.0,
scaleX: 1.0,
scaleY: 1.0
});
finalExplosion.x = player.x;
finalExplosion.y = player.y;
game.addChild(finalExplosion);
// Stop game scrolling
gameSpeed = 0;
// Animate explosion growing and fading out over 1.5 seconds
tween(finalExplosionGraphic, {
alpha: 0,
scaleX: 3.0,
scaleY: 3.0
}, {
duration: 1500,
onFinish: function onFinish() {
game.removeChild(finalExplosion);
LK.showGameOver();
}
});
}
}
}
};
return self;
});
// Define a class for missiles that launch at player
var Missile = Container.expand(function () {
var self = Container.call(this);
// Create missile graphic using dedicated missile asset
var missileGraphics = self.attachAsset('missile', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 1.5,
scaleY: 1.2
});
// Track missile properties
self.warningTime = 60; // 1 second warning at 60fps
self.isWarning = true; // Start in warning state
self.scrollSpeed = 0; // Will be set when missile is created
// Create warning indicator
self.warningIndicator = new Container();
var warningGraphic = self.warningIndicator.attachAsset('missile', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 1.2,
scaleY: 1.0,
tint: 0xFF0000 // Red color for warning
});
// Add warning text
self.warningText = new Text2('!', {
size: 60,
fill: 0xFFFFFF,
stroke: 0x000000,
strokeThickness: 3
});
self.warningText.anchor.set(0.5, 0.5);
self.warningIndicator.addChild(self.warningText);
// Update method for missile behavior
self.update = function () {
if (self.isWarning) {
// During warning phase, just count down
self.warningTime--;
// Make warning indicator blink
self.warningIndicator.alpha = Math.floor(self.warningTime / 10) % 2 === 0 ? 1.0 : 0.3;
// When warning time ends, start moving missile
if (self.warningTime <= 0) {
self.isWarning = false;
game.removeChild(self.warningIndicator);
}
} else {
// Move missile from right to left at 1.5x scroll speed
self.x -= self.scrollSpeed;
// Check if missile is off screen
if (self.x < -50) {
if (self.parent) {
self.parent.removeChild(self);
}
return;
}
// Check for collision with player
if (self.intersects(player) && player.lives > 0) {
// Create explosion
var explosion = new Container();
var explosionGraphic = explosion.attachAsset('playerHitExplosion', {
anchorX: 0.5,
anchorY: 0.5,
alpha: 0.9,
scaleX: 0.1,
scaleY: 0.1
});
explosion.x = self.x;
explosion.y = self.y;
explosion.scrollSpeed = gameSpeed;
explosion.update = function () {
explosion.x -= explosion.scrollSpeed;
};
game.addChild(explosion);
// Play explosion sound when player is hit by missile
LK.getSound('explosion').play();
// Animate explosion
tween(explosionGraphic, {
alpha: 0,
scaleX: 1.5,
scaleY: 1.5
}, {
duration: 1000,
onFinish: function onFinish() {
game.removeChild(explosion);
}
});
// Reduce player lives
player.lives--;
// Play sound when life is lost
LK.getSound('lifeLost').play();
// Update heart display
if (player.hearts.length > 0 && player.hearts[player.lives]) {
game.removeChild(player.hearts[player.lives]);
player.hearts.splice(player.lives, 1);
}
// Flash player to indicate damage
LK.effects.flashObject(player, 0xFF0000, 500);
// Game over if no lives left
if (player.lives <= 0) {
// Hide player
player.visible = false;
// Create explosion where player was
var finalExplosion = new Container();
var finalExplosionGraphic = finalExplosion.attachAsset('playerExplosion', {
anchorX: 0.5,
anchorY: 0.5,
alpha: 1.0,
scaleX: 1.0,
scaleY: 1.0
});
finalExplosion.x = player.x;
finalExplosion.y = player.y;
game.addChild(finalExplosion);
// Stop game scrolling
gameSpeed = 0;
// Animate explosion growing and fading out over 1.5 seconds
tween(finalExplosionGraphic, {
alpha: 0,
scaleX: 3.0,
scaleY: 3.0
}, {
duration: 1500,
onFinish: function onFinish() {
game.removeChild(finalExplosion);
LK.showGameOver();
}
});
}
// Remove missile
if (self.parent) {
self.parent.removeChild(self);
}
}
}
};
// Initialize missile with warning at the specified position
self.init = function (yPosition) {
// Position missile at right edge of screen
self.x = 2048;
self.y = yPosition;
// Set missile speed to 1.5x the current game speed
self.scrollSpeed = gameSpeed * 1.5;
// Position warning indicator at the right edge
self.warningIndicator.x = 2048;
self.warningIndicator.y = yPosition;
// Add warning indicator to game
game.addChild(self.warningIndicator);
};
return self;
});
//<Assets used in the game will automatically appear here>
// Define a class for the player character
var Player = Container.expand(function () {
var self = Container.call(this);
var playerGraphics = self.attachAsset('player', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 1.5,
scaleY: 1.5
});
self.speed = 5;
self.jumpHeight = 40;
self.isJumping = false;
self.velocityY = 0;
self.lives = 3; // Initialize player with 3 lives
self.hearts = []; // Array to store heart icons
self.canDropBomb = true; // Track if player can drop a bomb
self.activeBomb = null; // Reference to current active bomb
self.bombCooldown = 0; // Track cooldown time for bomb reload
self.bombReloadTime = 240; // 4 seconds at 60fps
self.createHearts = function () {
// Create three hearts in the middle of the screen near the bottom
for (var i = 0; i < self.lives; i++) {
var heart = new Container();
// Create a red heart shape using heart shape
var heartShape = heart.attachAsset('heart', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.8,
scaleY: 0.8,
tint: 0xFF0000 // Red color for hearts
});
// Calculate position in the middle of the screen
heart.x = 2048 / 2 + (i - 1) * 150; // Center horizontally with wider spacing
heart.y = 2732 - 600; // Position 400 pixels higher than before
// Remove heart from player and add to game so it stays fixed
self.hearts.push(heart);
game.addChild(heart);
}
};
// Initialize hearts when player is created
self.createHearts();
// Create bomb indicator
self.bombIndicator = new Container();
var bombGraphic = self.bombIndicator.attachAsset('bomb', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 1.2,
scaleY: 1.2
});
// Add cooldown overlay (starts invisible)
self.cooldownOverlay = LK.getAsset('bomb', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 1.2,
scaleY: 1.2,
tint: 0x666666,
alpha: 0.7
});
self.cooldownOverlay.y = 0;
self.cooldownOverlay.height = 0; // Start with no overlay
self.bombIndicator.addChild(self.cooldownOverlay);
// Add text to show reload progress
self.bombReadyText = new Text2('READY', {
size: 40,
fill: 0x00FF00,
stroke: 0x000000,
strokeThickness: 4
});
// Initialize style explicitly to avoid "Cannot set properties of undefined" error
self.bombReadyText.style = {
fill: 0x00FF00
};
self.bombReadyText.anchor.set(0.5, 0);
self.bombReadyText.y = 40;
self.bombIndicator.addChild(self.bombReadyText);
// Position bomb indicator at bottom of screen
self.bombIndicator.x = 2048 / 2;
self.bombIndicator.y = 2732 - 100;
game.addChild(self.bombIndicator);
self.update = function () {
if (self.isJumping) {
self.y += self.velocityY;
self.velocityY += 0.7; // Decreased gravity effect by 30%
if (self.y >= floorLevel) {
// Return to floor level
self.y = floorLevel;
self.isJumping = false;
self.velocityY = 0;
self.activeBomb = null; // Clear reference to active bomb
}
}
// Handle bomb cooldown
if (self.bombCooldown > 0) {
self.bombCooldown--;
// Update cooldown overlay height based on remaining cooldown
var progress = self.bombCooldown / self.bombReloadTime;
self.cooldownOverlay.height = bombGraphic.height * progress;
self.cooldownOverlay.y = -(bombGraphic.height / 2) + self.cooldownOverlay.height / 2;
// Update text to show progress
if (self.bombCooldown <= 0) {
self.canDropBomb = true;
self.bombReadyText.setText('READY');
self.bombReadyText.style.fill = 0x00FF00;
self.cooldownOverlay.height = 0;
// Play bomb ready sound when bomb becomes available
LK.getSound('bombReady').play();
} else {
var secondsLeft = Math.ceil(self.bombCooldown / 60);
self.bombReadyText.setText(secondsLeft + 's');
self.bombReadyText.style.fill = 0xFF0000;
}
}
};
self.jump = function () {
if (!self.isJumping) {
self.isJumping = true;
self.velocityY = -self.jumpHeight;
// Play jump sound when player jumps
LK.getSound('jump').play();
} else if (self.canDropBomb) {
// Drop a bomb if in mid-air and haven't dropped one yet
self.canDropBomb = false;
self.bombCooldown = self.bombReloadTime; // Start cooldown timer (4 seconds)
// Create new bomb
var bomb = new Bomb();
bomb.x = self.x;
bomb.y = self.y + 50; // Position slightly below player
bomb.lastY = bomb.y;
// Add bomb to game
game.addChild(bomb);
self.activeBomb = bomb;
}
};
});
// Define a class for street backgrounds (bottom part)
var StreetBackground = Container.expand(function () {
var self = Container.call(this);
self.speed = 3;
self.asset = null;
self.init = function (assetName, startX) {
self.asset = self.attachAsset(assetName, {
anchorX: 0,
anchorY: 0,
scaleY: 0.5 // Make the background half height
});
self.x = startX;
self.y = 2732 * 0.5; // Position in the bottom half of the screen
};
self.update = function () {
self.x -= gameSpeed;
// If background has moved completely off screen to the left, reposition it to the right
if (self.x <= -2048) {
self.x = 2048 * 2 - gameSpeed;
}
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x1A0933 // Dark purple background
});
/****
* Game Code
****/
// Game speed control variable
var gameSpeed = 5;
// Floor level variable (Y position for player and enemies)
var floorLevel = 2732 * 0.55 + 400; // 55% of screen height + 400px down
// Track enemies
var enemies = [];
// Create three scrolling backgrounds for the top part
var backgrounds = [];
// Create three scrolling backgrounds for the bottom part (street)
var streetBackgrounds = [];
// Create each background and position them
for (var i = 0; i < 3; i++) {
var bg = new Background();
bg.init('background' + (i + 1), i * 1366);
backgrounds.push(bg);
game.addChild(bg);
// Create street backgrounds using different assets
var streetBg = new StreetBackground();
streetBg.init('street' + (i + 1), i * 2048);
streetBackgrounds.push(streetBg);
game.addChild(streetBg);
}
// Initialize player
var player = game.addChild(new Player());
player.x = 2048 / 2 - 500; // Move player back 500 pixels
player.y = floorLevel; // Position player at the floor level
// Create a new Text2 object to display the score with cyberpunk styling
var scoreText = new Text2('Score: 0', {
size: 80,
fill: 0x00FFFF,
// Cyan color for cyberpunk neon effect
stroke: 0xFF00FF,
// Magenta stroke for contrast
strokeThickness: 5,
// Thick stroke for glow effect
dropShadow: true,
dropShadowColor: 0x00FFFF,
// Cyan shadow
dropShadowBlur: 10,
dropShadowAngle: Math.PI / 4,
dropShadowDistance: 6,
letterSpacing: 3 // Spacing between letters for futuristic look
});
// Add the score text to the game GUI at the top right of the screen
LK.gui.topRight.addChild(scoreText);
// Anchor the text to the right side
scoreText.anchor.set(1, 0);
// Add padding from the right edge
scoreText.x = -20;
scoreText.y = 20;
// Create a pulsating glow effect for the cyberpunk score display
function pulseScoreText() {
tween(scoreText, {
strokeThickness: 8,
dropShadowBlur: 15
}, {
duration: 800,
onFinish: function onFinish() {
tween(scoreText, {
strokeThickness: 5,
dropShadowBlur: 10
}, {
duration: 800,
onFinish: pulseScoreText
});
}
});
}
pulseScoreText();
// Handle game updates
game.update = function () {
// Increase game speed as score increases for difficulty progression
gameSpeed = 5 + Math.min(LK.getScore() / 10, 5); // Cap at max 10 speed
// Update scrolling backgrounds
for (var i = 0; i < backgrounds.length; i++) {
backgrounds[i].update();
}
// Update street backgrounds
for (var i = 0; i < streetBackgrounds.length; i++) {
streetBackgrounds[i].update();
}
player.update();
// Spawn enemies (wait 5 seconds at the start - 300 frames at 60fps)
if (LK.ticks > 300 && LK.ticks % 180 === 0) {
// Spawn enemy every 3 seconds (180 frames at 60fps)
var enemy = new Enemy();
enemy.x = 2048; // Start at right edge of screen
enemy.y = floorLevel; // Position at floor level
enemy.lastX = enemy.x; // Initialize lastX
game.addChild(enemy);
}
// Spawn missiles when player score reaches 1500
if (LK.getScore() >= 1500 && LK.ticks % 120 === 0) {
// Every 2 seconds (120 frames)
// Calculate a y-position for the missile
// Should be at least 500px above player but no higher than max jump height
var playerMaxHeight = floorLevel - player.jumpHeight * 6; // Approximate max jump height
var minMissileHeight = floorLevel - 2800; // At least 500px above player (increased from 300px)
var maxMissileHeight = floorLevel - 800; // Don't go too high
// Calculate the valid range for missile spawn positions
var validRangeMin = Math.max(maxMissileHeight, minMissileHeight);
var validRangeMax = floorLevel - 50;
// Generate a random position within this range
var missileY = validRangeMin + Math.random() * (validRangeMax - validRangeMin);
// Ensure missile is within screen bounds
missileY = Math.max(100, Math.min(missileY, floorLevel - 50));
// Create missile with warning
var missile = new Missile();
missile.init(missileY);
game.addChild(missile);
}
// Update all enemies and bombs
var children = game.children.slice();
for (var i = 0; i < children.length; i++) {
if (children[i] instanceof Enemy) {
children[i].update();
} else if (children[i] instanceof Bomb) {
children[i].update();
} else if (children[i] instanceof Missile) {
children[i].update();
} else if (children[i].update && children[i].scrollSpeed !== undefined) {
// Update any container with scrollSpeed (like our player hit explosions)
children[i].update();
}
}
// Update score display
scoreText.setText('Score: ' + LK.getScore());
};
// Handle player jump
game.down = function (x, y, obj) {
player.jump();
}; ===================================================================
--- original.js
+++ change.js
@@ -430,9 +430,9 @@
tint: 0xFF0000 // Red color for hearts
});
// Calculate position in the middle of the screen
heart.x = 2048 / 2 + (i - 1) * 150; // Center horizontally with wider spacing
- heart.y = 2732 - 200; // Position near the bottom of the screen
+ heart.y = 2732 - 600; // Position 400 pixels higher than before
// Remove heart from player and add to game so it stays fixed
self.hearts.push(heart);
game.addChild(heart);
}
cyberpunk pixel art asphalt street. In-Game asset. 2d. High contrast. No shadows, street debris
cyberpunk pixel art asphalt street. In-Game asset. 2d. High contrast. No shadows, street debris
digital explosion, burnt orange neon blue, pixels, sparks. In-Game asset. 2d. High contrast. No shadows
digital explosion. squares. pixels. chaos. neon. sparks. In-Game asset. 2d. High contrast. No shadows
Make it pixel art style
Make it pixel art style
Make this pixel art style
Make this pixel art style and give it a bit of a tail on the top as if it is flying downwards.
Make this look like pixel art
Neon pink heart. Pixel art style. Slight neon blue outer glow. In-Game asset. 2d. High contrast. No shadows
Pixel font in yellow that says "Tap to Jump". In-Game asset. 2d. High contrast. No shadows
Pixel font in yellow that says "Tap Again to Attack". In-Game asset. 2d. High contrast. No shadows