This question already has answers here:
What is an IndexOutOfRangeException / ArgumentOutOfRangeException and how do I fix it?
(5 answers)
Closed 3 years ago.
Array index is out of range in Unity, need some help!
void OnCollisionEnter2D(Collision2D col) {
rigidbody2D.velocity = new Vector2(0, 0);
transform.rotation = Quaternion.Euler (0, 0, headDownAngle);
if(!isDied) {
audios[1].Play();
animator.SetTrigger("dead");
iTween.ShakePosition(Camera.main.gameObject, new Vector3(0.3f, 0.3f, 0), 0.5f);
}
isDied = true;
isPlaying = false;
I don't see any other arrays being used (Unless one of your other functions use arrays) so it seems this line is causing the error:
audios[1].Play();
Remember Arrays are zero based so the first position in an array is actually 0, so if you are trying to get the first element do:
audios[0].Play().
If you are trying to get the second element, make sure audios has 2 elements.
Array index is out of range is an error caused when you try to use a part of an array that doesn't exist
example
float numOfTests = 2;
AudioSource[numOfTests] tests;
void Start()
{
tests[3].play();
}
since there are only 2 audio sources in the array we can access a third one because it doesn't exist.
I hope this is helpful. I used to code in unity put I moved over to c++ and writing custom engines so if my answer doesn't help that might because I haven't used unity in a year.
Related
I am trying to create a circle out of vertices based on certain parameters like subdivision or radius. This time I have been avoiding using tutorials as a crutch as I haven't been able to learn C# by not actually working with it. I finished this bit of code and got stuck on the console errors because I am a beginner with troubleshooting. Would any of you be able to help me understand what they mean?
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
[RequireComponent(typeof(MeshFilter), typeof(MeshRenderer))]
public class circleVerts : MonoBehaviour
{
private void Update () {
Generate();
}
private void Generate () {
GetComponent<MeshFilter>().mesh = mesh = new Mesh();
mesh.name = "Procedural Circle";
public int radiusR = 2;
public float nTimes = 1.0f; //# of subdivisions, cannot equal 0
public int numPlayers = 4;
public float thetaT = (Mathf.Pow(2, nTimes) / Mathf.Pow(numPlayers, nTimes)) * Mathf.PI;
vertices = new Vector3[(Mathf.Pow(2, nTimes - 1)) + 2];
for (int i = 0; i <= vertices.length; i++)
{
float x = Mathf.Cos(thetaT) * radiusR;
float y = Mathf.Sin(thetaT) * radiusR;
vertices[0] = new Vector3(0,0,0); //setting origin
vertices[1] = new Vector3(radiusR, 0, 0); //first vert is located at x-radius
vertices[i] = new Vector3(x, 0, y);
Gizmos.DrawSphere(vertices[i].position, 1);
}
mesh.vertices = vertices;
}
}
Very glad you are trying to do things by yourself, but it seems you lack basic grasp of C# syntax. Maybe instead of tutorials of how to achieve something, try tutorials on language itself.
With that out of the way, let's look at your issue.
There's really no point of addressing every error as they are caused by wrong syntax, and the problems just cascade further. They create even more bizarre errors, which seemingly makes no sense, like you certainly didn't mean to use tuples. It will be better if I just explain what's wrong with the code and why.
GetComponent<MeshFilter>().mesh = mesh = new Mesh(); - do you want to create new Mesh, or get the component of an existing one? Probably the latter. Create Mesh variable, and assign to it the result of GetComponent method like this: Mesh mesh = GetComponent<MeshFilter>().mesh;
Access modifiers shouldn't be used inside a method. When the method ends, the variables will be gone, so marking them public wouldn't make much sense anyway. Either declare them inside class body, or remove access modifiers (public).
vertices = new Vector3[(Mathf.Pow(2, nTimes - 1)) + 2]; You must first declare vertices variable before using it Vector3 vertices. This assignment is at least weird, check following points.
You are trying to use [] like you were working with an array, while you create a new Vector3 not an array of Vector3. Moreover, Vector3 doesn't have a constructor that accepts only one argument. Decide whether you want to use a Vector or an array of Vectors.
vertices[0] again, you are using your Vector as an array. If you want to access a Vector3, do it by using vertices.x or vertices.y. If you want to create and access an array, go checkout how to do it.
Good luck on your learning path :)
The "problem"
I appreciate this is similar to a question that has been asked many times before, I am aware of why this "problem" exists but I am now just trying to find a way to mitigate it.
Using Unity's transform class as an example, as we all likely know to change one of it's Vector3's position axis on it's own like x, y or z requires 3 lines of code, something similar to:
Vector3 position = transform.position;
position.x = 100f;
transform.position = position;
This will always be the case because it is using a getter so cannot be set, in other words we have to replace the entire position struct rather than modify it while attached to the transform object. There is something about this that just doesn't "feel nice", having to use 3 lines, create a new variable each time just to set it instantly and use it then be done with it, I hope I'm not the only one that feels this way! I have gone about a few different ways of trying to turn this into a one liner. One option is by adding extension methods for each internal value such as:
/* Transform
------------------------------------------*/
public static void SetX(this Transform transform, float x) {
Vector3 position = transform.position;
position.x = x;
transform.position = position;
}
public static void SetY(this Transform transform, float y) {
Vector3 position = transform.position;
position.y = y;
transform.position = position;
}
And can be used like this:
transform.SetX(100f);
However this keeps on coming up with other objects in Unity like Color/Color32 and a few others that are commonly used, and it would be nice to have a catch all solution, rather than having to write an extension method for every single internal value of every single struct like this.
My attempt at turning this into a one liner: Please know that I am aware my soltion below is pretty hideous, however it does work:
public static T ModifyInternalValue<T>(T obj, Func<T, T> action)
{
return action.Invoke(obj);
}
And this would be used like so:
transform.position = ModifyInternalValue<Vector3>(transform.position, p => {p.x = 100f; return p;});
It is disgusting in alot of ways, but my final question is quite simple:
Is there a way of simplifying this process? Neatening it up or making a short one liner for assigning a struct's internal values?
Thanks in advance for any advice :)
In C# 10, with expressions can be used on structs too:
transform.position = transform.position with { x = 100 };
That is a lot shorter than your ModifyInternalValue.
However, I don't think Unity supports C# 10 at the time of writing.
Before C# 10, with expressions only work with records, unfortunately.
Do note that both Vector3 and Color provide overloaded operators and static fields for unit vectors. You can also do this, which is also a similar length:
// using static UnityEngine.Vector3;
transform.position += (transform.position.x - 100) * left;
A similar thing can be done with Color with red, green and blue, though whether that is readable is questionable.
transform.position = new Vector3(100, transform.position.y, transform.position.z);
I'm trying to let a cube drop in unity when i call Input.GetKeyDown("space"), and when a cube is dropped, the second cube is generated and drop again when the space is pressed, however, when I press it again it doesn't work, here is my code
void Update ()
{
if (Input.GetKeyDown("space"))
{
if (!ss)
{
shabi.useGravity = true;
shabi.AddForce(0, 0, -100);
ss = true;
}
}
if (cube1.transform.position.y == y)
{
if (!singleExecution)
{
Rigidbody newCube = spawn();
if (Input.GetKeyDown("space")) //THE PART THAT DOESN'T WORK
{
Debug.Log("sb");
newCube.useGravity = true;
newCube.AddForce(0, 0, -100);
}
y++;
//cubeY += 2;
singleExecution = true;
}
}
}
The function spawn() is used for generate another cube, and the second Input.GetKeyDown doesn't work, thank you for answering my question
I think the problem actually already lies in the line before:
if(cube1.transform.position.y == y)
Since your first object uses gravity, what are the odds that the position in one frame matches exactly y? Additionally comparing two float values might never match even if the value should be the same, see Math.Approximately for more information on that.
This will almost never be true so your code doesn't even reach the Input part.
Now you could ofcourse use
if(Math.Approximately(cube1.transform.position.y, y)
trying to still match an exact y value but the odds that this matches on a free falling object are still very small!
Instead you should use a qualitative comparison like <=. You can either use a wider approximation using the difference between the two values (in this example it matches while the object is less then +-10cm appart from the expected y):
if(cube1.transform.position.y - y <= 0.1f)
but for fast moving objects (which is usually the case for free falling ones) it might be better to simply check if it is smaller than the desired height:
if(cube1.transform.position.y <= y)
This depends obviously on what exactly your purpose is here.
This question already has answers here:
Collection was modified; enumeration operation may not execute
(16 answers)
Closed 5 years ago.
I'm trying to build my unity project, however I can't as there is a problem with a foreach loop. Just below is the error code I'm receiving, but I don't understand it. Would anyone be able to explain what a possible a solution might be? Or why this error occurs?
InvalidOperationException: Collection was modified; enumeration operation may not execute.
System.Collections.Generic.List`1+Enumerator[UnityEngine.Vector3].VerifyState () (at /Users/builduser/buildslave/mono/build/mcs/class/corlib/System.Collections.Generic/List.cs:778)
System.Collections.Generic.List`1+Enumerator[UnityEngine.Vector3].MoveNext () (at /Users/builduser/buildslave/mono/build/mcs/class/corlib/System.Collections.Generic/List.cs:784)
Player_Movement.Update () (at Assets/Scripts/Player/Player_Movement.cs:46)
To give context to be code you draw a line on the screen and it creates a list of vectors for the player to move through.
void Update()
{
//when the player moves their finger accross the screen of the mouse button is held down
if ((Input.touchCount > 0 && Input.GetTouch(0).phase == TouchPhase.Moved) || (Input.GetMouseButton(0)))
{
//raycasthit variable called hit
RaycastHit hit;
//ray variable called ray
Ray ray;
//the ray variable is cast between the main camera and the mouse position
ray = Camera.main.ScreenPointToRay(Input.mousePosition);
//if the physics racast hit then calulate the distance betwen the point (mouse position) and the camera
if (Physics.Raycast(ray, out hit))
{
//save the positon as the nextPosition
nextPosition = hit.point;
//save the nextPositions point's yaxis
nextPosition.y = yAxis;
//if there are positions inside of the position list
if (positionList.Count != 0)
{
//then for each vector3 position in the list
Line 46 ===> foreach(Vector3 t in positionList)
{
//if there is no posiiton in the list where one should be
if (nextPosition != t)
{
//then create a position
positionList.Add(nextPosition);
}
}
}
else
{ //otherwise create a position in the position list
positionList.Add(nextPosition);
}
}
}
}
The reason that you're getting that exception is that you're trying to modify a collection while you're iterating over it. There are a few ways you can get around this, but probably the best way is to simply test your condition (does the collection contain a specific item) and then modify the collection (add the item) if the test is false.
The Linq extension Any comes in handy here. It returns true if any item in the collection matches the condition. Putting a ! in front of it means you're looking for the case where there are NOT Any items that match the condition:
if (!positionList.Any(position => position == nextPosition))
{
positionList.Add(nextPosition);
}
But you can do this without Linq also, using the Contains method, which is actually simpler and arguably more readable:
if (!positionList.Contains(nextPostition))
{
positionList.Add(nextPostition);
}
Note that these answers are also fixing a bug in your code as well. To expose the bug and still avoid the error, you can call ToList() on the collection inside the for loop, like so:
foreach(Vector3 t in positionList.ToList())
{
//if there is no posiiton in the list where one should be
if (nextPosition != t)
{
//then create a position
positionList.Add(nextPosition);
}
}
The call to ToList() here actually creates a new copy of the list and iterates over that one, so there is no conflict when the original one is modified. However, you will notice that your existing code will add nextPosition to the list every time it encounters a non-match, which I don't think is your intended behavior.
You can't modify a list (ie .Add() to it) while iterating over it.
Find your matching element, then add if necessary:
if(positionList.FirstOrDefault(t => nextPosition == t) != null)
positionList.Add(nextPosition);
This question already has answers here:
What is a NullReferenceException, and how do I fix it?
(27 answers)
Closed 8 years ago.
I'm currently working on a xna project, a 2D game. My problem is that when I want the bullet(poop) to appear after I pressed the Up key, i receive the error in the line which is giving the initial position to the Vector2 of my bullet(poop).
// for each bullet in the list, update it
foreach (Poop p in poopList)
{
p.Update(gameTime);
}
In the Poop class, in the update method, i have a case, depending on the direction in which the bullet should go:
Top (1)
Right (2)
Down (3)
Left (4)
case 1:
position = new Vector2(monitoPosition.X + monitoTexture.Width / 2 - poopTexture.Width / 2, monitoPosition.Y + monitoTexture.Height / 2);
position.Y = position.Y - speed;
if (position.Y <= 0 || position.Y >=500)
isVisible = false;
if (position.X <= 0 || position.X >= 800)
isVisible = false;
break;
So in the line, in which I assign a new position to the bullet(poop), it throws the error.
Please Help
A variable in your code is null, meaning you will get an Object reference not set an instance of an Object error, because it is basically nothing. See this StackOverflow question for more info.
Double check that all your variables are assigned to.
Assuming you are talking about this line:
position = new Vector2(monitoPosition.X + monitoTexture.Width / 2 - poopTexture.Width / 2, monitoPosition.Y + monitoTexture.Height / 2);
Make sure that monitoPosition and poopTexture are set. You can set a breakpoint on this line to pause the code, and hover over the variables to see if they are null.