User prompt
delete the names on the horses competing
User prompt
delete the names on the competing horses
User prompt
slide the names of the competing horses to the top of the colors
User prompt
remove the place your bets post
User prompt
undo the last transaction you made
User prompt
type place your bet in red and scroll to the bottom of race1/9
User prompt
move the place your bet race text up by 2 inches
User prompt
remove the horse names from the top of the posts right in the middle
User prompt
edit the code so that the races and names are written on the numbers of the horses competing
User prompt
let him write the races and names on the competing horses
User prompt
slide the horses towards the bottom of the start race section and get the start and finish line on the horse racing track
Code edit (1 edits merged)
Please save this source code
User prompt
Betting Derby: 9-Race Challenge
Initial prompt
betting is a horse racing game where we win and lose money that we know is a 9-race game
/**** * Plugins ****/ var tween = LK.import("@upit/tween.v1"); /**** * Classes ****/ // Horse class: represents a single horse in a race var Horse = Container.expand(function () { var self = Container.call(this); // Asset: Each horse is a colored ellipse with a number label and name var horseColor = self.horseColor || 0x888888; // Make the horse visual more prominent: increase size and add pulsing animation during race var horseAsset = self.attachAsset('horseShape', { width: 180, height: 90, color: horseColor, shape: 'ellipse', anchorX: 0.5, anchorY: 0.5 }); // Add a subtle pulsing animation to the horse when racing self.pulseTween = null; function startPulse() { if (self.pulseTween) return; self.pulseTween = tween(horseAsset, { scaleX: 1.15, scaleY: 0.92 }, { duration: 320, easing: tween.sineInOut, onFinish: function onFinish() { tween(horseAsset, { scaleX: 1, scaleY: 1 }, { duration: 320, easing: tween.sineInOut, onFinish: function onFinish() { self.pulseTween = null; if (self.isRacing) startPulse(); } }); } }); } function stopPulse() { if (self.pulseTween) { tween.stop(horseAsset, { scaleX: true, scaleY: true }); self.pulseTween = null; } horseAsset.scaleX = 1; horseAsset.scaleY = 1; } // Number label (top left of horse) var numberText = new Text2(self.horseNumber ? String(self.horseNumber) : '?', { size: 44, fill: 0xFFFFFF }); numberText.anchor.set(0, 0); numberText.x = -50; numberText.y = -28; self.addChild(numberText); // Name label removed (no name label on horse) // Horse properties self.horseNumber = self.horseNumber || 1; self.odd = self.odd || 2.0; self.lane = self.lane || 1; self.speed = 0; self.progress = 0; // 0 to 1 self.isRacing = false; self.horseName = ""; // will be set in prepareForRace // For animation self.update = function () { if (self.isRacing) { // Move horse forward based on speed self.progress += self.speed; if (self.progress > 1) self.progress = 1; // Update x position self.x = self.startX + (self.finishX - self.startX) * self.progress; } }; // Set up for race self.prepareForRace = function (startX, finishX, laneY, odd, horseNumber, color, horseName) { self.startX = startX; self.finishX = finishX; self.y = laneY; self.x = startX; self.progress = 0; self.odd = odd; self.horseNumber = horseNumber; horseAsset.tint = color; numberText.setText(String(horseNumber)); self.horseColor = color; self.horseName = horseName || ""; // nameText.setText(self.horseName); // removed, no name label }; // Start racing self.startRace = function (speed) { self.isRacing = true; self.speed = speed; startPulse(); }; // Stop racing self.stopRace = function () { self.isRacing = false; stopPulse(); }; return self; }); /**** * Initialize Game ****/ var game = new LK.Game({ backgroundColor: 0x1a3d5c }); /**** * Game Code ****/ // --- Game Constants --- var GAME_WIDTH = 2048; var GAME_HEIGHT = 2732; var LANE_COUNT = 5; var RACE_COUNT = 9; var HORSE_COLORS = [0xf44336, 0x2196f3, 0x4caf50, 0xffeb3b, 0x9c27b0, 0xff9800, 0x00bcd4, 0x795548, 0x607d8b]; var LANE_HEIGHT = 180; // Move the track down to align with the start button (which is at y: 480 in betPanel, which is at TRACK_TOP - 120) // The start button's y in global coordinates is TRACK_TOP - 120 + 480 = TRACK_TOP + 360 // We want the top of the track to be just below the start button, so set TRACK_TOP accordingly var TRACK_TOP = 900; // was 600, now moved down by 300px var TRACK_LEFT = 200; var TRACK_RIGHT = GAME_WIDTH - 200; var HORSE_SIZE = 180; var START_BALANCE = 1000; // --- Track Lines (Start/Finish) --- var startLine = null; var finishLine = null; // --- Game State --- var currentRace = 1; var playerBalance = START_BALANCE; var horses = []; var raceOdds = []; var raceResults = []; var playerBets = []; var isBettingOpen = true; var winningHorse = null; var raceInProgress = false; var raceFinished = false; var raceTimer = null; var betButtons = []; var betAmountInputs = []; var betTexts = []; var infoText = null; var balanceText = null; var raceText = null; var betPanel = null; var resultPanel = null; var nextRaceButton = null; // --- GUI Setup --- // Balance display balanceText = new Text2("Balance: $" + playerBalance, { size: 80, fill: 0xFFFFFF }); balanceText.anchor.set(0.5, 0); LK.gui.top.addChild(balanceText); // Race number display raceText = new Text2("Race 1 / " + RACE_COUNT, { size: 60, fill: 0xFFFFFF }); raceText.anchor.set(0.5, 0); LK.gui.top.addChild(raceText); raceText.y = 90; // Info text (centered) infoText = new Text2("", { size: 70, fill: 0xFFFBE6 }); infoText.anchor.set(0.5, 0.5); LK.gui.center.addChild(infoText); // --- Helper Functions --- function getLaneY(lane) { return TRACK_TOP + (lane - 1) * LANE_HEIGHT; } function randomOdd() { // Odds between 1.5 and 6.0, rounded to 1 decimal var odd = 1.5 + Math.random() * 4.5; return Math.round(odd * 10) / 10; } function shuffleArray(arr) { // Fisher-Yates shuffle for (var i = arr.length - 1; i > 0; i--) { var j = Math.floor(Math.random() * (i + 1)); var t = arr[i]; arr[i] = arr[j]; arr[j] = t; } return arr; } function resetBets() { playerBets = []; for (var i = 0; i < LANE_COUNT; i++) { playerBets.push(0); } } function updateBalanceText() { balanceText.setText("Balance: $" + playerBalance); } function updateRaceText() { raceText.setText("Race " + currentRace + " / " + RACE_COUNT); } function showInfo(msg, duration) { infoText.setText(msg); infoText.visible = true; if (duration) { LK.setTimeout(function () { infoText.setText(""); infoText.visible = false; }, duration); } } function showResultPanel(winning, payout) { if (!resultPanel) { resultPanel = new Container(); var bg = LK.getAsset('resultBg', { width: 900, height: 500, color: 0x222222, shape: 'box', anchorX: 0.5, anchorY: 0.5 }); resultPanel.addChild(bg); resultPanel.x = GAME_WIDTH / 2; resultPanel.y = GAME_HEIGHT / 2; resultPanel.zIndex = 1000; resultPanel.visible = false; game.addChild(resultPanel); resultPanel.resultText = new Text2("", { size: 80, fill: 0xFFFBE6 }); resultPanel.resultText.anchor.set(0.5, 0.5); resultPanel.resultText.y = -60; resultPanel.addChild(resultPanel.resultText); resultPanel.payoutText = new Text2("", { size: 60, fill: 0xFFFFFF }); resultPanel.payoutText.anchor.set(0.5, 0.5); resultPanel.payoutText.y = 60; resultPanel.addChild(resultPanel.payoutText); } resultPanel.resultText.setText("Winner: #" + winning); if (payout > 0) { resultPanel.payoutText.setText("You won $" + payout + "!"); } else { resultPanel.payoutText.setText("No winnings this race."); } resultPanel.visible = true; LK.setTimeout(function () { resultPanel.visible = false; }, 1800); } // --- Bet Panel Setup --- function setupBetPanel() { if (betPanel) { betPanel.destroy(); betPanel = null; } betPanel = new Container(); betPanel.x = GAME_WIDTH / 2; // Position betPanel directly under the racetrack betPanel.y = TRACK_TOP + LANE_COUNT * LANE_HEIGHT + 60; game.addChild(betPanel); // Play fun background music (looping, fade in) LK.playMusic('funbgmusic', { fade: { start: 0, end: 0.7, duration: 800 } }); // Title removed: No 'Place Your Bets!' post // Add 'BET' post/title to betPanel var betLabel = new Text2("BET", { size: 60, fill: 0xFFFBE6 }); betLabel.anchor.set(0.5, 0.5); betLabel.x = 0; betLabel.y = -100; betPanel.addChild(betLabel); // For each horse, show odds, bet amount, and a button to increase bet betButtons = []; betAmountInputs = []; betTexts = []; for (var i = 0; i < LANE_COUNT; i++) { (function (idx) { var laneY = i * 90; // Horse number and odds var horseLabel = new Text2("#" + (idx + 1) + " (" + raceOdds[idx] + "x)", { size: 48, fill: 0xFFFFFF }); horseLabel.anchor.set(0, 0.5); horseLabel.x = -320; horseLabel.y = laneY; betPanel.addChild(horseLabel); // Bet amount text var betText = new Text2("$" + playerBets[idx], { size: 48, fill: 0xFFFBE6 }); betText.anchor.set(0.5, 0.5); betText.x = 0; betText.y = laneY; betPanel.addChild(betText); betTexts.push(betText); // Bet + button var betBtn = LK.getAsset('betBtn', { width: 90, height: 60, color: 0x4caf50, shape: 'box', anchorX: 0.5, anchorY: 0.5, x: 180, y: laneY }); betPanel.addChild(betBtn); betButtons.push(betBtn); // Bet - button var betMinusBtn = LK.getAsset('betMinusBtn', { width: 90, height: 60, color: 0xf44336, shape: 'box', anchorX: 0.5, anchorY: 0.5, x: 90, y: laneY }); betPanel.addChild(betMinusBtn); // + Button event betBtn.down = function (x, y, obj) { if (!isBettingOpen) return; // Animate button press: scale down then back up tween(betBtn, { scaleX: 0.88, scaleY: 0.88 }, { duration: 60, easing: tween.cubicOut, onFinish: function onFinish() { tween(betBtn, { scaleX: 1, scaleY: 1 }, { duration: 80, easing: tween.cubicOut }); } }); // Play button press sound LK.getSound('botton').play(); if (playerBalance >= 10) { playerBets[idx] += 10; playerBalance -= 10; betTexts[idx].setText("$" + playerBets[idx]); updateBalanceText(); } }; // - Button event betMinusBtn.down = function (x, y, obj) { if (!isBettingOpen) return; // Animate button press: scale down then back up tween(betMinusBtn, { scaleX: 0.88, scaleY: 0.88 }, { duration: 60, easing: tween.cubicOut, onFinish: function onFinish() { tween(betMinusBtn, { scaleX: 1, scaleY: 1 }, { duration: 80, easing: tween.cubicOut }); } }); // Play button press sound LK.getSound('botton').play(); if (playerBets[idx] >= 10) { playerBets[idx] -= 10; playerBalance += 10; betTexts[idx].setText("$" + playerBets[idx]); updateBalanceText(); } }; })(i); } // Start Race button var startBtn = LK.getAsset('startBtn', { width: 320, height: 90, color: 0x2196f3, shape: 'box', anchorX: 0.5, anchorY: 0.5, x: 0, y: 480 }); betPanel.addChild(startBtn); var startBtnText = new Text2("Start Race", { size: 54, fill: 0xFFFFFF }); startBtnText.anchor.set(0.5, 0.5); startBtnText.x = 0; startBtnText.y = 480; betPanel.addChild(startBtnText); startBtn.down = function (x, y, obj) { if (!isBettingOpen) return; // Animate button press: scale down then back up tween(startBtn, { scaleX: 0.92, scaleY: 0.92 }, { duration: 70, easing: tween.cubicOut, onFinish: function onFinish() { tween(startBtn, { scaleX: 1, scaleY: 1 }, { duration: 100, easing: tween.cubicOut }); } }); // Play button press sound LK.getSound('horserace').play(); // Must bet at least on one horse var totalBet = 0; for (var i = 0; i < LANE_COUNT; i++) totalBet += playerBets[i]; if (totalBet === 0) { showInfo("Place a bet to start!", 1200); return; } isBettingOpen = false; betPanel.visible = false; // Stop fun background music LK.stopMusic(); // Play horse racing sound (already played above) startRace(); }; } // --- Race Setup --- function setupRace() { // Remove previous horses for (var i = 0; i < horses.length; i++) { horses[i].destroy(); } horses = []; // Remove previous lines if they exist if (startLine) { startLine.destroy(); startLine = null; } if (finishLine) { finishLine.destroy(); finishLine = null; } // --- RACE HEADER & HORSE NAMES --- // Remove previous race header/names if present if (game.raceHeader) { game.raceHeader.destroy(); game.raceHeader = null; } if (game.horseNameLabels) { for (var i = 0; i < game.horseNameLabels.length; i++) { game.horseNameLabels[i].destroy(); } game.horseNameLabels = null; } // Race header (e.g. "Race 1") game.raceHeader = new Text2("Race " + currentRace, { size: 90, fill: 0xFFFBE6 }); game.raceHeader.anchor.set(0.5, 0.5); game.raceHeader.x = GAME_WIDTH / 2; // Move race header to just above the new TRACK_TOP game.raceHeader.y = TRACK_TOP - 180; game.addChild(game.raceHeader); // Example horse names (can be replaced with dynamic names if desired) var HORSE_NAMES = ["Thunderbolt", "Blue Streak", "Green Flash", "Gold Rush", "Purple Haze", "Orange Blaze", "Aqua Jet", "Brown Sugar", "Steel Runner"]; // --- Race meter (startLine and finishLine) --- startLine = LK.getAsset('finalBg', { width: 48, //{2O} // Increased from 12 to 48 for a wider line height: LANE_COUNT * LANE_HEIGHT + 40, color: 0xffffff, shape: 'box', anchorX: 0.5, anchorY: 0.5, x: TRACK_LEFT, y: TRACK_TOP + LANE_COUNT * LANE_HEIGHT / 2 }); game.addChild(startLine); finishLine = LK.getAsset('finalBg', { width: 48, //{2V} // Increased from 12 to 48 for a wider line height: LANE_COUNT * LANE_HEIGHT + 40, color: 0xffd700, shape: 'box', anchorX: 0.5, anchorY: 0.5, x: TRACK_RIGHT, y: TRACK_TOP + LANE_COUNT * LANE_HEIGHT / 2 }); game.addChild(finishLine); // Generate odds for this race raceOdds = []; for (var i = 0; i < LANE_COUNT; i++) { raceOdds.push(randomOdd()); } // Shuffle horse colors for variety var colorOrder = []; for (var i = 0; i < LANE_COUNT; i++) colorOrder.push(HORSE_COLORS[i % HORSE_COLORS.length]); shuffleArray(colorOrder); // Create horses game.horseNameLabels = []; for (var i = 0; i < LANE_COUNT; i++) { var horse = new Horse(); // Slide horses to just above the start line (bottom of the start race section) var laneY = getLaneY(i + 1); // Offset horses so their center is just above the start line, and slide down a little more (e.g. +32px) var horseY = laneY + LANE_HEIGHT / 2 - HORSE_SIZE / 2 + 32; horse.prepareForRace(TRACK_LEFT, TRACK_RIGHT, horseY, raceOdds[i], i + 1, colorOrder[i], HORSE_NAMES[i] // pass horse name ); horses.push(horse); game.addChild(horse); // Add horse name label positioned on the horse, just below the top, so as not to cover the top var nameLabel = new Text2(HORSE_NAMES[i], { size: 48, fill: colorOrder[i], // Use the horse's color for the name label stroke: 0x000000, // Add black outline for readability strokeThickness: 8 }); nameLabel.anchor.set(0.5, 0); // Move the name label up a little more (from +2 to -10) nameLabel.x = horse.x; nameLabel.y = horse.y - HORSE_SIZE / 2 - 10; game.addChild(nameLabel); game.horseNameLabels.push(nameLabel); } resetBets(); isBettingOpen = true; raceInProgress = false; raceFinished = false; winningHorse = null; updateRaceText(); setupBetPanel(); showInfo("Race " + currentRace + ": Place your bets!", 1200); } // --- Race Logic --- function startRace() { raceInProgress = true; raceFinished = false; // Only show race shout if the game is not over and not finished if (currentRace <= RACE_COUNT && !raceFinished) { showInfo("They're off!", 1000); } // Assign random speeds, but ensure one winner // SLOWER: Reduce base and winner speed var baseSpeed = 0.003 + Math.random() * 0.001; // All horses move at least this fast (halved) var winnerIdx = Math.floor(Math.random() * LANE_COUNT); var winnerSpeed = baseSpeed + 0.001 + Math.random() * 0.001; // winner is also slower for (var i = 0; i < LANE_COUNT; i++) { if (i === winnerIdx) { horses[i].startRace(winnerSpeed); } else { // Randomize, but not faster than winner var s = baseSpeed + Math.random() * (winnerSpeed - baseSpeed - 0.0005); horses[i].startRace(s); } } winningHorse = winnerIdx + 1; // Stop the race and sound after 5 seconds if (raceTimer) { LK.clearTimeout(raceTimer); } raceTimer = LK.setTimeout(function () { if (raceInProgress && !raceFinished) { // Stop all horses for (var i = 0; i < LANE_COUNT; i++) { horses[i].stopRace(); } raceInProgress = false; raceFinished = true; // Stop the horse race sound LK.getSound('horserace').stop && LK.getSound('horserace').stop(); // If the winner hasn't crossed, finish the race anyway finishRace(); } }, 5000); } function finishRace() { raceInProgress = false; raceFinished = true; // Stop all horses for (var i = 0; i < LANE_COUNT; i++) { horses[i].stopRace(); } // Calculate payout var payout = 0; if (playerBets[winningHorse - 1] > 0) { payout = Math.floor(playerBets[winningHorse - 1] * raceOdds[winningHorse - 1]); playerBalance += payout; } updateBalanceText(); showResultPanel(winningHorse, payout); // Store result raceResults.push({ race: currentRace, winner: winningHorse, odds: raceOdds.slice(), bets: playerBets.slice(), payout: payout }); // Next race or end if (currentRace < RACE_COUNT) { LK.setTimeout(function () { currentRace++; setupRace(); }, 2000); } else { LK.setTimeout(function () { endGame(); }, 2200); } } function endGame() { // Show final result var finalPanel = new Container(); var bg = LK.getAsset('finalBg', { width: 1100, height: 700, color: 0x222222, shape: 'box', anchorX: 0.5, anchorY: 0.5 }); finalPanel.addChild(bg); finalPanel.x = GAME_WIDTH / 2; finalPanel.y = GAME_HEIGHT / 2; finalPanel.zIndex = 2000; game.addChild(finalPanel); var title = new Text2("Derby Complete!", { size: 100, fill: 0xFFFBE6 }); title.anchor.set(0.5, 0.5); title.y = -220; finalPanel.addChild(title); var bal = new Text2("Final Balance: $" + playerBalance, { size: 80, fill: 0xFFFFFF }); bal.anchor.set(0.5, 0.5); bal.y = -80; finalPanel.addChild(bal); var summary = new Text2("Thanks for playing!", { size: 60, fill: 0xFFFBE6 }); summary.anchor.set(0.5, 0.5); summary.y = 60; finalPanel.addChild(summary); // --- Detailed Derby Summary (below the flag image) --- var derbySummaryText = "The derby is over!\n\n"; derbySummaryText += "You completed " + RACE_COUNT + " races.\n"; derbySummaryText += "Final Balance: $" + playerBalance + "\n\n"; derbySummaryText += "Race Results:\n"; for (var i = 0; i < raceResults.length; i++) { var res = raceResults[i]; var betStr = ""; for (var j = 0; j < LANE_COUNT; j++) { if (res.bets[j] > 0) { betStr += "#" + (j + 1) + ": $" + res.bets[j] + " "; } } derbySummaryText += "Race " + res.race + ": Winner #" + res.winner + " (odds " + res.odds[res.winner - 1] + "x)" + (betStr ? " | Your bets: " + betStr : "") + (res.payout > 0 ? " | Won: $" + res.payout : "") + "\n"; } var derbySummary = new Text2(derbySummaryText, { size: 38, fill: 0xFFFBE6, wordWrap: true, wordWrapWidth: 950, align: "left" }); derbySummary.anchor.set(0.5, 0); derbySummary.y = 140; finalPanel.addChild(derbySummary); // Show "You Win" if balance > start, else "Game Over" if (playerBalance > START_BALANCE) { LK.setTimeout(function () { LK.showYouWin(); }, 1800); } else { LK.setTimeout(function () { LK.showGameOver(); }, 1800); } } // --- Game Update Loop --- game.update = function () { if (raceInProgress) { // Update horses var finishedCount = 0; for (var i = 0; i < horses.length; i++) { horses[i].update(); // Keep the horse name label on the horse, just below the top, following its x and y if (game.horseNameLabels && game.horseNameLabels[i]) { game.horseNameLabels[i].x = horses[i].x; game.horseNameLabels[i].y = horses[i].y - HORSE_SIZE / 2 - 10; // Always update the text in case horse names change dynamically game.horseNameLabels[i].setText(horses[i].horseName || ""); } if (horses[i].progress >= 1) finishedCount++; } // If winner crosses finish, finish race if (!raceFinished && horses[winningHorse - 1].progress >= 1) { // Stop the horse race sound immediately when winner finishes LK.getSound('horserace').stop && LK.getSound('horserace').stop(); finishRace(); } } }; // --- Start the first race --- setupRace(); updateBalanceText(); updateRaceText();
/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
/****
* Classes
****/
// Horse class: represents a single horse in a race
var Horse = Container.expand(function () {
var self = Container.call(this);
// Asset: Each horse is a colored ellipse with a number label and name
var horseColor = self.horseColor || 0x888888;
// Make the horse visual more prominent: increase size and add pulsing animation during race
var horseAsset = self.attachAsset('horseShape', {
width: 180,
height: 90,
color: horseColor,
shape: 'ellipse',
anchorX: 0.5,
anchorY: 0.5
});
// Add a subtle pulsing animation to the horse when racing
self.pulseTween = null;
function startPulse() {
if (self.pulseTween) return;
self.pulseTween = tween(horseAsset, {
scaleX: 1.15,
scaleY: 0.92
}, {
duration: 320,
easing: tween.sineInOut,
onFinish: function onFinish() {
tween(horseAsset, {
scaleX: 1,
scaleY: 1
}, {
duration: 320,
easing: tween.sineInOut,
onFinish: function onFinish() {
self.pulseTween = null;
if (self.isRacing) startPulse();
}
});
}
});
}
function stopPulse() {
if (self.pulseTween) {
tween.stop(horseAsset, {
scaleX: true,
scaleY: true
});
self.pulseTween = null;
}
horseAsset.scaleX = 1;
horseAsset.scaleY = 1;
}
// Number label (top left of horse)
var numberText = new Text2(self.horseNumber ? String(self.horseNumber) : '?', {
size: 44,
fill: 0xFFFFFF
});
numberText.anchor.set(0, 0);
numberText.x = -50;
numberText.y = -28;
self.addChild(numberText);
// Name label removed (no name label on horse)
// Horse properties
self.horseNumber = self.horseNumber || 1;
self.odd = self.odd || 2.0;
self.lane = self.lane || 1;
self.speed = 0;
self.progress = 0; // 0 to 1
self.isRacing = false;
self.horseName = ""; // will be set in prepareForRace
// For animation
self.update = function () {
if (self.isRacing) {
// Move horse forward based on speed
self.progress += self.speed;
if (self.progress > 1) self.progress = 1;
// Update x position
self.x = self.startX + (self.finishX - self.startX) * self.progress;
}
};
// Set up for race
self.prepareForRace = function (startX, finishX, laneY, odd, horseNumber, color, horseName) {
self.startX = startX;
self.finishX = finishX;
self.y = laneY;
self.x = startX;
self.progress = 0;
self.odd = odd;
self.horseNumber = horseNumber;
horseAsset.tint = color;
numberText.setText(String(horseNumber));
self.horseColor = color;
self.horseName = horseName || "";
// nameText.setText(self.horseName); // removed, no name label
};
// Start racing
self.startRace = function (speed) {
self.isRacing = true;
self.speed = speed;
startPulse();
};
// Stop racing
self.stopRace = function () {
self.isRacing = false;
stopPulse();
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x1a3d5c
});
/****
* Game Code
****/
// --- Game Constants ---
var GAME_WIDTH = 2048;
var GAME_HEIGHT = 2732;
var LANE_COUNT = 5;
var RACE_COUNT = 9;
var HORSE_COLORS = [0xf44336, 0x2196f3, 0x4caf50, 0xffeb3b, 0x9c27b0, 0xff9800, 0x00bcd4, 0x795548, 0x607d8b];
var LANE_HEIGHT = 180;
// Move the track down to align with the start button (which is at y: 480 in betPanel, which is at TRACK_TOP - 120)
// The start button's y in global coordinates is TRACK_TOP - 120 + 480 = TRACK_TOP + 360
// We want the top of the track to be just below the start button, so set TRACK_TOP accordingly
var TRACK_TOP = 900; // was 600, now moved down by 300px
var TRACK_LEFT = 200;
var TRACK_RIGHT = GAME_WIDTH - 200;
var HORSE_SIZE = 180;
var START_BALANCE = 1000;
// --- Track Lines (Start/Finish) ---
var startLine = null;
var finishLine = null;
// --- Game State ---
var currentRace = 1;
var playerBalance = START_BALANCE;
var horses = [];
var raceOdds = [];
var raceResults = [];
var playerBets = [];
var isBettingOpen = true;
var winningHorse = null;
var raceInProgress = false;
var raceFinished = false;
var raceTimer = null;
var betButtons = [];
var betAmountInputs = [];
var betTexts = [];
var infoText = null;
var balanceText = null;
var raceText = null;
var betPanel = null;
var resultPanel = null;
var nextRaceButton = null;
// --- GUI Setup ---
// Balance display
balanceText = new Text2("Balance: $" + playerBalance, {
size: 80,
fill: 0xFFFFFF
});
balanceText.anchor.set(0.5, 0);
LK.gui.top.addChild(balanceText);
// Race number display
raceText = new Text2("Race 1 / " + RACE_COUNT, {
size: 60,
fill: 0xFFFFFF
});
raceText.anchor.set(0.5, 0);
LK.gui.top.addChild(raceText);
raceText.y = 90;
// Info text (centered)
infoText = new Text2("", {
size: 70,
fill: 0xFFFBE6
});
infoText.anchor.set(0.5, 0.5);
LK.gui.center.addChild(infoText);
// --- Helper Functions ---
function getLaneY(lane) {
return TRACK_TOP + (lane - 1) * LANE_HEIGHT;
}
function randomOdd() {
// Odds between 1.5 and 6.0, rounded to 1 decimal
var odd = 1.5 + Math.random() * 4.5;
return Math.round(odd * 10) / 10;
}
function shuffleArray(arr) {
// Fisher-Yates shuffle
for (var i = arr.length - 1; i > 0; i--) {
var j = Math.floor(Math.random() * (i + 1));
var t = arr[i];
arr[i] = arr[j];
arr[j] = t;
}
return arr;
}
function resetBets() {
playerBets = [];
for (var i = 0; i < LANE_COUNT; i++) {
playerBets.push(0);
}
}
function updateBalanceText() {
balanceText.setText("Balance: $" + playerBalance);
}
function updateRaceText() {
raceText.setText("Race " + currentRace + " / " + RACE_COUNT);
}
function showInfo(msg, duration) {
infoText.setText(msg);
infoText.visible = true;
if (duration) {
LK.setTimeout(function () {
infoText.setText("");
infoText.visible = false;
}, duration);
}
}
function showResultPanel(winning, payout) {
if (!resultPanel) {
resultPanel = new Container();
var bg = LK.getAsset('resultBg', {
width: 900,
height: 500,
color: 0x222222,
shape: 'box',
anchorX: 0.5,
anchorY: 0.5
});
resultPanel.addChild(bg);
resultPanel.x = GAME_WIDTH / 2;
resultPanel.y = GAME_HEIGHT / 2;
resultPanel.zIndex = 1000;
resultPanel.visible = false;
game.addChild(resultPanel);
resultPanel.resultText = new Text2("", {
size: 80,
fill: 0xFFFBE6
});
resultPanel.resultText.anchor.set(0.5, 0.5);
resultPanel.resultText.y = -60;
resultPanel.addChild(resultPanel.resultText);
resultPanel.payoutText = new Text2("", {
size: 60,
fill: 0xFFFFFF
});
resultPanel.payoutText.anchor.set(0.5, 0.5);
resultPanel.payoutText.y = 60;
resultPanel.addChild(resultPanel.payoutText);
}
resultPanel.resultText.setText("Winner: #" + winning);
if (payout > 0) {
resultPanel.payoutText.setText("You won $" + payout + "!");
} else {
resultPanel.payoutText.setText("No winnings this race.");
}
resultPanel.visible = true;
LK.setTimeout(function () {
resultPanel.visible = false;
}, 1800);
}
// --- Bet Panel Setup ---
function setupBetPanel() {
if (betPanel) {
betPanel.destroy();
betPanel = null;
}
betPanel = new Container();
betPanel.x = GAME_WIDTH / 2;
// Position betPanel directly under the racetrack
betPanel.y = TRACK_TOP + LANE_COUNT * LANE_HEIGHT + 60;
game.addChild(betPanel);
// Play fun background music (looping, fade in)
LK.playMusic('funbgmusic', {
fade: {
start: 0,
end: 0.7,
duration: 800
}
});
// Title removed: No 'Place Your Bets!' post
// Add 'BET' post/title to betPanel
var betLabel = new Text2("BET", {
size: 60,
fill: 0xFFFBE6
});
betLabel.anchor.set(0.5, 0.5);
betLabel.x = 0;
betLabel.y = -100;
betPanel.addChild(betLabel);
// For each horse, show odds, bet amount, and a button to increase bet
betButtons = [];
betAmountInputs = [];
betTexts = [];
for (var i = 0; i < LANE_COUNT; i++) {
(function (idx) {
var laneY = i * 90;
// Horse number and odds
var horseLabel = new Text2("#" + (idx + 1) + " (" + raceOdds[idx] + "x)", {
size: 48,
fill: 0xFFFFFF
});
horseLabel.anchor.set(0, 0.5);
horseLabel.x = -320;
horseLabel.y = laneY;
betPanel.addChild(horseLabel);
// Bet amount text
var betText = new Text2("$" + playerBets[idx], {
size: 48,
fill: 0xFFFBE6
});
betText.anchor.set(0.5, 0.5);
betText.x = 0;
betText.y = laneY;
betPanel.addChild(betText);
betTexts.push(betText);
// Bet + button
var betBtn = LK.getAsset('betBtn', {
width: 90,
height: 60,
color: 0x4caf50,
shape: 'box',
anchorX: 0.5,
anchorY: 0.5,
x: 180,
y: laneY
});
betPanel.addChild(betBtn);
betButtons.push(betBtn);
// Bet - button
var betMinusBtn = LK.getAsset('betMinusBtn', {
width: 90,
height: 60,
color: 0xf44336,
shape: 'box',
anchorX: 0.5,
anchorY: 0.5,
x: 90,
y: laneY
});
betPanel.addChild(betMinusBtn);
// + Button event
betBtn.down = function (x, y, obj) {
if (!isBettingOpen) return;
// Animate button press: scale down then back up
tween(betBtn, {
scaleX: 0.88,
scaleY: 0.88
}, {
duration: 60,
easing: tween.cubicOut,
onFinish: function onFinish() {
tween(betBtn, {
scaleX: 1,
scaleY: 1
}, {
duration: 80,
easing: tween.cubicOut
});
}
});
// Play button press sound
LK.getSound('botton').play();
if (playerBalance >= 10) {
playerBets[idx] += 10;
playerBalance -= 10;
betTexts[idx].setText("$" + playerBets[idx]);
updateBalanceText();
}
};
// - Button event
betMinusBtn.down = function (x, y, obj) {
if (!isBettingOpen) return;
// Animate button press: scale down then back up
tween(betMinusBtn, {
scaleX: 0.88,
scaleY: 0.88
}, {
duration: 60,
easing: tween.cubicOut,
onFinish: function onFinish() {
tween(betMinusBtn, {
scaleX: 1,
scaleY: 1
}, {
duration: 80,
easing: tween.cubicOut
});
}
});
// Play button press sound
LK.getSound('botton').play();
if (playerBets[idx] >= 10) {
playerBets[idx] -= 10;
playerBalance += 10;
betTexts[idx].setText("$" + playerBets[idx]);
updateBalanceText();
}
};
})(i);
}
// Start Race button
var startBtn = LK.getAsset('startBtn', {
width: 320,
height: 90,
color: 0x2196f3,
shape: 'box',
anchorX: 0.5,
anchorY: 0.5,
x: 0,
y: 480
});
betPanel.addChild(startBtn);
var startBtnText = new Text2("Start Race", {
size: 54,
fill: 0xFFFFFF
});
startBtnText.anchor.set(0.5, 0.5);
startBtnText.x = 0;
startBtnText.y = 480;
betPanel.addChild(startBtnText);
startBtn.down = function (x, y, obj) {
if (!isBettingOpen) return;
// Animate button press: scale down then back up
tween(startBtn, {
scaleX: 0.92,
scaleY: 0.92
}, {
duration: 70,
easing: tween.cubicOut,
onFinish: function onFinish() {
tween(startBtn, {
scaleX: 1,
scaleY: 1
}, {
duration: 100,
easing: tween.cubicOut
});
}
});
// Play button press sound
LK.getSound('horserace').play();
// Must bet at least on one horse
var totalBet = 0;
for (var i = 0; i < LANE_COUNT; i++) totalBet += playerBets[i];
if (totalBet === 0) {
showInfo("Place a bet to start!", 1200);
return;
}
isBettingOpen = false;
betPanel.visible = false;
// Stop fun background music
LK.stopMusic();
// Play horse racing sound (already played above)
startRace();
};
}
// --- Race Setup ---
function setupRace() {
// Remove previous horses
for (var i = 0; i < horses.length; i++) {
horses[i].destroy();
}
horses = [];
// Remove previous lines if they exist
if (startLine) {
startLine.destroy();
startLine = null;
}
if (finishLine) {
finishLine.destroy();
finishLine = null;
}
// --- RACE HEADER & HORSE NAMES ---
// Remove previous race header/names if present
if (game.raceHeader) {
game.raceHeader.destroy();
game.raceHeader = null;
}
if (game.horseNameLabels) {
for (var i = 0; i < game.horseNameLabels.length; i++) {
game.horseNameLabels[i].destroy();
}
game.horseNameLabels = null;
}
// Race header (e.g. "Race 1")
game.raceHeader = new Text2("Race " + currentRace, {
size: 90,
fill: 0xFFFBE6
});
game.raceHeader.anchor.set(0.5, 0.5);
game.raceHeader.x = GAME_WIDTH / 2;
// Move race header to just above the new TRACK_TOP
game.raceHeader.y = TRACK_TOP - 180;
game.addChild(game.raceHeader);
// Example horse names (can be replaced with dynamic names if desired)
var HORSE_NAMES = ["Thunderbolt", "Blue Streak", "Green Flash", "Gold Rush", "Purple Haze", "Orange Blaze", "Aqua Jet", "Brown Sugar", "Steel Runner"];
// --- Race meter (startLine and finishLine) ---
startLine = LK.getAsset('finalBg', {
width: 48,
//{2O} // Increased from 12 to 48 for a wider line
height: LANE_COUNT * LANE_HEIGHT + 40,
color: 0xffffff,
shape: 'box',
anchorX: 0.5,
anchorY: 0.5,
x: TRACK_LEFT,
y: TRACK_TOP + LANE_COUNT * LANE_HEIGHT / 2
});
game.addChild(startLine);
finishLine = LK.getAsset('finalBg', {
width: 48,
//{2V} // Increased from 12 to 48 for a wider line
height: LANE_COUNT * LANE_HEIGHT + 40,
color: 0xffd700,
shape: 'box',
anchorX: 0.5,
anchorY: 0.5,
x: TRACK_RIGHT,
y: TRACK_TOP + LANE_COUNT * LANE_HEIGHT / 2
});
game.addChild(finishLine);
// Generate odds for this race
raceOdds = [];
for (var i = 0; i < LANE_COUNT; i++) {
raceOdds.push(randomOdd());
}
// Shuffle horse colors for variety
var colorOrder = [];
for (var i = 0; i < LANE_COUNT; i++) colorOrder.push(HORSE_COLORS[i % HORSE_COLORS.length]);
shuffleArray(colorOrder);
// Create horses
game.horseNameLabels = [];
for (var i = 0; i < LANE_COUNT; i++) {
var horse = new Horse();
// Slide horses to just above the start line (bottom of the start race section)
var laneY = getLaneY(i + 1);
// Offset horses so their center is just above the start line, and slide down a little more (e.g. +32px)
var horseY = laneY + LANE_HEIGHT / 2 - HORSE_SIZE / 2 + 32;
horse.prepareForRace(TRACK_LEFT, TRACK_RIGHT, horseY, raceOdds[i], i + 1, colorOrder[i], HORSE_NAMES[i] // pass horse name
);
horses.push(horse);
game.addChild(horse);
// Add horse name label positioned on the horse, just below the top, so as not to cover the top
var nameLabel = new Text2(HORSE_NAMES[i], {
size: 48,
fill: colorOrder[i],
// Use the horse's color for the name label
stroke: 0x000000,
// Add black outline for readability
strokeThickness: 8
});
nameLabel.anchor.set(0.5, 0);
// Move the name label up a little more (from +2 to -10)
nameLabel.x = horse.x;
nameLabel.y = horse.y - HORSE_SIZE / 2 - 10;
game.addChild(nameLabel);
game.horseNameLabels.push(nameLabel);
}
resetBets();
isBettingOpen = true;
raceInProgress = false;
raceFinished = false;
winningHorse = null;
updateRaceText();
setupBetPanel();
showInfo("Race " + currentRace + ": Place your bets!", 1200);
}
// --- Race Logic ---
function startRace() {
raceInProgress = true;
raceFinished = false;
// Only show race shout if the game is not over and not finished
if (currentRace <= RACE_COUNT && !raceFinished) {
showInfo("They're off!", 1000);
}
// Assign random speeds, but ensure one winner
// SLOWER: Reduce base and winner speed
var baseSpeed = 0.003 + Math.random() * 0.001; // All horses move at least this fast (halved)
var winnerIdx = Math.floor(Math.random() * LANE_COUNT);
var winnerSpeed = baseSpeed + 0.001 + Math.random() * 0.001; // winner is also slower
for (var i = 0; i < LANE_COUNT; i++) {
if (i === winnerIdx) {
horses[i].startRace(winnerSpeed);
} else {
// Randomize, but not faster than winner
var s = baseSpeed + Math.random() * (winnerSpeed - baseSpeed - 0.0005);
horses[i].startRace(s);
}
}
winningHorse = winnerIdx + 1;
// Stop the race and sound after 5 seconds
if (raceTimer) {
LK.clearTimeout(raceTimer);
}
raceTimer = LK.setTimeout(function () {
if (raceInProgress && !raceFinished) {
// Stop all horses
for (var i = 0; i < LANE_COUNT; i++) {
horses[i].stopRace();
}
raceInProgress = false;
raceFinished = true;
// Stop the horse race sound
LK.getSound('horserace').stop && LK.getSound('horserace').stop();
// If the winner hasn't crossed, finish the race anyway
finishRace();
}
}, 5000);
}
function finishRace() {
raceInProgress = false;
raceFinished = true;
// Stop all horses
for (var i = 0; i < LANE_COUNT; i++) {
horses[i].stopRace();
}
// Calculate payout
var payout = 0;
if (playerBets[winningHorse - 1] > 0) {
payout = Math.floor(playerBets[winningHorse - 1] * raceOdds[winningHorse - 1]);
playerBalance += payout;
}
updateBalanceText();
showResultPanel(winningHorse, payout);
// Store result
raceResults.push({
race: currentRace,
winner: winningHorse,
odds: raceOdds.slice(),
bets: playerBets.slice(),
payout: payout
});
// Next race or end
if (currentRace < RACE_COUNT) {
LK.setTimeout(function () {
currentRace++;
setupRace();
}, 2000);
} else {
LK.setTimeout(function () {
endGame();
}, 2200);
}
}
function endGame() {
// Show final result
var finalPanel = new Container();
var bg = LK.getAsset('finalBg', {
width: 1100,
height: 700,
color: 0x222222,
shape: 'box',
anchorX: 0.5,
anchorY: 0.5
});
finalPanel.addChild(bg);
finalPanel.x = GAME_WIDTH / 2;
finalPanel.y = GAME_HEIGHT / 2;
finalPanel.zIndex = 2000;
game.addChild(finalPanel);
var title = new Text2("Derby Complete!", {
size: 100,
fill: 0xFFFBE6
});
title.anchor.set(0.5, 0.5);
title.y = -220;
finalPanel.addChild(title);
var bal = new Text2("Final Balance: $" + playerBalance, {
size: 80,
fill: 0xFFFFFF
});
bal.anchor.set(0.5, 0.5);
bal.y = -80;
finalPanel.addChild(bal);
var summary = new Text2("Thanks for playing!", {
size: 60,
fill: 0xFFFBE6
});
summary.anchor.set(0.5, 0.5);
summary.y = 60;
finalPanel.addChild(summary);
// --- Detailed Derby Summary (below the flag image) ---
var derbySummaryText = "The derby is over!\n\n";
derbySummaryText += "You completed " + RACE_COUNT + " races.\n";
derbySummaryText += "Final Balance: $" + playerBalance + "\n\n";
derbySummaryText += "Race Results:\n";
for (var i = 0; i < raceResults.length; i++) {
var res = raceResults[i];
var betStr = "";
for (var j = 0; j < LANE_COUNT; j++) {
if (res.bets[j] > 0) {
betStr += "#" + (j + 1) + ": $" + res.bets[j] + " ";
}
}
derbySummaryText += "Race " + res.race + ": Winner #" + res.winner + " (odds " + res.odds[res.winner - 1] + "x)" + (betStr ? " | Your bets: " + betStr : "") + (res.payout > 0 ? " | Won: $" + res.payout : "") + "\n";
}
var derbySummary = new Text2(derbySummaryText, {
size: 38,
fill: 0xFFFBE6,
wordWrap: true,
wordWrapWidth: 950,
align: "left"
});
derbySummary.anchor.set(0.5, 0);
derbySummary.y = 140;
finalPanel.addChild(derbySummary);
// Show "You Win" if balance > start, else "Game Over"
if (playerBalance > START_BALANCE) {
LK.setTimeout(function () {
LK.showYouWin();
}, 1800);
} else {
LK.setTimeout(function () {
LK.showGameOver();
}, 1800);
}
}
// --- Game Update Loop ---
game.update = function () {
if (raceInProgress) {
// Update horses
var finishedCount = 0;
for (var i = 0; i < horses.length; i++) {
horses[i].update();
// Keep the horse name label on the horse, just below the top, following its x and y
if (game.horseNameLabels && game.horseNameLabels[i]) {
game.horseNameLabels[i].x = horses[i].x;
game.horseNameLabels[i].y = horses[i].y - HORSE_SIZE / 2 - 10;
// Always update the text in case horse names change dynamically
game.horseNameLabels[i].setText(horses[i].horseName || "");
}
if (horses[i].progress >= 1) finishedCount++;
}
// If winner crosses finish, finish race
if (!raceFinished && horses[winningHorse - 1].progress >= 1) {
// Stop the horse race sound immediately when winner finishes
LK.getSound('horserace').stop && LK.getSound('horserace').stop();
finishRace();
}
}
};
// --- Start the first race ---
setupRace();
updateBalanceText();
updateRaceText();
image of a racehorse. In-Game asset. 2d. High contrast. No shadows
pressable round button. In-Game asset. 2d. High contrast. No shadows
blue
green rectangle-shaped pressable button. In-Game asset. 2d. High contrast. No shadows
a line consisting of small squares in black and white is vertical from what happened at the races. In-Game asset. 2d. High contrast. No shadows