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

SpriteKit中实现敌人追踪移动玩家持续射击子弹的问题

SpriteKit敌人持续射击与子弹追踪问题修复

问题描述

我开发了一款SpriteKit游戏,其中enemy精灵周围有隐形触发圈,player精灵可围绕敌人360度自由移动。需求是:玩家进入触发圈后,敌人开始持续射击子弹,且子弹能追踪移动中的玩家。目前遇到两个问题:

  • 敌人无法持续射击子弹
  • 子弹发射后不会追踪玩家后续移动的位置

核心代码(原问题代码)

不确定fireBullets()函数的调用位置(update/didMove/didBegin),原函数实现如下:

func fireBullets() {

    var fireBulletAction: SKAction

    fireBulletAction = SKAction.run {
        let bullet = self.createBullets()
        var moveBullet = SKAction.move(to: self.player.position, duration: 1)
        bullet.run(moveBullet)
    }

    var waitForDuration: SKAction
    waitForDuration = SKAction.wait(forDuration: 1)

    var bulletSequence = SKAction.sequence([fireBulletAction, waitForDuration])

    var repeatBulletSequence = SKAction.repeatForever(bulletSequence)

    enemy.run(repeatBulletSequence, withKey: "fireBullet")
}

问题修复方案

1. 解决敌人无法持续射击的问题

  • 正确调用位置:fireBullets()应该放在didBegin(_ contact: SKPhysicsContact)中(检测到玩家进入触发圈时触发),但必须避免重复启动射击动作——每次触发前先检查敌人是否已经在执行射击动作,不存在再启动。
  • 离开触发圈停止射击:在didEnd(_ contact: SKPhysicsContact)中移除敌人的射击动作,确保玩家离开后停止射击。

修正后的触发逻辑:

override func didBegin(_ contact: SKPhysicsContact) {
    // 替换成你实际的物理碰撞掩码常量
    let enemyTriggerMask = 0b100
    let playerMask = 0b001
    
    let isPlayerEnterTrigger = (contact.bodyA.categoryBitMask == enemyTriggerMask && contact.bodyB.categoryBitMask == playerMask) ||
                               (contact.bodyB.categoryBitMask == enemyTriggerMask && contact.bodyA.categoryBitMask == playerMask)
    
    if isPlayerEnterTrigger {
        fireBullets()
    }
}

override func didEnd(_ contact: SKPhysicsContact) {
    let enemyTriggerMask = 0b100
    let playerMask = 0b001
    
    let isPlayerExitTrigger = (contact.bodyA.categoryBitMask == enemyTriggerMask && contact.bodyB.categoryBitMask == playerMask) ||
                              (contact.bodyB.categoryBitMask == enemyTriggerMask && contact.bodyA.categoryBitMask == playerMask)
    
    if isPlayerExitTrigger {
        enemy.removeAction(forKey: "fireBullet")
        // 可选:清理场上残留的子弹
        children.forEach { if $0.name == "bullet" { $0.removeFromParent() } }
    }
}

2. 解决子弹无法追踪移动中玩家的问题

原代码中SKAction.move(to: self.player.position)只会获取子弹创建瞬间的玩家位置,后续玩家移动时子弹不会更新目标。推荐用物理引擎控制子弹移动,在update中实时更新子弹的运动方向:

步骤1:修正fireBullets()函数

func fireBullets() {
    // 避免重复启动射击动作
    guard enemy.action(forKey: "fireBullet") == nil else { return }
    
    let fireBulletAction = SKAction.run {
        let bullet = self.createBullets()
        bullet.name = "bullet" // 标记子弹,方便后续在update中识别
        // 初始化子弹的初始方向(指向当前玩家位置)
        let direction = CGVector(dx: self.player.position.x - bullet.position.x, dy: self.player.position.y - bullet.position.y)
        let length = sqrt(direction.dx * direction.dx + direction.dy * direction.dy)
        let normalizedDir = CGVector(dx: direction.dx / length, dy: direction.dy / length)
        // 设置子弹速度(300为速度值,可根据需求调整)
        bullet.physicsBody?.velocity = CGVector(dx: normalizedDir.dx * 300, dy: normalizedDir.dy * 300)
    }
    
    let waitAction = SKAction.wait(forDuration: 1)
    let sequence = SKAction.sequence([fireBulletAction, waitAction])
    let repeatSequence = SKAction.repeatForever(sequence)
    
    enemy.run(repeatSequence, withKey: "fireBullet")
}

步骤2:在update中实时更新子弹方向

override func update(_ currentTime: TimeInterval) {
    // 遍历所有子弹,更新它们的运动方向
    for bullet in children where bullet.name == "bullet" {
        let direction = CGVector(dx: player.position.x - bullet.position.x, dy: player.position.y - bullet.position.y)
        let length = sqrt(direction.dx * direction.dx + direction.dy * direction.dy)
        // 避免除以0(子弹和玩家重合时)
        guard length > 0 else { continue }
        let normalizedDir = CGVector(dx: direction.dx / length, dy: direction.dy / length)
        // 保持子弹速度不变,只改变方向
        bullet.physicsBody?.velocity = CGVector(dx: normalizedDir.dx * 300, dy: normalizedDir.dy * 300)
    }
}

注意事项

  • 确保createBullets()函数给子弹添加了physicsBody,并且设置了正确的碰撞掩码(避免子弹和敌人碰撞)
  • 调整子弹速度值(示例中300)和射击间隔(示例中1秒)来匹配游戏节奏

内容的提问来源于stack exchange,提问作者quickj

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.16 10:55:39