0
\$\begingroup\$

I have a chunk system that I created for my tile-based game, however I am having problems translating the coordinate in tiles of the cursor to the coordinate in chunks. This is my code so far:

using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Tilemaps;

public class MapGeneration : MonoBehaviour
{
    public DimensionScriptable dim;
    public Tilemap ctm;
    public Tilemap nctm;
    public Grid grid;
    public Transform target;
    public int renderDistance = 1;

    private Vector2Int offset;
    private Dictionary<Vector2Int, Chunk> map;

    private void Start()
    {
        nctm.SetTile(Vector3Int.zero, dim.tiles[3]);
        int seed = 1232421;

        map = new Dictionary<Vector2Int, Chunk>();

        System.Random rng = new System.Random(seed);
        offset = new Vector2Int(rng.Next(-100000, 100000), rng.Next(-100000, 100000));
    }

    private void Update()
    {
        Vector2Int centerPoint = (Vector2Int)grid.LocalToCell(target.localPosition);
        centerPoint.x /= dim.chunkSize.x;
        centerPoint.y /= dim.chunkSize.y;

        for (int y = -renderDistance; y <= renderDistance; y++)
        {
            for (int x = -renderDistance; x <= renderDistance; x++)
            {
                Vector2Int pos = new Vector2Int(centerPoint.x + x, centerPoint.y + y);
                Chunk chunk;

                if (!map.TryGetValue(pos, out chunk))
                {
                    Chunk newChunk = new Chunk(pos, dim.chunkSize, dim.tiles, ctm, nctm);
                    newChunk.GenerateTiles(dim.scale, dim.persistance, dim.lacunarity, dim.octaves, offset);
                    newChunk.RenderTiles();

                    map.Add(pos, newChunk);
                }
                else
                {
                    chunk.RenderTiles();
                }
            }
        }

        if (Input.GetMouseButton(0))
        {
            Vector2Int mouseTile = (Vector2Int)grid.WorldToCell(Camera.main.ScreenToWorldPoint(Input.mousePosition));
            Vector2Int mouseChunk = new Vector2Int((mouseTile.x + dim.chunkSize.y / 2) / (dim.chunkSize.x), (mouseTile.y + dim.chunkSize.y / 2) / (dim.chunkSize.y));
            Chunk chunk;
            //Debug.Log("Mouse: " + mouseTile);
            Debug.Log("Chunk: " + mouseChunk);

            if (!map.TryGetValue(mouseChunk, out chunk))
            {
                Debug.Log(mouseTile);
                Debug.LogError("TILE NOT FOUND");
            }
            else
            {
                Vector2Int conversionVec = new Vector2Int(mouseChunk.x / 2 + dim.chunkSize.x / 2, mouseChunk.y / 2 + dim.chunkSize.y / 2);
                Vector2Int convertedCoords = mouseTile + conversionVec;
                //Debug.Log(new Vector2(convertedCoords.x % dim.chunkSize.x, convertedCoords.y % dim.chunkSize.y));
                //Vector2Int tileInChunk = new Vector2Int((mouseTile.x + dim.chunkSize.x / 2) % (dim.chunkSize.x), (mouseTile.y + dim.chunkSize.y / 2) % (dim.chunkSize.y));
                //Debug.Log("Tile: " + tileInChunk);
                //Debug.Log(new Vector2Int(Mathf.Abs((mousePos.x % dim.chunkSize.x) + dim.chunkSize.x / 2), Mathf.Abs((mousePos.y % dim.chunkSize.y) + dim.chunkSize.x / 2)));
                chunk.Modify(new Vector2Int(convertedCoords.x % dim.chunkSize.x, convertedCoords.y % dim.chunkSize.y), Tiles.WATER);
                ctm.SetTile(new Vector3Int(mouseChunk.x * dim.chunkSize.x - dim.chunkSize.x / 2, 0, mouseChunk.y * dim.chunkSize.y - dim.chunkSize.y / 2), dim.tiles[3]);
            }
        }
    }

