Unity3D: how to fix "TerrainData.SetHeights error" - c#

I have a problem with my terrain.
When I want to set the altitude it works, but the terrain is always displayed larger than the 2D array I use for the altitude. In this example, my array and terrain are 200x157. So why do I have this overhang in my display?
using MoonSharp.Interpreter;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
using System;
using System.Text;
using System.IO;
[MoonSharpUserData]
public class PrefabCreator : MonoBehaviour
{
/// <summary>
/// Classmembers for PrefabCreator
/// </summary>
private int terrainDepth;
private int terrainWidth;
private int terrainHeight;
private float terrainScale;
private float maxHeight;
public void CreateTerrain(int[][] mapData)
{
MapScale(mapData);
Terrain terrain = Resources.Load<Terrain>("TerrainObject") as Terrain;
Terrain prefabTerrain = Instantiate(terrain, new Vector3(0, 0, 0), Quaternion.identity);
prefabTerrain.terrainData = GenerateTerrain(prefabTerrain.terrainData, mapData);
}
private void MapScale(int[][] mapData)
{
terrainWidth = 0;
terrainHeight = 0;
terrainDepth = 10;
maxHeight = 0;
bool firstRun = true;
for (int i = 0; i < mapData.GetLength(0); i++)
{
terrainHeight++;
for (int j = 0; j < mapData[i].Length; j++)
{
if(mapData[i][j] > maxHeight)
{
maxHeight = mapData[i][j];
}
if (firstRun)
{
terrainWidth++;
}
}
firstRun = false;
}
Debug.Log("MAXHEIGHT: " + maxHeight);
}
private TerrainData GenerateTerrain(TerrainData terrainData, int[][] mapData)
{
if(terrainWidth >= terrainHeight)
{
terrainData.heightmapResolution = terrainWidth + 1;
}
else
{
terrainData.heightmapResolution = terrainHeight + 1;
}
terrainData.size = new Vector3(terrainWidth, terrainDepth, terrainHeight);
Debug.Log("Test" + terrainData.heightmapHeight);
Debug.Log("Test" + terrainData.heightmapWidth);
Debug.Log("Test" + terrainData.heightmapScale);
terrainData.SetHeights(0, 0, GenerateHeights(mapData));
return terrainData;
}
private float[,] GenerateHeights(int[][] mapData)
{
Debug.Log("Breite " + terrainWidth);
Debug.Log("Höhe " + terrainHeight);
float[,] heights = new float[terrainHeight, terrainWidth];
//Debug.Log("Test" + mapData[2][4]);
for (int x = 0; x <= terrainHeight - 1; x++)
{
//Debug.Log("X = " + x);
for (int y = 0; y <= terrainWidth - 1; y++)
{
//Debug.Log("Y = " + y);
float value = 0.0f + mapData[x][y];
heights[x, y] = (value / maxHeight);
//heights[x, y] = (float)value ;
Debug.Log(heights[x, y]);
}
}
return heights;
}
}
See the picture in the appendix. I don't understand why the overhangs exist at the edges?
Many thanks in advance People

Related

Mendelbrot Calculation Code Keeps Returning 2 for IterationCount

