Out of range exception in Unity - arrays

I create a game in Unity. And I got this error:
System.ThrowHelper.ThrowArgumentOutOfRangeException (System.ExceptionArgument argument, System.ExceptionResource resource)
Here is my short code:
public class OnlineGame : MonoBehaviour
{
private List<GameObject> domino = new List<GameObject>(7);
public void Start()
{
StartGame();
}
private void StartGame()
{
for (int i = 0; i < 7; i++)
{
domino[i] = Instantiate(dominoPrefab, new Vector3(11, 0, 0), Quaternion.identity) as GameObject;
}
}
}
If you need more details, write a comment. Thanks for help

private List<GameObject> domino = new List<GameObject>(7)
new List<T>(int capacity) constructor doesn't mean the resulting list will have hold capacity objects at beginning. The Count of elements in the list will still be 0.
When you use List class in c#, it will have capacity memory reserved for the list. When you add some elements to the list and its Count reaches capacity(or close to it, I'm not exactly sure), the list will automatically increase capacity by allocating additional memory so that you can add additional element to the list.
Usually when you use new List<T>() the list will have initial capacity of 0 where program doesn't know how many Count the list can possibly have and will dynamically adjust capacity to match your need.
Using new List<T>(int capacity) is like telling the program that the list will have at most capacity number of elements and list should have that capacity ready to avoid overhead of allocating more memory. Of course, when list's Count reach capacity it will increase as well.
To fix your problem, use Add method instead of assigning to array slot.
public class OnlineGame : MonoBehaviour
{
private List<GameObject> domino = new List<GameObject>(7);
public void Start()
{
StartGame();
}
private void StartGame()
{
for (int i = 0; i < 7; i++)
{
// domino[i] = Instantiate(dominoPrefab, new Vector3(11, 0, 0), Quaternion.identity) as GameObject;
domino.Add(Instantiate(dominoPrefab, new Vector3(11, 0, 0), Quaternion.identity) as GameObject);
}
}
}

Related

can't clear array of GameObjects in Unity

could someone please tell me why after clearing array and checking it again, i'm not getting length == 0?
public class test : MonoBehaviour
{
public GameObject[] allWayPoints;
public GameObject wayPoint;
void Start()
{
for(int i = 0; i < 10; i++)
{
GameObject pathPrefab = Instantiate(wayPoint, new Vector3(0, 0, 0), Quaternion.identity);
pathPrefab.tag = "PathPoint";
}
allWayPoints = GameObject.FindGameObjectsWithTag("PathPoint");
Debug.Log(allWayPoints.Length);
allWayPoints = GameObject.FindGameObjectsWithTag("PathPoint");
foreach (GameObject go in allWayPoints)
{
Destroy(go);
}
allWayPoints = new GameObject[0];
Debug.Log(allWayPoints.Length);
allWayPoints = GameObject.FindGameObjectsWithTag("PathPoint");
Debug.Log(allWayPoints.Length);
}
}
Debug.Log
Array
The only time length of the array will be 0 is when you explicitly set it to 0, as you can see in your logs.
When you destroy a GameObject, it isn't immediately removed either, and destroying a GameObject doesn't make the array smaller. Since the GameObject isn't immediately removed, you still find the old "to be removed" references from the scene.
An array is a collection with a fixed number of values/indexes, and it's length will always be as long as it was on creation as it occupies a specific piece of memory regardless of its actual content.
See fiddle here, array with only nulls still has the same length as it had upon creation, even though it's effectively empty.
https://dotnetfiddle.net/VmigUO

How do I restrict one random prefab to be used only once but placed randomly with a whole bunch of prefabs of arrays on top of other object?

