- Home /
Touch to place coins on a board game dynamically
Hi,
I'm new to Unity and I want a little help with an approach to solve a problem. I'm building a board game in which user clicks on a board (Board is full of 36 numbers in square boxes. 3 columns and 12 rows) and I have to place coins one over the other at the touched number. Now the complex problem is that user can click on the junction between numbers. So if user clicks on the line between 2 numbers, or on a junction point between four numbers, I have to be able to detect it, place coins and send information that the coin was placed on 4 number junction/ 2 number junction etc. Please help me understand with an approach to this problem. The board table is a sprite.
and how are you detecting when it clicks in the numbers? using buttons?
Nope. The board is a sprite. An image basically.
Answer by highpockets · Mar 01, 2019 at 09:05 AM
I think you should setup an array of X, Y positions that represent the center of your square boxes.
Then you have to figure out when to register a click on a number and when to register a click on a line or junction. Let's say your numbers are 1 unit apart (0x,0y is a square, 0,1 is a square, 1,0 is a square, 1,1 is a square, etc.), now you can find the closest square, 2nd closest square, 3rd closest square, 4th closest square to the user click by means of a for loop, looping through the array of x positions and y positions.
Then, if for example the click was at a distance of more than 0.3f away from the center of the closest square in the X or the Y (you'll have to play with this value to find the sweet spot, but let's just say that an offset of 0.3f in the y or 0.3f in the x is considered off the square, giving your square 0.6f in the x and 0.6f in the y directions to register a click), now you know that you are clicking on a line or junction.
Now if the click is more than 0.3f in the y and more than 0.3f in the x, you are at a junction, if it is only more than 0.3f in one direction, you are at a line. To find which line, you just need to know if the direction at which is more than 0.3f is more or less than the, let's say the y direction. If it is more, than the line is above, if less, the line is below.
For finding the junction, it's easy, you already know which 4 squares are closest, so it's the junction between them.
Thanks for the response here. But I want to know if placing the game objects on each of the squares and the junctions and points is better way of doing this? I do not understand how we can get the X,Y positions for every square on a sprite itself. And how much it would differ based on device kind. Please help me understand this in a little detail. Thanks much in advance.
There are a lot of ways to skin a cat. You could make a prefab of every piece of the game, add colliders to each the lines, junctions, and squares and place them in their respective positions. Now, all you have to do is get your click position, do a Raycast from your click position (turn the position to world space first via camera.ScreenToWorldPoint()) out to your board and your Raycast will hit one of the respective pieces. This is more work in the editor, less work with code. This would likely be much more expensive because of the colliders to do such a simple task in my opinion.
You could also just place colliders on the squares, which would be less expensive, but you would still have to test the x and y directions of the hit point relative to the square hit to find your junctions and lines.
In regards to working with the sprite. I don't know what it looks like, but if the squares are all the same size and the edges of the sprite are aligned with the edges of the squares that outline the game board and if it was placed on a quad for example, which I believe is 2 units by 2 units. You should be able to place and scale the quad manually in the editor to ensure that each square is one unit apart.
If you are having trouble doing that, I recommend making a mesh in blender for example and have each vertice represent a corner of a square, put the origin of the mesh in the center of one of the squares so you have a position to reference, UV map the vertices to the respective corners of the texture in blender. Place the .blend file directly in Unity and it will change it to FBX for you or you can export the FBX manually.
Whatever way you choose to do it, to make an array of the positions is quite easy if you have placed the positions correctly in the editor. Lets say you have your bottom left square at position 0,0. Now you can make a for loop with a nested for loop to find your position like so:
int columns = 3;
int rows = 12;
Vector2[] positions = new Vector2[columns, rows];
for (int x = 0; x < columns; x++)
{
for(int y = 0; y < rows; y++)
{
positions[x, y] = new Vector2(x, y);
}
}
Another thing, just thought of this. I don't really use 2D tools much, but I'm quite sure that in the sprite editor, you can manually or automatically split up the sprite into your square pieces and you can then have each square as its own game object. Like I said, many ways to skin a cat, just thought of this because maybe you haven't used blender (or other 3D object creation software). Anyhow, good luck.
Answer by WarmedxMints · Mar 01, 2019 at 12:02 PM
I did something similar for a level editor in a 2d game a while back. I assume as you are using a sprite that the game is 2D.
To use this script, set your pivot point on your sprite to the bottom left and add a boxcollider2d to it. Then either put the script on the same object as the sprite or a different object and drag a reference to the sprite's transform.
The script breaks the sprite up into a grid and places a prefab in the centre point of the nearest square where you click. You should be able to modify this for your needs.
using UnityEngine;
public class DetectGridClick : MonoBehaviour
{
public Transform SpriteTransform;
public GameObject Prefab;
public int NoOfColums = 3;
public int NoOfRows = 12;
private Vector2 _gridSize;
private float _xSpacing;
private float _ySpacing;
private float xGridPos;
private float yGridPos;
private void Start()
{
if (SpriteTransform == null)
SpriteTransform = transform;
var collider = GetComponent<BoxCollider2D>();
_gridSize = collider.size;
_xSpacing = _gridSize.x / NoOfColums;
_ySpacing = _gridSize.y / NoOfRows;
}
private void Update()
{
if (Input.GetMouseButtonDown(0))
{
//Get mouse click position
var cilckPos = Camera.main.ScreenToWorldPoint(Input.mousePosition);
//Check mouse click with bounds
if (CheckWithinBounds(cilckPos))
{
var spawnPos = GetSpawnPos();
Instantiate(Prefab, spawnPos, Quaternion.identity);
}
}
}
public bool CheckWithinBounds(Vector3 worldPosition)
{
var localPosition = GetRelativePos(worldPosition);
var localX = localPosition.x;
var localY = localPosition.y;
if (localX >= _gridSize.x)
return false;
if (localY > _gridSize.y)
return false;
if (localX < 0)
return false;
if (localY < 0)
return false;
xGridPos = GetIndexAlongAxis(localX, _xSpacing, NoOfColums);
yGridPos = GetIndexAlongAxis(localY, _ySpacing, NoOfRows);
return true;
}
private Vector2 GetRelativePos(Vector3 pos)
{
pos.x = Mathf.Abs(SpriteTransform.position.x - pos.x);
pos.y = Mathf.Abs(SpriteTransform.position.y - pos.y);
return pos;
}
private int GetIndexAlongAxis(float position, float spacing, int numberOfIncrements)
{
for (var i = 1; i <= numberOfIncrements; i++)
{
if (position >= spacing * (i - 1) && position < spacing * i)
{
return i;
}
}
return 0;
}
private Vector3 GetSpawnPos()
{
var ret = Vector3.zero;
ret.x = xGridPos * _xSpacing - (_xSpacing / 2);
ret.y = yGridPos * _ySpacing - (_ySpacing / 2);
return ret + SpriteTransform.position;
}
}
Your answer
Follow this Question
Related Questions
Moving character to points along a board - c# 2 Answers
Best way to handle troop positioning on a Risk-like game. 1 Answer
How to make a player move along a fixed route 1 Answer
Creating a 2D Movement Grid 0 Answers
Checker Board Grid 0 Answers