I'm working on writing a Mendelbrot renderer in C# to practice multithreading, but am having an issue where my calculation code maxes out at 2 iterations. I don't really understand why since the online references I've been looking at seem to calculate it the same way as me. No matter what coordinates of pixels I provide, it always returns 2 (aside from 0,0 and 0,1).
`
using System;
using System.Numerics;
using SkiaSharp;
namespace Mandelbrot
{
internal class Program
{
const int MaxIterations = 100;
static void Main(string[] args)
{
int size = 250;
int[,] grid = Run(size, 0, 0, 1);
// Console.WriteLine("Please specify a square size for the image.");
// try
// {
// Console.Write("Length: ");
// height = Int32.Parse(Console.ReadLine());
// }
// catch (FormatException e)
// {
// Console.WriteLine(e);
// throw;
// }
using (var surface = SKSurface.Create(width: size, height: size, SKColorType.Rgba8888, SKAlphaType.Premul))
{
SKCanvas canvas = surface.Canvas;
canvas.DrawColor(SKColors.Coral);
for (int i = 0; i < grid.GetLength(0); i++)
{
for (int j = 0; j < grid.GetLength(1); j++)
{
if (grid[i, j] >= MaxIterations)
canvas.DrawPoint(new SKPoint(i, j), SKColors.Black);
}
}
canvas.DrawPoint(new SKPoint(250, 250), SKColors.Chartreuse);
OutputImage(surface);
}
Console.WriteLine("Program successfully completed.");
}
public static int[,] Run(int size, int fromX, int fromY, int h)
{
int[] oulltput = new int[size * size];
int[,] output = new int[size, size];
for (int i = 0; i < output.GetLength(0); i += 1)
{
for (int j = 0; j < output.GetLength(1); j += 1)
{
float x = fromX + i * h;
float y = fromY + j * h;
output[i, j] = IterCount(x, y, MaxIterations);
}
}
return output;
}
public static int IterCount(float constX, float constY, int maxIterations)
{
const float maxMagnitude = 2f;
const float maxMagnitudeSquared = maxMagnitude * maxMagnitude;
int i = 0;
float x = 0.0f, y = 0.0f;
float xSquared = 0.0f, ySquared = 0.0f;
while (xSquared + ySquared <= maxMagnitudeSquared && i < maxIterations)
{
xSquared = x * x;
ySquared = y * y;
float xtmp = xSquared - ySquared + constX;
y = 2.0f * x * y + constY;
x = xtmp;
i++;
}
return i;
}
private static void OutputImage(SKSurface surface)
{
Console.WriteLine("Attempting to write .png to disk...");
using (var image = surface.Snapshot())
using (var data = image.Encode(SKEncodedImageFormat.Png, 80))
using (var stream = File.OpenWrite("out.png"))
{
// save the data to a stream
data.SaveTo(stream);
Console.WriteLine("Success!");
}
}
}
}
`
I tried to use breakpoints and writeline statements to debug but I can't figure out where my math is going wrong. I keep getting 2 for my iteration count.

Unity randomiser generating results in a non-random gradient