How do I restrict one random prefab to be used only once but placed randomly with a bunch of prefabs of arrays on top of other object?
using System.Collections.Generic;
using UnityEngine;
public class LevelRoomsScript : MonoBehaviour
{
[SerializeField]
private GameObject[] memberWoodArray = null;
[SerializeField]
private GameObject[] memberRoomPrefabArray = null;
void Start()
{
foreach (GameObject localWood in memberWoodArray)
{
int localNumRoomPrefab = memberRoomPrefabArray.Length;
int localRoomIndex = Random.Range(0, localNumRoomPrefab);
GameObject localRoomPrefab = memberRoomPrefabArray[localRoomIndex];
Instantiate(localRoomPrefab, localWood.transform.position, Quaternion.identity);
}
}
}
The way I understand your question is that you want to instantiate each element in memberRoomPrefabArray at most once.
You could create a temporary list that is a copy of memberRoomPrefabArray and remove each element that is instantiated before the next loop cycle.
void Start()
{
List<GameObject> temp = new List<GameObject>(memberRoomPrefabArray);
foreach (GameObject localWood in memberWoodArray)
{
int localRoomIndex = Random.Range(0, temp.Count);
Instantiate(temp[localRoomIndex], localWood.transform.position, Quaternion.identity);
temp.RemoveAt(localRoomIndex);
}
}
You might want to add some checks like if (temp.Count == 0) { break; } if it's possible for memberRoomPrefabArray to be shorter than memberWoodArray.
Edit: Changed Random.Range(0, temp.Count - 1) to Random.Range(0, temp.Count) since, apparently, it's only maximally inclusive with floats and not integers.
You rather want to "shuffle" the array once and then iterate the shuffled array e.g. using Linq OrderBy and using Random.value as order like
using System.Linq;
...
void Start()
{
if(memberRoomPrefabArray.Length < memberWoodArray.Length)
{
Debug.LogError($"Not enough prefabs available for {memberWoodArray.Length} unique spawns!", this);
return;
}
// as the method names suggest this will be a randomized array of the available prefabs
var shuffledPrefabs = memberRoomPrefabArray.OrderBy(m => Random.value).ToArray();
for (var i = 0; i < memberWoodArray.Length; i++)
{
// Since the array is already shuffled we can now go by consecutive order
Instantiate(suffledPrefabs[i], memberWoodArray[i].transform.position, Quaternion.identity);
}
}

Unity prefab array instantiate and destroy

I am having a very little problem in my Unity project but can't find a proper help or way to do. I am stuck at point where I have an array of prefab GameObjects and I am trying to instantiate index 1 GameObject and when it destroyed instantiate the next index. Here is how I am doing it. I have two scripts: One to instantiate and other one to destroy it.
Scripts 1:
public class GameObjectsArray : MonoBehaviour {
public static GameObjectsArray Instance { get; set; }
public GameObject[] Objects;
public int i=0;
// Use this for initialization
void Start()
{
InstiatingMethod();
//Instantiate(Objects[i]);
}
public void InstiatingMethod()
{
Instantiate(Objects[i]);
}
}
Scripts 2:
public class CheckDestroy : MonoBehaviour {
//public GameObject[] Objects;
//int i;
// Use this for initialization
void Start () {
Debug.Log("executed");
//Objects = GameObject.FindGameObjectsWithTag("Player");
//OnMouseDown();
//Instantiate(Objects[i], transform.position, transform.rotation);
}
// Update is called once per frame
void Update () {
if (Input.GetMouseButtonDown(0))
{
RaycastHit hit;
Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
if (Physics.Raycast(ray, out hit))
{
BoxCollider boxCollider = hit.collider as BoxCollider;
if (boxCollider != null)
{
GameObjectsArray.Instance.i++;
GameObjectsArray.Instance.InstiatingMethod();
Destroy(boxCollider.gameObject);
}
}
}
}
}
So I created a very quick project to make a good response:
Scene Image
In the scene, we will have an empty game object that will contain our script that I called "GameManager", basically this script will do everything, it's more logic to put your logic in one script.
public GameObject[] GameObjects;
private int _targetIndex = -1;
private RaycastHit _hit;
private void Start()
{
InstantiateNextGameObject();
}
public void InstantiateNextGameObject()
{
//if the index is pointing at the last game object in the array, init the index to -1
if (_targetIndex == GameObjects.Length - 1)
_targetIndex = -1;
Instantiate(GameObjects[++_targetIndex]);
}
private void Update()
{
if (Input.GetKeyDown(KeyCode.Mouse0))
{
Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
if (Physics.Raycast(ray, out _hit))
{
BoxCollider boxCollider = _hit.collider as BoxCollider;
if (boxCollider != null)
{
InstantiateNextGameObject();
Destroy(boxCollider.gameObject);
}
}
}
}
we will have an array of gameobjects following with the targetIndex which will start from -1.
The function InstantiateNextGameObject() will simply increment targetIndex and then instantiate a gameobject from the array (++targetIndex the first time will be 0, second time 1 etc). We have to check also if the targetIndex reaches the end of the array, put it back to -1.
Then basically what you did in the update, when you click on a gameobject, instantiate the next one and destroy the current.
At the end, you will get something like that:
https://ayoub-gharbi.org/youba_docs/stackoverflow/stackoverflow01.mp4
Feel free to ask me if you didn't understand anything:)
Happy coding!

