How to apply impulse to the node on touch angle

房东的猫 提交于 2020-01-02 18:06:33

问题


I want the node to move in the right direction but the impulse to be with set strength.

let node: SKSpriteNode!;

node = SKSpriteNode(color: UIColor.greenColor(), size: CGSizeMake(50, 50));
node.physicsBody = SKPhysicsBody(rectangleOfSize: node.size);
node.physicsBody?.affectedByGravity = false;
node.physicsBody?.allowsRotation = false;

override func touchesBegan(touches: Set<NSObject>, withEvent event: UIEvent) {

    node.physicsBody?.velocity = CGVectorMake(0, 0);   

    // ver 1     
    node.physicsBody?.applyImpulse(CGVectorMake((0.4) * (location.x - node.position.x), (0.4) * (location.y - node.position.y)), atPoint: CGPointMake(position.x,position.y));

    // ver 2
    let offset:CGPoint = self.vecSub(location, b: ghost.position);
    let direction: CGPoint = self.vecNormalize(offset);
    var len: CGPoint = self.vecMult(direction, b: 40);
    let impulseVector:CGVector = CGVectorMake(len.x, len.y);
    ghost.physicsBody?.applyImpulse(impulseVector);

}

func vecAdd(a: CGPoint, b:CGPoint) -> CGPoint {
    return CGPointMake(a.x + b.x, a.y + b.y);
}

func vecSub(a: CGPoint, b:CGPoint) -> CGPoint {
    return CGPointMake(a.x - b.x, a.y - b.y);
}

func vecMult(a: CGPoint, b:CGFloat) -> CGPoint {
    return CGPointMake(a.x * b, a.y * b);
}

func vecLenght(a:CGPoint)->CGFloat{
    return CGFloat( sqrtf( CFloat(a.x) * CFloat(a.x) + CFloat(a.y) * CFloat(a.y)));
}

func vecNormalize(a:CGPoint)->CGPoint{
    let len : CGFloat = self.vecLenght(a);
    return CGPointMake(a.x / len, a.y / len);
}
  • version 1 is horrible

  • version 2 is okay, but is too expensive

  • version 3: something not expensive and to apply impulse with 15-100 strength, because if the touch is at the edges of the screen the node should move only 15-100 of its current possition without reaching the touch position


回答1:


Both the methods you've detailed above work so I'm not exactly sure what you're problem is. Also, I'm not sure method two is it's too expensive, are you having frame rate drops using it?

But I've got another way you could do what you're after, it's basically the second version but cleaned up. But firstly I just wanted to point out a couple things with your current code:

1. You don't need to ; to the end of each line.

2. Instead of using vecAdd, vecSub etc you could overload the +, -, * and / operators which would make your code cleaner and clearer. This way, the operators would also be global so you could use them anywhere else you need to manipulate vectors.

Anyway, here's my attempt at it:

Firstly, extend CGVector to add the functionality you need. Things like length, which you were defining as functions, could be properties of CGVector:

extension CGVector {
    init(p1: CGPoint, p2: CGPoint) {
        self.dx = p1.x - p2.x
        self.dy = p1.y - p2.y
    }

    var length: CGFloat {
        get { return hypot(dx, dy) }

        set {
            normalise()
            dx *= newValue
            dy *= newValue
        }
    }

    mutating func normalise() {
        dx /= length
        dy /= length
    }
}

Secondly, using the new methods:

var vec = CGVector(p1: location, p2: ghost.position)
vec.length = 40
ghost.physicsBody!.applyImpulse(vec)

Alternatively, if you wanted the size of the impulse to relate to how far away from the ghost the user pressed, use the following:

vec.length *= 0.1 

Hope that helps!



来源:https://stackoverflow.com/questions/30173634/how-to-apply-impulse-to-the-node-on-touch-angle

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!