Swift Spritekit 等距地图触摸位置

6
我开始做一个小的Swift/SpriteKit项目来教自己游戏开发。它以等角地图开始,我已经成功地绘制了它。但是,我在获取地图上不同瓷砖的精确触摸位置时遇到了麻烦。它虽然能运行,但是有一点点偏差,并且似乎不太稳定。

这是我的函数:
class PlayScene: SKScene {

let map = SKNode()
    override func didMoveToView(view: SKView) {

        let origin = view.frame.origin
        let mapOrigin = CGPointMake(origin.x + self.frame.width / 4, origin.y - self.frame.height / 4)


        let mapConfig: Int[][] =

       [[0, 0, 0, 0, 1, 0, 0, 0],
        [0, 0, 0, 0, 1, 0, 0, 0],
        [0, 0, 0, 0, 1, 0, 0, 0],
        [2, 2, 2, 2, 1, 2, 2, 2],
        [0, 0, 0, 0, 1, 0, 0, 0],
        [0, 0, 0, 0, 1, 0, 0, 0],
        [0, 0, 0, 0, 1, 0, 0, 0],
        [0, 0, 0, 0, 1, 0, 0, 0]]

    drawMap(mapConfig, mapOrigin: mapOrigin)
}

使用:

 func drawMap(mapConfig:Int[][], mapOrigin:CGPoint)
{
    let tileHeight:CGFloat = 25.5
    let numColumns:Int = 8
    let numRows:Int = 8

    var position = mapOrigin
    var column: Int = 0
    var row: Int = 0

    for column = 0; column < numColumns; column++
    {
        for row = 0; row < numRows; row++
        {
            position.x = mapOrigin.x + CGFloat(column) * tileHeight
            position.y = mapOrigin.y + CGFloat(row) * tileHeight
            let isoPosition = twoDToIso(position)
            placeTile(isoPosition, mapConfig: mapConfig[row][column])
        }
    }
    self.addChild(map)
}

func placeTile(position:CGPoint, mapConfig:Int)
{
 switch mapConfig
    {
    case 0:
        let sprite = SKSpriteNode(imageNamed:"grassTile")
        sprite.position = position
        sprite.setScale(0.1)
        sprite.name = "\(position)"
        self.map.addChild(sprite)
    case 1:
        let sprite = SKSpriteNode(imageNamed:"roadTile")
        sprite.position = position
        sprite.setScale(0.1)
        sprite.name = "\(position)"
        self.map.addChild(sprite)
    default:
        let sprite = SKSpriteNode(imageNamed:"roadTileLTR")
        sprite.position = position
        sprite.setScale(0.1)
        sprite.name = "\(position)"
        self.map.addChild(sprite)
    }
}

然后我想隐藏我触摸的瓷砖(用于测试):

override func touchesBegan(touches: NSSet, withEvent event: UIEvent)
{
    for touch: AnyObject in touches
    {
        let locationNode = touch.locationInNode(self)
        nodeAtPoint(locationNode).hidden = true
    }
}

但它并不总是隐藏正确的瓷砖。

那么我该怎么解决呢?我的代码基本上有问题(可能)吗?还是我需要以某种方式将位置转换为ISO坐标?或者对瓷砖位掩码进行调整?

无论如何,感谢您的帮助!

1个回答

6
我遇到了一个类似的等角地图问题。
问题在于你点击的节点比显示的要大(它有透明部分)。请参见我的问题,以更好地解释这个问题。
以下是我解决问题的方法(抱歉,代码是Objective-C):
1.创建一个CGPathRef,按照瓦片的边缘进行跟踪(tileSize是纹理的大小)。这段代码适用于常规等角瓦片,而不是六角形瓦片,但思路相同。
// ObjC
-(CGPathRef)createTextureFrame:(CGSize)tileSize
{
    CGMutablePathRef path = CGPathCreateMutable();
    CGPathMoveToPoint(path, NULL, 0, -(self.tileSize.height / 2));
    CGPathAddLineToPoint(path, NULL, (self.tileSize.width / 2), 0);
    CGPathAddLineToPoint(path, NULL, 0, (self.tileSize.height / 2));
    CGPathAddLineToPoint(path, NULL, -(self.tileSize.width / 2), 0);
    CGPathCloseSubpath(path);
    return path;
}

// Swift
func createTextureFrame(tileSize:CGSize) -> CGPathRef {
    CGMutablePathRef path = CGPathCreateMutable()
    CGPathMoveToPoint(path, nil, 0, -(self.tileSize.height / 2))
    CGPathAddLineToPoint(path, nil, (self.tileSize.width / 2), 0)
    CGPathAddLineToPoint(path, nil, 0, (self.tileSize.height / 2))
    CGPathAddLineToPoint(path, nil, -(self.tileSize.width / 2), 0)
    CGPathCloseSubpath(path)
    return path
}

2.创建一个函数,检查给定的点是否在CGPathRef(textureFrame)内。

// ObjC
-(BOOL)isPointOnNode:(CGPoint)point
{
    return CGPathContainsPoint(textureFrame, NULL, point, YES);
}

// Swift
func isPointOnNode(point:CGPoint) -> Bool {
    return CGPathContainsPoint(textureFrame, nil, point, YES)
}

3. 对于每个被触碰到的节点,检查我们当前所处的 textureFrame。

// ObjC
UITouch *touch = [touches anyObject];
NSArray *nodes = [self nodesAtPoint:[touch locationInNode:self]];
for (SKNode *node in nodes)
{
    CGPoint locationInNode = [touch locationInNode:node];
    if ([node isPointOnNode:locationInNode])
    {
        node.hidden = YES;
    }
}

// Swift
var touch = touches.anyObject() as UITouch
var nodes = self.nodesAtPoint(touch.locationInNode(self))
for node in nodes as [SKNode] {
    var locationInNode = touch.locationInNode(node)

    if node.isPointOnNode() {
        node.hidden = true
    }
}

我不知道这是否是最佳解决方案,但它非常有效。 希望能对您有所帮助 :)

编辑:添加了代码的Swift版本


太好了,谢谢。我会尽快尝试,如果我能解决问题,就会发布Swift等价物。 - Gerome Pistre
2
自从我发布了这个问题,我开始学习Swift了。我更新了我的回答;)我是凭记忆写的,现在无法测试,所以可能会有一些错误。 - Heyfara

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接