I'm using code from the tutorial series "make a game" by Sebastian Lague and so far everything has been easily adapted to the new versions of unity. However on Episode 9, I have become unstuck. I have adapted the code for the map generator to get it to compile in my version of unity, 2019.3.11f1. However, the random map generation seems to bias towards lowest coordinated of the map.
My Gen results:
What it should look like:
[
This code is the map generator script it is placed on an empty in the world and adds cubes as obstacles, provided with some prefabs.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class MapGenerator : MonoBehaviour
{
public Transform tilePrefab;
public Vector2 mapSize;
public int seed = 10;
public Transform obstaclePrefab;
public int obstacleCount = 10;
[Range(0, 1)]
public float outlinePercent; // Cotrols scale of tiles
List<Coord> allTileCoords;
Queue<Coord> shuffledTileCoords;
private void Start()
{
GenerateMap();
}
public void GenerateMap()
{
allTileCoords = new List<Coord>();
for (int x = 0; x < mapSize.x; x++)
{
for (int y = 0; y < mapSize.y; y++)
{
allTileCoords.Add(new Coord(x, y)); //iterate through mapSize adding tiles
}
}
shuffledTileCoords = new Queue<Coord>(Utility.ShuffleArray(allTileCoords.ToArray(), seed)); //shuffled array of tiles coords
string holderName = "Generated Map"; //Added for the editor script
if (GameObject.Find(holderName)) //Added for the editor script
{ //Added for the editor script
DestroyImmediate(GameObject.Find(holderName)); //Added for the editor script
} //Added for the editor script
Transform mapHolder = new GameObject(holderName).transform; //This is only neccessary because of the editor script
mapHolder.parent = transform; //This is only neccessary because of the editor script
for (int x = 0; x < mapSize.x; x++)
{
for (int y = 0; y < mapSize.y; y++)
{
Vector3 tilePosition = relativeToSpacial(x, y); //converts grid x,y data to real spatial coords
Transform newTile = Instantiate(tilePrefab, tilePosition, Quaternion.Euler(Vector3.right * 90)) as Transform; //instantiates tile in loctaion from rel to spatial func with 90 rotation
newTile.localScale = Vector3.one * (1 - outlinePercent); //scales down tiles to leave a outline
newTile.parent = mapHolder;
}
}
for (int i = 0; i < obstacleCount; i++)
{
Coord randomCoord = GetRandomCoord();
Vector3 obstaclePosition = relativeToSpacial(randomCoord.x, randomCoord.y);
Transform newObstacle = Instantiate(obstaclePrefab, obstaclePosition + Vector3.up * .5f, Quaternion.identity) as Transform;
newObstacle.parent = mapHolder;
}
}
Vector3 relativeToSpacial(int x, int y)
{
return new Vector3(-mapSize.x / 2 + .5f + x, 0, -mapSize.y / 2 + .5f + y);
}
public Coord GetRandomCoord()
{
Coord randomCoord = shuffledTileCoords.Dequeue();
shuffledTileCoords.Enqueue(randomCoord);
//print("|| " + randomCoord.x + " || " + randomCoord.y + " ||");
return randomCoord;
}
public struct Coord
{
public int x;
public int y;
public Coord(int _x, int _y)
{
x = _x;
y = _y;
}
}
}
This is the code from Utility.ShuffleArray which is my custom function for shuffling arrays.
using System.Collections;
using System.Collections.Generic;
public static class Utility
{
public static T[] ShuffleArray<T>(T[] array, int seed)
{
System.Random prng = new System.Random(seed);
for (int i =0; i < array.Length -1; i++)
{
int randomIndex = prng.Next(i, array.Length);
T tempItem = array[randomIndex];
array[randomIndex] = array[i];
}
return array;
}
}
Any help appreciated.
int randomIndex = prng.Next(i, array.Length);
You are incrementing the clamp on your rng in this line in your for loop, so it becomes increasingly bias to the end of the array, also I added code to do a swap of positions rather than duplicate of position try something like this
int randomIndex = prng.Next(0, array.Length);
T tempItem = array[randomIndex];
T tempItemTwo = array[i];
array[randomIndex] = array[i];
array[i] = tempItemTWo;
if that doesnt work also try:
int randomIndex = prng.Next(i, array.Length);
T tempItem = array[randomIndex];
T tempItemTwo = array[i];
array[randomIndex] = array[i];
array[i] = tempItemTWo;

C# - 2d matrix - is guess left/right/up/down of point

Using a 2d array of buttons implemented and placed on a form.
Button[,] tmpButton = new Button[x, y];
private void DrawGrid()
{
int ButtonWidth = 48;
int ButtonHeight = 48;
int start_x = 88;
int start_y = 200;
for (int i = 0; i < x; i++)
{
for (int j = 0; j < y; j++)
{
tmpButton[i, j] = new Button();
tmpButton[i, j].Top = start_x + (i * ButtonHeight);
tmpButton[i, j].Left = start_y + (j * ButtonWidth);
tmpButton[i, j].Width = ButtonWidth;
tmpButton[i, j].Height = ButtonHeight;
tmpButton[i, j].Click += new EventHandler(BTN_Grid_Click);
this.Controls.Add(tmpButton[i, j]);
}
}
}
If a random location (x,y) is set true within the grid with the intention of guessing (by clicking on the surrounding grid buttons) it's location. If the location is !true it should return left right up down pointing to the random location we set earlier. If the true location is up and left, it should return whichever it is closest too.
What would be the best way to implement something like this?
This is getting close, but something I can't see is off a bit ...
public String GetDirection()
{
int xd = Guess.X - Clue.X;
int yd = Guess.Y - Clue.Y;
if(Math.Abs(xd) <= Math.Abs(yd))
return (xd <= 0) ? "Left" : "Right";
else
return (yd <= 0) ? "Down" : "Up";
}
Here is a visual representation of what is happening ...
Alright so you had most of it right however you made a easy mistake. When you create the buttons you're rendering from left to right then top to bottom which creates the height as the x position then the width as the y position. So when you go and correlate the guess to the correct position you forget that you did this and assume x is the width.
Here's my implementation which fixed this:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace UpDownLeftRight {
public partial class Form1 : Form {
public Form1() {
InitializeComponent();
this.Load += new System.EventHandler(this.Form1_Load);
}
public int[] winner = new int[2];
public Button[,] tmpButton = new Button[10, 10];
private void Form1_Load(object sender, EventArgs e) {
Random r = new Random();
int ButtonWidth = 48;
int ButtonHeight = 48;
int start_x = 0;
int start_y = 0;
winner = new int[] { r.Next(0, 10), r.Next(0, 10) };
this.Size = new Size((ButtonWidth * 11), (ButtonHeight * 11));
for (int i = 0; i < 10; i++) {
for (int j = 0; j < 10; j++) {
tmpButton[i, j] = new Button();
tmpButton[i, j].Left = start_x + (i * ButtonWidth);
tmpButton[i, j].Top = start_y + (j * ButtonHeight);
tmpButton[i, j].Width = ButtonWidth;
tmpButton[i, j].Height = ButtonHeight;
tmpButton[i, j].Font = new Font(FontFamily.GenericMonospace, 17);
tmpButton[i, j].Click += new EventHandler(BTN_Grid_Click);
this.Controls.Add(tmpButton[i, j]);
}
}
}
public void BTN_Grid_Click(object o, EventArgs e) {
int[] guess = new int[2];
for (int i = 0; i != tmpButton.GetLength(1); i++) {
for (int j = 0; j != tmpButton.GetLength(0); j++) {
if (tmpButton[i, j] == o) {
guess = new int[] { i, j };
}
}
}
int xDist = guess[0] - winner[0];
int yDist = guess[1] - winner[1];
string possible = "˂˃˄˅";
if (xDist > 0) { possible = possible.Replace("˃", ""); }
if (xDist < 0) { possible = possible.Replace("˂", ""); }
if (xDist == 0) { possible = possible.Replace("˂", ""); possible = possible.Replace("˃", ""); }
if (yDist > 0) { possible = possible.Replace("˅", ""); }
if (yDist < 0) { possible = possible.Replace("˄", ""); }
if (yDist == 0) { possible = possible.Replace("˄", ""); possible = possible.Replace("˅", ""); }
((Button)o).Text = possible;
}
}
}

