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

Swift 4无限跑酷游戏如何实现障碍物特定侧面碰撞检测?

嘿,作为iOS开发新手能做出无限跑酷游戏已经超棒啦!针对你现在遇到的「玩家碰障碍物任意侧面都会死亡」的问题,我来给你几个实用的解决思路,都是实际开发中常用的方案~

核心思路:区分碰撞的位置/区域

当前代码只是检测了「玩家和障碍物发生碰撞」这个事件,但没有判断碰撞发生在障碍物的哪个部位。我们需要通过碰撞点位置、多物理体分区或者碰撞方向向量来精准限制触发死亡的区域。

方法1:通过碰撞接触点的位置判断(最适合新手)

在碰撞回调里获取接触点,把它转换成障碍物坐标系下的位置,再判断这个点是否在你想要触发死亡的区域内(比如障碍物的正面)。

修改后的代码示例:

func didBegin(_ contact: SKPhysicsContact) {
    var firstBody = contact.bodyA
    var secondBody = contact.bodyB
    
    // 统一把玩家设为firstBody,方便后续判断
    if contact.bodyB.node?.name == "Player" {
        swap(&firstBody, &secondBody)
    }
    
    // 处理地面碰撞逻辑
    if firstBody.node?.name == "Player" && secondBody.node?.name == "Ground" {
        canJump = true
        return
    }
    
    // 检查是否是玩家和障碍物/巴士的碰撞
    guard firstBody.node?.name == "Player",
          let obstacleNode = secondBody.node,
          ["Bus", "Obstacle"].contains(obstacleNode.name) else {
        return
    }
    
    // 将碰撞点转换到障碍物的本地坐标系
    let contactPoint = contact.contactPoint
    let localPoint = obstacleNode.convert(contactPoint, from: obstacleNode.scene!)
    
    // 假设我们只在玩家碰撞到障碍物的「前20%区域」时触发死亡
    // 这里的数值需要根据你的障碍物尺寸、游戏方向调整
    // 比如跑酷里障碍物通常从右往左移动,那左侧区域就是正面
    let obstacleWidth = obstacleNode.frame.width
    if localPoint.x < obstacleWidth * 0.2 {
        playerDied()
    }
}

小贴士:如果你的障碍物是从左往右移动,就把判断条件改成 localPoint.x > obstacleWidth * 0.8,对应障碍物的右侧区域。

方法2:给障碍物添加多个分区物理体

给障碍物的不同侧面单独设置物理体,分配不同的碰撞分类,只在玩家碰撞到「死亡区域」的物理体时触发逻辑。

步骤1:先定义物理分类常量

struct PhysicsCategory {
    static let Player: UInt32 = 0b1 << 0
    static let Ground: UInt32 = 0b1 << 1
    static let ObstacleDeathZone: UInt32 = 0b1 << 2 // 触发死亡的区域
    static let ObstacleSafeZone: UInt32 = 0b1 << 3 // 安全区域
}

步骤2:给障碍物设置多物理体

// 假设你的障碍物是SKSpriteNode
let obstacle = SKSpriteNode(imageNamed: "obstacle")
obstacle.name = "Obstacle"

// 创建死亡区域物理体(比如左侧20%宽度)
let deathBody = SKPhysicsBody(rectangleOf: CGSize(width: obstacle.frame.width * 0.2, height: obstacle.frame.height))
deathBody.categoryBitMask = PhysicsCategory.ObstacleDeathZone
deathBody.position = CGPoint(x: -obstacle.frame.width * 0.4, y: 0) // 调整位置到障碍物左侧

// 创建安全区域物理体
let safeBody = SKPhysicsBody(rectangleOf: CGSize(width: obstacle.frame.width * 0.8, height: obstacle.frame.height))
safeBody.categoryBitMask = PhysicsCategory.ObstacleSafeZone
safeBody.position = CGPoint(x: obstacle.frame.width * 0.3, y: 0)

// 合并两个物理体作为障碍物的整体物理体
obstacle.physicsBody = SKPhysicsBody(bodies: [deathBody, safeBody])
obstacle.physicsBody?.contactTestBitMask = PhysicsCategory.Player
obstacle.physicsBody?.collisionBitMask = PhysicsCategory.Player | PhysicsCategory.Ground

步骤3:在碰撞回调里判断分类

func didBegin(_ contact: SKPhysicsContact) {
    var firstBody = contact.bodyA
    var secondBody = contact.bodyB
    
    if contact.bodyB.node?.name == "Player" {
        swap(&firstBody, &secondBody)
    }
    
    if firstBody.node?.name == "Player" {
        if secondBody.node?.name == "Ground" {
            canJump = true
        } else if secondBody.categoryBitMask == PhysicsCategory.ObstacleDeathZone {
            playerDied()
        }
    }
}

这个方法适合障碍物形状固定的场景,物理引擎会帮你自动区分碰撞区域,不需要手动计算位置。

方法3:利用碰撞方向向量判断

通过SKPhysicsContact的contactNormal属性获取碰撞的方向向量,判断碰撞是否来自你想要的方向(比如玩家正面撞到障碍物)。

示例代码:

func didBegin(_ contact: SKPhysicsContact) {
    var firstBody = contact.bodyA
    var secondBody = contact.bodyB
    
    if contact.bodyB.node?.name == "Player" {
        swap(&firstBody, &secondBody)
    }
    
    // 处理地面碰撞
    if firstBody.node?.name == "Player" && secondBody.node?.name == "Ground" {
        canJump = true
        return
    }
    
    guard firstBody.node?.name == "Player",
          ["Bus", "Obstacle"].contains(secondBody.node?.name) else {
        return
    }
    
    // contactNormal是碰撞的法向量,指向碰撞体的外部
    // 假设游戏中玩家向右跑,障碍物向左移动,那么正面碰撞的法向量x分量会是负数
    if contact.contactNormal.x < -0.5 { // 接近向左的方向,说明撞到障碍物正面
        playerDied()
    }
}

这个方法适合移动的障碍物,不需要关心物体尺寸,但需要调试法向量的数值,确保方向判断准确。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.15 04:48:57