3
\$\begingroup\$

I've been trying to get my head around this for hours now, I hope one of you is able to help.

I'm trying to make a small game (2D using sprites) that allows you to place blocks (tiles). That is pretty simple in itself, I use ScreenToWorldPoint and mouse position to place the block (no snapping to grid yet).

Now, what I need to do is ensure that the player places blocks on either side of the block that was just placed, and not just some random place on the screen.

A block is just a 1x1 sprite in this case.

For example. Player placed a single block on the screen:

            can place here
                  |
can place here - [#] - can place here
                  |
            can place here

Player then places another block next to the already placed block:

            can place here
                  |  |
can place here - [#][#] - can place here
                  |  |
            can place here

As you see, there is always room to place 1 block around each block placed (using the word block too much!). This is in 2D space.

So in the end, the player might make this:

                   can place here
                      |  |   |
can place here     - [#] |  [#] - can place here
can place here  - [#][#][#][#][#] - can place here

As you also see here, there is always room for 1 block to be placed around the already placed blocks - obviously not when there's already a block placed next to it.

Hope it makes sense.

I guess what I'm after is just: How would I go about creating a grid around a single game object (2D sprite) - I can then use Ray's to figure out if player has pressed one of the grids around it.

Thanks a lot!

EDIT:

So, I managed to get something working. I made a game object with 4 parents (1x1 sprites: top, right, left, bottom) - clicking on one of these parents, "replaces" (destroys) the object and inserts another tile with 4 parents.

This seems like a really bad implementation, so please suggest alternative ways of doing this.

Screenshot: Grid

Code:

using UnityEngine;
using System.Collections;

public class GameManager : MonoBehaviour {

    public Transform boatObject;
    public GameObject tile;
    public GameObject boatPlank;

    private Vector2 mousePosition;


    void Start ()
    {
        Vector3 position = new Vector3 (boatObject.transform.position.x, boatObject.transform.position.y, 0);
        GameObject gridTile = Instantiate (tile, position, Quaternion.identity) as GameObject;
        gridTile.transform.SetParent (boatObject.transform);
    }

    void Update ()
    {
        // Mouse button 1
        if (Input.GetMouseButton (0))
        {
            Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
            RaycastHit2D hit = Physics2D.Raycast (ray.origin, ray.direction);

            if (hit.collider.gameObject.tag == "GridItem")
            {
                Vector3 position = new Vector3 (hit.collider.transform.position.x, hit.collider.transform.position.y, 0);

                GameObject gridTile = Instantiate (tile, position, Quaternion.identity) as GameObject;
                gridTile.GetComponent<SpriteRenderer> ().sortingOrder = 10;
                gridTile.transform.SetParent (boatObject.transform);

                // Destroy the grid item that was clicked
                Destroy (hit.collider.gameObject);

                Debug.Log ("Hit something: " + hit.collider.gameObject.tag);
            }
        }
    }
}
\$\endgroup\$

1 Answer 1

2
\$\begingroup\$

I don't know if this is the best way but it is how I go about it if I have a board which can have a lot of interactions.

Have a class called BoardManager which will be in control of the board and what happens to it. This script contains a List (or other array type object) which knows where you can place tiles.

// In order to use Lists/Dictionaries need,
Using System.Collections.Generic;

public class BoardManager(){
    public GameObject tileObject;
    public GameObject canPlaceObject;

    // List containing positions where tiles can be made.
    private List<Vector2> possibleTiles;
    // List containing positions where tiles already are.
    private List<Vector2> tiledPositions;

    public void AttemptCreateTileAt(Vector2 point){
        // You will need to round the point to the nearest tile point
        if(possibleTiles.Contains(point){
            // Create the tile at the point
            Instantiate(.....);
            possibleTiles.Remove(point);
            tiledPositions.Add(point);
            CanMakeTilesAround(point);
        }
    }

    public void CanMakeTilesAround(Vector2 point){
        // Now iterate through all the possible positions next to the point
        // If there isn't a tile there add it to the possibles and spawn the
        // appropriate gameobject
        if(!tiledPositions.Contains(new Vector2(point.x +1,point.y)){
            possibleTiles.Add(new Vector2(point.x +1,point.y));
            Instantiate(....)
        }
        ....// Add other positions
    }
}

Note this is kinda pseudo-code and it will need changing by you.

So when you detected a mouse click you tell the BoardManager to try to create a tile there (you could make AttemptCreateTileAt(Vector2 point) a bool so you know if it worked). If it can create a tile there it then makes the positions around that tile possible CanMakeTilesAround(Vector2 point).

I like this approach for certain reasons;

  • it means all the logic is in the code, I don't need to worry about if an object instantiated correctly to determine if a position can have a tile created at,
  • all the information about the board is in one place and protected (can only change it via public functions),
  • you can make changes to the code to allow you to get references to the different tiles or parts of the board, or even add functions which can do useful things i.e. get a reference to neighbouring tiles etc.(i.e. make List<Vector2> tiledPositions into a dictionary Dictionary<Vector2,Tile> tiles).

It does have some drawbacks though,

  • it takes a lot longer to set up and get working to a point where you can test it,
  • it is code intensive and you may not want to spend all your time debugging the board for your game.

Also I am sorry for the length of the answer I got a little carried away.

\$\endgroup\$
2
  • \$\begingroup\$ Thanks Malrig - that should get me further :). Lengthy answers are great, brainstorm! \$\endgroup\$
    – Benny Mose
    Feb 19, 2016 at 18:57
  • \$\begingroup\$ Cheers, hope it goes well. Added some more comments to the code but you probably didn't need them. \$\endgroup\$
    – Malrig
    Feb 19, 2016 at 19:26

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .