Search code examples
swiftsprite-kitsktilemapnode

Spritekit: How to limit player movement to certain tiles only


Background of the problem: As shown in the screenshot, I have a 24*24 tilemap and a player sprite node. The current problem I am trying to solve is, I hope to restrict the movement of the player just within the letter A shaped red tiles. enter image description here

The solution I have tried: I used intersects method to detect collision between the tilemap and the player sprite node by frames. However, I hope to compare the player sprite node with only the frame of the letter A shaped red tiles instead of the entire tilemap.

func detectMapCollision(){
    if player.frame.intersects(self.mainTileMap.frame){
        print("you are on the map! yay! ")
    }
}

So, how can I separate the letter A shaped red tiles from the entire tilemap, then compare its frames with the player so I can restrict the player movement to the letter area only?


Solution

  • The way to do this would be to define a tile group and corresponding tile definitions for your game's tiles. Doing this allows you to define specific identifiers in the userData info of each of your tile groups so that you can differentiate them in code.

    https://developer.apple.com/documentation/spritekit/sktiledefinition/1645813-userdata

    In your game, for example, you could create a tile group that corresponds to all those red tiles that make up the letter A. You can then set a custom key in the userData dictionary for that tile type to identify it. Then check for the key or the key's value in code whenever the Player wants to move to a new tile. You can directly set a tile's userData dictionary in the Attributes Inspector in the variant's tile definition.

    The code to check would be something like this (assuming you set a Boolean key 'letterA' to true in the userData dictionary:

    let letterTile = myTileMap.tileDefinition(atColumn: column, row: row)
    
    if letterTile.userData?.value(forKey: "letterA") == true {
        // Allow the player to move to this tile as it's one of the letter A tiles.
    }
    

    Edit:

    In response to your query, you do not have to populate your game map/grid in code. To do this I am assuming you have created a game project with a GameScene.sks already prepopulated. In this file you can drop a 'Tile Map Node' from the object library, and that's where you'll use the editor to add your tiles.

    Now the tiles with their User Data will come from a SpriteKit TileSet resource file that should also have been added to your project. As of the current Xcode (v11.3.1) the default tile set comes with prebuilt tiles, but there is nothing that stops you from adding your own custom tiles (red tiles for your letter A route). Then when you have created your tile groups and tile definitions, you can modify their user data dictionary by selecting particular variants and adding keys/values in the inspector window.

    If you are unsure about how to do the process I have outlined in the previous 2 paragraphs, there are various current SpriteKit TileMap tutorials that are freely available online. I believe they may help you further in this regard.

    What must be coded however, is the actual logic to check the UserData info in specific tiles, so that you can restrict player movement as you wish -- an example of which I gave in my original response.