我正在尝试将我的精灵定位在手机的底部中心

Posted

技术标签:

【中文标题】我正在尝试将我的精灵定位在手机的底部中心【英文标题】:I'm trying to position my sprite at the bottom center of the phone 【发布时间】:2018-11-13 02:31:36 【问题描述】:

这是我从 didMoveToScene 调用来添加播放器的函数,我的场景锚定在 0.5、0.5。 tileMapNode 位于 0, -800 以使其在场景中居中,并且它也锚定在 0.5, 0.5。无论我将播放器放在哪里,它仍然是手机的死角。我做错了什么。

func addPlayer() 
    player = Player(imageNamed: GameConstants.StringConstants.playerImageName)
    player.name = String(GameConstants.StringConstants.playerName)

    player.anchorPoint = CGPoint(x: 0.5, y: 0.5)
    player.position = CGPoint(x: (scene?.frame.midX)!, y: (scene?.frame.minY)!)

    player.xScale = 1
    player.yScale = 1
    player.zPosition = GameConstants.ZPositions.playerZ
    player.lightingBitMask = 1

    PhysicsHelper.addPhysicsBody(to: player, with: GameConstants.StringConstants.playerName)

    addAttackArea()
    scene?.addChild(player)

    lightsCameraAction()

    player.playerState = .idle

这是完整的 GameScene 文件。我怎么知道场景何时加载?我是一个老派程序员。大约 24 年没有写过任何代码 :)。事情发生了一些变化。

import SpriteKit

//MARK:--------------------------Global Variables
enum GameState 
case playing, paused, finished


// MARK: ----------------------------------GameScene
class GameScene: SKScene, SKPhysicsContactDelegate 

   // MARK: -----------------------------------Movement Variables
    let movePointsPerSecond: CGFloat = 250.0
    var velocity = CGVector(dx: 0.0, dy: 0.0)
    var lastUpdateTime: CFTimeInterval = 0

    // MARK: ----------------------------------Gesture Recognizer
    let singleTapRec = UITapGestureRecognizer()

    let lightNode: SKLightNode = SKLightNode()
    let cameraNode: SKCameraNode = SKCameraNode()
    let gameScene: SKScene = SKScene()

    var gameState = GameState.playing 
        willSet 
            switch newValue 
            case .playing:
                player.playerState = .idle
            case .finished:
                player.playerState = .idle
            case .paused:
                scene?.isPaused = true
            
        
    

    // MARK: ---------------------------------didMove to view
    override func didMove(to view: SKView) 
        physicsWorld.contactDelegate = self

        switch gameState 
            case .playing:
                setupGestures()
                addPlayer()
                addEnemy()
                addEnemy()
                addEnemy()
                addEnemy()
                addEnemy()
                addEnemy()
            case .paused:
                scene?.isPaused = true
            default:
                break
        
    

    // MARK: ---------------------Touches Section
    override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) 
       // var touchedLocation = CGPoint()
        switch gameState 
            case .playing:
                //if let touch = touches.first 
                    //let touchLocation = touch.location(in: self)
                   // touchedLocation = touchLocation
                    player.playerState = .idle
                   // moveAndRotate(spriteNode: player, toPosition: touchedLocation)
               // 
            case .paused:
                scene?.isPaused = true
            default:
                break
            
    

    override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) 
        var touchedLocation = CGPoint()
        switch gameState 
            case .playing:
                if let touch = touches.first 
                    let touchLocation = touch.location(in: self)
                    touchedLocation = touchLocation
                    player.playerState = .walking
                    moveAndRotate(spriteNode: player, toPosition: touchedLocation)
                
            case .paused:
                scene?.isPaused = true
            default:
                break
        
   

    override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) 
        removeAllActions()
        switch gameState 
            case .playing:
                player.playerState = .idle
                player.removeAction(forKey: "RotateAction")
            case .paused:
                scene?.isPaused = true
            default:
                break
            
    

    // MARK:------------------------------------Physics contact
    func didBegin(_ contact: SKPhysicsContact) 
        var enemyIndex = 0
        let contactMask = contact.bodyA.categoryBitMask | contact.bodyB.categoryBitMask

        if contact.bodyA.node?.name !=  "Player" && contact.bodyA.node?.name != "AttackArea" 
            let node = contact.bodyA.node

            enemyIndex = findEnemy(contactName: (node?.name)!)

         else 
            let node = contact.bodyB.node

            enemyIndex = findEnemy(contactName: (node?.name)!)

        
        enemyID = enemyIndex

        switch contactMask 
            case GameConstants.PhysicsCategory.attackAreaCategory | GameConstants.PhysicsCategory.enemyCategory:
                handleEnemyContact(entity: enemyIndex)
            case GameConstants.PhysicsCategory.playerCategory | GameConstants.PhysicsCategory.enemyCategory:
                handleEnemyContact(entity: enemyIndex)
            default:
                break
        
    

    func didEnd(_ contact: SKPhysicsContact) 

    

    // MARK: ---------------------Update Section
    override func update(_ currentTime: CFTimeInterval) 
        let deltaTime = max(1.0 / 30, currentTime - lastUpdateTime)
        lastUpdateTime = currentTime
        update(dt: deltaTime)
    

    func update(dt: CFTimeInterval) 
        if player.playerState == .walking 
            let newX = player.position.x + velocity.dx * CGFloat(dt)
            let newY = player.position.y + velocity.dy * CGFloat(dt)
            player.position = CGPoint(x: newX, y: newY)
            cameraNode.position = player.position
            lightNode.position =  player.position
            newAttack.position = player.position
        
    

