Code edit (2 edits merged)
Please save this source code
User prompt
when tracking, change drone debugTextto orange too. DON'T USE fill PROPERY but tint
User prompt
Please fix the bug: 'TypeError: Cannot set properties of undefined (setting 'fill')' in or related to this line: 'self.debugText.style.fill = 0xFFA500; // Change debugText tint to orange when tracking' Line Number: 372
User prompt
Please fix the bug: 'TypeError: Cannot set properties of undefined (setting 'fill')' in or related to this line: 'self.debugText.style.fill = 0xFFA500; // Change debugText tint to orange when tracking' Line Number: 370
User prompt
when tracking, change drone debugText tint to orange too
User prompt
Please fix the bug: 'TypeError: Cannot set properties of undefined (setting 'fill')' in or related to this line: 'self.debugText.style.fill = self.state === 'tracking' ? 0xFFA500 : 0xFFFFFF; // Change color to orange when tracking' Line Number: 345
User prompt
when tranking, change drone debugText color to orange too
User prompt
when tracking, switch scan laser tint to orange
User prompt
add a debugText to track drone state
User prompt
Please fix the bug: 'Cannot read properties of undefined (reading 'addChild')' in or related to this line: 'foregroundContainer.addChild(debugText);' Line Number: 634
User prompt
create a global variable debugText; initialize it in initalizeGame
User prompt
add a debugText; respect coding style
Code edit (2 edits merged)
Please save this source code
User prompt
use log() instead of console.log()
Code edit (2 edits merged)
Please save this source code
User prompt
in attacking mode, check every 2 sec if scan laser intersects knight bounding box, if not, return to scanning mode
User prompt
Please fix the bug: 'TypeError: tween.cancel is not a function' in or related to this line: 'tween.cancel(self);' Line Number: 361 βͺπ‘ Consider importing and using the following plugins: @upit/tween.v1
Code edit (1 edits merged)
Please save this source code
User prompt
Please fix the bug: 'Cannot set properties of undefined (setting 'followKnight')' in or related to this line: 'self.followKnight = function (knight) {' Line Number: 736
User prompt
Please fix the bug: 'Cannot set properties of undefined (setting 'followKnight')' in or related to this line: 'self.followKnight = function (knight) {' Line Number: 721
User prompt
in drone class create a new function followKnight that sets the knight as target and moves toward him until reaching a distance = 500
Code edit (1 edits merged)
Please save this source code
Code edit (2 edits merged)
Please save this source code
User prompt
add a global isDebug
User prompt
add a boundingBox to knight
/**** 
* Plugins
****/ 
var tween = LK.import("@upit/tween.v1");
/**** 
* Classes
****/ 
// Import the tween plugin
var Drone = Container.expand(function () {
	var self = Container.call(this);
	var droneGraphics = LK.getAsset('drone', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	var shadowDrone = LK.getAsset('drone', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	self.shadowOffset = {
		x: -30,
		y: 40
	}; // Define shadow offset property
	shadowDrone.alpha = 0.5;
	shadowDrone.tint = 0x000000;
	//shadowDrone.rotation = Math.PI / 12;
	//shadowDrone.scale.y = 0.5;
	shadowDrone.x = -10;
	shadowDrone.y = 40;
	self.addChild(shadowDrone);
	self.droneScanLaser = LK.getAsset('droneScanLaser', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	self.droneScanBar = LK.getAsset('droneScanBar', {
		anchorX: 0,
		anchorY: 0.5
	});
	self.droneScanLaser.visible = true; // Always visible
	self.droneScanLaser.x = droneGraphics.width * 2;
	self.addChild(self.droneScanLaser);
	self.droneScanBar.x = droneGraphics.width / 2; // droneScanLaser.x; 
	self.droneScanBar.blendMode = 3;
	self.droneScanBar.y = self.droneScanLaser.y;
	self.addChild(self.droneScanBar);
	function loopScanLaserTint() {
		tween(self.droneScanLaser, {
			tint: 0x00FF00
		}, {
			duration: 1000,
			easing: tween.easeInOut,
			onFinish: function onFinish() {
				tween(self.droneScanLaser, {
					tint: 0x00AA00
				}, {
					duration: 1000,
					easing: tween.easeInOut,
					onFinish: loopScanLaserTint // Recursively call to loop
				});
			}
		});
	}
	loopScanLaserTint(); // Start the loop
	self.droneScanLaser.alpha = 0.3; // Set alpha to 0.3
	function animateScanBar() {
		tween(self.droneScanBar, {
			alpha: 0.3,
			rotation: Math.PI / 6.5
		}, {
			duration: 1000,
			easing: tween.easeInOut,
			onFinish: function onFinish() {
				tween(self.droneScanBar, {
					alpha: 0.6,
					rotation: -Math.PI / 6.5
				}, {
					duration: 1000,
					easing: tween.easeInOut,
					onFinish: animateScanBar // Recursively call to loop
				}); // Ensure the tween is started
			}
		}); // Ensure the tween is started
	}
	animateScanBar(); // Start the loop
	self.addChild(droneGraphics);
	self.speed = 5;
	self.state = 'scanning'; // Possible states: scanning, tracking, attacking
	self.fireRange = 300; // Example fire range value
	self.currentTargetIndex = 0;
	self.target = {
		x: 0,
		y: 0
	};
	self.selectTarget = function () {
		var newTargetIndex;
		do {
			newTargetIndex = Math.floor(Math.random() * corners.length);
		} while (newTargetIndex === self.currentTargetIndex);
		self.currentTargetIndex = newTargetIndex;
		self.target = corners[newTargetIndex];
		var distance = Math.sqrt(Math.pow(self.target.x - self.x, 2) + Math.pow(self.target.y - self.y, 2));
		var moveSpeed = 0.2; // Adjust this value to control drone speed
		var duration = distance / moveSpeed; // Calculate duration based on distance and speed
		// Calculate rotation angle before starting movement
		var dx = self.target.x - self.x;
		var dy = self.target.y - self.y;
		tween(self, {
			rotation: Math.atan2(dy, dx)
		}, {
			duration: 1000,
			easing: tween.easeInOut,
			onUpdate: function onUpdate() {
				shadowDrone.x = self.shadowOffset.x * Math.cos(self.rotation);
				shadowDrone.y = self.shadowOffset.y * Math.sin(self.rotation);
			},
			onFinish: function onFinish() {
				tween(self, {
					x: self.target.x,
					y: self.target.y
				}, {
					duration: duration,
					easing: tween.easeInOut,
					onFinish: function onFinish() {
						self.selectTarget();
					}
				});
			}
		});
	};
	self.update = function () {
		if (self.state === 'scanning') {
			// Check for intersection with knight
			if (self.droneScanLaser.intersects(knight)) {
				self.state = 'attacking';
				console.log("Drone switched to attacking mode!");
			}
			// We don't need the distance calculation and threshold check anymore
			// since the tween handles movement and calls selectTarget when done
			// We still want to update rotation during movement for a more natural look
			if (self.target) {
				var dx = self.target.x - self.x;
				var dy = self.target.y - self.y;
				// Only update rotation if we're still moving (distance > small threshold)
				var distance = Math.sqrt(dx * dx + dy * dy);
				shadowDrone.x = self.shadowOffset.x * Math.cos(self.rotation);
				shadowDrone.y = self.shadowOffset.y * Math.sin(self.rotation);
			}
			// Update droneScanBar width based on its rotation
			self.droneScanBar.width = 600 * (1 + 0.46 * Math.abs(Math.sin(self.droneScanBar.rotation)));
		}
	};
});
var Knight = Container.expand(function () {
	var self = Container.call(this);
	// Add boundingBox for collision detection
	var boundingBox = LK.getAsset('boundingBox', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	self.addChild(boundingBox);
	boundingBox.visible = false; // Set to false if you don't want it visible
	var directionMapping = {
		'down-left': 'dir1',
		'left': 'dir2',
		'up-left': 'dir3',
		'up': 'dir4',
		'up-right': 'dir5',
		'right': 'dir6',
		'down-right': 'dir7',
		'down': 'dir8'
	};
	// Pre-create a list of assets for each direction
	var knightAssets = {};
	var shadowAssets = {}; // Shadow assets for the knight
	var knightIdleAssets = {}; // Idle assets for the knight
	var shadowIdleAssets = {}; // Shadow idle assets for the knight
	var color = 0xFFFFFF; // Original blue / 0xff4d4d; // Red / 0x9aff9a; // Green
	// Initialize run animation assets
	for (var dir in directionMapping) {
		knightAssets[dir] = [];
		shadowAssets[dir] = []; // Initialize shadow assets array for each direction
		for (var i = 1; i <= 8; i++) {
			var frameNumber = i.toString().padStart(3, '0');
			// Create knight sprite
			knightAssets[dir].push(LK.getAsset('knight-run-' + directionMapping[dir] + '-' + frameNumber, {
				anchorX: 0.5,
				anchorY: 0.5,
				tint: color
			}));
			// Create shadow sprite using the same assets but with modifications
			var shadowSprite = LK.getAsset('knight-run-' + directionMapping[dir] + '-' + frameNumber, {
				anchorX: 0.5,
				anchorY: 0.5
			});
			// Apply shadow properties
			shadowSprite.alpha = 0.5;
			shadowSprite.tint = 0x000000;
			shadowSprite.rotation = Math.PI / 12; // Rotate by 15 degrees (Ο/12 radians)
			shadowSprite.scale.y = 0.5; // Flatten the shadow vertically
			shadowAssets[dir].push(shadowSprite);
		}
		// Initialize idle animation assets (one frame per direction)
		knightIdleAssets[dir] = LK.getAsset('knight-idle-' + directionMapping[dir] + '-001', {
			anchorX: 0.5,
			anchorY: 0.5,
			tint: color
		});
		// Create shadow for idle animation
		var shadowIdleSprite = LK.getAsset('knight-idle-' + directionMapping[dir] + '-001', {
			anchorX: 0.5,
			anchorY: 0.5
		});
		// Apply shadow properties
		shadowIdleSprite.alpha = 0.5;
		shadowIdleSprite.tint = 0x000000;
		shadowIdleSprite.rotation = Math.PI / 12;
		shadowIdleSprite.scale.y = 0.5;
		shadowIdleAssets[dir] = shadowIdleSprite;
	}
	var currentFrame = 0;
	var animationSpeed = 0.2; // Controls how fast the animation plays
	var frameCounter = 0;
	var knightGraphics = knightIdleAssets['down']; // Initialize with the 'down' direction idle asset
	var shadowGraphics = shadowIdleAssets['down']; // Initialize shadow with the 'down' direction idle asset
	// Add shadow first (so it appears behind the knight)
	self.addChild(shadowGraphics);
	// Then add the knight
	self.addChild(knightGraphics);
	knightGraphics.anchor.set(0.5, 0.5);
	knightGraphics.visible = true;
	shadowGraphics.visible = true;
	// Position the shadow slightly offset from the knight
	var shadowOffsetX = -5;
	var shadowOffsetY = 20;
	shadowGraphics.x = shadowOffsetX;
	shadowGraphics.y = shadowOffsetY;
	self.lastDirection = 'down'; // Initialize lastDirection to track previous direction
	self.isMoving = false; // Track if the knight is currently moving
	self.speed = 9;
	self.switchAsset = function (direction) {
		if (!knightGraphics) {
			return;
		}
		// Detach current assets
		// Hide current assets
		knightGraphics.visible = false;
		shadowGraphics.visible = false;
		// Switch to new assets based on direction and movement state
		if (self.isMoving) {
			// Use running animation
			knightGraphics = knightAssets[direction][currentFrame];
			shadowGraphics = shadowAssets[direction][currentFrame];
		} else {
			// Use idle animation
			knightGraphics = knightIdleAssets[direction];
			shadowGraphics = shadowIdleAssets[direction];
		}
		self.addChild(shadowGraphics);
		self.addChild(knightGraphics);
		// Show new assets
		knightGraphics.visible = true;
		shadowGraphics.visible = true;
		// Position the shadow slightly offset from the knight
		shadowGraphics.x = shadowOffsetX;
		shadowGraphics.y = shadowOffsetY;
		// Update last direction
		self.lastDirection = direction;
	};
	self.updateAnimation = function () {
		if (self.isMoving) {
			// Only update animation if moving
			frameCounter += animationSpeed;
			if (frameCounter >= 1) {
				frameCounter = 0;
				currentFrame = (currentFrame + 1) % 8; // Cycle through 8 frames
				if (self.lastDirection) {
					self.switchAsset(self.lastDirection);
				}
			}
		} else if (self.lastDirection) {
			// Make sure we're showing the idle animation when not moving
			self.switchAsset(self.lastDirection);
		}
	};
	self.moveToDirection = function (direction) {
		if (self.lastDirection !== direction) {
			self.switchAsset(direction);
			self.lastDirection = direction;
		}
		switch (direction) {
			case 'up':
				self.y -= self.speed;
				break;
			case 'down':
				self.y += self.speed;
				break;
			case 'left':
				self.x -= self.speed;
				break;
			case 'right':
				self.x += self.speed;
				break;
			case 'up-left':
				self.x -= self.speed / Math.sqrt(2);
				self.y -= self.speed / Math.sqrt(2);
				break;
			case 'up-right':
				self.x += self.speed / Math.sqrt(2);
				self.y -= self.speed / Math.sqrt(2);
				break;
			case 'down-left':
				self.x -= self.speed / Math.sqrt(2);
				self.y += self.speed / Math.sqrt(2);
				break;
			case 'down-right':
				self.x += self.speed / Math.sqrt(2);
				self.y += self.speed / Math.sqrt(2);
				break;
		}
	};
});
var Target = Container.expand(function () {
	var self = Container.call(this);
	self.x = 0;
	self.y = 0;
});
/**** 
* Initialize Game
****/ 
var game = new LK.Game({
	backgroundColor: 0x000000 //Init game with black background 
});
/**** 
* Game Code
****/ 
var gameStarted = false;
var droneManager;
//<Write entity 'classes' with empty functions for important behavior here>
//<Write imports for supported plugins here>
//<Assets used in the game will automatically appear here>
//<Write game logic code here, including initializing arrays and variables>
var DroneManager = function DroneManager() {
	var self = this;
	self.drones = [];
	self.start = function () {
		// Spawn a drone in a random corner
		var currentTargetIndex = Math.floor(Math.random() * corners.length);
		var cornerPosition = corners[currentTargetIndex];
		// Create the drone
		var drone = new Drone();
		// Explicitly set position before adding to the scene
		drone.x = cornerPosition.x;
		drone.y = cornerPosition.y;
		// Store the current target index
		drone.currentTargetIndex = currentTargetIndex;
		// Set the initial target to the current corner position
		drone.target = {
			x: cornerPosition.x,
			y: cornerPosition.y
		};
		// Add to container and array
		middlegroundContainer.addChild(drone);
		self.drones.push(drone);
		// Call selectTarget after adding to scene to start movement
		// This ensures all properties are set before tweening begins
		LK.setTimeout(function () {
			drone.selectTarget();
		}, 100);
	};
};
var backgroundContainer;
var middlegroundContainer;
var foregroundContainer;
var knight;
var target;
var runSoundInterval;
var borderOffset = 380;
var corners = [{
	x: borderOffset,
	y: borderOffset
}, {
	x: 2048 - borderOffset,
	y: borderOffset
}, {
	x: borderOffset,
	y: 2732 - borderOffset
}, {
	x: 2048 - borderOffset,
	y: 2732 - borderOffset
}];
function initializeGame() {
	// Create containers
	backgroundContainer = new Container();
	middlegroundContainer = new Container();
	foregroundContainer = new Container();
	// Add containers to game
	game.addChild(backgroundContainer);
	game.addChild(middlegroundContainer);
	game.addChild(foregroundContainer);
	// Initialize background
	var background = LK.getAsset('background', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	background.x = 2048 / 2;
	background.y = 2732 / 2;
	backgroundContainer.addChild(background);
	// Initialize knight
	knight = new Knight();
	knight.x = 2048 / 2;
	knight.y = 2732 / 2;
	middlegroundContainer.addChild(knight);
	// Initialize target
	target = new Target();
	target.x = knight.x;
	target.y = knight.y;
	foregroundContainer.addChild(target);
	// Initialize sound
	runSoundInterval = LK.setInterval(playRunSound, 350);
	droneManager = new DroneManager();
	LK.setTimeout(function () {
		gameStarted = true;
		droneManager.start();
	}, 1000);
}
function playRunSound() {
	if (knight.isMoving) {
		LK.getSound('knight-run').play();
	}
}
game.down = function (x, y, obj) {
	var game_position = game.toLocal(obj.global);
	target.x = game_position.x;
	target.y = game_position.y;
};
game.update = function () {
	var dx = target.x - knight.x;
	var dy = target.y - knight.y;
	var distance = Math.sqrt(dx * dx + dy * dy);
	var distanceThreshold = 8; // Define a threshold to avoid small movements
	var directionThreshold = 5; // Define a threshold for direction changes to avoid shaking
	if (distance > distanceThreshold) {
		// Set knight to moving state if not already moving
		if (!knight.isMoving) {
			knight.isMoving = true;
			knight.switchAsset(knight.lastDirection || 'down'); // Update asset to running animation
		}
		// Determine the primary direction based on the larger component (dx or dy)
		if (Math.abs(dx) > Math.abs(dy) + directionThreshold) {
			// Horizontal movement dominates
			if (dx > 0) {
				if (dy > directionThreshold) {
					knight.moveToDirection('down-right');
				} else if (dy < -directionThreshold) {
					knight.moveToDirection('up-right');
				} else {
					knight.moveToDirection('right');
				}
			} else {
				if (dy > directionThreshold) {
					knight.moveToDirection('down-left');
				} else if (dy < -directionThreshold) {
					knight.moveToDirection('up-left');
				} else {
					knight.moveToDirection('left');
				}
			}
		} else if (Math.abs(dy) > Math.abs(dx) + directionThreshold) {
			// Vertical movement dominates
			if (dy > 0) {
				if (dx > directionThreshold) {
					knight.moveToDirection('down-right');
				} else if (dx < -directionThreshold) {
					knight.moveToDirection('down-left');
				} else {
					knight.moveToDirection('down');
				}
			} else {
				if (dx > directionThreshold) {
					knight.moveToDirection('up-right');
				} else if (dx < -directionThreshold) {
					knight.moveToDirection('up-left');
				} else {
					knight.moveToDirection('up');
				}
			}
		} else {
			// The difference between dx and dy is small, use diagonal movement
			if (dx > 0 && dy > 0) {
				knight.moveToDirection('down-right');
			} else if (dx > 0 && dy < 0) {
				knight.moveToDirection('up-right');
			} else if (dx < 0 && dy > 0) {
				knight.moveToDirection('down-left');
			} else if (dx < 0 && dy < 0) {
				knight.moveToDirection('up-left');
			}
		}
	} else {
		// Set knight to idle state if currently moving
		if (knight.isMoving) {
			knight.isMoving = false;
			knight.switchAsset(knight.lastDirection || 'down'); // Update asset to idle animation
		}
	}
	// Update knight animation
	knight.updateAnimation();
};
initializeGame(); /**** 
* Plugins
****/ 
var tween = LK.import("@upit/tween.v1");
/**** 
* Classes
****/ 
// Import the tween plugin
var Drone = Container.expand(function () {
	var self = Container.call(this);
	var droneGraphics = LK.getAsset('drone', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	var shadowDrone = LK.getAsset('drone', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	self.shadowOffset = {
		x: -30,
		y: 40
	}; // Define shadow offset property
	shadowDrone.alpha = 0.5;
	shadowDrone.tint = 0x000000;
	//shadowDrone.rotation = Math.PI / 12;
	//shadowDrone.scale.y = 0.5;
	shadowDrone.x = -10;
	shadowDrone.y = 40;
	self.addChild(shadowDrone);
	self.droneScanLaser = LK.getAsset('droneScanLaser', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	self.droneScanBar = LK.getAsset('droneScanBar', {
		anchorX: 0,
		anchorY: 0.5
	});
	self.droneScanLaser.visible = true; // Always visible
	self.droneScanLaser.x = droneGraphics.width * 2;
	self.addChild(self.droneScanLaser);
	self.droneScanBar.x = droneGraphics.width / 2; // droneScanLaser.x; 
	self.droneScanBar.blendMode = 3;
	self.droneScanBar.y = self.droneScanLaser.y;
	self.addChild(self.droneScanBar);
	function loopScanLaserTint() {
		tween(self.droneScanLaser, {
			tint: 0x00FF00
		}, {
			duration: 1000,
			easing: tween.easeInOut,
			onFinish: function onFinish() {
				tween(self.droneScanLaser, {
					tint: 0x00AA00
				}, {
					duration: 1000,
					easing: tween.easeInOut,
					onFinish: loopScanLaserTint // Recursively call to loop
				});
			}
		});
	}
	loopScanLaserTint(); // Start the loop
	self.droneScanLaser.alpha = 0.3; // Set alpha to 0.3
	function animateScanBar() {
		tween(self.droneScanBar, {
			alpha: 0.3,
			rotation: Math.PI / 6.5
		}, {
			duration: 1000,
			easing: tween.easeInOut,
			onFinish: function onFinish() {
				tween(self.droneScanBar, {
					alpha: 0.6,
					rotation: -Math.PI / 6.5
				}, {
					duration: 1000,
					easing: tween.easeInOut,
					onFinish: animateScanBar // Recursively call to loop
				}); // Ensure the tween is started
			}
		}); // Ensure the tween is started
	}
	animateScanBar(); // Start the loop
	self.addChild(droneGraphics);
	self.speed = 5;
	self.state = 'scanning'; // Possible states: scanning, tracking, attacking
	self.fireRange = 300; // Example fire range value
	self.currentTargetIndex = 0;
	self.target = {
		x: 0,
		y: 0
	};
	self.selectTarget = function () {
		var newTargetIndex;
		do {
			newTargetIndex = Math.floor(Math.random() * corners.length);
		} while (newTargetIndex === self.currentTargetIndex);
		self.currentTargetIndex = newTargetIndex;
		self.target = corners[newTargetIndex];
		var distance = Math.sqrt(Math.pow(self.target.x - self.x, 2) + Math.pow(self.target.y - self.y, 2));
		var moveSpeed = 0.2; // Adjust this value to control drone speed
		var duration = distance / moveSpeed; // Calculate duration based on distance and speed
		// Calculate rotation angle before starting movement
		var dx = self.target.x - self.x;
		var dy = self.target.y - self.y;
		tween(self, {
			rotation: Math.atan2(dy, dx)
		}, {
			duration: 1000,
			easing: tween.easeInOut,
			onUpdate: function onUpdate() {
				shadowDrone.x = self.shadowOffset.x * Math.cos(self.rotation);
				shadowDrone.y = self.shadowOffset.y * Math.sin(self.rotation);
			},
			onFinish: function onFinish() {
				tween(self, {
					x: self.target.x,
					y: self.target.y
				}, {
					duration: duration,
					easing: tween.easeInOut,
					onFinish: function onFinish() {
						self.selectTarget();
					}
				});
			}
		});
	};
	self.update = function () {
		if (self.state === 'scanning') {
			// Check for intersection with knight
			if (self.droneScanLaser.intersects(knight)) {
				self.state = 'attacking';
				console.log("Drone switched to attacking mode!");
			}
			// We don't need the distance calculation and threshold check anymore
			// since the tween handles movement and calls selectTarget when done
			// We still want to update rotation during movement for a more natural look
			if (self.target) {
				var dx = self.target.x - self.x;
				var dy = self.target.y - self.y;
				// Only update rotation if we're still moving (distance > small threshold)
				var distance = Math.sqrt(dx * dx + dy * dy);
				shadowDrone.x = self.shadowOffset.x * Math.cos(self.rotation);
				shadowDrone.y = self.shadowOffset.y * Math.sin(self.rotation);
			}
			// Update droneScanBar width based on its rotation
			self.droneScanBar.width = 600 * (1 + 0.46 * Math.abs(Math.sin(self.droneScanBar.rotation)));
		}
	};
});
var Knight = Container.expand(function () {
	var self = Container.call(this);
	// Add boundingBox for collision detection
	var boundingBox = LK.getAsset('boundingBox', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	self.addChild(boundingBox);
	boundingBox.visible = false; // Set to false if you don't want it visible
	var directionMapping = {
		'down-left': 'dir1',
		'left': 'dir2',
		'up-left': 'dir3',
		'up': 'dir4',
		'up-right': 'dir5',
		'right': 'dir6',
		'down-right': 'dir7',
		'down': 'dir8'
	};
	// Pre-create a list of assets for each direction
	var knightAssets = {};
	var shadowAssets = {}; // Shadow assets for the knight
	var knightIdleAssets = {}; // Idle assets for the knight
	var shadowIdleAssets = {}; // Shadow idle assets for the knight
	var color = 0xFFFFFF; // Original blue / 0xff4d4d; // Red / 0x9aff9a; // Green
	// Initialize run animation assets
	for (var dir in directionMapping) {
		knightAssets[dir] = [];
		shadowAssets[dir] = []; // Initialize shadow assets array for each direction
		for (var i = 1; i <= 8; i++) {
			var frameNumber = i.toString().padStart(3, '0');
			// Create knight sprite
			knightAssets[dir].push(LK.getAsset('knight-run-' + directionMapping[dir] + '-' + frameNumber, {
				anchorX: 0.5,
				anchorY: 0.5,
				tint: color
			}));
			// Create shadow sprite using the same assets but with modifications
			var shadowSprite = LK.getAsset('knight-run-' + directionMapping[dir] + '-' + frameNumber, {
				anchorX: 0.5,
				anchorY: 0.5
			});
			// Apply shadow properties
			shadowSprite.alpha = 0.5;
			shadowSprite.tint = 0x000000;
			shadowSprite.rotation = Math.PI / 12; // Rotate by 15 degrees (Ο/12 radians)
			shadowSprite.scale.y = 0.5; // Flatten the shadow vertically
			shadowAssets[dir].push(shadowSprite);
		}
		// Initialize idle animation assets (one frame per direction)
		knightIdleAssets[dir] = LK.getAsset('knight-idle-' + directionMapping[dir] + '-001', {
			anchorX: 0.5,
			anchorY: 0.5,
			tint: color
		});
		// Create shadow for idle animation
		var shadowIdleSprite = LK.getAsset('knight-idle-' + directionMapping[dir] + '-001', {
			anchorX: 0.5,
			anchorY: 0.5
		});
		// Apply shadow properties
		shadowIdleSprite.alpha = 0.5;
		shadowIdleSprite.tint = 0x000000;
		shadowIdleSprite.rotation = Math.PI / 12;
		shadowIdleSprite.scale.y = 0.5;
		shadowIdleAssets[dir] = shadowIdleSprite;
	}
	var currentFrame = 0;
	var animationSpeed = 0.2; // Controls how fast the animation plays
	var frameCounter = 0;
	var knightGraphics = knightIdleAssets['down']; // Initialize with the 'down' direction idle asset
	var shadowGraphics = shadowIdleAssets['down']; // Initialize shadow with the 'down' direction idle asset
	// Add shadow first (so it appears behind the knight)
	self.addChild(shadowGraphics);
	// Then add the knight
	self.addChild(knightGraphics);
	knightGraphics.anchor.set(0.5, 0.5);
	knightGraphics.visible = true;
	shadowGraphics.visible = true;
	// Position the shadow slightly offset from the knight
	var shadowOffsetX = -5;
	var shadowOffsetY = 20;
	shadowGraphics.x = shadowOffsetX;
	shadowGraphics.y = shadowOffsetY;
	self.lastDirection = 'down'; // Initialize lastDirection to track previous direction
	self.isMoving = false; // Track if the knight is currently moving
	self.speed = 9;
	self.switchAsset = function (direction) {
		if (!knightGraphics) {
			return;
		}
		// Detach current assets
		// Hide current assets
		knightGraphics.visible = false;
		shadowGraphics.visible = false;
		// Switch to new assets based on direction and movement state
		if (self.isMoving) {
			// Use running animation
			knightGraphics = knightAssets[direction][currentFrame];
			shadowGraphics = shadowAssets[direction][currentFrame];
		} else {
			// Use idle animation
			knightGraphics = knightIdleAssets[direction];
			shadowGraphics = shadowIdleAssets[direction];
		}
		self.addChild(shadowGraphics);
		self.addChild(knightGraphics);
		// Show new assets
		knightGraphics.visible = true;
		shadowGraphics.visible = true;
		// Position the shadow slightly offset from the knight
		shadowGraphics.x = shadowOffsetX;
		shadowGraphics.y = shadowOffsetY;
		// Update last direction
		self.lastDirection = direction;
	};
	self.updateAnimation = function () {
		if (self.isMoving) {
			// Only update animation if moving
			frameCounter += animationSpeed;
			if (frameCounter >= 1) {
				frameCounter = 0;
				currentFrame = (currentFrame + 1) % 8; // Cycle through 8 frames
				if (self.lastDirection) {
					self.switchAsset(self.lastDirection);
				}
			}
		} else if (self.lastDirection) {
			// Make sure we're showing the idle animation when not moving
			self.switchAsset(self.lastDirection);
		}
	};
	self.moveToDirection = function (direction) {
		if (self.lastDirection !== direction) {
			self.switchAsset(direction);
			self.lastDirection = direction;
		}
		switch (direction) {
			case 'up':
				self.y -= self.speed;
				break;
			case 'down':
				self.y += self.speed;
				break;
			case 'left':
				self.x -= self.speed;
				break;
			case 'right':
				self.x += self.speed;
				break;
			case 'up-left':
				self.x -= self.speed / Math.sqrt(2);
				self.y -= self.speed / Math.sqrt(2);
				break;
			case 'up-right':
				self.x += self.speed / Math.sqrt(2);
				self.y -= self.speed / Math.sqrt(2);
				break;
			case 'down-left':
				self.x -= self.speed / Math.sqrt(2);
				self.y += self.speed / Math.sqrt(2);
				break;
			case 'down-right':
				self.x += self.speed / Math.sqrt(2);
				self.y += self.speed / Math.sqrt(2);
				break;
		}
	};
});
var Target = Container.expand(function () {
	var self = Container.call(this);
	self.x = 0;
	self.y = 0;
});
/**** 
* Initialize Game
****/ 
var game = new LK.Game({
	backgroundColor: 0x000000 //Init game with black background 
});
/**** 
* Game Code
****/ 
var gameStarted = false;
var droneManager;
//<Write entity 'classes' with empty functions for important behavior here>
//<Write imports for supported plugins here>
//<Assets used in the game will automatically appear here>
//<Write game logic code here, including initializing arrays and variables>
var DroneManager = function DroneManager() {
	var self = this;
	self.drones = [];
	self.start = function () {
		// Spawn a drone in a random corner
		var currentTargetIndex = Math.floor(Math.random() * corners.length);
		var cornerPosition = corners[currentTargetIndex];
		// Create the drone
		var drone = new Drone();
		// Explicitly set position before adding to the scene
		drone.x = cornerPosition.x;
		drone.y = cornerPosition.y;
		// Store the current target index
		drone.currentTargetIndex = currentTargetIndex;
		// Set the initial target to the current corner position
		drone.target = {
			x: cornerPosition.x,
			y: cornerPosition.y
		};
		// Add to container and array
		middlegroundContainer.addChild(drone);
		self.drones.push(drone);
		// Call selectTarget after adding to scene to start movement
		// This ensures all properties are set before tweening begins
		LK.setTimeout(function () {
			drone.selectTarget();
		}, 100);
	};
};
var backgroundContainer;
var middlegroundContainer;
var foregroundContainer;
var knight;
var target;
var runSoundInterval;
var borderOffset = 380;
var corners = [{
	x: borderOffset,
	y: borderOffset
}, {
	x: 2048 - borderOffset,
	y: borderOffset
}, {
	x: borderOffset,
	y: 2732 - borderOffset
}, {
	x: 2048 - borderOffset,
	y: 2732 - borderOffset
}];
function initializeGame() {
	// Create containers
	backgroundContainer = new Container();
	middlegroundContainer = new Container();
	foregroundContainer = new Container();
	// Add containers to game
	game.addChild(backgroundContainer);
	game.addChild(middlegroundContainer);
	game.addChild(foregroundContainer);
	// Initialize background
	var background = LK.getAsset('background', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	background.x = 2048 / 2;
	background.y = 2732 / 2;
	backgroundContainer.addChild(background);
	// Initialize knight
	knight = new Knight();
	knight.x = 2048 / 2;
	knight.y = 2732 / 2;
	middlegroundContainer.addChild(knight);
	// Initialize target
	target = new Target();
	target.x = knight.x;
	target.y = knight.y;
	foregroundContainer.addChild(target);
	// Initialize sound
	runSoundInterval = LK.setInterval(playRunSound, 350);
	droneManager = new DroneManager();
	LK.setTimeout(function () {
		gameStarted = true;
		droneManager.start();
	}, 1000);
}
function playRunSound() {
	if (knight.isMoving) {
		LK.getSound('knight-run').play();
	}
}
game.down = function (x, y, obj) {
	var game_position = game.toLocal(obj.global);
	target.x = game_position.x;
	target.y = game_position.y;
};
game.update = function () {
	var dx = target.x - knight.x;
	var dy = target.y - knight.y;
	var distance = Math.sqrt(dx * dx + dy * dy);
	var distanceThreshold = 8; // Define a threshold to avoid small movements
	var directionThreshold = 5; // Define a threshold for direction changes to avoid shaking
	if (distance > distanceThreshold) {
		// Set knight to moving state if not already moving
		if (!knight.isMoving) {
			knight.isMoving = true;
			knight.switchAsset(knight.lastDirection || 'down'); // Update asset to running animation
		}
		// Determine the primary direction based on the larger component (dx or dy)
		if (Math.abs(dx) > Math.abs(dy) + directionThreshold) {
			// Horizontal movement dominates
			if (dx > 0) {
				if (dy > directionThreshold) {
					knight.moveToDirection('down-right');
				} else if (dy < -directionThreshold) {
					knight.moveToDirection('up-right');
				} else {
					knight.moveToDirection('right');
				}
			} else {
				if (dy > directionThreshold) {
					knight.moveToDirection('down-left');
				} else if (dy < -directionThreshold) {
					knight.moveToDirection('up-left');
				} else {
					knight.moveToDirection('left');
				}
			}
		} else if (Math.abs(dy) > Math.abs(dx) + directionThreshold) {
			// Vertical movement dominates
			if (dy > 0) {
				if (dx > directionThreshold) {
					knight.moveToDirection('down-right');
				} else if (dx < -directionThreshold) {
					knight.moveToDirection('down-left');
				} else {
					knight.moveToDirection('down');
				}
			} else {
				if (dx > directionThreshold) {
					knight.moveToDirection('up-right');
				} else if (dx < -directionThreshold) {
					knight.moveToDirection('up-left');
				} else {
					knight.moveToDirection('up');
				}
			}
		} else {
			// The difference between dx and dy is small, use diagonal movement
			if (dx > 0 && dy > 0) {
				knight.moveToDirection('down-right');
			} else if (dx > 0 && dy < 0) {
				knight.moveToDirection('up-right');
			} else if (dx < 0 && dy > 0) {
				knight.moveToDirection('down-left');
			} else if (dx < 0 && dy < 0) {
				knight.moveToDirection('up-left');
			}
		}
	} else {
		// Set knight to idle state if currently moving
		if (knight.isMoving) {
			knight.isMoving = false;
			knight.switchAsset(knight.lastDirection || 'down'); // Update asset to idle animation
		}
	}
	// Update knight animation
	knight.updateAnimation();
};
initializeGame();
knight-run
Sound effect
knight-attack
Sound effect
drone-hit
Sound effect
knight-hit
Sound effect
drone-beam
Sound effect
drone-scan
Sound effect
drone-explode
Sound effect
knight-killed
Sound effect
knight-die
Sound effect
knight-win
Sound effect
knight-bonus
Sound effect