Reputation: 1786
I need some help in making the player in my platform game jump. The problem I'm having is that he jumps through a pillar which he's not supposed to do (I do have the physics set up correctly). I suspect it is because of my horribly inefficient code below. I know there's a better way to move him along a path but I'm not sure how to do it.
var xStep = CGFloat(18)
var yStep = CGFloat(30)
var x = CGFloat(playerJump.position.x)
var y = CGFloat(playerJump.position.y)
let follow = SKAction.move(to: CGPoint(x: x, y:y), duration: 0.1)
x += xStep
y += yStep
let follow2 = SKAction.move(to: CGPoint(x: x, y:y), duration: 0.1)
x += xStep
y += yStep
let follow3 = SKAction.move(to: CGPoint(x: x, y:y), duration: 0.1)
x += xStep
y += yStep
let follow4 = SKAction.move(to: CGPoint(x: x, y:y), duration: 0.1)
x += xStep
y += yStep
let follow5 = SKAction.move(to: CGPoint(x: x, y:y), duration: 0.1)
x += xStep
y -= yStep
let follow6 = SKAction.move(to: CGPoint(x: x, y:y), duration: 0.1)
x += xStep
y -= yStep
let follow7 = SKAction.move(to: CGPoint(x: x, y:y), duration: 0.1)
x += xStep
y -= yStep
let follow8 = SKAction.move(to: CGPoint(x: x, y:y), duration: 0.1)
x += xStep
y -= yStep
let follow9 = SKAction.move(to: CGPoint(x: x, y:y), duration: 0.1)
let group = SKAction.group([
SKAction.repeat(jumpAnimation!, count: 1),
SKAction.sequence([follow,follow2,follow3,follow4,follow5,follow6,follow7,follow8,follow9])
])
if playerJump.parent == nil {
addChild(playerJump)
}
playerJump.run(SKAction.sequence([group]), completion: {
self.player.position=self.playerJump.position
self.playerJump.removeAllActions()
self.playerJump.removeFromParent()
self.addChild(self.player)
})
Thanks in advance for any assistance.
UPDATE The problem started when I increased the value in xStep. The total distance the character jumps would put it past the pillar. That's why I thought my code was an issue. Here's a video of what's happening. Jumping Video
UPDATE 2 Here's my newest code which still puts the player on the other side of the pillar.
@objc func jumpTapped() {
var xStep = CGFloat(18)
let yStep = CGFloat(12)
jumping=true
xStep = player.xScale * xStep
var x = player.position.x
var y = player.position.y
var moveAnimation = [SKAction]()
for i in 0...8 {
x += xStep
if i < 5 {
y += yStep
} else {
y -= yStep
}
let move = SKAction.move(to: CGPoint(x: x, y: y), duration: 0.1)
moveAnimation.append(move)
}
let group = SKAction.group([jumpAnimation!, SKAction.sequence(moveAnimation)])
player.physicsBody?.affectedByGravity = false
player.removeAllActions()
player.run(group) {
self.endJump()
}
}
func endJump() {
player.removeAllActions()
player.physicsBody?.affectedByGravity = true
player.run(SKAction.repeatForever(self.playerAnimation!))
jumping=false
}
Upvotes: 0
Views: 220
Reputation: 1786
I figured out what I was doing wrong. My mistake was moving the sprite within the SKAction. I should have been moving the sprite in the update method. So, I added this to update():
if jumping {
if jumpCount > 3 {
player.position.x += xStep // Jump straight up for a couple of frames to clear steps
}
if jumpCount < maxJump/2 {
player.position.y += yStep //Move sprite up for first half of jump
} else {
player.position.y -= yStep //Move sprite down for last half of jump
}
jumpCount += 1
if jumpCount >= maxJump {
endJump()
}
}
All the collision detection works properly and the player doesn't jump through pillars.
Upvotes: 0
Reputation: 6061
It looks like you are setting player.position to self.playerJump.position
That is probably your problem, it is jumping beyond where the pillar is. You might as well have said player.position.x = player.position.x + 500 which will put you on the other side of the pillar as well ignoring any physics all together.
Why are you adding a sprite and running the actions on it? why not just run the animation and the actions on the player sprite?
As far as cleaning up your code goes you can try this. there are other things you can do as well like have the character jump along a Bezier path but this might be fine for what you are doing. But I highly doubt this will have any impact on your issue of the player jumping through the pillar.
Some small tidbits for you.
Sprite positions are already a CGFloat no need to cast them
short hand completion code syntax is object.run(someAction) { //do something when complete }
running an action with repeat of 1 is pointless
running a sequence of a single action (SKAction.sequence([group])
) is also pointless
var xStep = CGFloat(18)
var yStep = CGFloat(30)
var x = playerJump.position.x
var y = playerJump.position.y
var moveAnimation: [SKAction]!
for _ in 0...9 {
x += xStep
y += yStep
moveAnimation.append(SKAction.move(to: CGPoint(x: x, y: y), duration: 0.1))
}
let group = SKAction.group([jumpAnimation, SKAction.sequence(moveAnimation)])
guard playerJump.parent else { addChild(playerJump)}
playerJump.run(group) {
self.player.position = self.playerJump.position
self.playerJump.removeAllActions()
self.playerJump.removeFromParent()
self.addChild(self.player)
}
Edit try adding the below function to your code
func didBegin(_ contact: SKPhysicsContact) {
let contactAName = contact.bodyA.node?.name
let contactBName = contact.bodyB.node?.name
if (contactAName == "pillar") || (contactBName == "pillar") {
//assuming only player can hit pillar so don't need to check if one of the contacts is player
endJump()
}
}
Upvotes: 1