Code edit (3 edits merged)
Please save this source code
User prompt
if a closest enemy was found, increase the baseAngle by the angle from the hero to the closestEnemy
User prompt
In the weaponCross class replace the TODO comment by finding the closest (square distance) child in the midgroundContainer, making sure that the child has tag TAG_ENEMY and not TAG_PROJECTILE
Code edit (2 edits merged)
Please save this source code
User prompt
Rename the midBackContainer to midgroundContainer
User prompt
Remove the midFrontContainer, replacing any occurrences with midBackContainer
Code edit (1 edits merged)
Please save this source code
Code edit (21 edits merged)
Please save this source code
User prompt
Please fix the bug: 'TypeError: e is undefined' in or related to this line: 'LK.effects.flashObject(self.collision, 0xAA0000, 1000);' Line Number: 508
Code edit (1 edits merged)
Please save this source code
Code edit (1 edits merged)
Please save this source code
Code edit (1 edits merged)
Please save this source code
Code edit (2 edits merged)
Please save this source code
User prompt
Please fix the bug: 'ReferenceError: heightDifference is not defined' in or related to this line: 'var dy = hero.y + heightDifference - self.y;' Line Number: 97
Code edit (16 edits merged)
Please save this source code
User prompt
Please fix the bug: 'TypeError: self is undefined' in or related to this line: 'var updateBase = self.update;' Line Number: 117
User prompt
Please fix the bug: 'ReferenceError: WeaponFireball is not defined' in or related to this line: 'startingWeapons.push(backgroundContainer.addChild(new PickupWeapon({' Line Number: 525
Code edit (2 edits merged)
Please save this source code
User prompt
add a hero asset with anchor (0.5, 1.0) to the Hero class
Code edit (1 edits merged)
Please save this source code
User prompt
Please fix the bug: 'ReferenceError: tint is not defined' in or related to this line: 'var bar = self.attachAsset('shapeBox', {' Line Number: 73
Code edit (7 edits merged)
Please save this source code
User prompt
add an outlineSmall asset to the joystickKnob and an outlineLarge asset to the joystick
Code edit (2 edits merged)
Please save this source code
User prompt
add a new sorting container (inheriting from Container) that has an update function that sorts it's children array by their ascending y value
===================================================================
--- original.js
+++ change.js
@@ -79,9 +79,9 @@
anchorY: 0.5,
tint: 0x000000
});
var countTxt = self.addChild(new BorderedText('0', {
- y: config.size / 3,
+ y: config.size / 4,
fill: config.fill,
anchorX: .5,
anchorY: .5
}));
@@ -428,10 +428,10 @@
anchorX: 0.5,
anchorY: 1.0
});
var experienceBar = self.addChild(new ProgressBar({
- y: -heroGraphics.height - 25
- // percentage: 0
+ y: -heroGraphics.height - 25,
+ percentage: 0.01
}));
var healthBar = self.addChild(new ProgressBar({
y: -heroGraphics.height - 35,
tint: HERO_COLOUR
@@ -439,9 +439,9 @@
var levelTxt = self.addChild(new BorderedText('1', {
y: -heroGraphics.height - 30,
anchorX: 0.5,
anchorY: 0.5,
- size: 60
+ size: 65
}));
// Public functions
self.update = function () {
if (!isPaused && joystick.direction !== undefined) {
@@ -474,9 +474,11 @@
};
self.takeDamage = function (amount) {
self.health = Math.max(0, self.health - amount);
healthBar.updatePercentage(self.health / self.healthMax);
- LK.effects.flashObject(self.collision, 0xAA0000, 1000);
+ if (self.collision) {
+ LK.effects.flashObject(self.collision, 0xAA0000, 1000);
+ }
if (self.health <= 0) {
LK.effects.flashScreen(0xAA0000, 1000);
LK.showGameOver();
}
@@ -490,8 +492,230 @@
};
// Enable inheritance
return self;
});
+var Enemy = ConfigContainer.expand(function (config) {
+ var self = ConfigContainer.call(this, config);
+ // Private variables
+ var damageTaken = 0;
+ var cooldown = 0;
+ // Public variables
+ self.healthBar;
+ self.health = 0;
+ self.healthOffset = 0;
+ self.speed = 0;
+ self.fleeRange = 0;
+ self.attackRange = 0;
+ self.attackCooldown = 0;
+ self.animationAlpha = 0;
+ self.xpDropBase = 0;
+ self.xpDropChance = 0;
+ // Public functions
+ self.update = function () {
+ if (!isPaused) {
+ self.animationAlpha++;
+ var state = ENEMY_STATE_MOVE;
+ var dx = hero.x - self.x;
+ var dy = hero.y - self.y;
+ var distanceSqr = dx * dx + dy * dy;
+ if (checkBounds(self.x, self.y, ENEMY_BORDER)) {
+ if (self.fleeRange > 0 && distanceSqr < self.fleeRange * self.fleeRange) {
+ state = ENEMY_STATE_FLEE;
+ } else if (self.attackRange > 0 && distanceSqr <= self.attackRange * self.attackRange) {
+ state = ENEMY_STATE_ATTACK;
+ }
+ }
+ var stateValues = self.adjustState(state, {
+ cooldownAdjustment: 0,
+ speedFactor: 0,
+ canAttack: false
+ });
+ // Perform the movement
+ if (stateValues.speedFactor !== 0) {
+ var distance = Math.sqrt(distanceSqr);
+ self.x += dx / distance * self.speed * stateValues.speedFactor;
+ self.y += dy / distance * self.speed * stateValues.speedFactor;
+ }
+ // Perform the attack if it is ready
+ cooldown += stateValues.cooldownAdjustment;
+ if (stateValues.canAttack && cooldown <= 0) {
+ cooldown = self.attackCooldown;
+ self.onAttack();
+ }
+ // Adjust the owner parent based on the position
+ var newParent = self.y <= hero.y ? midBackContainer : midFrontContainer;
+ if (self.parent !== newParent) {
+ newParent.addChild(self);
+ }
+ self.onUpdate();
+ }
+ };
+ self.adjustState = function (state, stateValues) {
+ switch (state) {
+ case ENEMY_STATE_MOVE:
+ stateValues.speedFactor = 1;
+ break;
+ case ENEMY_STATE_FLEE:
+ stateValues.cooldownAdjustment = self.attackCooldown - cooldown;
+ stateValues.speedFactor = -1;
+ break;
+ case ENEMY_STATE_ATTACK:
+ stateValues.cooldownAdjustment = -1;
+ stateValues.canAttack = true;
+ break;
+ }
+ return stateValues;
+ };
+ self.takeDamage = function (amount) {
+ damageTaken += amount;
+ if (damageTaken >= self.health) {
+ self.callDestroy();
+ }
+ if (!healthBar) {
+ healthBar = self.addChild(new ProgressBar({
+ y: self.healthOffset,
+ tint: ENEMY_COLOUR
+ }));
+ }
+ healthBar.updatePercentage(Math.max(0, 1 - damageTaken / self.health));
+ LK.effects.flashObject(self.graphics, ENEMY_COLOUR, 1000);
+ };
+ self.onDestroy = function () {
+ dropExperience();
+ enemyCount--;
+ foregroundContainer.addChild(new EffectEnemyDeath({
+ x: self.x,
+ y: self.y
+ }));
+ };
+ self.onUpdate = function () {};
+ self.onAttack = function () {};
+ // Private functions
+ function dropExperience() {
+ var amount = self.xpDropBase;
+ if (self.xpDropChance > 0) {
+ for (var i = 0; i <= minorBoonLevels['Luck']; i++) {
+ if (Math.random() < self.xpDropChance) {
+ amount++;
+ }
+ }
+ }
+ if (amount > 0) {
+ backgroundContainer.addChild(new PickupExperience({
+ x: self.x + ENEMY_XP_RANGE * (1 - 2 * Math.random()),
+ y: self.y + ENEMY_XP_RANGE * (1 - 2 * Math.random()),
+ experience: amount
+ }));
+ }
+ }
+ enemyCount++;
+ // Enable inheritance
+ return self;
+});
+var EnemyRanged = Enemy.expand(function (config) {
+ var self = Enemy.call(this, config);
+ var adjustStateBase = self.adjustState;
+ // Public variables
+ self.speed = ENEMY_RANGED_SPEED;
+ self.fleeRange = self.attackRange * ENEMY_RANGED_FLEE_DISTANCE_FACTOR;
+ self.health = ENEMY_RANGED_HEALTH_BASE + ENEMY_RANGED_HEALTH_SCALE * difficultyScale;
+ self.healthOffset = ENEMY_RANGED_HEALTH_OFFSET;
+ self.attackRange = ENEMY_RANGED_RANGE_MIN * ENEMY_RANGED_RANGE_VAR * Math.random();
+ self.attackCooldown = ENEMY_RANGED_ATTACK_COOLDOWN;
+ self.xpDropBase = ENEMY_RANGED_XP_DROP_BASE;
+ self.xpDropChance = ENEMY_RANGED_XP_DROP_CHANCE;
+ self.graphics = self.attachAsset('enemyRanged', {
+ y: ENEMY_RANGED_GRAPHICS_OFFSET,
+ anchorX: 0.6,
+ anchorY: 0.5
+ });
+ // Public functions
+ self.adjustState = function (state, stateValues) {
+ var newStateValues = adjustStateBase(state, stateValues);
+ switch (state) {
+ case ENEMY_STATE_MOVE:
+ newStateValues.cooldownAdjustment += ENEMY_RANGED_MOVE_COOLDOWN_ADJUSTMENT;
+ break;
+ case ENEMY_STATE_FLEE:
+ stateValues.speedFactor *= ENEMY_RANGED_FLEE_SPEED_FACTOR;
+ break;
+ }
+ return newStateValues;
+ };
+ self.onAttack = function () {
+ LK.effects.flashObject(self.graphics, 0x000000, 500);
+ self.parent.addChild(new ProjectileEnemy({
+ x: graphics.x,
+ y: graphics.y,
+ direction: Math.atan2(dy, dx),
+ damage: ENEMY_RANGED_ATTACK_DAMAGE
+ }));
+ };
+ self.onUpdate = function () {
+ // Scale the enemy up and down
+ var newScale = 1 + Math.sin(self.animationAlpha / ENEMY_RANGED_SCALE_PERIOD) * ENEMY_RANGED_SCALE_MAGNITUDE;
+ self.graphics.scale.x = newScale;
+ self.graphics.scale.y = newScale;
+ };
+ // Enable inheritance
+ return self;
+});
+var EnemyBasic = Enemy.expand(function (config) {
+ var self = Enemy.call(this, config);
+ var onDestroyBase = self.onDestroy;
+ // Public variables
+ self.speed = ENEMY_BASIC_SPEED;
+ self.health = ENEMY_BASIC_HEALTH_BASE + ENEMY_BASIC_HEALTH_SCALE * difficultyScale;
+ self.attackRange = ENEMY_BASIC_ATTACK_RANGE;
+ self.attackCooldown = ENEMY_BASIC_ATTACK_COOLDOWN;
+ self.xpDropChance = ENEMY_BASIC_XP_DROP_CHANCE;
+ self.attachAsset('shapeEllipse', {
+ width: 100,
+ height: 10,
+ anchorX: 0.5,
+ anchorY: 0.5,
+ tint: 0x000000,
+ alpha: 0.75
+ });
+ self.graphics = self.attachAsset('enemyBasic', {
+ y: ENEMY_BASIC_GRAPHICS_OFFSET,
+ anchorX: 0.5,
+ anchorY: 0.5
+ });
+ // Public functions
+ self.onUpdate = function () {
+ // Bob the enemy up and down
+ self.graphics.y = ENEMY_BASIC_GRAPHICS_OFFSET + ENEMY_BASIC_BOB_MAGNITUDE * Math.sin(self.animationAlpha / ENEMY_BASIC_BOB_PERIOD);
+ if (self.healthBar) {
+ self.healthOffset = self.graphics.y + ENEMY_BASIC_HEALTH_OFFSET;
+ self.healthBar.y = self.healthOffset;
+ }
+ };
+ self.onAttack = function () {
+ hero.takeDamage(ENEMY_BASIC_ATTACK_DAMAGE);
+ };
+ self.onDestroy = function () {
+ onDestroyBase();
+ if (pickupCrucifixCount < PICKUP_CRUCIFIX_COUNT && Math.random() < Math.sqrt(minorBoonLevels['Luck']) / 100) {
+ backgroundContainer.addChild(new PickupCrucifix({
+ x: self.x,
+ y: self.y
+ }));
+ } else if (pickupHealthCount < PICKUP_HEALTH_COUNT) {
+ for (var k = 0; k <= 1 + minorBoonLevels['Luck']; k++) {
+ if (Math.random() < PICKUP_HEALTH_CHANCE) {
+ backgroundContainer.addChild(new PickupHealing({
+ x: self.x,
+ y: self.y
+ }));
+ break;
+ }
+ }
+ }
+ };
+ // Enable inheritance
+ return self;
+});
/**
* config {
* x : Number || 0, // See: ConfigContainer
* y : Number || 0, // See: ConfigContainer
@@ -558,8 +782,49 @@
buildTextAssets(text);
// Enable inheritance
return self;
});
+var EnemySpawner = Container.expand(function () {
+ var self = Container.call(this);
+ var borderedWidth = GAME_WIDTH - 2 * ENEMY_BORDER_SPAWN;
+ var borderedHeight = GAME_HEIGHT - 2 * ENEMY_BORDER_SPAWN;
+ var spawnTimer = ENEMY_SPAWN_DELAY;
+ self.update = function () {
+ if (enemyCount < ENEMY_LIMIT && --spawnTimer <= 0) {
+ spawnTimer = Math.max(ENEMY_SPAWN_RATE_MIN, ENEMY_SPAWN_RATE_BASE - Math.floor(ENEMY_SPAWN_RATE_SCALE * difficultyScale));
+ var isRanged = difficultyScale >= ENEMY_RANGED_DIFFICULTY && Math.random() < Math.min(ENEMY_RANGED_SPAWN_CHANCE_MIN, ENEMY_RANGED_SPAWN_CHANCE_FACTOR * difficultyScale);
+ var enemyClass = isRanged ? EnemyRanged : EnemyBasic;
+ self.spawnClass(enemyClass);
+ }
+ };
+ self.spawnClass = function (enemyClass) {
+ var spawnX, spawnY;
+ var side = Math.floor(Math.random() * 4);
+ var distance = Math.random();
+ switch (side) {
+ case 0:
+ spawnX = borderedWidth * distance;
+ spawnY = ENEMY_BORDER_SPAWN;
+ break;
+ case 1:
+ spawnX = GAME_WIDTH - ENEMY_BORDER_SPAWN;
+ spawnY = borderedHeight * distance;
+ break;
+ case 2:
+ spawnX = borderedWidth * distance;
+ spawnY = GAME_HEIGHT - ENEMY_BORDER_SPAWN;
+ break;
+ case 3:
+ spawnX = ENEMY_BORDER_SPAWN;
+ spawnY = borderedHeight * distance;
+ break;
+ }
+ midFrontContainer.addChild(new enemyClass({
+ x: spawnX,
+ y: spawnY
+ }));
+ };
+});
var SortingContainer = Container.expand(function () {
var self = Container.call(this);
self.update = function () {
self.children.sort(function (a, b) {
@@ -716,8 +981,9 @@
countdown: 300
}));
;
// Game instances
+game.addChild(new EnemySpawner());
game.attachAsset('grassTop', {
y: HERO_BORDER - 100,
x: GAME_WIDTH / 2,
anchorX: 0.5
@@ -772,9 +1038,7 @@
//==============================================================================
// Global helper functions
//==============================================================================
;
-function checkBounds(x, y) {
- var borderOrBorderX = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : 0;
- var borderY = arguments.length > 3 ? arguments[3] : undefined;
- return x < borderOrBorderX || x > 2048 - borderOrBorderX || y < (borderY || borderOrBorderX) || y > 2732 - (borderY || borderOrBorderX);
+function checkBounds(x, y, border) {
+ return !(x < border || x > GAME_WIDTH - border || y < border || y > GAME_HEIGHT - border);
}
\ No newline at end of file
pixel art cross with blue accents Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows.
pixel art of a white orb. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows.
pixel art of a white orb with a halo. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows.
pixel art of a pulsating white heart with a halo. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows.
pixel art of a dark goo projectile with red highlights. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows.
pixel art tall blue fireball. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows.
pixel art of an evil fantasy sword facing downward. Minor red details. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows.
backgroundAmbient
Sound effect
heroHealed
Sound effect
pickupExperience
Sound effect
heroLeveled
Sound effect
weaponCrossImpact
Sound effect
heroImpact
Sound effect
enemyDeath
Sound effect
pickupWeapon
Sound effect
pickupCrucifix
Sound effect
weaponCrossLaunch
Sound effect
heroDeath
Sound effect
enemyRoar
Sound effect
clockChime
Sound effect