I have a player node that is of type Skier that I want to move around the x-axis with a touch and drag similar to this tutorial . I added my player node to the scene and it has a physics body with isDynamic set to true, but for some reason when I touch and drag the player doesn't move. What am I doing wrong? Here is my GameScene and my Skier class:
Skier:
class Skier: SKSpriteNode {
let playerTexture = SKTexture(imageNamed: "snowmanFancy_NE")
let playerSize = CGSize(width: 24, height: 40)
init () {
super.init(texture: playerTexture, color: UIColor.clear, size: playerSize)
self.name = "player"
setPhysics()
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
func setPhysics(){
self.anchorPoint = CGPoint(x: 0.5, y: 0.5)
self.physicsBody? = SKPhysicsBody(rectangleOf: size)
self.physicsBody?.categoryBitMask = PhysicsCategory.player
self.physicsBody?.contactTestBitMask = PhysicsCategory.tree |
PhysicsCategory.rock | PhysicsCategory.cabin | PhysicsCategory.snowman |
PhysicsCategory.marker
self.physicsBody?.collisionBitMask = 0
self.physicsBody?.allowsRotation = false
self.physicsBody?.angularDamping = 0
self.physicsBody?.isDynamic = true
}
}
GameScene:
class GameScene: SKScene, SKPhysicsContactDelegate {
var lastTouch: CGPoint? = nil
var world = SKNode()
var cam = SKCameraNode()
var player = Skier()
let playerDefaultYInset : CGFloat = 350
var sceneVelocity = CGVector(dx: 0, dy: -170)
var zPositionCounter: CGFloat = 0
override func didMove(to view: SKView) {
//Set up the scene
self.anchorPoint = CGPoint(x: 0.5, y: 0.5)
backgroundColor = SKColor.white
//Add top-level world node to the scene
self.addChild(world)
self.physicsWorld.contactDelegate = self
//Add player to scene
spawnPlayer()
}
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
let touch = touches.first
if let location = touch?.location(in: self) {
lastTouch = location
}
}
override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
let touch = touches.first
if let location = touch?.location(in: self) {
lastTouch = location
}
}
override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
lastTouch = nil
}
override func update(_ currentTime: TimeInterval) {
// Only add an impulse if there's a lastTouch stored
if let touch = lastTouch {
let impulseVector = CGVector(dx: touch.x - player.position.x, dy: 0)
// If myShip starts moving too fast or too slow, you can multiply impulseVector by a constant or clamp its range
player.physicsBody?.applyImpulse(impulseVector)
}
}
func spawnPlayer() {
player.position = CGPoint(x: 0, y: (-self.frame.height / 2) + playerDefaultYInset)
player.zPosition = CGFloat(Int.min)
world.addChild(player)
}
}
I figured out what I was doing wrong. When I set up my physics body for the Skier class, I assigned the physics body like this with an optional:
self.physicsBody? = SKPhysicsBody(rectangleOf: size)
so the physics body wasn't actually being assigned to the sprite. I fixed it by changing it to this:
self.physicsBody = SKPhysicsBody(rectangleOf: playerSize)
and now it works perfectly. That being said, for anyone else trying to achieve something similar to this effect with a finger drag moving a sprite around a scene, I ended up coming up with a much simpler solution. I have this in my touchesMoved method:
let touch = touches.first
if let location = touch?.location(in: self) {
let prev = touch?.previousLocation(in: self)
let impulse = CGVector(dx: 0.02 * (location.x - (prev?.x)!), dy: 0)
player.physicsBody?.applyImpulse(impulse)
}
And it works without having to worry about the update, touchesBegan, or touchesEnded methods at all. Much simpler and easier.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.