/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
var storage = LK.import("@upit/storage.v1", {
money: 0,
clickValue: 1,
clickUpgradeCost: 50,
passiveIncome: 0,
passiveUpgradeCost: 100
});
/****
* Classes
****/
// Passive Income Upgrade Button
var PassiveButton = Container.expand(function () {
var self = Container.call(this);
var btn = self.attachAsset('passiveBtn', {
anchorX: 0.5,
anchorY: 0.5
});
var txt = new Text2('', {
size: 44,
fill: 0xFFFBE6
});
txt.anchor.set(0.5, 0.5);
self.addChild(txt);
function updateText() {
txt.setText("Auto-Sell\n$" + storage.passiveUpgradeCost);
}
self.updateText = updateText;
self.down = function (x, y, obj) {
if (storage.money >= storage.passiveUpgradeCost) {
storage.money -= storage.passiveUpgradeCost;
storage.passiveIncome += 1;
storage.passiveUpgradeCost = Math.floor(storage.passiveUpgradeCost * 1.7 + 20);
updateMoneyDisplay();
updatePassiveDisplay();
updateUpgradeButtons();
// Animate
tween(self, {
scaleX: 1.1,
scaleY: 1.1
}, {
duration: 80,
easing: tween.easeOut,
onFinish: function onFinish() {
tween(self, {
scaleX: 1,
scaleY: 1
}, {
duration: 80,
easing: tween.easeIn
});
}
});
LK.getSound('upgrade').play();
} else {
// Subtle shake if not enough money
tween(self, {
x: self.x + 18
}, {
duration: 60,
easing: tween.easeIn,
onFinish: function onFinish() {
tween(self, {
x: self.x - 36
}, {
duration: 60,
easing: tween.easeIn,
onFinish: function onFinish() {
tween(self, {
x: self.x + 18
}, {
duration: 60,
easing: tween.easeOut
});
}
});
}
});
}
};
updateText();
return self;
});
// Shoe Button (tap to sell)
var ShoeButton = Container.expand(function () {
var self = Container.call(this);
var btn = self.attachAsset('shoeBtn', {
anchorX: 0.5,
anchorY: 0.5
});
// Decorative: subtle bounce on tap
self.down = function (x, y, obj) {
// Animate scale
tween(self, {
scaleX: 0.92,
scaleY: 0.92
}, {
duration: 60,
easing: tween.easeIn,
onFinish: function onFinish() {
tween(self, {
scaleX: 1,
scaleY: 1
}, {
duration: 80,
easing: tween.easeOut
});
}
});
// Play sale sound
LK.getSound('sale').play();
// Add money
storage.money += storage.clickValue;
updateMoneyDisplay();
// Subtle money icon pop
popMoneyIcon();
};
return self;
});
// Upgrade Button (tap to increase click value)
var UpgradeButton = Container.expand(function () {
var self = Container.call(this);
var btn = self.attachAsset('upgradeBtn', {
anchorX: 0.5,
anchorY: 0.5
});
var txt = new Text2('', {
size: 48,
fill: 0xFFFBE6
});
txt.anchor.set(0.5, 0.5);
self.addChild(txt);
function updateText() {
txt.setText("Upgrade\n$" + storage.clickUpgradeCost);
}
self.updateText = updateText;
self.down = function (x, y, obj) {
if (storage.money >= storage.clickUpgradeCost) {
storage.money -= storage.clickUpgradeCost;
storage.clickValue += 1;
storage.clickUpgradeCost = Math.floor(storage.clickUpgradeCost * 1.5 + 10);
updateMoneyDisplay();
updateClickValueDisplay();
updateUpgradeButtons();
// Animate
tween(self, {
scaleX: 1.1,
scaleY: 1.1
}, {
duration: 80,
easing: tween.easeOut,
onFinish: function onFinish() {
tween(self, {
scaleX: 1,
scaleY: 1
}, {
duration: 80,
easing: tween.easeIn
});
}
});
LK.getSound('upgrade').play();
} else {
// Subtle shake if not enough money
tween(self, {
x: self.x + 18
}, {
duration: 60,
easing: tween.easeIn,
onFinish: function onFinish() {
tween(self, {
x: self.x - 36
}, {
duration: 60,
easing: tween.easeIn,
onFinish: function onFinish() {
tween(self, {
x: self.x + 18
}, {
duration: 60,
easing: tween.easeOut
});
}
});
}
});
}
};
updateText();
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0xede7d2 // Subtle vintage beige
});
/****
* Game Code
****/
// Sound for upgrade
// Sound for sale
// Boutique background (subtle, not a full background, just a decorative element)
// Money icon
// Passive income upgrade button
// Upgrade button
// Main shoe button (luxury shoe)
// Decorative boutique ellipse at top
var boutiqueDeco = LK.getAsset('boutiqueDeco', {
anchorX: 0.5,
anchorY: 0,
x: 2048 / 2,
y: 0,
scaleX: 1.1,
scaleY: 1
});
game.addChild(boutiqueDeco);
// Money display
var moneyIcon = LK.getAsset('moneyIcon', {
anchorX: 0.5,
anchorY: 0.5,
x: 2048 / 2 - 120,
y: 120
});
moneyIcon.scaleX = 1.1;
moneyIcon.scaleY = 1.1;
game.addChild(moneyIcon);
var moneyTxt = new Text2('', {
size: 90,
fill: 0x7C6F57
});
moneyTxt.anchor.set(0, 0.5);
moneyTxt.x = 2048 / 2 - 60;
moneyTxt.y = 120;
game.addChild(moneyTxt);
function formatMoney(val) {
if (val >= 1e9) {
return (val / 1e9).toFixed(2) + "B";
}
if (val >= 1e6) {
return (val / 1e6).toFixed(2) + "M";
}
if (val >= 1e3) {
return (val / 1e3).toFixed(1) + "K";
}
return "" + Math.floor(val);
}
function updateMoneyDisplay() {
moneyTxt.setText("$" + formatMoney(storage.money));
}
function popMoneyIcon() {
tween.stop(moneyIcon, {
scaleX: true,
scaleY: true
});
moneyIcon.scaleX = 1.1;
moneyIcon.scaleY = 1.1;
tween(moneyIcon, {
scaleX: 1.25,
scaleY: 1.25
}, {
duration: 60,
easing: tween.easeOut,
onFinish: function onFinish() {
tween(moneyIcon, {
scaleX: 1.1,
scaleY: 1.1
}, {
duration: 80,
easing: tween.easeIn
});
}
});
}
// Click value display
var clickValueTxt = new Text2('', {
size: 48,
fill: 0x8B7B5A
});
clickValueTxt.anchor.set(0.5, 0);
clickValueTxt.x = 2048 / 2;
clickValueTxt.y = 320;
game.addChild(clickValueTxt);
function updateClickValueDisplay() {
clickValueTxt.setText("Per Tap: $" + formatMoney(storage.clickValue));
}
// Passive income display
var passiveTxt = new Text2('', {
size: 44,
fill: 0xB7A77A
});
passiveTxt.anchor.set(0.5, 0);
passiveTxt.x = 2048 / 2;
passiveTxt.y = 390;
game.addChild(passiveTxt);
function updatePassiveDisplay() {
if (storage.passiveIncome > 0) {
passiveTxt.setText("Auto: $" + formatMoney(storage.passiveIncome) + "/sec");
} else {
passiveTxt.setText("Auto: $0/sec");
}
}
// Main shoe button
var shoeBtn = new ShoeButton();
shoeBtn.x = 2048 / 2;
shoeBtn.y = 800;
game.addChild(shoeBtn);
// Upgrade buttons
var upgradeBtn = new UpgradeButton();
upgradeBtn.x = 2048 / 2 - 220;
upgradeBtn.y = 1200;
game.addChild(upgradeBtn);
var passiveBtn = new PassiveButton();
passiveBtn.x = 2048 / 2 + 220;
passiveBtn.y = 1200;
game.addChild(passiveBtn);
function updateUpgradeButtons() {
upgradeBtn.updateText();
passiveBtn.updateText();
}
// --- START MENU IMPLEMENTATION ---
var startMenuContainer = new Container();
var startBg = LK.getAsset('boutiqueDeco', {
anchorX: 0.5,
anchorY: 0.5,
x: 2048 / 2,
y: 2732 / 2,
scaleX: 2.2,
scaleY: 2.2
});
startMenuContainer.addChild(startBg);
var startTitle = new Text2('SHOE TYCOON', {
size: 120,
fill: 0x7C6F57
});
startTitle.anchor.set(0.5, 0.5);
startTitle.x = 2048 / 2;
startTitle.y = 900;
startMenuContainer.addChild(startTitle);
var playBtn = LK.getAsset('upgradeBtn', {
anchorX: 0.5,
anchorY: 0.5,
x: 2048 / 2,
y: 1500,
scaleX: 1.4,
scaleY: 1.2
});
startMenuContainer.addChild(playBtn);
var playTxt = new Text2('PLAY', {
size: 80,
fill: 0xFFFBE6
});
playTxt.anchor.set(0.5, 0.5);
playTxt.x = 2048 / 2;
playTxt.y = 1400;
startMenuContainer.addChild(playTxt);
game.addChild(startMenuContainer);
// Hide all gameplay UI until play is pressed
function setGameplayUIVisible(visible) {
moneyIcon.visible = visible;
moneyTxt.visible = visible;
clickValueTxt.visible = visible;
passiveTxt.visible = visible;
shoeBtn.visible = visible;
upgradeBtn.visible = visible;
passiveBtn.visible = visible;
boutiqueDeco.visible = visible;
if (typeof titleTxt !== "undefined" && titleTxt) {
titleTxt.visible = visible;
}
}
setGameplayUIVisible(false);
// Play button handler
playBtn.interactive = true;
playBtn.down = function (x, y, obj) {
// Animate play button
tween(playBtn, {
scaleX: 1.2,
scaleY: 1.1
}, {
duration: 80,
easing: tween.easeOut,
onFinish: function onFinish() {
tween(playBtn, {
scaleX: 1.4,
scaleY: 1.2
}, {
duration: 80,
easing: tween.easeIn
});
}
});
// Fade out menu
tween(startMenuContainer, {
alpha: 0
}, {
duration: 220,
easing: tween.easeIn,
onFinish: function onFinish() {
startMenuContainer.visible = false;
setGameplayUIVisible(true);
}
});
};
// GUI Title
var titleTxt = new Text2('SHOE TYCOON', {
size: 100,
fill: 0x7C6F57
});
titleTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(titleTxt);
// Center title, but not in top left 100x100
titleTxt.x = LK.gui.top.width / 100;
titleTxt.y = 1300;
// Initial display update
updateMoneyDisplay();
updateClickValueDisplay();
updatePassiveDisplay();
updateUpgradeButtons();
// Passive income timer
var passiveTimer = LK.setInterval(function () {
if (storage.passiveIncome > 0) {
storage.money += storage.passiveIncome;
updateMoneyDisplay();
popMoneyIcon();
}
}, 1000);
// Save progress every 2 seconds
var saveTimer = LK.setInterval(function () {
// Storage is auto-persistent, but we can force a write if needed
// (No-op, but placeholder for future expansion)
}, 2000);
// Game update (not much needed, but could be used for future features)
game.update = function () {
// No per-frame logic needed for MVP
};
// Clean up on game over (not strictly needed, but good practice)
game.on('destroy', function () {
LK.clearInterval(passiveTimer);
LK.clearInterval(saveTimer);
});
// Touch handling for shoeBtn and upgrade buttons
// (Handled by their own .down methods, no need for game.down)
// Prevent elements in top left 100x100
// (All elements are centered or offset from center, so this is satisfied); /****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
var storage = LK.import("@upit/storage.v1", {
money: 0,
clickValue: 1,
clickUpgradeCost: 50,
passiveIncome: 0,
passiveUpgradeCost: 100
});
/****
* Classes
****/
// Passive Income Upgrade Button
var PassiveButton = Container.expand(function () {
var self = Container.call(this);
var btn = self.attachAsset('passiveBtn', {
anchorX: 0.5,
anchorY: 0.5
});
var txt = new Text2('', {
size: 44,
fill: 0xFFFBE6
});
txt.anchor.set(0.5, 0.5);
self.addChild(txt);
function updateText() {
txt.setText("Auto-Sell\n$" + storage.passiveUpgradeCost);
}
self.updateText = updateText;
self.down = function (x, y, obj) {
if (storage.money >= storage.passiveUpgradeCost) {
storage.money -= storage.passiveUpgradeCost;
storage.passiveIncome += 1;
storage.passiveUpgradeCost = Math.floor(storage.passiveUpgradeCost * 1.7 + 20);
updateMoneyDisplay();
updatePassiveDisplay();
updateUpgradeButtons();
// Animate
tween(self, {
scaleX: 1.1,
scaleY: 1.1
}, {
duration: 80,
easing: tween.easeOut,
onFinish: function onFinish() {
tween(self, {
scaleX: 1,
scaleY: 1
}, {
duration: 80,
easing: tween.easeIn
});
}
});
LK.getSound('upgrade').play();
} else {
// Subtle shake if not enough money
tween(self, {
x: self.x + 18
}, {
duration: 60,
easing: tween.easeIn,
onFinish: function onFinish() {
tween(self, {
x: self.x - 36
}, {
duration: 60,
easing: tween.easeIn,
onFinish: function onFinish() {
tween(self, {
x: self.x + 18
}, {
duration: 60,
easing: tween.easeOut
});
}
});
}
});
}
};
updateText();
return self;
});
// Shoe Button (tap to sell)
var ShoeButton = Container.expand(function () {
var self = Container.call(this);
var btn = self.attachAsset('shoeBtn', {
anchorX: 0.5,
anchorY: 0.5
});
// Decorative: subtle bounce on tap
self.down = function (x, y, obj) {
// Animate scale
tween(self, {
scaleX: 0.92,
scaleY: 0.92
}, {
duration: 60,
easing: tween.easeIn,
onFinish: function onFinish() {
tween(self, {
scaleX: 1,
scaleY: 1
}, {
duration: 80,
easing: tween.easeOut
});
}
});
// Play sale sound
LK.getSound('sale').play();
// Add money
storage.money += storage.clickValue;
updateMoneyDisplay();
// Subtle money icon pop
popMoneyIcon();
};
return self;
});
// Upgrade Button (tap to increase click value)
var UpgradeButton = Container.expand(function () {
var self = Container.call(this);
var btn = self.attachAsset('upgradeBtn', {
anchorX: 0.5,
anchorY: 0.5
});
var txt = new Text2('', {
size: 48,
fill: 0xFFFBE6
});
txt.anchor.set(0.5, 0.5);
self.addChild(txt);
function updateText() {
txt.setText("Upgrade\n$" + storage.clickUpgradeCost);
}
self.updateText = updateText;
self.down = function (x, y, obj) {
if (storage.money >= storage.clickUpgradeCost) {
storage.money -= storage.clickUpgradeCost;
storage.clickValue += 1;
storage.clickUpgradeCost = Math.floor(storage.clickUpgradeCost * 1.5 + 10);
updateMoneyDisplay();
updateClickValueDisplay();
updateUpgradeButtons();
// Animate
tween(self, {
scaleX: 1.1,
scaleY: 1.1
}, {
duration: 80,
easing: tween.easeOut,
onFinish: function onFinish() {
tween(self, {
scaleX: 1,
scaleY: 1
}, {
duration: 80,
easing: tween.easeIn
});
}
});
LK.getSound('upgrade').play();
} else {
// Subtle shake if not enough money
tween(self, {
x: self.x + 18
}, {
duration: 60,
easing: tween.easeIn,
onFinish: function onFinish() {
tween(self, {
x: self.x - 36
}, {
duration: 60,
easing: tween.easeIn,
onFinish: function onFinish() {
tween(self, {
x: self.x + 18
}, {
duration: 60,
easing: tween.easeOut
});
}
});
}
});
}
};
updateText();
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0xede7d2 // Subtle vintage beige
});
/****
* Game Code
****/
// Sound for upgrade
// Sound for sale
// Boutique background (subtle, not a full background, just a decorative element)
// Money icon
// Passive income upgrade button
// Upgrade button
// Main shoe button (luxury shoe)
// Decorative boutique ellipse at top
var boutiqueDeco = LK.getAsset('boutiqueDeco', {
anchorX: 0.5,
anchorY: 0,
x: 2048 / 2,
y: 0,
scaleX: 1.1,
scaleY: 1
});
game.addChild(boutiqueDeco);
// Money display
var moneyIcon = LK.getAsset('moneyIcon', {
anchorX: 0.5,
anchorY: 0.5,
x: 2048 / 2 - 120,
y: 120
});
moneyIcon.scaleX = 1.1;
moneyIcon.scaleY = 1.1;
game.addChild(moneyIcon);
var moneyTxt = new Text2('', {
size: 90,
fill: 0x7C6F57
});
moneyTxt.anchor.set(0, 0.5);
moneyTxt.x = 2048 / 2 - 60;
moneyTxt.y = 120;
game.addChild(moneyTxt);
function formatMoney(val) {
if (val >= 1e9) {
return (val / 1e9).toFixed(2) + "B";
}
if (val >= 1e6) {
return (val / 1e6).toFixed(2) + "M";
}
if (val >= 1e3) {
return (val / 1e3).toFixed(1) + "K";
}
return "" + Math.floor(val);
}
function updateMoneyDisplay() {
moneyTxt.setText("$" + formatMoney(storage.money));
}
function popMoneyIcon() {
tween.stop(moneyIcon, {
scaleX: true,
scaleY: true
});
moneyIcon.scaleX = 1.1;
moneyIcon.scaleY = 1.1;
tween(moneyIcon, {
scaleX: 1.25,
scaleY: 1.25
}, {
duration: 60,
easing: tween.easeOut,
onFinish: function onFinish() {
tween(moneyIcon, {
scaleX: 1.1,
scaleY: 1.1
}, {
duration: 80,
easing: tween.easeIn
});
}
});
}
// Click value display
var clickValueTxt = new Text2('', {
size: 48,
fill: 0x8B7B5A
});
clickValueTxt.anchor.set(0.5, 0);
clickValueTxt.x = 2048 / 2;
clickValueTxt.y = 320;
game.addChild(clickValueTxt);
function updateClickValueDisplay() {
clickValueTxt.setText("Per Tap: $" + formatMoney(storage.clickValue));
}
// Passive income display
var passiveTxt = new Text2('', {
size: 44,
fill: 0xB7A77A
});
passiveTxt.anchor.set(0.5, 0);
passiveTxt.x = 2048 / 2;
passiveTxt.y = 390;
game.addChild(passiveTxt);
function updatePassiveDisplay() {
if (storage.passiveIncome > 0) {
passiveTxt.setText("Auto: $" + formatMoney(storage.passiveIncome) + "/sec");
} else {
passiveTxt.setText("Auto: $0/sec");
}
}
// Main shoe button
var shoeBtn = new ShoeButton();
shoeBtn.x = 2048 / 2;
shoeBtn.y = 800;
game.addChild(shoeBtn);
// Upgrade buttons
var upgradeBtn = new UpgradeButton();
upgradeBtn.x = 2048 / 2 - 220;
upgradeBtn.y = 1200;
game.addChild(upgradeBtn);
var passiveBtn = new PassiveButton();
passiveBtn.x = 2048 / 2 + 220;
passiveBtn.y = 1200;
game.addChild(passiveBtn);
function updateUpgradeButtons() {
upgradeBtn.updateText();
passiveBtn.updateText();
}
// --- START MENU IMPLEMENTATION ---
var startMenuContainer = new Container();
var startBg = LK.getAsset('boutiqueDeco', {
anchorX: 0.5,
anchorY: 0.5,
x: 2048 / 2,
y: 2732 / 2,
scaleX: 2.2,
scaleY: 2.2
});
startMenuContainer.addChild(startBg);
var startTitle = new Text2('SHOE TYCOON', {
size: 120,
fill: 0x7C6F57
});
startTitle.anchor.set(0.5, 0.5);
startTitle.x = 2048 / 2;
startTitle.y = 900;
startMenuContainer.addChild(startTitle);
var playBtn = LK.getAsset('upgradeBtn', {
anchorX: 0.5,
anchorY: 0.5,
x: 2048 / 2,
y: 1500,
scaleX: 1.4,
scaleY: 1.2
});
startMenuContainer.addChild(playBtn);
var playTxt = new Text2('PLAY', {
size: 80,
fill: 0xFFFBE6
});
playTxt.anchor.set(0.5, 0.5);
playTxt.x = 2048 / 2;
playTxt.y = 1400;
startMenuContainer.addChild(playTxt);
game.addChild(startMenuContainer);
// Hide all gameplay UI until play is pressed
function setGameplayUIVisible(visible) {
moneyIcon.visible = visible;
moneyTxt.visible = visible;
clickValueTxt.visible = visible;
passiveTxt.visible = visible;
shoeBtn.visible = visible;
upgradeBtn.visible = visible;
passiveBtn.visible = visible;
boutiqueDeco.visible = visible;
if (typeof titleTxt !== "undefined" && titleTxt) {
titleTxt.visible = visible;
}
}
setGameplayUIVisible(false);
// Play button handler
playBtn.interactive = true;
playBtn.down = function (x, y, obj) {
// Animate play button
tween(playBtn, {
scaleX: 1.2,
scaleY: 1.1
}, {
duration: 80,
easing: tween.easeOut,
onFinish: function onFinish() {
tween(playBtn, {
scaleX: 1.4,
scaleY: 1.2
}, {
duration: 80,
easing: tween.easeIn
});
}
});
// Fade out menu
tween(startMenuContainer, {
alpha: 0
}, {
duration: 220,
easing: tween.easeIn,
onFinish: function onFinish() {
startMenuContainer.visible = false;
setGameplayUIVisible(true);
}
});
};
// GUI Title
var titleTxt = new Text2('SHOE TYCOON', {
size: 100,
fill: 0x7C6F57
});
titleTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(titleTxt);
// Center title, but not in top left 100x100
titleTxt.x = LK.gui.top.width / 100;
titleTxt.y = 1300;
// Initial display update
updateMoneyDisplay();
updateClickValueDisplay();
updatePassiveDisplay();
updateUpgradeButtons();
// Passive income timer
var passiveTimer = LK.setInterval(function () {
if (storage.passiveIncome > 0) {
storage.money += storage.passiveIncome;
updateMoneyDisplay();
popMoneyIcon();
}
}, 1000);
// Save progress every 2 seconds
var saveTimer = LK.setInterval(function () {
// Storage is auto-persistent, but we can force a write if needed
// (No-op, but placeholder for future expansion)
}, 2000);
// Game update (not much needed, but could be used for future features)
game.update = function () {
// No per-frame logic needed for MVP
};
// Clean up on game over (not strictly needed, but good practice)
game.on('destroy', function () {
LK.clearInterval(passiveTimer);
LK.clearInterval(saveTimer);
});
// Touch handling for shoeBtn and upgrade buttons
// (Handled by their own .down methods, no need for game.down)
// Prevent elements in top left 100x100
// (All elements are centered or offset from center, so this is satisfied);