User prompt
delever package on the right house when player collide with correct house
User prompt
add an arrow indicator to the house where the player should be delivering the package, and also for the package that has to pickup ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
sorry, car front side is left side, switch sprite orientation ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
cars when moving always turn the sprite to that direction, the front side of the sprite is right side ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
prevent house generation to overlap, cars, dogs and player should collide with houses
User prompt
when you click in the screen, player character should follow the mouse instead of teleporting to mouse
User prompt
dog behaviour follows player when get close to him
Code edit (1 edits merged)
Please save this source code
User prompt
Delivery Dash
Initial prompt
Create a simple yet fun 2D pixel art game titled "Delivery Dash". Genre: Action / Arcade / Time Management View: Top-down (like old-school Zelda or GTA 1 style) Main Gameplay Loop: The player controls a delivery person riding a bike or walking around a city map. The objective is to deliver packages to correct houses before time runs out. Houses are randomly placed, and the player must avoid obstacles like cars, dogs, or rival delivery agents. The player earns points based on speed, accuracy, and package condition. Controls: Arrow keys or WASD to move Spacebar or E to deliver a package when standing in front of the right house Optional: Shift for dash (limited stamina) Features: Timer countdown per level Increasing difficulty with new obstacles Power-ups like time extenders, speed boosts, or package protectors Simple scoring system 2-4 progressively harder levels with different city layouts Art Style: Pixel art, colorful and cartoony Sound: Add upbeat chiptune background music and delivery sound effects Make it playable in-browser. Keep code modular and readable in case I want to expand later.
/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
/****
* Classes
****/
var Arrow = Container.expand(function (targetType) {
var self = Container.call(this);
var arrowGraphics = self.attachAsset('arrow', {
anchorX: 0.5,
anchorY: 0.5
});
// Set color based on target type
if (targetType === 'pickup') {
arrowGraphics.tint = 0x00ff00; // Green for package pickup
} else if (targetType === 'delivery') {
arrowGraphics.tint = 0xff0000; // Red for delivery house
}
self.targetType = targetType;
self.target = null;
self.update = function () {
if (self.target && player) {
// Calculate direction to target
var dx = self.target.x - player.x;
var dy = self.target.y - player.y;
var angle = Math.atan2(dy, dx);
// Position arrow around player
var radius = 80;
self.x = player.x + Math.cos(angle) * radius;
self.y = player.y + Math.sin(angle) * radius;
// Rotate arrow to point towards target
arrowGraphics.rotation = angle + Math.PI / 2;
// Pulse animation using tween
if (!self.tweening) {
self.tweening = true;
tween(self, {
scaleX: 1.3,
scaleY: 1.3
}, {
duration: 500,
easing: tween.easeInOut,
onFinish: function onFinish() {
tween(self, {
scaleX: 1,
scaleY: 1
}, {
duration: 500,
easing: tween.easeInOut,
onFinish: function onFinish() {
self.tweening = false;
}
});
}
});
}
}
};
return self;
});
var Car = Container.expand(function () {
var self = Container.call(this);
var carGraphics = self.attachAsset('car', {
anchorX: 0.5,
anchorY: 0.5
});
self.speedX = (Math.random() - 0.5) * 4;
self.speedY = (Math.random() - 0.5) * 4;
self.update = function () {
var oldX = self.x;
var oldY = self.y;
self.x += self.speedX;
self.y += self.speedY;
// Calculate rotation based on movement direction
// Front of sprite is left side, so 0 rotation = moving left
var targetRotation = Math.atan2(self.speedY, self.speedX) + Math.PI;
// Smooth rotation using tween
tween.stop(carGraphics, {
rotation: true
});
tween(carGraphics, {
rotation: targetRotation
}, {
duration: 200,
easing: tween.easeOut
});
// Check collision with houses
var hitHouse = false;
for (var h = 0; h < houses.length; h++) {
if (self.intersects(houses[h])) {
hitHouse = true;
break;
}
}
// If hit house, revert movement and bounce
if (hitHouse) {
self.x = oldX;
self.y = oldY;
self.speedX *= -1;
self.speedY *= -1;
}
// Bounce off edges
if (self.x < 40 || self.x > 2008) {
self.speedX *= -1;
}
if (self.y < 40 || self.y > 2692) {
self.speedY *= -1;
}
// Keep in bounds
self.x = Math.max(40, Math.min(2008, self.x));
self.y = Math.max(40, Math.min(2692, self.y));
};
return self;
});
var Dog = Container.expand(function () {
var self = Container.call(this);
var dogGraphics = self.attachAsset('dog', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 2;
self.direction = Math.random() * Math.PI * 2;
self.update = function () {
// Check distance to player
var dx = player.x - self.x;
var dy = player.y - self.y;
var distanceToPlayer = Math.sqrt(dx * dx + dy * dy);
var detectionRange = 150;
if (distanceToPlayer < detectionRange && player) {
// Follow player behavior
var angleToPlayer = Math.atan2(dy, dx);
self.direction = angleToPlayer;
self.speed = 2.5; // Slightly faster when chasing
} else {
// Simple AI - change direction occasionally
if (Math.random() < 0.02) {
self.direction = Math.random() * Math.PI * 2;
}
self.speed = 2; // Normal speed when wandering
}
var oldX = self.x;
var oldY = self.y;
self.x += Math.cos(self.direction) * self.speed;
self.y += Math.sin(self.direction) * self.speed;
// Check collision with houses
var hitHouse = false;
for (var h = 0; h < houses.length; h++) {
if (self.intersects(houses[h])) {
hitHouse = true;
break;
}
}
// If hit house, revert movement and change direction
if (hitHouse) {
self.x = oldX;
self.y = oldY;
self.direction = Math.random() * Math.PI * 2;
}
// Bounce off edges
if (self.x < 15 || self.x > 2033) {
self.direction = Math.PI - self.direction;
}
if (self.y < 15 || self.y > 2717) {
self.direction = -self.direction;
}
// Keep in bounds
self.x = Math.max(15, Math.min(2033, self.x));
self.y = Math.max(15, Math.min(2717, self.y));
};
return self;
});
var House = Container.expand(function (houseId) {
var self = Container.call(this);
var houseGraphics = self.attachAsset('house', {
anchorX: 0.5,
anchorY: 0.5
});
self.houseId = houseId;
self.hasDelivery = false;
self.down = function (x, y, obj) {
if (player.hasPackage && self.distanceTo(player) < 80) {
if (player.targetHouse === self.houseId) {
// Correct delivery
LK.setScore(LK.getScore() + 100);
player.hasPackage = false;
player.targetHouse = null;
self.hasDelivery = true;
packagesDelivered++;
// Visual feedback
tween(self, {
scaleX: 1.3,
scaleY: 1.3
}, {
duration: 200,
onFinish: function onFinish() {
tween(self, {
scaleX: 1,
scaleY: 1
}, {
duration: 200
});
}
});
LK.getSound('delivery').play();
scoreText.setText(LK.getScore());
// Remove delivery arrow
if (deliveryArrow) {
deliveryArrow.destroy();
deliveryArrow = null;
}
// Create pickup arrow for next available package
if (packages.length > 0) {
pickupArrow = game.addChild(new Arrow('pickup'));
pickupArrow.target = packages[0];
}
// Check win condition
if (packagesDelivered >= totalPackages) {
if (currentLevel < 4) {
currentLevel++;
startLevel();
} else {
LK.showYouWin();
}
}
} else {
// Wrong delivery
LK.setScore(Math.max(0, LK.getScore() - 50));
scoreText.setText(LK.getScore());
LK.effects.flashObject(self, 0xff0000, 500);
}
}
};
self.distanceTo = function (other) {
var dx = self.x - other.x;
var dy = self.y - other.y;
return Math.sqrt(dx * dx + dy * dy);
};
return self;
});
var Package = Container.expand(function () {
var self = Container.call(this);
var packageGraphics = self.attachAsset('package', {
anchorX: 0.5,
anchorY: 0.5
});
self.collected = false;
return self;
});
var Player = Container.expand(function () {
var self = Container.call(this);
var playerGraphics = self.attachAsset('player', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 5;
self.hasPackage = false;
self.targetHouse = null;
return self;
});
var PowerUp = Container.expand(function (type) {
var self = Container.call(this);
var powerupGraphics = self.attachAsset('powerup', {
anchorX: 0.5,
anchorY: 0.5
});
self.type = type; // 'time', 'speed', 'shield'
self.collected = false;
// Set different colors for different types
if (type === 'time') {
powerupGraphics.tint = 0x00FF00;
} else if (type === 'speed') {
powerupGraphics.tint = 0x0080FF;
} else if (type === 'shield') {
powerupGraphics.tint = 0xFFFF00;
}
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x228B22
});
/****
* Game Code
****/
// Game variables
var player;
var packages = [];
var houses = [];
var cars = [];
var dogs = [];
var powerups = [];
var currentLevel = 1;
var totalPackages = 3;
var packagesDelivered = 0;
var gameTime = 60000; // 60 seconds
var timeRemaining = gameTime;
var dragNode = null;
var lastCollisionCheck = {};
var targetX = null;
var targetY = null;
var isMoving = false;
var pickupArrow = null;
var deliveryArrow = null;
// UI elements
var scoreText = new Text2('Score: 0', {
size: 60,
fill: 0xFFFFFF
});
scoreText.anchor.set(0.5, 0);
LK.gui.top.addChild(scoreText);
var timeText = new Text2('Time: 60', {
size: 60,
fill: 0xFFFFFF
});
timeText.anchor.set(1, 0);
LK.gui.topRight.addChild(timeText);
var levelText = new Text2('Level 1', {
size: 60,
fill: 0xFFFFFF
});
levelText.anchor.set(0, 0);
LK.gui.topLeft.addChild(levelText);
// Create road background
for (var i = 0; i < 21; i++) {
for (var j = 0; j < 28; j++) {
var road = LK.getAsset('road', {
x: i * 100,
y: j * 100,
anchorX: 0,
anchorY: 0
});
game.addChild(road);
}
}
function startLevel() {
// Clear existing game objects
for (var i = packages.length - 1; i >= 0; i--) {
packages[i].destroy();
}
for (var i = houses.length - 1; i >= 0; i--) {
houses[i].destroy();
}
for (var i = cars.length - 1; i >= 0; i--) {
cars[i].destroy();
}
for (var i = dogs.length - 1; i >= 0; i--) {
dogs[i].destroy();
}
for (var i = powerups.length - 1; i >= 0; i--) {
powerups[i].destroy();
}
// Clear arrow indicators
if (pickupArrow) {
pickupArrow.destroy();
pickupArrow = null;
}
if (deliveryArrow) {
deliveryArrow.destroy();
deliveryArrow = null;
}
packages = [];
houses = [];
cars = [];
dogs = [];
powerups = [];
packagesDelivered = 0;
// Reset time
timeRemaining = gameTime;
// Update UI
levelText.setText('Level ' + currentLevel);
// Create player if not exists
if (!player) {
player = game.addChild(new Player());
player.x = 1024;
player.y = 2366;
}
player.hasPackage = false;
player.targetHouse = null;
// Helper function to check if position overlaps with existing houses
function isPositionClear(x, y, minDistance) {
for (var j = 0; j < houses.length; j++) {
var dx = x - houses[j].x;
var dy = y - houses[j].y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance < minDistance) {
return false;
}
}
return true;
}
// Create packages and houses
totalPackages = 2 + currentLevel;
for (var i = 0; i < totalPackages; i++) {
// Create package
var pkg = new Package();
pkg.x = 200 + Math.random() * 1600;
pkg.y = 200 + Math.random() * 1200;
packages.push(pkg);
game.addChild(pkg);
}
// Create corresponding house with overlap prevention
// Create pickup arrow indicator pointing to first available package
if (packages.length > 0) {
pickupArrow = game.addChild(new Arrow('pickup'));
pickupArrow.target = packages[0];
}
// Create packages and houses
for (var i = 0; i < totalPackages; i++) {
var house = new House(i);
var attempts = 0;
var maxAttempts = 50;
var minHouseDistance = 200; // Minimum distance between houses
do {
house.x = 200 + Math.random() * 1600;
house.y = 1500 + Math.random() * 1000;
attempts++;
} while (!isPositionClear(house.x, house.y, minHouseDistance) && attempts < maxAttempts);
houses.push(house);
game.addChild(house);
}
// Create cars (more with each level)
var numCars = currentLevel + 1;
for (var i = 0; i < numCars; i++) {
var car = new Car();
car.x = Math.random() * 2048;
car.y = Math.random() * 2732;
cars.push(car);
game.addChild(car);
}
// Create dogs
var numDogs = Math.floor(currentLevel / 2) + 1;
for (var i = 0; i < numDogs; i++) {
var dog = new Dog();
dog.x = Math.random() * 2048;
dog.y = Math.random() * 2732;
dogs.push(dog);
game.addChild(dog);
}
// Create power-ups
var powerupTypes = ['time', 'speed', 'shield'];
for (var i = 0; i < 2; i++) {
var powerup = new PowerUp(powerupTypes[Math.floor(Math.random() * powerupTypes.length)]);
powerup.x = Math.random() * 2048;
powerup.y = Math.random() * 2732;
powerups.push(powerup);
game.addChild(powerup);
}
}
function handleMove(x, y, obj) {
// Set target position for smooth movement
targetX = Math.max(30, Math.min(2018, x));
targetY = Math.max(30, Math.min(2702, y));
isMoving = true;
}
game.move = handleMove;
game.down = function (x, y, obj) {
// Check if clicking on package to pick up
for (var i = 0; i < packages.length; i++) {
var pkg = packages[i];
if (!pkg.collected && pkg.intersects && player.intersects(pkg)) {
if (!player.hasPackage) {
pkg.collected = true;
pkg.destroy();
packages.splice(i, 1);
player.hasPackage = true;
player.targetHouse = i; // Set target house ID
LK.getSound('pickup').play();
// Remove pickup arrow and create delivery arrow
if (pickupArrow) {
pickupArrow.destroy();
pickupArrow = null;
}
// Create delivery arrow pointing to target house
if (player.targetHouse < houses.length) {
deliveryArrow = game.addChild(new Arrow('delivery'));
deliveryArrow.target = houses[player.targetHouse];
}
return;
}
}
}
handleMove(x, y, obj);
};
game.up = function (x, y, obj) {
// Mouse up - no action needed for smooth movement
};
game.update = function () {
// Smooth player movement towards target
if (isMoving && targetX !== null && targetY !== null) {
var dx = targetX - player.x;
var dy = targetY - player.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance > 5) {
// Move towards target with player speed
var moveX = dx / distance * player.speed;
var moveY = dy / distance * player.speed;
var oldX = player.x;
var oldY = player.y;
player.x += moveX;
player.y += moveY;
// Check collision with houses
var hitHouse = false;
for (var h = 0; h < houses.length; h++) {
if (player.intersects(houses[h])) {
hitHouse = true;
break;
}
}
// If hit house, revert movement
if (hitHouse) {
player.x = oldX;
player.y = oldY;
isMoving = false; // Stop movement when hitting house
}
} else {
// Close enough to target, stop moving
player.x = targetX;
player.y = targetY;
isMoving = false;
}
}
// Update time
timeRemaining -= 16.67; // Approximate 60fps
var seconds = Math.ceil(timeRemaining / 1000);
timeText.setText('Time: ' + Math.max(0, seconds));
// Check time up
if (timeRemaining <= 0) {
LK.showGameOver();
return;
}
// Check package pickup
for (var i = packages.length - 1; i >= 0; i--) {
var pkg = packages[i];
if (!pkg.collected && player.intersects(pkg)) {
if (!player.hasPackage) {
pkg.collected = true;
pkg.destroy();
packages.splice(i, 1);
player.hasPackage = true;
player.targetHouse = i;
LK.getSound('pickup').play();
// Remove pickup arrow and create delivery arrow
if (pickupArrow) {
pickupArrow.destroy();
pickupArrow = null;
}
// Create delivery arrow pointing to target house
if (player.targetHouse < houses.length) {
deliveryArrow = game.addChild(new Arrow('delivery'));
deliveryArrow.target = houses[player.targetHouse];
}
}
}
}
// Check powerup collection
for (var i = powerups.length - 1; i >= 0; i--) {
var powerup = powerups[i];
if (!powerup.collected && player.intersects(powerup)) {
powerup.collected = true;
powerup.destroy();
powerups.splice(i, 1);
if (powerup.type === 'time') {
timeRemaining += 10000; // Add 10 seconds
} else if (powerup.type === 'speed') {
player.speed = 8;
LK.setTimeout(function () {
player.speed = 5;
}, 5000);
}
LK.getSound('powerup').play();
LK.setScore(LK.getScore() + 25);
scoreText.setText(LK.getScore());
}
}
// Check collisions with obstacles
for (var i = 0; i < cars.length; i++) {
var car = cars[i];
var carKey = 'car_' + i;
var currentCollision = player.intersects(car);
if (!lastCollisionCheck[carKey] && currentCollision) {
// Just started colliding
LK.setScore(Math.max(0, LK.getScore() - 25));
scoreText.setText(LK.getScore());
LK.effects.flashObject(player, 0xff0000, 500);
}
lastCollisionCheck[carKey] = currentCollision;
}
for (var i = 0; i < dogs.length; i++) {
var dog = dogs[i];
var dogKey = 'dog_' + i;
var currentCollision = player.intersects(dog);
if (!lastCollisionCheck[dogKey] && currentCollision) {
// Just started colliding
LK.setScore(Math.max(0, LK.getScore() - 15));
scoreText.setText(LK.getScore());
LK.effects.flashObject(player, 0xff0000, 300);
}
lastCollisionCheck[dogKey] = currentCollision;
}
};
// Start the first level
startLevel();
// Play background music
LK.playMusic('bgmusic'); ===================================================================
--- original.js
+++ change.js
@@ -5,8 +5,61 @@
/****
* Classes
****/
+var Arrow = Container.expand(function (targetType) {
+ var self = Container.call(this);
+ var arrowGraphics = self.attachAsset('arrow', {
+ anchorX: 0.5,
+ anchorY: 0.5
+ });
+ // Set color based on target type
+ if (targetType === 'pickup') {
+ arrowGraphics.tint = 0x00ff00; // Green for package pickup
+ } else if (targetType === 'delivery') {
+ arrowGraphics.tint = 0xff0000; // Red for delivery house
+ }
+ self.targetType = targetType;
+ self.target = null;
+ self.update = function () {
+ if (self.target && player) {
+ // Calculate direction to target
+ var dx = self.target.x - player.x;
+ var dy = self.target.y - player.y;
+ var angle = Math.atan2(dy, dx);
+ // Position arrow around player
+ var radius = 80;
+ self.x = player.x + Math.cos(angle) * radius;
+ self.y = player.y + Math.sin(angle) * radius;
+ // Rotate arrow to point towards target
+ arrowGraphics.rotation = angle + Math.PI / 2;
+ // Pulse animation using tween
+ if (!self.tweening) {
+ self.tweening = true;
+ tween(self, {
+ scaleX: 1.3,
+ scaleY: 1.3
+ }, {
+ duration: 500,
+ easing: tween.easeInOut,
+ onFinish: function onFinish() {
+ tween(self, {
+ scaleX: 1,
+ scaleY: 1
+ }, {
+ duration: 500,
+ easing: tween.easeInOut,
+ onFinish: function onFinish() {
+ self.tweening = false;
+ }
+ });
+ }
+ });
+ }
+ }
+ };
+ return self;
+});
var Car = Container.expand(function () {
var self = Container.call(this);
var carGraphics = self.attachAsset('car', {
anchorX: 0.5,
@@ -150,8 +203,18 @@
}
});
LK.getSound('delivery').play();
scoreText.setText(LK.getScore());
+ // Remove delivery arrow
+ if (deliveryArrow) {
+ deliveryArrow.destroy();
+ deliveryArrow = null;
+ }
+ // Create pickup arrow for next available package
+ if (packages.length > 0) {
+ pickupArrow = game.addChild(new Arrow('pickup'));
+ pickupArrow.target = packages[0];
+ }
// Check win condition
if (packagesDelivered >= totalPackages) {
if (currentLevel < 4) {
currentLevel++;
@@ -240,8 +303,10 @@
var lastCollisionCheck = {};
var targetX = null;
var targetY = null;
var isMoving = false;
+var pickupArrow = null;
+var deliveryArrow = null;
// UI elements
var scoreText = new Text2('Score: 0', {
size: 60,
fill: 0xFFFFFF
@@ -288,8 +353,17 @@
}
for (var i = powerups.length - 1; i >= 0; i--) {
powerups[i].destroy();
}
+ // Clear arrow indicators
+ if (pickupArrow) {
+ pickupArrow.destroy();
+ pickupArrow = null;
+ }
+ if (deliveryArrow) {
+ deliveryArrow.destroy();
+ deliveryArrow = null;
+ }
packages = [];
houses = [];
cars = [];
dogs = [];
@@ -327,9 +401,17 @@
pkg.x = 200 + Math.random() * 1600;
pkg.y = 200 + Math.random() * 1200;
packages.push(pkg);
game.addChild(pkg);
- // Create corresponding house with overlap prevention
+ }
+ // Create corresponding house with overlap prevention
+ // Create pickup arrow indicator pointing to first available package
+ if (packages.length > 0) {
+ pickupArrow = game.addChild(new Arrow('pickup'));
+ pickupArrow.target = packages[0];
+ }
+ // Create packages and houses
+ for (var i = 0; i < totalPackages; i++) {
var house = new House(i);
var attempts = 0;
var maxAttempts = 50;
var minHouseDistance = 200; // Minimum distance between houses
@@ -385,10 +467,20 @@
pkg.collected = true;
pkg.destroy();
packages.splice(i, 1);
player.hasPackage = true;
- player.targetHouse = packages.length; // Simple targeting system
+ player.targetHouse = i; // Set target house ID
LK.getSound('pickup').play();
+ // Remove pickup arrow and create delivery arrow
+ if (pickupArrow) {
+ pickupArrow.destroy();
+ pickupArrow = null;
+ }
+ // Create delivery arrow pointing to target house
+ if (player.targetHouse < houses.length) {
+ deliveryArrow = game.addChild(new Arrow('delivery'));
+ deliveryArrow.target = houses[player.targetHouse];
+ }
return;
}
}
}
@@ -451,8 +543,18 @@
packages.splice(i, 1);
player.hasPackage = true;
player.targetHouse = i;
LK.getSound('pickup').play();
+ // Remove pickup arrow and create delivery arrow
+ if (pickupArrow) {
+ pickupArrow.destroy();
+ pickupArrow = null;
+ }
+ // Create delivery arrow pointing to target house
+ if (player.targetHouse < houses.length) {
+ deliveryArrow = game.addChild(new Arrow('delivery'));
+ deliveryArrow.target = houses[player.targetHouse];
+ }
}
}
}
// Check powerup collection
shield icon inside of a blue energy bubble. In-Game asset. 2d. High contrast. No shadows
1+ up heart icon. In-Game asset. 2d. High contrast. No shadows
fast foward icon. In-Game asset. 2d. High contrast. No shadows
+10 inside of a clock icon. In-Game asset. 2d. High contrast. No shadows
Street block, garden with concrete walkway on the border. In-Game asset. 2d. High contrast. No shadows