SpriteKit游戏随机生成精灵问题:香蕉仅掉落一次无法重复掉落
Hey there! Let's break down why your bananas only drop once and fix that so you can keep the fruit flowing for your players.
First, let's look at the core issue in your current setup: your bananaDrop function runs once, but there's no logic in place to trigger it again after a banana is collected (or after it finishes its fall). Let's walk through two solid solutions depending on how you want your game to behave.
The Problem in Your Current Code Snippet
Your existing bananaDrop creates a banana just fine, but without a way to re-run the function, it'll only ever spawn one. Here's your code for reference:
func bananaDrop(timer: Timer) { print("- Debug: [bananaDrop] successfully initiated -") let spriteGenerator = GKShuffledDistribution(lowestValue: 1, highestValue: 7) let banana = SKSpriteNode(imageNamed:"banana") // (I assume you have code here to position the banana, add physics, etc.) }
Solution 1: Auto-Spawn Bananas on a Repeat Timer
If you want bananas to drop at fixed intervals (e.g., every 2 seconds), you just need to make sure your timer is set to repeat, and store it as a scene property so it doesn't get deallocated.
Step-by-Step Implementation:
- Add a timer property to your scene class:
class GameScene: SKScene { var dropTimer: Timer? // Rest of your scene code... }
- Initialize the repeat timer when your scene loads:
override func didMove(to view: SKView) { // Start spawning bananas every 2 seconds dropTimer = Timer.scheduledTimer( timeInterval: 2.0, target: self, selector: #selector(bananaDrop), userInfo: nil, repeats: true ) }
- Update your
bananaDropfunction (make it@objcfor the timer selector) and add full spawn logic:
@objc func bananaDrop() { print("- Debug: [bananaDrop] successfully initiated -") let spriteGenerator = GKShuffledDistribution(lowestValue: 1, highestValue: 7) let banana = SKSpriteNode(imageNamed:"banana") // Set random X position so bananas don't all drop in the same spot let screenWidth = UIScreen.main.bounds.width let xPos = CGFloat(spriteGenerator.nextInt()) * (screenWidth / 8) // Fit 7 positions across the screen banana.position = CGPoint(x: xPos, y: self.frame.maxY + banana.size.height/2) // Add physics so the banana falls banana.physicsBody = SKPhysicsBody(rectangleOf: banana.size) banana.physicsBody?.categoryBitMask = 0b10 // Assign banana collision category banana.physicsBody?.contactTestBitMask = 0b01 // Detect contact with player banana.physicsBody?.collisionBitMask = 0 // No physical collisions, just contact detection banana.physicsBody?.affectedByGravity = true self.addChild(banana) }
- Clean up the timer when the scene exits to avoid memory leaks:
override func willMove(from view: SKView) { dropTimer?.invalidate() }
Solution 2: Spawn a New Banana Immediately After Collection
If you want to spawn a new banana right when the player collects the current one, you'll use collision detection to trigger the next spawn.
Step-by-Step Implementation:
- Make your scene conform to
SKPhysicsContactDelegate:
class GameScene: SKScene, SKPhysicsContactDelegate { // Rest of your scene code... }
- Set up the contact delegate and spawn the first banana when the scene loads:
override func didMove(to view: SKView) { physicsWorld.contactDelegate = self bananaDrop() // Spawn the first banana right away }
- Use the contact delegate method to detect when the player collects a banana, then spawn a new one:
func didBegin(_ contact: SKPhysicsContact) { let contactCombination = contact.bodyA.categoryBitMask | contact.bodyB.categoryBitMask // Check if the contact is between player (0b01) and banana (0b10) if contactCombination == 0b01 | 0b10 { // Remove the collected banana let collectedBanana = contact.bodyA.categoryBitMask == 0b10 ? contact.bodyA.node : contact.bodyB.node collectedBanana?.removeFromParent() // Spawn a new banana immediately bananaDrop() print("- Debug: Banana collected! Spawning new one -") } }
- Your
bananaDropfunction stays mostly the same (you can remove the timer parameter since we're calling it directly):
func bananaDrop() { print("- Debug: [bananaDrop] successfully initiated -") let spriteGenerator = GKShuffledDistribution(lowestValue: 1, highestValue: 7) let banana = SKSpriteNode(imageNamed:"banana") // Same positioning and physics setup as Solution 1 let screenWidth = UIScreen.main.bounds.width let xPos = CGFloat(spriteGenerator.nextInt()) * (screenWidth / 8) banana.position = CGPoint(x: xPos, y: self.frame.maxY + banana.size.height/2) banana.physicsBody = SKPhysicsBody(rectangleOf: banana.size) banana.physicsBody?.categoryBitMask = 0b10 banana.physicsBody?.contactTestBitMask = 0b01 banana.physicsBody?.collisionBitMask = 0 banana.physicsBody?.affectedByGravity = true self.addChild(banana) }
Whichever approach you pick, the key fix is ensuring bananaDrop gets called repeatedly—either via a repeating timer or via collision detection when a banana is collected. That'll keep the bananas falling nonstop for your players to catch!
内容的提问来源于stack exchange,提问作者Micah Shackelford

