var DropEffect = Container.expand(function (x, y, player) {
var self = Container.call(this);
var angle = player.angle + Math.random() * DROP_ANGLE_VARIANCE;
var speed = 10 + Math.random() * 5;
var speedX = Math.cos(angle) * speed;
var speedY = Math.sin(angle) * speed;
var spinSpeed = Math.random() * 0.2 - 0.1;
var scale = 1;
var scaleDecrement = 1 / 60;
var graphics = self.createAsset('pickupProjectile', 'Drop graphics', 0.5, 0.95);
graphics.rotation = Math.random() * MATH_PI_BY_2;
;
self.x = x;
self.y = y;
self.update = update;
;
function update(velocityX, velocityY) {
self.x += speedX - velocityX;
self.y += speedY - velocityY;
scale -= scaleDecrement;
graphics.rotation += spinSpeed;
graphics.scale.set(scale);
return scale <= 0;
}
});
var BloodsplatterEffect = Container.expand(function (x, y) {
var self = Container.call(this);
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.x = x;
self.y = y;
self.update = update;
;
function update(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 (x, y) {
var self = Container.call(this);
var active = false;
var updateTick = 0;
var updatePeriod = 30;
var jumpSpeedMax = 30;
var jumpHeight = 100;
var jumpVelocityX = 0;
var jumpVelocityY = 0;
var jumpDuration = updatePeriod * 2 / 3;
var invulnerabilityBoost = 1.8;
var jumpDistMax = jumpSpeedMax * jumpDuration;
var jumpDistMaxSqr = jumpDistMax * jumpDistMax;
var activationDist = 1000;
var activationDistSqr = activationDist * activationDist;
var despawnY = -2500;
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.alpha = SHADOW_BASE_ALPHA;
;
self.x = x;
self.y = y;
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 boost = player.invulnerable ? invulnerabilityBoost : 1;
var targetPosX = player.x + velocityX * jumpDuration * boost;
var targetPosY = player.y + velocityY * jumpDuration * boost;
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;
}
}
var height = -Math.max(0, updateCurve) * jumpHeight;
graphics.y = height;
graphics.scale.x = player.x < self.x ? -1 : 1;
graphics.scale.y = 1 + Math.min(0, updateCurve);
var shadowScale = (SHADOW_CRITICAL_HEIGHT + height) / SHADOW_CRITICAL_HEIGHT;
shadow.alpha = 0.5 * shadowScale;
shadow.scale.set(shadowScale);
}
self.x += jumpVelocityX - velocityX;
self.y += jumpVelocityY - velocityY;
return self.y < despawnY;
}
});
var Pickup = Container.expand(function (x, y) {
var self = Container.call(this);
var active = false;
var tilted = false;
var flipScaling = 1;
var decorOffset = -0.68;
var flipTickCounter = randomizeFlipTicks();
var graphics = self.createAsset('pickup', 'Pickup graphics', 0.5, 1);
var base = self.createAsset('pickupBase', 'Pickup base', 0.5, 0.5);
var decor = self.createAsset('pickupDecor', 'Pickup decor', 0, 0.45);
decor.x = 6;
decor.y = decorOffset * graphics.height;
;
self.x = x;
self.y = y;
self.update = update;
;
function update(velocityX, velocityY, args) {
var {player} = args;
self.x -= velocityX;
self.y -= velocityY;
var dx = player.x - self.x;
var dy = player.y - self.y;
var distSqr = dx * dx + dy * dy;
if (!active) {
if (distSqr <= PICKUP_COLLECT_SQRDIST) {
activate(args);
} else if (--flipTickCounter <= 0) {
flipScaling *= -1;
decor.scale.set(PICKUP_FLIP_SCALE + Math.random() * (1 - PICKUP_FLIP_SCALE), flipScaling);
flipTickCounter = randomizeFlipTicks();
}
}
if (!tilted && !player.airborne && distSqr <= PICKUP_TILT_SQRDIST) {
tilted = true;
graphics.scale.y = PICKUP_TILT_SCALE + Math.random() * (1 - PICKUP_TILT_SCALE);
graphics.rotation = (PICKUP_TILT_BASE + Math.random() * PICKUP_TILT_VARIANCE) * (Math.sign(velocityX) || 1);
}
return self.y < 0;
}
function randomizeFlipTicks() {
var value = PICKUP_FLIP_BASE + Math.random() * PICKUP_FLIP_VARIANCE;
if (flipScaling < 0) {
value = 2 * Math.sqrt(value);
}
return Math.floor(value);
}
function activate(args) {
var {pickupProjectileList, player, layers} = args;
var projectileX = self.x + decor.x + decor.width / 2;
var projectileY = self.y + decor.y;
pickupProjectileList.push(layers[LAYER_FOREGROUND].addChild(new PickupProjectile(projectileX, projectileY, player)));
decor.destroy();
active = true;
}
});
var PickupProjectile = Container.expand(function (x, y, target) {
var self = Container.call(this);
var graphics = self.createAsset('pickupProjectile', 'Pickup Projectile graphics', 0.5, 0.5);
;
self.x = x;
self.y = y;
self.update = update;
;
function update() {
var targetY = target.y + PLAYER_COLLECTION_HEIGHT - target.rampHeight;
var dx = target.x - self.x;
var dy = targetY - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
var velocityX = dx / distance * PICKUP_SPEED;
var velocityY = dy / distance * PICKUP_SPEED;
self.x += velocityX;
self.y += velocityY;
return distance <= PICKUP_COLLIDE_DIST;
}
});
var LandscapeTile = Container.expand(function (x, y, {lookup, xIndex, yIndex, density, pickups, monsters, player, key, landscapeTiles, layers, rampList}) {
var self = Container.call(this);
var obstructions = [];
var background = self.createAsset('landscapeBackground', 'Landscape background', 0.5, 0.5);
background.width = TILE_SIZE;
background.height = TILE_SIZE;
background.alpha = 0.03;
background.x = yIndex % 2 === 0 ? TILE_BACKGROUND_OFFSET : 0;
;
self.x = x;
self.y = y;
self.activate = activate;
self.active = false;
self.key = key;
self.checkCollision = checkCollision;
;
function checkCollision(player) {
if (!player.airborne) {
var reach = 200;
var dx = Math.abs(player.x - self.x);
var dy = Math.abs(player.y - self.y);
if (dx < TILE_SIZE / 2 + reach && dy < TILE_SIZE / 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 = 300;
var clearanceDistSqr = clearanceDist * clearanceDist;
var spawnBorder = 25;
var cellSize = 150;
var cols = Math.ceil(TILE_SIZE / cellSize);
var rows = Math.ceil(TILE_SIZE / cellSize);
var cellWidth = TILE_SIZE / cols;
var cellHeight = TILE_SIZE / rows;
var landmark;
if (Math.random() <= SPAWN_PICKUP_CHANCE) {
var {pointX, pointY} = randomPointInRect(self.x, self.y, TILE_SIZE, TILE_SIZE, clearanceDist);
pickups.push(landmark = self.parent.addChild(new Pickup(pointX, pointY)));
} else if (Math.random() <= SPAWN_RAMP_CHANCE) {
var {pointX, pointY} = randomPointInRect(self.x, self.y, TILE_SIZE, TILE_SIZE, clearanceDist);
rampList.push(landmark = layers[LAYER_BACKGROUND].addChild(new Ramp(pointX, pointY)));
}
if (player.distanceTravelled > MONSTER_SPAWN_DIST && Math.random() <= SPAWN_MONSTER_CHANCE) {
var {pointX, pointY} = randomPointInRect(self.x, self.y, TILE_SIZE, TILE_SIZE, clearanceDist);
monsters.push(self.parent.addChild(new Monster(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 (landmark) {
var dx = landmark.x - pointX;
var dy = landmark.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(self.addChild(new Obstruction(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 / DIFFICULTY_FACTOR_DIST + 2), 2)) / 100;
if (!lookup[leftKey]) {
landscapeTiles.push(lookup[leftKey] = self.parent.addChild(new LandscapeTile(self.x - TILE_SIZE, self.y, {
key: leftKey,
density: newDensity,
xIndex: xIndex - 1,
yIndex,
landscapeTiles,
rampList,
lookup,
pickups,
monsters,
layers,
player
})));
}
if (!lookup[rightKey]) {
landscapeTiles.push(lookup[rightKey] = self.parent.addChild(new LandscapeTile(self.x + TILE_SIZE, self.y, {
key: rightKey,
density: newDensity,
xIndex: xIndex + 1,
yIndex,
landscapeTiles,
rampList,
lookup,
pickups,
monsters,
layers,
player
})));
}
if (!lookup[downKey]) {
landscapeTiles.push(lookup[downKey] = self.parent.addChild(new LandscapeTile(self.x, self.y + TILE_SIZE, {
key: downKey,
density: newDensity,
yIndex: yIndex + 1,
xIndex,
landscapeTiles,
rampList,
lookup,
pickups,
monsters,
layers,
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 Ramp = Container.expand(function (x, y) {
var self = Container.call(this);
var rampPillar = self.createAsset('rampPillar', 'Ramp pillar graphics', 0.5, 0.5);
var rampShadow = self.createAsset('rampShadow', 'Ramp shadow graphics', 0.5, -0.2);
var rampGraphics = self.createAsset('ramp', 'Ramp graphics', 0.5, 0);
var rampArrow = self.createAsset('rampArrow', 'Ramp direction arrow', 0.5, 0.5);
var hitbox = self.createAsset('hitbox', 'Ramp hitbox', 0.5, 0);
rampShadow.rotation = 0.1;
rampShadow.alpha = SHADOW_BASE_ALPHA;
rampPillar.y = rampGraphics.height;
rampArrow.y = rampGraphics.height / 2;
rampArrow.alpha = 0.85;
hitbox.width = rampGraphics.width;
hitbox.height = 50;
hitbox.alpha = 0;
;
self.x = x;
self.y = y;
self.hitbox = hitbox;
self.update = update;
;
function update(velocityX, velocityY, player) {
self.x -= velocityX;
self.y -= velocityY;
if (self.y < -200) {
return true;
}
if (!player.airborne && player.hitbox.intersects(self.hitbox)) {
player.ramp();
}
}
});
var Obstruction = Container.expand(function (x, y, type) {
var self = Container.call(this);
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.x = x;
self.y = y;
self.active = true;
self.hitbox = hitbox;
self.deactivate = deactivate;
self.scale.set(randomScale, randomScale);
;
function deactivate() {
self.active = false;
graphics.alpha = 0.5;
}
});
var Player = Container.expand(function (x, y) {
var self = Container.call(this);
var speed = 0;
var reduction = 0;
var travelDistX = 0;
var travelDistY = 0;
var rampRemaining = 0;
var rampDuration = 0;
var rampHeightMax = 0;
var playerShadow = self.createAsset('shadow', 'Player shadow', 0.5, 0.5);
var platformGraphics = self.createAsset('platform', 'Platform image', 0.4, 0.5);
var playerFront = self.createAsset('playerFront', 'Player front graphic', 0.5, 1);
var playerSide = self.createAsset('playerSide', 'Player side graphic', 0.5, 1);
var hitbox = self.createAsset('hitbox', 'Player Hitbox', 0.5, 0.5);
playerShadow.alpha = SHADOW_BASE_ALPHA;
playerShadow.width = playerFront.width * 0.6;
playerShadow.height = playerShadow.width * 0.6;
hitbox.width = 25;
hitbox.height = 25;
hitbox.alpha = 0;
;
self.x = x;
self.y = y;
self.angle = 0;
self.netSpeed = 0;
self.airborne = false;
self.rampHeight = 0;
self.invulnerable = false;
self.invulnerableTime = 3 * 60;
self.invulnerableTimer = 0;
self.distanceTravelled = 0;
self.hitbox = hitbox;
self.update = update;
self.ramp = ramp;
;
function update(targetPosition) {
if (self.invulnerable) {
if (--self.invulnerableTimer <= 0) {
self.invulnerable = false;
}
self.alpha = self.invulnerableTimer % 60 < 30 ? 1 : 0.5;
}
if (self.airborne) {
if (--rampRemaining <= 0) {
self.airborne = false;
}
self.rampHeight = rampHeightMax * Math.sin(Math.PI * rampRemaining / rampDuration);
platformGraphics.y = playerFront.y = playerSide.y = -self.rampHeight;
var shadowScale = (SHADOW_CRITICAL_HEIGHT - self.rampHeight) / SHADOW_CRITICAL_HEIGHT;
playerShadow.alpha = SHADOW_BASE_ALPHA * shadowScale;
playerShadow.scale.set(shadowScale);
}
if (!self.airborne) {
var dx = targetPosition.x - self.x;
var dy = targetPosition.y - self.y;
self.angle = angleClamp(Math.atan2(dy, dx));
}
var acceleration = (Math.sin(self.angle) - PLAYER_ACCELERATION_ANGLE) * PLAYER_ACCELERATION_MAGNITUDE;
var boost = self.airborne ? RAMP_SPEED_BOOST : 1;
reduction = self.invulnerable ? 1 - self.invulnerableTimer / self.invulnerableTime : 1;
speed = Math.max(0, speed * PLAYER_DECELERATION_FACTOR + acceleration);
self.netSpeed = speed * reduction * boost;
var velocityX = Math.cos(self.angle) * self.netSpeed;
var velocityY = Math.sin(self.angle) * self.netSpeed;
travelDistX += velocityX;
travelDistY += velocityY;
self.distanceTravelled = Math.sqrt(travelDistX * travelDistX + travelDistY * travelDistY);
if (!self.airborne) {
var facingSide = targetPosition.x < self.x ? -1 : 1;
var criticalAngle = (MATH_PI_BY_2 - self.angle) / MATH_PI_BY_2;
var imageAlpha = speed === 0 || Math.abs(criticalAngle) < PLAYER_FRONTFACE_FACTOR ? 1 : 0;
var tiltAngle = self.netSpeed * criticalAngle / PLAYER_TILT_SPEED_FACTOR;
platformGraphics.rotation = self.angle;
playerFront.rotation = playerSide.rotation = tiltAngle;
playerFront.scale.x = playerSide.scale.x = facingSide;
playerFront.alpha = imageAlpha;
playerSide.alpha = 1 - imageAlpha;
}
return {
velocityX,
velocityY
};
}
function angleClamp(angle) {
return angle >= 0 ? angle : angle < -MATH_PI_BY_2 ? Math.PI : 0;
}
function ramp() {
if (!self.airborne && speed * reduction > RAMP_CRITICAL_SPEED) {
var rampFactor = speed * reduction - RAMP_CRITICAL_REDUX;
self.airborne = true;
rampHeightMax = rampFactor * RAMP_SPEED_HEIGHT;
rampDuration = Math.round(rampFactor * RAMP_SPEED_DURATION);
rampRemaining = rampDuration;
}
}
});
var Trail = Container.expand(function (x, y) {
var self = Container.call(this);
var trailLength = 60;
var trailAlpha = 0.4;
var trailElements = [];
;
self.x = x;
self.y = y;
self.update = update;
;
function update(velocityX, velocityY, active) {
var trailElement = null;
if (active && (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 (x, y) {
var self = Container.call(this);
var score = 0;
var lives = 3;
var lifeIcons = [];
var banner = self.createAsset('banner', 'Interface banner', 0.5, 0.5);
var scoreIcon = self.createAsset('scoreIcon', 'Score icon', 1, 0.5);
var dividor = self.createAsset('scoreDividor', 'Score dividor', 0.5, 0.5);
var scoreText = self.addChild(new Text2(score, {
size: 70,
fill: "#000000",
align: 'left'
}));
var distanceText = self.addChild(new Text2('0 m', {
size: 70,
fill: "#000000",
align: 'right'
}));
var speedText = self.addChild(new Text2('0 m/s', {
size: 70,
fill: "#000000",
align: 'right'
}));
for (var i = 0; i < lives; i++) {
var lifeIcon = self.createAsset('lifeIcon', 'Life icon', 0, 0.5);
lifeIcon.x = dividor.width / 2 + INTERFACE_DIVIDOR_BORDER + i * (lifeIcon.width + INTERFACE_SPACING);
lifeIcons.push(lifeIcon);
}
scoreIcon.x = -(dividor.width / 2 + INTERFACE_DIVIDOR_BORDER);
scoreText.x = scoreIcon.x - (scoreIcon.width + INTERFACE_SPACING);
scoreText.anchor.set(1, 0.5);
speedText.x = STAGE_WIDTH / 2 - 350;
speedText.anchor.set(1, 0.5);
distanceText.x = STAGE_WIDTH / 2 - 350;
distanceText.y = speedText.y + speedText.height + INTERFACE_SPACING;
distanceText.anchor.set(1, 0.5);
;
self.x = x;
self.y = y;
self.update = update;
self.changeScore = changeScore;
self.changeLives = changeLives;
;
function update(distance, netSpeed) {
distanceText.setText(Math.round(distance * SCREEN_METERAGE) + ' m');
speedText.setText((netSpeed * 60 * SCREEN_METERAGE).toFixed(1) + ' m/s');
}
function changeLives(amount) {
lives += amount;
for (var i = 0; i < lifeIcons.length; i++) {
if (i < lives) {
lifeIcons[i].alpha = 1;
lifeIcons[i].tint = 0xFFFFFF;
} else {
lifeIcons[i].alpha = 0.5;
lifeIcons[i].tint = 0x000000;
}
}
if (amount < 0) {
LK.effects.flashScreen(0xaa0000, 300);
if (lives <= 0) {
return true;
}
}
return false;
}
function changeScore(amount) {
var returnValue = amount < 0 && score > 0;
score = Math.max(0, score + amount);
LK.setScore(score);
scoreText.setText(score);
return returnValue;
}
});
var Instructions = Container.expand(function () {
var self = Container.call(this);
var instructionsText = self.addChild(new Text2('Tap, click or drag to change direction', {
size: 50,
fill: "#000000",
align: 'center'
}));
instructionsText.anchor.set(0.5, 1);
instructionsText.x = 0;
instructionsText.y = 800;
});
;
var MATH_PI_BY_2 = Math.PI / 2;
var MATH_PI_BY_180 = Math.PI / 180;
var STAGE_WIDTH = 2048;
var STAGE_HEIGHT = 2732;
var SCREEN_METERAGE = 1 / 150;
var MONSTER_SPAWN_DIST = 100 / SCREEN_METERAGE;
var DIFFICULTY_FACTOR_DIST = 150 / SCREEN_METERAGE;
var TILE_SIZE = 512;
var TILE_MARGIN = TILE_SIZE;
var TILE_BACKGROUND_OFFSET = 100;
var PLAYER_ACCELERATION_ANGLE = 0.1;
var PLAYER_ACCELERATION_MAGNITUDE = 2.0;
var PLAYER_DECELERATION_FACTOR = 0.95;
var PLAYER_TILT_SPEED_FACTOR = 25 * MATH_PI_BY_2;
var PLAYER_COLLECTION_HEIGHT = -100;
var PLAYER_FRONTFACE_FACTOR = 0.2;
var PICKUP_FLIP_BASE = 10;
var PICKUP_FLIP_VARIANCE = 60;
var PICKUP_FLIP_SCALE = 0.8;
var PICKUP_COLLECT_DIST = 300;
var PICKUP_COLLECT_SQRDIST = PICKUP_COLLECT_DIST * PICKUP_COLLECT_DIST;
var PICKUP_TILT_DIST = 50;
var PICKUP_TILT_SQRDIST = PICKUP_TILT_DIST * PICKUP_TILT_DIST;
var PICKUP_TILT_BASE = 5 * MATH_PI_BY_180;
var PICKUP_TILT_VARIANCE = 60 * MATH_PI_BY_180;
var PICKUP_TILT_SCALE = 0.6;
var PICKUP_SPEED = 20;
var PICKUP_COLLIDE_DIST = 50;
var PICKUP_COLLIDE_SQRDIST = PICKUP_COLLIDE_DIST * PICKUP_COLLIDE_DIST;
var SPAWN_PICKUP_CHANCE = 0.05;
var SPAWN_MONSTER_CHANCE = 0.01;
var SPAWN_RAMP_CHANCE = 0.025;
var RAMP_CRITICAL_SPEED = 15.0;
var RAMP_CRITICAL_REDUX = 10;
var RAMP_SPEED_BOOST = 1.25;
var RAMP_SPEED_DURATION = 3.0;
var RAMP_SPEED_HEIGHT = 20.0;
var DROP_ANGLE_VARIANCE = 10 * MATH_PI_BY_180;
var SHADOW_BASE_ALPHA = 0.5;
var SHADOW_CRITICAL_HEIGHT = 1000;
var INTERFACE_HEIGHT_OFFSET = 40;
var INTERFACE_DIVIDOR_BORDER = -80;
var INTERFACE_SPACING = 10;
var LAYER_BACKGROUND = 0;
var LAYER_MIDGROUND = 1;
var LAYER_FOREGROUND = 2;
;
var Game = Container.expand(function () {
var self = Container.call(this);
var playerPosX = Math.round(STAGE_WIDTH / 2);
var playerPosY = Math.round(STAGE_WIDTH / 3);
var landscapeLookup = {};
var landscapeTiles = [];
var pickups = [];
var pickupProjectileList = [];
var monsters = [];
var effects = [];
var rampList = [];
;
var layers = [self.addChild(new Container()), self.addChild(new Container()), self.addChild(new Container())];
var interface = LK.gui.topCenter.addChild(new Interface(0, INTERFACE_HEIGHT_OFFSET));
var instructions = LK.gui.center.addChild(new Instructions());
var trail = layers[LAYER_BACKGROUND].addChild(new Trail(playerPosX, playerPosY));
var player = layers[LAYER_MIDGROUND].addChild(new Player(playerPosX, playerPosY));
landscapeTiles.push(landscapeLookup['0:0'] = layers[LAYER_FOREGROUND].addChild(new LandscapeTile(STAGE_WIDTH / 2, TILE_SIZE / 2, {
density: -1,
lookup: landscapeLookup,
xIndex: 0,
yIndex: 0,
key: '0:0',
landscapeTiles,
rampList,
monsters,
pickups,
layers,
player
})));
var isMouseDown = false;
var targetPosition = {
x: playerPosX,
y: playerPosY
};
LK.stageContainer.setBackgroundColor(0xFFFFFF);
;
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, !player.airborne);
interface.update(player.distanceTravelled, player.netSpeed);
for (var i = landscapeTiles.length - 1; i >= 0; i--) {
var landscapeTile = landscapeTiles[i];
landscapeTile.x -= velocityX;
landscapeTile.y -= velocityY;
if (landscapeTile.y < -(TILE_SIZE / 2 + TILE_MARGIN)) {
landscapeTile.destroy();
landscapeTiles.splice(i, 1);
landscapeLookup[landscapeTile.key] = undefined;
} else if (!landscapeTile.active && landscapeTile.x > -TILE_MARGIN && landscapeTile.x < STAGE_WIDTH + TILE_MARGIN && landscapeTile.y < STAGE_HEIGHT + TILE_MARGIN) {
landscapeTile.activate();
} else if (landscapeTile.checkCollision(player)) {
if (interface.changeScore(-1)) {
effects.push(layers[LAYER_FOREGROUND].addChild(new DropEffect(player.x, player.y + PLAYER_COLLECTION_HEIGHT, player)));
}
if (!player.invulnerable) {
player.invulnerable = true;
player.invulnerableTimer = player.invulnerableTime;
}
}
}
;
var pickupArgs = {
pickupProjectileList,
layers,
player
};
for (var i = pickups.length - 1; i >= 0; i--) {
var pickup = pickups[i];
if (pickup.update(velocityX, velocityY, pickupArgs)) {
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 = rampList.length - 1; i >= 0; i--) {
var ramp = rampList[i];
if (ramp.update(velocityX, velocityY, player)) {
rampList.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 && !player.airborne && monster.hitbox.intersects(player.hitbox)) {
effects.push(layers[LAYER_FOREGROUND].addChild(new BloodsplatterEffect(monster.x, monster.y)));
monster.destroy();
monsters.splice(i, 1);
if (interface.changeLives(-1)) {
LK.showGameOver();
}
}
}
for (var i = pickupProjectileList.length - 1; i >= 0; i--) {
var pickupProjectile = pickupProjectileList[i];
if (pickupProjectile.update()) {
pickupProjectile.destroy();
pickupProjectileList.splice(i, 1);
interface.changeScore(1);
}
}
});
;
function updatePosition(event) {
var pos = event.getLocalPosition(self);
targetPosition.x = pos.x;
targetPosition.y = pos.y;
}
});
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 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 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.
pixel art of a red flag. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows.
pixel art of a red orb. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows.
white
white
pixel art shape of a red arrow pointing downwards. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows.
pixel art banner of a pair of skis crossed. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows.
white