Index was outside the bounds of the array. 3d array [duplicate] - c#

This question already has answers here:
What is an IndexOutOfRangeException / ArgumentOutOfRangeException and how do I fix it?
(5 answers)
Closed 1 year ago.
IndexOutOfRangeException: Index was outside the bounds of the array. (wrapper managed-to-managed) System.Object.ElementAddr_4(object,int,int,int) Camera_s.Start () (at Assets/scripts/Camera_s.cs:19)
Script Move.cs:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Move : MonoBehaviour
{
public Block scr;
public Camera_s cam;
public Transform my_block;
private int[,,] grid;
void Start()
{
my_block = gameObject.transform.parent;
scr = my_block.GetComponent<Block>();
cam = GameObject.Find("Main Camera").GetComponent<Camera_s>();
grid = cam.Grid;
}
void OnMouseDown(){
if (scr.IsActive){
if (gameObject.transform.name == "left"){
my_block.position -= new Vector3(cam.Jump_Size, 0f);
}
else if (gameObject.transform.name == "right"){
my_block.position += new Vector3(cam.Jump_Size, 0f);
}
else if (gameObject.transform.name == "up"){
my_block.position += new Vector3(0f, cam.Jump_Size);
}
else if (gameObject.transform.name == "down"){
my_block.position -= new Vector3(0f, cam.Jump_Size);
}
}
}
void Update()
{
}
}
Script Block.cs:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Block : MonoBehaviour
{
public bool IsActive = false;
public Camera_s Camera_Script;
public int Id;
public int[] coords;
public int color;
private int[,,] grid;
void Start()
{
Camera_Script = GameObject.Find("Main Camera").GetComponent<Camera_s>();
Id = Camera_Script.Block_max + 1;
Camera_Script.Block_max += 1;
grid = Camera_Script.Grid;
grid[coords[0], coords[1], 0] = 1;
grid[coords[0], coords[1], 0] = color;
}
void OnMouseDown(){
IsActive = true;
Camera_Script.Active = Id;
Debug.Log("Active");
}
// Update is called once per frame
void Update()
{
if (Camera_Script.Active != Id){
IsActive = false;
}
}
}
Script Camera_s.cs:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Camera_s : MonoBehaviour
{
public int Active = -1;
public int Block_max = -1;
public float Jump_Size;
public int[] Grid_Size;
public int[,,] Grid;
void Start()
{
Grid = new int[Grid_Size[1], Grid_Size[0], 2];
for (int i = 0;i < 3;i++){
for (int j = 0;j< 5;j++){
Grid[j, i, 0] = 0;
Grid[j, i, 1] = 0;
}
}
}
// Update is called once per frame
void Update()
{
}
}
I understand something wrong with my for, but i dont know how to fix it.
Main part of code, in which I had mistake:
for (int i = 0;i < 3;i++){
for (int j = 0;i < 5;j++){
Grid[j, i, 0] = 0;
Grid[j, i, 1] = 0;
}
}
Data inputed by Unity Editor:
Jump_Size = 3f; Grid_Size = [5, 3]
Thanks!

If what you input is really Grid_Size = [5, 3], that means your first two dimensions are flipped.
You could simply correct that, but you should not expose the sizes if anything but one value pair is generating errors.
Grid = new int[Grid_Size[0], Grid_Size[1], 2];
for (int i = 0;i < Grid.GetLength(1);i++){
for (int j = 0;j< Grid.GetLength(0);j++){
Grid[j, i, 0] = 0;
Grid[j, i, 1] = 0;
}
}
Would result in the same array dimensions as before if you flip the input, but still use the same access order as before. How exactly you do this depends on what you want to do with the array of course.
Additionally it would be advisable to check the input for correct values, in Block you are indexing Grid with input (coords) from the editor again. I'd recommend to make sure that input is in expected bounds of the array

Related

modified Texture2D not showing up

So I am trying to make 2 different texture2d's from 1. basically by cutting it in half. I tried a simple way, but it is kinda slow and right now ddoesn't work at all.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
namespace MediaPipe.HandPose
{
public sealed class camerasplitter : MonoBehaviour
{
public WebcamInput main, first, second;
public Texture2D camdata,firsttex,secondtex;
public int frame = 0;
// Start is called before the first frame update
void Start()
{
firsttex = new Texture2D(1080, 960);
secondtex = new Texture2D(1080, 960);
first._dummyImage = firsttex;
second._dummyImage = secondtex;
}
// Update is called once per frame
void Update()
{
frame++;
if (frame > 1000) frame = 1;
if (frame % 3 == 0)
{
camdata =toTexture2D(main.Texture);
for (int i = 0; i < camdata.height; i++)
{
for (int j = 0; j < camdata.width/2; j++)
{
firsttex.SetPixel(i, j, camdata.GetPixel(i, j));
secondtex.SetPixel(i, j + camdata.width / 2, camdata.GetPixel(i, j + camdata.width / 2));
}
}
firsttex.Apply(false);
/*for (int i = 0; i < camdata.height; i++)
{
for (int j = camdata.width / 2; j < camdata.width; j++)
{
secondtex.SetPixel(i, j, camdata.GetPixel(i, j));
}
}*/
secondtex.Apply(false);
}
}
public Texture2D toTexture2D(Texture rTex)
{
Texture2D dest = new Texture2D(rTex.width, rTex.height, TextureFormat.RGBA32, false);
Graphics.CopyTexture(rTex, dest);
return dest;
}
}
}
when i run it, the camdata is getting data from other script and it shows. but firsttex and secondtex are not showing. they are gray. even if it lags to do the "for" operation.
thats the thing that is stopping my project. Thanks in advance!

