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));
Related
I've created a procedural mesh script while watching one of Freya Holmér's improvised live course vods, and re purposed the code to create a procedural tube mesh with subdivision and plenty of other niche features.
But, after looking over the code and the lesson, I still cannot for the life of me figure out why sometimes I will get an:
argument out of range exception
...and sometimes I won't depending on the level of subdivision; also, entire faces wont be generated by the script.
TL;DR Problems list:
Argument out of range exception (Depending on level of subdivision).
Entire sides/faces of the tube mesh will not be generated, even when no errors are provided.
These problems are stemming from line 154 in the UpdateTris() method.
Code
using System.Collections.Generic;
using UnityEngine;
#if UNITY_EDITOR
using UnityEditor;
using OpenNexus.ExtraGizmos;
#endif
using OpenNexus.BaseMath;
using OpenNexus.MeshFormat;
namespace OpenNexus.Procedurals
{
[RequireComponent(typeof(MeshFilter))]
public class TubeMesh : MonoBehaviour
{
private MeshFilter filter;
private Mesh mesh;
public List<Vector3> Points = new List<Vector3>()
{
new Vector3(0, 0, 0),
new Vector3(0, 1, 1),
new Vector3(0, 0, 2)
};
[Header("Bezier Data")]
public Precision BezierPrecision = Precision.Fast;
[Header("Tube Data")]
[Range(0.01f, 1f)]public float Radius = 0.01f;
[Range(3, 32)] public int Segments = 8;
[Range(3, 6)] public int Subdivisions = 3;
[Header("Mesh Data")]
public ProceduralMesh2D BaseProceduralMesh = new ProceduralMesh2D();
public List<Vector3> Vertices;
public List<int> Tris;
private void OnEnable()
{
if (!GetComponent<MeshRenderer>()) // Check for and add missing mesh renderer.
gameObject.AddComponent<MeshRenderer>();
if (filter == null) // Check for and assign mesh filter variable.
filter = GetComponent<MeshFilter>();
if (mesh == null) // Check for and instantiate a new mesh object.
mesh = new Mesh();
mesh.name = "TubeMesh"; // Set name to mesh object.
filter.sharedMesh = mesh; // Set MeshFilter's shared mesh variable to new mesh object.
}
private void Update()
{
/*
Data reset
------------------------------
*/
// Reset base mesh data.
BaseProceduralMesh.Vertices = new List<Vertex>();
BaseProceduralMesh.LineIndex = new List<int>();
// Reset mesh data.
Vertices = new List<Vector3>();
Tris = new List<int>();
/*
Data update
------------------------------
*/
// Update base mesh.
UpdateBaseMesh();
// Update mesh data.
UpdateVertices();
UpdateTris();
}
private void LateUpdate() => UpdateMesh();
private BezierPoint GetBezierPoint(int index)
{
float _t = index / (Segments - 1f);
BezierPoint _bp = BezierMath.QuadraticBezier(Points, BezierPrecision, _t);
return _bp;
}
private void UpdateBaseMesh()
{
// Generate base vertices.
for (int i = 0; i < Subdivisions; i++)
{
float _point = i / (float)Subdivisions;
float _radius = _point * Floats.TAU;
Vertex _vertex = new Vertex(VectorThrees.UnitVectorByAngle(_radius) * Radius);
BaseProceduralMesh.Vertices.Add(_vertex);
}
// Generate base LineIndexes.
for (int i = 0; i < BaseProceduralMesh.VertexCount; i++)
{
BaseProceduralMesh.LineIndex.Add(i);
}
BaseProceduralMesh.LineIndex.Add(0);
}
private void UpdateVertices()
{
for (int i = 0; i < Segments; i++)
{
BezierPoint _point = GetBezierPoint(i);
for (int j = 0; j < BaseProceduralMesh.VertexCount; j++)
{
Vertices.Add(_point.LocalToWorldPosition(BaseProceduralMesh.Vertices[j].Point));
}
}
}
private void UpdateTris()
{
for (int s = 0; s < Segments - 1; s++)
{
int _root = s * BaseProceduralMesh.VertexCount;
int _rootNext = (s + 1) * BaseProceduralMesh.VertexCount;
for (int i = 0; i < BaseProceduralMesh.EdgeCount; i+=2)
{
int _lineA = BaseProceduralMesh.LineIndex[i];
int _lineB = BaseProceduralMesh.LineIndex[i + 1];
int _currentA = _root + _lineA;
int _currentB = _root + _lineB;
int _nextA = _rootNext + _lineA;
int _nextB = _rootNext + _lineB;
Tris.Add(_currentA);
Tris.Add(_nextA);
Tris.Add(_nextB);
Tris.Add(_currentA);
Tris.Add(_nextB);
Tris.Add(_currentB);
}
}
}
private void UpdateMesh()
{
mesh.Clear();
mesh.SetVertices(Vertices);
mesh.SetTriangles(Tris, 0);
mesh.RecalculateNormals();
}
#if UNITY_EDITOR
private void OnDrawGizmos()
{
// Draw psudo mesh with gizmos.
/*
Draw segment/edge loops
-------------------------------------
*/
for (int i = 0; i < Segments; i++) // Debug each segment, and what their 2D mesh segment should look like.
{
BezierPoint _point = GetBezierPoint(i);
WireGizmos.DrawWireCircle(_point.Position, _point.Rotation, Radius, Subdivisions);
}
Gizmos.color = Color.red;
for (int i = 0; i < Vertices.Count; i++) // Debug each vertex.
{
Gizmos.DrawSphere(Vertices[i], 0.01f);
Handles.Label(Vertices[i], "\n\nVertex: " + i + "\n\nVertex position:\n" + Vertices[i].ToString());
}
for (int i = 0; i < Tris.Count; i++)
{
Gizmos.DrawLine(Vertices[Tris[i]], Vertices[Tris[(i + 1) % Tris.Count]]);
}
}
#endif
}
}
I've already looked over my code compared to the code in the video, it's fundamentally the same, with the main differences being, how I'm creating the 2D mesh format for the script to work with, and the structure of the code.
After looking back at what they had done compared to mine, I just don't see how I'm running into this issue.
Things I've tried
Change the loop iteration i+=2 -to- i++ (This spits out the exception, but generates the first section of the tube before getting stuck between the second vertex in the next segment, and vert 0).
Every suggestion I try from this question, I will update the "Things I've tried..." list.
Please let me know if I need to clarify anything in this post, and if you wish to see the other classes/structs referenced in this script.
After a day of resting, and the a couple of hours of testing different values and questioning the code. I've found the problem.
The real issue
The nested for loop in the UpdateTris() method was going up by twos assuming I was making a hard edge mesh with pared vertices. This caused the loop to skip over an entire face of the mesh, and causing the
ArgumentOutOfRangeException
...when the Subdivision value was an even number.
My solution
I had to bring it back to the default single iteration (since I was trying to make a smooth lighting mesh), the second issue with the for loop was the iteration limit BaseProceduralMesh.LineCount needing to be subtracted by one since that was causing another
ArgumentOutOfRangeException
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
I have a code for a crafting system that checks if the inventory has the ingredients needed to craft an item and adds a button to craft it. The problem is when I want to position my button it goes way off the canvas. I have seen some people saying that it has something to do with rect transform. I've been stuck with it for over an hour. Any help is appreciated.
I have tried
removing the setparent() function,
using anchoredPosition,
using localPosition
My code
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Crafting : MonoBehaviour
{
public List<recipe> recipes = new List<recipe>();
public GameObject base_item, parent;
List<GameObject> items = new List<GameObject>();
public int y = 75;
public int x = -45;
public Inv inv;
private void Start()
{
inv = GetComponent<Inv>();
}
private void Update()
{
if (Input.GetKeyDown(KeyCode.Tab))
{
checkitems();
Debug.Log("y = " + y + " x = " + (x - 40));
}
}
public void checkitems()
{
for (int i = 0; i < recipes.Count; i++)
{
recipe r = recipes[i];
for (int x = 0; x < r.ingredients.Count; x++)
{
if (!inv.hasitem(r.ingredients[x])){
return;
}
}
showitem(r.result);
}
}
public void onClick(int _slot)
{
recipe r = recipes[_slot];
for (int i = 0; i < r.ingredients.Count; i++)
{
inv.removeitem(inv.getitem(r.ingredients[i]));
}
inv.additem(inv.getFirstAvailable(), r.result, r.stack);
}
public void showitem(string name)
{
GameObject obj = Instantiate(base_item);
if (items.Count != 0)
{
if (((items.Count) % 3) != 0)
{
Debug.Log("first thing");
obj.GetComponent<RectTransform>().position = new Vector2(x, y);
obj.transform.SetParent(parent.transform);
obj.SetActive(true);
items.Add(obj);
x = x + 40;
Debug.Log("x + 40");
}
else if (((items.Count + 1) % 3) == 0)
{
Debug.Log("second thing");
x = -45;
Debug.Log("x + 40");
y = y + 40;
Debug.Log(" y + 40");
obj.GetComponent<RectTransform>().position = new Vector2(x, y);
obj.transform.SetParent(parent.transform);
obj.SetActive(true);
items.Add(obj);
}
}else
{
obj.GetComponent<RectTransform>().position = new Vector2(x, y);
obj.transform.SetParent(parent.transform);
obj.SetActive(true);
items.Add(obj);
x = x + 40;
Debug.Log("x + 40");
}
}
}
Blue circle where it spawns. Red circle where I want it to be
Seems you are confusing a bunch of terms for being the issue of your problem. Firstly I want to address the red X over your scroll bar. Whenever this occurs, it means that your RectTransform of this UI object has been dragged from its positive vertices to negative or vice versa, causing it to almost invert. I would correct this but it is not the reason your objects are not childing correctly.
Generally, with UI objects, I would never use LocalPosition, just AnchoredPosition. LocalPosition is a field from Transform which I believe RectTransform inherits from. As RectTransforms have a lot of modifications to their position from pivots, anchors, and anchored positions, the LocalPosition will most likely need to recalculate data to properly move the object, whereas AnchoredPosition has already done these calculations.
I believe the issue with your current code is how you are using SetParent. There is a second parameter of SetParent which governs whether the object keeps the same position based in world space after being childed. As you are not passing in a new bool for this parameter, it is defaulting to true. As you want your objects to be childed to the parent but not keep their world space positions, you would want to pass in false.
In your case, as it looks as if you want to set objects in a grid-like pattern childed to this ScrollRect, I would attach a GridLayoutGroup to the Content of your scroll and child the new objects to this object. You can set the max columns of this grid and spacing to give the same layout you are attempting to achieve in code.
To summarize, I would remove all the hand placement you are doing in code with LocalPosition and AnchorPosition and just attach a GridLayoutGroup. To fix the current positioning of your objects relative to the parent, change all lines of obj.transform.SetParent(parent.transform); to obj.transform.SetParent(parent.transform, false);. If you want to keep changing position locally in code instead of a layout element, use SetParent first, and use AnchoredPosition instead of LocalPosition as the SetParent with false passed in will override the position you set.
Below is a few simple lines of code that is part of uni tech demo. In an attempt to create a 3D grid of vectors within a given area.
My solution thus far is to create a 2D grid at the starting X and Y points and then repeat this process along the Z.
As a temporary visualization I then instantiate Sphere prefabs.
The purpose of which is to use this grid of vectors as a model for a depth first search path algorithm which I will use to input vectors for a procedurally generated track(currently control points are set manually via editor methods)
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
public class GridLayout : MonoBehaviour {
public int GridWidth;
public int GridLength;
public int GridHeight;
public int resolution;
private int ResW;
private int ResL;
private int ResH;
private List<Vector3> GridPoints = new List<Vector3>();
private bool GridCompleted = false;
private GameObject tempObject;
// Use this for initialization
void Start () {
//Area box Start square
GridPoints.Add(new Vector3(0,0,0));
GridPoints.Add(new Vector3(0,GridHeight,0));
GridPoints.Add(new Vector3(GridWidth,0,0));
GridPoints.Add(new Vector3(GridWidth,GridHeight,0));
ResW = GridWidth/resolution;
ResH = GridHeight/resolution;
ResL = GridLength/resolution;
}
// Update is called once per frame
void Update () {
if (GridCompleted == false)
CreateGrid();
else
{
for(int i = 0; i <= GridPoints.Count; i++)
{
tempObject = GameObject.CreatePrimitive(PrimitiveType.Sphere);
tempObject.transform.position = GridPoints[i];
}
}
} //Area Box End square
// GridPoints.Add(new Vector3(0,0,GridLength));
// GridPoints.Add(new Vector3(0,GridHeight,GridLength));
// GridPoints.Add(new Vector3(GridWidth,0,GridLength));
// GridPoints.Add(new Vector3(GridWidth,GridHeight,GridLength));
void CreateGrid()
{
if(ResW != GridWidth | ResL != GridLength | ResH != GridHeight)
{
for(int l = 1;ResL <= GridLength; l++)
{
GridPoints.Add (new Vector3(0,0,ResL));
ResL = (GridLength/(resolution))*l;
for(int w = 1;ResW <= GridWidth; w++)
{
GridPoints.Add (new Vector3(ResW,0,0));
ResW = (GridWidth/(resolution))*w;
for(int h = 1;ResW <= GridHeight; h++)
{
GridPoints.Add (new Vector3(0,ResH,0));
ResH = (GridHeight/(resolution))*h;
}
}
}
}
else
{
GridCompleted = true;
}
}
}
Unfortunately this triple for loop leads to a memory exception - this is a high end PC however I will be forced to run my project on a laptop with 4GB ram.
With that in mind : is there a more memory efficient way of creating a vector3 grid.
Thanks in advance.
Typing failure in line
for(int h = 1;ResW <= GridHeight; h++)
Is causing your memory problems. The most inner loop runs infinitely, it should be ResH. Therefore I suggest to check the for-variable inside the for-statement and not something else:
for(int h = 1; h < wharever; h++)
secondly: bad code formatting and indentation.
Finally, so far, a list<object> is a 1D structure. A 3rd structure would be a list<list<list<object>>> or a array object [][][]:
Vector3 [][][] vector3grid;
vector3grid = new vector3[lenX][][];
for (int x=0; x<lenX; x++)
{
vector3grid[x] = new vector3 [lenY][];
for (int y=0; y<lenY; y++)
{
vector3grid[x][y] = new vector3 [lenZ];
// init if needed:
for(int z=0; ...
vector3grid[x][y][z] = ...
}
}
Edit:
I just noticed that my answer is not 100% correct. The sample above is 1 of 2 (or more) ways to create a 3D array. The easier one of them is following:
In C++/cli:
Array<vector3, 3>^ vector3grid = gcnew array<vector3, 3>(lenX, lenY, lenZ);
For c# and VB.net I need to look up the Syntax first.
This is a REAL 3D array now. ;-)
Edit 2:
3D in c#:
Vector3 [,,] vector3grid = New vector3[lenX,lenY,lenZ];
Having a slight c# problem here.
I'm currently coding a small platformer-game with Unity and I had some raycasts which checked collisions and such.
Now, I started to clean the code a bit, by storing the results of those raycasts into an integer array, but I'm getting a IndexOutOfRangeException.
I've tried to read through my code many times but can't seem to find what is causing the problem. If someone can help me out, I would be really glad.
Here's my code:
using UnityEngine;
using System.Collections;
public class PlayerRayCaster : MonoBehaviour {
public float playerHeight = 1;
public enum FeetState {Air, Ground};
public FeetState playerFeetState = FeetState.Air;
public int feetHitRays;
public int behindHitRay;
//Arrays of rays. value of 1 means that ray hits a target, 0 means that it does not hit.
public int[] sideRays; // [0-3] = Left side. [4-8] = Right side.
public int[] depthRays; // [0] = Away from camera. [1] = Towards camera.
public int[] feetRays;
public int counter;
void Start(){
sideRays = new int[8];
depthRays = new int[2];
feetRays = new int[3];
}
// Update is called once per frame
void Update () {
FeetRays();
SideRays();
BehindRay();
}
//Rays, which check if the character is bumping into an object, left or right.
void SideRays(){
float rayLength = 0.4f;
counter = 0;
//Left side rays.
for(int rayHeight = 0 ; rayHeight>=-4 ; rayHeight-=1 , counter++){
Debug.Log(sideRays[counter]);
if(Physics.Raycast(transform.position-new Vector3(0,rayHeight/2,0), new Vector3(-1,0,0),rayLength)){
sideRays[counter] = 1;
Debug.DrawRay(transform.position-new Vector3(0,rayHeight/2,0), new Vector3(-rayLength,0,0), Color.green);
}
else{
sideRays[counter] = 0;
Debug.DrawRay(transform.position-new Vector3(0,rayHeight/2,0), new Vector3(-rayLength,0,0), Color.yellow);
}
}
//Right side rays.
for(int rayHeight = 0;rayHeight>=-4;rayHeight-=1,counter++){
if(Physics.Raycast(transform.position-new Vector3(0,rayHeight/2,0), new Vector3(1,0,0),rayLength)){
sideRays[counter] = 1;
Debug.DrawRay(transform.position-new Vector3(0,rayHeight/2,0), new Vector3(rayLength,0,0), Color.green);
}
else{
sideRays[counter] = 0;
Debug.DrawRay(transform.position-new Vector3(0,rayHeight/2,0), new Vector3(rayLength,0,0), Color.yellow);
}
}
}
//Three rays, which check if the characters feet are on the ground or not.
void FeetRays(){
feetHitRays = 0;
float rayLength = 0.2f;
//Shoots three rays down from player.
for(float i=-0.7f;i<=0.7f;i+=0.7f){
if(Physics.Raycast(transform.position-new Vector3(i/2,0,0), new Vector3(0,-1,0),rayLength)){
feetHitRays++;
Debug.DrawRay(transform.position-new Vector3(i/2,0,0), new Vector3(0,-rayLength,0), Color.green);
}
else{
Debug.DrawRay(transform.position-new Vector3(i/2,0,0), new Vector3(0,-rayLength,0), Color.red);
}
}
//Sets the feet state.
if(feetHitRays==0)
{
playerFeetState = PlayerRayCaster.FeetState.Air;
}
else{
playerFeetState = PlayerRayCaster.FeetState.Ground;
}
}
//Shoots a raycast in z-direction from the character, to check for door access.
void BehindRay(){
behindHitRay = 0;
float rayLength = 2;
if(Physics.Raycast(transform.position, new Vector3(0,0,1), rayLength)){ //Away from camera
behindHitRay = 1;
Debug.DrawRay(transform.position, new Vector3(0,0,rayLength), Color.green);
}
if(Physics.Raycast(transform.position, new Vector3(0,0,-1), rayLength)){ // Towards camera.
behindHitRay = -1;
Debug.DrawRay(transform.position, new Vector3(0,0,-rayLength), Color.green);
}
}
}
This is the line that gives me the exception:
sideRays[counter] = 1;
Thanks in advance.
I believe this is the problem:
for(int rayHeight = 0 ; rayHeight>=-4 ; rayHeight-=1 , counter++)
You're basically doing that twice, and that means 10 iterations, whereas your array is initialized like this:
sideRays = new int[8];
You may well want:
// Note the > instead of >=
for (int rayHeight = 0; rayHeight > -4; rayHeight--, counter++)
(As an aside, I'd very strongly recommend that you don't use public fields, but that's a different matter.)
You declare sideRays with a size of 8, but it looks from a quick glance at your loops that counter can get as high as 10.
Check your bounds on for(int rayHeight = 0;rayHeight>=-4;rayHeight-=1,counter++){ You'll end up accessing the array 5 times for each loop and you've defined your array to have 8 items. Accessing 9 and 10 will throw an exception.