Hello,
I am trying to code a 2d dungeon crawler and am currently playing around with the movement of the player in a tilemap-based map.
The borders have a collider type of grid, the rest/path has a collider type of none.
My goal is basically to block my character from moving into wall-tiles. It should not be able to move there at all.
The collision works but my player-object moves still a bit into the wall when I try to move into a wall making it stick with that 0.12f(example) when I move back to a path-tile and then I can’t move to another path tile because I have that value from the collider added for the rest of time. Also legit moving ( only moving in path-tiles/white), sometimes it does not work too, prob. bcs of some collider overlay.
Grid layout is 0.4
Tilesizes & playerobject sprite size is 0.36.
Player object has a rigidbody attached and also a block collider with size of 0.36(matching a tile).
In my script I tell my p1 to move 0.4 in the direction I press a button for.
Script attached to my player-object:
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Tilemaps;
public class p1 : MonoBehaviour
{
public GameObject border;
private Tilemap borderTilemap;
private Rigidbody2D rigidBody;
private Vector2 lastPosition;
// Start is called before the first frame update
void Start()
{
rigidBody = gameObject.GetComponent<Rigidbody2D>();
borderTilemap = border.GetComponent<Tilemap>();
}
// Update is called once per frame
void Update()
{
var currentPositionX = rigidBody.position.x;
var currentPositionY = rigidBody.position.y;
lastPosition = new Vector2(currentPositionX, currentPositionY);
if (Input.GetKeyDown("up"))
{
//if (!borderTilemap.HasTile(new Vector3Int (Convert.ToInt32(currentPositionX) , Convert.ToInt32(currentPositionY + 0.4f),0)));
rigidBody.MovePosition(new Vector2(currentPositionX , currentPositionY + 0.4f));
}
if (Input.GetKeyDown("down"))
{
rigidBody.MovePosition(new Vector2(currentPositionX , currentPositionY - 0.4f));
}
if (Input.GetKeyDown("left"))
{
rigidBody.MovePosition(new Vector2(currentPositionX - 0.4f , currentPositionY));
}
if (Input.GetKeyDown("right"))
{
rigidBody.MovePosition(new Vector2(currentPositionX + 0.4f , currentPositionY));
}
}
void OnCollisionEnter( Collision col)
{
rigidBody.position = lastPosition.normalized;
}
}
Any help appreciated.
Thanks in advance.
Heiko
try changing the way player movement works to not be “free + collide with walls”
instead each tile can have a rule “blockWalk true or false”
then when getting player input before you move the player, you check if the tile where the player wants to move can be walked on. if yes then you move the player from the current tile to the next tile. if not then you don’t do nothing. or you can move it a bit and then get it back from where it started
the idea is that you don’t use collisions and free movement.
Thanks for your answer. Sounds good.
How can I implement that since I am not able to give the tiles any attributes other than telling the collider type?
Thanks in advance
Heiko
Generally you don’t want to use physics / physics2D when you’re already in a grid.
Tile-based / grid-based 2D games: match3, tetris, chips challenge, rogue, etc:
For any tile-based game such as Match3 or Tetris or a grid-based Roguelike, do all the logical comparisons in your own data storage mechanism for the tiles, such as a 2D array of tiles.
Otherwise you needlessly bind your game logic into Unity objects and the Unity API, making it about 10x more complicated than it needs to be.
If you have no idea how to work with 2D arrays, hurry to some basic C# tutorials for the language portions of it, then look at any good tutorial that uses a 2D array
Here is my Match3 demo using this technique of storing data in a grid. Full source linked in game comments.
It stores all of its data in a 2D array:
PieceController[,] Board;
This allows for easy simple checking in code, not relying on anything like physics.
You should strive to use that pattern for all logic, then only use Unity to present what is happening in the game logic.
Update.
I now got it to work with the following code.
The code in the start function basically was just to see the coordinates of the existing tiles., because I had a hard time to see/understand the cell/grid-coordinates.
Then I basically configured what @altepTest suggested.
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
using UnityEngine.Tilemaps;
public class p1 : MonoBehaviour
{
public GameObject tilemap;
private Tilemap tm;
private Rigidbody2D rigidBody;
private Vector2 lastPosition;
public List<Vector3> tileWorldLocations;
TileBase[] allTiles;
// Start is called before the first frame update
void Start()
{
rigidBody = gameObject.GetComponent<Rigidbody2D>();
tm = tilemap.GetComponent<Tilemap>();
BoundsInt bounds = tm.cellBounds;
allTiles = tm.GetTilesBlock(bounds);
for (int x = 0; x < bounds.size.x; x++) {
for (int y = 0; y < bounds.size.y; y++) {
TileBase tile = allTiles[x + y * bounds.size.x];
if (tile != null) {
Debug.Log("x:" + x + " y:" + y + " tile:" + tile.name);
} else {
Debug.Log("x:" + x + " y:" + y + " tile: (null)");
}
}
}
}
// Update is called once per frame
void Update()
{
var currentPositionX = rigidBody.position.x;
var currentPositionY = rigidBody.position.y;
if (Input.GetKeyDown("up") )
{
var x = tm.GetTile(tm.WorldToCell(new Vector3(currentPositionX,currentPositionY + 0.4f, 0)));
if (x.name != "border")
{
rigidBody.MovePosition(new Vector2(currentPositionX , currentPositionY + 0.4f));
}
}
if (Input.GetKeyDown("down"))
{
var x = tm.GetTile(tm.WorldToCell(new Vector3(currentPositionX,currentPositionY - 0.4f, 0)));
if (x.name != "border")
{
rigidBody.MovePosition(new Vector2(currentPositionX , currentPositionY - 0.4f));
}
}
if (Input.GetKeyDown("left"))
{
var x = tm.GetTile(tm.WorldToCell(new Vector3(currentPositionX - 0.4f,currentPositionY, 0)));
if (x.name != "border")
{
rigidBody.MovePosition(new Vector2(currentPositionX - 0.4f , currentPositionY));
}
}
if (Input.GetKeyDown("right"))
{
var x = tm.GetTile(tm.WorldToCell(new Vector3(currentPositionX + 0.4f,currentPositionY, 0)));
if (x.name != "border")
{
rigidBody.MovePosition(new Vector2(currentPositionX + 0.4f , currentPositionY));
}
}
}
}
Now of course I am pretty much open for improvement suggestions but please with examples & explanations 
Also @Kurt-Dekker
By saying not using physics you mean getting rid of the rigidbody?
What to use for movement instead? transform in this case?
Thanks in advance
Heiko