Allowing User to Select multiple items in a GridView

Very new to coding through Android with no knowledge of Java watsoever. I've been putting together pieces through other questions posted but I'm struggling.
I created an array called 'images2' at the top of my OnCreate method and put a bunch of colors from my drawable into it, one by one. That part works great but I've been trying to create an onClickListner that has an OnClick method that changes the drawable when you click on it to another color. I want them all to change to the same color. I know that I can set the selector programmatically: gridview2.setSelector(new ColorDrawable(Color.BLACK)); but change the selector, either in the backend or XMl code doesn't help me get the new drawable to stick. So I created another listArray in the adapter and I can call it in the main. I have an index in the onClick that will go through all 25 possible item positions and I want to make it so that it will change the drawable to each position that is in the array. It also adds the current position clicked into the array myarray.add(position); but I just realized that value might not be being saved. The arrayList is declared public but it is declared public within the adapter so do changes in the OnCreate have no effect? I'm sorry. THAT is definitely a noobinoob-noob question.
/**
* Created by Jordan on 3/25/2017.
*/
public class Welcome extends AppCompatActivity implements AdapterView.OnItemClickListener {
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.welcome);
final List<Integer> images2 = new ArrayList<Integer>();
images2.add(R.drawable.grid1);images2.add(R.drawable.grid6);
images2.add(R.drawable.grid2);images2.add(R.drawable.grid2);
images2.add(R.drawable.grid3);images2.add(R.drawable.grid1);
images2.add(R.drawable.grid4);images2.add(R.drawable.grid3);
images2.add(R.drawable.grid5);images2.add(R.drawable.grid2);
images2.add(R.drawable.grid6);images2.add(R.drawable.grid6);
images2.add(R.drawable.open);images2.add(R.drawable.grid4);
images2.add(R.drawable.grid1);images2.add(R.drawable.grid1);
images2.add(R.drawable.grid6);images2.add(R.drawable.grid4);
images2.add(R.drawable.grid4);images2.add(R.drawable.grid2);
images2.add(R.drawable.grid3);images2.add(R.drawable.grid3);
images2.add(R.drawable.grid6);images2.add(R.drawable.grid1);
images2.add(R.drawable.grid5);
this.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
final GridView gridview2 = (GridView) findViewById(R.id.welcomeGrid);
final Welcome.ImageAdapter mAdapter = new Welcome.ImageAdapter(this, images2);
gridview2.setAdapter(mAdapter);
gridview2.setChoiceMode(GridView.CHOICE_MODE_MULTIPLE);
gridview2.setItemChecked(2, true);
gridview2.setOnItemClickListener(this);
gridview2.setOnItemClickListener(new AdapterView.OnItemClickListener() {
public void onItemClick(AdapterView<?> parent, View v, int position, long id) {
// ArrayList<Integer> clickedStatus = new ArrayList<Integer>();
ArrayList<Integer> clickedStatus = new ArrayList<>(25);
clickedStatus.add(position);
if (position == 12){
setContentView(R.layout.login);
}
else if(position != 12) {
// no matter, whether the item has already been clicked or not I want this toast to pop up to promp the user to actually enter the app and sign in
Toast.makeText(Welcome.this, "You selected " + position+ ".. Please select middle tile to enter!",
Toast.LENGTH_SHORT).show();
if(clickedStatus.contains(position)){
// as soon as it's noticed that the an integer matching the current position is currently stored in the
// array list (clickedStatus), I want it removed right below
// was passing item in place of position into the remove(). Don't know why Integer item = (Integer) parent.getItemAtPosition(position);
//I want to go through 25 numbers and
for(int i=0; i<25;i++ ){
// compare those ints to what is in contained in the clickedstatus
if(clickedStatus.contains(i)){
// Drawable Marker = getResources().getDrawable(R.drawable.celeb1);
images2.set(i, R.drawable.celeb1);
//for every int that is stored in click status I want
// to call the item and change the background of that item to a specified drawable file.
}
}
}
else {
clickedStatus.add(position);
// images2.set(position, );
for(int i=1; i<25;i++ ){
// compare those ints to what is in contained in the clickedstatus
if(clickedStatus.contains(i)){
// Drawable Marker = getResources().getDrawable(R.drawable.celeb1);
images2.set(i, R.drawable.celeb1);
//for every int that is stored in click status I want
// to call the item and change the background of that item to a specified drawable file.
}
}
}
// gridview2.setSelector(new ColorDrawable(Color.BLACK));
// mAdapter.notifyDataSetChanged();
}
}
}
);
}
// I think this got generated automatically at some point somehow. Might of been with the multichoicemode line above ^
#Override
public void onItemClick(AdapterView<?> adapterView, View view, int i, long l) {
}
public class ImageAdapter extends BaseAdapter {
private Context mContext;
//IMAGES ARE REFERENCED HERE V---
private List<Integer> mImages2;
public ArrayList<Integer> clickedStatus = new ArrayList<Integer>();
//create array to store whether an item has been clicked or not. needs to be public!!
//check to determine the case in the below method
// IGNORE THIS
// private int selectedPosition = -1;
//public void setSelectedPosition(int position) {
// selectedPosition = position;
//}
public ImageAdapter( final Context c, final List<Integer> images2){
mContext = c;
mImages2 = images2;
}
public int getCount() {
return mImages2.size();
}
public Object getItem(int position) {
return position;
}
public long getItemId(int position) {
return 1;
}
// create a new ImageView for each item referenced by the Adapter
public View getView(int position, View convertView, ViewGroup parent) {
ImageView imageView;
if (convertView == null) {
// if it's not recycled, initialize some attributes
imageView = new ImageView(mContext);
imageView.setLayoutParams(new GridView.LayoutParams(140, 120));
imageView.setScaleType(ImageView.ScaleType.CENTER_CROP);
imageView.setPadding(0, 0, 0, 0);
} else {
imageView = (ImageView) convertView;
}
if(clickedStatus.contains(position)){
convertView.setSelected(true);
convertView.setPressed(true);
convertView.setBackgroundColor(Color.GREEN);
}
imageView.setImageResource(mImages2.get(position));
return imageView;
}
;}
}
I created and finalized a different set of Arrays for holding every possible five combinations of selections that would result in a win. Titled Diagonal (1, 2, 3, 4, 5), Horizontal(1, 2, 3, 4, 5) , Vertical (1, 2, 3, 4, 5), etc. Upon click a value is stored at the appropriate position of the ListArray and I have relative checks (if statements) that loops everytime the button is click. Does not slow the app down substantially, looks ugly on paper but is very functional without the use of checkboxes. If anybody is interested in seeing the code they may comment.

