2

I need to move a node but instead of SKAction to use velocity Because in this question Moving Node on top of a moving platform

I want the node to move with the platform, but since the platform don't have velocity I can't use Epic Byte suggestion

This is how I move the node

// Move node vertically
let up = SKAction.moveByX(0, y: 200, duration: moveDuration);
let down = SKAction.moveByX(0, y: -200, duration: moveDuration);

node.runAction(SKAction.repeatActionForever(SKAction.sequence([up, down])));

// Move node horizontally
let right = SKAction.moveByX(400, y: 0, duration: moveDuration);
let left = SKAction.moveByX(-400, y: 0, duration: moveDuration);

node.runAction(SKAction.repeatActionForever(SKAction.sequence([right, left])));
Community
  • 1
  • 1
grape1
  • 759
  • 2
  • 8
  • 19

1 Answers1

4

You should edit this one to make it more clear. It looks like you want to use the physics engine to achieve the moving platform effect instead of using SKActions because you need your platforms to be dynamic and interact with the physics engine (like in this example).

So you have two options. The first is to move your node to a point, and keep checking if the node arrived at that point. If it did, then move the node back to its starting point. To move a node to a particular point using real-time motion, you can see my answer here. If your platforms only move in one direction (horizontal or vertical) then you should only apply the velocity in that direction.

Another approach I often use when moving platforms is centripetal motion. This will allow you to move platforms in a circle. What's even cooler is that if you restrict the centripetal motion to one direction (horizontal or vertical) then you can move the platform easily and get a perfect ease-in and ease-out effect. You can see an example of how to simulate real-time centripetal motion in my answer here.

Below is the code for moving the platform horizontally by exploiting this centripetal motion effect I described above. What's nice about this is that it allows you to set the radius as well as the period of the platform's motion. But if you need your platform to travel some arbitrary path of points this won't work, so you will need to resort to using the first option that I mentioned.

class GameScene: SKScene {
    var platform: SKSpriteNode!
    var platformAngularDistance: CGFloat = 0

    override func didMoveToView(view: SKView) {
        physicsWorld.gravity = CGVector(dx: 0, dy: 0)
        platform = SKSpriteNode(color: SKColor.redColor(), size: CGSize(width: 80, height: 20))
        platform.position = CGPoint(x: self.size.width/2.0+50, y: self.size.height/2.0)
        platform.physicsBody = SKPhysicsBody(rectangleOfSize: platform.size)
        self.addChild(platform)
    }
    override func update(currentTime: NSTimeInterval) {
        let dt: CGFloat = 1.0/60.0 //Delta Time
        let period: CGFloat = 3 //Number of seconds it takes to complete 1 orbit.
        let orbitPosition = CGPoint(x: self.size.width/2.0, y: self.size.height/2.0) //Point to orbit.
        let orbitRadius: CGFloat = 50 /*CGPoint(x: 50, y: 50)*/ //Radius of orbit.
        let normal = CGVector(dx:orbitPosition.x + CGFloat(cos(self.platformAngularDistance)) * orbitRadius, dy:0 /*orbitPosition.y + CGFloat(sin(self.node2AngularDistance))*orbitRadius.y*/)
        self.platformAngularDistance += (CGFloat(M_PI)*2.0)/period*dt;
        if (self.platformAngularDistance>CGFloat(M_PI)*2)
        {
            self.platformAngularDistance = 0
        }
        if (self.platformAngularDistance < 0) {
            self.platformAngularDistance = CGFloat(M_PI)*2
        }
        platform.physicsBody!.velocity = CGVector(dx:(normal.dx-platform.position.x)/dt ,dy:0/*(normal.dy-platform.position.y)/dt*/);
    }

}
Community
  • 1
  • 1