Unity: Error CS1041 on line 5: Identifier expected: 'public' is a keyword?

I have been following the Unity3D Procedural Cave Generation, but I found an error very early on in MapGeneration.cs. Unity says that on line 1 word 1, there is an error: Identifier expected: 'public' is a keyword. I cannot see any difference from my code and the tutorial's code. Here is the link to the tutorial video: [\Tutorial video 1] and here is my code:
using UnityEngine;
using System.Collections;
using System
public class MapGeneration : MonoBehaviour {
public int width;
public int height;
public string seed;
public bool useRandomSeed;
[Range(0,100)]
public int randomFillPercent;
int[,] map;
void Start() {
GenerateMap();
}
void GenerateMap() {
map = new int[width,height];
}
void RandomFillMap() {
if (useRandomSeed) {
seed = Time.time.ToString();
}
System.Random psuedoRandom = new System.Random(seed.GetHashCode());
for (int x = 0; x < width; x++) {
for (int y = 0; y < height; y ++) {
map[x,y] = (psuedoRandom.Next(0,100) < randomFillPercent)? 1: 0;
}
}
}
void OnDrawGizmos() {
if (map != null) {
for (int x = 0; x < width; x++) {
for (int y = 0; y < height; y ++) {
Gizmos.color = (map[x,y] == 1)? Color.black: Color.white;
Vector3 position = new Vector3(-width/2 + x + .5f,0,-height/2 + y + .5f);
Gizmos.DrawCube(position,Vector3.one);
}
}
}
}
}
The error is public on line one.
You don't have the ; after using System (that, maybe, is also an incomplete import).

C# XNA Tile engine drawing wrong tiles

