Перемещение SKSpriteNode с помощью прикосновения, ускоряется на половине экрана - PullRequest
0 голосов
/ 24 октября 2019

Я работаю над 2-й игрой в стиле платформера. Я очень новичок в разработке IOS и Swift. Я пытаюсь использовать кнопку (другой узел) для перемещения моего персонажа по экрану слева направо. Он работает нормально, пока я не достигну половины, затем резко ускоряется, и отпускание нажатия кнопки не всегда останавливает его. Иногда это требует другого прикосновения. Также фон, кажется, не поспевает за игроком. Как только игрок дойдет до середины экрана, фон должен сместиться, когда игрок продолжит движение.

Я собрал то, что я сделал вместе, из нескольких учебных примеров, но я застрял в этом.

class StoryModeScene: SKScene, SKPhysicsContactDelegate {

var tileMap = JSTileMap(named: "legend1Level1.tmx")
var tileSize:CGSize!
var xPointsToMovePerSecond:CGFloat = 0
var rightMoveButton = SKSpriteNode(imageNamed: "right-move")
var leftMoveButton = SKSpriteNode(imageNamed: "left-move")
var jumpButton = SKSpriteNode(imageNamed: "a-button")
var fireButton = SKSpriteNode(imageNamed: "b-button")
var forwardMarch:Bool = false
var mightAsWellJump:Bool = false
var onGround:Bool = true

//CREATE THE PLAYER ATLAS FOR ANIMATION
let playerAtlas = SKTextureAtlas(named:"legend1")
var playerSprites = Array<Any>()
var player = SKSpriteNode(imageNamed: "legend1")
var repeatActionPlayer = SKAction()

override func didMove(to view: SKView) {
    /* Setup your scene here */
    setupScene()
    addPlayer()

    //PREPARE TO ANIMATE THE PLAYER AND REPEAT THE ANIMATION FOREVER
    let animatedPlayer = SKAction.animate(with: self.playerSprites as! [SKTexture], timePerFrame: 0.1)
    self.repeatActionPlayer = SKAction.repeatForever(animatedPlayer)

    leftMoveButton.position.x = 64
    leftMoveButton.position.y = 64
    leftMoveButton.name = "moveLeft"
    addChild(leftMoveButton)

    rightMoveButton.position.x = 124
    rightMoveButton.position.y = 64
    rightMoveButton.name = "moveRight"
    addChild(rightMoveButton)

    jumpButton.position.x = 771
    jumpButton.position.y = 64
    jumpButton.name = "jumpButton"
    addChild(jumpButton)

    fireButton.position.x = 836
    fireButton.position.y = 64
    fireButton.name = "fireButton"
    addChild(fireButton)

}

override func update(_ currentTime: TimeInterval) {
    if (forwardMarch) {
        //let moveAction = SKAction.moveBy(x: 3, y: 0, duration: 1)
        //let repeatForEver = SKAction.repeatForever(moveAction)
        //let seq = SKAction.sequence([moveAction, repeatForEver])

        //run the action on your ship
        //player.run(seq)
        player.position.x = player.position.x + 3
        setViewpointCenter(player.position)
    }

    if (mightAsWellJump) {
        let jumpForce = CGPoint(x: 0.0, y: 310.0)
        let jumpCutoff: Float = 150.0

        if mightAsWellJump && onGround {
            player.physicsBody!.velocity = CGVector(dx: player.physicsBody!.velocity.dx + jumpForce.x, dy: player.physicsBody!.velocity.dy + jumpForce.y)
            onGround = false
        } else if !mightAsWellJump && player.physicsBody!.velocity.dy > CGFloat(jumpCutoff) {
            player.physicsBody!.velocity = CGVector(dx: player.physicsBody!.velocity.dx, dy: CGFloat(jumpCutoff))
        }


        player.position = CGPoint(x: player.position.x, y: player.position.y + 5);
    }
}

override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
    for touch in (touches) {
        let positionInScene = touch.location(in: self)
        let touchedNode = self.atPoint(positionInScene)
        if let name = touchedNode.name {
            if name == "jumpButton" {
                mightAsWellJump = true
                player.texture = SKTexture(imageNamed: "legend1_jump")
            }
            if name == "moveRight" {
                forwardMarch = true
                self.player.run(repeatActionPlayer)
            }
        }
    }
}

