User prompt
musuh meledak saat kena tembak ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
buat musuh bisa menyerang melee ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
buat maze berukuran setengah layar
User prompt
buat pergerakkan player lembut tidak patah patah ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
musuh bergerak bolak balik ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
swipe for control
Code edit (1 edits merged)
Please save this source code
User prompt
Ore Hunter: Underground Maze
Initial prompt
random maze generate. hunting valuable ore. player manual shooting enemy. enemy melee attack
/**** * Plugins ****/ var tween = LK.import("@upit/tween.v1"); /**** * Classes ****/ var Bullet = Container.expand(function () { var self = Container.call(this); var bulletGraphics = self.attachAsset('bullet', { anchorX: 0.5, anchorY: 0.5 }); self.speed = 8; self.direction = { x: 0, y: 0 }; self.lifetime = 0; self.maxLifetime = 120; // 2 seconds at 60fps self.update = function () { self.x += self.direction.x * self.speed; self.y += self.direction.y * self.speed; self.lifetime++; }; return self; }); var Enemy = Container.expand(function () { var self = Container.call(this); var enemyGraphics = self.attachAsset('enemy', { anchorX: 0.5, anchorY: 0.5 }); self.speed = 1; self.health = 2; self.attackRange = 40; self.patrolDirection = Math.random() > 0.5 ? 1 : -1; // Random initial direction self.patrolAxis = Math.random() > 0.5 ? 'x' : 'y'; // Random patrol axis (horizontal or vertical) self.patrolDistance = CELL_SIZE * 3; // Patrol 3 cells distance self.startPosition = { x: 0, y: 0 }; // Will be set when enemy is placed self.isMoving = false; self.lastPlayerDistance = Infinity; self.startPatrol = function () { if (self.isMoving) return; self.isMoving = true; var targetX = self.x; var targetY = self.y; // Calculate target position based on patrol axis if (self.patrolAxis === 'x') { targetX = self.startPosition.x + self.patrolDirection * self.patrolDistance; } else { targetY = self.startPosition.y + self.patrolDirection * self.patrolDistance; } // Check if target position is valid if (canMoveTo(targetX, targetY)) { // Move to target position using tween tween(self, { x: targetX, y: targetY }, { duration: 2000, easing: tween.linear, onFinish: function onFinish() { self.isMoving = false; self.patrolDirection *= -1; // Reverse direction } }); } else { // If can't move in current direction, reverse immediately self.isMoving = false; self.patrolDirection *= -1; } }; self.update = function () { var dx = player.x - self.x; var dy = player.y - self.y; var distance = Math.sqrt(dx * dx + dy * dy); // Start patrol movement if not already moving if (!self.isMoving) { self.startPatrol(); } // Attack player if in range if (distance < self.attackRange) { if (!self.lastPlayerDistance || self.lastPlayerDistance >= self.attackRange) { // Just entered attack range playerHealth--; LK.effects.flashObject(player, 0xFF0000, 500); // Stop patrolling when attacking tween.stop(self); self.isMoving = false; } } self.lastPlayerDistance = distance; }; return self; }); var Ore = Container.expand(function () { var self = Container.call(this); var oreGraphics = self.attachAsset('ore', { anchorX: 0.5, anchorY: 0.5 }); self.value = 1; self.bobTimer = 0; self.baseY = self.y; self.update = function () { self.bobTimer++; self.y = self.baseY + Math.sin(self.bobTimer * 0.1) * 3; }; return self; }); /**** * Initialize Game ****/ var game = new LK.Game({ backgroundColor: 0x2C1810 }); /**** * Game Code ****/ // Game constants var MAZE_WIDTH = 25; var MAZE_HEIGHT = 33; var CELL_SIZE = 80; var MAZE_OFFSET_X = (2048 - MAZE_WIDTH * CELL_SIZE) / 2; var MAZE_OFFSET_Y = 100; // Game variables var maze = []; var player; var enemies = []; var ores = []; var bullets = []; var playerHealth = 3; var oreCollected = 0; var oreTarget = 10; var level = 1; var exit; var gameContainer; // UI elements var healthText = new Text2('Health: 3', { size: 60, fill: 0xFF4444 }); healthText.anchor.set(0, 0); LK.gui.topLeft.addChild(healthText); var oreText = new Text2('Ore: 0/10', { size: 60, fill: 0xFFD700 }); oreText.anchor.set(0.5, 0); LK.gui.top.addChild(oreText); var levelText = new Text2('Level: 1', { size: 60, fill: 0xFFFFFF }); levelText.anchor.set(1, 0); LK.gui.topRight.addChild(levelText); // Initialize maze array function initializeMaze() { maze = []; for (var y = 0; y < MAZE_HEIGHT; y++) { maze[y] = []; for (var x = 0; x < MAZE_WIDTH; x++) { maze[y][x] = 1; // 1 = wall, 0 = floor } } } // Simple maze generation using recursive backtracking function generateMaze() { initializeMaze(); var stack = []; var startX = 1; var startY = 1; maze[startY][startX] = 0; stack.push({ x: startX, y: startY }); while (stack.length > 0) { var current = stack[stack.length - 1]; var neighbors = []; // Check all four directions var directions = [{ x: 0, y: -2 }, { x: 2, y: 0 }, { x: 0, y: 2 }, { x: -2, y: 0 }]; for (var i = 0; i < directions.length; i++) { var nx = current.x + directions[i].x; var ny = current.y + directions[i].y; if (nx > 0 && nx < MAZE_WIDTH - 1 && ny > 0 && ny < MAZE_HEIGHT - 1 && maze[ny][nx] === 1) { neighbors.push({ x: nx, y: ny, dir: directions[i] }); } } if (neighbors.length > 0) { var chosen = neighbors[Math.floor(Math.random() * neighbors.length)]; // Remove wall between current and chosen maze[current.y + chosen.dir.y / 2][current.x + chosen.dir.x / 2] = 0; maze[chosen.y][chosen.x] = 0; stack.push(chosen); } else { stack.pop(); } } } // Create visual maze function createMazeVisual() { gameContainer = game.addChild(new Container()); for (var y = 0; y < MAZE_HEIGHT; y++) { for (var x = 0; x < MAZE_WIDTH; x++) { var cellX = MAZE_OFFSET_X + x * CELL_SIZE; var cellY = MAZE_OFFSET_Y + y * CELL_SIZE; if (maze[y][x] === 1) { // Wall var wall = LK.getAsset('wall', { x: cellX, y: cellY }); gameContainer.addChild(wall); } else { // Floor var floor = LK.getAsset('floor', { x: cellX, y: cellY }); gameContainer.addChild(floor); } } } } // Place ore in maze function placeOre() { var oreCount = oreTarget + Math.floor(level / 2); var placed = 0; while (placed < oreCount) { var x = Math.floor(Math.random() * MAZE_WIDTH); var y = Math.floor(Math.random() * MAZE_HEIGHT); if (maze[y][x] === 0 && (x !== 1 || y !== 1)) { var ore = gameContainer.addChild(new Ore()); ore.x = MAZE_OFFSET_X + x * CELL_SIZE + CELL_SIZE / 2; ore.y = MAZE_OFFSET_Y + y * CELL_SIZE + CELL_SIZE / 2; ore.baseY = ore.y; ores.push(ore); placed++; } } } // Place enemies in maze function placeEnemies() { var enemyCount = 3 + level; var placed = 0; while (placed < enemyCount) { var x = Math.floor(Math.random() * MAZE_WIDTH); var y = Math.floor(Math.random() * MAZE_HEIGHT); if (maze[y][x] === 0 && (x !== 1 || y !== 1) && Math.sqrt((x - 1) * (x - 1) + (y - 1) * (y - 1)) > 5) { var enemy = gameContainer.addChild(new Enemy()); enemy.x = MAZE_OFFSET_X + x * CELL_SIZE + CELL_SIZE / 2; enemy.y = MAZE_OFFSET_Y + y * CELL_SIZE + CELL_SIZE / 2; enemy.startPosition.x = enemy.x; enemy.startPosition.y = enemy.y; enemies.push(enemy); placed++; } } } // Place exit function placeExit() { // Find a position far from start var placed = false; while (!placed) { var x = Math.floor(Math.random() * MAZE_WIDTH); var y = Math.floor(Math.random() * MAZE_HEIGHT); if (maze[y][x] === 0 && Math.sqrt((x - 1) * (x - 1) + (y - 1) * (y - 1)) > 10) { exit = gameContainer.addChild(LK.getAsset('exit', { x: MAZE_OFFSET_X + x * CELL_SIZE, y: MAZE_OFFSET_Y + y * CELL_SIZE })); placed = true; } } } // Check if position is valid for movement function canMoveTo(x, y) { var mazeX = Math.floor((x - MAZE_OFFSET_X) / CELL_SIZE); var mazeY = Math.floor((y - MAZE_OFFSET_Y) / CELL_SIZE); if (mazeX < 0 || mazeX >= MAZE_WIDTH || mazeY < 0 || mazeY >= MAZE_HEIGHT) { return false; } return maze[mazeY][mazeX] === 0; } // Initialize level function initializeLevel() { // Clear existing game objects if (gameContainer) { gameContainer.destroy(); } enemies = []; ores = []; bullets = []; oreCollected = 0; // Generate new maze generateMaze(); createMazeVisual(); // Create player player = gameContainer.addChild(LK.getAsset('player', { anchorX: 0.5, anchorY: 0.5, x: MAZE_OFFSET_X + 1 * CELL_SIZE + CELL_SIZE / 2, y: MAZE_OFFSET_Y + 1 * CELL_SIZE + CELL_SIZE / 2 })); // Place game objects placeOre(); placeEnemies(); placeExit(); // Update UI updateUI(); } // Update UI function updateUI() { healthText.setText('Health: ' + playerHealth); oreText.setText('Ore: ' + oreCollected + '/' + oreTarget); levelText.setText('Level: ' + level); } // Shooting system var dragNode = null; var shootCooldown = 0; function shoot(targetX, targetY) { if (shootCooldown > 0) return; var dx = targetX - player.x; var dy = targetY - player.y; var distance = Math.sqrt(dx * dx + dy * dy); if (distance < 50) return; // Don't shoot if too close var bullet = gameContainer.addChild(new Bullet()); bullet.x = player.x; bullet.y = player.y; bullet.direction.x = dx / distance; bullet.direction.y = dy / distance; bullets.push(bullet); shootCooldown = 15; // Quarter second cooldown LK.getSound('shoot').play(); } // Main game loop game.update = function () { if (shootCooldown > 0) shootCooldown--; // Update bullets for (var i = bullets.length - 1; i >= 0; i--) { var bullet = bullets[i]; // Check bullet lifetime if (bullet.lifetime >= bullet.maxLifetime) { bullet.destroy(); bullets.splice(i, 1); continue; } // Check wall collision if (!canMoveTo(bullet.x, bullet.y)) { bullet.destroy(); bullets.splice(i, 1); continue; } // Check enemy collision var hitEnemy = false; for (var j = enemies.length - 1; j >= 0; j--) { if (bullet.intersects(enemies[j])) { enemies[j].health--; LK.getSound('enemyHit').play(); if (enemies[j].health <= 0) { enemies[j].destroy(); enemies.splice(j, 1); } bullet.destroy(); bullets.splice(i, 1); hitEnemy = true; break; } } if (hitEnemy) continue; } // Check ore collection for (var i = ores.length - 1; i >= 0; i--) { if (player.intersects(ores[i])) { oreCollected++; LK.getSound('oreCollect').play(); ores[i].destroy(); ores.splice(i, 1); updateUI(); } } // Check exit condition if (exit && player.intersects(exit) && oreCollected >= oreTarget) { level++; oreTarget += 2; initializeLevel(); return; } // Check game over if (playerHealth <= 0) { LK.showGameOver(); return; } // Check win condition (survive 10 levels) if (level > 10) { LK.showYouWin(); return; } }; // Swipe-based movement system var swipeStart = { x: 0, y: 0 }; var swipeEnd = { x: 0, y: 0 }; var isTracking = false; var playerSpeed = 80; // Full cell movement var swipeThreshold = 50; // Minimum distance for swipe detection var lastMoveTime = 0; var moveDelay = 200; // Delay between moves in milliseconds game.down = function (x, y, obj) { swipeStart.x = x; swipeStart.y = y; isTracking = true; }; game.move = function (x, y, obj) { if (isTracking) { swipeEnd.x = x; swipeEnd.y = y; } }; game.up = function (x, y, obj) { if (!isTracking) return; isTracking = false; var dx = swipeEnd.x - swipeStart.x; var dy = swipeEnd.y - swipeStart.y; var swipeDistance = Math.sqrt(dx * dx + dy * dy); // Check if swipe is long enough if (swipeDistance < swipeThreshold) { // Short tap - shoot in that direction shoot(x, y); return; } // Prevent too frequent moves var currentTime = Date.now(); if (currentTime - lastMoveTime < moveDelay) return; // Determine swipe direction var moveX = 0; var moveY = 0; if (Math.abs(dx) > Math.abs(dy)) { // Horizontal swipe moveX = dx > 0 ? playerSpeed : -playerSpeed; } else { // Vertical swipe moveY = dy > 0 ? playerSpeed : -playerSpeed; } // Calculate new position var newX = player.x + moveX; var newY = player.y + moveY; // Check if movement is valid if (canMoveTo(newX, player.y) && Math.abs(moveX) > 0) { player.x = newX; lastMoveTime = currentTime; } else if (canMoveTo(player.x, newY) && Math.abs(moveY) > 0) { player.y = newY; lastMoveTime = currentTime; } }; // Initialize the first level initializeLevel();
===================================================================
--- original.js
+++ change.js
@@ -34,38 +34,65 @@
});
self.speed = 1;
self.health = 2;
self.attackRange = 40;
- self.moveTimer = 0;
- self.direction = {
+ self.patrolDirection = Math.random() > 0.5 ? 1 : -1; // Random initial direction
+ self.patrolAxis = Math.random() > 0.5 ? 'x' : 'y'; // Random patrol axis (horizontal or vertical)
+ self.patrolDistance = CELL_SIZE * 3; // Patrol 3 cells distance
+ self.startPosition = {
x: 0,
y: 0
- };
+ }; // Will be set when enemy is placed
+ self.isMoving = false;
self.lastPlayerDistance = Infinity;
+ self.startPatrol = function () {
+ if (self.isMoving) return;
+ self.isMoving = true;
+ var targetX = self.x;
+ var targetY = self.y;
+ // Calculate target position based on patrol axis
+ if (self.patrolAxis === 'x') {
+ targetX = self.startPosition.x + self.patrolDirection * self.patrolDistance;
+ } else {
+ targetY = self.startPosition.y + self.patrolDirection * self.patrolDistance;
+ }
+ // Check if target position is valid
+ if (canMoveTo(targetX, targetY)) {
+ // Move to target position using tween
+ tween(self, {
+ x: targetX,
+ y: targetY
+ }, {
+ duration: 2000,
+ easing: tween.linear,
+ onFinish: function onFinish() {
+ self.isMoving = false;
+ self.patrolDirection *= -1; // Reverse direction
+ }
+ });
+ } else {
+ // If can't move in current direction, reverse immediately
+ self.isMoving = false;
+ self.patrolDirection *= -1;
+ }
+ };
self.update = function () {
var dx = player.x - self.x;
var dy = player.y - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
- // Simple AI: move towards player if close enough
- if (distance < 300) {
- var moveX = dx > 0 ? 1 : -1;
- var moveY = dy > 0 ? 1 : -1;
- var newX = self.x + moveX * self.speed;
- var newY = self.y + moveY * self.speed;
- // Check if movement is valid (no walls)
- if (canMoveTo(newX, self.y)) {
- self.x = newX;
- }
- if (canMoveTo(self.x, newY)) {
- self.y = newY;
- }
+ // Start patrol movement if not already moving
+ if (!self.isMoving) {
+ self.startPatrol();
}
// Attack player if in range
if (distance < self.attackRange) {
if (!self.lastPlayerDistance || self.lastPlayerDistance >= self.attackRange) {
// Just entered attack range
playerHealth--;
LK.effects.flashObject(player, 0xFF0000, 500);
+ // Stop patrolling when attacking
+ tween.stop(self);
+ self.isMoving = false;
}
}
self.lastPlayerDistance = distance;
};
@@ -246,8 +273,10 @@
if (maze[y][x] === 0 && (x !== 1 || y !== 1) && Math.sqrt((x - 1) * (x - 1) + (y - 1) * (y - 1)) > 5) {
var enemy = gameContainer.addChild(new Enemy());
enemy.x = MAZE_OFFSET_X + x * CELL_SIZE + CELL_SIZE / 2;
enemy.y = MAZE_OFFSET_Y + y * CELL_SIZE + CELL_SIZE / 2;
+ enemy.startPosition.x = enemy.x;
+ enemy.startPosition.y = enemy.y;
enemies.push(enemy);
placed++;
}
}
2d sprites old dwarf hold shootgun. In-Game asset. 2d. High contrast. No shadows
2d chibi green evil underground fat ork. In-Game asset. 2d. High contrast. No shadows
2d golds ors brigh stone. In-Game asset. 2d. High contrast. No shadows
2d cave tunnel corridor. In-Game asset. 2d. High contrast. No shadows