/**** * Plugins ****/ var tween = LK.import("@upit/tween.v1"); /**** * Classes ****/ // Checkpoint class: save progress var Checkpoint = Container.expand(function () { var self = Container.call(this); var cp = self.attachAsset('checkpoint', { anchorX: 0.5, anchorY: 1 }); self.activated = false; self.activate = function () { if (!self.activated) { self.activated = true; tween(cp, { tint: 0x00ff00 }, { duration: 300 }); } }; return self; }); // Platform class: static or moving platform var Platform = Container.expand(function () { var self = Container.call(this); // Attach platform asset (box shape) var plat = self.attachAsset('platform', { anchorX: 0.5, anchorY: 0.5 }); // Platform movement config self.isMoving = false; self.moveAxis = 'x'; // 'x' or 'y' self.moveFrom = 0; self.moveTo = 0; self.moveDuration = 0; self.moveDir = 1; // For moving platforms, set up tween self.startMove = function () { if (!self.isMoving) return; var prop = {}; prop[self.moveAxis] = self.moveTo; tween(self, prop, { duration: self.moveDuration, easing: tween.linear, onFinish: function onFinish() { // Swap direction var tmp = self.moveFrom; self.moveFrom = self.moveTo; self.moveTo = tmp; self.startMove(); } }); }; return self; }); // Player class: main character var Player = Container.expand(function () { var self = Container.call(this); var _char = self.attachAsset('player', { anchorX: 0.5, anchorY: 1 }); self.width = _char.width; self.height = _char.height; self.vx = 0; self.vy = 0; self.onGround = false; self.dead = false; self.jumpQueued = false; self.respawn = function (x, y) { self.x = x; self.y = y; self.vx = 0; self.vy = 0; self.dead = false; }; return self; }); // Spike class: deadly obstacle var Spike = Container.expand(function () { var self = Container.call(this); // Attach spike asset (triangle shape, but use box for now) var spike = self.attachAsset('spike', { anchorX: 0.5, anchorY: 1 }); return self; }); /**** * Initialize Game ****/ var game = new LK.Game({ backgroundColor: 0x222222 }); /**** * Game Code ****/ /* Level is an array of objects: {type: 'platform'|'spike'|'checkpoint', x, y, [w], [h], [moveAxis], [moveFrom], [moveTo], [moveDuration]} All positions are in game coordinates. */ // --- Level Data (MVP: 1 level, hardcoded) --- // Tween plugin for platform/character movement and effects // --- Asset Initialization --- var levelData = [ // Floor { type: 'platform', x: 1024, y: 2600, w: 1200, h: 60 }, // First jump { type: 'platform', x: 600, y: 2200, w: 400, h: 40 }, { type: 'spike', x: 800, y: 2160 }, // Second jump { type: 'platform', x: 1400, y: 2000, w: 400, h: 40 }, { type: 'spike', x: 1200, y: 1960 }, // Moving platform { type: 'platform', x: 1024, y: 1700, w: 300, h: 40, moveAxis: 'x', moveFrom: 724, moveTo: 1324, moveDuration: 1800 }, { type: 'spike', x: 1024, y: 1660 }, // Checkpoint { type: 'checkpoint', x: 1024, y: 1600 }, // Final platform { type: 'platform', x: 1024, y: 1200, w: 400, h: 40 }, // End spike { type: 'spike', x: 1024, y: 1160 }]; // --- Game State --- var platforms = []; var spikes = []; var checkpoints = []; var player = null; var currentCheckpoint = null; var deaths = 0; var levelEndY = 1100; // Y position to reach to win // --- UI --- var deathsTxt = new Text2('Deaths: 0', { size: 90, fill: "#fff" }); deathsTxt.anchor.set(0.5, 0); LK.gui.top.addChild(deathsTxt); // --- Level Construction --- function buildLevel() { // Clear previous for (var i = 0; i < platforms.length; ++i) platforms[i].destroy(); for (var i = 0; i < spikes.length; ++i) spikes[i].destroy(); for (var i = 0; i < checkpoints.length; ++i) checkpoints[i].destroy(); platforms = []; spikes = []; checkpoints = []; currentCheckpoint = null; // Build for (var i = 0; i < levelData.length; ++i) { var obj = levelData[i]; if (obj.type === 'platform') { var plat = new Platform(); plat.x = obj.x; plat.y = obj.y; plat.width = obj.w || 400; plat.height = obj.h || 40; plat.children[0].width = plat.width; plat.children[0].height = plat.height; if (obj.moveAxis) { plat.isMoving = true; plat.moveAxis = obj.moveAxis; plat.moveFrom = obj.moveFrom; plat.moveTo = obj.moveTo; plat.moveDuration = obj.moveDuration; plat[plat.moveAxis] = plat.moveFrom; plat.startMove(); } game.addChild(plat); platforms.push(plat); } else if (obj.type === 'spike') { var spike = new Spike(); spike.x = obj.x; spike.y = obj.y; game.addChild(spike); spikes.push(spike); } else if (obj.type === 'checkpoint') { var cp = new Checkpoint(); cp.x = obj.x; cp.y = obj.y; game.addChild(cp); checkpoints.push(cp); } } } // --- Player Spawn --- function spawnPlayer() { if (player) player.destroy(); player = new Player(); var spawnX = 1024, spawnY = 2500; if (currentCheckpoint) { spawnX = currentCheckpoint.x; spawnY = currentCheckpoint.y - 10; } player.respawn(spawnX, spawnY); game.addChild(player); } // --- Death/Respawn --- function killPlayer() { if (player.dead) return; player.dead = true; deaths += 1; deathsTxt.setText('Deaths: ' + deaths); LK.effects.flashScreen(0xff2222, 400); LK.setTimeout(function () { spawnPlayer(); }, 400); } // --- Win Condition --- function checkWin() { if (player.y < levelEndY) { LK.showYouWin(); } } // --- Collision Helpers --- function rectsIntersect(a, b) { return a.x - a.width / 2 < b.x + b.width / 2 && a.x + a.width / 2 > b.x - b.width / 2 && a.y - a.height < b.y && a.y > b.y - b.height; } // --- Tablet Controller (Virtual Joystick) --- // Controller state var controllerActive = false; var controllerStartX = 0; var controllerStartY = 0; var controllerCurX = 0; var controllerCurY = 0; var controllerRadius = 180; // px, joystick max distance var controllerBase = null; var controllerStick = null; var controllerCenterX = 0; var controllerCenterY = 0; var controllerDirX = 0; var controllerDirY = 0; var controllerJumpQueued = false; // Place controller in bottom left, safe from menu (not in top left 100x100) controllerCenterX = 220; controllerCenterY = 2732 - 220; // Draw controller base and stick function createControllerGraphics() { if (controllerBase) controllerBase.destroy(); if (controllerStick) controllerStick.destroy(); // Use shapes for base and stick controllerBase = LK.getAsset('platform', { width: controllerRadius * 2, height: controllerRadius * 2, color: 0x444444, anchorX: 0.5, anchorY: 0.5, x: controllerCenterX, y: controllerCenterY, alpha: 0.18 }); controllerStick = LK.getAsset('player', { width: 100, height: 100, color: 0xffffff, anchorX: 0.5, anchorY: 0.5, x: controllerCenterX, y: controllerCenterY, alpha: 0.45 }); LK.gui.bottomLeft.addChild(controllerBase); LK.gui.bottomLeft.addChild(controllerStick); } createControllerGraphics(); // Helper: get distance and angle from center function getControllerInput(x, y) { var dx = x - controllerCenterX; var dy = y - controllerCenterY; var dist = Math.sqrt(dx * dx + dy * dy); if (dist > controllerRadius) { dx = dx * controllerRadius / dist; dy = dy * controllerRadius / dist; dist = controllerRadius; } return { dx: dx, dy: dy, dist: dist }; } // Touch down: activate controller if in left-bottom quarter, else jump if in right-bottom game.down = function (x, y, obj) { // Only activate controller if touch is in left-bottom quarter (not in top left 100x100) if (x < 2048 / 2 && y > 2732 - 500 && y > 100) { controllerActive = true; controllerStartX = x; controllerStartY = y; controllerCurX = x; controllerCurY = y; var input = getControllerInput(x, y); controllerStick.x = controllerCenterX + input.dx; controllerStick.y = controllerCenterY + input.dy; controllerDirX = input.dx / controllerRadius; controllerDirY = input.dy / controllerRadius; controllerJumpQueued = false; } else if (x > 2048 / 2 && y > 2732 - 500) { // Right-bottom: jump controllerJumpQueued = true; } }; game.move = function (x, y, obj) { if (controllerActive) { controllerCurX = x; controllerCurY = y; var input = getControllerInput(x, y); controllerStick.x = controllerCenterX + input.dx; controllerStick.y = controllerCenterY + input.dy; controllerDirX = input.dx / controllerRadius; controllerDirY = input.dy / controllerRadius; } }; game.up = function (x, y, obj) { controllerActive = false; controllerStick.x = controllerCenterX; controllerStick.y = controllerCenterY; controllerDirX = 0; controllerDirY = 0; controllerJumpQueued = false; }; // --- END Tablet Controller --- // --- Physics Constants --- var GRAVITY = 2.2; var MOVE_SPEED = 18; var JUMP_VEL = -48; var MAX_FALL = 60; // --- Game Update Loop --- game.update = function () { if (!player || player.dead) return; // Horizontal movement (tablet controller) if (controllerDirX < -0.2) { player.vx = -MOVE_SPEED * Math.min(1, Math.abs(controllerDirX)); } else if (controllerDirX > 0.2) { player.vx = MOVE_SPEED * Math.min(1, Math.abs(controllerDirX)); } else { player.vx = 0; } // Jump (tablet controller) if ((controllerJumpQueued || controllerActive && controllerDirY < -0.5) && player.onGround) { player.vy = JUMP_VEL; player.onGround = false; controllerJumpQueued = false; } // Gravity player.vy += GRAVITY; if (player.vy > MAX_FALL) player.vy = MAX_FALL; // Save old position var oldX = player.x, oldY = player.y; // Move X player.x += player.vx; // Collide with platforms (X axis) for (var i = 0; i < platforms.length; ++i) { var plat = platforms[i]; if (rectsIntersect(player, plat)) { if (player.vx > 0) { player.x = plat.x - plat.width / 2 - player.width / 2; } else if (player.vx < 0) { player.x = plat.x + plat.width / 2 + player.width / 2; } player.vx = 0; } } // Move Y player.y += player.vy; player.onGround = false; // Collide with platforms (Y axis) for (var i = 0; i < platforms.length; ++i) { var plat = platforms[i]; if (rectsIntersect(player, plat)) { if (player.vy > 0) { player.y = plat.y - plat.height / 2; player.onGround = true; } else if (player.vy < 0) { player.y = plat.y + plat.height / 2 + player.height; } player.vy = 0; } } // Collide with spikes for (var i = 0; i < spikes.length; ++i) { var spike = spikes[i]; if (rectsIntersect(player, spike)) { killPlayer(); return; } } // Collide with checkpoints for (var i = 0; i < checkpoints.length; ++i) { var cp = checkpoints[i]; if (!cp.activated && rectsIntersect(player, cp)) { cp.activate(); currentCheckpoint = cp; } } // Out of bounds (fall) if (player.y > 2800) { killPlayer(); return; } // Win checkWin(); }; // --- Build Level and Start --- buildLevel(); spawnPlayer(); deaths = 0; deathsTxt.setText('Deaths: 0');
===================================================================
--- original.js
+++ change.js
@@ -276,56 +276,132 @@
// --- Collision Helpers ---
function rectsIntersect(a, b) {
return a.x - a.width / 2 < b.x + b.width / 2 && a.x + a.width / 2 > b.x - b.width / 2 && a.y - a.height < b.y && a.y > b.y - b.height;
}
-// --- Touch Controls (Mobile) ---
-var touchLeft = false,
- touchRight = false,
- touchJump = false;
-var dragStartX = null,
- dragStartY = null;
-var dragActive = false;
-// Touch areas: left 1/3 = left, right 1/3 = right, bottom 1/3 = jump
+// --- Tablet Controller (Virtual Joystick) ---
+// Controller state
+var controllerActive = false;
+var controllerStartX = 0;
+var controllerStartY = 0;
+var controllerCurX = 0;
+var controllerCurY = 0;
+var controllerRadius = 180; // px, joystick max distance
+var controllerBase = null;
+var controllerStick = null;
+var controllerCenterX = 0;
+var controllerCenterY = 0;
+var controllerDirX = 0;
+var controllerDirY = 0;
+var controllerJumpQueued = false;
+// Place controller in bottom left, safe from menu (not in top left 100x100)
+controllerCenterX = 220;
+controllerCenterY = 2732 - 220;
+// Draw controller base and stick
+function createControllerGraphics() {
+ if (controllerBase) controllerBase.destroy();
+ if (controllerStick) controllerStick.destroy();
+ // Use shapes for base and stick
+ controllerBase = LK.getAsset('platform', {
+ width: controllerRadius * 2,
+ height: controllerRadius * 2,
+ color: 0x444444,
+ anchorX: 0.5,
+ anchorY: 0.5,
+ x: controllerCenterX,
+ y: controllerCenterY,
+ alpha: 0.18
+ });
+ controllerStick = LK.getAsset('player', {
+ width: 100,
+ height: 100,
+ color: 0xffffff,
+ anchorX: 0.5,
+ anchorY: 0.5,
+ x: controllerCenterX,
+ y: controllerCenterY,
+ alpha: 0.45
+ });
+ LK.gui.bottomLeft.addChild(controllerBase);
+ LK.gui.bottomLeft.addChild(controllerStick);
+}
+createControllerGraphics();
+// Helper: get distance and angle from center
+function getControllerInput(x, y) {
+ var dx = x - controllerCenterX;
+ var dy = y - controllerCenterY;
+ var dist = Math.sqrt(dx * dx + dy * dy);
+ if (dist > controllerRadius) {
+ dx = dx * controllerRadius / dist;
+ dy = dy * controllerRadius / dist;
+ dist = controllerRadius;
+ }
+ return {
+ dx: dx,
+ dy: dy,
+ dist: dist
+ };
+}
+// Touch down: activate controller if in left-bottom quarter, else jump if in right-bottom
game.down = function (x, y, obj) {
- if (y > 2732 - 400) {
- touchJump = true;
- player.jumpQueued = true;
- } else if (x < 2048 / 3) {
- touchLeft = true;
- } else if (x > 2048 * 2 / 3) {
- touchRight = true;
+ // Only activate controller if touch is in left-bottom quarter (not in top left 100x100)
+ if (x < 2048 / 2 && y > 2732 - 500 && y > 100) {
+ controllerActive = true;
+ controllerStartX = x;
+ controllerStartY = y;
+ controllerCurX = x;
+ controllerCurY = y;
+ var input = getControllerInput(x, y);
+ controllerStick.x = controllerCenterX + input.dx;
+ controllerStick.y = controllerCenterY + input.dy;
+ controllerDirX = input.dx / controllerRadius;
+ controllerDirY = input.dy / controllerRadius;
+ controllerJumpQueued = false;
+ } else if (x > 2048 / 2 && y > 2732 - 500) {
+ // Right-bottom: jump
+ controllerJumpQueued = true;
}
};
-game.up = function (x, y, obj) {
- touchLeft = false;
- touchRight = false;
- touchJump = false;
- player.jumpQueued = false;
-};
game.move = function (x, y, obj) {
- // No drag controls for MVP
+ if (controllerActive) {
+ controllerCurX = x;
+ controllerCurY = y;
+ var input = getControllerInput(x, y);
+ controllerStick.x = controllerCenterX + input.dx;
+ controllerStick.y = controllerCenterY + input.dy;
+ controllerDirX = input.dx / controllerRadius;
+ controllerDirY = input.dy / controllerRadius;
+ }
};
+game.up = function (x, y, obj) {
+ controllerActive = false;
+ controllerStick.x = controllerCenterX;
+ controllerStick.y = controllerCenterY;
+ controllerDirX = 0;
+ controllerDirY = 0;
+ controllerJumpQueued = false;
+};
+// --- END Tablet Controller ---
// --- Physics Constants ---
var GRAVITY = 2.2;
var MOVE_SPEED = 18;
var JUMP_VEL = -48;
var MAX_FALL = 60;
// --- Game Update Loop ---
game.update = function () {
if (!player || player.dead) return;
- // Horizontal movement
- if (touchLeft) {
- player.vx = -MOVE_SPEED;
- } else if (touchRight) {
- player.vx = MOVE_SPEED;
+ // Horizontal movement (tablet controller)
+ if (controllerDirX < -0.2) {
+ player.vx = -MOVE_SPEED * Math.min(1, Math.abs(controllerDirX));
+ } else if (controllerDirX > 0.2) {
+ player.vx = MOVE_SPEED * Math.min(1, Math.abs(controllerDirX));
} else {
player.vx = 0;
}
- // Jump
- if (player.jumpQueued && player.onGround) {
+ // Jump (tablet controller)
+ if ((controllerJumpQueued || controllerActive && controllerDirY < -0.5) && player.onGround) {
player.vy = JUMP_VEL;
player.onGround = false;
- player.jumpQueued = false;
+ controllerJumpQueued = false;
}
// Gravity
player.vy += GRAVITY;
if (player.vy > MAX_FALL) player.vy = MAX_FALL;