NullReferenceException: Object reference not set to an instance of an object when calling transform.localScale [duplicate]

This question already has answers here:
What is a NullReferenceException, and how do I fix it?
(27 answers)
Closed 2 years ago.
I have a 2D array of gameObjects pieces. When I want to rescale them in my private void ScalePieces() method, I get a NullReferenceException. If I instead just use Debug.Log() I dont get an Error. This is the whole code:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class PieceDrawer : MonoBehaviour
{
public string[,] BoardArray = new string[8, 8];
public GameObject[,] pieces = new GameObject[8, 8];
private bool setup = false;
public float scale = 0.7f;
private (int, int) WhiteKing = (0, 0);
private (int, int) BlackKing = (0, 0);
public GameObject bishopBlack, bishopWhite, kingBlack, kingWhite, knightBlack, knightWhite;
public GameObject pawnBlack, pawnWhite, queenBlack, queenWhite, rookBlack, rookWhite;
private Dictionary<string, GameObject> PrefabPiece = new Dictionary<string, GameObject>();
public string fen = "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1";
void Start()
{
PrefabPiece["b_b"] = bishopBlack;
PrefabPiece["b_w"] = bishopWhite;
PrefabPiece["k_b"] = kingBlack;
PrefabPiece["k_w"] = kingWhite;
PrefabPiece["n_b"] = knightBlack;
PrefabPiece["n_w"] = knightWhite;
PrefabPiece["p_b"] = pawnBlack;
PrefabPiece["p_w"] = pawnWhite;
PrefabPiece["q_b"] = queenBlack;
PrefabPiece["q_w"] = queenWhite;
PrefabPiece["r_b"] = rookBlack;
PrefabPiece["r_w"] = rookWhite;
}
private void Update()
{
if (fen != "" && !setup)
{
SetupPieces();
setup = true;
}
}
private void SetupPieces()
{
var x = 0;
var y = 0;
var fenList = fen.Split();
foreach (var position in fenList[0])
{
if (position == '/')
{
x = 0;
y++;
}
else if (char.IsDigit(position))
{
for (int i = 0; i < (position - '0'); i++)
{
BoardArray[x + i, y] = " ";
}
x += position - '0';
}
else
{
switch (position)
{
case 'k':
BlackKing = (x, y);
break;
case 'K':
WhiteKing = (x, y);
break;
}
var clr = char.IsUpper(position) ? "_w" : "_b";
BoardArray[x, y] = position.ToString().ToLower() + clr;
x++;
}
}
DrawPieces();
}
private void DrawPieces()
{
for (int x = 0; x < 8; x++)
{
for (int y = 0; y < 8; y++)
{
if (BoardArray[x, y] != " ")
{
pieces[x, y] = Instantiate (PrefabPiece[BoardArray[x, y]], new Vector3 (x, y, 0), Quaternion.identity);
pieces[x, y].GetComponent<SpriteRenderer>().sortingOrder = 1;
ScalePieces();
}
}
}
}
private void ScalePieces()
{
for (int x = 0; x < 8; x++)
{
for (int y = 0; y < 8; y++)
{
// Debug.Log("Hello");
Vector3 scaleVec = new Vector3(scale, scale, 1);
pieces[x, y].transform.localScale = scaleVec;
}
}
}
}
And the error message I get in unity:
NullReferenceException: Object reference not set to an instance of an object
PieceDrawer.ScalePieces () (at Assets/PieceDrawer.cs:118)
PieceDrawer.DrawPieces () (at Assets/PieceDrawer.cs:104)
PieceDrawer.SetupPieces () (at Assets/PieceDrawer.cs:91)
PieceDrawer.Update () (at Assets/PieceDrawer.cs:44)
As I said changing the method to something else fixes the error, so I think it definetly has to do with transform.localScale. I also tried calling the method from other methods; same error.
ScalePieces is called inside the loop in DrawPieces when not all entries of pieces[] are set. Better call it after the loop.

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;

Unexplained increasement of variable