Epic Byte
  • 33,840
  • 12
  • 45
  • 93
  • This works amazing! But how to move the hero node with the platform, and also if i use only didBeginContact to know if the hero node is above the platform is it sufficient enough? – grape1 Jul 23 '15 at 18:55
  • I make it stick using SKPhysicsJointFixed.jointWithBodyA but then the hero node can't move or jump – grape1 Jul 23 '15 at 18:57
  • @grape1 mmm I wouldn't do any joints to keep the player on. As you have found out it makes moving the character very hard and more expensive with the joint. Did you see the answer http://stackoverflow.com/a/28057926/2158465? You simply add a property to your hero to keep track of the "extra velocity" it should receive when you are on the platform. And yes you can use didBeginContact for this, just add a flag to your hero to keep track when he is on the platform and not on the platform. Then in the method where you set your hero's velocity, simply add on the extra velocity. – Epic Byte Jul 23 '15 at 19:03
  • Alternatively, you can set the `affectedByGravity` property of the platform's `physicsBody` to false instead of disabling gravity in the simulation. You can then use friction to move the character on top of the platform. If you do that, you should set the `allowsRotation = false` so the platform doesn't spin when the character jumps on it. And you should consider constraining the platform's `y` position with an `SKConstraint`, so it does move vertically when the character jumps on it. – 0x141E Jul 23 '15 at 19:09
  • @0x141E Yup all great points! Regarding the friction though, I found that Sprite Kit does not simulate friction correctly when moving the platform (the hero ends up sliding too much). Which is why I always calculate the relative velocity of the hero when on the platform. – Epic Byte Jul 23 '15 at 19:14
  • horizontally moving platforms are fixed, I use userData to pass to where the node should go and use it in orbitPosition. But Any tips about vertically moving platforms? The node will move with the platform up or down, but when its moving down the hero node falls behind. Maybe use extraVelocity and update the hero by the y axis? – grape1 Jul 23 '15 at 19:18
  • @grape1 So here is how I fix this issue. You see, I treat a node as on the platform if they are within a given rectangle around the platform. They don't have to be physically touching the platform. For example, you can check if the bottom point of the hero (his feet) intersect some small rectangle above the platform, then you can still add the additional velocity to the hero and have it continue to move with the platform. – Epic Byte Jul 23 '15 at 19:21
  • Try that by enumerateChildNodesWithName("allPlatforms") and check if the frame of the node using node.frame.intersect but maybe I didn't implemented correctly – grape1 Jul 23 '15 at 19:25
  • Keep in mind, the frame of the node will probably not be large enough. You will need to expand the frame up a little. What I do a lot when working with frame is draw a node on the screen for debugging and look to see where the frame is visually. Also a side note, Try to avoid using enumerateChildNodesWithName multiple times in the code. If you can consolidate it to one area such as the update method so you have one spot in your game for iterating the nodes. – Epic Byte Jul 23 '15 at 19:29
  • @grape1 Also if you can try to make an array of nodes and iterate the array because it is faster then making sprite kit search the tree for all nodes named "platform." – Epic Byte Jul 23 '15 at 19:30
  • Okay I will try that, just i notice since self.platformAngularDistance is global there can't be more of 1 moving platform, but if maybe if I add the node in array with user data i can get the data and update it. But i'm not sure if updating userData in update loop is good idea – grape1 Jul 23 '15 at 19:48
  • @grape1 Don't use userData, subclass the node instead and name the class Platform or something like that. Then add all of the platform related properties to the platform class. – Epic Byte Jul 23 '15 at 19:50
  • yes, good idea! You are very advanced @EpicByte, awesome skills. Also in your game do you make 2d water ? Like in here https://youtu.be/W25BAba0oqc?t=9m7s It could be made with joints, but try many times and i don't get the effect – grape1 Jul 23 '15 at 19:56
  • In there is no many tutorials for sprite kit. I have many books, dvd's and many of them show stuff that I already know, not cool and interesting stuff – grape1 Jul 23 '15 at 19:57
  • @grape1 This is a totally different question. But while I am here I guess I can answer it. Yes I do have water. I use a combination of shaders (search sprite kit water shader in Google for various approaches) and I simulate water physics using my answer here http://stackoverflow.com/a/25353062/2158465 – Epic Byte Jul 23 '15 at 20:00
  • yes I already implement that, but the water doesn't move like in tiny wings. Also on collision doesn't move – grape1 Jul 23 '15 at 20:05
  • @grape1 Oh something like that could use animation or a series of interconnecting joints with a white image. There are probably other ways to get that effect as well. – Epic Byte Jul 23 '15 at 20:31
  • I will try this weekend to make the water, but I have a question about your answer here http://stackoverflow.com/a/20206522/984734 . I'm using option 2 but when the node hit a wall when moving it sticks, and the gravity effect him very slowly. If I set the dy to 0, or the node dy its doesn't fall, only when I release left or right movement – grape1 Jul 24 '15 at 11:31
  • @EpicByte I would really appreciate it if you could assist me in anyway with this SpriteKit question I asked earlier http://stackoverflow.com/questions/42602058/how-to-interrupt-a-spritekit-sequence-of-actions-and-resume-as-if-there-was-no-i – ItsMeAgain Mar 10 '17 at 22:58