/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
/****
* Classes
****/
// Cactus obstacle
var Cactus = Container.expand(function () {
var self = Container.call(this);
var cactusSprite = self.attachAsset('cactus', {
anchorX: 0.5,
anchorY: 1
});
self.width = cactusSprite.width;
self.height = cactusSprite.height;
self.speed = 0; // Set by game
self.update = function () {
self.x -= self.speed;
};
return self;
});
// Dino (player) class
var Dino = Container.expand(function () {
var self = Container.call(this);
var dinoSprite = self.attachAsset('dino', {
anchorX: 0.5,
anchorY: 1
});
self.width = dinoSprite.width;
self.height = dinoSprite.height;
// State
self.isJumping = false;
self.velocityY = 0;
self.gravity = 2.2 * 1; // gravity is positive, pulls dino down
self.jumpStrength = -48; // negative jumpStrength makes dino go up (y decreases)
self.groundY = 0; // Set after adding to game
// Jump
self.jump = function () {
if (!self.isJumping) {
self.isJumping = true;
self.velocityY = self.jumpStrength;
LK.getSound('jump').play();
}
};
// Update per frame
self.update = function () {
if (self.isJumping) {
self.y += self.velocityY;
self.velocityY += self.gravity;
if (self.y >= self.groundY) {
self.y = self.groundY;
self.isJumping = false;
self.velocityY = 0;
}
}
};
return self;
});
// Pterodactyl obstacle
var Ptero = Container.expand(function () {
var self = Container.call(this);
var pteroSprite = self.attachAsset('ptero', {
anchorX: 0.5,
anchorY: 0.5
});
self.width = pteroSprite.width;
self.height = pteroSprite.height;
self.speed = 0; // Set by game
self.update = function () {
self.x -= self.speed;
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0xf5f5f5
});
/****
* Game Code
****/
// Game constants
// Dinosaur (player)
// Cactus (obstacle)
// Pterodactyl (obstacle)
// Ground
// Jump sound
var GROUND_Y = 2200;
var DINO_START_X = 400;
var OBSTACLE_MIN_GAP = 700;
var OBSTACLE_MAX_GAP = 1200;
var PTERO_MIN_Y = GROUND_Y - 400;
var PTERO_MAX_Y = GROUND_Y - 700;
var GAME_SPEED_START = 22;
var GAME_SPEED_MAX = 60;
var GAME_SPEEDUP_EVERY = 600; // ticks
var GAME_SPEEDUP_AMOUNT = 1.2;
// Game state
var dino;
var ground;
var obstacles = [];
var gameSpeed = GAME_SPEED_START;
var ticksSinceLastObstacle = 0;
var nextObstacleGap = 0;
var score = 0;
var scoreTxt;
var dragNode = null;
var isTouching = false;
var ducking = false;
var lastObstacleType = null;
// Add ground
ground = LK.getAsset('ground', {
anchorX: 0,
anchorY: 0,
x: 0,
y: GROUND_Y + 1
});
game.addChild(ground);
// Add dino
dino = new Dino();
game.addChild(dino);
dino.x = DINO_START_X;
dino.groundY = GROUND_Y;
dino.y = GROUND_Y;
// Score text
scoreTxt = new Text2('0', {
size: 120,
fill: "#222"
});
scoreTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(scoreTxt);
// Helper: spawn obstacle
function spawnObstacle() {
// Increase obstacle variety as score increases
var availableTypes = ['cactus', 'ptero'];
if (score > 500) {
availableTypes.push('double_cactus');
}
if (score > 1200) {
availableTypes.push('low_ptero');
}
if (score > 2000) {
availableTypes.push('triple_cactus');
}
// Randomly pick type, but avoid two pteros in a row
var type = availableTypes[Math.floor(Math.random() * availableTypes.length)];
if ((type === 'ptero' || type === 'low_ptero') && lastObstacleType && (lastObstacleType === 'ptero' || lastObstacleType === 'low_ptero')) {
type = 'cactus';
}
lastObstacleType = type;
var obs;
if (type === 'cactus') {
obs = new Cactus();
obs.x = 2048 + obs.width + Math.floor(Math.random() * 120); // randomize spawn x
obs.y = GROUND_Y;
obs.speed = gameSpeed;
obstacles.push(obs);
game.addChild(obs);
} else if (type === 'double_cactus') {
// Two cacti close together
for (var i = 0; i < 2; i++) {
obs = new Cactus();
obs.x = 2048 + obs.width + i * (obs.width + 60 + Math.floor(Math.random() * 40));
obs.y = GROUND_Y;
obs.speed = gameSpeed;
obstacles.push(obs);
game.addChild(obs);
}
} else if (type === 'triple_cactus') {
// Three cacti close together
for (var i = 0; i < 3; i++) {
obs = new Cactus();
obs.x = 2048 + obs.width + i * (obs.width + 50 + Math.floor(Math.random() * 30));
obs.y = GROUND_Y;
obs.speed = gameSpeed;
obstacles.push(obs);
game.addChild(obs);
}
} else if (type === 'ptero') {
obs = new Ptero();
obs.x = 2048 + obs.width + Math.floor(Math.random() * 120);
// Randomize ptero height
obs.y = PTERO_MIN_Y + Math.floor(Math.random() * (PTERO_MAX_Y - PTERO_MIN_Y));
obs.speed = gameSpeed + 2;
obstacles.push(obs);
game.addChild(obs);
} else if (type === 'low_ptero') {
obs = new Ptero();
obs.x = 2048 + obs.width + Math.floor(Math.random() * 120);
// Lower flying ptero, forces jump
obs.y = GROUND_Y - 120 - Math.floor(Math.random() * 60);
obs.speed = gameSpeed + 2.5;
obstacles.push(obs);
game.addChild(obs);
}
}
// Helper: reset game state
function resetGame() {
// Remove obstacles
for (var i = 0; i < obstacles.length; i++) {
obstacles[i].destroy();
}
obstacles = [];
gameSpeed = GAME_SPEED_START;
ticksSinceLastObstacle = 0;
// Reset with dynamic gap scaling
var minGap = Math.max(350, OBSTACLE_MIN_GAP - Math.floor(score / 10));
var maxGap = Math.max(minGap + 200, OBSTACLE_MAX_GAP - Math.floor(score / 8));
nextObstacleGap = minGap + Math.floor(Math.random() * (maxGap - minGap));
score = 0;
scoreTxt.setText(score);
dino.x = DINO_START_X;
dino.y = GROUND_Y;
dino.isJumping = false;
dino.velocityY = 0;
lastObstacleType = null;
}
// Touch/drag controls
game.down = function (x, y, obj) {
isTouching = true;
dino.jump();
};
game.up = function (x, y, obj) {
isTouching = false;
};
game.move = function (x, y, obj) {};
// Main game loop
game.update = function () {
// Speed up over time
if (LK.ticks % GAME_SPEEDUP_EVERY === 0 && gameSpeed < GAME_SPEED_MAX) {
gameSpeed += GAME_SPEEDUP_AMOUNT;
if (gameSpeed > GAME_SPEED_MAX) {
gameSpeed = GAME_SPEED_MAX;
}
}
// Update dino
dino.update();
// Update obstacles
for (var i = obstacles.length - 1; i >= 0; i--) {
var obs = obstacles[i];
obs.speed = gameSpeed + (obs instanceof Ptero ? 2 : 0);
obs.update();
// Remove if off screen
if (obs.x < -300) {
obs.destroy();
obstacles.splice(i, 1);
continue;
}
// Collision detection
if (dino.intersects(obs)) {
LK.getSound('hit').play();
LK.effects.flashScreen(0xff0000, 800);
LK.showGameOver();
return;
}
}
// Obstacle spawning
ticksSinceLastObstacle += gameSpeed;
// Make gap smaller as score increases (min 350)
var minGap = Math.max(350, OBSTACLE_MIN_GAP - Math.floor(score / 10));
var maxGap = Math.max(minGap + 200, OBSTACLE_MAX_GAP - Math.floor(score / 8));
if (ticksSinceLastObstacle >= nextObstacleGap) {
spawnObstacle();
ticksSinceLastObstacle = 0;
nextObstacleGap = minGap + Math.floor(Math.random() * (maxGap - minGap));
}
// Score increases with distance
score += Math.floor(gameSpeed / 6);
scoreTxt.setText(score);
LK.setScore(score);
};
// Reset game state on game start
resetGame(); /****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
/****
* Classes
****/
// Cactus obstacle
var Cactus = Container.expand(function () {
var self = Container.call(this);
var cactusSprite = self.attachAsset('cactus', {
anchorX: 0.5,
anchorY: 1
});
self.width = cactusSprite.width;
self.height = cactusSprite.height;
self.speed = 0; // Set by game
self.update = function () {
self.x -= self.speed;
};
return self;
});
// Dino (player) class
var Dino = Container.expand(function () {
var self = Container.call(this);
var dinoSprite = self.attachAsset('dino', {
anchorX: 0.5,
anchorY: 1
});
self.width = dinoSprite.width;
self.height = dinoSprite.height;
// State
self.isJumping = false;
self.velocityY = 0;
self.gravity = 2.2 * 1; // gravity is positive, pulls dino down
self.jumpStrength = -48; // negative jumpStrength makes dino go up (y decreases)
self.groundY = 0; // Set after adding to game
// Jump
self.jump = function () {
if (!self.isJumping) {
self.isJumping = true;
self.velocityY = self.jumpStrength;
LK.getSound('jump').play();
}
};
// Update per frame
self.update = function () {
if (self.isJumping) {
self.y += self.velocityY;
self.velocityY += self.gravity;
if (self.y >= self.groundY) {
self.y = self.groundY;
self.isJumping = false;
self.velocityY = 0;
}
}
};
return self;
});
// Pterodactyl obstacle
var Ptero = Container.expand(function () {
var self = Container.call(this);
var pteroSprite = self.attachAsset('ptero', {
anchorX: 0.5,
anchorY: 0.5
});
self.width = pteroSprite.width;
self.height = pteroSprite.height;
self.speed = 0; // Set by game
self.update = function () {
self.x -= self.speed;
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0xf5f5f5
});
/****
* Game Code
****/
// Game constants
// Dinosaur (player)
// Cactus (obstacle)
// Pterodactyl (obstacle)
// Ground
// Jump sound
var GROUND_Y = 2200;
var DINO_START_X = 400;
var OBSTACLE_MIN_GAP = 700;
var OBSTACLE_MAX_GAP = 1200;
var PTERO_MIN_Y = GROUND_Y - 400;
var PTERO_MAX_Y = GROUND_Y - 700;
var GAME_SPEED_START = 22;
var GAME_SPEED_MAX = 60;
var GAME_SPEEDUP_EVERY = 600; // ticks
var GAME_SPEEDUP_AMOUNT = 1.2;
// Game state
var dino;
var ground;
var obstacles = [];
var gameSpeed = GAME_SPEED_START;
var ticksSinceLastObstacle = 0;
var nextObstacleGap = 0;
var score = 0;
var scoreTxt;
var dragNode = null;
var isTouching = false;
var ducking = false;
var lastObstacleType = null;
// Add ground
ground = LK.getAsset('ground', {
anchorX: 0,
anchorY: 0,
x: 0,
y: GROUND_Y + 1
});
game.addChild(ground);
// Add dino
dino = new Dino();
game.addChild(dino);
dino.x = DINO_START_X;
dino.groundY = GROUND_Y;
dino.y = GROUND_Y;
// Score text
scoreTxt = new Text2('0', {
size: 120,
fill: "#222"
});
scoreTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(scoreTxt);
// Helper: spawn obstacle
function spawnObstacle() {
// Increase obstacle variety as score increases
var availableTypes = ['cactus', 'ptero'];
if (score > 500) {
availableTypes.push('double_cactus');
}
if (score > 1200) {
availableTypes.push('low_ptero');
}
if (score > 2000) {
availableTypes.push('triple_cactus');
}
// Randomly pick type, but avoid two pteros in a row
var type = availableTypes[Math.floor(Math.random() * availableTypes.length)];
if ((type === 'ptero' || type === 'low_ptero') && lastObstacleType && (lastObstacleType === 'ptero' || lastObstacleType === 'low_ptero')) {
type = 'cactus';
}
lastObstacleType = type;
var obs;
if (type === 'cactus') {
obs = new Cactus();
obs.x = 2048 + obs.width + Math.floor(Math.random() * 120); // randomize spawn x
obs.y = GROUND_Y;
obs.speed = gameSpeed;
obstacles.push(obs);
game.addChild(obs);
} else if (type === 'double_cactus') {
// Two cacti close together
for (var i = 0; i < 2; i++) {
obs = new Cactus();
obs.x = 2048 + obs.width + i * (obs.width + 60 + Math.floor(Math.random() * 40));
obs.y = GROUND_Y;
obs.speed = gameSpeed;
obstacles.push(obs);
game.addChild(obs);
}
} else if (type === 'triple_cactus') {
// Three cacti close together
for (var i = 0; i < 3; i++) {
obs = new Cactus();
obs.x = 2048 + obs.width + i * (obs.width + 50 + Math.floor(Math.random() * 30));
obs.y = GROUND_Y;
obs.speed = gameSpeed;
obstacles.push(obs);
game.addChild(obs);
}
} else if (type === 'ptero') {
obs = new Ptero();
obs.x = 2048 + obs.width + Math.floor(Math.random() * 120);
// Randomize ptero height
obs.y = PTERO_MIN_Y + Math.floor(Math.random() * (PTERO_MAX_Y - PTERO_MIN_Y));
obs.speed = gameSpeed + 2;
obstacles.push(obs);
game.addChild(obs);
} else if (type === 'low_ptero') {
obs = new Ptero();
obs.x = 2048 + obs.width + Math.floor(Math.random() * 120);
// Lower flying ptero, forces jump
obs.y = GROUND_Y - 120 - Math.floor(Math.random() * 60);
obs.speed = gameSpeed + 2.5;
obstacles.push(obs);
game.addChild(obs);
}
}
// Helper: reset game state
function resetGame() {
// Remove obstacles
for (var i = 0; i < obstacles.length; i++) {
obstacles[i].destroy();
}
obstacles = [];
gameSpeed = GAME_SPEED_START;
ticksSinceLastObstacle = 0;
// Reset with dynamic gap scaling
var minGap = Math.max(350, OBSTACLE_MIN_GAP - Math.floor(score / 10));
var maxGap = Math.max(minGap + 200, OBSTACLE_MAX_GAP - Math.floor(score / 8));
nextObstacleGap = minGap + Math.floor(Math.random() * (maxGap - minGap));
score = 0;
scoreTxt.setText(score);
dino.x = DINO_START_X;
dino.y = GROUND_Y;
dino.isJumping = false;
dino.velocityY = 0;
lastObstacleType = null;
}
// Touch/drag controls
game.down = function (x, y, obj) {
isTouching = true;
dino.jump();
};
game.up = function (x, y, obj) {
isTouching = false;
};
game.move = function (x, y, obj) {};
// Main game loop
game.update = function () {
// Speed up over time
if (LK.ticks % GAME_SPEEDUP_EVERY === 0 && gameSpeed < GAME_SPEED_MAX) {
gameSpeed += GAME_SPEEDUP_AMOUNT;
if (gameSpeed > GAME_SPEED_MAX) {
gameSpeed = GAME_SPEED_MAX;
}
}
// Update dino
dino.update();
// Update obstacles
for (var i = obstacles.length - 1; i >= 0; i--) {
var obs = obstacles[i];
obs.speed = gameSpeed + (obs instanceof Ptero ? 2 : 0);
obs.update();
// Remove if off screen
if (obs.x < -300) {
obs.destroy();
obstacles.splice(i, 1);
continue;
}
// Collision detection
if (dino.intersects(obs)) {
LK.getSound('hit').play();
LK.effects.flashScreen(0xff0000, 800);
LK.showGameOver();
return;
}
}
// Obstacle spawning
ticksSinceLastObstacle += gameSpeed;
// Make gap smaller as score increases (min 350)
var minGap = Math.max(350, OBSTACLE_MIN_GAP - Math.floor(score / 10));
var maxGap = Math.max(minGap + 200, OBSTACLE_MAX_GAP - Math.floor(score / 8));
if (ticksSinceLastObstacle >= nextObstacleGap) {
spawnObstacle();
ticksSinceLastObstacle = 0;
nextObstacleGap = minGap + Math.floor(Math.random() * (maxGap - minGap));
}
// Score increases with distance
score += Math.floor(gameSpeed / 6);
scoreTxt.setText(score);
LK.setScore(score);
};
// Reset game state on game start
resetGame();