You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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:

  1. Add a timer property to your scene class:
class GameScene: SKScene {
    var dropTimer: Timer?
    // Rest of your scene code...
}
  1. 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
    )
}
  1. Update your bananaDrop function (make it @objc for 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)
}
  1. 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:

  1. Make your scene conform to SKPhysicsContactDelegate:
class GameScene: SKScene, SKPhysicsContactDelegate {
    // Rest of your scene code...
}
  1. 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
}
  1. 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 -")
    }
}
  1. Your bananaDrop function 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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.22 09:05:28