override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
    let touch = touches.first!
    if rightMoveButton.contains(touch.location(in: self)) {
        forwardMarch = false
        player.removeAllActions()
        player.texture = SKTexture(imageNamed: "legend1")
    }
    if jumpButton.contains(touch.location(in: self)) {
        mightAsWellJump = false
        player.removeAllActions()
        player.texture = SKTexture(imageNamed: "legend1")
    }
}

func setViewpointCenter(_ position: CGPoint) {
    var x = max(position.x, size.width / 2)
    var y = max(position.y, size.height / 2)
    x = min(x, (tileMap!.mapSize.width * tileMap!.tileSize.width) - size.width / 2)
    y = min(y, (tileMap!.mapSize.height * tileMap!.tileSize.height) - size.height / 2)
    let actualPosition = CGPoint(x: CGFloat(x), y: CGFloat(y))
    let centerOfView = CGPoint(x: size.width / 2, y: size.height / 2)
    let viewPoint = CGPoint(x: (centerOfView.x - actualPosition.x) * 3, y: centerOfView.y - actualPosition.y)
    tileMap!.position = viewPoint

}


func setupScene() {
    playerSprites.append(playerAtlas.textureNamed("legend1_0"))
    playerSprites.append(playerAtlas.textureNamed("legend1_1"))
    playerSprites.append(playerAtlas.textureNamed("legend1_2"))
    playerSprites.append(playerAtlas.textureNamed("legend1_3"))
    playerSprites.append(playerAtlas.textureNamed("legend1_4"))
    playerSprites.append(playerAtlas.textureNamed("legend1_5"))

    backgroundColor = UIColor(red: 165.0/255.0, green: 216.0/255.0, blue: 255.0/255.0, alpha: 1.0)

    physicsWorld.gravity = CGVector(dx: 0, dy: -9.8)

    anchorPoint = CGPoint(x: 0, y: 0)
    position = CGPoint(x: 0, y: 0)

    let point = tileMap!.calculateAccumulatedFrame()
    print (point)
    tileMap!.position = CGPoint(x: 0, y: 0)
    addChild(tileMap!)

    addFloor()
}

func addFloor() {
    for a in 0..<Int(tileMap!.mapSize.width) {
        for b in 0..<Int(tileMap!.mapSize.height) {
            let layerInfo:TMXLayerInfo = tileMap!.layers.firstObject as! TMXLayerInfo
            let point = CGPoint(x: a, y: b)
            let walls = tileMap!.layerNamed("Walls")
            let wallInfo:TMXLayerInfo = walls!.layerInfo
            let wallGIDs = wallInfo.layer.tileGid(at: wallInfo.layer.point(forCoord: point))

            if wallGIDs > 0 {
                //print (wallGIDs)
                //let node = walls
                let node = wallInfo.layer.tile(atCoord: point)
                node!.physicsBody = SKPhysicsBody(rectangleOf: node!.size)
                node!.physicsBody?.isDynamic = false
            }
        }
    }
}

func addPlayer() {
    tileSize = tileMap?.tileSize
    player.position = CGPoint(x: tileSize.width + player.size.width/2, y: tileSize.height + player.size.height*8)
    let rect = CGRect(origin: CGPoint(x: 0,y :0), size: CGSize(width: 50, height: 95))
    player.physicsBody = SKPhysicsBody(rectangleOf: rect.size)
    player.physicsBody!.velocity = CGVector(dx: 0.0, dy: 0.0)
    player.physicsBody!.isDynamic = true
    player.physicsBody!.restitution = 0
    player.physicsBody!.allowsRotation = false
    player.physicsBody!.friction = 1.0
    addChild(player)
}

}

Удерживание правой кнопки «Перемещение» должно двигаться в одинаковом темпе вправо. Когда игрок добирается до середины экрана, точка обзора фона должна смещаться, пока не достигнет конца фона, после чего игрок может покинуть экран и пройти уровень. Отпускание кнопки должно позволить игроку остановиться.

Ответы [ 2 ]

1 голос
/ 24 октября 2019

Вы можете перемещать сцену по мере движения персонажа, создав SKCameraNode. Затем вы можете выбрать, когда перемещать камеру, чтобы создать правильный эффект. Обязательно установите камеру в качестве камеры вашей игры. Вы можете узнать о камерах здесь . Что касается ускорения, я предполагаю, что это как-то связано с вашей физикой тела. Если вас интересует движение игрока, вы можете посмотреть здесь или здесь . Есть много других отличных видео и сайтов в Интернете, которые вы можете найти, выполнив поиск «Движение игрока SpriteKit».