    public void GenerateMap()
    {
        map = new Dictionary<Vector2Int, Chunk>();
    }
}

And this is my Chunk class (the static class method Noise.GenerateNoiseMap is always returning a constant value and as such is not relevant for this problem)

using UnityEngine;
using UnityEngine.Tilemaps;

public class Chunk
{
    private Vector2Int position;
    public static int width;
    public static int height;

    private int[,] modifiedMap;
    private int[,] map;

    private Tilemap ctm;
    private Tilemap nctm;
    private Tile[] tiles;

    public Chunk(Vector2Int position, Vector2Int size, Tile[] tiles, Tilemap colidableTileMap, Tilemap nonCollidableTilemap)
    {
        this.position = position;
        width = size.x;
        height = size.y;
        map = new int[width, height];
        modifiedMap = new int[width, height];
        ctm = colidableTileMap;
        nctm = nonCollidableTilemap;
        this.tiles = tiles;
    }

    public void GenerateTiles(float scale, float persistance, float lacunarity, int octaves, Vector2Int mapOffset)
    {
        Vector2 offset = new Vector2(position.x * width + mapOffset.x, position.y * height + mapOffset.y);
        float[,] heightMap = Noise.GenerateHeightMap(offset, scale, persistance, lacunarity, octaves);

        for (int y = 0; y < height; y++)
        {
            for (int x = 0; x < width; x++)
            {
                float height = heightMap[x, y];
                Tiles tileId = Tiles.STONE;

                if (height < 0.25)
                {
                    tileId = Tiles.WATER;
                }
                else if (height < 0.75)
                {
                    tileId = Tiles.GRASS;
                }

                map[x, y] = (int)tileId;
            }
        }
        map[0, 0] = (int) Tiles.GRASS;
    }

    public void RenderTiles()
    {
        for (int y = 0; y < height; y++)
        {
            for (int x = 0; x < width; x++)
            {
                if (modifiedMap[x, y] == 0)
                {
                    if (map[x, y] == (int)Tiles.GRASS)
                    {
                        nctm.SetTile(new Vector3Int(position.x * width + x - width / 2, position.y * height + y - height / 2, 0), tiles[map[x, y]]);
                    }
                    else
                    {
                    ctm.SetTile(new Vector3Int(position.x * width + x - width / 2, position.y * height + y - height / 2, 0), tiles[map[x, y]]);
                    }
                }
                else
                {
                    if (modifiedMap[x, y] == (int)Tiles.GRASS)
                    {
                        nctm.SetTile(new Vector3Int(position.x * width + x - width / 2, position.y * height + y - height / 2, 0), tiles[modifiedMap[x, y]]);
                    }
                    else
                    {
                        ctm.SetTile(new Vector3Int(position.x * width + x - width / 2, position.y * height + y - height / 2, 0), tiles[modifiedMap[x, y]]);
                    }
                }
            }
        }
    }

    public void Modify(Vector2Int position, Tiles tile)
    {
        modifiedMap[position.x, position.y] = (int)tile;
        RenderTiles();
    }
}
\$\endgroup\$
0
\$\begingroup\$

Found the answer, the thing was that I wanted the least positive residue, not the signed modulo, so I followed this answer from ShreevatsaR

I always use my own mod function, defined as

int mod(int x, int m) {
    return (x%m + m)%m;
}

Of course, if you're bothered about having two calls to the modulus operation, you could write it as

int mod(int x, int m) {
    int r = x%m;
    return r<0 ? r+m : r;
}

or variants thereof.

The reason it works is that "x%m" is always in the range [-m+1, m-1]. So if at all it is negative, adding m to it will put it in the positive range without changing its value modulo m.

\$\endgroup\$
1
  • \$\begingroup\$ Don't forget to Accept your answer with the green checkmark if it worked for you. \$\endgroup\$ – DMGregory Jun 3 '20 at 18:32

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.