Game development summary - how to create a bounded 2D map in Unity

Game development summary - how to create a bounded 2D map in Unity

Create a bounded map of a 2D game in Unity and make it connect the edges. It's a lightweight and simple solution for Clash Royale and other types of games.

When creating a map, we want to keep players within bounds. But it's also nice to have the world actually wrap around itself: this can provide an interesting element to the game mechanics, while also giving the player an impression of increased freedom.
In this article, we'll show you a simple way how to achieve this behavior for 2D games.
Restricting Player Positions in N by M Grid Maps
In most cases, maps for 2D games are defined as fully populated N by M grids. In this case, the obvious solution to constraining the player's position within the bounds is to check its position relative to the defined bounds, and adjust accordingly.
This can be achieved with a simple Monobehaviour component:

class PositionClamper: MonoBehaviour {
    
    
  public int mapWidth;
  public int mapHeight;

  void LateUpdate() {
    
    
    Vector3 pos = transform.position;

    //假设地图从(0,0)开始
    pos.x = Mathf.Max(Mathf.Min(pos.x, mapWidth), 0);
    pos.y = Mathf.Max(Mathf.Min(pos.y, mapHeight), 0);

    // 设置transform position.。尽可能使用本地位置local position 
  }
}

This will ensure that the player's position is clamped within the map dimensions.
One thing to note is that multiple game objects will check these bounds, so you should consider rewriting them to use an external data source such as a Scriptable object or a singleton. This will be more convenient and more error-tolerant than specifying fields directly in each game object.

Implement wrap around coordinates

This is also fairly simple, we just need to check if the transition position is out of bounds, and adjust it accordingly.
We'll also use a boolean to check if we want to wrap around the position.

class PositionClamper: MonoBehaviour {
    
    
  public int mapWidth;
  public int mapHeight;

  public bool isWrapping;

  void LateUpdate() {
    
    
    Vector3 pos = transform.position;


    if (bIsWrapping) {
    
    
      如果我们到达地图的x边界,请将位置回绕到0,使用地图尺寸
      if (pos.x > mapWidth) {
    
    
        pos.x -= mapWidth;
      } else if (pos.x < 0f) {
    
    
        pos.x += mapWidth;
      }
      
      //  我们对y也做同样的事情
      if (pos.y > mapHeight) {
    
    
        pos.y -= mapHeight;
      } else if (pos.y < 0f) {
    
    
        pos.y += mapHeight;
      }

    } else {
    
    
      pos.x = Mathf.Max(Mathf.Min(pos.x, mapWidth), 0);
      pos.y = Mathf.Max(Mathf.Min(pos.y, mapHeight), 0);
    }


    // 设置transform position。尽可能使用本地位置local position
    transform.position = pos;
  }
}

This way, when the player reaches the map border, he will actually be teleported to the other end of the map.
Note that there is actually a cleaner way to write the above code and avoid writing the if: use the modulo operator!

pos.x = pos.x % mapWidth;
pos.y = pos.y % mapHeight;

Draw more sprites to simulate seamless transitions

The main problem with the above approach is that the player will appear to "teleport" when viewed by others.
Again using a simple trick: we just draw more spirte!
Using our current player Gameobject as the center, we need to add other Gameobjects containing the same spirte but at different positions: (-mapWidth, 0), (mapWidth, 0), (0, -mapHeight), (0, mapHeight ).
Although simple, this approach requires you to share the current state of the spirte between children, and you need to apply it to all Gameobjects that have a spirte renderer.
Still, since you're drawing the same spirte multiple times, they will be batched, so the performance hit shouldn't be too big.

Guess you like

Origin blog.csdn.net/qq_37270421/article/details/129806368