User prompt
remove comic intro from game
User prompt
display the SKIP and NEXT buttons as rextangular boxes with text. Make text black. Move both button left on screen
User prompt
increase the size of the SKIP and NEXT button text by 500%, opacity is 100%
User prompt
force the SKIP button to display on the top layer. Move it up and left into the visible screen space
User prompt
5. **Add Explicit Z-Index Management**: Use explicit `addChild` and `setChildIndex` calls after all elements are created to ensure proper layering to make the NEXT and SKIP buttons visible
User prompt
- Verify your container hierarchy - You did var comicIntro = new Container(); LK.gui.addChild(comicIntro); - so your intro (and its buttons) live on the GUI layer. Make sure you never do game.addChild(comicIntro) after calling LK.gui.addChild(), or you’ll bury it under the game stage. - Double-check visibility flags - Before your comic starts, you do game.visible = false; comicIntro.visible = true; // implicit - If you ever do game.visible = false after adding children to LK.gui, some engines will also hide GUI. Log it: console.log('game.visible', game.visible, 'comicIntro.visible', comicIntro.visible); - Make sure your buttons actually live in comicIntro after all pages - You want: comicIntro.addChild(nextBtn, skipBtn); // then force them to the front: comicIntro.setChildIndex(nextBtn, comicIntro.children.length - 1); comicIntro.setChildIndex(skipBtn, comicIntro.children.length - 1); - If you instead call comicIntro.addChild() for buttons before you add or fade your pages, the pages can render over them. - Dump out their computed bounds - Right after you create them, sprinkle: console.log('Next Btn bounds:', nextBtn.getBounds()); console.log('Skip Btn bounds:', skipBtn.getBounds()); - That tells you if they’re off-screen. - Add a temporary debug overlay - Give each button a semitransparent background so you can see where it is: var dbg = LK.getAsset('trajectory', { width: 400, height: 150, color: 0xff0000 }); dbg.alpha = 0.2; nextBtn.addChild(dbg); skipBtn.addChild(dbg.clone()); // or create another - Anchor‐based layout alternative If you’d rather pin by anchor, set each button’s background anchor to the top-right and position at (game.width, game.height) minus margins: bg.anchorX = 1; bg.anchorY = 1; btnContainer.x = game.width - margin; btnContainer.y = game.height - margin; - That way no matter how your canvas is sized, the button hugs the corner. — run through those steps and you’ll see whether the buttons are: • Being buried under the pages • Being hidden by a visibility flag • Positioned off-scree
User prompt
To guarantee your Skip/Next buttons always sit in the lower‐right corner of the comic intro—regardless of screen size—position them relative to your game’s width/height instead of hard-coding “1700/2400”. For example, right after you create your comicIntro container and before you call makeButton(), do something like this: // pick a margin from the edge var margin = 50; // know your button dims (your bg is 400×150) var btnW = 400, btnH = 150; // compute a shared Y so both buttons sit on the same horizontal line var btnY = game.height - btnH/2 - margin; // compute X positions for Skip and Next var skipX = game.width - btnW/2 - margin; var nextX = skipX - btnW - margin; // Next Button var nextBtn = makeButton("▶ Next", nextX, btnY, 0x3333aa, function(){ /* ... */ } ); // Skip Button var skipBtn = makeButton("✖ Skip", skipX, btnY, 0xaa3333, function(){ /* ... */ } ); // add them on top of your pages comicIntro.addChild(nextBtn); comicIntro.addChild(skipBtn); comicIntro.setChildIndex(nextBtn, comicIntro.children.length - 1); comicIntro.setChildIndex(skipBtn, comicIntro.children.length - 1); Key changes: - We read game.width and game.height at runtime, so no matter the device or whether your pages are scaled, the buttons hug the bottom-right. - We subtract half the button’s width/height (because your makeButton centers via .anchorX/.anchorY = 0.5) plus a margin, so they’re always fully on-screen.
User prompt
display the NEXT and SKIP buttons for the comic pages in the visisble screen space
User prompt
AdD comicPage2 to intro add a NEXT button so that comicPage1 displays before comicPage2. Move both the next button and skip button to the bottom right corner of the screen
User prompt
force layer order with setChildIndex: // Ensure treeline is always behind mailbox zone game.setChildIndex(treelineContainer, game.getChildIndex(mailboxZone) - 1); ✅ That will keep the mailbox zone’s green strip in front of the treeline.
User prompt
draw the treeline graphic so that is displays behind the mailbox zone. But do not chnage its Y axis position.
User prompt
✅ 1. Add treelineContainer before foreground elements game.addChild(treelineContainer); // Already present game.addChild(house); // Comes after treeline game.addChild(mailbox); // Comes after house
User prompt
move the treeline graphical asset below the mailbox zone
User prompt
✅ Increase treeline tile count to add one duplicate to the right side
User prompt
add 1 duplicate of the treeline graphic to the leftside end of the screen
User prompt
✅ Treeline Fix Strategy: Snap and Wrap Precisely Here’s how to tighten it up: 1. Snap positions to integers Floating-point drift can cause tiny gaps. Before re-aligning tiles, round their x positions: t.x = Math.round(t.x); Do this before the flush alignment loop. 2. Flush-align using consistent width Instead of relying on each tile’s .width, use a fixed tileWidth var tileWidth = treelines[0].width; // or your known constant treelines[idx].x = treelines[(idx - 1 + treelines.length) % treelines.length].x + tileWidth; his avoids cumulative width errors if assets vary slightly. 3. Wrap with overlap buffer When wrapping tiles from left to right, add a small overlap to ensure coverage: if (t.x + tileWidth < 0) { var rightMost = Math.max.apply(Math, treelines.map(tr => tr.x)); t.x = rightMost + tileWidth - 1; // subtract 1px to overlap }
User prompt
align the top left corner of the comic page asset with the top left corner of the screen.
User prompt
always resize Comic page assets so that they fit the scale of the comicPage box ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
align edges of comicPage1 with the edges of the screen. ensure image does not get cut off
User prompt
adjust the anchor point for the comic page so that the graphic displays centered on the screen
User prompt
x: game.width / 2, y: game.height / 2, anchorX: 0.5, anchorY: 0.5, scaleX: 0.67, scaleY: 0.89
User prompt
comic page anchor point: anchorX: 0.5, anchorY: 0.5, x: 1024, y: 1366
/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
/****
* Classes
****/
var House = Container.expand(function () {
var self = Container.call(this);
var graphics = self.attachAsset('house', {
anchorX: 0.5,
anchorY: 1.0
});
self.active = true;
// Remove scrolling from update, handled by tweens
self.update = function () {};
return self;
});
var Mailbox = Container.expand(function () {
var self = Container.call(this);
var graphics = self.attachAsset('mailbox', {
anchorX: 0.5,
anchorY: 1.0
});
self.hit = false;
self.active = true;
self.update = function () {}; // no auto-scrolling
return self;
});
var Newspaper = Container.expand(function () {
var self = Container.call(this);
var graphics = self.attachAsset('newspaper', {
anchorX: 0.5,
anchorY: 0.5
});
// Physics properties
self.vx = 0;
self.vy = 0;
self.gravity = 0.4;
self.active = true;
// Store starting position for scaling math
self.startY = null;
self.update = function () {
if (!self.active) {
return;
}
// Apply velocity
self.x += self.vx;
self.y += self.vy;
// Apply gravity
self.vy += self.gravity;
// Record starting Y on first update
if (self.startY === null) {
self.startY = self.y;
}
// Scale down as it rises (depth effect)
var travel = self.startY - self.y;
var scaleFactor = Math.max(0.2, 1 - travel / 1500);
graphics.scaleX = graphics.scaleY = scaleFactor;
// Cleanup when it goes "into the distance"
if (self.y < mailboxZoneY - 300 || self.y > 2732 || self.x < -200 || self.x > 2300) {
self.active = false;
// Trigger turn end if this was the last shot
if (currentHouse && !isHouseTransitioning) {
removeHouse(currentHouse, function () {
currentHouse = null;
hasThrownThisTurn = false; // reset throw flag
// Clear leftover mailboxes
for (var k = mailboxes.length - 1; k >= 0; k--) {
mailboxes[k].destroy();
mailboxes.splice(k, 1);
}
});
}
}
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x87ceeb
});
/****
* Game Code
****/
// green
// orange
game.setBackgroundColor(0x87ceeb);
// Start background music immediately when game loads
LK.playMusic('MothmanBoogie');
/****
* Color Interpolation Helper
****/
function lerpColor(c1, c2, t) {
var r1 = c1 >> 16 & 0xff,
g1 = c1 >> 8 & 0xff,
b1 = c1 & 0xff;
var r2 = c2 >> 16 & 0xff,
g2 = c2 >> 8 & 0xff,
b2 = c2 & 0xff;
var r = Math.round(r1 + (r2 - r1) * t);
var g = Math.round(g1 + (g2 - g1) * t);
var b = Math.round(b1 + (b2 - b1) * t);
return r << 16 | g << 8 | b;
}
/****
* Sun Path Parameters
****/
// Sun path parameters
var sunStartX = 100; // left side
var sunEndX = 1948; // right side
var sunBaseY = 600; // baseline (sky zone level)
var sunArcHeight = 400; // how high the sun climbs
/****
* Zone Setup
****/
// Define Y positions for zones (adjust as needed to match your reference image)
var streetZoneY = 2000; // Green bottom zone where slingshot sits
var mailboxZoneY = 1200; // Orange middle zone where mailbox spawns
var houseZoneY = 1000; // Houses aligned just above mailbox zone
// Ground reference (for houses)
var groundY = 2400;
/****
* Visual Zone Placeholders
****/
// Street zone background (green)
var streetZone = game.addChild(LK.getAsset('streetZone', {
anchorX: 0.5,
anchorY: 0.5
}));
streetZone.x = 1024;
streetZone.y = streetZoneY;
// Mailbox zone background (orange)
var mailboxZone = game.addChild(LK.getAsset('mailboxZone', {
anchorX: 0.5,
anchorY: 0.5
}));
mailboxZone.x = 1024;
mailboxZone.y = mailboxZoneY;
// Treeline container to move with houses
var treelineContainer = new Container();
// compute how many tiles we need to cover the screen plus one extra on each side
var tileWidth = LK.getAsset('treeline', {}).width;
var screenWidth = 2048; // your game width
var sideBuffers = 2; // two extra tiles on left side, one on right
var tileCount = Math.ceil(screenWidth / tileWidth) + sideBuffers * 2 + 1; // +1 for additional right side duplicate
var treelines = [];
for (var i = 0; i < tileCount; i++) {
var tile = treelineContainer.addChild(LK.getAsset('treeline', {
anchorX: 0,
anchorY: 1
}));
// position so that the first tile starts at –tileWidth
tile.x = (i - sideBuffers) * tileWidth;
tile.y = 0;
treelines.push(tile);
}
// lock the whole strip at the correct vertical position
treelineContainer.x = 0;
treelineContainer.y = mailboxZoneY - 350;
// Add treeline container before other game elements to render behind them
game.addChild(treelineContainer);
// Parallax scrolling parameters
var baseSpeed = 5; // Base movement speed for reference
var treeParallaxFactor = 0.2; // Trees move at 20% of house speed for depth effect
// Update function for treeline infinite scroll
function updateTreeline(speed) {
for (var i = 0; i < treelines.length; i++) {
var t = treelines[i];
t.x -= speed;
// Snap positions to integers to prevent floating-point drift
t.x = Math.round(t.x);
}
// After moving, check for wrap and re-align all treelines to be flush
// Find the leftmost treeline
var leftMostIndex = 0;
var leftMostX = treelines[0].x;
for (var i = 1; i < treelines.length; i++) {
if (treelines[i].x < leftMostX) {
leftMostX = treelines[i].x;
leftMostIndex = i;
}
}
// Now, starting from leftmost, set each treeline's x so they are flush
var startX = treelines[leftMostIndex].x;
for (var i = 0; i < treelines.length; i++) {
var idx = (leftMostIndex + i) % treelines.length;
if (i === 0) {
treelines[idx].x = startX;
} else {
treelines[idx].x = treelines[(idx - 1 + treelines.length) % treelines.length].x + tileWidth;
}
}
// If any treeline is now off the left edge, move it to the right of the last one
for (var i = 0; i < treelines.length; i++) {
var t = treelines[i];
if (t.x + tileWidth < 0) {
// Find the rightmost treeline
var rightMost = Math.max.apply(Math, treelines.map(function (tr) {
return tr.x;
}));
t.x = rightMost + tileWidth - 1; // subtract 1px to overlap
}
}
}
// Game variables
var mothman;
var sun;
var slingshot;
var newspapers = [];
var mailboxes = [];
var houses = [];
var trajectoryDots = [];
// Create one reusable graphics line for the trajectory
var trajectoryLine = new Container();
// Pull-back origin indicator will be created after slingshot for proper layering
var pullOriginIndicator;
var pennies = 0;
var targetPennies = 650;
var gameTime = 0;
var maxGameTime = 18000; // 5 minutes at 60fps
var isAiming = false;
var aimStartX = 0;
var aimStartY = 0;
var aimPower = 0;
var aimAngle = 0;
var hasThrownThisTurn = false;
// Create UI
var paycheckText = new Text2('Paycheck: $0.00', {
size: 65,
fill: 0x006400,
font: "'Comic Sans MS', cursive"
});
paycheckText.anchor.set(0.5, 0);
paycheckText.y = 100;
LK.gui.top.addChild(paycheckText);
function updatePaycheck() {
paycheckText.setText('Paycheck: $' + (pennies / 100).toFixed(2));
}
// Power bar background + fill
var powerBarBG = LK.getAsset('powerBarBGShape', {
anchorX: 0.5,
anchorY: 0.5
});
powerBarBG.x = 1024;
powerBarBG.y = 200; // top center instead of bottom
LK.gui.top.addChild(powerBarBG);
var powerBarFill = LK.getAsset('powerBarFillShape', {
width: 0,
// start empty
anchorX: 0,
anchorY: 0.5
});
powerBarFill.x = powerBarBG.x - 150;
powerBarFill.y = powerBarBG.y;
LK.gui.top.addChild(powerBarFill);
// Create mothman
mothman = game.addChild(new Container());
var mothmanGraphics = mothman.attachAsset('mothman', {
anchorX: 0.5,
anchorY: 0.5
});
mothman.x = 200;
mothman.y = 400;
// Hide mothman (no sprite during gameplay)
mothman.visible = false;
// Create pull origin indicator after mothman to ensure proper layering in front
pullOriginIndicator = LK.getAsset('aimOriginShape', {
anchorX: 0.5,
anchorY: 0.5
});
// Position the aim origin indicator at slingshot position, moved up by 100 pixels
pullOriginIndicator.x = 1024;
pullOriginIndicator.y = 2000; // streetZoneY (2000) + 100 - 100 = 2000
pullOriginIndicator.visible = true; // Always visible
// Add aiming visuals after mothman to ensure they render on top
game.addChild(trajectoryLine);
game.addChild(pullOriginIndicator);
// Create sun
sun = game.addChild(new Container());
var sunGraphics = sun.attachAsset('sun', {
anchorX: 0.5,
anchorY: 0.5
});
sun.x = sunStartX;
sun.y = sunBaseY - sunArcHeight;
/****
* Draw Sun Arc Path
****/
// Draw sun trajectory arc with dotted path
function drawSunPath() {
for (var t = 0; t <= 1; t += 0.05) {
var x = sunStartX + (sunEndX - sunStartX) * t;
var y = sunBaseY - Math.sin(t * Math.PI) * sunArcHeight;
var dot = game.addChild(LK.getAsset('trajectory', {
width: 6,
height: 6,
color: 0xffff66,
// pale yellow
anchorX: 0.5,
anchorY: 0.5
}));
dot.x = x;
dot.y = y;
dot.alpha = 0.3; // semi-transparent
}
}
drawSunPath();
// Create slingshot area - positioned in street zone center
slingshot = game.addChild(new Container());
var slingshotGraphics = slingshot.attachAsset('slingshot', {
anchorX: 0.5,
anchorY: 0.5
});
slingshot.x = 1024; // center of screen
slingshot.y = streetZoneY + 100;
// Slingshot bands (for stretch feedback)
var bandLeft = new Container();
var bandRight = new Container();
game.addChild(bandLeft);
game.addChild(bandRight);
// Ground level
var groundY = 2400;
// Turn-based house cycle variables
var currentHouse = null;
var isHouseTransitioning = false;
var turnComplete = true;
var prevHouseX = 1024; // Track previous house X position for treeline scroll
function ensureMailboxForTurn() {
// Clear leftover mailboxes
for (var k = mailboxes.length - 1; k >= 0; k--) {
mailboxes[k].destroy();
mailboxes.splice(k, 1);
}
createMailbox(); // always create (no RNG)
}
function createHouse() {
var house = new House();
// Start just off-screen to the right
house.x = 2200;
house.y = mailboxZoneY + 250; // roughly center mailbox zone
houses.push(house);
game.addChild(house);
currentHouse = house;
isHouseTransitioning = true;
turnComplete = false;
hasThrownThisTurn = false;
// Tween it into center of mailbox zone
tween(house, {
x: 1024
}, {
duration: 1000,
easing: tween.easeOut,
onFinish: function onFinish() {
isHouseTransitioning = false;
ensureMailboxForTurn(); // mailbox priority
}
});
return house;
}
function removeHouse(house, onComplete) {
if (!house) {
return;
}
isHouseTransitioning = true;
tween(house, {
x: -200
}, {
duration: 1000,
easing: tween.easeIn,
onFinish: function onFinish() {
house.destroy();
var index = houses.indexOf(house);
if (index !== -1) {
houses.splice(index, 1);
}
isHouseTransitioning = false;
turnComplete = true;
if (onComplete) {
onComplete();
}
}
});
}
function createMailbox() {
if (!currentHouse) {
return;
}
var mailbox = new Mailbox();
// Calculate house position and width to avoid overlap
var houseX = currentHouse.x;
var houseWidth = 900; // house asset width
var houseLeftEdge = houseX - houseWidth * 0.5;
var houseRightEdge = houseX + houseWidth * 0.5;
// Generate random position that doesn't overlap with house
var mailboxX;
var attempts = 0;
do {
mailboxX = 400 + Math.random() * 1200; // stays in safe horizontal range
attempts++;
// Safety check to prevent infinite loop
if (attempts > 50) {
// If we can't find a spot, place it far from house
if (houseX > 1024) {
mailboxX = 500; // place on left side
} else {
mailboxX = 1500; // place on right side
}
break;
}
} while (mailboxX >= houseLeftEdge - 100 && mailboxX <= houseRightEdge + 100);
mailbox.x = mailboxX;
mailbox.y = mailboxZoneY + (Math.random() * 200 - 100);
// Random horizontal flip
if (Math.random() < 0.5) {
mailbox.scaleX = -1;
} else {
mailbox.scaleX = 1;
}
mailboxes.push(mailbox);
game.addChild(mailbox);
// Ensure mailbox is drawn in front of house
game.setChildIndex(mailbox, game.getChildIndex(currentHouse) + 1);
return mailbox;
}
function shootNewspaper(power, angle) {
var newspaper = new Newspaper();
newspaper.x = 1024; // slingshot center
newspaper.y = 2200; // bottom
// Use power + angle for velocity
newspaper.vx = Math.cos(angle) * power;
newspaper.vy = Math.sin(angle) * power;
newspapers.push(newspaper);
game.addChild(newspaper);
LK.getSound('Paperthrow').play();
}
function updateSlingshotBands(endX, endY) {
bandLeft.removeChildren();
bandRight.removeChildren();
// Don't draw visible bands - keep containers for positioning only
}
function calculateScore(distance) {
if (distance < 15) {
return 5;
} // Perfect hit
if (distance < 25) {
return 4;
} // Great hit
if (distance < 35) {
return 3;
} // Good hit
if (distance < 45) {
return 2;
} // OK hit
return 1; // Glancing hit
}
function payoutFor(distancePx) {
if (distancePx <= 25) return {
cents: 25,
label: '+25¢ Perfect!'
};
if (distancePx <= 60) return {
cents: 15,
label: '+15¢ Very close'
};
if (distancePx <= 120) return {
cents: 5,
label: '+5¢ Close'
};
return null;
}
function updateTrajectory(originX, originY, pullX, pullY) {
// Clear any previous drawing
trajectoryLine.removeChildren();
if (!isAiming) return;
// Launch vector = opposite of pull
var dx = originX - pullX;
var dy = originY - pullY;
var power = Math.sqrt(dx * dx + dy * dy) * 0.1;
var angle = Math.atan2(dy, dx);
// Launch velocity
var vX = Math.cos(angle) * power;
var vY = Math.sin(angle) * power;
// Choose a projection distance (how long the line should be)
var projectionTime = 80; // tweak for how far line extends
var g = 0.3;
// Predict end point of the line
var endX = originX + vX * projectionTime;
var endY = originY + vY * projectionTime - 0.5 * g * projectionTime * projectionTime;
// Create line graphic
var lineGraphic = trajectoryLine.addChild(LK.getAsset('trajectory', {
width: Math.sqrt((endX - originX) * (endX - originX) + (endY - originY) * (endY - originY)),
height: 4,
color: 0x00ff00,
anchorX: 0,
anchorY: 0.5
}));
lineGraphic.x = originX;
lineGraphic.y = originY;
lineGraphic.rotation = Math.atan2(endY - originY, endX - originX);
lineGraphic.alpha = 0.7;
}
// Game input handlers - natural slingshot controls
game.down = function (x, y, obj) {
// Only allow aiming if player clicks/touches near the slingshot
if (y > streetZoneY - 200) {
isAiming = true;
aimStartX = x;
aimStartY = y;
// Pull origin indicator is already positioned and visible
// No need to reposition it during aiming
}
};
game.move = function (x, y, obj) {
if (isAiming) {
// Draw a preview trajectory
updateTrajectory(1024, 2000, x, y);
// Compute pull distance for power
var dx = 1024 - x;
var dy = 2200 - y;
var pullDistance = Math.sqrt(dx * dx + dy * dy);
var maxPull = 600; // clamp so bar doesn't overflow
var percent = Math.min(1, pullDistance / maxPull);
// Dynamic color based on power level
var color = 0x00ff00; // green
if (percent > 0.66) {
color = 0xff0000; // red
} else if (percent > 0.33) {
color = 0xffff00; // yellow
}
// Re-create the fill shape with new color and width
powerBarFill.destroy();
powerBarFill = LK.getAsset('powerBarFillShape', {
width: percent * 300,
color: color,
anchorX: 0,
anchorY: 0.5
});
powerBarFill.x = powerBarBG.x - 150;
powerBarFill.y = powerBarBG.y;
LK.gui.top.addChild(powerBarFill);
}
};
game.up = function (x, y, obj) {
if (!isAiming || hasThrownThisTurn) return;
var originX = 1024,
originY = 2000; // slingshot base moved up by 100 pixels
var pullX = x - originX;
var pullY = y - originY;
// Launch vector = opposite of pull
var launchX = -pullX;
var launchY = -pullY;
// Power is proportional to pull distance
var pullDistance = Math.sqrt(launchX * launchX + launchY * launchY);
var powerScale = 0.15; // tweak this number to control speed
var power = pullDistance * powerScale;
// Angle from pull-back vector
var angle = Math.atan2(launchY, launchX);
if (power > 2) {
shootNewspaper(power, angle);
hasThrownThisTurn = true;
}
// Reset aiming visuals
isAiming = false;
trajectoryLine.removeChildren();
// Pull origin indicator stays visible
powerBarFill.width = 0;
};
game.update = function () {
gameTime++;
// Update sun position (moves across sky as timer)
var timeProgress = gameTime / maxGameTime;
sun.x = sunStartX + (sunEndX - sunStartX) * timeProgress;
sun.y = sunBaseY - Math.sin(timeProgress * Math.PI) * sunArcHeight;
// Sky color progression with smooth transitions
var skyColors = [{
t: 0.0,
color: 0xE6E6FA
},
// Lavender
{
t: 0.2,
color: 0xADD8E6
},
// Light Blue
{
t: 0.4,
color: 0x87CEEB
},
// Bright Blue
{
t: 0.7,
color: 0xFFA500
},
// Orange
{
t: 1.0,
color: 0x4B0082
} // Deep Purple
];
// Find the two colors to interpolate between
for (var i = 0; i < skyColors.length - 1; i++) {
var c1 = skyColors[i];
var c2 = skyColors[i + 1];
if (timeProgress >= c1.t && timeProgress <= c2.t) {
var localT = (timeProgress - c1.t) / (c2.t - c1.t);
var blended = lerpColor(c1.color, c2.color, localT);
game.setBackgroundColor(blended);
break;
}
}
// Turn-based house cycle management
if (turnComplete && !isHouseTransitioning && !currentHouse) {
createHouse(); // mailbox is guaranteed in onFinish
}
// Watchdog: if for any reason a mailbox isn't present, create one.
if (currentHouse && !isHouseTransitioning && mailboxes.length === 0) {
ensureMailboxForTurn();
}
// Update newspapers
for (var i = newspapers.length - 1; i >= 0; i--) {
var newspaper = newspapers[i];
if (!newspaper.active) {
newspaper.destroy();
newspapers.splice(i, 1);
continue;
}
// Check if newspaper went off screen without hitting (miss)
if (newspaper.active && (newspaper.x > 2048 || newspaper.y > 2732)) {
newspaper.active = false;
// End the turn if no hit occurred
if (currentHouse && !isHouseTransitioning) {
removeHouse(currentHouse, function () {
currentHouse = null;
hasThrownThisTurn = false; // reset throw flag
// Clear mailboxes for this turn
for (var k = mailboxes.length - 1; k >= 0; k--) {
mailboxes[k].destroy();
mailboxes.splice(k, 1);
}
});
}
continue;
}
// Check mailbox collisions
for (var j = 0; j < mailboxes.length; j++) {
var m = mailboxes[j];
if (m.hit) continue;
// enlarge hitbox with tolerance for better hit detection
var gfx = m.children && m.children[0] ? m.children[0] : m;
var halfW = (gfx.width || 100) * 0.5;
var fullH = gfx.height || 100;
var left = m.x - halfW;
var right = m.x + halfW;
var top = m.y - fullH;
var bottom = m.y;
// loosen bounds by 20px in all directions
var tol = 20;
var insideX = newspaper.x >= left - tol && newspaper.x <= right + tol;
var insideY = newspaper.y >= top - tol && newspaper.y <= bottom + tol;
if (!insideX || !insideY) continue;
// compute accuracy off the mailbox "mouth"
var mouthY = m.y - fullH * 0.6;
var dx = newspaper.x - m.x;
var dy = newspaper.y - mouthY;
var dist = Math.sqrt(dx * dx + dy * dy);
// if payoutFor returns null (too far), still give a glancing hit
var res = payoutFor(dist) || {
cents: 5,
label: '+5¢ Close enough'
};
pennies += res.cents;
updatePaycheck();
m.hit = true;
newspaper.active = false;
// floating green payout text that fades away (large and bold)
var _float = new Text2(res.label, {
size: 72,
fill: 0x00aa00,
font: "'GillSans-Bold',Impact,'Arial Black',Tahoma"
});
_float.anchor.set(0.5, 1);
_float.x = m.x;
_float.y = top - 10;
game.addChild(_float);
tween(_float, {
y: _float.y - 80,
alpha: 0
}, {
duration: 800,
onFinish: function onFinish() {
_float.destroy();
}
});
LK.effects.flashObject(m, 0x00ff00, 500);
LK.getSound('MailboxHit').play();
// end turn after scoring (keep existing cleanup behavior)
if (currentHouse && !isHouseTransitioning) {
removeHouse(currentHouse, function () {
currentHouse = null;
hasThrownThisTurn = false; // reset throw flag
for (var k = mailboxes.length - 1; k >= 0; k--) {
mailboxes[k].destroy();
mailboxes.splice(k, 1);
}
});
}
break;
}
}
// Update and clean up mailboxes
for (var i = mailboxes.length - 1; i >= 0; i--) {
var mailbox = mailboxes[i];
if (!mailbox.active) {
mailbox.destroy();
mailboxes.splice(i, 1);
}
}
// Update and clean up houses
for (var i = houses.length - 1; i >= 0; i--) {
var house = houses[i];
if (!house.active) {
house.destroy();
houses.splice(i, 1);
}
}
// Check win condition
if (pennies >= targetPennies) {
LK.showYouWin();
}
// Infinite-scroll treeline every frame with parallax effect
if (currentHouse) {
var houseSpeed = prevHouseX - currentHouse.x;
// Apply parallax factor to create depth - trees move slower than houses
var parallaxSpeed = houseSpeed * treeParallaxFactor;
updateTreeline(parallaxSpeed);
prevHouseX = currentHouse.x;
}
// Ensure treeline is always behind mailbox zone
game.setChildIndex(treelineContainer, game.getChildIndex(mailboxZone) - 1);
// Force aiming visuals to always render on top
game.setChildIndex(trajectoryLine, game.children.length - 1);
game.setChildIndex(pullOriginIndicator, game.children.length - 2);
// Check lose condition
if (gameTime >= maxGameTime) {
LK.showGameOver();
}
}; ===================================================================
--- original.js
+++ change.js
@@ -87,213 +87,13 @@
/****
* Game Code
****/
-// orange
// green
+// orange
game.setBackgroundColor(0x87ceeb);
-// Comic Intro Container
-var comicIntro = new Container();
-LK.gui.addChild(comicIntro);
-// Array of comic page images
-var comicPages = [LK.getAsset('comicPage1', {
- x: 0,
- y: 0,
- anchorX: 0,
- anchorY: 0,
- scaleX: 0.67,
- scaleY: 0.89
-}), LK.getAsset('comicPage2', {
- anchorX: 0.5,
- anchorY: 0.5,
- x: 1024,
- y: 1366,
- scaleX: 1.0,
- scaleY: 1.0
-}), LK.getAsset('comicPage3', {
- anchorX: 0.5,
- anchorY: 0.5,
- x: game.width / 2,
- y: game.height / 2,
- scaleX: 0.67,
- scaleY: 0.89
-})];
-var currentPageIndex = 0;
-// Position and add pages
-for (var p = 0; p < comicPages.length; p++) {
- var page = comicPages[p];
- page.visible = false;
- comicIntro.addChild(page);
-}
-comicPages[0].visible = true;
-// Function to create button with background
-function makeButton(label, x, y, color, onClick) {
- var btnContainer = new Container();
- // Create rectangular background using shape asset
- var bg = LK.getAsset('powerBarBGShape', {
- width: 400,
- height: 150,
- color: color,
- anchorX: 0.5,
- anchorY: 0.5
- });
- btnContainer.addChild(bg);
- // Create black text
- var txt = new Text2(label, {
- size: 360,
- fill: 0x000000,
- font: "'GillSans-Bold',Impact,'Arial Black',Tahoma"
- });
- txt.anchor.set(0.5);
- txt.alpha = 1.0;
- btnContainer.addChild(txt);
- // position
- btnContainer.x = x;
- btnContainer.y = y;
- // interaction
- btnContainer.interactive = true;
- btnContainer.buttonMode = true;
- btnContainer.alpha = 1;
- btnContainer.down = onClick;
- return btnContainer;
-}
-// Force buttons to use absolute positioning within visible screen area
-var margin = 50;
-var btnW = 400,
- btnH = 150;
-// Use fixed screen dimensions (2048x2732) instead of game dimensions
-var screenWidth = 2048;
-var screenHeight = 2732;
-var btnY = screenHeight - btnH / 2 - margin;
-// Move both buttons to left side of screen
-var skipX = btnW / 2 + margin;
-var nextX = skipX + btnW + margin;
-// Next Button (bottom right) - positioned within visible screen area
-var nextBtn = makeButton("▶ Next", nextX, btnY, 0x3333aa, function () {
- var currentPage = comicPages[currentPageIndex];
- tween(currentPage, {
- alpha: 0
- }, {
- duration: 300,
- onFinish: function onFinish() {
- currentPage.visible = false;
- currentPage.alpha = 1;
- currentPageIndex++;
- if (currentPageIndex < comicPages.length) {
- var nextPage = comicPages[currentPageIndex];
- nextPage.visible = true;
- nextPage.alpha = 0;
- tween(nextPage, {
- alpha: 1
- }, {
- duration: 300,
- onFinish: function onFinish() {
- // Ensure buttons stay on top after page transition
- ensureButtonsOnTop();
- }
- });
- } else {
- startGame();
- }
- // Ensure buttons stay on top after any page change
- ensureButtonsOnTop();
- }
- });
-});
-// Skip Button - force to visible position in upper right area
-var skipBtn = makeButton("✖ Skip", 1700, 300, 0xaa3333, function () {
- startGame();
-});
-// Force SKIP button to be fully visible and interactive
-skipBtn.alpha = 1;
-skipBtn.visible = true;
-skipBtn.interactive = true;
-skipBtn.buttonMode = true;
-// Add buttons after pages to ensure they render on top
-comicIntro.addChild(nextBtn);
-comicIntro.addChild(skipBtn);
-// Function to ensure buttons stay at front with explicit Z-index management
-function ensureButtonsOnTop() {
- // Force SKIP button to left side position
- skipBtn.x = btnW / 2 + margin;
- skipBtn.y = btnY;
- // Remove and re-add buttons to guarantee they're at the front
- if (nextBtn.parent === comicIntro) {
- comicIntro.removeChild(nextBtn);
- }
- if (skipBtn.parent === comicIntro) {
- comicIntro.removeChild(skipBtn);
- }
- // Re-add SKIP button LAST to ensure it's at the very top
- comicIntro.addChild(nextBtn);
- comicIntro.addChild(skipBtn);
- // Force SKIP button to absolute highest Z-index
- var totalChildren = comicIntro.children.length;
- comicIntro.setChildIndex(skipBtn, totalChildren - 1);
- comicIntro.setChildIndex(nextBtn, totalChildren - 2);
- // Force SKIP button visibility and interaction
- skipBtn.interactive = true;
- skipBtn.buttonMode = true;
- skipBtn.alpha = 1;
- skipBtn.visible = true;
- skipBtn.x = btnW / 2 + margin; // Force position again
- skipBtn.y = btnY;
- // Ensure next button visibility
- nextBtn.interactive = true;
- nextBtn.buttonMode = true;
- nextBtn.alpha = 1;
- nextBtn.visible = true;
-}
-// Initial button setup with forced SKIP positioning
-ensureButtonsOnTop();
-// Additional forced positioning for SKIP button visibility
-skipBtn.x = btnW / 2 + margin;
-skipBtn.y = btnY;
-skipBtn.alpha = 1;
-skipBtn.visible = true;
-// Force SKIP to absolute top of container
-comicIntro.setChildIndex(skipBtn, comicIntro.children.length - 1);
-// Add additional debug logging after button setup
-console.log('Buttons added to comic intro. Next visible:', nextBtn.visible, 'Skip visible:', skipBtn.visible);
-console.log('Button alpha values - Next:', nextBtn.alpha, 'Skip:', skipBtn.alpha);
-// Function to start game
-function startGame() {
- comicIntro.visible = false;
- game.visible = true;
- // Start background music when game actually starts
- LK.playMusic('MothmanBoogie');
-}
-// Debug logging for button visibility and positioning
-console.log('game.visible', game.visible, 'comicIntro.visible', comicIntro.visible);
-console.log('Next Btn bounds:', nextBtn.getBounds());
-console.log('Skip Btn bounds:', skipBtn.getBounds());
-console.log('Next button position:', nextBtn.x, nextBtn.y);
-console.log('Skip button position:', skipBtn.x, skipBtn.y);
-console.log('Game dimensions:', game.width, game.height);
-console.log('Comic intro children count:', comicIntro.children.length);
-console.log('Next button index:', comicIntro.getChildIndex(nextBtn));
-console.log('Skip button index:', comicIntro.getChildIndex(skipBtn));
-// Initially hide game until comic is done
-game.visible = false;
-// Add frequent check to ensure buttons stay visible and properly positioned
-LK.setInterval(function () {
- if (comicIntro.visible) {
- // Check if buttons have been displaced or buried
- var nextIndex = comicIntro.getChildIndex(nextBtn);
- var skipIndex = comicIntro.getChildIndex(skipBtn);
- var totalChildren = comicIntro.children.length;
- // If buttons aren't at the front, or lost from container, fix them
- if (nextBtn.parent !== comicIntro || skipBtn.parent !== comicIntro || nextIndex < totalChildren - 2 || skipIndex < totalChildren - 1) {
- console.log('Buttons displaced from front, re-establishing Z-index...');
- ensureButtonsOnTop();
- }
- // Additional visibility check
- if (!nextBtn.visible || !skipBtn.visible || nextBtn.alpha < 1 || skipBtn.alpha < 1) {
- console.log('Button visibility compromised, restoring...');
- ensureButtonsOnTop();
- }
- }
-}, 100);
+// Start background music immediately when game loads
+LK.playMusic('MothmanBoogie');
/****
* Color Interpolation Helper
****/
function lerpColor(c1, c2, t) {