【问题标题】:Friction in SpriteKitSpriteKit 中的摩擦
【发布时间】:2014-12-11 19:42:09
【问题描述】:

我正在使用 Swift、SpriteKit 和 Xcode 6, 我的屏幕上有一个圆形节点,我可以用手指改变节点的位置,但我想对这个节点实现摩擦效果,但我现在不知道如何做,这是我的代码:

class PlayScene: SKScene
{    
let firstCircle = SKSpriteNode(imageNamed: "Circle")

// theses 3 variables allows me to move the node according to my finger, but my finger don't have to touch the node
var departCircleLocation = CGPoint()
var departTouchLocation = CGPoint()
var currentTouchLocation = CGPoint()

override func didMoveToView(view: SKView)
{
    addChild(firstCircle)
}

override func touchesBegan(touches: NSSet, withEvent event: UIEvent)
{
    for touch: AnyObject in touches
    {
        departTouchLocation = touch.locationInNode(self) 
    }

    departCircleLocation = firstCircle.position
}

override func touchesMoved(touches: NSSet, withEvent event: UIEvent)
{
    for touch: AnyObject in touches
    {
        currentTouchLocation = touch.locationInNode(self)
    }

    moveCircle()
}

func moveCircle()
{
    firstCircle.position.x = departCircleLocation.x - departTouchLocation.x + currentTouchLocation.x
    firstCircle.position.y = departCircleLocation.y - departTouchLocation.y + currentTouchLocation.y
}
}

我尝试将其放入我的代码中,但没有成功:

firstCircle.physicsBody = SKPhysicsBody(circleOfRadius: 7)
firstCircle.physicsBody?.affectedByGravity = false
firstCircle.physicsBody?.friction = 0.4

我不想要重力,因为游戏是从上方观看的

有人可以向我解释如何对这个节点实施摩擦吗? 例如,我想当我以一定的速度向上滑动时,当我松开手指时,节点会继续上升一点时间,但是如果我再次将手指放在屏幕上,摩擦会立即停止,例如:

如果我将手指放在节点下方 50 像素处,它不会做任何事情,但如果我将手指(即节点下方 50 像素)移动到节点下方 80 像素处,节点将从 30 像素向下移动,这有效在任何 x 和 y 方向上,我可以在不触摸它的情况下移动节点,但是如果我的手指,它将跟随路径,例如,现在如果我将手指从 30 像素向下移动非常快并且我松开手指,节点将由于摩擦力继续向下,但我的手指不再在屏幕上(效果看起来像我们在iphone上滚动网站时,由于速度的原因松开手指时会有一点摩擦你的滑动)但我不能使用 UISwipeGesture 因为它只检测向上、向右、向下和向左的方向,而不是像我想要的每个方向。 我希望你能明白我在说什么

【问题讨论】:

  • 如何移动节点?你想要摩擦同时节点被手指移动吗?在这种情况下,您不能直接设置节点的位置,而是需要对身体施加脉冲/力
  • @LearnCocos2D,好吧,我编辑了我的帖子,也许这样你会更容易理解,我不是英语,所以我很难准确地解释我想要什么跨度>
  • 听起来你想模拟空气阻力而不是摩擦力,所以你应该设置linearDamping属性。无论如何,LearnCocos2D 是正确的,你需要通过对圆的物理体施加脉冲或力来移动圆,而不是直接改变它的位置。
  • 好的,谢谢@0x141E,但我不知道如何用力而不是手指的位置来移动节点!我的意思是,我知道我必须使用 apllyForce 或 applyImpulse,但是如何检测手指的方向和力度?
  • 这取决于你。您可以从手指位置中减去精灵的位置。如果您的手指是正确的,则向右移动精灵,等等。如果需要,您可以根据手指和精灵之间的距离决定施加更大或更小的脉冲。

标签: swift sprite-kit game-physics skphysicsbody


【解决方案1】:

这是一个如何根据触摸移动精灵的示例。这种方法使用物理体的velocity属性来移动精灵,因此它会与场景中的其他物理体进行适当的交互,并受到阻尼、摩擦等的影响。

首先,定义比例和阻尼属性。 scale 控制圆圈向触摸位置移动的速率。较大的值将以更快的速度移动圆。 damping 属性用于在触摸结束时减慢精灵的速度。较小的值会以更快的速度减慢精灵。

let scale:CGFloat = 2.0
let damping:CGFloat = 0.98

var point:CGPoint?

在触摸开始时保存位置。精灵会朝这个位置移动。

override func touchesBegan(touches: NSSet, withEvent event: UIEvent) {        
    if let touch = touches.anyObject() as UITouch? {
        let location = touch.locationInNode(self)
        point = location
    }
}

触摸移动时更新位置

override func touchesMoved(touches: NSSet, withEvent event: UIEvent) {
    if let touch = touches.anyObject() as UITouch? {
        let location = touch.locationInNode(self)
        point = location
    }
}

触摸结束时重置触摸位置

override func touchesEnded(touches: NSSet, withEvent event: UIEvent) {
    point = nil
}

将精灵移向指定位置

func moveNodeToPoint(sprite:SKSpriteNode, point:CGPoint) {
    var dx:CGFloat = (point.x - sprite.position.x) * scale
    var dy:CGFloat = (point.y - sprite.position.y) * scale
    sprite.physicsBody?.velocity = CGVectorMake(dx, dy)
}

在渲染每一帧之前调用它。如果触摸处于活动状态,它会调用更新精灵位置的函数,否则它会随着时间的推移减慢精灵的速度

override func update(currentTime: CFTimeInterval) {
    if (point != nil) {
        moveNodeToPoint(firstCircle, point: point!)
    }
    else {
        // This will slow the circle over time when after the touch ends
        let dx = firstCircle.physicsBody!.velocity.dx * damping
        let dy = firstCircle.physicsBody!.velocity.dy * damping
        firstCircle.physicsBody!.velocity = CGVectorMake(dx, dy)
    }
}

【讨论】:

  • 谢谢,真的很有帮助!我刚刚添加了一个代码,该代码仅在我们在 touchesBegan 中触摸它时才授权节点移动!但是我有一些问题:为什么使用 let damping:CGFloat = 0.98 而不是 let damping = 0.98,为什么使用 var point:CGPoint?而不是 var point = CGPoint() ?同样在 moveNodeToPoint(firstCircle, point: point!) 中,为什么要在点的末尾加上感叹号! ?
  • 由于我在update 函数中将damping 乘以CGFloat,因此我需要将其定义为CGFloat 或在表达式中将其转换为1。另外,CGPoint 是一个结构而不是一个类,所以point = CGPoint()? 不会编译。最后,point 是可选的。我只是用point! 解开它。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-08-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-09-05
  • 1970-01-01
相关资源
最近更新 更多