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);
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 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.
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 wanted to know if writing points using a for loop in the begin end batch works or not, so I read up on a sphere algorithm and produced this based on my reading. There are some problems with it as you can see below in the output screen capture. My goal is to produce a sphere procedurally and then modify it at runtime.
but I would like to set my goal on the short-term and figure out why the faces are not correct. anyone have any ideas?
I've got this code:
private void openGLControl_OpenGLDraw(object sender, RenderEventArgs e)
{
// Get the OpenGL object.
OpenGL gl = openGLControl.OpenGL;
// Clear the color and depth buffer.
gl.Clear(OpenGL.GL_COLOR_BUFFER_BIT | OpenGL.GL_DEPTH_BUFFER_BIT);
// Load the identity matrix.
gl.LoadIdentity();
// Rotate around the Y axis.
gl.Rotate(rotation, 0.0f, 1.0f, 0.0f);
//Draw a ball
//Drawing Mode
gl.PolygonMode(SharpGL.Enumerations.FaceMode.FrontAndBack, SharpGL.Enumerations.PolygonMode.Lines);
//ball fields
double radius = 4.0d;
const double DEGREE = Math.PI/11.25;
double x = 0;
double y = 0;
double z = 0;
// ball batch
gl.Begin(OpenGL.GL_TRIANGLE_STRIP_ADJACENCY);
for (double j = 0.0d; j < Math.PI; j = j +DEGREE)
{
for (double i = 0; i < 2 * Math.PI; i = i + DEGREE)
{
x = radius * Math.Cos(i) * Math.Sin(j);
y = radius * Math.Sin(j) * Math.Sin(i);
z = radius * Math.Cos(j);
gl.Color(Math.Abs(x + y), Math.Abs(y + z), Math.Abs(z + x));
gl.Vertex(x, y, z);
}
}
gl.End();
// Nudge the rotation.
rotation += 3.0f;
}
I have some problems with collision. I want to ge coords of a sprite that can be rotated scaled or whatever. It's similiar to Riemers guide, but he's getting a collision of two sprites and I only need those points where alpha is zero.
Better see source:
public Color[,] TextureTo2DArray(Texture2D texture) // to get color array
{
Color[] colors1D = new Color[texture.Width * texture.Height];
texture.GetData(colors1D);
Color[,] colors2D = new Color[texture.Width, texture.Height];
for (int x = 0; x < texture.Width; x++)
for (int y = 0; y < texture.Height; y++)
colors2D[x, y] = colors1D[x + y * texture.Width];
return colors2D;
}
With color is pretty easy, but here is the part where I get points:
public Vector2 TexturePos(Color[,] Color, Matrix matrix)
{
int width1 = Color.GetLength(0);
int height1 = Color.GetLength(1);
for (int x = 0; x < width1; x++)
{
for (int y = 0; y < height1; y++)
{
Vector2 pos1 = new Vector2(x, y);
if (Color[x, y].A > 0)
{
Vector2 screenPos = Vector2.Transform(pos1, matrix);
return screenPos;
}
}
}
return new Vector2(-1, -1);
}
And for matrix I'm using this:
Matrix matrix =
Matrix.CreateTranslation(new Vector3(origin, 0)) *
Matrix.CreateRotationZ(MathHelper.ToRadians(rotation))*
Matrix.CreateScale(scale) *
Matrix.CreateTranslation(new Vector3(pos, 0));
Sprite is rectangular but i get circular movement: I'm rotating it (rotation += 0,5), adding gravity and making it collide with some y value:
Pos.Y += 5;
if (Position.Y >= 200)
BoxPos.Y -= 5;
And I get that it rotates as a circle colliding a line, but not as a rectangle.
Is this normal? Maybe I need some fixes in source?
"That method is supposed to get a position of a pixel (in sprite) that is not transperent but is rotated, scaled (depending on sprite)."
You need to have a look at this:
http://create.msdn.com/en-US/education/catalog/tutorial/collision_2d_perpixel_transformed
This is a great article about 2D collisions in XNA and has an example method that performs 2D collision detection for a Scaled & Rotated set of sprites.