我是iOS编程的新手,几乎没有SpriteKit的经验,所以如果这是一个荒谬的问题,请原谅我。
我一直在尝试使用2D数组制作基本的网格,我更喜欢从左上角0, 0
开始使用它。
研究了UIKit和SpriteKit之间的坐标系差异之后,我遇到了this answer关于Converting Between View and Scene Coordinates的问题,但是它似乎并没有像我想的那样改变y值。我猜我使用不正确,或者我不知道这不是它的本意。
当我尝试这样做时:
let convertedCoordinates = convert(cellCoordinates, to: grid)
print(cellCoordinates.y, convertedCoordinates.y)
它似乎对y值没有任何影响。
我发现当我在行y: -cy
中更改为“ let cellCoordinates = CGPoint(x: cx, y: cy)
”时
然后它确实按照我希望的方式工作,但是我不知道这是否是唯一的解决方案,或者在更复杂的情况下这样做是否可以按预期工作。
这是我正在使用的代码:
import SpriteKit
import GameplayKit
class GameScene: SKScene {
override func didMove(to view: SKView) {
var background: SKShapeNode!
background = SKShapeNode(rectOf: CGSize(width: frame.size.width, height: frame.size.height))
background.fillColor = SKColor.lightGray
self.addChild(background)
let margin = CGFloat(50)
let width = frame.size.width - margin
let height = frame.size.height - margin
let centerX = frame.midX - width / 2
let centerY = frame.midY - height / 2
var grid: SKShapeNode!
grid = SKShapeNode(rectOf: CGSize(width: width, height: height))
grid.strokeColor = SKColor.clear
self.addChild(grid)
let numRows = 2
let numCols = 3
let cellWidth = width / CGFloat(numCols)
for r in 0..<numRows {
for c in 0..<numCols {
let cx = centerX + (cellWidth / 2) + (CGFloat(c) * cellWidth)
let cy = centerY + (cellWidth / 2) + (CGFloat(r) * cellWidth)
//***
let cellCoordinates = CGPoint(x: cx, y: cy)
//***
let cellNode = SKShapeNode(rectOf: CGSize(width: cellWidth, height: cellWidth))
let convertedCoordinates = convert(cellCoordinates, to: grid)
print(cellCoordinates.y, convertedCoordinates.y)
cellNode.strokeColor = SKColor.black
cellNode.lineWidth = 5
cellNode.fillColor = SKColor.darkGray
cellNode.position = convertedCoordinates
let textNode = SKLabelNode(text: String("\(r),\(c)"))
textNode.fontName = "Menlo"
textNode.fontSize = 60
textNode.verticalAlignmentMode = .center
textNode.position = convertedCoordinates
grid.addChild(cellNode)
grid.addChild(textNode)
}
}
}
}
答案 0 :(得分:1)
这比实现的答案更是哲学的答案。至于以某种方式翻转SpriteKit的坐标系,那么您将一直在与之抗争。最好只接受系统本身。
您的问题的实质不过是模型与视图的分离之一。当你说
我希望从左上角开始使用0,0
您的意思是,从心理上讲,您正在将游戏视为单元格的网格,左上角为0,0。那是完全正常和自然的。那就是你的游戏模型。但是您在代码中写什么?
let cx = centerX + (cellWidth / 2) + (CGFloat(c) * cellWidth)
let cy = centerY + (cellWidth / 2) + (CGFloat(r) * cellWidth)
let cellCoordinates = CGPoint(x: cx, y: cy)
let convertedCoordinates = convert(cellCoordinates, to: grid)
这就是您努力摆脱困境的观点。您有一个抽象模型网格,该网格用r,c索引,左上角的0,0,其坐标以单位向下和向右递增。然后是模型的视图,它可能取决于屏幕分辨率,宽高比,设备方向等。如果您将两个精神上分开,通常会发现可以将两个系统之间的转换隔离到一个小的界面中。在那些地方,您可能需要做一些事情,例如缩放轴或翻转其中之一,或者沿一个方向拉伸物体以匹配长宽比。
在这种情况下,如果您从心智模型开始,并在左上角选择了0,0,然后思考游戏的运行方式,那么通常是在单元格方面。好的,这表明2D数组或数组数组是自然的。也许细胞最终将成为您游戏中的一类。它们可能具有存储SpriteKit节点的node属性。您可能会遇到这样的事情:
struct boardPosition {
let row: Int
let col: Int
}
class Cell {
let pos: boardPosition
let node: SKNode
init(pos: boardPosition, in board: Board) {
self.pos = pos
node = SKShapeNode(...)
board.node.addChild(node)
}
}
class Board {
let cells: [[Cell]]
let node: SKNode
init(numRows: Int, numColumns: Int) {
...
}
func movePiece(from: boardPosition, to: boardPosition) {
let piece = cell[from.row][from.col].removePiece()
cell[to.row][to.col].addPiece(piece)
}
}
游戏的操作将取决于您的思维模式。单元格SKNode
节点的y坐标随行索引的增加而减小的事实将被完全掩盖。
答案 1 :(得分:0)
设置所有适用的节点,并将场景的锚点设置为0.1,以将其安装到左上角并设置世界节点的坐标(如果您没有该节点,我建议添加它,这是一个基本的SKNode,您可以用来放置所有游戏节点,从而使您可以将一个单独的节点用于不适用于游戏世界的事物(例如平视显示器和叠加层)。yScale到-1可使y向下而不是向上递增。
编辑:
在处理SKShapeNodes时,除非形状晦涩,否则不必担心图像反转。在为晦涩的形状设计CGPath时,只需将其翻转即可。
shape.path = shape.path!.copy(using:CGAffineTransform(scaleX:1,y:-1))
更大的问题是SKShapeNode没有锚点。相反,您需要移动整个CGPath
为此,请添加以下行:
shape.path = shape.path!.copy(using:CGAffineTransform(translationX:shape.frame.width/2,y:shape.frame.height/2))
如果将来与SKSprite节点打交道... 这将导致资产倒置,因此您所需要做的就是在导入之前翻转资产,使用辅助节点翻转y轴或为所有节点分配yScale -1。在垂直导入之前翻转所有资产是最便宜的方法,我相信您也可以在xcassets内部翻转它,但是当我再次回到MacOS时,我需要进行验证。