Code edit (9 edits merged)
Please save this source code
User prompt
add an update function to the Interface class that takes in the player's `distanceTravelled` variable as a parameter, and displays (just the numerical value) the value to the right of the class
User prompt
Fix Bug: 'ReferenceError: DIFFICULTY_FACTOR_DIST is not defined' in this line: 'var newDensity = (1 + Math.pow(Math.log(player.distanceTravelled / DIFFICULTY_FACTOR_DIST + 2), 2)) / 100;' Line Number: 251
User prompt
Fix Bug: 'ReferenceError: MONSTER_SPAWN_DIST is not defined' in this line: 'if (player.distanceTravelled > MONSTER_SPAWN_DIST && Math.random() <= SPAWN_MONSTER_CHANCE) {' Line Number: 223
User prompt
Replace LandscapeTile's distanceFactor and monsterDistance variables with globals called DIFFICULTY_FACTOR_DIST and MONSTER_SPAWN_DIST respectively. Make sure to update all usages of these variables within the LandscapeTile class
Code edit (4 edits merged)
Please save this source code
User prompt
in the ramp update function, return true if the ramp's y becomes less than -200
Code edit (1 edits merged)
Please save this source code
User prompt
Fix Bug: 'TypeError: rampList is undefined' in this line: 'rampList.push(landmark = self.parent.addChild(new Ramp(pointX, pointY)));' Line Number: 223
User prompt
Fix Bug: 'TypeError: rampList is undefined' in this line: 'rampList.push(landmark = self.parent.addChild(new Ramp(pointX, pointY)));' Line Number: 223
Code edit (1 edits merged)
Please save this source code
User prompt
Fix Bug: 'TypeError: parent.addChild is not a function' in this line: 'parent.addChild(self);' Line Number: 342
Code edit (4 edits merged)
Please save this source code
User prompt
create a rampList variable, and iterate through each ramp, calling it's update function
Code edit (7 edits merged)
Please save this source code
User prompt
Fix Bug: 'ReferenceError: graphics is not defined' in this line: 'rampPillar.y = graphics.height;' Line Number: 320
Code edit (1 edits merged)
Please save this source code
User prompt
Fix Bug: 'TypeError: playerGraphics is undefined' in this line: 'playerShadow.y = playerGraphics.height * 0.5;' Line Number: 366
User prompt
the player has a `shadow` asset underneath it
User prompt
ramps have a `rampShadow` asset underneath them
User prompt
ramps have a `rampPillar` asset underneath them
User prompt
if a landscape tile fails to create a pickup (in it's activate method), try create a ramp with a 5% chance
User prompt
add a ramp class with an update method that checks for a collision with the player
Code edit (1 edits merged)
Please save this source code
Code edit (1 edits merged)
Please save this source code
var DropEffect = Container.expand(function (parent, x, y) {
var self = Container.call(this);
parent.addChild(self);
self.x = x;
self.y = y;
var angle = Math.random() * Math.PI * 2;
var speed = 5 + Math.random() * 5;
var velocityX = Math.cos(angle) * speed;
var velocityY = Math.sin(angle) * speed;
var spinSpeed = Math.random() * 0.2 - 0.1;
var scale = 1;
var scaleDecrement = 1 / 60;
var variant = Math.floor(Math.random() * 3);
var graphics = self.createAsset('pickup' + variant, 'Drop graphics', 0.5, 0.95);
graphics.rotation = Math.random() * Math.PI * 2;
self.update = update;
function update(velocityX, velocityY) {
self.x += velocityX;
self.y += velocityY;
scale -= 0.05;
graphics.rotation += spinSpeed;
graphics.scale.set(scale);
return scale <= 0;
}
;
});
var BloodsplatterEffect = Container.expand(function (parent, x, y) {
var self = Container.call(this);
parent.addChild(self);
self.x = x;
self.y = y;
var duration = 15;
var remaining = duration;
var maxScale = 2.0;
var startAlpha = 0.5;
var graphics = self.createAsset('bloodsplatter', 'Bloodsplatter graphics', 0.5, 0.5);
graphics.alpha = startAlpha;
graphics.y = -graphics.height / 2;
self.update = function (velocityX, velocityY) {
var progress = 1 - remaining-- / duration;
if (remaining <= 0) {
return true;
}
graphics.scale.set(1 + (maxScale - 1) * progress);
graphics.alpha = startAlpha * (1 - progress);
self.x -= velocityX;
self.y -= velocityY;
};
});
var Monster = Container.expand(function (parent, x, y) {
var self = Container.call(this);
parent.addChild(self);
self.x = x;
self.y = y;
var active = false;
var updateTick = 0;
var updatePeriod = 60;
var jumpVelocityX = 0;
var jumpVelocityY = 0;
var jumpSpeedMax = 25;
var jumpHeight = 100;
var jumpDuration = updatePeriod * 2 / 3;
var jumpDistMax = jumpSpeedMax * jumpDuration;
var jumpDistMaxSqr = jumpDistMax * jumpDistMax;
var activationDist = 1000;
var activationDistSqr = activationDist * activationDist;
var despawnY = -1500;
var shadowReduction = 0.1;
var shadow = self.createAsset('shadow', 'Monster shadow', 0.45, 1);
var graphics = self.createAsset('monster', 'Monster graphics', 0.5, 1);
graphics.scale.x = Math.random() < 0.5 ? 1 : -1;
shadow.width = graphics.width * 0.9;
shadow.height = graphics.width * 0.45;
shadow.tint = 0x000000;
shadow.alpha = 0.5;
self.jumping = false;
self.hitbox = shadow;
self.update = update;
function update(velocityX, velocityY, player) {
if (!active) {
var dx = player.x - self.x;
var dy = player.y - self.y;
var distSqr = dx * dx + dy * dy;
if (distSqr <= activationDistSqr) {
active = true;
}
}
if (active) {
var updateCurve = (-Math.cos(++updateTick * Math.PI / (updatePeriod / 2)) + 0.5) / 1.5;
if (self.jumping) {
if (updateCurve <= 0) {
self.jumping = false;
jumpVelocityX = 0;
jumpVelocityY = 0;
}
} else {
if (updateCurve > 0) {
var targetPosX = player.x + velocityX * jumpDuration;
var targetPosY = player.y + velocityY * jumpDuration;
var ddx = targetPosX - self.x;
var ddy = targetPosY - self.y;
var angle = Math.atan2(ddy, ddx);
var targetDistSqr = ddx * ddx + ddy * ddy;
var jumpSpeed = jumpSpeedMax * (targetDistSqr >= jumpDistMaxSqr ? 1 : Math.sqrt(targetDistSqr) / jumpDistMax);
jumpVelocityX = Math.cos(angle) * jumpSpeed;
jumpVelocityY = Math.sin(angle) * jumpSpeed;
self.jumping = true;
}
}
graphics.y = -Math.max(0, updateCurve) * jumpHeight;
graphics.scale.x = player.x < self.x ? -1 : 1;
graphics.scale.y = 1 + Math.min(0, updateCurve);
shadow.scale.set(1 - shadowReduction * updateCurve);
}
self.x += jumpVelocityX - velocityX;
self.y += jumpVelocityY - velocityY;
return self.y < despawnY;
}
});
var Pickup = Container.expand(function (parent, x, y) {
var self = Container.call(this);
parent.addChild(self);
self.x = x;
self.y = y;
self.update = update;
var activeDist = 300;
var activeDistSqr = activeDist * activeDist;
var collectDist = 50;
var collectDistSqr = collectDist * collectDist;
var collectSpeed = 25;
var collectOffset = -50;
var active = false;
var variant = Math.floor(Math.random() * 3);
var graphics = self.createAsset('pickup' + variant, 'Pickup graphics', 0.5, 0.95);
var backShadow = self.createAsset('shadow', 'Pickup background shadow', 0.5, 0.5);
var foreShadow = self.createAsset('shadow', 'Pickup foreground shadow', 0.5, 0.5);
foreShadow.width = graphics.width;
foreShadow.height = graphics.width * 0.25;
backShadow.width = graphics.width;
backShadow.height = graphics.width * 0.25;
backShadow.tint = 0x000000;
backShadow.y = -3;
function update(velocityX, velocityY, player) {
var dx = player.x - self.x;
var dy = player.y + collectOffset - self.y;
var distSqr = dx * dx + dy * dy;
if (self.active) {
var dist = Math.sqrt(distSqr);
self.x += dx / dist * collectSpeed;
self.y += dy / dist * collectSpeed;
} else if (distSqr <= activeDistSqr) {
self.active = true;
backShadow.destroy();
foreShadow.destroy();
} else {
self.x -= velocityX;
self.y -= velocityY;
}
return distSqr <= collectDistSqr;
}
});
var LandscapeTile = Container.expand(function (parent, x, y, {lookup, xIndex, yIndex, width, height, density, pickups, monsters, player, key, landscapeTiles}) {
var self = Container.call(this);
parent.addChild(self);
self.x = x;
self.y = y;
var pickupChance = 0.1;
var monsterChance = 0.01;
var distanceFactor = 10000;
var monsterDistance = 20000;
var obstructions = [];
var visual = self.createAsset('hitbox', 'Landscape area', 0.5, 0.5);
visual.alpha = 0;
visual.width = width;
visual.height = height;
self.activate = activate;
self.width = width;
self.height = height;
self.active = false;
self.key = key;
self.checkCollision = checkCollision;
function checkCollision(player) {
var reach = 100;
var dx = Math.abs(player.x - self.x);
var dy = Math.abs(player.y - self.y);
if (dx < width / 2 + reach && dy < height / 2 + reach) {
for (var i = 0; i < obstructions.length; i++) {
var obstruction = obstructions[i];
if (obstruction.active && player.hitbox.intersects(obstruction.hitbox)) {
obstruction.deactivate();
return true;
}
}
}
return false;
}
function activate() {
if (!self.active) {
self.active = true;
var densityChance = density * Math.random();
var obstructionTypes = ['largeTree', 'smallTree', 'smallTree', 'deadTree', 'smallRock', 'smallRock', 'largeRock', 'stump'];
var clearanceDist = 150;
var clearanceDistSqr = clearanceDist * clearanceDist;
var spawnBorder = 25;
var cellSize = 150;
var cols = Math.ceil(width / cellSize);
var rows = Math.ceil(height / cellSize);
var cellWidth = width / cols;
var cellHeight = height / rows;
var pickup;
if (Math.random() <= 0.1) {
var {pointX, pointY} = randomPointInRect(self.x, self.y, width, height, clearanceDist);
pickups.push(pickup = new Pickup(parent, pointX, pointY));
}
if (player.distanceTravelled > monsterDistance && Math.random() <= monsterChance) {
var {pointX, pointY} = randomPointInRect(self.x, self.y, width, height, clearanceDist);
monsters.push(new Monster(parent, self.x, self.y));
}
for (i = 0; i < cols; i++) {
for (j = 0; j < rows; j++) {
if (Math.random() <= densityChance) {
var canPlace = true;
var {pointX, pointY} = randomPointInRect(cellWidth * i, cellHeight * j, cellWidth, cellHeight, spawnBorder);
if (pickup) {
var dx = pickup.x - pointX;
var dy = pickup.y - pointY;
var distSqr = dx * dx + dy * dy;
if (distSqr <= clearanceDistSqr) {
canPlace = false;
}
}
if (canPlace) {
var type = obstructionTypes[Math.floor(Math.random() * obstructionTypes.length)];
obstructions.push(new Obstruction(self, pointX, pointY, type));
}
}
}
}
}
var leftKey = xIndex - 1 + ':' + yIndex;
var rightKey = xIndex + 1 + ':' + yIndex;
var downKey = xIndex + ':' + (yIndex + 1);
var newDensity = (1 + Math.pow(Math.log(player.distanceTravelled / distanceFactor + 1), 2)) / 100;
if (!lookup[leftKey]) {
landscapeTiles.push(lookup[leftKey] = new LandscapeTile(parent, self.x - width, self.y, {
key: leftKey,
density: newDensity,
xIndex: xIndex - 1,
yIndex,
landscapeTiles,
width,
height,
lookup,
pickups,
monsters,
player
}));
}
if (!lookup[rightKey]) {
landscapeTiles.push(lookup[rightKey] = new LandscapeTile(parent, self.x + width, self.y, {
key: rightKey,
density: newDensity,
xIndex: xIndex + 1,
yIndex,
landscapeTiles,
width,
height,
lookup,
pickups,
monsters,
player
}));
}
if (!lookup[downKey]) {
landscapeTiles.push(lookup[downKey] = new LandscapeTile(parent, self.x, self.y + height, {
key: downKey,
density: newDensity,
yIndex: yIndex + 1,
xIndex,
landscapeTiles,
width,
height,
lookup,
pickups,
monsters,
player
}));
}
function randomPointInRect(centerX, centerY, width, height, border = 0) {
var startX = centerX - width / 2 + border;
var startY = centerY - height / 2 + border;
var innerWidth = width - border * 2;
var innerHeight = height - border * 2;
var pointX = startX + Math.random() * innerWidth;
var pointY = startY + Math.random() * innerHeight;
return {
pointX,
pointY
};
}
}
});
var Obstruction = Container.expand(function (parent, x, y, type) {
var self = Container.call(this);
parent.addChild(self);
self.x = x;
self.y = y;
var graphics = self.createAsset(type, 'Obstruction graphics', 0.5, 1);
var hitbox = self.createAsset('hitbox', 'Obstruction hitbox', 0.5, 0.5);
var randomScale = 0.9 + Math.random() * 0.2;
hitbox.y = -25;
hitbox.alpha = 0;
hitbox.width = graphics.width * 0.8;
hitbox.height = graphics.width * 0.45;
self.scale.set(randomScale, randomScale);
self.active = true;
self.hitbox = hitbox;
self.deactivate = deactivate;
function deactivate() {
self.active = false;
graphics.alpha = 0.5;
}
});
var Player = Container.expand(function (parent, x, y) {
var self = Container.call(this);
parent.addChild(self);
self.x = x;
self.y = y;
var speed = 0;
var tiltSpeedFactor = 100;
var invulnerableReduction = 0.75;
var platformGraphics = self.createAsset('platform', 'Platform image', 0.4, 0.5);
var playerGraphics = self.createAsset('player', 'Player character', 0.575, 1);
var hitbox = self.createAsset('hitbox', 'Player Hitbox', 0.5, 0.5);
hitbox.width = 25;
hitbox.height = 25;
hitbox.alpha = 0;
self.invulnerable = false;
self.invulnerableTime = 3 * 60;
self.invulnerableTimer = 0;
self.distanceTravelled = 0;
self.hitbox = hitbox;
self.update = update;
function update(targetPosition) {
if (self.invulnerable) {
if (--self.invulnerableTimer <= 0) {
self.invulnerable = false;
}
self.alpha = self.invulnerableTimer % 60 < 30 ? 1 : 0.5;
}
var dx = targetPosition.x - self.x;
var dy = targetPosition.y - self.y;
var angle = angleClamp(Math.atan2(dy, dx));
var acceleration = (Math.sin(angle) - 0.1) * 2.0;
var reduction = self.invulnerable ? 1 - self.invulnerableTimer / self.invulnerableTime : 1;
speed = Math.max(0, speed * 0.95 + acceleration);
var velocityX = Math.cos(angle) * reduction * speed;
var velocityY = Math.sin(angle) * reduction * speed;
var facingSide = targetPosition.x < self.x ? -1 : 1;
self.distanceTravelled += speed;
platformGraphics.rotation = angle;
playerGraphics.rotation = speed * reduction / tiltSpeedFactor * (Math.PI / 2) * facingSide;
playerGraphics.scale.x = facingSide;
return {
velocityX,
velocityY
};
}
function angleClamp(angle) {
return angle >= 0 ? angle : angle < -Math.PI / 2 ? Math.PI : 0;
}
});
var Trail = Container.expand(function (parent, x, y) {
var self = Container.call(this);
parent.addChild(self);
self.x = x;
self.y = y;
var trailLength = 60;
var trailAlpha = 0.4;
var trailElements = [];
self.update = update;
function update(velocityX, velocityY) {
var trailElement = null;
if (velocityX !== 0 || velocityY !== 0) {
trailElement = self.createAsset('trail', 'Trail element', 0, 0.5);
var angle = Math.atan2(velocityY, velocityX);
var speed = Math.sqrt(velocityX * velocityX + velocityY * velocityY);
trailElement.rotation = angle;
trailElement.scale.x = speed / 100;
}
trailElements.push(trailElement);
if (trailElements.length > trailLength) {
var removedElement = trailElements.shift();
if (removedElement) {
removedElement.destroy();
}
}
for (var i = trailElements.length - 1; i >= 0; i--) {
var element = trailElements[i];
if (element) {
var alpha = trailAlpha * (i / trailLength);
element.x -= velocityX;
element.y -= velocityY;
element.alpha = alpha;
}
}
}
});
var Interface = Container.expand(function (parent, x, y) {
var self = Container.call(this);
parent.addChild(self);
self.x = x;
self.y = y;
var score = 0;
var lives = 3;
var lifeIcons = [];
var scoreIcon = self.createAsset('scoreIcon', 'Score icon', 0.5, 0);
var scoreText = new Text2('| ' + score, {
size: 70,
fill: "#000000",
align: 'left'
});
self.addChild(scoreText);
for (var i = 0; i < lives; i++) {
var lifeIcon = self.createAsset('lifeIcon', 'Life icon', 1, 0);
lifeIcon.x = -10 - i * 60;
lifeIcon.y = scoreIcon.height + 20;
lifeIcons.push(lifeIcon);
}
scoreText.x = -5;
scoreText.y = scoreIcon.height;
scoreText.anchor.set(0, 0);
self.changeScore = changeScore;
self.changeLives = changeLives;
function changeLives(amount) {
lives += amount;
for (var i = 0; i < lifeIcons.length; i++) {
lifeIcons[i].alpha = i < lives ? 1 : 0.5;
}
if (amount < 0) {
LK.effects.flashScreen(0xaa0000, 300);
if (lives <= 0) {
LK.showGameOver();
}
}
}
function changeScore(amount) {
score = Math.max(0, score + amount);
LK.setScore(score);
scoreText.setText('| ' + score);
}
});
var Game = Container.expand(function () {
var self = Container.call(this);
var stageWidth = 2048;
var stageHeight = 2732;
var tileSize = 512;
var playerPosX = Math.round(stageWidth / 2);
var playerPosY = Math.round(stageWidth / 3);
var tileMargin = tileSize;
var background = self.createAsset('background', 'Fullscreen background', 0, 0);
var landscapeLookup = {};
var landscapeTiles = [];
var pickups = [];
var monsters = [];
var effects = [];
var speed = 0;
background.width = stageWidth;
background.height = stageHeight;
var interface = new Interface(self, 0, 10);
LK.gui.topCenter.addChild(interface);
var trail = new Trail(self, playerPosX, playerPosY);
var player = new Player(self, playerPosX, playerPosY);
landscapeTiles.push(landscapeLookup['0:0'] = new LandscapeTile(self, player.x, player.y, {
width: tileSize,
height: tileSize,
density: -1,
lookup: landscapeLookup,
xIndex: 0,
yIndex: 0,
key: '0:0',
landscapeTiles,
monsters,
pickups,
player
}));
var isMouseDown = false;
var targetPosition = {
x: playerPosX,
y: playerPosY
};
stage.on('down', function (obj) {
isMouseDown = true;
updatePosition(obj.event);
});
stage.on('up', function (obj) {
isMouseDown = false;
});
stage.on('move', function (obj) {
if (isMouseDown) {
updatePosition(obj.event);
}
});
LK.on('tick', function () {
var {velocityX, velocityY} = player.update(targetPosition);
trail.update(velocityX, velocityY);
for (var i = landscapeTiles.length - 1; i >= 0; i--) {
var landscapeTile = landscapeTiles[i];
landscapeTile.x -= velocityX;
landscapeTile.y -= velocityY;
if (landscapeTile.y < -(tileSize / 2 + tileMargin)) {
landscapeTile.destroy();
landscapeTiles.splice(i, 1);
landscapeLookup[landscapeTile.key] = undefined;
} else if (!landscapeTile.active && landscapeTile.x > -tileMargin && landscapeTile.x < stageWidth + tileMargin && landscapeTile.y < stageHeight + tileMargin) {
landscapeTile.activate();
} else if (landscapeTile.checkCollision(player)) {
interface.changeScore(-1);
effects.push(new DropEffect(self, player.x, player.y));
if (!player.invulnerable) {
player.invulnerable = true;
player.invulnerableTimer = player.invulnerableTime;
}
}
}
for (var i = pickups.length - 1; i >= 0; i--) {
var pickup = pickups[i];
if (pickup.update(velocityX, velocityY, player)) {
interface.changeScore(1);
pickup.destroy();
pickups.splice(i, 1);
} else if (pickup.y < -(tileSize / 2 + tileMargin) || pickup.active && player.hitbox.intersects(pickup.hitbox)) {
pickup.destroy();
pickups.splice(i, 1);
}
}
for (var i = effects.length - 1; i >= 0; i--) {
var effect = effects[i];
if (effect.update(velocityX, velocityY)) {
effect.destroy();
effects.splice(i, 1);
}
}
for (var i = monsters.length - 1; i >= 0; i--) {
var monster = monsters[i];
if (monster.update(velocityX, velocityY, player)) {
monster.destroy();
monsters.splice(i, 1);
} else if (!monster.jumping && monster.hitbox.intersects(player.hitbox)) {
effects.push(new BloodsplatterEffect(self, monster.x, monster.y));
interface.changeLives(-1);
monster.destroy();
monsters.splice(i, 1);
}
}
});
function updatePosition(event) {
var pos = event.getLocalPosition(self);
targetPosition.x = pos.x;
targetPosition.y = pos.y;
}
});
Pixel art of a Santa. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows.
pixel art of a tree stump covered in snow. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows.
pixel art of a dead tree covered in snow. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows.
pixel art of a christmas tree covered in snow. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows.
pixel art of a spruce tree covered in snow. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows.
pixel art of a rock covered in snow. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows.
pixel art of a christmas present counter. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows.
pixel art of a christmas present. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows.
pixel art of a blue christmas present. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows.
Pixel art heart icon . Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows.
two vertical lines with a blank background.
pixel art of a large, snow covered rock . Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows.
pixel art of skiis . Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows.
pixel art of a floating grinch monster . Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows.
single green firework explosion . Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows.
pixel art of a wooden board covered in snow. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows.
pixel art of a wooden pole with snow at it's base. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows.
tileable white water texture pixel art.