User prompt
Create a rhythm-based game experience using the following audio assets with synchronized timing: bgtrack: Simple Happy Life – this is the main background music that defines the rhythm, tempo, and beat structure. hit (greenOrb): Phonk Chime Bell – this sound is soft and percussive. It should play exactly on-beat with the background track whenever the player hits a green orb. hitr (redOrb): Wind Chime from Sample Focus – this should sound clean and magical, triggered precisely when the player hits a red orb. It must also align on the beat of the bgtrack to feel musical. 🎵 Requirements: Synchronize the spawning of red and green orbs based on the beat timing of the bgtrack, using BPM-based intervals (e.g. 60000 / BPM = spawn interval). Both hit and hitr should play exactly on beat, triggered by the player’s action. Never allow sounds to play slightly off the rhythm. Increase BPM and orb falling speed based on combo count (e.g., every 10 combo = +5 BPM). Update both spawning logic and movement accordingly to stay in sync with the music. Use beat subdivisions like quarter or eighth notes to space out orb spawns, ensuring they do not overlap unnaturally. Ensure the different hit sounds (bell and wind chime) feel like natural extensions of the bgtrack and do not clash with its melody. Make sure all audio loops seamlessly, even as the BPM dynamically changes. 🎯 Final goal: Achieve a harmonic, beat-matched gameplay where every orb, sound, and combo effect feels like part of the song. ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
Use two different sound effects for orb hits: - Use 'hit' when hitting a greenOrb. - Use 'hitr' when hitting a redOrb. In the handleOrbHit() and autoHitOrbWithClone() functions, replace LK.getSound('hit').play() with a conditional that plays 'hit' for greenOrb and 'hitr' for redOrb.
User prompt
Make orbs spawn in sync with the background music's BPM (beats per minute). For example, at 120 BPM, spawn a new orb every 500ms. Ensure the spawn timing matches the beat rhythm to give players a strong sense of music synchronization. Adjust spawnInterval dynamically based on BPM.
User prompt
Add a mechanic where the speed of all falling orbs (red, green, black) increases gradually based on the player's combo count. For every 10 combo streak, increase orb fall speed slightly to make the game more challenging. This should dynamically update during gameplay and reset back to base speed when the combo breaks.
Code edit (2 edits merged)
Please save this source code
User prompt
swordmasterın yetenek aktiflik süresini 2 sn ye düşür ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
swordmasterın yeteneğinin aktiflik süresini 4 sn ye çıkar
Code edit (1 edits merged)
Please save this source code
User prompt
Update the ability of the character "swordmaster" so that when his ability is used, he spawns a temporary clone inside the targetZone. The clone should be controlled by basic AI logic: - It should automatically move toward the nearest redOrb or greenOrb within the targetZone. - It should avoid blackBomb orbs entirely (do not target or move toward them). - It should not move outside the boundaries of the targetZone. - The clone should move at a speed of 8 and only exist for 1 second. - While the clone is active, every 100ms it should check for a redOrb or greenOrb in range (distance < 100) and auto-hit it. - If it hits an orb, play the "hit" sound, increase the score, and animate it fading out. - After 1 second, the clone should fade out and be destroyed. Add the clone movement behavior using AI and integrate it into the main game update loop. ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
Create a rhythm game where: The player drags the selected character (ninja, wizard, or swordmaster) inside a fixed target zone. The goal is to touch and destroy red and green orbs using the character. If the player misses 5 red/green orbs (they fall past the zone), the game ends. If the player touches 5 black orbs, the game also ends. Ninja Ability: When the player taps on the ninja character, it activates a 3-second phase mode: During this time, the ninja can pass through black orbs without penalty. Show a visual effect (e.g. glow) while active. After 3 seconds, the ability ends. Add variables: missedCount → increases when red/green orb falls. blackTouchCount → increases when touching black orb. Call gameOver() when either reaches 5. ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
I am building a rhythm-based mobile game using Upit Engine. I want to implement a new control mechanic where the player character (ninja, wizard, or swordmaster) can be dragged around inside the targetZone and used to destroy orbs by touching them. Please implement or fix the following mechanics: 🔹 1. Character Movement (Drag & Drop): The player should be able to tap and drag the selected character only within the targetZone area. The character follows the finger as long as it remains in the zone. Movement should feel smooth and responsive. 🔹 2. Orb Collision and Hit Logic: When the character sprite touches a red or green orb, that orb is destroyed and the score increases based on combo logic. If the character touches a black orb, nothing happens on the first hit — but on the second hit (same orb or another black one), the game ends (game over). 🔹 3. Ability Activation Logic: To use a character’s ability, the player must release the drag and directly tap the character itself (i.e. no dragging). This triggers the character’s special ability (freeze, auto combo, clone, etc.). 🔹 4. Target Zone Visual & Mechanics: The targetZone should be a visually clear area at the bottom (alpha ~0.5 or visible color like dark blue). Character dragging and orb collision can only happen inside this zone. Notes: The rest of the rhythm logic (orb spawning from top, combo tracking, music syncing) is already implemented. Clone ability of swordmaster should continue to auto-destroy orbs while the original character is being dragged. Please provide a revised code implementation for these mechanics. Thank you! ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
I'm working on a mobile rhythm game made with JavaScript and Upit Engine. The game has red, green, and black orbs that fall vertically from the top. At the bottom of the screen, there’s a targetZone where players must tap the orbs to score. There’s also a character (ninja, wizard, or swordmaster) with a special ability. Please help fix and improve the following issues in my current code: Orbs are not clickable in the target zone. 👉 Fix: Orbs should only be tappable when they are within the targetZone rectangle. Make sure the click detection is constrained to that area (X and Y bounds). Character ability is triggering when tapping the target zone. 👉 Fix: Ability should only activate when tapping directly on the character sprite, not when tapping the targetZone or screen. Swordmaster’s clone ability is not working. 👉 Fix: The clone spawns correctly, but it does not auto-hit orbs. Make the clone auto-hit the nearest orb inside the targetZone every 100ms for 1 second. TargetZone visibility is too low. 👉 Fix: Increase the visibility (e.g., set alpha to 0.5) and optionally give it a clearer color like dark blue for better UX. Additional Notes: Orbs fall straight down (this part is already correct). The game runs at ~60 FPS. The code is written in Upit’s framework with Container, LK.init.shape, and LK.getAsset. Please fix these problems and give me a corrected code block that I can directly paste into Upit Studio. ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
Please update the game logic for a more intuitive tap-timing rhythm style: 1. Modify the orb movement: - All orbs should fall straight down from top to bottom (no target-based vector movement). - Remove all references to orb.targetX and orb.targetY. - Instead, orbs just increase their y position by `orb.speed` each frame. 2. Modify the target zone: - Make the targetZone much taller (e.g., height: 300) and stretch it across the full bottom of the screen. - Place the targetZone at the bottom of the screen (e.g., y: 2300 or 2400 depending on canvas size). 3. Modify the hit detection: - Players can only successfully hit orbs if they are within the targetZone bounds. - Tapping anywhere outside the zone does nothing. - Taps must be on orbs that are inside the vertical range of the targetZone (collision check). 4. Update swordmaster's clone AI: - The clone should only auto-hit orbs when they are inside the targetZone. - The clone should behave like a player: look for orbs inside the zone and auto-hit one every 100ms. 5. Bonus: Make orb speed slightly slower (e.g., speed: 4). This turns the game into a clearer rhythm-timing challenge like Friday Night Funkin' or Piano Tiles. ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
In this Upit rhythm game code, please change the swordmaster character's ability. Instead of "dual strike", make it so that when the swordmaster uses their ability, it spawns a temporary clone of themselves. This clone should appear next to the original swordmaster, automatically hit orbs for 1 second (as if it perfectly taps the correct ones), and then disappear. The clone should visually look like the swordmaster and help the player for 1 second. Update only the related parts (the ability and orb interaction logic), and do not affect other characters. ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
In this Upit game code, the character selection screen shows the characters (ninja, wizard, swordmaster), but tapping on them doesn’t trigger the selection function. Please fix the input detection so that tapping on the characters correctly selects them using selectCharacter(type) as intended. Do not change unrelated parts of the game.
User prompt
Redesign the gameplay to be more like Beat Saber. - Orbs should move toward the player from the top (not lanes) - Spawning should match BPM of the background music - Tapping or swiping should break orbs (use color to determine side or action) - Add simple feedback effects like screen shake or color flash - Allow player to use abilities like time-slow or auto-hit You can refactor the orb system and remove lane dependency if needed. ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
Scene 1 – Character Selection Screen: The player starts in a mystical dojo-like space with soft ambient music playing. On screen are 3 animated character avatars. Player must tap on one to begin the rhythm game. Character Options (Selectable): 🔹 Blue Mage • Appearance: Tall figure wearing a glowing blue robe, wide wizard hat, and holding a crystal staff. Mystical blue eyes, long white beard. • Animation: Calm idle floating motion, magic particles flowing around • Ability: Can cast “Ice Freeze” every 10 seconds to slow down incoming beat orbs for 3 seconds • Difficulty: Medium • Tagline: “Slow the rhythm, control the chaos.” 🔴 Dual Blade Swordmaster • Appearance: White torn martial arts outfit, red belt, bandaged arms, wild hair, two glowing swords • Animation: Breathing heavily, does quick sword swings while idle • Ability: Can slash both left and right lanes at the same time (multi-touch bonus), 2x combo window • Difficulty: Hard • Tagline: “Two blades. One rhythm.” ⚫ Shadow Ninja • Appearance: Full black suit, masked face, glowing dagger in hand, red eyes • Animation: Quick shadow dashes, fades in/out • Ability: Increased tap/slash speed; auto-slice chain combo when timing is perfect • Difficulty: Easy to pick, hard to master • Tagline: “Strike with silence. Dance with speed.” Gameplay Transition: Once the player selects a character, fade-in transition with music rising leads into rhythm gameplay arena (Scene 2). The player’s class ability is activated and UI adapts accordingly.
User prompt
Scene 1 – Character Selection Screen: The player starts in a mystical dojo-like space with soft ambient music playing. On screen are 3 animated character avatars. Player must tap on one to begin the rhythm game. Character Options (Selectable): 🔹 Blue Mage • Appearance: Tall figure wearing a glowing blue robe, wide wizard hat, and holding a crystal staff. Mystical blue eyes, long white beard. • Animation: Calm idle floating motion, magic particles flowing around • Ability: Can cast “Ice Freeze” every 10 seconds to slow down incoming beat orbs for 3 seconds • Difficulty: Medium • Tagline: “Slow the rhythm, control the chaos.” 🔴 Dual Blade Swordmaster • Appearance: White torn martial arts outfit, red belt, bandaged arms, wild hair, two glowing swords • Animation: Breathing heavily, does quick sword swings while idle • Ability: Can slash both left and right lanes at the same time (multi-touch bonus), 2x combo window • Difficulty: Hard • Tagline: “Two blades. One rhythm.” ⚫ Shadow Ninja • Appearance: Full black suit, masked face, glowing dagger in hand, red eyes • Animation: Quick shadow dashes, fades in/out • Ability: Increased tap/slash speed; auto-slice chain combo when timing is perfect • Difficulty: Easy to pick, hard to master • Tagline: “Strike with silence. Dance with speed.” Gameplay Transition: Once the player selects a character, fade-in transition with music rising leads into rhythm gameplay arena (Scene 2). The player’s class ability is activated and UI adapts accordingly. ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
Scene 1 – Character Selection Screen: The player starts in a mystical dojo-like space with soft ambient music playing. On screen are 3 animated character avatars. Player must tap on one to begin the rhythm game. Character Options (Selectable): 🔹 Blue Mage • Appearance: Tall figure wearing a glowing blue robe, wide wizard hat, and holding a crystal staff. Mystical blue eyes, long white beard. • Animation: Calm idle floating motion, magic particles flowing around • Ability: Can cast “Ice Freeze” every 10 seconds to slow down incoming beat orbs for 3 seconds • Difficulty: Medium • Tagline: “Slow the rhythm, control the chaos.” 🔴 Dual Blade Swordmaster • Appearance: White torn martial arts outfit, red belt, bandaged arms, wild hair, two glowing swords • Animation: Breathing heavily, does quick sword swings while idle • Ability: Can slash both left and right lanes at the same time (multi-touch bonus), 2x combo window • Difficulty: Hard • Tagline: “Two blades. One rhythm.” ⚫ Shadow Ninja • Appearance: Full black suit, masked face, glowing dagger in hand, red eyes • Animation: Quick shadow dashes, fades in/out • Ability: Increased tap/slash speed; auto-slice chain combo when timing is perfect • Difficulty: Easy to pick, hard to master • Tagline: “Strike with silence. Dance with speed.” Gameplay Transition: Once the player selects a character, fade-in transition with music rising leads into rhythm gameplay arena (Scene 2). The player’s class ability is activated and UI adapts accordingly.
User prompt
Scene 1 – Character Selection Screen: The player starts in a mystical dojo-like space with soft ambient music playing. On screen are 3 animated character avatars. Player must tap on one to begin the rhythm game. Character Options (Selectable): 🔹 Blue Mage • Appearance: Tall figure wearing a glowing blue robe, wide wizard hat, and holding a crystal staff. Mystical blue eyes, long white beard. • Animation: Calm idle floating motion, magic particles flowing around • Ability: Can cast “Ice Freeze” every 10 seconds to slow down incoming beat orbs for 3 seconds • Difficulty: Medium • Tagline: “Slow the rhythm, control the chaos.” 🔴 Dual Blade Swordmaster • Appearance: White torn martial arts outfit, red belt, bandaged arms, wild hair, two glowing swords • Animation: Breathing heavily, does quick sword swings while idle • Ability: Can slash both left and right lanes at the same time (multi-touch bonus), 2x combo window • Difficulty: Hard • Tagline: “Two blades. One rhythm.” ⚫ Shadow Ninja • Appearance: Full black suit, masked face, glowing dagger in hand, red eyes • Animation: Quick shadow dashes, fades in/out • Ability: Increased tap/slash speed; auto-slice chain combo when timing is perfect • Difficulty: Easy to pick, hard to master • Tagline: “Strike with silence. Dance with speed.” Gameplay Transition: Once the player selects a character, fade-in transition with music rising leads into rhythm gameplay arena (Scene 2). The player’s class ability is activated and UI adapts accordingly. ↪💡 Consider importing and using the following plugins: @upit/tween.v1
Code edit (1 edits merged)
Please save this source code
User prompt
Rhythm Warriors: Beat Battle Arena
Initial prompt
Game Type: Music rhythm-based action game with fantasy RPG elements Visual Style: 3D stylized / vibrant / slightly cartoonish Theme: Players choose one of 3 classes — Ninja, Wizard, or Swordmaster — and enter a rhythm battle arena where colorful beat orbs come toward the player in sync with popular music tracks. Mechanics: • Notes come at the player in 3 lanes, color-coded: • 🔴 Red = hit left side • 🟢 Green = hit right side • ⚫ Black = bomb — must be dodged or ignored (touch = instant fail) • Orbs move faster as music progresses • Player interacts by tapping or slashing based on character’s ability Classes & Abilities: • Ninja: Fast dashes, quicker tap/slash speed, special move: “Shadow Slice” (auto-hits a fast series of beats) • Wizard: Normal speed, casts freeze spell every 10 seconds to slow incoming beats for 3 seconds • Swordmaster: Dual-wielding – can tap both left and right lanes at once (multi-touch), higher combo multiplier Game Objective: • Survive the full duration of the song without hitting bombs • Score is based on accuracy, combo, and class skill use • Unlock skins and new songs after each win Popular Track Suggestions: • “Blinding Lights” by The Weeknd • “Levitating” by Dua Lipa • “Believer” by Imagine Dragons • “Bad Guy” by Billie Eilish Interface Notes: • Color-coded lanes with beatballs moving toward player • Touch screen input or FaceKit interaction (head tilt to dodge bombs?) • Energy bar depletes if notes missed • Flashy effects for class abilities, visual feedback on perfect/good/miss
/**** * Plugins ****/ var tween = LK.import("@upit/tween.v1"); var storage = LK.import("@upit/storage.v1"); /**** * Classes ****/ var BeatOrb = Container.expand(function (orbType) { var self = Container.call(this); self.orbType = orbType; self.speed = 4; self.hit = false; var orbGraphics = self.attachAsset(orbType, { anchorX: 0.5, anchorY: 0.5 }); self.update = function () { var speedMultiplier = 1; if (selectedCharacter && selectedCharacter.freezeActive) { speedMultiplier = 0.3; } // Simple fall down movement self.y += self.speed * speedMultiplier; }; return self; }); var Character = Container.expand(function (characterType) { var self = Container.call(this); self.type = characterType; self.abilityReady = true; self.abilityCooldown = 0; self.freezeActive = false; self.freezeTime = 0; self.phaseMode = false; self.phaseModeTime = 0; self.baseY = 0; self.floatOffset = 0; self.animSpeed = 0.05 + Math.random() * 0.03; var characterGraphics = self.attachAsset(characterType, { anchorX: 0.5, anchorY: 0.5 }); self.useAbility = function () { if (!self.abilityReady) return false; LK.getSound('ability').play(); if (self.type === 'ninja') { // Phase Mode: Pass through black orbs for 3 seconds self.phaseMode = true; self.phaseModeTime = 3000; // Add glowing effect tween(self, { tint: 0x9932cc }, { duration: 500 }); LK.effects.flashObject(self, 0x9932cc, 3000); } else if (self.type === 'wizard') { // Time Freeze: Slow orbs for 3 seconds self.freezeActive = true; self.freezeTime = 3000; LK.effects.flashObject(self, 0x00ffff, 3000); } else if (self.type === 'swordmaster') { // Clone Ability: Spawn temporary clone that auto-hits orbs spawnSwordmasterClone(); LK.effects.flashObject(self, 0xffd700, 1000); } self.abilityReady = false; self.abilityCooldown = 10000; // 10 second cooldown return true; }; self.update = function () { if (!self.abilityReady) { self.abilityCooldown -= 16; // ~60fps if (self.abilityCooldown <= 0) { self.abilityReady = true; } } if (self.freezeActive) { self.freezeTime -= 16; if (self.freezeTime <= 0) { self.freezeActive = false; } } if (self.phaseMode) { self.phaseModeTime -= 16; if (self.phaseModeTime <= 0) { self.phaseMode = false; // Remove glow effect tween(self, { tint: 0xffffff }, { duration: 500 }); } } // Floating animation for character selection if (gameState === 'classSelection') { self.floatOffset += self.animSpeed; self.y = self.baseY + Math.sin(self.floatOffset) * 20; // Add mystical particle effect for wizard if (self.type === 'wizard' && LK.ticks % 20 === 0) { LK.effects.flashObject(self, 0x4169e1, 400); } // Add shadow dash effect for ninja if (self.type === 'ninja' && LK.ticks % 30 === 0) { LK.effects.flashObject(self, 0x9932cc, 300); } // Add sword gleam for swordmaster if (self.type === 'swordmaster' && LK.ticks % 25 === 0) { LK.effects.flashObject(self, 0xffd700, 350); } } }; return self; }); /**** * Initialize Game ****/ var game = new LK.Game({ backgroundColor: 0x1a1a2e }); /**** * Game Code ****/ // Game state var gameState = 'classSelection'; // 'classSelection', 'playing', 'gameOver' var selectedCharacter = null; var score = 0; var combo = 0; var maxCombo = 0; var lives = 3; var comboMode = 0; // Ninja ability counter var dualStrikeActive = false; // Swordmaster ability var swordmasterClone = null; var cloneActiveTime = 0; var songProgress = 0; var songDuration = 120000; // 2 minutes // Drag mechanics var isDragging = false; var dragStartX = 0; var dragStartY = 0; var blackOrbHits = 0; // Track black orb hits for game over var missedCount = 0; // Track missed red/green orbs var blackTouchCount = 0; // Track black orb touches // Game objects var orbs = []; var lanes = []; var characters = {}; var targetZone = null; // UI elements var scoreText = null; var comboText = null; var livesText = null; var abilityText = null; var instructionText = null; var ninjaDescText = null; var wizardDescText = null; var swordmasterDescText = null; var titleText = null; // Target position for Beat Saber style var targetY = 2200; var lastSpawnTime = 0; var spawnInterval = 500; // Base spawn interval in ms // Start ambient music for character selection LK.playMusic('ambient', { volume: 0.6 }); // Target zone targetZone = game.addChild(LK.getAsset('targetZone', { anchorX: 0.5, anchorY: 0.5, x: 2048 / 2, y: 2400, alpha: 0.5, width: 2048, height: 300, tint: 0x000080 })); // Create character selection characters.ninja = game.addChild(new Character('ninja')); characters.ninja.x = 2048 * 0.25; characters.ninja.y = 1000; characters.ninja.baseY = 1000; characters.wizard = game.addChild(new Character('wizard')); characters.wizard.x = 2048 * 0.5; characters.wizard.y = 1000; characters.wizard.baseY = 1000; characters.swordmaster = game.addChild(new Character('swordmaster')); characters.swordmaster.x = 2048 * 0.75; characters.swordmaster.y = 1000; characters.swordmaster.baseY = 1000; // UI Setup scoreText = new Text2('Score: 0', { size: 60, fill: 0xFFFFFF }); scoreText.anchor.set(0, 0); LK.gui.topLeft.addChild(scoreText); scoreText.x = 120; scoreText.y = 20; comboText = new Text2('Combo: 0', { size: 50, fill: 0xFFFF00 }); comboText.anchor.set(0.5, 0); LK.gui.top.addChild(comboText); comboText.y = 80; livesText = new Text2('Lives: 3', { size: 50, fill: 0xFF4444 }); livesText.anchor.set(1, 0); LK.gui.topRight.addChild(livesText); livesText.x = -20; livesText.y = 20; abilityText = new Text2('Ability Ready!', { size: 40, fill: 0x00FF00 }); abilityText.anchor.set(0.5, 1); LK.gui.bottom.addChild(abilityText); abilityText.y = -100; // Title text titleText = new Text2('RHYTHM WARRIORS\nBeat Battle Arena', { size: 80, fill: 0xFFD700 }); titleText.anchor.set(0.5, 0); LK.gui.top.addChild(titleText); titleText.y = 200; // Character descriptions ninjaDescText = new Text2('⚫ SHADOW NINJA\n"Strike with silence. Dance with speed."\nAbility: Shadow Slice auto-combo\nDifficulty: Easy to pick, hard to master', { size: 35, fill: 0x9932cc }); ninjaDescText.anchor.set(0.5, 0); game.addChild(ninjaDescText); ninjaDescText.x = 2048 * 0.25; ninjaDescText.y = 1200; wizardDescText = new Text2('🔵 BLUE MAGE\n"Slow the rhythm, control the chaos."\nAbility: Ice Freeze slows orbs\nDifficulty: Medium', { size: 35, fill: 0x4169e1 }); wizardDescText.anchor.set(0.5, 0); game.addChild(wizardDescText); wizardDescText.x = 2048 * 0.5; wizardDescText.y = 1200; swordmasterDescText = new Text2('⚔️ DUAL BLADE SWORDMASTER\n"Two blades. One rhythm."\nAbility: Multi-touch dual strike\nDifficulty: Hard', { size: 35, fill: 0x8b4513 }); swordmasterDescText.anchor.set(0.5, 0); game.addChild(swordmasterDescText); swordmasterDescText.x = 2048 * 0.75; swordmasterDescText.y = 1200; instructionText = new Text2('TAP A CHARACTER TO BEGIN', { size: 50, fill: 0xFFFFFF }); instructionText.anchor.set(0.5, 1); LK.gui.bottom.addChild(instructionText); instructionText.y = -50; // Add move handler for dragging game.move = function (x, y, obj) { if (gameState === 'playing' && isDragging && selectedCharacter) { // Constrain character movement to targetZone bounds var targetLeft = targetZone.x - targetZone.width / 2; var targetRight = targetZone.x + targetZone.width / 2; var targetTop = targetZone.y - targetZone.height / 2; var targetBottom = targetZone.y + targetZone.height / 2; // Keep character within targetZone selectedCharacter.x = Math.max(targetLeft + 60, Math.min(targetRight - 60, x)); selectedCharacter.y = Math.max(targetTop + 60, Math.min(targetBottom - 60, y)); } }; // Input handling game.down = function (x, y, obj) { if (gameState === 'classSelection') { // Check character selection using bounds checking var ninjaLeft = characters.ninja.x - 60; var ninjaRight = characters.ninja.x + 60; var ninjaTop = characters.ninja.y - 60; var ninjaBottom = characters.ninja.y + 60; if (x >= ninjaLeft && x <= ninjaRight && y >= ninjaTop && y <= ninjaBottom) { selectCharacter('ninja'); } else { var wizardLeft = characters.wizard.x - 60; var wizardRight = characters.wizard.x + 60; var wizardTop = characters.wizard.y - 60; var wizardBottom = characters.wizard.y + 60; if (x >= wizardLeft && x <= wizardRight && y >= wizardTop && y <= wizardBottom) { selectCharacter('wizard'); } else { var swordmasterLeft = characters.swordmaster.x - 60; var swordmasterRight = characters.swordmaster.x + 60; var swordmasterTop = characters.swordmaster.y - 60; var swordmasterBottom = characters.swordmaster.y + 60; if (x >= swordmasterLeft && x <= swordmasterRight && y >= swordmasterTop && y <= swordmasterBottom) { selectCharacter('swordmaster'); } } } } else if (gameState === 'playing') { // Check if tapping on character var charLeft = selectedCharacter.x - 60; var charRight = selectedCharacter.x + 60; var charTop = selectedCharacter.y - 60; var charBottom = selectedCharacter.y + 60; if (x >= charLeft && x <= charRight && y >= charTop && y <= charBottom) { // Start dragging isDragging = true; dragStartX = x; dragStartY = y; } else { // Check if tap is within targetZone bounds for orb hits (fallback for non-drag gameplay) var targetLeft = targetZone.x - targetZone.width / 2; var targetRight = targetZone.x + targetZone.width / 2; var targetTop = targetZone.y - targetZone.height / 2; var targetBottom = targetZone.y + targetZone.height / 2; if (x >= targetLeft && x <= targetRight && y >= targetTop && y <= targetBottom) { // Determine hit type based on tap position (Beat Saber style) var hitType = x < 2048 * 0.5 ? 'red' : 'green'; handleOrbHit(x, y, hitType); } } } }; // Handle touch/mouse release game.up = function (x, y, obj) { if (gameState === 'playing' && isDragging) { isDragging = false; // Check if this was a tap (minimal movement) for ability activation var moveDistance = Math.sqrt(Math.pow(x - dragStartX, 2) + Math.pow(y - dragStartY, 2)); if (moveDistance < 30) { // Minimal movement threshold // This was a tap, not a drag - trigger ability if (selectedCharacter && selectedCharacter.abilityReady) { selectedCharacter.useAbility(); updateAbilityText(); } } } }; function selectCharacter(type) { selectedCharacter = characters[type]; gameState = 'playing'; // Hide character descriptions and selection UI titleText.visible = false; ninjaDescText.visible = false; wizardDescText.visible = false; swordmasterDescText.visible = false; instructionText.visible = false; // Hide unselected characters for (var charType in characters) { if (charType !== type) { characters[charType].visible = false; } } // Position selected character in targetZone selectedCharacter.x = 2048 / 2; selectedCharacter.y = targetZone.y; // Character-specific selection effects if (type === 'ninja') { LK.effects.flashScreen(0x9932cc, 800); } else if (type === 'wizard') { LK.effects.flashScreen(0x4169e1, 800); } else if (type === 'swordmaster') { LK.effects.flashScreen(0xffd700, 800); } // Start music and orb spawning LK.playMusic('bgtrack'); } function checkCharacterOrbCollisions() { if (!selectedCharacter || gameState !== 'playing') return; // Check collision with each orb for (var i = orbs.length - 1; i >= 0; i--) { var orb = orbs[i]; if (orb.hit) continue; // Check if orb is within targetZone var targetLeft = targetZone.x - targetZone.width / 2; var targetRight = targetZone.x + targetZone.width / 2; var targetTop = targetZone.y - targetZone.height / 2; var targetBottom = targetZone.y + targetZone.height / 2; var orbInZone = orb.x >= targetLeft && orb.x <= targetRight && orb.y >= targetTop && orb.y <= targetBottom; if (orbInZone) { // Check collision with character (simple distance check) var dx = orb.x - selectedCharacter.x; var dy = orb.y - selectedCharacter.y; var distance = Math.sqrt(dx * dx + dy * dy); if (distance < 80) { // Collision threshold if (orb.orbType === 'blackBomb') { // Check if ninja is in phase mode if (selectedCharacter.type === 'ninja' && selectedCharacter.phaseMode) { // Phase through black orb without penalty orb.hit = true; LK.effects.flashObject(selectedCharacter, 0x9932cc, 200); } else { // Normal black orb collision blackTouchCount++; if (blackTouchCount >= 5) { // Fifth black orb touch - game over LK.getSound('bomb').play(); LK.effects.flashScreen(0xff0000, 500); endGame(); return; } else { // Black orb touch - visual feedback LK.getSound('bomb').play(); LK.effects.flashScreen(0xff0000, 200); orb.hit = true; } } } else { // Hit red or green orb - always successful when touching character var points = 100; if (comboMode > 0) { comboMode--; points *= 2; // Ninja bonus } if (dualStrikeActive) { points *= 2; // Swordmaster bonus dualStrikeActive = false; } combo++; if (combo > maxCombo) maxCombo = combo; points *= Math.min(combo, 10); score += points; LK.getSound('hit').play(); // Visual feedback var hitColor = orb.orbType === 'redOrb' ? 0xff4444 : 0x44ff44; LK.effects.flashScreen(hitColor, 150); tween(orb, { scaleX: 1.5, scaleY: 1.5, alpha: 0 }, { duration: 300 }); orb.hit = true; updateUI(); } } } } } function handleOrbHit(tapX, tapY, expectedType) { var hitOrb = null; var bestDistance = Infinity; // Find closest orb near tap position within targetZone (Beat Saber style) for (var i = 0; i < orbs.length; i++) { var orb = orbs[i]; if (!orb.hit) { // Check if orb is within targetZone bounds var targetLeft = targetZone.x - targetZone.width / 2; var targetRight = targetZone.x + targetZone.width / 2; var targetTop = targetZone.y - targetZone.height / 2; var targetBottom = targetZone.y + targetZone.height / 2; var orbInZone = orb.x >= targetLeft && orb.x <= targetRight && orb.y >= targetTop && orb.y <= targetBottom; if (orbInZone) { var dx = orb.x - tapX; var dy = orb.y - tapY; var distance = Math.sqrt(dx * dx + dy * dy); if (distance < 120 && distance < bestDistance) { hitOrb = orb; bestDistance = distance; } } } } if (hitOrb) { if (hitOrb.orbType === 'blackBomb') { // Hit a bomb - lose life lives--; combo = 0; LK.getSound('bomb').play(); LK.effects.flashScreen(0xff0000, 300); hitOrb.hit = true; if (lives <= 0) { endGame(); return; } } else if (hitOrb.orbType === 'redOrb' && expectedType === 'red' || hitOrb.orbType === 'greenOrb' && expectedType === 'green' || comboMode > 0) { // Successful hit var points = 100; if (comboMode > 0) { comboMode--; points *= 2; // Ninja bonus } if (dualStrikeActive) { points *= 2; // Swordmaster bonus dualStrikeActive = false; } combo++; if (combo > maxCombo) maxCombo = combo; // Combo multiplier points *= Math.min(combo, 10); score += points; LK.getSound('hit').play(); // Enhanced visual feedback for Beat Saber style var hitColor = hitOrb.orbType === 'redOrb' ? 0xff4444 : 0x44ff44; LK.effects.flashScreen(hitColor, 150); tween(hitOrb, { scaleX: 1.5, scaleY: 1.5, alpha: 0 }, { duration: 300 }); hitOrb.hit = true; } else { // Wrong color hit combo = 0; LK.getSound('miss').play(); } } else { // Missed - no orb in range combo = 0; LK.getSound('miss').play(); } updateUI(); } function spawnSwordmasterClone() { if (swordmasterClone) return; // Only one clone at a time swordmasterClone = game.addChild(LK.getAsset('swordmaster', { anchorX: 0.5, anchorY: 0.5, x: selectedCharacter.x + 150, y: selectedCharacter.y, alpha: 0.7 })); cloneActiveTime = 1000; // 1 second // Flash effect for clone spawn LK.effects.flashObject(swordmasterClone, 0xffd700, 300); } function spawnOrb() { var orbTypes = ['redOrb', 'greenOrb', 'blackBomb']; var weights = [0.4, 0.4, 0.2]; // 40% red, 40% green, 20% bomb var rand = Math.random(); var orbType = 'redOrb'; if (rand < weights[0]) orbType = 'redOrb';else if (rand < weights[0] + weights[1]) orbType = 'greenOrb';else orbType = 'blackBomb'; var orb = new BeatOrb(orbType); // Spawn from random position at top of screen orb.x = 400 + Math.random() * 1248; // Random X within safe bounds orb.y = -100; // Start above screen orbs.push(orb); game.addChild(orb); // Add spawn effect LK.effects.flashObject(orb, 0xffffff, 200); } function autoHitOrbWithClone() { if (!swordmasterClone) return; // Find closest non-bomb orb within targetZone to auto-hit var closestOrb = null; var closestDistance = Infinity; for (var i = 0; i < orbs.length; i++) { var orb = orbs[i]; if (!orb.hit && orb.orbType !== 'blackBomb') { // Check if orb is within targetZone bounds var targetLeft = targetZone.x - targetZone.width / 2; var targetRight = targetZone.x + targetZone.width / 2; var targetTop = targetZone.y - targetZone.height / 2; var targetBottom = targetZone.y + targetZone.height / 2; var orbInZone = orb.x >= targetLeft && orb.x <= targetRight && orb.y >= targetTop && orb.y <= targetBottom; if (orbInZone) { var dx = orb.x - swordmasterClone.x; var dy = orb.y - swordmasterClone.y; var distance = Math.sqrt(dx * dx + dy * dy); if (distance < closestDistance) { closestOrb = orb; closestDistance = distance; } } } } // Auto-hit the closest orb if (closestOrb) { var points = 150; // Clone hits give bonus points combo++; if (combo > maxCombo) maxCombo = combo; points *= Math.min(combo, 10); score += points; LK.getSound('hit').play(); // Visual feedback var hitColor = closestOrb.orbType === 'redOrb' ? 0xff4444 : 0x44ff44; LK.effects.flashScreen(hitColor, 100); tween(closestOrb, { scaleX: 1.5, scaleY: 1.5, alpha: 0 }, { duration: 300 }); closestOrb.hit = true; updateUI(); } } function updateUI() { scoreText.setText('Score: ' + score); comboText.setText('Combo: ' + combo); livesText.setText('Missed: ' + missedCount + '/5 | Black: ' + blackTouchCount + '/5'); LK.setScore(score); } function updateAbilityText() { if (!selectedCharacter) return; if (selectedCharacter.abilityReady) { abilityText.setText('Ability Ready!'); abilityText.tint = 0x00ff00; } else { var cooldownSeconds = Math.ceil(selectedCharacter.abilityCooldown / 1000); abilityText.setText('Ability: ' + cooldownSeconds + 's'); abilityText.tint = 0xff4444; } } function gameOver() { gameState = 'gameOver'; LK.effects.flashScreen(0xff0000, 1000); LK.showGameOver(); } function endGame() { gameState = 'gameOver'; // Save high score var highScore = storage.highScore || 0; if (score > highScore) { storage.highScore = score; } // Save stats storage.gamesPlayed = (storage.gamesPlayed || 0) + 1; if (maxCombo > (storage.maxCombo || 0)) { storage.maxCombo = maxCombo; } LK.showGameOver(); } function checkWinCondition() { if (songProgress >= songDuration) { // Survived the full song! var bonusScore = lives * 1000 + maxCombo * 100; score += bonusScore; LK.setScore(score); // Save completion storage.songsCompleted = (storage.songsCompleted || 0) + 1; LK.showYouWin(); } } // Main game update loop game.update = function () { if (gameState !== 'playing') return; songProgress += 16; // ~60fps // Update character abilities if (selectedCharacter) { selectedCharacter.update(); updateAbilityText(); } // Check character-orb collisions checkCharacterOrbCollisions(); // Update swordmaster clone if (swordmasterClone && cloneActiveTime > 0) { cloneActiveTime -= 16; // ~60fps // Clone auto-hits orbs every 100ms if (LK.ticks % 6 === 0) { // Every ~100ms at 60fps autoHitOrbWithClone(); } // Remove clone when time expires if (cloneActiveTime <= 0) { tween(swordmasterClone, { alpha: 0, scaleX: 0.5, scaleY: 0.5 }, { duration: 300, onFinish: function onFinish() { if (swordmasterClone) { swordmasterClone.destroy(); swordmasterClone = null; } } }); } } // Spawn orbs based on BPM timing (Beat Saber style) var currentTime = Date.now(); if (currentTime - lastSpawnTime > spawnInterval) { spawnOrb(); lastSpawnTime = currentTime; // Gradually increase spawn rate if (spawnInterval > 300) { spawnInterval -= 2; } } // Update orbs for (var i = orbs.length - 1; i >= 0; i--) { var orb = orbs[i]; // Remove hit orbs after animation if (orb.hit) { orb.alpha -= 0.1; if (orb.alpha <= 0) { orb.destroy(); orbs.splice(i, 1); } continue; } // Check if orb passed the targetZone (missed) var targetBottom = targetZone.y + targetZone.height / 2; if (orb.y > targetBottom + 50) { if (orb.orbType === 'blackBomb') { // Bomb passed through - no penalty for missing bombs } else { // Missed a good orb missedCount++; combo = 0; LK.getSound('miss').play(); // Check if missed 5 orbs if (missedCount >= 5) { endGame(); return; } } orb.destroy(); orbs.splice(i, 1); updateUI(); continue; } } // Check win condition checkWinCondition(); };
===================================================================
--- original.js
+++ change.js
@@ -32,8 +32,10 @@
self.abilityReady = true;
self.abilityCooldown = 0;
self.freezeActive = false;
self.freezeTime = 0;
+ self.phaseMode = false;
+ self.phaseModeTime = 0;
self.baseY = 0;
self.floatOffset = 0;
self.animSpeed = 0.05 + Math.random() * 0.03;
var characterGraphics = self.attachAsset(characterType, {
@@ -43,11 +45,18 @@
self.useAbility = function () {
if (!self.abilityReady) return false;
LK.getSound('ability').play();
if (self.type === 'ninja') {
- // Shadow Slice: Auto-hit next 3 orbs
- comboMode = 3;
- LK.effects.flashObject(self, 0x9932cc, 500);
+ // Phase Mode: Pass through black orbs for 3 seconds
+ self.phaseMode = true;
+ self.phaseModeTime = 3000;
+ // Add glowing effect
+ tween(self, {
+ tint: 0x9932cc
+ }, {
+ duration: 500
+ });
+ LK.effects.flashObject(self, 0x9932cc, 3000);
} else if (self.type === 'wizard') {
// Time Freeze: Slow orbs for 3 seconds
self.freezeActive = true;
self.freezeTime = 3000;
@@ -73,8 +82,20 @@
if (self.freezeTime <= 0) {
self.freezeActive = false;
}
}
+ if (self.phaseMode) {
+ self.phaseModeTime -= 16;
+ if (self.phaseModeTime <= 0) {
+ self.phaseMode = false;
+ // Remove glow effect
+ tween(self, {
+ tint: 0xffffff
+ }, {
+ duration: 500
+ });
+ }
+ }
// Floating animation for character selection
if (gameState === 'classSelection') {
self.floatOffset += self.animSpeed;
self.y = self.baseY + Math.sin(self.floatOffset) * 20;
@@ -122,8 +143,10 @@
var isDragging = false;
var dragStartX = 0;
var dragStartY = 0;
var blackOrbHits = 0; // Track black orb hits for game over
+var missedCount = 0; // Track missed red/green orbs
+var blackTouchCount = 0; // Track black orb touches
// Game objects
var orbs = [];
var lanes = [];
var characters = {};
@@ -370,20 +393,28 @@
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance < 80) {
// Collision threshold
if (orb.orbType === 'blackBomb') {
- blackOrbHits++;
- if (blackOrbHits >= 2) {
- // Second black orb hit - game over
- LK.getSound('bomb').play();
- LK.effects.flashScreen(0xff0000, 500);
- endGame();
- return;
- } else {
- // First black orb hit - just visual feedback
- LK.getSound('bomb').play();
- LK.effects.flashScreen(0xff0000, 200);
+ // Check if ninja is in phase mode
+ if (selectedCharacter.type === 'ninja' && selectedCharacter.phaseMode) {
+ // Phase through black orb without penalty
orb.hit = true;
+ LK.effects.flashObject(selectedCharacter, 0x9932cc, 200);
+ } else {
+ // Normal black orb collision
+ blackTouchCount++;
+ if (blackTouchCount >= 5) {
+ // Fifth black orb touch - game over
+ LK.getSound('bomb').play();
+ LK.effects.flashScreen(0xff0000, 500);
+ endGame();
+ return;
+ } else {
+ // Black orb touch - visual feedback
+ LK.getSound('bomb').play();
+ LK.effects.flashScreen(0xff0000, 200);
+ orb.hit = true;
+ }
}
} else {
// Hit red or green orb - always successful when touching character
var points = 100;
@@ -570,9 +601,9 @@
}
function updateUI() {
scoreText.setText('Score: ' + score);
comboText.setText('Combo: ' + combo);
- livesText.setText('Lives: ' + lives);
+ livesText.setText('Missed: ' + missedCount + '/5 | Black: ' + blackTouchCount + '/5');
LK.setScore(score);
}
function updateAbilityText() {
if (!selectedCharacter) return;
@@ -584,8 +615,13 @@
abilityText.setText('Ability: ' + cooldownSeconds + 's');
abilityText.tint = 0xff4444;
}
}
+function gameOver() {
+ gameState = 'gameOver';
+ LK.effects.flashScreen(0xff0000, 1000);
+ LK.showGameOver();
+}
function endGame() {
gameState = 'gameOver';
// Save high score
var highScore = storage.highScore || 0;
@@ -674,10 +710,16 @@
if (orb.orbType === 'blackBomb') {
// Bomb passed through - no penalty for missing bombs
} else {
// Missed a good orb
+ missedCount++;
combo = 0;
LK.getSound('miss').play();
+ // Check if missed 5 orbs
+ if (missedCount >= 5) {
+ endGame();
+ return;
+ }
}
orb.destroy();
orbs.splice(i, 1);
updateUI();
A ninja wearing tight black clothes, purple scarf, masked face, white skin, glowing purple eyes, slim and agile body, simple background, front-facing character with no background, standing pose, 2D game character. In-Game asset. 2d. High contrast. No shadows
A white-clothed male samurai with torn clothes, long gray hair tied back, pale skin, red belt on his waist, holding two swords, standing confidently, simple pose, no background, front-facing, 2D game character. In-Game asset. 2d. High contrast. No shadows
A female mage with pale skin, long white hair, wearing a long blue robe and a pointed blue hat, holding a glowing icy staff with a blue crystal, snowflake patterns on robe, cold expression, simple background, front-facing, no background, 2D game character. In-Game asset. 2d. High contrast. No shadows
Green goblin without backround. In-Game asset. 2d. High contrast. No shadows
Red wild monster. In-Game asset. 2d. High contrast. No shadows
Black monster , white eyes looks like bomb. In-Game asset. 2d. High contrast. No shadows