Spritekit: How to limit player movement to certain tiles only - swift

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.
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?

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.

Related

Unity - Tilemap Contains - how to read if Tilemap contains a tile on a specific coordinate in world?

I'm a complete noob in gamedev, but I've watched a number of videos on generating a 2D array to setup Grid-based combat (pathing, obstacles etc), and I don't find the programmable approach intuitive or visually friendly.
Is it possible to setup such level with obstacles using multiple tilemaps?
1st tilemap would include the whole level zone (I named it "General Tilemap"):
2nd tilemap would only contain tiles that would be marked as collision when being read (I named it "Collision Tilemap") and player wouldn't be able to move to them:
My logic would be to read the adjacent tiles around the player, and if:
A tile exists on the General tilemap, but not on the Collision tilemap, player can click it and move there.
A tile exists on both tilemaps, it is marked as collision, it cannot be clicked.
A tile doesn't exist, it is out of boundaries, it cannot be clicked.
Could you please let me know if this is a valid approach (for smaller levels at least, I won't be making anything large so scalability is not an issue), or have I gone completely off course and there's a superior way to do this properly?
I'm currently stuck at the very first step - reading whether the tile on a coordinate (next to player) is existing or null for both tilemaps. Doing my best to figure it out though.
Thanks!
Managed to check if tilemap contains a tile on xy coordinates in Start function, by finding the relevant Tilemap and using hasTile to read it it has value or not. This returns a boolean.
Tilemap generalTilemap = GameObject.Find("General Tilemap").GetComponent<Tilemap>();
hasGTile = generalTilemap.HasTile(playerTileCoord);
Still not sure if this approach will work for me long-term, especially when I get to the pathfinding algorithm, but we'll see!

Render order according to hierarchy in Unity

I am trying to understand how Unity decides what to draw first in a 2D game. I could just give everything an order in layer, but I have so many objects that it would be so much easier if it was just drawing in the order of the hierarchy. I could write a script that gives every object its index, but I also want to see it in editor.
So the question is, is there an option that I can check so that it uses the order in the hierarchy window as the default sorting order?
From your last screenshot I could see you are using SpriteRenderer.
The short answer to the question "is there an option that I can check so that it uses the order in the hierarchy window as the default sorting order?" would be no, there isn't by default*.
Sprite renderers calculates which object is in front of others in one of two ways:
By using the distance to the camera, this will draw the objects closest to the camera on top of the rest of the objects in that same order in layer, as per the docs:
Sprite Sort Point
This property is only available when the Sprite Renderer’s Draw Mode is set to Simple.
In a 2D project, the Main Camera is set to Orthographic Projection mode by default. In this mode, Unity renders Sprites in the order of their their distance to the camera, along the direction of the Camera’s view.
If you want to keep everything on the same sorting layer/order in layer you can change the order in which the objects appear by moving one of the two objects further away from the camera (this is probably further down the z axis). For example if your Cashew is on z = 0, and you place the walnut on z = 1 then the cashew will be drawn on top of the walnut. If Cashew is on z=0 and the walnut is on z = -1 then the walnut will be draw on top (Since negative is closer to the camera). If both of the objects are on z - 0 they are both equally as far away from the camera, so it becomes a coin toss for which object gets drawn in front, as it does not take into account the hierarchy.
The second way the order can be changed is by creating different sorting layers, and adjusting the order in layer in the sprite renderer component. But you already figured that out.
*However, that doesn't mean it cannot be done, technically...
If you feel adventurous there is nothing stopping you from making an editor script that automates setting the order in layer for you based on the position in the hierarchy. This script would loop through all the objects in your hierarchy, grab the index of the object in the hierarchy, and assign the index to the Order in Layer.
I don't think Unity has such feature (https://docs.unity3d.com/Manual/2DSorting.html).
Usually you shall define some Sorting Layers:
far background
background
foreground
and assign Sprite Renderer of each sprite to one of Sorting Layers

Unity all objects have same position

I have a 3d building model in my Unity project. It has many children like doors, walls etc. The problem is, all of the children points to same position in the Unity world (24.97, -2.08, 19.35). Their transforms show this position. And this position is far away from their actual one. How can i fix this?
I tried freeing all children from parent but this didn't change anything.
I want them to show their real position, which appears with move tool when we click upon them.
Here is the image link
It seems that this is simply their pivot point exported "wrongly" from the 3D editor your model was made with.
This won't change until you export it correctly from a 3D editor (Blender, Maya, etc).
Unity is not made for 3D mesh modeling and therefore in Unity itself you can't change the pivot points.
There is a very simple fix
Add a new empty GameObject
In the Inspector go to the Transform component, click on the context menu and hit Reset (you also simply set it to position 0,0,0 rotation 0,0,0 and scale 1,1,1) assuming the pivot should be at 0,0,0
Now drag and drop all objects into the empty GameObject
=> You have now one parent object with correct pivot.
By wrapping it in a parent object the childrens pivots don't matter anymore. You can simply do all translation, rotation and scaling on the parent object with the correct pivot and don't have to care about that "wrong" position at all.

Duplicate a gameobject in right way Unity 5

I have a game object named Bolt with for example white texture , when I duplicate that and rename duplicate into EnemyBolt and change texture to orange the Bolt texture is changing into orange too , how can I copy or duplicate a gameObject that dosen't change its reference?
When you duplicate a GameObject, you also duplicate all the components that are attached to it. This way the new object gets its own set of component instances. This is in Hierarchy panel representing the content of the scene.
The Project panel represents the assets to be used in the different scenes. When you drag a material to a Renderer, that renderer instance points to a material that will be instantiated at runtime.
In order to optimise rendering process, if a material is shared among many object, only one material is created, this will reduce draw calls.
Now for your solution, you need to duplicate your material and assign the new one to the new object. Now, when you change it on one side, it does not affect the other since they are using different material. On the other hand, you increased the draw call.

How to select objects in OpenGL on iPhone without using glUnProject or GL_SELECT?

I have 3 OpenGL objects which are shown at the same time. If the user touches any one of them, then that particular OpenGL object alone should display in screen.
Just use gluUnProject to convert your touch point to a point on your near clipping plane and a point on your far clipping plane. Use the ray between those two points in a ray-triangle intersection algorithm. Figure out which triangle was closest, and whatever object that triangle is part of is your object. Another approach is to give each object a unique ID color. Then, whenever the user touches the screen, render using your unique ID colors with no lighting, but don't present the render buffer. Now you can just check the color of the pixel where the user touched and compare it against your list of object color ID's. Quick and easy, and it supports up to 16,581,375 unique objects.
You would have to parse every object of your scene and check the possible collision of each one of them with the ray you computed thanks to gluUnProject.
Depending on whether you want to select a face or an object, you could test the collision of the ray with bounding volumes (e.g. bounding box) of your objects for efficiency purposes.