/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
/****
* Classes
****/
var Castle = Container.expand(function () {
var self = Container.call(this);
// Castle base
var castleBase = self.attachAsset('obstacle', {
anchorX: 0.5,
anchorY: 1.0,
x: 0,
y: 0,
scaleX: 2.0,
scaleY: 1.5,
tint: 0x696969
});
// Castle towers
var tower1 = self.attachAsset('obstacle', {
anchorX: 0.5,
anchorY: 1.0,
x: -80,
y: -100,
scaleX: 0.8,
scaleY: 1.8,
tint: 0x555555
});
var tower2 = self.attachAsset('obstacle', {
anchorX: 0.5,
anchorY: 1.0,
x: 80,
y: -100,
scaleX: 0.8,
scaleY: 1.8,
tint: 0x555555
});
// Castle flags
var flag1 = self.attachAsset('scroll', {
anchorX: 0.0,
anchorY: 1.0,
x: -80,
y: -260,
scaleX: 1.2,
scaleY: 1.0,
tint: 0xff0000
});
var flag2 = self.attachAsset('scroll', {
anchorX: 0.0,
anchorY: 1.0,
x: 80,
y: -260,
scaleX: 1.2,
scaleY: 1.0,
tint: 0x0000ff
});
self.speed = -3;
self.update = function () {
self.x += self.speed;
// Flags wave in wind
flag1.rotation = Math.sin(LK.ticks * 0.1) * 0.2;
flag2.rotation = Math.sin(LK.ticks * 0.1 + 1) * 0.2;
};
return self;
});
var Cloud = Container.expand(function (size) {
var self = Container.call(this);
var cloudType = size || 'medium';
var cloudGraphics = self.attachAsset('cloud_' + cloudType, {
anchorX: 0.5,
anchorY: 0.5,
alpha: 0.7
});
self.speed = -1 - Math.random() * 2;
self.driftY = Math.random() * 0.5 - 0.25;
self.update = function () {
self.x += self.speed;
self.y += self.driftY;
// Gentle cloud movement with fog effect
cloudGraphics.alpha = 0.2 + Math.sin(LK.ticks * 0.01) * 0.1;
};
return self;
});
var Dragon = Container.expand(function () {
var self = Container.call(this);
// Main dragon body (center)
var dragonBody = self.attachAsset('dragon_body', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 1.8,
scaleY: 1.6,
tint: 0xff4500
});
// Body segments for segmented look
var bodySegment1 = self.attachAsset('dragon_body', {
anchorX: 0.5,
anchorY: 0.5,
x: -50,
y: 3,
scaleX: 1.6,
scaleY: 1.4,
tint: 0xe03e00
});
var bodySegment2 = self.attachAsset('dragon_body', {
anchorX: 0.5,
anchorY: 0.5,
x: -90,
y: 8,
scaleX: 1.4,
scaleY: 1.2,
tint: 0xcc3700
});
var bodySegment3 = self.attachAsset('dragon_body', {
anchorX: 0.5,
anchorY: 0.5,
x: -125,
y: 12,
scaleX: 1.2,
scaleY: 1.0,
tint: 0xb83500
});
// Dragon head with neck
var dragonNeck = self.attachAsset('dragon_body', {
anchorX: 0.5,
anchorY: 0.5,
x: 80,
y: -10,
scaleX: 1.0,
scaleY: 0.8,
tint: 0xd4451a
});
var dragonHead = self.attachAsset('dragon_head', {
anchorX: 0.5,
anchorY: 0.5,
x: 110,
y: -20,
scaleX: 1.8,
scaleY: 1.7,
tint: 0xb30000
});
// Dragon snout details
var snout = self.attachAsset('dragon_head', {
anchorX: 0.5,
anchorY: 0.5,
x: 140,
y: -15,
scaleX: 0.8,
scaleY: 0.6,
tint: 0x990000
});
// Dragon eyes
var leftEye = self.attachAsset('gem', {
anchorX: 0.5,
anchorY: 0.5,
x: 120,
y: -28,
scaleX: 0.35,
scaleY: 0.35,
tint: 0x00ff00
});
var rightEye = self.attachAsset('gem', {
anchorX: 0.5,
anchorY: 0.5,
x: 120,
y: -12,
scaleX: 0.35,
scaleY: 0.35,
tint: 0x00ff00
});
// Eye pupils
var leftPupil = self.attachAsset('gem', {
anchorX: 0.5,
anchorY: 0.5,
x: 122,
y: -28,
scaleX: 0.15,
scaleY: 0.15,
tint: 0x000000
});
var rightPupil = self.attachAsset('gem', {
anchorX: 0.5,
anchorY: 0.5,
x: 122,
y: -12,
scaleX: 0.15,
scaleY: 0.15,
tint: 0x000000
});
// Dragon nostrils
var leftNostril = self.attachAsset('gem', {
anchorX: 0.5,
anchorY: 0.5,
x: 148,
y: -18,
scaleX: 0.1,
scaleY: 0.1,
tint: 0x000000
});
var rightNostril = self.attachAsset('gem', {
anchorX: 0.5,
anchorY: 0.5,
x: 148,
y: -12,
scaleX: 0.1,
scaleY: 0.1,
tint: 0x000000
});
// Dragon tail segments
var dragonTail1 = self.attachAsset('dragon_tail', {
anchorX: 0.5,
anchorY: 0.5,
x: -155,
y: 5,
scaleX: 1.0,
scaleY: 1.8,
tint: 0xaa2200
});
var dragonTail2 = self.attachAsset('dragon_tail', {
anchorX: 0.5,
anchorY: 0.5,
x: -185,
y: 10,
scaleX: 0.8,
scaleY: 1.5,
tint: 0x993300
});
var dragonTail3 = self.attachAsset('dragon_tail', {
anchorX: 0.5,
anchorY: 0.5,
x: -210,
y: 15,
scaleX: 0.6,
scaleY: 1.2,
tint: 0x882200
});
// Main wings
var leftWing = self.attachAsset('dragon_wing_left', {
anchorX: 0.8,
anchorY: 0.5,
x: -30,
y: -35,
scaleX: 1.8,
scaleY: 1.6
});
var rightWing = self.attachAsset('dragon_wing_right', {
anchorX: 0.2,
anchorY: 0.5,
x: -30,
y: 35,
scaleX: 1.8,
scaleY: 1.6
});
// Wing membranes (inner wing details)
var leftWingMembrane = self.attachAsset('dragon_wing_left', {
anchorX: 0.8,
anchorY: 0.5,
x: -25,
y: -32,
scaleX: 1.4,
scaleY: 1.2,
tint: 0xcc5533,
alpha: 0.7
});
var rightWingMembrane = self.attachAsset('dragon_wing_right', {
anchorX: 0.2,
anchorY: 0.5,
x: -25,
y: 32,
scaleX: 1.4,
scaleY: 1.2,
tint: 0xcc5533,
alpha: 0.7
});
// Wing bones/struts
var leftWingBone1 = self.attachAsset('dragon_tail', {
anchorX: 0.5,
anchorY: 0.5,
x: -50,
y: -45,
scaleX: 0.3,
scaleY: 0.8,
tint: 0x886644,
rotation: -0.5
});
var leftWingBone2 = self.attachAsset('dragon_tail', {
anchorX: 0.5,
anchorY: 0.5,
x: -70,
y: -40,
scaleX: 0.3,
scaleY: 0.6,
tint: 0x886644,
rotation: -0.3
});
var rightWingBone1 = self.attachAsset('dragon_tail', {
anchorX: 0.5,
anchorY: 0.5,
x: -50,
y: 45,
scaleX: 0.3,
scaleY: 0.8,
tint: 0x886644,
rotation: 0.5
});
var rightWingBone2 = self.attachAsset('dragon_tail', {
anchorX: 0.5,
anchorY: 0.5,
x: -70,
y: 40,
scaleX: 0.3,
scaleY: 0.6,
tint: 0x886644,
rotation: 0.3
});
// Dragon horns
var leftHorn = self.attachAsset('dragon_tail', {
anchorX: 0.5,
anchorY: 1.0,
x: 105,
y: -45,
scaleX: 0.2,
scaleY: 0.4,
tint: 0x444444,
rotation: -0.3
});
var rightHorn = self.attachAsset('dragon_tail', {
anchorX: 0.5,
anchorY: 1.0,
x: 115,
y: -45,
scaleX: 0.2,
scaleY: 0.4,
tint: 0x444444,
rotation: 0.3
});
// Dragon belly scales
var bellyScale1 = self.attachAsset('dragon_body', {
anchorX: 0.5,
anchorY: 0.5,
x: 0,
y: 25,
scaleX: 1.4,
scaleY: 0.6,
tint: 0xffaa44,
alpha: 0.8
});
var bellyScale2 = self.attachAsset('dragon_body', {
anchorX: 0.5,
anchorY: 0.5,
x: -45,
y: 28,
scaleX: 1.2,
scaleY: 0.5,
tint: 0xffaa44,
alpha: 0.8
});
var bellyScale3 = self.attachAsset('dragon_body', {
anchorX: 0.5,
anchorY: 0.5,
x: -85,
y: 30,
scaleX: 1.0,
scaleY: 0.4,
tint: 0xffaa44,
alpha: 0.8
});
// Store references for animations
self.dragonBody = dragonBody;
self.dragonHead = dragonHead;
self.leftWing = leftWing;
self.rightWing = rightWing;
self.dragonTail = dragonTail1;
self.bodySegment1 = bodySegment1;
self.bodySegment2 = bodySegment2;
self.velocity = 0;
self.maxVelocity = 10;
self.gravity = 0.4;
self.flapPower = -16;
self.isFlapping = false;
self.wingFlapTimer = 0;
self.flap = function () {
self.velocity = self.flapPower;
self.isFlapping = true;
self.wingFlapTimer = 15; // Duration for wing flap animation
LK.getSound('flap').play();
// Wing flap animation with smoother tweens
tween(self.leftWing, {
rotation: -0.8,
scaleY: 1.8,
scaleX: 1.6
}, {
duration: 80,
easing: tween.easeOut
});
tween(self.rightWing, {
rotation: 0.8,
scaleY: 1.8,
scaleX: 1.6
}, {
duration: 80,
easing: tween.easeOut,
onFinish: function onFinish() {
// Return wings to normal position
tween(self.leftWing, {
rotation: 0.1,
scaleY: 1.6,
scaleX: 1.8
}, {
duration: 120,
easing: tween.easeInOut
});
tween(self.rightWing, {
rotation: -0.1,
scaleY: 1.6,
scaleX: 1.8
}, {
duration: 120,
easing: tween.easeInOut
});
}
});
// Head bob animation with better smoothness
tween(self.dragonHead, {
y: -30,
rotation: -0.1
}, {
duration: 60,
easing: tween.easeOut,
onFinish: function onFinish() {
tween(self.dragonHead, {
y: -20,
rotation: 0
}, {
duration: 80,
easing: tween.easeIn
});
}
});
};
self.update = function () {
// Apply gravity - Flappy Bird style
self.velocity += self.gravity;
// Limit velocity to prevent too fast falling
if (self.velocity > self.maxVelocity) {
self.velocity = self.maxVelocity;
}
if (self.velocity < -self.maxVelocity) {
self.velocity = -self.maxVelocity;
}
// Update position
self.y += self.velocity;
// Flappy Bird style rotation based on velocity
var targetRotation = self.velocity * 0.08;
if (targetRotation > 0.5) targetRotation = 0.5;
if (targetRotation < -0.4) targetRotation = -0.4;
// Smooth rotation transitions
tween.stop(self.dragonBody);
tween(self.dragonBody, {
rotation: targetRotation
}, {
duration: 100,
easing: tween.easeOut
});
tween.stop(self.dragonHead);
tween(self.dragonHead, {
rotation: targetRotation * 0.6
}, {
duration: 80,
easing: tween.easeOut
});
tween.stop(self.dragonTail);
tween(self.dragonTail, {
rotation: targetRotation * 1.4
}, {
duration: 120,
easing: tween.easeOut
});
// Body segments follow with slight delay for more natural movement
tween.stop(self.bodySegment1);
tween(self.bodySegment1, {
rotation: targetRotation * 0.8
}, {
duration: 110,
easing: tween.easeOut
});
tween.stop(self.bodySegment2);
tween(self.bodySegment2, {
rotation: targetRotation * 0.6
}, {
duration: 140,
easing: tween.easeOut
});
// Wing flap timer countdown
if (self.wingFlapTimer > 0) {
self.wingFlapTimer--;
}
// Wings gentle movement when not actively flapping
if (self.wingFlapTimer <= 0) {
var gentleWingMovement = Math.sin(LK.ticks * 0.06) * 0.15;
self.leftWing.rotation = gentleWingMovement + 0.1;
self.rightWing.rotation = -gentleWingMovement - 0.1;
}
// Keep dragon on screen with kill zone boundaries
if (self.y < 120) {
self.y = 120;
self.velocity = Math.max(0, self.velocity);
}
if (self.y > 2612) {
self.y = 2612;
self.velocity = Math.min(0, self.velocity);
}
self.isFlapping = self.wingFlapTimer > 0;
};
return self;
});
var Mountain = Container.expand(function () {
var self = Container.call(this);
// Mountain peak
var mountainPeak = self.attachAsset('obstacle', {
anchorX: 0.5,
anchorY: 1.0,
x: 0,
y: 0,
scaleX: 3.0,
scaleY: 2.5,
tint: 0x696969
});
// Mountain side
var mountainSide = self.attachAsset('obstacle', {
anchorX: 0.5,
anchorY: 1.0,
x: -60,
y: 0,
scaleX: 2.5,
scaleY: 2.0,
tint: 0x778899
});
// Snow cap
var snowCap = self.attachAsset('cloud_small', {
anchorX: 0.5,
anchorY: 1.0,
x: 0,
y: -200,
scaleX: 1.5,
scaleY: 0.6,
tint: 0xfffafa
});
self.speed = -2;
self.update = function () {
self.x += self.speed;
};
return self;
});
var Obstacle = Container.expand(function (type) {
var self = Container.call(this);
var obstacleType = type || 'tree';
self.speed = -4;
self.passed = false;
if (obstacleType === 'tree') {
// Flappy Bird style tree pipe from bottom - much longer
var treePipe = self.attachAsset('obstacle', {
anchorX: 0.5,
anchorY: 0.0,
x: 0,
y: 0,
scaleX: 1.5,
scaleY: 20.0,
tint: 0x228b22
});
// Pipe cap at top
var treeCap = self.attachAsset('obstacle', {
anchorX: 0.5,
anchorY: 0.0,
x: 0,
y: treePipe.height - 40,
scaleX: 2.0,
scaleY: 0.8,
tint: 0x32cd32
});
} else if (obstacleType === 'rock') {
// Rock obstacle from top - much longer
var rockMain = self.attachAsset('obstacle', {
anchorX: 0.5,
anchorY: 1.0,
x: 0,
y: 0,
scaleX: 1.8,
scaleY: 18.0,
tint: 0x696969
});
// Rock cap at bottom
var rockCap = self.attachAsset('obstacle', {
anchorX: 0.5,
anchorY: 1.0,
x: 0,
y: -rockMain.height + 40,
scaleX: 2.2,
scaleY: 0.9,
tint: 0x555555
});
}
self.update = function () {
self.x += self.speed;
};
return self;
});
var Scroll = Container.expand(function () {
var self = Container.call(this);
var scrollGraphics = self.attachAsset('scroll', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = -4;
self.collected = false;
self.update = function () {
self.x += self.speed;
// Gentle sway animation
scrollGraphics.rotation = Math.sin(LK.ticks * 0.02) * 0.1;
};
return self;
});
var Spike = Container.expand(function (type) {
var self = Container.call(this);
var spikeType = type || 'top';
var spikeGraphics = self.attachAsset('spike_' + spikeType, {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = -4;
self.update = function () {
self.x += self.speed;
// Add menacing glow effect
var glowIntensity = 0.8 + Math.sin(LK.ticks * 0.2) * 0.2;
spikeGraphics.alpha = glowIntensity;
// Subtle color shift between dark gray and red
var colorShift = Math.sin(LK.ticks * 0.1);
if (colorShift > 0.3) {
spikeGraphics.tint = 0x4a0000; // Dark red
} else {
spikeGraphics.tint = 0x2c2c2c; // Dark gray
}
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x87ceeb
});
/****
* Game Code
****/
// Game variables
var dragon;
var obstacles = [];
var scrolls = [];
var clouds = [];
var mountains = [];
var castles = [];
var topSpikes = [];
var bottomSpikes = [];
var gameSpeed = 1;
var spawnTimer = 0;
var scrollSpawnTimer = 0;
var cloudSpawnTimer = 0;
var spikeSpawnTimer = 0;
var distance = 0;
var speedMultiplier = 1.00;
// UI Elements
var scoreTxt = new Text2('Score: 0', {
size: 60,
fill: 0xFFFFFF
});
scoreTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(scoreTxt);
var distanceTxt = new Text2('Distance: 0m', {
size: 50,
fill: 0xFFFFFF
});
distanceTxt.anchor.set(1, 0);
distanceTxt.x = -20;
distanceTxt.y = 80;
LK.gui.topRight.addChild(distanceTxt);
var speedTxt = new Text2('1.00x', {
size: 50,
fill: 0xFFFFFF
});
speedTxt.anchor.set(0, 0);
speedTxt.x = 120;
speedTxt.y = 20;
LK.gui.topLeft.addChild(speedTxt);
// Create dragon
dragon = game.addChild(new Dragon());
dragon.x = 400;
dragon.y = 1366;
// Make dragon smaller to fix hitbox
dragon.scaleX = 0.45;
dragon.scaleY = 0.45;
// Ensure dragon is always visible by setting maximum z-index
dragon.zIndex = 10000;
// Create permanent kill zones to prevent camping
createPermanentKillZones();
// Controls
game.down = function (x, y, obj) {
dragon.flap();
};
game.move = function (x, y, obj) {
// Optional: Allow continuous flapping while holding
};
game.up = function (x, y, obj) {
// Release action if needed
};
// Spawn obstacle
function spawnObstacle() {
// Create Flappy Bird style obstacles - always spawn in pairs with gap
var gapSize = 400; // Size of gap between top and bottom obstacles
var gapCenter = 800 + Math.random() * 1200; // Random vertical position for gap center
// Bottom tree pipe
var treeObstacle = new Obstacle('tree');
treeObstacle.x = 2200;
treeObstacle.y = gapCenter + gapSize / 2; // Position bottom of gap
obstacles.push(treeObstacle);
game.addChild(treeObstacle);
// Top rock obstacle
var rockObstacle = new Obstacle('rock');
rockObstacle.x = 2200;
rockObstacle.y = gapCenter - gapSize / 2; // Position top of gap
obstacles.push(rockObstacle);
game.addChild(rockObstacle);
}
// Spawn scroll
function spawnScroll() {
var scroll = new Scroll();
scroll.x = 2200;
scroll.y = 400 + Math.random() * 1900;
scrolls.push(scroll);
game.addChild(scroll);
}
// Spawn cloud
function spawnCloud() {
var cloudSizes = ['small', 'medium', 'large'];
var size = cloudSizes[Math.floor(Math.random() * cloudSizes.length)];
var cloud = new Cloud(size);
cloud.x = 2200;
cloud.y = 200 + Math.random() * 2000;
cloud.zIndex = -200; // Put clouds in far background
cloud.scaleX = 3.5; // Make clouds much bigger
cloud.scaleY = 3.5;
cloud.alpha = 0.3; // Add fog effect - make clouds more transparent
clouds.push(cloud);
game.addChild(cloud);
}
// Create permanent kill zones at top and bottom
function createPermanentKillZones() {
// Top kill zone - continuous barrier
for (var i = 0; i < 30; i++) {
var topKillBrick = new Spike('top');
topKillBrick.x = i * 80;
topKillBrick.y = 30;
topKillBrick.speed = 0; // Static, doesn't move
topSpikes.push(topKillBrick);
game.addChild(topKillBrick);
}
// Bottom kill zone - continuous barrier
for (var j = 0; j < 30; j++) {
var bottomKillBrick = new Spike('bottom');
bottomKillBrick.x = j * 80;
bottomKillBrick.y = 2702;
bottomKillBrick.speed = 0; // Static, doesn't move
bottomSpikes.push(bottomKillBrick);
game.addChild(bottomKillBrick);
}
}
// Spawn deadly spikes at top
function spawnTopSpikes() {
for (var i = 0; i < 8; i++) {
var spike = new Spike('top');
spike.x = 2200 + i * 80;
spike.y = 30;
topSpikes.push(spike);
game.addChild(spike);
}
}
// Spawn deadly spikes at bottom
function spawnBottomSpikes() {
for (var i = 0; i < 8; i++) {
var spike = new Spike('bottom');
spike.x = 2200 + i * 80;
spike.y = 2702;
bottomSpikes.push(spike);
game.addChild(spike);
}
}
// Spawn mountain environment
function spawnMountain() {
var mountain = new Mountain();
mountain.x = 2400;
mountain.y = 2600 + Math.random() * 200; // Position at bottom
mountain.zIndex = -100; // Put mountains in background
mountain.scaleX = 4.0; // Make mountains much bigger
mountain.scaleY = 4.0;
mountain.alpha = 0.4; // Add fog effect - make mountains more transparent
mountains.push(mountain);
game.addChild(mountain);
}
// Spawn castle environment
function spawnCastle() {
var castle = new Castle();
castle.x = 2400;
castle.y = 2500 + Math.random() * 200; // Position at bottom
castle.zIndex = -100; // Put castles in background
castle.scaleX = 3.5; // Make castles much bigger
castle.scaleY = 3.5;
castle.alpha = 0.5; // Add fog effect - make castles more transparent
castles.push(castle);
game.addChild(castle);
}
// Main game loop
game.update = function () {
distance += gameSpeed;
distanceTxt.setText('Distance: ' + Math.floor(distance / 10) + 'm');
// Increase difficulty over time
if (LK.ticks % 1800 === 0) {
// Every 30 seconds
gameSpeed += 0.2;
}
// Spawn obstacles - Flappy Bird style with dynamic spacing based on speed
spawnTimer++;
var dynamicSpawnDelay = Math.floor(160 + (speedMultiplier - 1) * 2000); // Increase spacing as speed increases
if (spawnTimer > dynamicSpawnDelay) {
// More consistent spacing like Flappy Bird, adjusted for speed
spawnObstacle();
spawnTimer = 0;
}
// Spawn scrolls (rare)
scrollSpawnTimer++;
if (scrollSpawnTimer > 600) {
spawnScroll();
scrollSpawnTimer = 0;
}
// Spawn clouds for atmosphere
cloudSpawnTimer++;
if (cloudSpawnTimer > 200 + Math.random() * 300) {
spawnCloud();
cloudSpawnTimer = 0;
}
// Spawn mountains (background environment)
if (LK.ticks % 900 === 0) {
spawnMountain();
}
// Spawn castles (background environment)
if (LK.ticks % 1200 === 0) {
spawnCastle();
}
// Update and clean up mountains
for (var m = mountains.length - 1; m >= 0; m--) {
var mountain = mountains[m];
if (mountain.x < -600) {
mountain.destroy();
mountains.splice(m, 1);
}
}
// Update and clean up castles
for (var ct = castles.length - 1; ct >= 0; ct--) {
var castle = castles[ct];
if (castle.x < -400) {
castle.destroy();
castles.splice(ct, 1);
}
}
// Spawn deadly spikes periodically (less frequent now that we have permanent ones)
spikeSpawnTimer++;
if (spikeSpawnTimer > 800 + Math.random() * 400) {
spawnTopSpikes();
spawnBottomSpikes();
spikeSpawnTimer = 0;
}
// Update and clean up clouds
for (var c = clouds.length - 1; c >= 0; c--) {
var cloud = clouds[c];
if (cloud.x < -400) {
cloud.destroy();
clouds.splice(c, 1);
}
}
// Update and check obstacles
for (var i = obstacles.length - 1; i >= 0; i--) {
var obstacle = obstacles[i];
if (obstacle.lastX === undefined) obstacle.lastX = obstacle.x;
// Remove off-screen obstacles
if (obstacle.lastX >= -100 && obstacle.x < -100) {
obstacle.destroy();
obstacles.splice(i, 1);
continue;
}
// Check collision with dragon
if (dragon.intersects(obstacle)) {
// Enhanced collision effect - shake dragon before game over
tween(dragon, {
x: dragon.x + 20
}, {
duration: 50,
onFinish: function onFinish() {
tween(dragon, {
x: dragon.x - 40
}, {
duration: 50,
onFinish: function onFinish() {
tween(dragon, {
x: dragon.x + 20
}, {
duration: 50,
onFinish: function onFinish() {
// Flash screen and show game over
LK.effects.flashScreen(0xff0000, 1000);
LK.showGameOver();
}
});
}
});
}
});
return;
}
// Score for passing obstacle - 1 point per obstacle
if (!obstacle.passed && obstacle.x < dragon.x - 60) {
obstacle.passed = true;
LK.setScore(LK.getScore() + 1);
speedMultiplier += 0.01;
scoreTxt.setText('Score: ' + LK.getScore());
// Format speed display to show clean decimals (1.1, 1.2, etc)
var displaySpeed = Math.round(speedMultiplier * 100) / 100;
speedTxt.setText(displaySpeed.toFixed(1) + 'x');
}
obstacle.lastX = obstacle.x;
}
// Update and check scrolls
for (var k = scrolls.length - 1; k >= 0; k--) {
var scroll = scrolls[k];
if (scroll.lastX === undefined) scroll.lastX = scroll.x;
// Remove off-screen scrolls
if (scroll.lastX >= -50 && scroll.x < -50) {
scroll.destroy();
scrolls.splice(k, 1);
continue;
}
// Check collection
if (!scroll.collected && dragon.intersects(scroll)) {
scroll.collected = true;
LK.setScore(LK.getScore() + 100);
scoreTxt.setText('Score: ' + LK.getScore());
LK.getSound('collect').play();
// Scroll collection effect
tween(scroll, {
alpha: 0,
scaleX: 1.5,
scaleY: 1.5
}, {
duration: 400,
onFinish: function onFinish() {
scroll.destroy();
}
});
scrolls.splice(k, 1);
continue;
}
scroll.lastX = scroll.x;
}
// Update and clean up top spikes
for (var s1 = topSpikes.length - 1; s1 >= 0; s1--) {
var topSpike = topSpikes[s1];
if (topSpike.x < -100) {
topSpike.destroy();
topSpikes.splice(s1, 1);
continue;
}
// Check deadly collision with dragon
if (dragon.intersects(topSpike)) {
// Enhanced death effect - make dragon flash red
tween(dragon, {
tint: 0xff0000,
scaleX: 1.3,
scaleY: 1.3
}, {
duration: 200,
onFinish: function onFinish() {
LK.effects.flashScreen(0xff0000, 1500);
LK.showGameOver();
}
});
return;
}
}
// Update and clean up bottom spikes
for (var s2 = bottomSpikes.length - 1; s2 >= 0; s2--) {
var bottomSpike = bottomSpikes[s2];
if (bottomSpike.x < -100) {
bottomSpike.destroy();
bottomSpikes.splice(s2, 1);
continue;
}
// Check deadly collision with dragon
if (dragon.intersects(bottomSpike)) {
// Enhanced death effect - make dragon flash red
tween(dragon, {
tint: 0xff0000,
scaleX: 1.3,
scaleY: 1.3
}, {
duration: 200,
onFinish: function onFinish() {
LK.effects.flashScreen(0xff0000, 1500);
LK.showGameOver();
}
});
return;
}
}
// Win condition - survive long enough
if (LK.getScore() >= 2000) {
LK.showYouWin();
}
};
// Start background music
LK.playMusic('flight'); /****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
/****
* Classes
****/
var Castle = Container.expand(function () {
var self = Container.call(this);
// Castle base
var castleBase = self.attachAsset('obstacle', {
anchorX: 0.5,
anchorY: 1.0,
x: 0,
y: 0,
scaleX: 2.0,
scaleY: 1.5,
tint: 0x696969
});
// Castle towers
var tower1 = self.attachAsset('obstacle', {
anchorX: 0.5,
anchorY: 1.0,
x: -80,
y: -100,
scaleX: 0.8,
scaleY: 1.8,
tint: 0x555555
});
var tower2 = self.attachAsset('obstacle', {
anchorX: 0.5,
anchorY: 1.0,
x: 80,
y: -100,
scaleX: 0.8,
scaleY: 1.8,
tint: 0x555555
});
// Castle flags
var flag1 = self.attachAsset('scroll', {
anchorX: 0.0,
anchorY: 1.0,
x: -80,
y: -260,
scaleX: 1.2,
scaleY: 1.0,
tint: 0xff0000
});
var flag2 = self.attachAsset('scroll', {
anchorX: 0.0,
anchorY: 1.0,
x: 80,
y: -260,
scaleX: 1.2,
scaleY: 1.0,
tint: 0x0000ff
});
self.speed = -3;
self.update = function () {
self.x += self.speed;
// Flags wave in wind
flag1.rotation = Math.sin(LK.ticks * 0.1) * 0.2;
flag2.rotation = Math.sin(LK.ticks * 0.1 + 1) * 0.2;
};
return self;
});
var Cloud = Container.expand(function (size) {
var self = Container.call(this);
var cloudType = size || 'medium';
var cloudGraphics = self.attachAsset('cloud_' + cloudType, {
anchorX: 0.5,
anchorY: 0.5,
alpha: 0.7
});
self.speed = -1 - Math.random() * 2;
self.driftY = Math.random() * 0.5 - 0.25;
self.update = function () {
self.x += self.speed;
self.y += self.driftY;
// Gentle cloud movement with fog effect
cloudGraphics.alpha = 0.2 + Math.sin(LK.ticks * 0.01) * 0.1;
};
return self;
});
var Dragon = Container.expand(function () {
var self = Container.call(this);
// Main dragon body (center)
var dragonBody = self.attachAsset('dragon_body', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 1.8,
scaleY: 1.6,
tint: 0xff4500
});
// Body segments for segmented look
var bodySegment1 = self.attachAsset('dragon_body', {
anchorX: 0.5,
anchorY: 0.5,
x: -50,
y: 3,
scaleX: 1.6,
scaleY: 1.4,
tint: 0xe03e00
});
var bodySegment2 = self.attachAsset('dragon_body', {
anchorX: 0.5,
anchorY: 0.5,
x: -90,
y: 8,
scaleX: 1.4,
scaleY: 1.2,
tint: 0xcc3700
});
var bodySegment3 = self.attachAsset('dragon_body', {
anchorX: 0.5,
anchorY: 0.5,
x: -125,
y: 12,
scaleX: 1.2,
scaleY: 1.0,
tint: 0xb83500
});
// Dragon head with neck
var dragonNeck = self.attachAsset('dragon_body', {
anchorX: 0.5,
anchorY: 0.5,
x: 80,
y: -10,
scaleX: 1.0,
scaleY: 0.8,
tint: 0xd4451a
});
var dragonHead = self.attachAsset('dragon_head', {
anchorX: 0.5,
anchorY: 0.5,
x: 110,
y: -20,
scaleX: 1.8,
scaleY: 1.7,
tint: 0xb30000
});
// Dragon snout details
var snout = self.attachAsset('dragon_head', {
anchorX: 0.5,
anchorY: 0.5,
x: 140,
y: -15,
scaleX: 0.8,
scaleY: 0.6,
tint: 0x990000
});
// Dragon eyes
var leftEye = self.attachAsset('gem', {
anchorX: 0.5,
anchorY: 0.5,
x: 120,
y: -28,
scaleX: 0.35,
scaleY: 0.35,
tint: 0x00ff00
});
var rightEye = self.attachAsset('gem', {
anchorX: 0.5,
anchorY: 0.5,
x: 120,
y: -12,
scaleX: 0.35,
scaleY: 0.35,
tint: 0x00ff00
});
// Eye pupils
var leftPupil = self.attachAsset('gem', {
anchorX: 0.5,
anchorY: 0.5,
x: 122,
y: -28,
scaleX: 0.15,
scaleY: 0.15,
tint: 0x000000
});
var rightPupil = self.attachAsset('gem', {
anchorX: 0.5,
anchorY: 0.5,
x: 122,
y: -12,
scaleX: 0.15,
scaleY: 0.15,
tint: 0x000000
});
// Dragon nostrils
var leftNostril = self.attachAsset('gem', {
anchorX: 0.5,
anchorY: 0.5,
x: 148,
y: -18,
scaleX: 0.1,
scaleY: 0.1,
tint: 0x000000
});
var rightNostril = self.attachAsset('gem', {
anchorX: 0.5,
anchorY: 0.5,
x: 148,
y: -12,
scaleX: 0.1,
scaleY: 0.1,
tint: 0x000000
});
// Dragon tail segments
var dragonTail1 = self.attachAsset('dragon_tail', {
anchorX: 0.5,
anchorY: 0.5,
x: -155,
y: 5,
scaleX: 1.0,
scaleY: 1.8,
tint: 0xaa2200
});
var dragonTail2 = self.attachAsset('dragon_tail', {
anchorX: 0.5,
anchorY: 0.5,
x: -185,
y: 10,
scaleX: 0.8,
scaleY: 1.5,
tint: 0x993300
});
var dragonTail3 = self.attachAsset('dragon_tail', {
anchorX: 0.5,
anchorY: 0.5,
x: -210,
y: 15,
scaleX: 0.6,
scaleY: 1.2,
tint: 0x882200
});
// Main wings
var leftWing = self.attachAsset('dragon_wing_left', {
anchorX: 0.8,
anchorY: 0.5,
x: -30,
y: -35,
scaleX: 1.8,
scaleY: 1.6
});
var rightWing = self.attachAsset('dragon_wing_right', {
anchorX: 0.2,
anchorY: 0.5,
x: -30,
y: 35,
scaleX: 1.8,
scaleY: 1.6
});
// Wing membranes (inner wing details)
var leftWingMembrane = self.attachAsset('dragon_wing_left', {
anchorX: 0.8,
anchorY: 0.5,
x: -25,
y: -32,
scaleX: 1.4,
scaleY: 1.2,
tint: 0xcc5533,
alpha: 0.7
});
var rightWingMembrane = self.attachAsset('dragon_wing_right', {
anchorX: 0.2,
anchorY: 0.5,
x: -25,
y: 32,
scaleX: 1.4,
scaleY: 1.2,
tint: 0xcc5533,
alpha: 0.7
});
// Wing bones/struts
var leftWingBone1 = self.attachAsset('dragon_tail', {
anchorX: 0.5,
anchorY: 0.5,
x: -50,
y: -45,
scaleX: 0.3,
scaleY: 0.8,
tint: 0x886644,
rotation: -0.5
});
var leftWingBone2 = self.attachAsset('dragon_tail', {
anchorX: 0.5,
anchorY: 0.5,
x: -70,
y: -40,
scaleX: 0.3,
scaleY: 0.6,
tint: 0x886644,
rotation: -0.3
});
var rightWingBone1 = self.attachAsset('dragon_tail', {
anchorX: 0.5,
anchorY: 0.5,
x: -50,
y: 45,
scaleX: 0.3,
scaleY: 0.8,
tint: 0x886644,
rotation: 0.5
});
var rightWingBone2 = self.attachAsset('dragon_tail', {
anchorX: 0.5,
anchorY: 0.5,
x: -70,
y: 40,
scaleX: 0.3,
scaleY: 0.6,
tint: 0x886644,
rotation: 0.3
});
// Dragon horns
var leftHorn = self.attachAsset('dragon_tail', {
anchorX: 0.5,
anchorY: 1.0,
x: 105,
y: -45,
scaleX: 0.2,
scaleY: 0.4,
tint: 0x444444,
rotation: -0.3
});
var rightHorn = self.attachAsset('dragon_tail', {
anchorX: 0.5,
anchorY: 1.0,
x: 115,
y: -45,
scaleX: 0.2,
scaleY: 0.4,
tint: 0x444444,
rotation: 0.3
});
// Dragon belly scales
var bellyScale1 = self.attachAsset('dragon_body', {
anchorX: 0.5,
anchorY: 0.5,
x: 0,
y: 25,
scaleX: 1.4,
scaleY: 0.6,
tint: 0xffaa44,
alpha: 0.8
});
var bellyScale2 = self.attachAsset('dragon_body', {
anchorX: 0.5,
anchorY: 0.5,
x: -45,
y: 28,
scaleX: 1.2,
scaleY: 0.5,
tint: 0xffaa44,
alpha: 0.8
});
var bellyScale3 = self.attachAsset('dragon_body', {
anchorX: 0.5,
anchorY: 0.5,
x: -85,
y: 30,
scaleX: 1.0,
scaleY: 0.4,
tint: 0xffaa44,
alpha: 0.8
});
// Store references for animations
self.dragonBody = dragonBody;
self.dragonHead = dragonHead;
self.leftWing = leftWing;
self.rightWing = rightWing;
self.dragonTail = dragonTail1;
self.bodySegment1 = bodySegment1;
self.bodySegment2 = bodySegment2;
self.velocity = 0;
self.maxVelocity = 10;
self.gravity = 0.4;
self.flapPower = -16;
self.isFlapping = false;
self.wingFlapTimer = 0;
self.flap = function () {
self.velocity = self.flapPower;
self.isFlapping = true;
self.wingFlapTimer = 15; // Duration for wing flap animation
LK.getSound('flap').play();
// Wing flap animation with smoother tweens
tween(self.leftWing, {
rotation: -0.8,
scaleY: 1.8,
scaleX: 1.6
}, {
duration: 80,
easing: tween.easeOut
});
tween(self.rightWing, {
rotation: 0.8,
scaleY: 1.8,
scaleX: 1.6
}, {
duration: 80,
easing: tween.easeOut,
onFinish: function onFinish() {
// Return wings to normal position
tween(self.leftWing, {
rotation: 0.1,
scaleY: 1.6,
scaleX: 1.8
}, {
duration: 120,
easing: tween.easeInOut
});
tween(self.rightWing, {
rotation: -0.1,
scaleY: 1.6,
scaleX: 1.8
}, {
duration: 120,
easing: tween.easeInOut
});
}
});
// Head bob animation with better smoothness
tween(self.dragonHead, {
y: -30,
rotation: -0.1
}, {
duration: 60,
easing: tween.easeOut,
onFinish: function onFinish() {
tween(self.dragonHead, {
y: -20,
rotation: 0
}, {
duration: 80,
easing: tween.easeIn
});
}
});
};
self.update = function () {
// Apply gravity - Flappy Bird style
self.velocity += self.gravity;
// Limit velocity to prevent too fast falling
if (self.velocity > self.maxVelocity) {
self.velocity = self.maxVelocity;
}
if (self.velocity < -self.maxVelocity) {
self.velocity = -self.maxVelocity;
}
// Update position
self.y += self.velocity;
// Flappy Bird style rotation based on velocity
var targetRotation = self.velocity * 0.08;
if (targetRotation > 0.5) targetRotation = 0.5;
if (targetRotation < -0.4) targetRotation = -0.4;
// Smooth rotation transitions
tween.stop(self.dragonBody);
tween(self.dragonBody, {
rotation: targetRotation
}, {
duration: 100,
easing: tween.easeOut
});
tween.stop(self.dragonHead);
tween(self.dragonHead, {
rotation: targetRotation * 0.6
}, {
duration: 80,
easing: tween.easeOut
});
tween.stop(self.dragonTail);
tween(self.dragonTail, {
rotation: targetRotation * 1.4
}, {
duration: 120,
easing: tween.easeOut
});
// Body segments follow with slight delay for more natural movement
tween.stop(self.bodySegment1);
tween(self.bodySegment1, {
rotation: targetRotation * 0.8
}, {
duration: 110,
easing: tween.easeOut
});
tween.stop(self.bodySegment2);
tween(self.bodySegment2, {
rotation: targetRotation * 0.6
}, {
duration: 140,
easing: tween.easeOut
});
// Wing flap timer countdown
if (self.wingFlapTimer > 0) {
self.wingFlapTimer--;
}
// Wings gentle movement when not actively flapping
if (self.wingFlapTimer <= 0) {
var gentleWingMovement = Math.sin(LK.ticks * 0.06) * 0.15;
self.leftWing.rotation = gentleWingMovement + 0.1;
self.rightWing.rotation = -gentleWingMovement - 0.1;
}
// Keep dragon on screen with kill zone boundaries
if (self.y < 120) {
self.y = 120;
self.velocity = Math.max(0, self.velocity);
}
if (self.y > 2612) {
self.y = 2612;
self.velocity = Math.min(0, self.velocity);
}
self.isFlapping = self.wingFlapTimer > 0;
};
return self;
});
var Mountain = Container.expand(function () {
var self = Container.call(this);
// Mountain peak
var mountainPeak = self.attachAsset('obstacle', {
anchorX: 0.5,
anchorY: 1.0,
x: 0,
y: 0,
scaleX: 3.0,
scaleY: 2.5,
tint: 0x696969
});
// Mountain side
var mountainSide = self.attachAsset('obstacle', {
anchorX: 0.5,
anchorY: 1.0,
x: -60,
y: 0,
scaleX: 2.5,
scaleY: 2.0,
tint: 0x778899
});
// Snow cap
var snowCap = self.attachAsset('cloud_small', {
anchorX: 0.5,
anchorY: 1.0,
x: 0,
y: -200,
scaleX: 1.5,
scaleY: 0.6,
tint: 0xfffafa
});
self.speed = -2;
self.update = function () {
self.x += self.speed;
};
return self;
});
var Obstacle = Container.expand(function (type) {
var self = Container.call(this);
var obstacleType = type || 'tree';
self.speed = -4;
self.passed = false;
if (obstacleType === 'tree') {
// Flappy Bird style tree pipe from bottom - much longer
var treePipe = self.attachAsset('obstacle', {
anchorX: 0.5,
anchorY: 0.0,
x: 0,
y: 0,
scaleX: 1.5,
scaleY: 20.0,
tint: 0x228b22
});
// Pipe cap at top
var treeCap = self.attachAsset('obstacle', {
anchorX: 0.5,
anchorY: 0.0,
x: 0,
y: treePipe.height - 40,
scaleX: 2.0,
scaleY: 0.8,
tint: 0x32cd32
});
} else if (obstacleType === 'rock') {
// Rock obstacle from top - much longer
var rockMain = self.attachAsset('obstacle', {
anchorX: 0.5,
anchorY: 1.0,
x: 0,
y: 0,
scaleX: 1.8,
scaleY: 18.0,
tint: 0x696969
});
// Rock cap at bottom
var rockCap = self.attachAsset('obstacle', {
anchorX: 0.5,
anchorY: 1.0,
x: 0,
y: -rockMain.height + 40,
scaleX: 2.2,
scaleY: 0.9,
tint: 0x555555
});
}
self.update = function () {
self.x += self.speed;
};
return self;
});
var Scroll = Container.expand(function () {
var self = Container.call(this);
var scrollGraphics = self.attachAsset('scroll', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = -4;
self.collected = false;
self.update = function () {
self.x += self.speed;
// Gentle sway animation
scrollGraphics.rotation = Math.sin(LK.ticks * 0.02) * 0.1;
};
return self;
});
var Spike = Container.expand(function (type) {
var self = Container.call(this);
var spikeType = type || 'top';
var spikeGraphics = self.attachAsset('spike_' + spikeType, {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = -4;
self.update = function () {
self.x += self.speed;
// Add menacing glow effect
var glowIntensity = 0.8 + Math.sin(LK.ticks * 0.2) * 0.2;
spikeGraphics.alpha = glowIntensity;
// Subtle color shift between dark gray and red
var colorShift = Math.sin(LK.ticks * 0.1);
if (colorShift > 0.3) {
spikeGraphics.tint = 0x4a0000; // Dark red
} else {
spikeGraphics.tint = 0x2c2c2c; // Dark gray
}
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x87ceeb
});
/****
* Game Code
****/
// Game variables
var dragon;
var obstacles = [];
var scrolls = [];
var clouds = [];
var mountains = [];
var castles = [];
var topSpikes = [];
var bottomSpikes = [];
var gameSpeed = 1;
var spawnTimer = 0;
var scrollSpawnTimer = 0;
var cloudSpawnTimer = 0;
var spikeSpawnTimer = 0;
var distance = 0;
var speedMultiplier = 1.00;
// UI Elements
var scoreTxt = new Text2('Score: 0', {
size: 60,
fill: 0xFFFFFF
});
scoreTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(scoreTxt);
var distanceTxt = new Text2('Distance: 0m', {
size: 50,
fill: 0xFFFFFF
});
distanceTxt.anchor.set(1, 0);
distanceTxt.x = -20;
distanceTxt.y = 80;
LK.gui.topRight.addChild(distanceTxt);
var speedTxt = new Text2('1.00x', {
size: 50,
fill: 0xFFFFFF
});
speedTxt.anchor.set(0, 0);
speedTxt.x = 120;
speedTxt.y = 20;
LK.gui.topLeft.addChild(speedTxt);
// Create dragon
dragon = game.addChild(new Dragon());
dragon.x = 400;
dragon.y = 1366;
// Make dragon smaller to fix hitbox
dragon.scaleX = 0.45;
dragon.scaleY = 0.45;
// Ensure dragon is always visible by setting maximum z-index
dragon.zIndex = 10000;
// Create permanent kill zones to prevent camping
createPermanentKillZones();
// Controls
game.down = function (x, y, obj) {
dragon.flap();
};
game.move = function (x, y, obj) {
// Optional: Allow continuous flapping while holding
};
game.up = function (x, y, obj) {
// Release action if needed
};
// Spawn obstacle
function spawnObstacle() {
// Create Flappy Bird style obstacles - always spawn in pairs with gap
var gapSize = 400; // Size of gap between top and bottom obstacles
var gapCenter = 800 + Math.random() * 1200; // Random vertical position for gap center
// Bottom tree pipe
var treeObstacle = new Obstacle('tree');
treeObstacle.x = 2200;
treeObstacle.y = gapCenter + gapSize / 2; // Position bottom of gap
obstacles.push(treeObstacle);
game.addChild(treeObstacle);
// Top rock obstacle
var rockObstacle = new Obstacle('rock');
rockObstacle.x = 2200;
rockObstacle.y = gapCenter - gapSize / 2; // Position top of gap
obstacles.push(rockObstacle);
game.addChild(rockObstacle);
}
// Spawn scroll
function spawnScroll() {
var scroll = new Scroll();
scroll.x = 2200;
scroll.y = 400 + Math.random() * 1900;
scrolls.push(scroll);
game.addChild(scroll);
}
// Spawn cloud
function spawnCloud() {
var cloudSizes = ['small', 'medium', 'large'];
var size = cloudSizes[Math.floor(Math.random() * cloudSizes.length)];
var cloud = new Cloud(size);
cloud.x = 2200;
cloud.y = 200 + Math.random() * 2000;
cloud.zIndex = -200; // Put clouds in far background
cloud.scaleX = 3.5; // Make clouds much bigger
cloud.scaleY = 3.5;
cloud.alpha = 0.3; // Add fog effect - make clouds more transparent
clouds.push(cloud);
game.addChild(cloud);
}
// Create permanent kill zones at top and bottom
function createPermanentKillZones() {
// Top kill zone - continuous barrier
for (var i = 0; i < 30; i++) {
var topKillBrick = new Spike('top');
topKillBrick.x = i * 80;
topKillBrick.y = 30;
topKillBrick.speed = 0; // Static, doesn't move
topSpikes.push(topKillBrick);
game.addChild(topKillBrick);
}
// Bottom kill zone - continuous barrier
for (var j = 0; j < 30; j++) {
var bottomKillBrick = new Spike('bottom');
bottomKillBrick.x = j * 80;
bottomKillBrick.y = 2702;
bottomKillBrick.speed = 0; // Static, doesn't move
bottomSpikes.push(bottomKillBrick);
game.addChild(bottomKillBrick);
}
}
// Spawn deadly spikes at top
function spawnTopSpikes() {
for (var i = 0; i < 8; i++) {
var spike = new Spike('top');
spike.x = 2200 + i * 80;
spike.y = 30;
topSpikes.push(spike);
game.addChild(spike);
}
}
// Spawn deadly spikes at bottom
function spawnBottomSpikes() {
for (var i = 0; i < 8; i++) {
var spike = new Spike('bottom');
spike.x = 2200 + i * 80;
spike.y = 2702;
bottomSpikes.push(spike);
game.addChild(spike);
}
}
// Spawn mountain environment
function spawnMountain() {
var mountain = new Mountain();
mountain.x = 2400;
mountain.y = 2600 + Math.random() * 200; // Position at bottom
mountain.zIndex = -100; // Put mountains in background
mountain.scaleX = 4.0; // Make mountains much bigger
mountain.scaleY = 4.0;
mountain.alpha = 0.4; // Add fog effect - make mountains more transparent
mountains.push(mountain);
game.addChild(mountain);
}
// Spawn castle environment
function spawnCastle() {
var castle = new Castle();
castle.x = 2400;
castle.y = 2500 + Math.random() * 200; // Position at bottom
castle.zIndex = -100; // Put castles in background
castle.scaleX = 3.5; // Make castles much bigger
castle.scaleY = 3.5;
castle.alpha = 0.5; // Add fog effect - make castles more transparent
castles.push(castle);
game.addChild(castle);
}
// Main game loop
game.update = function () {
distance += gameSpeed;
distanceTxt.setText('Distance: ' + Math.floor(distance / 10) + 'm');
// Increase difficulty over time
if (LK.ticks % 1800 === 0) {
// Every 30 seconds
gameSpeed += 0.2;
}
// Spawn obstacles - Flappy Bird style with dynamic spacing based on speed
spawnTimer++;
var dynamicSpawnDelay = Math.floor(160 + (speedMultiplier - 1) * 2000); // Increase spacing as speed increases
if (spawnTimer > dynamicSpawnDelay) {
// More consistent spacing like Flappy Bird, adjusted for speed
spawnObstacle();
spawnTimer = 0;
}
// Spawn scrolls (rare)
scrollSpawnTimer++;
if (scrollSpawnTimer > 600) {
spawnScroll();
scrollSpawnTimer = 0;
}
// Spawn clouds for atmosphere
cloudSpawnTimer++;
if (cloudSpawnTimer > 200 + Math.random() * 300) {
spawnCloud();
cloudSpawnTimer = 0;
}
// Spawn mountains (background environment)
if (LK.ticks % 900 === 0) {
spawnMountain();
}
// Spawn castles (background environment)
if (LK.ticks % 1200 === 0) {
spawnCastle();
}
// Update and clean up mountains
for (var m = mountains.length - 1; m >= 0; m--) {
var mountain = mountains[m];
if (mountain.x < -600) {
mountain.destroy();
mountains.splice(m, 1);
}
}
// Update and clean up castles
for (var ct = castles.length - 1; ct >= 0; ct--) {
var castle = castles[ct];
if (castle.x < -400) {
castle.destroy();
castles.splice(ct, 1);
}
}
// Spawn deadly spikes periodically (less frequent now that we have permanent ones)
spikeSpawnTimer++;
if (spikeSpawnTimer > 800 + Math.random() * 400) {
spawnTopSpikes();
spawnBottomSpikes();
spikeSpawnTimer = 0;
}
// Update and clean up clouds
for (var c = clouds.length - 1; c >= 0; c--) {
var cloud = clouds[c];
if (cloud.x < -400) {
cloud.destroy();
clouds.splice(c, 1);
}
}
// Update and check obstacles
for (var i = obstacles.length - 1; i >= 0; i--) {
var obstacle = obstacles[i];
if (obstacle.lastX === undefined) obstacle.lastX = obstacle.x;
// Remove off-screen obstacles
if (obstacle.lastX >= -100 && obstacle.x < -100) {
obstacle.destroy();
obstacles.splice(i, 1);
continue;
}
// Check collision with dragon
if (dragon.intersects(obstacle)) {
// Enhanced collision effect - shake dragon before game over
tween(dragon, {
x: dragon.x + 20
}, {
duration: 50,
onFinish: function onFinish() {
tween(dragon, {
x: dragon.x - 40
}, {
duration: 50,
onFinish: function onFinish() {
tween(dragon, {
x: dragon.x + 20
}, {
duration: 50,
onFinish: function onFinish() {
// Flash screen and show game over
LK.effects.flashScreen(0xff0000, 1000);
LK.showGameOver();
}
});
}
});
}
});
return;
}
// Score for passing obstacle - 1 point per obstacle
if (!obstacle.passed && obstacle.x < dragon.x - 60) {
obstacle.passed = true;
LK.setScore(LK.getScore() + 1);
speedMultiplier += 0.01;
scoreTxt.setText('Score: ' + LK.getScore());
// Format speed display to show clean decimals (1.1, 1.2, etc)
var displaySpeed = Math.round(speedMultiplier * 100) / 100;
speedTxt.setText(displaySpeed.toFixed(1) + 'x');
}
obstacle.lastX = obstacle.x;
}
// Update and check scrolls
for (var k = scrolls.length - 1; k >= 0; k--) {
var scroll = scrolls[k];
if (scroll.lastX === undefined) scroll.lastX = scroll.x;
// Remove off-screen scrolls
if (scroll.lastX >= -50 && scroll.x < -50) {
scroll.destroy();
scrolls.splice(k, 1);
continue;
}
// Check collection
if (!scroll.collected && dragon.intersects(scroll)) {
scroll.collected = true;
LK.setScore(LK.getScore() + 100);
scoreTxt.setText('Score: ' + LK.getScore());
LK.getSound('collect').play();
// Scroll collection effect
tween(scroll, {
alpha: 0,
scaleX: 1.5,
scaleY: 1.5
}, {
duration: 400,
onFinish: function onFinish() {
scroll.destroy();
}
});
scrolls.splice(k, 1);
continue;
}
scroll.lastX = scroll.x;
}
// Update and clean up top spikes
for (var s1 = topSpikes.length - 1; s1 >= 0; s1--) {
var topSpike = topSpikes[s1];
if (topSpike.x < -100) {
topSpike.destroy();
topSpikes.splice(s1, 1);
continue;
}
// Check deadly collision with dragon
if (dragon.intersects(topSpike)) {
// Enhanced death effect - make dragon flash red
tween(dragon, {
tint: 0xff0000,
scaleX: 1.3,
scaleY: 1.3
}, {
duration: 200,
onFinish: function onFinish() {
LK.effects.flashScreen(0xff0000, 1500);
LK.showGameOver();
}
});
return;
}
}
// Update and clean up bottom spikes
for (var s2 = bottomSpikes.length - 1; s2 >= 0; s2--) {
var bottomSpike = bottomSpikes[s2];
if (bottomSpike.x < -100) {
bottomSpike.destroy();
bottomSpikes.splice(s2, 1);
continue;
}
// Check deadly collision with dragon
if (dragon.intersects(bottomSpike)) {
// Enhanced death effect - make dragon flash red
tween(dragon, {
tint: 0xff0000,
scaleX: 1.3,
scaleY: 1.3
}, {
duration: 200,
onFinish: function onFinish() {
LK.effects.flashScreen(0xff0000, 1500);
LK.showGameOver();
}
});
return;
}
}
// Win condition - survive long enough
if (LK.getScore() >= 2000) {
LK.showYouWin();
}
};
// Start background music
LK.playMusic('flight');