I'm building a tile engine for my first game ever and i've been following a guide step by step (can't link it because i'm limited to 2). I have however, made a few modifications to the tilemap so that i can continue with my project.
And while testing my program a noticed a bug that i was hoping you guys could help me resolve...
...The tile engine is drawing the wrong tiles!
This is my TileMap (with numbers assigned to each tile) and this is what my engine draws.
While it should follow the order as seen below (the code is self-explanatory)
rows[0].columns[3].tileID = 0;
rows[0].columns[4].tileID = 1;
rows[0].columns[5].tileID = 2;
rows[0].columns[6].tileID = 3;
rows[0].columns[7].tileID = 4;
rows[1].columns[3].tileID = 5;
rows[1].columns[4].tileID = 6;
rows[1].columns[5].tileID = 7;
rows[1].columns[6].tileID = 8;
rows[1].columns[7].tileID = 9;
rows[2].columns[3].tileID = 10;
rows[2].columns[4].tileID = 11;
rows[2].columns[5].tileID = 12;
rows[2].columns[6].tileID = 13;
rows[2].columns[7].tileID = 14;
rows[3].columns[3].tileID = 15;
rows[3].columns[4].tileID = 16;
rows[3].columns[5].tileID = 17;
rows[3].columns[6].tileID = 18;
rows[3].columns[7].tileID = 19;
rows[4].columns[3].tileID = 20;
rows[4].columns[4].tileID = 21;
rows[4].columns[5].tileID = 22;
rows[4].columns[6].tileID = 23;
rows[4].columns[7].tileID = 24;
rows[5].columns[3].tileID = 25;
rows[5].columns[4].tileID = 26;
rows[5].columns[5].tileID = 27;
rows[5].columns[6].tileID = 28;
rows[5].columns[7].tileID = 29;
Code Essentials
The Important parts of my code
Tile.class
Where i define the tile size and have a function which navigates the tilemap to find my deiserd tile.
namespace TileEngine
{
static class Tile
{
static public Texture2D tileSetTexture;
static public int tileWidth = 48;
static public int tileHeight = 48;
static public Rectangle getSourceRectangle(int tileIndex)
{
int tileY = tileIndex / (tileSetTexture.Width / tileWidth);
int tileX = tileIndex % (tileSetTexture.Height / tileHeight);
return new Rectangle(tileX * tileWidth, tileY * tileHeight, tileWidth, tileHeight);
}
}
}
MapCell
Where i define the tileID
class MapCell
{
public List<int> baseTiles = new List<int>();
public int tileID
{
get { return baseTiles.Count > 0 ? baseTiles[0] : 0; }
set
{
if (baseTiles.Count > 0)
baseTiles[0] = value;
else
addBaseTile(value);
}
}
public void addBaseTile(int tileID)
{
baseTiles.Add(tileID);
}
public MapCell(int tileID)
{
this.tileID = tileID;
}
}
TileMap
Where i build the map
class MapRow
{
public List<MapCell> columns = new List<MapCell>();
}
class TileMap
{
public List<MapRow> rows = new List<MapRow>();
public int mapWidth = 50;
public int mapHeight = 50;
public TileMap()
{
for (int y = 0; y < mapHeight; y++)
{
MapRow thisRow = new MapRow();
for (int x = 0; x < mapWidth; x++)
{
thisRow.columns.Add(new MapCell(0));
}
rows.Add(thisRow);
}
}
}
Draw
And lastly my draw code.
protected override void Draw(GameTime gameTime)
{
GraphicsDevice.Clear(Color.Black);
spriteBatch.Begin();
Vector2 firstSquare = new Vector2(Camera.location.X / Tile.tileWidth, Camera.location.Y / Tile.tileHeight);
int firstX = (int)firstSquare.X;
int firstY = (int)firstSquare.Y;
Vector2 squareOffset = new Vector2(Camera.location.X % Tile.tileWidth, Camera.location.Y % Tile.tileHeight);
int offsetX = (int)squareOffset.X;
int offsetY = (int)squareOffset.Y;
for (int y = 0; y < squaresDown; y++)
{
for (int x = 0; x < squaresAcross; x++)
{
foreach (int tileID in myMap.rows[y + firstY].columns[x + firstX].baseTiles)
{
spriteBatch.Draw(
Tile.tileSetTexture,
new Rectangle(
(x * Tile.tileWidth) - offsetX, (y * Tile.tileHeight) - offsetY,
Tile.tileWidth, Tile.tileHeight),
Tile.getSourceRectangle(tileID),
Color.White);
}
}
}
spriteBatch.End();
base.Draw(gameTime);
}

Categories