/**** * Plugins ****/ var tween = LK.import("@upit/tween.v1"); var storage = LK.import("@upit/storage.v1"); /**** * Classes ****/ // Enemy class (moves left/right) var Enemy = Container.expand(function () { var self = Container.call(this); var en = self.attachAsset('enemy', { anchorX: 0.5, anchorY: 0.5 }); self.speed = 3 + Math.random() * 2; self.direction = Math.random() < 0.5 ? 1 : -1; self.range = 300 + Math.random() * 200; self.originX = 0; self.update = function () { self.x += self.speed * self.direction; if (Math.abs(self.x - self.originX) > self.range) { self.direction *= -1; } }; return self; }); // Football class (follows player or can be dropped) var Football = Container.expand(function () { var self = Container.call(this); var fb = self.attachAsset('football', { anchorX: 0.5, anchorY: 0.5 }); self.carried = true; self.vx = 0; self.vy = 0; self.update = function () { if (!self.carried) { // Gravity self.vy += 2.5; self.x += self.vx; self.y += self.vy; // Collide with platforms for (var i = 0; i < platforms.length; ++i) { var p = platforms[i]; if (self.intersects(p) && self.vy > 0) { self.y = p.y - p.height / 2 - self.height / 2; self.vy = 0; } } // Clamp to ground if (self.y > 2732 - 40) { self.y = 2732 - 40; self.vy = 0; } } }; return self; }); // Goal class var Goal = Container.expand(function () { var self = Container.call(this); var g = self.attachAsset('goal', { anchorX: 0.5, anchorY: 1 }); return self; }); // Hazard class var Hazard = Container.expand(function () { var self = Container.call(this); var hz = self.attachAsset('hazard', { anchorX: 0.5, anchorY: 0.5 }); return self; }); // Platform class var Platform = Container.expand(function () { var self = Container.call(this); var plat = self.attachAsset('platform', { anchorX: 0.5, anchorY: 0.5 }); return self; }); // Player class var Player = Container.expand(function () { var self = Container.call(this); var pl = self.attachAsset('player', { anchorX: 0.5, anchorY: 0.5 }); self.vx = 0; self.vy = 0; self.onGround = false; self.carrying = true; self.update = function () { // Apply gravity self.vy += 3.5; // Move self.x += self.vx; self.y += self.vy; // Clamp to world bounds if (self.x < self.width / 2) self.x = self.width / 2; if (self.x > 2048 - self.width / 2) self.x = 2048 - self.width / 2; if (self.y > 2732 - 40) { self.y = 2732 - 40; self.vy = 0; self.onGround = true; } // Collide with platforms self.onGround = false; for (var i = 0; i < platforms.length; ++i) { var p = platforms[i]; if (self.intersects(p) && self.vy > 0) { self.y = p.y - p.height / 2 - self.height / 2; self.vy = 0; self.onGround = true; } } }; return self; }); /**** * Initialize Game ****/ var game = new LK.Game({ backgroundColor: 0x222244 }); /**** * Game Code ****/ // Football (ellipse), Player (box), Enemy (box), Platform (box), Goal (box), Hazard (box) // Level data (platforms, hazards, enemies) var level = 1; if (storage.level) level = storage.level; var platforms = []; var hazards = []; var enemies = []; var player = null; var football = null; var goal = null; var dragging = false; var dragStartX = 0; var dragStartY = 0; var moveDir = 0; // -1 left, 1 right, 0 none var jumpQueued = false; var infoText = null; var levelText = null; var carryingBall = true; var canPickupBall = false; var lastGoalIntersect = false; var lastEnemyIntersect = false; var lastHazardIntersect = false; var lastFootballIntersect = false; var lastFootballGoalIntersect = false; var lastFootballHazardIntersect = false; var lastFootballEnemyIntersect = false; // GUI: Level display levelText = new Text2('Level ' + level, { size: 90, fill: '#fff' }); levelText.anchor.set(0.5, 0); LK.gui.top.addChild(levelText); // GUI: Info text infoText = new Text2('', { size: 70, fill: '#fff' }); infoText.anchor.set(0.5, 0); LK.gui.bottom.addChild(infoText); // Helper: Reset level function setupLevel() { // Clear old for (var i = 0; i < platforms.length; ++i) platforms[i].destroy(); for (var i = 0; i < hazards.length; ++i) hazards[i].destroy(); for (var i = 0; i < enemies.length; ++i) enemies[i].destroy(); if (player) player.destroy(); if (football) football.destroy(); if (goal) goal.destroy(); platforms = []; hazards = []; enemies = []; player = null; football = null; goal = null; carryingBall = true; canPickupBall = false; lastGoalIntersect = false; lastEnemyIntersect = false; lastHazardIntersect = false; lastFootballIntersect = false; lastFootballGoalIntersect = false; lastFootballHazardIntersect = false; lastFootballEnemyIntersect = false; // Level layout // Start platform var plat = new Platform(); plat.x = 200; plat.y = 2500; game.addChild(plat); platforms.push(plat); // Middle platforms var platCount = 4 + level; for (var i = 0; i < platCount; ++i) { var p = new Platform(); p.x = 400 + i * 350 + Math.random() * 80; p.y = 2500 - i * 350 + Math.random() * 60; game.addChild(p); platforms.push(p); // Hazards if (level > 1 && Math.random() < 0.4) { var hz = new Hazard(); hz.x = p.x + (Math.random() < 0.5 ? -1 : 1) * 100; hz.y = p.y - 40; game.addChild(hz); hazards.push(hz); } // Enemies if (level > 1 && Math.random() < 0.5) { var en = new Enemy(); en.x = p.x; en.y = p.y - 100; en.originX = en.x; game.addChild(en); enemies.push(en); } } // Goal goal = new Goal(); goal.x = platforms[platforms.length - 1].x + 300; goal.y = platforms[platforms.length - 1].y - 60; game.addChild(goal); // Player player = new Player(); player.x = plat.x; player.y = plat.y - 120; game.addChild(player); // Football football = new Football(); football.x = player.x; football.y = player.y - 100; football.carried = true; game.addChild(football); // GUI levelText.setText('Level ' + level); infoText.setText('Drag to move, tap to jump'); } // Touch controls game.down = function (x, y, obj) { // If tap below half screen, jump if (y > 2732 / 2) { jumpQueued = true; return; } // Else, drag to move dragging = true; dragStartX = x; dragStartY = y; moveDir = 0; }; game.move = function (x, y, obj) { if (dragging) { var dx = x - dragStartX; if (Math.abs(dx) > 30) { moveDir = dx > 0 ? 1 : -1; } else { moveDir = 0; } } }; game.up = function (x, y, obj) { dragging = false; moveDir = 0; }; // Main update loop game.update = function () { // Player movement if (moveDir !== 0) { player.vx = 14 * moveDir; } else { player.vx *= 0.7; if (Math.abs(player.vx) < 1) player.vx = 0; } // Jump if (jumpQueued && player.onGround) { player.vy = -55 - 4 * level; jumpQueued = false; } jumpQueued = false; // Update player, football, enemies player.update(); football.update(); for (var i = 0; i < enemies.length; ++i) enemies[i].update(); // Carry football if (football.carried) { football.x = player.x; football.y = player.y - player.height / 2 - football.height / 2 + 20; football.vx = 0; football.vy = 0; } // Football pickup var footballNear = player.intersects(football); if (!football.carried && footballNear && !carryingBall) { carryingBall = true; football.carried = true; infoText.setText('Ball picked up!'); tween(infoText, { alpha: 0 }, { duration: 1200, onFinish: function onFinish() { infoText.setText(''); infoText.alpha = 1; } }); } // Football drop on enemy/hazard var hitEnemy = false; for (var i = 0; i < enemies.length; ++i) { if (player.intersects(enemies[i]) && football.carried) hitEnemy = true; } var hitHazard = false; for (var i = 0; i < hazards.length; ++i) { if (player.intersects(hazards[i]) && football.carried) hitHazard = true; } if ((hitEnemy || hitHazard) && football.carried) { football.carried = false; carryingBall = false; football.vx = player.vx * 0.7; football.vy = -20; infoText.setText('You dropped the ball!'); tween(infoText, { alpha: 0 }, { duration: 1200, onFinish: function onFinish() { infoText.setText(''); infoText.alpha = 1; } }); LK.effects.flashObject(player, 0xff0000, 600); } // Football collides with hazard/enemy: reset to start var fbHitHazard = false; for (var i = 0; i < hazards.length; ++i) { if (football.intersects(hazards[i]) && !football.carried) fbHitHazard = true; } var fbHitEnemy = false; for (var i = 0; i < enemies.length; ++i) { if (football.intersects(enemies[i]) && !football.carried) fbHitEnemy = true; } if ((fbHitHazard || fbHitEnemy) && !football.carried) { // Reset football to start football.x = platforms[0].x; football.y = platforms[0].y - 100; football.vx = 0; football.vy = 0; infoText.setText('Ball reset!'); tween(infoText, { alpha: 0 }, { duration: 1200, onFinish: function onFinish() { infoText.setText(''); infoText.alpha = 1; } }); } // Win condition: player+football at goal var atGoal = player.intersects(goal); var fbAtGoal = football.intersects(goal); if (atGoal && football.carried && fbAtGoal) { // Next level infoText.setText('Touchdown! Next level...'); tween(infoText, { alpha: 0 }, { duration: 1200, onFinish: function onFinish() { infoText.setText(''); infoText.alpha = 1; } }); level += 1; storage.level = level; LK.setTimeout(setupLevel, 1200); return; } // Lose condition: player falls off if (player.y > 2732 - 10) { LK.effects.flashScreen(0xff0000, 1000); infoText.setText('You fell! Try again.'); tween(infoText, { alpha: 0 }, { duration: 1200, onFinish: function onFinish() { infoText.setText(''); infoText.alpha = 1; } }); LK.setTimeout(setupLevel, 1200); return; } // Lose condition: football lost off screen if (football.y > 2732 - 10) { infoText.setText('Ball lost! Try again.'); tween(infoText, { alpha: 0 }, { duration: 1200, onFinish: function onFinish() { infoText.setText(''); infoText.alpha = 1; } }); LK.setTimeout(setupLevel, 1200); return; } }; // Start first level setupLevel();
/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
var storage = LK.import("@upit/storage.v1");
/****
* Classes
****/
// Enemy class (moves left/right)
var Enemy = Container.expand(function () {
var self = Container.call(this);
var en = self.attachAsset('enemy', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 3 + Math.random() * 2;
self.direction = Math.random() < 0.5 ? 1 : -1;
self.range = 300 + Math.random() * 200;
self.originX = 0;
self.update = function () {
self.x += self.speed * self.direction;
if (Math.abs(self.x - self.originX) > self.range) {
self.direction *= -1;
}
};
return self;
});
// Football class (follows player or can be dropped)
var Football = Container.expand(function () {
var self = Container.call(this);
var fb = self.attachAsset('football', {
anchorX: 0.5,
anchorY: 0.5
});
self.carried = true;
self.vx = 0;
self.vy = 0;
self.update = function () {
if (!self.carried) {
// Gravity
self.vy += 2.5;
self.x += self.vx;
self.y += self.vy;
// Collide with platforms
for (var i = 0; i < platforms.length; ++i) {
var p = platforms[i];
if (self.intersects(p) && self.vy > 0) {
self.y = p.y - p.height / 2 - self.height / 2;
self.vy = 0;
}
}
// Clamp to ground
if (self.y > 2732 - 40) {
self.y = 2732 - 40;
self.vy = 0;
}
}
};
return self;
});
// Goal class
var Goal = Container.expand(function () {
var self = Container.call(this);
var g = self.attachAsset('goal', {
anchorX: 0.5,
anchorY: 1
});
return self;
});
// Hazard class
var Hazard = Container.expand(function () {
var self = Container.call(this);
var hz = self.attachAsset('hazard', {
anchorX: 0.5,
anchorY: 0.5
});
return self;
});
// Platform class
var Platform = Container.expand(function () {
var self = Container.call(this);
var plat = self.attachAsset('platform', {
anchorX: 0.5,
anchorY: 0.5
});
return self;
});
// Player class
var Player = Container.expand(function () {
var self = Container.call(this);
var pl = self.attachAsset('player', {
anchorX: 0.5,
anchorY: 0.5
});
self.vx = 0;
self.vy = 0;
self.onGround = false;
self.carrying = true;
self.update = function () {
// Apply gravity
self.vy += 3.5;
// Move
self.x += self.vx;
self.y += self.vy;
// Clamp to world bounds
if (self.x < self.width / 2) self.x = self.width / 2;
if (self.x > 2048 - self.width / 2) self.x = 2048 - self.width / 2;
if (self.y > 2732 - 40) {
self.y = 2732 - 40;
self.vy = 0;
self.onGround = true;
}
// Collide with platforms
self.onGround = false;
for (var i = 0; i < platforms.length; ++i) {
var p = platforms[i];
if (self.intersects(p) && self.vy > 0) {
self.y = p.y - p.height / 2 - self.height / 2;
self.vy = 0;
self.onGround = true;
}
}
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x222244
});
/****
* Game Code
****/
// Football (ellipse), Player (box), Enemy (box), Platform (box), Goal (box), Hazard (box)
// Level data (platforms, hazards, enemies)
var level = 1;
if (storage.level) level = storage.level;
var platforms = [];
var hazards = [];
var enemies = [];
var player = null;
var football = null;
var goal = null;
var dragging = false;
var dragStartX = 0;
var dragStartY = 0;
var moveDir = 0; // -1 left, 1 right, 0 none
var jumpQueued = false;
var infoText = null;
var levelText = null;
var carryingBall = true;
var canPickupBall = false;
var lastGoalIntersect = false;
var lastEnemyIntersect = false;
var lastHazardIntersect = false;
var lastFootballIntersect = false;
var lastFootballGoalIntersect = false;
var lastFootballHazardIntersect = false;
var lastFootballEnemyIntersect = false;
// GUI: Level display
levelText = new Text2('Level ' + level, {
size: 90,
fill: '#fff'
});
levelText.anchor.set(0.5, 0);
LK.gui.top.addChild(levelText);
// GUI: Info text
infoText = new Text2('', {
size: 70,
fill: '#fff'
});
infoText.anchor.set(0.5, 0);
LK.gui.bottom.addChild(infoText);
// Helper: Reset level
function setupLevel() {
// Clear old
for (var i = 0; i < platforms.length; ++i) platforms[i].destroy();
for (var i = 0; i < hazards.length; ++i) hazards[i].destroy();
for (var i = 0; i < enemies.length; ++i) enemies[i].destroy();
if (player) player.destroy();
if (football) football.destroy();
if (goal) goal.destroy();
platforms = [];
hazards = [];
enemies = [];
player = null;
football = null;
goal = null;
carryingBall = true;
canPickupBall = false;
lastGoalIntersect = false;
lastEnemyIntersect = false;
lastHazardIntersect = false;
lastFootballIntersect = false;
lastFootballGoalIntersect = false;
lastFootballHazardIntersect = false;
lastFootballEnemyIntersect = false;
// Level layout
// Start platform
var plat = new Platform();
plat.x = 200;
plat.y = 2500;
game.addChild(plat);
platforms.push(plat);
// Middle platforms
var platCount = 4 + level;
for (var i = 0; i < platCount; ++i) {
var p = new Platform();
p.x = 400 + i * 350 + Math.random() * 80;
p.y = 2500 - i * 350 + Math.random() * 60;
game.addChild(p);
platforms.push(p);
// Hazards
if (level > 1 && Math.random() < 0.4) {
var hz = new Hazard();
hz.x = p.x + (Math.random() < 0.5 ? -1 : 1) * 100;
hz.y = p.y - 40;
game.addChild(hz);
hazards.push(hz);
}
// Enemies
if (level > 1 && Math.random() < 0.5) {
var en = new Enemy();
en.x = p.x;
en.y = p.y - 100;
en.originX = en.x;
game.addChild(en);
enemies.push(en);
}
}
// Goal
goal = new Goal();
goal.x = platforms[platforms.length - 1].x + 300;
goal.y = platforms[platforms.length - 1].y - 60;
game.addChild(goal);
// Player
player = new Player();
player.x = plat.x;
player.y = plat.y - 120;
game.addChild(player);
// Football
football = new Football();
football.x = player.x;
football.y = player.y - 100;
football.carried = true;
game.addChild(football);
// GUI
levelText.setText('Level ' + level);
infoText.setText('Drag to move, tap to jump');
}
// Touch controls
game.down = function (x, y, obj) {
// If tap below half screen, jump
if (y > 2732 / 2) {
jumpQueued = true;
return;
}
// Else, drag to move
dragging = true;
dragStartX = x;
dragStartY = y;
moveDir = 0;
};
game.move = function (x, y, obj) {
if (dragging) {
var dx = x - dragStartX;
if (Math.abs(dx) > 30) {
moveDir = dx > 0 ? 1 : -1;
} else {
moveDir = 0;
}
}
};
game.up = function (x, y, obj) {
dragging = false;
moveDir = 0;
};
// Main update loop
game.update = function () {
// Player movement
if (moveDir !== 0) {
player.vx = 14 * moveDir;
} else {
player.vx *= 0.7;
if (Math.abs(player.vx) < 1) player.vx = 0;
}
// Jump
if (jumpQueued && player.onGround) {
player.vy = -55 - 4 * level;
jumpQueued = false;
}
jumpQueued = false;
// Update player, football, enemies
player.update();
football.update();
for (var i = 0; i < enemies.length; ++i) enemies[i].update();
// Carry football
if (football.carried) {
football.x = player.x;
football.y = player.y - player.height / 2 - football.height / 2 + 20;
football.vx = 0;
football.vy = 0;
}
// Football pickup
var footballNear = player.intersects(football);
if (!football.carried && footballNear && !carryingBall) {
carryingBall = true;
football.carried = true;
infoText.setText('Ball picked up!');
tween(infoText, {
alpha: 0
}, {
duration: 1200,
onFinish: function onFinish() {
infoText.setText('');
infoText.alpha = 1;
}
});
}
// Football drop on enemy/hazard
var hitEnemy = false;
for (var i = 0; i < enemies.length; ++i) {
if (player.intersects(enemies[i]) && football.carried) hitEnemy = true;
}
var hitHazard = false;
for (var i = 0; i < hazards.length; ++i) {
if (player.intersects(hazards[i]) && football.carried) hitHazard = true;
}
if ((hitEnemy || hitHazard) && football.carried) {
football.carried = false;
carryingBall = false;
football.vx = player.vx * 0.7;
football.vy = -20;
infoText.setText('You dropped the ball!');
tween(infoText, {
alpha: 0
}, {
duration: 1200,
onFinish: function onFinish() {
infoText.setText('');
infoText.alpha = 1;
}
});
LK.effects.flashObject(player, 0xff0000, 600);
}
// Football collides with hazard/enemy: reset to start
var fbHitHazard = false;
for (var i = 0; i < hazards.length; ++i) {
if (football.intersects(hazards[i]) && !football.carried) fbHitHazard = true;
}
var fbHitEnemy = false;
for (var i = 0; i < enemies.length; ++i) {
if (football.intersects(enemies[i]) && !football.carried) fbHitEnemy = true;
}
if ((fbHitHazard || fbHitEnemy) && !football.carried) {
// Reset football to start
football.x = platforms[0].x;
football.y = platforms[0].y - 100;
football.vx = 0;
football.vy = 0;
infoText.setText('Ball reset!');
tween(infoText, {
alpha: 0
}, {
duration: 1200,
onFinish: function onFinish() {
infoText.setText('');
infoText.alpha = 1;
}
});
}
// Win condition: player+football at goal
var atGoal = player.intersects(goal);
var fbAtGoal = football.intersects(goal);
if (atGoal && football.carried && fbAtGoal) {
// Next level
infoText.setText('Touchdown! Next level...');
tween(infoText, {
alpha: 0
}, {
duration: 1200,
onFinish: function onFinish() {
infoText.setText('');
infoText.alpha = 1;
}
});
level += 1;
storage.level = level;
LK.setTimeout(setupLevel, 1200);
return;
}
// Lose condition: player falls off
if (player.y > 2732 - 10) {
LK.effects.flashScreen(0xff0000, 1000);
infoText.setText('You fell! Try again.');
tween(infoText, {
alpha: 0
}, {
duration: 1200,
onFinish: function onFinish() {
infoText.setText('');
infoText.alpha = 1;
}
});
LK.setTimeout(setupLevel, 1200);
return;
}
// Lose condition: football lost off screen
if (football.y > 2732 - 10) {
infoText.setText('Ball lost! Try again.');
tween(infoText, {
alpha: 0
}, {
duration: 1200,
onFinish: function onFinish() {
infoText.setText('');
infoText.alpha = 1;
}
});
LK.setTimeout(setupLevel, 1200);
return;
}
};
// Start first level
setupLevel();