忘记添加游戏场景扩展。

    import SpriteKit

// MARK: ----------------------------------Enumerations
enum Animation: String 
    case Walking, Idle, Attacking, Waiting


enum RewardType: String 
    case LevelUp, MagicItem, DefeatEnemy, DefeatBoss, CompleteQuest


enum Dice: Int 
    case d20, d10, d8, d6, d4


// MARK: ----------------------------------GLobal Variables
var player: Player!
var enemy: Enemy!

let textureName: String = GameConstants.StringConstants.playerImageName
let playerTexture: SKTexture = SKTexture(imageNamed: GameConstants.StringConstants.playerImageName)
var playerPosition: CGPoint = CGPoint(x: 0, y: 0)
let attackAreaTexture: SKTexture = SKTexture(imageNamed: "AttackCircle")
var requiredXPForNextLevel = 0

let enemyTexture: SKTexture = SKTexture(imageNamed: GameConstants.StringConstants.enemyImageName)

var playerIsAttacking: Bool = false
var enemyIsAttacking: Bool = false

var playerIsDead: Bool = false
var enemyIsDead: Bool = false

var enemies: [Enemy] = []
var enemyID: Int = 0

var newAttack: SKSpriteNode!

extension GameScene 

    //MARK:--------------------------------------------Add Player
    func addPlayer() 
        player = Player(imageNamed: GameConstants.StringConstants.playerImageName)
        player.name = String(GameConstants.StringConstants.playerName)

        player.anchorPoint = CGPoint(x: 0.5, y: 0.5)
        player.position = CGPoint(x: 0, y: 0)

        player.xScale = 1
        player.yScale = 1
        player.zPosition = GameConstants.ZPositions.playerZ
        player.lightingBitMask = 1

        PhysicsHelper.addPhysicsBody(to: player, with: GameConstants.StringConstants.playerName)

        addAttackArea()
        scene!.addChild(player)

        lightsCameraAction()

        player.playerState = .idle
    

    //MARK:------------------------------------Lights and Camera
    func lightsCameraAction() 
        let lightNode: SKLightNode = setupLighting()
        addChild(lightNode)

        let cameraNode: SKCameraNode = setupCamera()
        addChild(cameraNode)
    

    //MARK:-------------------------------------------Add Enemy
    func addEnemy() 
        let enemyIndex = enemyID
        enemy = Enemy(imageNamed: GameConstants.StringConstants.enemyImageName )
        enemies.append(enemy)

        let randomX = Int.random(in: -100 ..< 1500)
        let randomY = Int.random(in: -100 ..< 1500)

        let currentEnemy = enemies[enemyIndex]

        currentEnemy.name = "Enemy\(enemyIndex + 1)"
        currentEnemy.stats.id = enemyID
        currentEnemy.position = CGPoint(x: randomX, y: randomY)
        currentEnemy.xScale = 1
        currentEnemy.yScale = 1
        currentEnemy.zPosition = GameConstants.ZPositions.enemyZ
        currentEnemy.lightingBitMask = 1

        PhysicsHelper.addPhysicsBody(to: currentEnemy, with: GameConstants.StringConstants.enemyName)

        addChild(currentEnemy)
        enemyID += 1
    

    //MARK:-------------------------------Attack
    func addAttackArea() 
        newAttack = SKSpriteNode(texture: attackAreaTexture, color: UIColor.clear, size: player.size)
        newAttack.name = GameConstants.StringConstants.attackAreaName
        newAttack.position = player.position
        newAttack.size.width = player.size.width + 75
        newAttack.size.height = player.size.height + 75
        newAttack.zPosition = player.zPosition - 1
        PhysicsHelper.addPhysicsBody(to: newAttack, with: GameConstants.StringConstants.attackAreaName)

        addChild(newAttack)
    

    func attack() 
        player.playerState = .attacking
        playerIsAttacking = true
        if enemyIsDead 
            playerIsAttacking = false
        
    

    //MARK:----------------------------Gestures
    func setupGestures() 
        singleTapRec.addTarget(self, action: #selector(singleTap))
        singleTapRec.numberOfTouchesRequired = 1
        singleTapRec.numberOfTapsRequired = 1
        view!.addGestureRecognizer(singleTapRec)
    

    @objc func singleTap() 
        attack()
    

    func cleanUp() 
        for gesture in (view?.gestureRecognizers)! 
            view?.removeGestureRecognizer(gesture)
        
    

    //MARK:-------------------------Lighting and Camera
    func setupLighting() -> SKLightNode 
        lightNode.lightColor = UIColor.white
        lightNode.ambientColor = UIColor.black
        lightNode.shadowColor = UIColor.black
        lightNode.falloff = 1.5
        lightNode.zPosition = GameConstants.ZPositions.objectZ
        lightNode.alpha = 1
        lightNode.position = player.position

        return lightNode
    

    func setupCamera() -> SKCameraNode 
        camera = cameraNode
        cameraNode.position =  player.position

        return cameraNode
    

    //MARK:-----------------------------Handle Enemy Contact
    func handleEnemyContact(entity: Int) 
        //var currentEnemy = enemies[entity]

        if enemies.count != 0 
            if enemies[entity].stats.hp <= 0 
                enemyIsDead = true
                //handlePlayerReward(level: enemyLevel)
                enemies[entity].removeFromParent()
                enemies.remove(at: entity)
             else 
                print("\nAttacking: \(enemies[entity].name as Any)")
                print("enemyHP: \(enemies[entity].stats.hp)")
                enemies[entity].stats.hp -= 1
            
        
    

    //MARK:-------------------------------------Find Enemy
    func findEnemy(contactName: String) -> Int 
        var enemiesIndex = 0
        var enemyIndex = 0
        for _ in enemies 
            let entityName = enemies[enemiesIndex].name
            if entityName == contactName 
                enemyIndex = enemiesIndex
                enemies[enemyIndex].stats.id = enemyIndex
             else 
            enemiesIndex += 1
            
        
        return enemyIndex

    

    //MARK:-------------------------------------Player Reward
    func handlePlayerReward(level: Int) 
        /*
        let playerXP = userData?.value(forKey: "PlayerXP") as? Int
        let newPlayerXP = (level * 10) + playerXP!

        if newPlayerXP > requiredXPForNextLevel 
            levelUp()
        
        userData?["PlayerXP"] = newPlayerXP as Any
        */
    

    //MARK:-----------------------------------------Level Up
    func levelUp() 
        /*
        var enemyLevel = userData?.value(forKey: "\(enemyID)Level") as! Int

        let playerXP = userData?.value(forKey: "PlayerXP") as! Int
        let newPlayerXP = (enemyLevel  * 10) + playerXP

        enemyLevel += 1

        userData?["PlayerXP"] = newPlayerXP
        userData?["\(enemyID)Level"] = enemyLevel

        requiredXPForNextLevel  = requiredXPForNextLevel * 2
        */
    

//MARK-----------------------------------Roll Dice
    func rollDice(die: Dice) -> Int 
        switch die 
            case .d20:
                let d20 = Int(arc4random_uniform(20)) + 1
                return d20
           case .d10:
                let d10 = Int(arc4random_uniform(10)) + 1
                return d10
            case .d8:
                let d8 = Int(arc4random_uniform(8)) + 1
                return d8
            case .d6:
                let d6 = Int(arc4random_uniform(6)) + 1
                return d6
            case .d4:
                let d4 = Int(arc4random_uniform(4)) + 1
                return d4
            
    


    //MARK:-------------------------------Move and Rotate
    func moveAndRotate(spriteNode: SKSpriteNode, toPosition position: CGPoint) 

        let angle = atan2(position.y -  spriteNode.position.y, position.x - spriteNode.position.x)
        let rotateAction = SKAction.rotate(toAngle: angle + CGFloat.pi / 2, duration: 0, shortestUnitArc: true)

        if let _ = spriteNode.action(forKey: "RotateAction") 
            spriteNode.removeAction(forKey: "RotateAction")
            spriteNode.run(rotateAction, withKey: "RotateAction")
         else 
            spriteNode.run(rotateAction, withKey: "RotateAction")
        

        let offsetX = position.x - spriteNode.position.x
        let offsetY = position.y - spriteNode.position.y
        let normal = simd_normalize(simd_double2(x: Double(offsetX), y: Double(offsetY)))

        velocity = CGVector(dx: CGFloat(normal.x) * movePointsPerSecond, dy: CGFloat(normal.y) * movePointsPerSecond)
    

    /*
    func whoIsThis(entity: String) 

        if entity != player.name! 
            print("Entity:  \(entity)")
            print("EnemyID:  \(enemyID)")
            print("EnemyHP:  \(String(describing: userData?.value(forKey: "HP")))")
            print("EnemyName:  \(String(describing: enemy.name))")
         else 
            print("Entity:  \(entity)")
            print("PlayerHP:  \(String(describing: userData?.value(forKey: "HP")))")
            print("PlayerName:  \(String(describing: player.name))")
        
    
    */

【问题讨论】:

我要说的是 scene?.frame.midX 是 0,因为此时你的场景大小是 0 场景大小设置为 1080, 1960 ? 是的,但在您创建播放器时,可能尚未设置 我已经添加了整个 GameScene 文件,不知道如何知道场景何时加载。 这段代码没有意义 【参考方案1】:

如果我正确地遵循了您的代码,则问题可能是您在更新循环中将相机置于播放器的中心。

如果您希望他位于屏幕底部,则需要偏移此位置,而不是将其直接设置在玩家的位置上,否则无论您将他移动到哪里,他都将始终位于中心。

//cameraNode.position = player.position
let yOffset = player.position.y+scene.height/2-player.size.height/2 
cameraNode.position = CGPoint(player.position.x, yOffset) //might get you want you want.

【讨论】:

做到了,非常感谢。我从来没有考虑过。

以上是关于我正在尝试将我的精灵定位在手机的底部中心的主要内容,如果未能解决你的问题,请参考以下文章

如何旋转精灵和移动

如何在swift中找到离场景底部最近的精灵节点

基于中心点旋转和缩放几个精灵的位置?

在 Andengine 中摇摆精灵

在带有文本的按钮内有一个精灵图像

统一绘制文本的精灵