2014-07-25 9 views
5

Zacząłem robić mały projekt typu "szybka/spritekit", aby nauczyć się gry na urządzenia. Zaczyna się od mapy izometrycznej, którą udało mi się narysować. Mam problem z uzyskaniem precyzyjnego położenia dotykowego na różnych kafelkach mapy. Działa, ale jest nieco nie na miejscu i nie wydaje się być spójny.Lokalizacja dotykowa mapy izometrycznej Swift Spritekit

Oto moje funkcje:

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

Z:

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

a następnie chcę, aby ukryć płytki dotykam (do testowania):

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

Ale to robi nie zawsze ukrywam właściwą płytkę. Jak mam sobie z tym poradzić? Czy mój kod jest całkowicie błędny (możliwy)? Czy muszę w jakiś sposób przekonwertować lokalizację na współrzędne iso? Lub zabawić się z maską bitmask?

Dzięki za pomoc w każdym przypadku!

Odpowiedz

6

Miałem podobny problem z mapą izometryczną.

Problem polega na tym, że wybrany węzeł jest większy niż wyświetlany (ma przezroczyste części). Zobacz my question here, aby uzyskać lepsze wyjaśnienie problemu.

Oto jak rozwiązać go (kod przykro jest w Objective-C):

1.Create CGPathRef po brzegi płytek (tileSize jest wielkość tekstury). Ten kod dotyczy zwykłych płytek izometrycznych, a nie sześciokątnych, ale idea jest taka sama.

// 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.Utwórz funkcję, która sprawdza, czy dany punkt znajduje się wewnątrz 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.For każdy dotknął węzły, sprawdzić, które textureFrame jesteśmy w.

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

Nie wiem, czy jest to najlepsze rozwiązanie, ale działa świetnie. Mam nadzieję, że to pomaga :)

Edit: Dodany Swift wersja kodu

+0

Wielkiej, dzięki. Spróbuję tego wkrótce i jeśli uda mi się to wypracować, opublikuję odpowiednik Swift. –

+2

Odkąd to opublikowałem, zacząłem uczyć się Swift. Uaktualniłem swoją odpowiedź;) Napisałem to z pamięci i nie mogę tego teraz przetestować, więc mogą wystąpić błędy – Heyfara