Swift Spritekit等距地图触摸位置 [英] Swift Spritekit isometric map touch location

查看:102
本文介绍了Swift Spritekit等距地图触摸位置的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我已经开始做一个小的swift / spritekit项目来教我自己的游戏开发。
它以等轴测图开始,我设法绘制。
但是我在地图的不同瓷砖上获得精确的触摸位置时遇到了麻烦。
它有效,但有点不合适,似乎不一致。

I've started doing a small swift / spritekit project to teach myself game dev. It starts with an isometric map, which I managed to draw. But I'm having trouble getting a precise touch location on the different tiles of the map. It works, but is slightly out of place, and does not seem consistent.

以下是我的功能:

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)
    }
}

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

And then I want to hide the tile I touch (for testing) :

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

但它并不总是隐藏正确的图块。
那我应该怎么解决这个问题呢?我的代码是否根本错误(可能)?或者我需要以某种方式将位置转换为iso坐标?或者使用瓷砖位掩码?

But it does not always hide the correct tile. So how should I tackle this ? Is my code fundamentally wrong (possible) ? Or do I need to convert the location to iso coordinates in some way ? Or play with the tiles bitmask ?

感谢您在任何情况下的帮助!

Thanks for your help in any case !

推荐答案

我在等轴测图中遇到了类似的问题。

I had a similar issue with isometric map.

问题是你点击的节点大于显示的节点(它有透明的部分)。有关问题的更好解释,请参见此处的问题

The problem is that the node you click on is bigger than displayed (it has transparent parts). See my question here for a better explanation of the issue.

以下是我解决它的方法(抱歉代码在Objective-C中):

Here is how I solved it (sorry code is in Objective-C) :

1.在边缘之后创建一个CGPathRef瓦片的大小(tileSize是纹理的大小)。此代码适用于常规等距切片,而不是六边形,但想法是相同的。

1.Create a CGPathRef following the edges of the tile (tileSize being the size of the texture). This code is for regular isometric tiles, not hexagonal but the idea is the same.

// 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)内。

2.Create a function that checks if a given point is inside the 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。

3.For each touched nodes, check which textureFrame we're in.

// 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
    }
}

我不知道它是否是最好的解决方案但效果很好。
我希望它有所帮助:)

I do not know if it's the best solution but it works great. I hope it helps :)

编辑:添加Swift版本的代码

Edit : Added Swift version of the code

这篇关于Swift Spritekit等距地图触摸位置的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