can't clear array of GameObjects in Unity - arrays

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

Related

Out of range exception in Unity

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);
}
}
}

Positioning Array Content (Sprites)

I have Pictures with Numbers on it (I mean Sprites).
I got them on an Empty GameObject, I mean [SerializeField] and added through the script (C# Ofcourse), So the Objects are not really there they are being Generated when the Game begins.
So as you can see in the Code that I can set Row and Columns Amount and with Offset also distances in X and Y Axis. But I cannot re-position it. It seems that the first one being generated is locked to the middle of the project (the first one up-Left)So I tried to move the gizmo of the empty gameobject but the sprites are still on the spot even if I use the Inspector Instead. It seems that it would need to be positioned it in the script, But How?
Please give me enough Examples witch will work with Unity?
What I tried is to position it in Unity as I already mentioned with moving the Gizmo of the Gameobject and also in the Inspector It really seems that it can only be done on the script (I might be wrong but I tried everything).
public class Controll : MonoBehaviour
{
public const int gridRows = 6;
public const int gridCols = 6;
public const float offsetX = 0.65f;
public const float offsetY = 0.97f;
[SerializeField] private GameObject[] cardBack;
// Use this for initialization
void Start ()
{
for (int i = 0; i < gridRows; i++)
{
for (int j = 0; j < gridCols; j++)
{
Instantiate(cardBack[i], new Vector3(offsetY*j, offsetX* i *-1 , -0.1f), Quaternion.identity);
}
}
}
You are instantiating all objects into the Scene root level. They are in no way related to the GameObject which was originally responsible for the instantiation.
If you rather want them to be positioned relative to the spawning GameObject then use
var position = transform.position + new Vector3(offsetY * j, offsetX * i * -1, -0.1f);
Instantiate(cardBack[i], position, Quaternion.Identity, transform);
in order to instantiate them as child objects of the GameObject this Controll script is attched to.
Now if you translate, rotate or scale that parent object all instantiated objects are transformed along with it.

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!

AS3- how to addchild this array(john) correctly

I do not know how to add the john array and make a hittestobject with it.
Bal is a different class non relevant to this problem.
I've tried to do john[new Bal]
tried john[ k ]
tried z and to specify z as a for-loop but then i would just get Z balls place.
This is supposed to become a space-invader type of game. I'm trying to make a hit test object between HENK and the 'falling balls' (JOHN). I do not know how to work with arrays especially given the fact that is should be timer-triggered.
Thanks
public class Main extends Sprite
{
public var henk:Sprite = new Sprite();
public var level:Timer = new Timer (2000, 0);
public var valTijd:Number = new Number
public var i:Number = 2000;
public var john:Array = new Array();
public var k:Number = 9000;
public function Main():void
{
henk.graphics.beginFill(0xFF00FF);
henk.graphics.drawCircle(0, 500, 20);
henk.graphics.endFill();
addChild(henk);
level.addEventListener(TimerEvent.TIMER, up);
level.start();
henk.addEventListener(Event.ENTER_FRAME, muis);
henk.addEventListener(Event.ENTER_FRAME, hit);
}
public function up(e:TimerEvent):void
{
var tijdje:Timer = new Timer( i, 0)
tijdje.addEventListener(TimerEvent.TIMER, tijdLuisteraar);
tijdje.start();
i = i - 250;
}
public function muis (e:Event):void
{
henk.x = mouseX;
}
public function hit (e:Event): void
{
if ( henk.hitTestObject(john [k] ))
{
if (contains(john[k] ))
{
removeChild(henk);
}
}
}
public function tijdLuisteraar(e:TimerEvent):void
{
john.push(new Bal);
addChild(john[k]);
}
}
}
welcome to stackoverflow!
This problem is actually fairly simple, I will describe how you will probably want to use an array in the case you described.
At the part where you create new Balls you want to append them to an array, which will be something like the following:
var ball = new Bal();
john.push(ball);
addChild(ball);
This will go inside your timer-triggered function, obviously.
Secondly, you want to have a hitTestObject with henk and all of the balls stored in the john array.
for(var i = 0; i < john.length; i++) {
if (henk.hitTestObject(john[i])) {
// well, that's a bummer for your player, henk hit one of the balls in the john array
// display something like a message here
}
}
This will automatically detect the size of the array, so all elements are tested. Be careful with hitTestObject when you have a lot of elements in the john-array, this can slow down your game drastically.
Furthermore, reflecting your code I suggest the following:
remove public var i:Number = 2000; and public var k:Number = 9000;, these have no meaning anymore
use a mouse event to move your henk object, not an ENTER_FRAME. I guess you will be able to find how this works. This will only trigger the function when it has to do something, resulting in less CPU-power needed and a cleaner code.
if you want to make the game even cooler, you could add the support for using the arrow keys

Actionscript 3 eventlisteners, hittestobject and arrays of custom objects

Another desperately stuck first year student here. And I have to use FlashCS as my coding environment. And it sucks. So I'll try some well constructed and clear questions. There is:
public var object: symbol1;
public var objectarray: Array = new Array();
in my main. Then a function there that uses a timer and spawns a new object and pushes it onto the array:
object = new symbol1;
objectarray.push(object)
but then when I trace() the .length of the array it displays TWO numbers of the array length every timer period in the output. As in:
1 1 2 2 3 3
etc. This is my first mystery. Why two not one? because there is no way I'm calling the function that includes the trace () twice. Also I think I need to be able to remove my object from the objectarray when it goes off the stage, but the objectarray.pop() doesn't seem to work if I use it like so in a function:
if (object.y == stage.stageHeight)
objectarray.pop()
As in I try trace() the array.length before and after the .pop(), but it just keeps going up by one every timer period.
And the other, bigger issue is I want to know if you are allowed to put the .addEventListeners that you usually place right under the main function of any class into a statement loop. As in I've got
class extends Main {
class function() {
for (var i:Number = 0; i < objectarray.length; i++){
objectarray[i].addEventListener(Event.ENTER_FRAME, collision);}}
And then, if it is allowed, the program doesn't seem to enter the collision function of this same class anyway.
function collision (event:Event) : void{
if (this.hitTestObject(object)){
trace('hit');}}
so I searched and ended up adding a
var clip:MovieClip = MovieClip(e.target);
in the first line of the function, but then it didn't work and I realized I on't understand what's it meant to do, what's going on anymore and what is the syntax for this casting.
Thank you very much.
Edit/Update: adding more of my code eventhough I hate copypasting it like this. This is the symbol class that is going to change when an object of another class hits it
public class Head extends Main {
public function Head(){
this.stop();
for (var i:Number = 0; i < nicesnowflakearray.length; i++){
nicesnowflakearray[i].addEventListener(Event.ENTER_FRAME, snowhit);
}
}
public function snowhit(event:Event) : void {
if (this.hitTestObject(nicesnowflake)){
//I changed this line to (e.currentTarget.hitTestObject(nicesnowflake)) as Atriace suggested, but nothing changed, and I just don't understand why my version wouldn't work.
trace("hit");
}
}
And this is the class that spawns the objects that are supposed to hit the Head object:
public class Main extends MovieClip {
public var nicesnowflake: fallingsnow;
var nicesnowflakespawntimer: Timer = new Timer(1000);
public var nicesnowflakearray: Array = new Array();
public function Main() {
nicesnowflakespawntimer.addEventListener(TimerEvent.TIMER, nicesnowflakespawn);
nicesnowflakespawntimer.start();
}
public function nicesnowflakespawn(event:TimerEvent) : void {
nicesnowflake = new fallingsnow;
nicesnowflake.x = Math.random()* stage.stageWidth;
nicesnowflake.y = - stage.stageHeight + 100;
nicesnowflakearray.push(nicesnowflake);
stage.addChild(nicesnowflake);
trace(nicesnowflakearray.length);
}
Why two, not one?
Anytime you extend another class, it implicitly calls the parent class' constructor. We know this as super(), and can be quite handy. This is why you're getting doubles on your trace statement. Technically, you can choose not to call super().
.pop()
It should remove the last element from that array, however, I'm thinking that if an arbitrary object leaves the stage, you can't be gauranteed it'll be the last element. Ergo, you want splice()
if (object.y == stage.stageHeight) {
objectarray.splice(objectarray.indexOf(object), 1)
}
Event Listeners
I didn't follow your quandary, so I'll just try to rewrite what I think you were trying to do.
package {
import flash.display.MovieClip;
public class Main extends MovieClip {
private var objectarray:Array = []; // Note, I haven't populated it with anything, I'm assuming you have.
private var theWall:MovieClip = new MovieClip(); // I haven't added this to the stage, or given it shape. You need to for hitTestObject to work.
public function Main() {
// This is your constructor.
for (var i:Number = 0; i < objectarray.length; i++) {
objectarray[i].addEventListener(Event.ENTER_FRAME, collision);
}
}
private function collision(e:Event):void {
if (e.currentTarget.hitTestObject(theWall)) {
trace('hit');
}
}
}
}
Of note, you may want to look at a guide to hitTestObject() if it's giving you issues.

Resources