Code edit (1 edits merged)
Please save this source code
User prompt
Monster Mayhem: Punch or Perish
Initial prompt
Make a game about monsters in the middle of the screen getting bigger and you have to punch them to death before they cover the screen. Make it very very very very very bloody. If they cover the screen add a jumpscare
/**** * Plugins ****/ var tween = LK.import("@upit/tween.v1"); var storage = LK.import("@upit/storage.v1", { highScore: 0 }); /**** * Classes ****/ var BloodParticle = Container.expand(function () { var self = Container.call(this); var bloodGraphics = self.attachAsset('blood', { anchorX: 0.5, anchorY: 0.5, scaleX: 0.2 + Math.random() * 0.6, scaleY: 0.2 + Math.random() * 0.6, alpha: 0.7 + Math.random() * 0.3 }); // Random velocity self.vx = (Math.random() - 0.5) * 40; self.vy = (Math.random() - 0.5) * 40; self.lifetime = 1000 + Math.random() * 2000; self.createdAt = Date.now(); self.update = function () { self.x += self.vx; self.y += self.vy; // Slow down self.vx *= 0.95; self.vy *= 0.95; // Fade out based on lifetime var age = Date.now() - self.createdAt; if (age > self.lifetime) { self.destroy(); var index = bloodParticles.indexOf(self); if (index !== -1) { bloodParticles.splice(index, 1); } } else if (age > self.lifetime * 0.7) { bloodGraphics.alpha = 1 - (age - self.lifetime * 0.7) / (self.lifetime * 0.3); } }; return self; }); var Monster = Container.expand(function () { var self = Container.call(this); var monsterGraphics = self.attachAsset('monster', { anchorX: 0.5, anchorY: 0.5, scaleX: 0.5, scaleY: 0.5 }); self.health = 5; self.growthRate = 0.004; self.maxScale = 5; self.isDying = false; self.baseScale = 0.5; // Apply a random tint to make monsters look different var tints = [0x4A2B0F, 0x7E3500, 0x5D4037, 0x330000, 0x2D0C01]; monsterGraphics.tint = tints[Math.floor(Math.random() * tints.length)]; self.update = function () { if (self.isDying) { return; } // Grow the monster if (monsterGraphics.scale.x < self.maxScale) { monsterGraphics.scale.x += self.growthRate; monsterGraphics.scale.y += self.growthRate; } else { // Monster has grown too big - game over! gameOver(); } }; self.punch = function () { if (self.isDying) { return; } self.health--; // Temporarily shrink the monster when punched var currentScale = monsterGraphics.scale.x; tween(monsterGraphics.scale, { x: currentScale * 0.8, y: currentScale * 0.8 }, { duration: 100, easing: tween.easeOut, onFinish: function onFinish() { if (!self.isDying) { tween(monsterGraphics.scale, { x: currentScale, y: currentScale }, { duration: 300, easing: tween.easeOut }); } } }); // Flash red tween(monsterGraphics, { tint: 0xFF0000 }, { duration: 100, onFinish: function onFinish() { if (!self.isDying) { tween(monsterGraphics, { tint: monsterGraphics.tint }, { duration: 200 }); } } }); // Add blood spray createBloodSpray(self.x, self.y, 8); // Play punch sound LK.getSound('punch').play(); // Check if monster is dead if (self.health <= 0) { self.die(); } }; self.die = function () { self.isDying = true; LK.getSound('monsterDeath').play(); // Create a big blood explosion createBloodSpray(self.x, self.y, 20); // Shrink and fade out tween(monsterGraphics.scale, { x: 0.1, y: 0.1 }, { duration: 500, easing: tween.easeIn }); tween(monsterGraphics, { alpha: 0 }, { duration: 500, easing: tween.easeIn, onFinish: function onFinish() { self.destroy(); monstersKilled++; updateScore(); // Spawn next monster after delay if (monsterSpawnTimeout) { LK.clearTimeout(monsterSpawnTimeout); } monsterSpawnTimeout = LK.setTimeout(spawnMonster, 1000); } }); }; self.down = function (x, y, obj) { self.punch(); }; return self; }); /**** * Initialize Game ****/ var game = new LK.Game({ backgroundColor: 0xD3D3D3 }); /**** * Game Code ****/ /* Supported Types: 1. Shape: - Simple geometric figures with these properties: * width: (required) pixel width of the shape. * height: (required) pixel height of the shape. * color: (required) color of the shape. * shape: (required) type of shape. Valid options: 'box', 'ellipse'. 2. Image: - Imported images with these properties: * width: (required) pixel resolution width. * height: (required) pixel resolution height. * id: (required) identifier for the image. * flipX: (optional) horizontal flip. Valid values: 0 (no flip), 1 (flip). * flipY: (optional) vertical flip. Valid values: 0 (no flip), 1 (flip). * orientation: (optional) rotation in multiples of 90 degrees, clockwise. Valid values: - 0: No rotation. - 1: Rotate 90 degrees. - 2: Rotate 180 degrees. - 3: Rotate 270 degrees. Note: Width and height remain unchanged upon flipping. 3. Sound: - Sound effects with these properties: * id: (required) identifier for the sound. * volume: (optional) custom volume. Valid values are a float from 0 to 1. 4. Music: - In contract to sound effects, only one music can be played at a time - Music is using the same API to initilize just like sound. - Music loops by default - Music with these config options: * id: (required) identifier for the sound. * volume: (optional) custom volume. Valid values are a float from 0 to 1. * start: (optional) a float from 0 to 1 used for cropping and indicates the start of the cropping * end: (optional) a float from 0 to 1 used for cropping and indicates the end of the cropping */ // Game variables //{0.1} var monster = null; var bloodParticles = []; var monstersKilled = 0; var monsterSpawnTimeout = null; var difficultyLevel = 1; var isGameActive = true; var lastMonsterKillTime = 0; // UI elements var scoreTxt = new Text2('0', { size: 100, fill: 0xFF0000 }); var highScoreTxt = new Text2('Best: 0', { size: 60, fill: 0xFFFFFF }); var waveTxt = new Text2('Wave: 1', { size: 60, fill: 0xFFFFFF }); function initializeGame() { // Set up background var backgroundSprite = LK.getAsset('background', { anchorX: 0.5, anchorY: 0.5, x: 2048 / 2, y: 2732 / 2, alpha: 1.0 // Ensure maximum brightness by setting alpha to maximum }); game.addChild(backgroundSprite); // Set up score display scoreTxt.anchor.set(0.5, 0); scoreTxt.y = 50; LK.gui.top.addChild(scoreTxt); // Set up high score display highScoreTxt.anchor.set(0.5, 0); highScoreTxt.y = 150; LK.gui.top.addChild(highScoreTxt); updateHighScore(); // Set up wave display waveTxt.anchor.set(0.5, 0); waveTxt.y = 220; LK.gui.top.addChild(waveTxt); // Start background music LK.playMusic('bgMusic', { fade: { start: 0, end: 0.3, duration: 1000 } }); // Spawn the first monster spawnMonster(); } function spawnMonster() { if (!isGameActive) { return; } // Create new monster monster = new Monster(); monster.x = 2048 / 2; monster.y = 2732 / 2; // Increase difficulty based on monsters killed if (monstersKilled > 0) { // Every 3 monsters, increase difficulty level if (monstersKilled % 3 === 0) { difficultyLevel++; waveTxt.setText('Wave: ' + difficultyLevel); LK.effects.flashScreen(0x330000, 500); } // Adjust monster properties based on difficulty monster.health = 5 + Math.min(5, difficultyLevel); monster.growthRate = 0.008 + difficultyLevel * 0.001; monster.baseScale = 0.5 + difficultyLevel * 0.03; monster.speed = 1 + difficultyLevel * 0.1; // Increase speed based on difficulty // Update monster's initial appearance var monsterGraphics = LK.getAsset('jumpscare', { anchorX: 0.5, anchorY: 0.5 }); monster.addChild(monsterGraphics); monsterGraphics.scale.x = monster.baseScale; monsterGraphics.scale.y = monster.baseScale; } // Add monster to game game.addChild(monster); LK.getSound('monsterGrowl').play(); } function createBloodSpray(x, y, count) { for (var i = 0; i < count; i++) { var blood = new BloodParticle(); blood.x = x; blood.y = y; bloodParticles.push(blood); game.addChild(blood); } } function updateScore() { scoreTxt.setText(monstersKilled.toString()); // Check if high score needs updating if (monstersKilled > storage.highScore) { storage.highScore = monstersKilled; updateHighScore(); } lastMonsterKillTime = Date.now(); } function updateHighScore() { highScoreTxt.setText('Best: ' + storage.highScore); } function gameOver() { if (!isGameActive) { return; } isGameActive = false; // Play a loud and distorted grainy scream sound LK.getSound('jumpscare').play(); // Fade music out LK.playMusic('bgMusic', { fade: { start: 0.3, end: 0, duration: 500 } }); // Flash screen red LK.effects.flashScreen(0xFF0000, 800); // Show jumpscare sprite before game over screen var jumpscareSprite = LK.getAsset('jumpscare', { anchorX: 0.5, anchorY: 0.5, x: 2048 / 2, y: 2732 / 2, alpha: 1.0, tint: 0xFF0000 // Tint the sprite red }); game.addChild(jumpscareSprite); // Make the jumpscare sprite shake continuously and violently function shakeSprite(sprite) { tween(sprite, { x: sprite.x + 40 }, { duration: 15, easing: tween.easeInOut, onFinish: function onFinish() { tween(sprite, { x: sprite.x - 80 }, { duration: 15, easing: tween.easeInOut, onFinish: function onFinish() { tween(sprite, { x: sprite.x + 40 }, { duration: 15, easing: tween.easeInOut, onFinish: function onFinish() { shakeSprite(sprite); // Recursively call to continue shaking } }); } }); } }); } shakeSprite(jumpscareSprite); LK.setTimeout(function () { jumpscareSprite.destroy(); LK.showGameOver(); }, 800); } // Initialize game on startup initializeGame(); // Event handling game.down = function (x, y, obj) { // This handles general taps on game area (not on specific monsters) // Not needed for now as monsters have their own down handler }; // Game update loop game.update = function () { // Update all blood particles for (var i = bloodParticles.length - 1; i >= 0; i--) { // BloodParticle.update() handles its own removal from the array if needed // We don't need to do anything here } // Check if we should increase difficulty over time // If a monster hasn't been killed in a while, make it grow faster if (monster && lastMonsterKillTime > 0) { var timeSinceLastKill = Date.now() - lastMonsterKillTime; if (timeSinceLastKill > 5000) { // Gradually increase growth rate if player is taking too long monster.growthRate *= 1.002; } } };
/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
var storage = LK.import("@upit/storage.v1", {
highScore: 0
});
/****
* Classes
****/
var BloodParticle = Container.expand(function () {
var self = Container.call(this);
var bloodGraphics = self.attachAsset('blood', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.2 + Math.random() * 0.6,
scaleY: 0.2 + Math.random() * 0.6,
alpha: 0.7 + Math.random() * 0.3
});
// Random velocity
self.vx = (Math.random() - 0.5) * 40;
self.vy = (Math.random() - 0.5) * 40;
self.lifetime = 1000 + Math.random() * 2000;
self.createdAt = Date.now();
self.update = function () {
self.x += self.vx;
self.y += self.vy;
// Slow down
self.vx *= 0.95;
self.vy *= 0.95;
// Fade out based on lifetime
var age = Date.now() - self.createdAt;
if (age > self.lifetime) {
self.destroy();
var index = bloodParticles.indexOf(self);
if (index !== -1) {
bloodParticles.splice(index, 1);
}
} else if (age > self.lifetime * 0.7) {
bloodGraphics.alpha = 1 - (age - self.lifetime * 0.7) / (self.lifetime * 0.3);
}
};
return self;
});
var Monster = Container.expand(function () {
var self = Container.call(this);
var monsterGraphics = self.attachAsset('monster', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.5,
scaleY: 0.5
});
self.health = 5;
self.growthRate = 0.004;
self.maxScale = 5;
self.isDying = false;
self.baseScale = 0.5;
// Apply a random tint to make monsters look different
var tints = [0x4A2B0F, 0x7E3500, 0x5D4037, 0x330000, 0x2D0C01];
monsterGraphics.tint = tints[Math.floor(Math.random() * tints.length)];
self.update = function () {
if (self.isDying) {
return;
}
// Grow the monster
if (monsterGraphics.scale.x < self.maxScale) {
monsterGraphics.scale.x += self.growthRate;
monsterGraphics.scale.y += self.growthRate;
} else {
// Monster has grown too big - game over!
gameOver();
}
};
self.punch = function () {
if (self.isDying) {
return;
}
self.health--;
// Temporarily shrink the monster when punched
var currentScale = monsterGraphics.scale.x;
tween(monsterGraphics.scale, {
x: currentScale * 0.8,
y: currentScale * 0.8
}, {
duration: 100,
easing: tween.easeOut,
onFinish: function onFinish() {
if (!self.isDying) {
tween(monsterGraphics.scale, {
x: currentScale,
y: currentScale
}, {
duration: 300,
easing: tween.easeOut
});
}
}
});
// Flash red
tween(monsterGraphics, {
tint: 0xFF0000
}, {
duration: 100,
onFinish: function onFinish() {
if (!self.isDying) {
tween(monsterGraphics, {
tint: monsterGraphics.tint
}, {
duration: 200
});
}
}
});
// Add blood spray
createBloodSpray(self.x, self.y, 8);
// Play punch sound
LK.getSound('punch').play();
// Check if monster is dead
if (self.health <= 0) {
self.die();
}
};
self.die = function () {
self.isDying = true;
LK.getSound('monsterDeath').play();
// Create a big blood explosion
createBloodSpray(self.x, self.y, 20);
// Shrink and fade out
tween(monsterGraphics.scale, {
x: 0.1,
y: 0.1
}, {
duration: 500,
easing: tween.easeIn
});
tween(monsterGraphics, {
alpha: 0
}, {
duration: 500,
easing: tween.easeIn,
onFinish: function onFinish() {
self.destroy();
monstersKilled++;
updateScore();
// Spawn next monster after delay
if (monsterSpawnTimeout) {
LK.clearTimeout(monsterSpawnTimeout);
}
monsterSpawnTimeout = LK.setTimeout(spawnMonster, 1000);
}
});
};
self.down = function (x, y, obj) {
self.punch();
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0xD3D3D3
});
/****
* Game Code
****/
/*
Supported Types:
1. Shape:
- Simple geometric figures with these properties:
* width: (required) pixel width of the shape.
* height: (required) pixel height of the shape.
* color: (required) color of the shape.
* shape: (required) type of shape. Valid options: 'box', 'ellipse'.
2. Image:
- Imported images with these properties:
* width: (required) pixel resolution width.
* height: (required) pixel resolution height.
* id: (required) identifier for the image.
* flipX: (optional) horizontal flip. Valid values: 0 (no flip), 1 (flip).
* flipY: (optional) vertical flip. Valid values: 0 (no flip), 1 (flip).
* orientation: (optional) rotation in multiples of 90 degrees, clockwise. Valid values:
- 0: No rotation.
- 1: Rotate 90 degrees.
- 2: Rotate 180 degrees.
- 3: Rotate 270 degrees.
Note: Width and height remain unchanged upon flipping.
3. Sound:
- Sound effects with these properties:
* id: (required) identifier for the sound.
* volume: (optional) custom volume. Valid values are a float from 0 to 1.
4. Music:
- In contract to sound effects, only one music can be played at a time
- Music is using the same API to initilize just like sound.
- Music loops by default
- Music with these config options:
* id: (required) identifier for the sound.
* volume: (optional) custom volume. Valid values are a float from 0 to 1.
* start: (optional) a float from 0 to 1 used for cropping and indicates the start of the cropping
* end: (optional) a float from 0 to 1 used for cropping and indicates the end of the cropping
*/
// Game variables
//{0.1}
var monster = null;
var bloodParticles = [];
var monstersKilled = 0;
var monsterSpawnTimeout = null;
var difficultyLevel = 1;
var isGameActive = true;
var lastMonsterKillTime = 0;
// UI elements
var scoreTxt = new Text2('0', {
size: 100,
fill: 0xFF0000
});
var highScoreTxt = new Text2('Best: 0', {
size: 60,
fill: 0xFFFFFF
});
var waveTxt = new Text2('Wave: 1', {
size: 60,
fill: 0xFFFFFF
});
function initializeGame() {
// Set up background
var backgroundSprite = LK.getAsset('background', {
anchorX: 0.5,
anchorY: 0.5,
x: 2048 / 2,
y: 2732 / 2,
alpha: 1.0 // Ensure maximum brightness by setting alpha to maximum
});
game.addChild(backgroundSprite);
// Set up score display
scoreTxt.anchor.set(0.5, 0);
scoreTxt.y = 50;
LK.gui.top.addChild(scoreTxt);
// Set up high score display
highScoreTxt.anchor.set(0.5, 0);
highScoreTxt.y = 150;
LK.gui.top.addChild(highScoreTxt);
updateHighScore();
// Set up wave display
waveTxt.anchor.set(0.5, 0);
waveTxt.y = 220;
LK.gui.top.addChild(waveTxt);
// Start background music
LK.playMusic('bgMusic', {
fade: {
start: 0,
end: 0.3,
duration: 1000
}
});
// Spawn the first monster
spawnMonster();
}
function spawnMonster() {
if (!isGameActive) {
return;
}
// Create new monster
monster = new Monster();
monster.x = 2048 / 2;
monster.y = 2732 / 2;
// Increase difficulty based on monsters killed
if (monstersKilled > 0) {
// Every 3 monsters, increase difficulty level
if (monstersKilled % 3 === 0) {
difficultyLevel++;
waveTxt.setText('Wave: ' + difficultyLevel);
LK.effects.flashScreen(0x330000, 500);
}
// Adjust monster properties based on difficulty
monster.health = 5 + Math.min(5, difficultyLevel);
monster.growthRate = 0.008 + difficultyLevel * 0.001;
monster.baseScale = 0.5 + difficultyLevel * 0.03;
monster.speed = 1 + difficultyLevel * 0.1; // Increase speed based on difficulty
// Update monster's initial appearance
var monsterGraphics = LK.getAsset('jumpscare', {
anchorX: 0.5,
anchorY: 0.5
});
monster.addChild(monsterGraphics);
monsterGraphics.scale.x = monster.baseScale;
monsterGraphics.scale.y = monster.baseScale;
}
// Add monster to game
game.addChild(monster);
LK.getSound('monsterGrowl').play();
}
function createBloodSpray(x, y, count) {
for (var i = 0; i < count; i++) {
var blood = new BloodParticle();
blood.x = x;
blood.y = y;
bloodParticles.push(blood);
game.addChild(blood);
}
}
function updateScore() {
scoreTxt.setText(monstersKilled.toString());
// Check if high score needs updating
if (monstersKilled > storage.highScore) {
storage.highScore = monstersKilled;
updateHighScore();
}
lastMonsterKillTime = Date.now();
}
function updateHighScore() {
highScoreTxt.setText('Best: ' + storage.highScore);
}
function gameOver() {
if (!isGameActive) {
return;
}
isGameActive = false;
// Play a loud and distorted grainy scream sound
LK.getSound('jumpscare').play();
// Fade music out
LK.playMusic('bgMusic', {
fade: {
start: 0.3,
end: 0,
duration: 500
}
});
// Flash screen red
LK.effects.flashScreen(0xFF0000, 800);
// Show jumpscare sprite before game over screen
var jumpscareSprite = LK.getAsset('jumpscare', {
anchorX: 0.5,
anchorY: 0.5,
x: 2048 / 2,
y: 2732 / 2,
alpha: 1.0,
tint: 0xFF0000 // Tint the sprite red
});
game.addChild(jumpscareSprite);
// Make the jumpscare sprite shake continuously and violently
function shakeSprite(sprite) {
tween(sprite, {
x: sprite.x + 40
}, {
duration: 15,
easing: tween.easeInOut,
onFinish: function onFinish() {
tween(sprite, {
x: sprite.x - 80
}, {
duration: 15,
easing: tween.easeInOut,
onFinish: function onFinish() {
tween(sprite, {
x: sprite.x + 40
}, {
duration: 15,
easing: tween.easeInOut,
onFinish: function onFinish() {
shakeSprite(sprite); // Recursively call to continue shaking
}
});
}
});
}
});
}
shakeSprite(jumpscareSprite);
LK.setTimeout(function () {
jumpscareSprite.destroy();
LK.showGameOver();
}, 800);
}
// Initialize game on startup
initializeGame();
// Event handling
game.down = function (x, y, obj) {
// This handles general taps on game area (not on specific monsters)
// Not needed for now as monsters have their own down handler
};
// Game update loop
game.update = function () {
// Update all blood particles
for (var i = bloodParticles.length - 1; i >= 0; i--) {
// BloodParticle.update() handles its own removal from the array if needed
// We don't need to do anything here
}
// Check if we should increase difficulty over time
// If a monster hasn't been killed in a while, make it grow faster
if (monster && lastMonsterKillTime > 0) {
var timeSinceLastKill = Date.now() - lastMonsterKillTime;
if (timeSinceLastKill > 5000) {
// Gradually increase growth rate if player is taking too long
monster.growthRate *= 1.002;
}
}
};