0 голосов
/ 24 октября 2019

Ответ Эли Фронта указал мне правильное направление. У меня все еще есть некоторые проблемы с этим кодом, но ответом на мой вопрос было использование узла SKCamera, как указал Эли. Я просто хотел опубликовать код, который работает, поэтому, если у кого-то есть подобный вопрос, есть пример кода, касающийся перемещения камеры с плеером. Проблема скорости была по сути оптической иллюзией с слишком быстрым движением фона.

Обратите внимание, что элементы управления являются дочерними элементами камеры. Это значит, что они перемещаются вместе с камерой, в противном случае, когда ваш узел перемещается, элементы управления переместились бы за пределы экрана.

import UIKit
import SpriteKit
import GameKit

class StoryModeScene: SKScene, SKPhysicsContactDelegate {

    var tileMap = JSTileMap(named: "legend1Level1.tmx")
    var tileSize:CGSize!
    var xPointsToMovePerSecond:CGFloat = 0
    var rightMoveButton = SKSpriteNode(imageNamed: "right-move")
    var leftMoveButton = SKSpriteNode(imageNamed: "left-move")
    var jumpButton = SKSpriteNode(imageNamed: "a-button")
    var fireButton = SKSpriteNode(imageNamed: "b-button")
    var forwardMarch:Bool = false
    var mightAsWellJump:Bool = false
    var onGround:Bool = true

    //CREATE THE Player ATLAS FOR ANIMATION
    let playerAtlas = SKTextureAtlas(named:"legend1")
    var playerSprites = Array<Any>()
    var player = SKSpriteNode(imageNamed: "legend1")
    var repeatActionPlayer = SKAction()
    let cam = SKCameraNode()

    var previousUpdateTime: TimeInterval = 0

    override func didMove(to view: SKView) {
        // SETUP CAMERA
        self.camera = cam
        scene?.addChild(cam)
        cam.position.x = 448
        cam.position.y = 212

        setupScene()
        addPlayer()

        //PREPARE TO ANIMATE THE PLAYER AND REPEAT THE ANIMATION FOREVER
        let animatedPlayer = SKAction.animate(with: self.playerSprites as! [SKTexture], timePerFrame: 0.1)
        self.repeatActionPlayer = SKAction.repeatForever(animatedPlayer)

        // SETUP CONTROLS
        leftMoveButton.position.x = -338
        leftMoveButton.position.y = -112
        leftMoveButton.name = "moveLeft"
        leftMoveButton.zPosition = 5
        cam.addChild(leftMoveButton)

        rightMoveButton.position.x = -278
        rightMoveButton.position.y = -112
        rightMoveButton.name = "moveRight"
        cam.addChild(rightMoveButton)

        jumpButton.position.x = 278
        jumpButton.position.y = -112
        jumpButton.name = "jumpButton"
        jumpButton.zPosition = 5
        cam.addChild(jumpButton)

        fireButton.position.x = 338
        fireButton.position.y = -112
        fireButton.name = "fireButton"
        cam.addChild(fireButton)

    }

    override func update(_ currentTime: TimeInterval) {

        if (forwardMarch) {
            if player.position.x > 448 && player.position.x < 1800 {
                cam.position.x = player.position.x
            } else if player.position.x >= 1800 {
                cam.position.x = 1800
            }
            setViewpointCenter(player.position)
            player.position.x = player.position.x + 3
        }

        if (mightAsWellJump) {
            let jumpForce = CGPoint(x: 0.0, y: 310.0)
            let jumpCutoff: Float = 150.0

            if mightAsWellJump && onGround {
                player.physicsBody!.velocity = CGVector(dx: player.physicsBody!.velocity.dx + jumpForce.x, dy: player.physicsBody!.velocity.dy + jumpForce.y)
                onGround = false
            } else if !mightAsWellJump && player.physicsBody!.velocity.dy > CGFloat(jumpCutoff) {
                player.physicsBody!.velocity = CGVector(dx: player.physicsBody!.velocity.dx, dy: CGFloat(jumpCutoff))
            }

            player.position = CGPoint(x: player.position.x, y: player.position.y + 5);
        }
    }