In one of my loops which I use to change the settings of my buttons, I also use the AddListener function rather then the one in the Inspector. I have 5 items, giving a range of "i" from 0-4, but when I print "i" trough the function it should call, it always logs 5, no matter what button I press, which is weird since "i" never even reaches 5. Any idea?
P.s. I use a CustomEditor to show the 2 buttons "Preview Layout" and "Delete Preview" in the inspector.
Code:
using UnityEngine;
using System.Collections;
using UnityEditor;
using UnityEngine.UI;
public class RateMeManager : MonoBehaviour {
public GameObject rateMeCanvas;
public Sprite emptyStar, fullStar, button;
public float spriteWidth, spriteHeight, spritePadding;
[HideInInspector]
public GameObject currentCanvas, tempButton;
void Start () {
RemovePreview();
GenerateStars();
}
// Update is called once per frame
public void GenerateStars () {
RectTransform myRectTransform;
if (currentCanvas != null)
{
GameObject temp;
temp = currentCanvas;
DestroyImmediate(temp);
}
currentCanvas = Instantiate(rateMeCanvas, Vector3.zero, Quaternion.identity) as GameObject;
GameObject subCanvas = currentCanvas.transform.FindChild("subCanvas").gameObject;
myRectTransform = subCanvas.GetComponent<RectTransform>();
myRectTransform.sizeDelta = new Vector2((5*spriteWidth) + (4*spritePadding), spriteHeight);
myRectTransform.anchoredPosition = Vector2.zero;
Button[] buttons = subCanvas.GetComponentsInChildren<Button>();
float[] positions = new float[] {((2*spriteWidth)+(2*spritePadding))*-1, ((1 * spriteWidth) + (1 * spritePadding)) * -1 , 0, ((1 * spriteWidth) + (1 * spritePadding)), ((2 * spriteWidth) + (2 * spritePadding))};
for (int i = 0; i < buttons.Length; i++)
{
Debug.Log(i);
tempButton = buttons[i].gameObject;
tempButton.GetComponent<Button>().image.sprite = emptyStar;
myRectTransform = buttons[i].GetComponent<RectTransform>();
myRectTransform.sizeDelta = new Vector2(spriteWidth, spriteHeight);
myRectTransform.anchoredPosition = new Vector2(positions[i], 0);
tempButton.GetComponent<Button>().onClick.AddListener(() => OnGivenRate(i));
}
}
public void RemovePreview()
{
DestroyImmediate(currentCanvas);
}
private void OnGivenRate(int stars)
{
Debug.Log("pressed star: " + stars);
}
public class RateMeEditor
{
[CustomEditor(typeof(RateMeManager))]
public class button : Editor
{
public override void OnInspectorGUI()
{
base.OnInspectorGUI();
RateMeManager myScript = (RateMeManager)target;
if (GUILayout.Button("Preview Layout"))
{
myScript.GenerateStars();
}
if (GUILayout.Button("Delete Preview"))
{
myScript.RemovePreview();
}
}
}
}
}
Your error is here:
tempButton.GetComponent<Button>().onClick.AddListener(() => OnGivenRate(i));
You have to store i in a variable before passing it to OnGivenRate or use a closure.
Because at the end of the loop i is equal to 5. It's why when you click on your button i displays 5.
So do:
var rate = i;
tempButton.GetComponent<Button>().onClick.AddListener(() => OnGivenRate(rate));
or
Action<int> OnGivenRateClosure(int rate)
{
return () => OnGivenRate(rate);
}
with
tempButton.GetComponent<Button>().onClick.AddListener(OnGivenRateClosure(i));
You reference to i on your for-loop:
tempButton.GetComponent().onClick.AddListener(() => OnGivenRate(i));
And you use an anonymous method to call OnGivenRate(i). This piece of code will live outside the scope of your for-loop, yet it will have access to i variable. The variable, when it is referenced by the () => OnGivenRate(i) anonymous method, will most likely have i=5 (when the for-loop is exited).
You're accessing a closure, so the called function inside the for loop gets the i value only after a while, when the loop is in another cycle and i has been already modified.
Another thing. When you write:
for(int i = 0; i < 5; i++)
the code executes the statements inside the for loop with i values of 0, 1, 2, 3, 4, but the last value of i is 5. In fact, when the cycle with 4 ended, i is incremented, the check "i < 5" is made, it results false, so the loop exits.
Your code is redundant. You already have buttons as array before the for loop then you converted it a gameObject(tempButton) then into a button again.... This looks like a reference problem. Just replace your for loop with the code below.
To display 0 to 4:
for (int i = 0; i < buttons.Length; i++)
{
buttons[i].image.sprite = emptyStar;
myRectTransform = buttons[i].GetComponent<RectTransform>();
myRectTransform.sizeDelta = new Vector2(spriteWidth, spriteHeight);
myRectTransform.anchoredPosition = new Vector2(positions[i], 0);
buttons[i].onClick.AddListener(() => OnGivenRate(i));
}
To display 1 to 5:
for (int i = 0; i < buttons.Length; i++)
{
buttons[i].image.sprite = emptyStar;
myRectTransform = buttons[i].GetComponent<RectTransform>();
myRectTransform.sizeDelta = new Vector2(spriteWidth, spriteHeight);
myRectTransform.anchoredPosition = new Vector2(positions[i], 0);
buttons[i].onClick.AddListener(() => OnGivenRate(i+1));
}
Notice the difference: buttons[i].onClick.AddListener(() => OnGivenRate(i+1));

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).

Categories