微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

在 Swift/SpriteKit 中碰撞时的空气曲棍球圆环脉冲?

如何解决在 Swift/SpriteKit 中碰撞时的空气曲棍球圆环脉冲?

背景:我正在 SpriteKit (Swift) 中开发一个简单的游戏/应用程序。它类似于空气曲棍球,但带有磁铁(如名为 Klask 的桌面游戏)。我已经花了很多时间添加商店、广告、菜单等。到目前为止,这对我来说是一个有趣的学习项目。

当前方法当球员/槌击球时,我对球施加脉冲。这个脉冲(它接受一个 CGVector(dx:..,dy:..))是由帧到帧的触摸移动/位置计算的。因此,例如,如果玩家向东北方向移动木槌并且检测到球与玩家之间发生碰撞,则球将直接向东北方向移动(向上和向右)。

问题:这并没有考虑到玩家何时夹球,这会导致扭曲效果。玩家会期望球向基于球撞击位置的方向移动玩家用槌子(圆形)而不是触摸的方向(通常效果很好)。

Here is a clip to better explain the issue:

期望的实现(来自 Acceleroto 的 Air Hockey 的演示):

enter image description here

当前实现/代码

// In player class
override func touchesMoved(_ touches: Set<UITouch>,with event: UIEvent?)
{
    bottomTouchIsActive = true
    var releventTouch:UITouch!
    //convert set to kNown type
    let touchSet = touches
    //get array of touches so we can loop through them
    let orderedtouches = Array(touchSet)

    for touch in orderedtouches
    {
        //if we've not yet found a relevent touch
        if releventTouch == nil
        {
            //look for a touch that is in the activeArea (Avoid touches by opponent)
            if activeArea.contains(CGPoint(x: touch.location(in: parent!).x,y: touch.location(in: parent!).y + frame.height * 0.24))
            {
                isUserInteractionEnabled = true
                releventTouch = touch
            }
            else
            {
                releventTouch = nil
            }
        }
    }     
    if (releventTouch != nil) && lastTouchTimeStamp != nil
    {
        //get touch position and relocate player
        let location = CGPoint(x: releventTouch!.location(in: parent!).x,y: releventTouch!.location(in: parent!).y + frame.height * 0.24)
        position = location
            
        //find old location and use pythagoras to determine length between both points
        let oldLocation = CGPoint(x: releventTouch!.prevIoUsLocation(in: parent!).x,y: releventTouch!.prevIoUsLocation(in: parent!).y + frame.height * 0.24)
        let xOffset = location.x - oldLocation.x
        let yOffset = location.y - oldLocation.y
        let vectorLength = sqrt(xOffset * xOffset + yOffset * yOffset)
        let seconds = releventTouch.timestamp - lastTouchTimeStamp!
        let veLocity = 0.015 * Double(vectorLength) / seconds
            
        //to calculate the vector,the velcity needs to be converted to a CGFloat
        let veLocityCGFloat = CGFloat(veLocity)
            
            
        // NSUserDefaults for more direct access in collision detection
        let forceSaveDX = UserDefaults.standard
        forceSaveDX.set(veLocityCGFloat * xOffset / vectorLength,forKey: "BottomForceDX")
        forceSaveDX.synchronize()
            
        let forceSaveDY = UserDefaults.standard
        forceSaveDY.set(veLocityCGFloat * yOffset / vectorLength,forKey: "BottomForceDY")
        forceSaveDY.synchronize()
            
        //Only apply an impulse if the touch is active.
        delegate?.bottomTouchIsActive(bottomTouchIsActive,fromBottomPlayer: self)

        //update latest touch time for next calculation
        lastTouchTimeStamp = releventTouch.timestamp
    }
    else if (releventTouch != nil) && lastTouchTimeStamp == nil
    {
        //get touch position and relocate player
        let location = CGPoint(x: releventTouch!.location(in: parent!).x,y: releventTouch!.prevIoUsLocation(in: parent!).y + frame.height * 0.24)
        let xOffset = location.x - oldLocation.x
        let yOffset = location.y - oldLocation.y
        let vectorLength = sqrt(xOffset * xOffset + yOffset * yOffset)
            
        //update latest touch time for next calculation
        lastTouchTimeStamp = releventTouch.timestamp
    }
}
// In main gameScene
func didBegin(_ contact: SKPhysicsContact)
{
    if (contact.bodyA.categoryBitMask == BodyType.ball.rawValue && contact.bodyB.categoryBitMask == BodyType.player.rawValue) && (contact.bodyA.contactTestBitMask == 25 || contact.bodyB.contactTestBitMask == 25) && bottomTouchForCollision == true
    {
        ball!.physicsBody!.applyImpulse(CGVector(dx: CGFloat(UserDefaults.standard.float(forKey: "BottomForceDX")),dy: CGFloat(UserDefaults.standard.float(forKey: "BottomForceDY"))))
    }
}

我为这么长的问题道歉,很难解释问题是什么。但基本上我只需要使用球击中球员槌的位置而不是触球方向来计算冲量。如果这可以直接在碰撞检测功能中完成,那就更好了,因为不会有专门用于计算触摸方向的额外帧。我被困了一段时间。

我认为最好将触球速度和球击中槌的位置结合起来,以获得最真实的冲击力。我只是不知道如何以这种方式计算向量。我愿意接受所有想法!

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。