我正在尝试将我的精灵定位在手机的底部中心
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.
【讨论】:
做到了,非常感谢。我从来没有考虑过。以上是关于我正在尝试将我的精灵定位在手机的底部中心的主要内容,如果未能解决你的问题,请参考以下文章