Giving each object that share the same class, their own individual variables that won't affect the other variables

Good Evening/ Morning.
This is a games related question.
I am facing an issue where I have three objects, (three goblins) data typed to the same class.
These three objects are in an array and data typed to that class, and initialized as the array.
private var goblin1:Goblin = new Goblin();
private var goblin2:Goblin = new Goblin();
private var goblin3:Goblin = new Goblin();
So the variables above have been then placed into an array.
private var aGoblinArray = new Array(container.goblin1, container.goblin2, container.goblin3);
After placing the objects into an array I have looped through all of my goblins.
for (var i:int = 0; i < aGoblinArray.length; i++)
{
var goblin:Goblin = aGoblinArray[i];
}
now I have a hitTest in the for loop and the hitTest is:
if (goblin.hitTestPoint(_character.x + 100, _character.y - 45, true))
{
goblinCanMove = false;
trace("lance hits");
//hitOnce
if (!hitOnce)
{
hitOnce = true;
trace("take on damage");
}
goblin.moveBack();
goblin.minusHealth();
}
This means if this player hits any of the goblins, they will do this function.
How ever in the goblin class.
public static var goblinLife; int;
goblinLife = 2;//put in main constructor
public function minusHealth():void
{
goblinLife --;
checkDeath();
}
private function checkDeath():void
{
if (goblinLife == 0)
{
parent.removeChild(this);
}
}
the problem is, if I hit goblin1, then goblinLife would = 1. This means all othet goblins(goblin2 and 3) will have 1 life. Since they share the same class.
if goblin1 dies, he is removed and the var goblinLife would = 0;
Now I can reset it back to 2, but this will fix half of the problem.
My question is, is there a way on how I can make sure each goblin has it's own individual life system. Thank you in advance.
Thank you very much Pan and Marty!
Static meant that it could be changed from any class and any function.
Private means that it will be protected to each individual goblin.
From changing
public static var goblinLife; int;
to
private var goblinLife; int;
it means that each individual goblin will have their own variable, that no other class or object of the same class can change.
Thank you Pan and Martyn. I guess I need to read AS3 101: Quick Tip – When to Use Static Properties and Methods and other coding books!

Resources