I'm trying to write an algorithm that will split an arbitrary quad into smaller quads that all have the same x, y, and z scales (so, cubes). Right now I have code that splits quads into scaled down versions of themselves, but I'd like the ratio to be 1:1:1. How would I modify the code below to do that?
for (int x=0; x < 2; x++) {
for (int y=0; y < 2; y++) {
for (int z=0; z < 2; z++) {
GameObject newCube = Instantiate(gameObject);
newCube.transform.localScale = new Vector3(
newCube.transform.localScale.x/2,
newCube.transform.localScale.y/2,
newCube.transform.localScale.z/2
);
newCube.transform.position = new Vector3(
newCube.transform.position.x + ((x-0.5f) * newCube.transform.localScale.x),
newCube.transform.position.y + ((y-0.5f) * newCube.transform.localScale.y),
newCube.transform.position.z + ((z-0.5f) * newCube.transform.localScale.z)
);
}
}
Destroy(gameObject);
If I understood you correctly, you want to make squares from a rectangle (actually the 3D equivalent of those, but whatever).
So your inner squares must have a side, at most, half of the SMALLER side of the rectangle. And, since they are squares, all the sides must have the same size. So, you must find which is the smaller side of x, y and z, and create your cubes with all sides set to half of that value.
Putting that into your code:
for (int x=0; x < 2; x++) {
for (int y=0; y < 2; y++) {
for (int z=0; z < 2; z++) {
GameObject newCube = Instantiate(gameObject);
var cubeSize = Math.Min(oldQuad.x, Math.Min(oldQuad.y, oldQuad.z)) / 2;
newCube.transform.localScale = new Vector3(
cubeSize,
cubeSize,
cubeSize
);
newCube.transform.position = new Vector3(
newCube.transform.position.x + ((x-0.5f) * newCube.transform.localScale.x),
newCube.transform.position.y + ((y-0.5f) * newCube.transform.localScale.y),
newCube.transform.position.z + ((z-0.5f) * newCube.transform.localScale.z)
);
}
}
Destroy(gameObject);
Since you told nothing about how you want to position them, I keep that part the same.
Related
I am trying to generate a grid across my map and add nodes depending on the perlin noise value. Depending on the value obtained from the perlin noise at a location, I will add a new Node which will be of a certain type e.g. Mountain, Water etc to represent terrian. Here I am trying to make it so that if the value is > 0.5, this mean it's only mountains and so a black coloured cubes should surround the mountain areas, However, my black cubes do not match the mountain areas from the perlin noise and I cannot seem to figure out why I am going wrong. Would appreciate any insight into how I could go about achieving this.
private void LocateWalkableCells()
{
for(int z = 0; z < Height; z++)
{
for(int x = 0; x < Width; x++)
{
noise = GetNoiseValue(x, z);
if(noise > 0.5) {
grid[x,z] = new Node(new Vector3(x, 0, z), TerrainType.Mountain, 1);
}
else {
grid[x,z] = new Node(new Vector3(x, 0, z), TerrainType.Grass, 1);
}
}
}
}
private float GetNoiseValue(int x, int z)
{
int pos = (x * Width) + z;
return Mathf.Round(terrainGenerator.noiseArray[pos] * 10) / 10;
}
// Draw gizmos to visualize colour
void OnDrawGizmos()
{
Gizmos.DrawWireCube(transform.position, new Vector3(Width, 1, Height));
if(grid != null)
{
foreach(Node n in grid)
{
if(n.TerrainType == TerrainType.Grass)
{
Gizmos.color = Color.green;
}
else if(n.TerrainType == TerrainType.Mountain)
{
Gizmos.color = Color.black;
}
Gizmos.DrawCube(n.Position, Vector3.one * (nodeDiameter - .1f));
}
}
}
noiseArray is used for the vertices of the terrain in the following code:
vertices = new Vector3[(Width + 1) * (Depth + 1)];
noiseArray = PerlinNoise();
int i = 0;
for(int z = 0; z <= Depth; z++)
{
for(int x = 0; x <= Width; x++)
{
var currentHeight = noiseArray[i];
if(currentHeight > HeightThreshold)
{
currentHeight *= HeightMultiplier;
}
vertices[i] = new Vector3(x, currentHeight, z);
i++;
}
}
Output
Result from suggested answer
Still seems to miss some mountain areas, colouring green instead of black.
It think the issue is in
var pos = (x * Width) + z;
since x is you index on the width of the grid you would probably rather want
var pos = z * Width + x;
in other words you want to
skip z rows
each row has Width elements
then from there take the xth element
assuming your terrain is laid out row-wise.
Or if it is laid out column-wise (which is rather unusual but possible)
var pos = x * Height + z;
or in other words
skip x columns
each column has Height elements
then from there take the zth element
See also Converting index of one dimensional array into two dimensional array i. e. row and column
Update
Now that you have showed the terrain generation code it needs to be
var pos = z * (Width + 1) + x;
since the terrain array has actually Width + 1 elements per row.
I'm currently working on a chess game and I ran into a problem when drawing the board: the first element is in the top-left corner and the last one is in the lower-right corner.
How can I change my code so that the first element gets generated in the bottom-left corner and the last one in the top-right corner?
My code:
int l = -1;
for (int x = 0; x < gridSize; x++)
{
for (int y = 0; y < gridSize; y++)
{
l++;
points[l] = new Point(tileSize * x, tileSize * y);
}
}
Any help would be greatly appreciated!
Change your y loop to start at the max value and work downward.
int l = -1;
for (int x = 0; x < gridSize; x++)
{
for (int y = gridSize - 1; y >= 0; y--)
{
l++;
points[l] = new Point(tileSize * x, tileSize * y);
}
}
This will go up the first column, then up the second column, etc, until it reaches the top right corner.
I am learning C# for unity and could use some pointers.
I am following catlikecoding hex map tutorial but I have modified the grid for my own means.
http://catlikecoding.com/unity/tutorials/hex-map-1/
My goal is to create a pyramid of squares procedurally starting from a 7 * 7 grid. I am using a prefab plane
How do I place a limit on The CreateCell looped function so that cells with the (x,y) coordinates are not created when they meet the following expression
x + y > n - 1 where n = grid size (for example (6,1) or (5,6)
I have gotten as far as creating a rhombus of planes with the undesired planes below the ground plane.
The script is as follows.
public class HexGrid : MonoBehaviour {
public int width = 7;
public int height = 7;
public int length = 1;
public SquareCell cellPrefab;
public Text cellLabelPrefab;
SquareCell[] cells;
Canvas gridCanvas;
void Awake () {
gridCanvas = GetComponentInChildren<Canvas>();
cells = new SquareCell[height * width * length];
for (int z = 0 ; z < height; z++) {
for (int x = 0; x < width; x++) {
for (int y = 0; y < length; y++)
CreateCell(x, z, y);
}
}
}
void CreateCell(int x, int z, int y) {
Vector3 position;
position.x = x * 10f ;
position.y = ((y + 1) - (x + z)) * 10f + 60f;
position.z = z * 10f ;
Cell cell = Instantiate<Cell>(cellPrefab);
cell.transform.SetParent(transform, false);
cell.transform.localPosition = position;
Text label = Instantiate<Text>(cellLabelPrefab);
label.rectTransform.SetParent(gridCanvas.transform, false);
label.rectTransform.anchoredPosition =
new Vector2(position.x, position.z);
label.text = x.ToString() + "\n" + z.ToString();
}
}
Grid so far
A quick solution would be to add an if statement before the part of the code that creates a cell. In this case the method CreateCell(). That if statement should have your logic in code. You would also have to create two variables for the size to check. For example:
public int tempX;
public int tempY;
void Awake () {
gridCanvas = GetComponentInChildren<Canvas>();
cells = new SquareCell[height * width * length];
for (int z = 0 ; z < height; z++) {
for (int x = 0; x < width; x++) {
for (int y = 0; y < length; y++)
{
if (x + y < (tempX + tempY) - 1)
{
CreateCell(x, z, y);
}
}
}
}
}
I am using Unity 5 to create an isometric game. I have generated a grid of tiles and it works well. However, when I use two different tiles to fill in the grid (their image sizes are slightly different), I get gaps in between the tiles. The obvious solution would be to create the tiles so that they are all the same image size, but this would prevent me from creating anything on a tile that is larger than the size of a tile (eg. a tree).
Here are some images to demonstrate:
With only one type of tile:
With two types of tile:
This is the code I use to create the map:
private void CreateMap() {
float tileWidth;
float tileHeight;
int orderInLayer = 0;
SpriteRenderer r = floorTiles [0].GetComponent<SpriteRenderer> ();
tileWidth = r.bounds.max.x - r.bounds.min.x;
tileHeight = r.bounds.max.y - r.bounds.min.y;
for (int i = 0; i < map.GetLength(0); i++) {
orderInLayer += 1;
for (int j = 0; j < map.GetLength (1); j++) {
Vector2 position = new Vector2 ((j * tileWidth / 2) + (i * tileWidth / 2) + (tileWidth / 2), (j * tileHeight / 2) - (i * tileHeight / 2) + (tileHeight/ 2));
r = map[i,j].GetComponent<SpriteRenderer>();
r.sortingOrder = orderInLayer;
Instantiate(map[i, j], position, Quaternion.identity);
}
}
}
Any help would be greatly appreciated, I cannot seem to fix it!
You appear to be calculating a position for each of your tiles from scratch every time you create one. If you have 2 different sized tiles, then your calculation comes out different, hence the gaps in your tiles. This is because you're only using the width/height of the current tile, failing to take into account any previous tiles that may be a shorter/longer height/width.
Given you have varying heights AND widths you'll need a way to calculate the correct position for both to prevent gaps in the X and Y direction. I've mocked up something here, but it's untested. More of a concept(?) I guess.
float tileHeight = 0;
float tileWidth = 0;
Vector2 position = new Vector2(0,0);
Dictionary<int, float> HeightMap = new Dictionary<int, float>();
for (int iRow = 0; iRow < map.GetLength(0); iRow++)
{
position.x = 0;
orderInLayer += 1;
for (int jColumn = 0; jColumn < map.GetLength (1); jColumn++)
{
position.y = HeightMap[jColumn];
r = map[iRow, jColumn].GetComponent<SpriteRenderer>();
tileWidth = r.bounds.max.x - r.bounds.min.x;
tileHeight = r.bounds.max.y - r.bounds.min.y;
r.sortingOrder = orderInLayer;
position.x += tileWidth / 2;
position.y += tileHeight / 2;
Instantiate(map[iRow, jColumn], position, Quaternion.identity);
HeightMap[jColumn] = position.y;
}
}
I leave the best way of storing the height, or instantiating the contents of the HeightMap dictionary to however you see fit.
I've been trying to combine a couple of riemers tutorials to make a terrain that is textured and lit. I'm almost there but I can't get the application of the texture right. I believe the problem is in SetUpVertices() with the setting of the texture coordinates. I know currently the code reads that they're all set to (0, 0) and I need to have it so that they are set to the corners of the texture but I can't seem to get the code right. Anybody out there able to assist?
private void SetUpVertices()
{
vertices = new VertexPositionNormalTexture[terrainWidth * terrainHeight];
for (int x = 0; x < terrainWidth; x++)
{
for (int y = 0; y < terrainHeight; y++)
{
vertices[x + y * terrainWidth].Position = new Vector3(x, -y, heightData[x, y]);
vertices[x + y * terrainWidth].TextureCoordinate.X = 0;
vertices[x + y * terrainWidth].TextureCoordinate.Y = 0;
}
}
}
I've added the full code of Game1.cs to this pastie http://pastebin.com/REd8QDZA
You can stretch the texture across the surface by interpolating from 0 to 1:
vertices[x + y * terrainWidth].TextureCoordinate.X = x / (terrainWidth - 1.0);
vertices[x + y * terrainWidth].TextureCoordinate.Y = y / (terrainHeight - 1.0);