    override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
        for touch in (touches) {
            let positionInScene = touch.location(in: self)
            let touchedNode = self.atPoint(positionInScene)
            if let name = touchedNode.name {
                if name == "jumpButton" {
                    mightAsWellJump = true
                    player.texture = SKTexture(imageNamed: "legend1_jump")
                }
                if name == "moveRight" {
                    player.physicsBody!.velocity.dy = 0.0
                    forwardMarch = true
                    self.player.run(repeatActionPlayer)
                }
            }
        }
    }

    override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
        for touch in (touches) {
            let positionInScene = touch.location(in: self)
            let touchedNode = self.atPoint(positionInScene)
            if let name = touchedNode.name {
                if name == "jumpButton" {
                    mightAsWellJump = false
                    player.removeAllActions()
                    player.texture = SKTexture(imageNamed: "legend1")
                    player.physicsBody!.velocity = CGVector(dx: 0.0, dy: 0.0)
                }
                if name == "moveRight" {
                    player.removeAllActions()
                    player.texture = SKTexture(imageNamed: "legend1")
                    forwardMarch = false
                }
            }
        }
    }

    func setViewpointCenter(_ position: CGPoint) {
        var x = max(position.x, size.width / 2)
        var y = max(position.y, size.height / 2)
        x = min(x, (tileMap!.mapSize.width * tileMap!.tileSize.width) - size.width / 2)
        y = min(y, (tileMap!.mapSize.height * tileMap!.tileSize.height) - size.height / 2)
        let actualPosition = CGPoint(x: CGFloat(x), y: CGFloat(y))
        let centerOfView = CGPoint(x: size.width / 2, y: size.height / 2)
        let viewPoint = CGPoint(x: centerOfView.x - actualPosition.x, y: centerOfView.y - actualPosition.y)
        if (actualPosition.x > 1800) {
            tileMap!.position = tileMap!.position
        } else {
            tileMap!.position = viewPoint
        }
    }

    func setupScene() {
        // ADD PLAYER SPRITES @TODO MAKE THIS DYNAMIC
        playerSprites.append(playerAtlas.textureNamed("legend1_0"))
        playerSprites.append(playerAtlas.textureNamed("legend1_1"))
        playerSprites.append(playerAtlas.textureNamed("legend1_2"))
        playerSprites.append(playerAtlas.textureNamed("legend1_3"))
        playerSprites.append(playerAtlas.textureNamed("legend1_4"))
        playerSprites.append(playerAtlas.textureNamed("legend1_5"))

        backgroundColor = UIColor(red: 165.0/255.0, green: 216.0/255.0, blue: 255.0/255.0, alpha: 1.0)
        anchorPoint = CGPoint(x: 0, y: 0)
        position = CGPoint(x: 0, y: 0)

        // let point = tileMap!.calculateAccumulatedFrame()
        tileMap!.position = CGPoint(x: 0, y: 0)
        addChild(tileMap!)

        addFloor()
    }

    func addFloor() {
        for a in 0..<Int(tileMap!.mapSize.width) {
            for b in 0..<Int(tileMap!.mapSize.height) {
                // let layerInfo:TMXLayerInfo = tileMap!.layers.firstObject as! TMXLayerInfo
                let point = CGPoint(x: a, y: b)
                let walls = tileMap!.layerNamed("Walls")
                let wallInfo:TMXLayerInfo = walls!.layerInfo
                let wallGIDs = wallInfo.layer.tileGid(at: wallInfo.layer.point(forCoord: point))

                if wallGIDs > 0 {
                    let node = wallInfo.layer.tile(atCoord: point)
                    node!.physicsBody = SKPhysicsBody(rectangleOf: node!.size)
                    node!.physicsBody?.isDynamic = false
                }
            }
        }
    }

    func addPlayer() {
        tileSize = tileMap?.tileSize
        player.position = CGPoint(x: tileSize.width + player.size.width/2, y: tileSize.height + player.size.height*8)
        let rect = CGRect(origin: CGPoint(x: 0,y :0), size: CGSize(width: 50, height: 95))
        player.physicsBody = SKPhysicsBody(rectangleOf: rect.size)
        player.physicsBody!.velocity = CGVector(dx: 0.0, dy: 0.0)
        player.physicsBody!.isDynamic = true
        player.physicsBody!.restitution = 0
        player.physicsBody!.allowsRotation = false
        player.physicsBody!.friction = 1.0
        player.physicsBody!.mass = 1.0
        addChild(player)
    }

}

Как я уже упоминал, у меня все еще есть некоторые проблемы, такие как игрок плывет / летает, когда я прыгаю /бежать в то же время. 1-й прыжок - правильная высота, и все последующие прыжки меньше и т. Д., Но я работаю над тем, чтобы выяснить это.

...