Be a Supporter!

Disabling hitTestObject from object

  • 506 Views
  • 22 Replies
New Topic Respond to this Topic
jeteran
jeteran
  • Member since: Feb. 10, 2011
  • Offline.
Forum Stats
Member
Level 01
Game Developer
Disabling hitTestObject from object 2012-08-23 18:01:48 Reply

Hello everyone.

I came up with a little problem. Let me explain the whole situation.

I'm making a game that has 2 arrays, one for an inventory and one that keeps track of the objects in the game.

The thing is that I want the inventory objects, if they touch the objects in the game, dissapear.

So far so god. Let me show you:

if (mission1[i].hitTestObject(event.currentTarget.valueOf())) {
						event.currentTarget.valueOf().removeEventListener(MouseEvent.MOUSE_UP, invObjectFree);
						event.currentTarget.valueOf().visible = false;
						trace("Nice");
					}

That code is inside a for, that reads all the objects available in the game. If the inventory object is release over a mission1[i] object, it disappear.

This works GREAT. Now I want that, when is not over a mission1[i] object, go back to it's place.

I did this:

else
					{
						trace("GOOD");
						event.currentTarget.valueOf().x = event.currentTarget.valueOf()._x;
						event.currentTarget.valueOf().y = initialPositionY;
					}

But this is not working correctly, sometimes it disappear and sometimes don't. I think is because it's reading all the mission[i] objects at once. When I didn't have the objects of the mission array, it worked perfectly, now with mission[i] it doesn't.

Can you guide me??

Thanks so much guys for your help !!

theCodeCat
theCodeCat
  • Member since: Feb. 24, 2009
  • Offline.
Forum Stats
Member
Level 04
Programmer
Response to Disabling hitTestObject from object 2012-08-23 20:04:34 Reply

I'm guessing you have this code within a loop (for "i") in a function which is triggered by an event (Enter Frame?).

Right now you are making the target object check for a collision with each object in the array and have it make a decision on its state after EVERY collision check.

Your target object can only be in one of those states, and the state will always get set to something after each collision check. So what the state is before a collision check doesn't matter.

I'm bad at explaining this stuff, in short: Only the last collision check in your loop makes a difference because the decisions made by the other collision checks just get overwritten.

You want your object to go to state 1 if there is ANY collision, and to state 2 if there is NO collision.

The way I would program this is to have a boolean-type variable called something like "isCol" which is false at the beginning of the function. Then you loop through the array and check for collisions.
If there is a collision you set the objects state, set "isCol" to true, and exit the loop. If there isn't a collision, just do nothing.

Then after the loop is complete you set the objects to state 2 if there were no collision (if "isCol" is false).

Something like:

var isCol:Boolean = false;

for(var i:int = 0; i<a.length; i++){
if(collisionWithObject){

SetToStateOne();

isCol = true;

break;
}
}

if(isCol == false){
SetToStateTwo();
}


You forgot to use code tags, didn't you?

jeteran
jeteran
  • Member since: Feb. 10, 2011
  • Offline.
Forum Stats
Member
Level 01
Game Developer
Response to Disabling hitTestObject from object 2012-08-23 20:25:54 Reply

At 8/23/12 08:04 PM, XJ-47 wrote: I'm guessing you have this code within a loop (for "i") in a function which is triggered by an event (Enter Frame?).

Right now you are making the target object check for a collision with each object in the array and have it make a decision on its state after EVERY collision check.

Your target object can only be in one of those states, and the state will always get set to something after each collision check. So what the state is before a collision check doesn't matter.

I'm bad at explaining this stuff, in short: Only the last collision check in your loop makes a difference because the decisions made by the other collision checks just get overwritten.

You want your object to go to state 1 if there is ANY collision, and to state 2 if there is NO collision.

The way I would program this is to have a boolean-type variable called something like "isCol" which is false at the beginning of the function. Then you loop through the array and check for collisions.
If there is a collision you set the objects state, set "isCol" to true, and exit the loop. If there isn't a collision, just do nothing.

Then after the loop is complete you set the objects to state 2 if there were no collision (if "isCol" is false).

Something like:

var isCol:Boolean = false;

for(var i:int = 0; i<a.length; i++){
if(collisionWithObject){

SetToStateOne();

isCol = true;

break;
}
}

if(isCol == false){
SetToStateTwo();
}

Hey XJ-47, thanks for your reply.

This is what I did. I closed that "for" and open a new one. On that new, I put this:

if ((mission1[k].hitTestObject(event.currentTarget.valueOf())) != true)

Telling the program that if that value is false, return the object to his initial place.

With this in mind, I try to tweek it with more efficient code but didn't work, so for now I will leave it like this.

Thanks so much XJ-47 for your response !!

theCodeCat
theCodeCat
  • Member since: Feb. 24, 2009
  • Offline.
Forum Stats
Member
Level 04
Programmer
Response to Disabling hitTestObject from object 2012-08-24 02:25:37 Reply

I'm a little confused, can you post all of the code you have for the section now?


You forgot to use code tags, didn't you?

jeteran
jeteran
  • Member since: Feb. 10, 2011
  • Offline.
Forum Stats
Member
Level 01
Game Developer
Response to Disabling hitTestObject from object 2012-08-24 13:56:31 Reply

At 8/24/12 02:25 AM, XJ-47 wrote: I'm a little confused, can you post all of the code you have for the section now?

Sure I can, and I really hope helps other to achieve the same thing.

I'm going to simplify the code for better reading and I will comment it.

Firt, I create a listener to all the objects inside the inventory. Because they are in an array, i create a for beforehand and then:

objectsInv[i].addEventListener(MouseEvent.MOUSE_UP, noClickObject);
objectsInv[i].addEventListener(MouseEvent.MOUSE_DOWN, clicObject);

If it's click starts drag, but if it left over the object in the scene and if it's not:

function noClickObject(event:MouseEvent)
			{
				event.currentTarget.stopDrag();
				
				for (var j:uint = 0; j < totalObjectsMission1; j++)
				{
					
					if (event.currentTarget.valueOf().hitTestObject(mission1[j]))
					{
						event.currentTarget.valueOf().visible = false;
						event.currentTarget.valueOf().removeEventListener(MouseEvent.MOUSE_UP, noClickObject);
					}
					
					
				}
				for (var k:uint = 0; k < totalObjectsMission1; k++)
				{
					if ((mission1[k].hitTestObject(event.currentTarget.valueOf())) != true)
					{
						event.currentTarget.valueOf().x = event.currentTarget.valueOf()._x;
						event.currentTarget.valueOf().y = initialPositionY;
					}
				}
			}

Really hope I was clear enough. If not, let me know and I will explain it with more details.

Thanks once again !!

MSGhero
MSGhero
  • Member since: Dec. 15, 2010
  • Offline.
Forum Stats
Supporter
Level 16
Game Developer
Response to Disabling hitTestObject from object 2012-08-24 14:13:35 Reply

Instead of calling valueOf() every time, you can cast e.target. OF course, you'd have to pick a class generic enough to be the superclass of all possible e.targets (Sprite usually works; you can't use "Rocket" if e.target could possibly be a "Bullet" for example).

var s:Sprite = e.target as Sprite;
s.hitTestObject...

Also, why do you have 2 for loops? I didn't look that hard at them, but it seems like the first one is hitTestObj = true, then you loop again to test if it's false instead of using else.

jeteran
jeteran
  • Member since: Feb. 10, 2011
  • Offline.
Forum Stats
Member
Level 01
Game Developer
Response to Disabling hitTestObject from object 2012-08-24 14:44:48 Reply

Hey MSGhero , thank you very much for your reply.

At 8/24/12 02:13 PM, MSGhero wrote: Instead of calling valueOf() every time, you can cast e.target. OF course, you'd have to pick a class generic enough to be the superclass of all possible e.targets (Sprite usually works; you can't use "Rocket" if e.target could possibly be a "Bullet" for example).

var s:Sprite = e.target as Sprite;
s.hitTestObject...

Awesome thanks a lot for your suggestion, I change it and still works fine.

Also, why do you have 2 for loops? I didn't look that hard at them, but it seems like the first one is hitTestObj = true, then you loop again to test if it's false instead of using else.

This is a very tricky part. In the beginning, I had only else, but something was wrong. If I left the else without the for, some targets are touch, and some not.

After SOOO many tries, I finally got it right that way. I track what was doing with a trace and the only thing I saw was that the game objects were called every time.

What do you think??

Thanks once again ! Happy deving !

MSGhero
MSGhero
  • Member since: Dec. 15, 2010
  • Offline.
Forum Stats
Supporter
Level 16
Game Developer
Response to Disabling hitTestObject from object 2012-08-24 18:37:12 Reply

At 8/24/12 02:44 PM, jeteran wrote: This is a very tricky part. In the beginning, I had only else, but something was wrong. If I left the else without the for, some targets are touch, and some not.

After SOOO many tries, I finally got it right that way. I track what was doing with a trace and the only thing I saw was that the game objects were called every time.

What do you think??

Thanks once again ! Happy deving !

Ok, I actually have to do that occasionally as well. Basically, you're editing a property; but you can't call the 2nd half of the for loop until everything has been looped through once. As far as efficiency and stuff, you're basically doubling the array size, which is fine for basic projects. It's when you square the number of loops that things can get laggy.

jeteran
jeteran
  • Member since: Feb. 10, 2011
  • Offline.
Forum Stats
Member
Level 01
Game Developer
Response to Disabling hitTestObject from object 2012-08-24 19:25:25 Reply

At 8/24/12 06:37 PM, MSGhero wrote: Ok, I actually have to do that occasionally as well. Basically, you're editing a property; but you can't call the 2nd half of the for loop until everything has been looped through once. As far as efficiency and stuff, you're basically doubling the array size, which is fine for basic projects. It's when you square the number of loops that things can get laggy.

Hey MSGhero, thanks for your response.

Hot it. Yes I believe that something like that is (was) happening. I always try my best to do a good praxis when making code. Now, if we were working on a bigger project, what is your suggestion to avoid this?

Thanks once again !!

MSGhero
MSGhero
  • Member since: Dec. 15, 2010
  • Offline.
Forum Stats
Supporter
Level 16
Game Developer
Response to Disabling hitTestObject from object 2012-08-24 20:22:40 Reply

At 8/24/12 07:25 PM, jeteran wrote: Hey MSGhero, thanks for your response.

Hot it. Yes I believe that something like that is (was) happening. I always try my best to do a good praxis when making code. Now, if we were working on a bigger project, what is your suggestion to avoid this?

Thanks once again !!

Sometimes it can't be avoided. The only way to avoid doing it that way would be to completely change how you're approaching the problem, which might mean changing the foundation of your code. Sometimes it has to be done, but only if the loops become a major problem.

jeteran
jeteran
  • Member since: Feb. 10, 2011
  • Offline.
Forum Stats
Member
Level 01
Game Developer
Response to Disabling hitTestObject from object 2012-08-24 21:34:18 Reply

At 8/24/12 08:22 PM, MSGhero wrote: Sometimes it can't be avoided. The only way to avoid doing it that way would be to completely change how you're approaching the problem, which might mean changing the foundation of your code. Sometimes it has to be done, but only if the loops become a major problem.

Undestood, thanks so much for your response.

Actually I'm doing it again in the "store" of the game, where I have both a 2D array for the store objects (with their name) and the inventory objects (with their name). I tried to do it as before but I couldn't. Now I'm working to apply some flags, but I'm having deep problems :S

So now I will change the approach: If you click an store object, it will push() an object in the inventory and will substract money. If you click an inventory object, pop() it and money earn.

What do you think about it? I was thinking that maybe I need to make a 3D array that stores it's id, name and cost $$, what is the best I can do??

Thanks man once again !!

MSGhero
MSGhero
  • Member since: Dec. 15, 2010
  • Offline.
Forum Stats
Supporter
Level 16
Game Developer
Response to Disabling hitTestObject from object 2012-08-24 21:48:35 Reply

At 8/24/12 09:34 PM, jeteran wrote: What do you think about it? I was thinking that maybe I need to make a 3D array that stores it's id, name and cost $$, what is the best I can do??

Thanks man once again !!

Push and pop (splice probably though) are fine. I'd 100% avoid 3D arrays if at all possible. What you can do instead is make a new class for shop items. In that class, define id, name, and cost vars. Then push/splice them to/from a 1D array. To make things a bit fancier (following MVC pattern), you can define items as public static constants and give them an "asset" property, which would hold the item image.

// shortened a bit, won't compile without editing
public class Item { 

   private vars _id, _name, _cost and their getters/setters

   public function Item(id:String, name:String, cost:int) {
      _id = id;
      etc
----------------------------------

public class Items {

   public static const GUN:Item = new Item("id", "Gun", 10);
----------------------------------
...
   buyItem(Items.GUN);
...

private function buyItem(i:Item) {

   cash -= i.cost;
   inventory.push(i);  // inventory is a 1D array filled with Item(s)
   addChild(i.itemImage); // for example
jeteran
jeteran
  • Member since: Feb. 10, 2011
  • Offline.
Forum Stats
Member
Level 01
Game Developer
Response to Disabling hitTestObject from object 2012-08-25 13:55:37 Reply

At 8/24/12 09:48 PM, MSGhero wrote: Push and pop (splice probably though) are fine. I'd 100% avoid 3D arrays if at all possible. What you can do instead is make a new class for shop items. In that class, define id, name, and cost vars. Then push/splice them to/from a 1D array. To make things a bit fancier (following MVC pattern), you can define items as public static constants and give them an "asset" property, which would hold the item image.

// shortened a bit, won't compile without editing
public class Item {

private vars _id, _name, _cost and their getters/setters

public function Item(id:String, name:String, cost:int) {
_id = id;
etc
----------------------------------

public class Items {

public static const GUN:Item = new Item("id", "Gun", 10);
----------------------------------
...
buyItem(Items.GUN);
...

private function buyItem(i:Item) {

cash -= i.cost;
inventory.push(i); // inventory is a 1D array filled with Item(s)
addChild(i.itemImage); // for example

Hey MSGhero , as always, thanks so much for your guidance.

This is something VERY similar I was thinking last night. Let me tell you about it and see how I can implement it with your logic.

I thought about making a class called for example GameItems, where it will hold all the items of all the game. Each will have many vars, like "gun._cost = 200", "glasses._name = glasses", "rock._description = A happy rock" etc

When we have that, I will create 2 arrays. One is called store that will recieve the objects depending on the mission. And the other one is called inventory, where will recieve the objects in the store (only if you have money for it !)

What you told me makes me a lot of sense.; and is very similar of what I though. But I feel yours it's more PRO.

Ok now, in your example, you have a class named Item, that's a single Item or you use it to store only the properties of the items? If so, inside the Items class, you create all the items with the properties from item, right?

Then, if you want to buy a gun f.i., you substract what it cost inside cash (I should make an "if" to catch when you run out of money) you push I to the 1D array cald inventory and addChild to show up it in the scene, I'm alright?

It couldn't be more perfect ! It's awesome to see it that way.

So to add the objects in the store, pretty much will be something similar to the buyItem function, where I push in a 1D array called store, the objects that I want. But then, buyItem have to come FROM storeItem function, am I right?

Ok I'm going to try this today, I'm very happy about this, thanks SO much for your help, you are doing a great job !!

BTW. When you say avoid 3D arrays, I'm curious, why is that? (from now on, I will avoid them though)

Thanks again !!

MiloticMaster
MiloticMaster
  • Member since: Oct. 26, 2010
  • Offline.
Forum Stats
Member
Level 12
Blank Slate
Response to Disabling hitTestObject from object 2012-08-25 14:11:55 Reply

At 8/25/12 01:55 PM, jeteran wrote: BTW. When you say avoid 3D arrays, I'm curious, why is that? (from now on, I will avoid them though)

An Array of Arrays of Arrays is the 3D Array.
Not only is it a serious hog of memory, its also very inefficient at storing/getting information.
If you're using the arrays to store data, best follow MSGhero's idea of making a new class, then making an array
of that class. 2D Arrays are only used when the position of the object is defined in a 2D plane by the corresponding Array numbers (like a Tilemap), but doing that in 3D is just crazy.
Also, Vectors should be used in the Tilemap case anyway.


There are redundant words here.

jeteran
jeteran
  • Member since: Feb. 10, 2011
  • Offline.
Forum Stats
Member
Level 01
Game Developer
Response to Disabling hitTestObject from object 2012-08-25 14:23:50 Reply

At 8/25/12 02:11 PM, MiloticMaster wrote: An Array of Arrays of Arrays is the 3D Array.
Not only is it a serious hog of memory, its also very inefficient at storing/getting information.
If you're using the arrays to store data, best follow MSGhero's idea of making a new class, then making an array
of that class. 2D Arrays are only used when the position of the object is defined in a 2D plane by the corresponding Array numbers (like a Tilemap), but doing that in 3D is just crazy.
Also, Vectors should be used in the Tilemap case anyway.

Thanks so much Milotic for that piece of education, I will use the MSGhero's method starting TODAY.

Thanks once again !!

jeteran
jeteran
  • Member since: Feb. 10, 2011
  • Offline.
Forum Stats
Member
Level 01
Game Developer
Response to Disabling hitTestObject from object 2012-08-25 17:44:42 Reply

At 8/24/12 09:48 PM, MSGhero wrote: // shortened a bit, won't compile without editing
public class Item {

private vars _id, _name, _cost and their getters/setters

public function Item(id:String, name:String, cost:int) {
_id = id;
etc
----------------------------------

public class Items {

public static const GUN:Item = new Item("id", "Gun", 10);
----------------------------------
...
buyItem(Items.GUN);
...

private function buyItem(i:Item) {

cash -= i.cost;
inventory.push(i); // inventory is a 1D array filled with Item(s)
addChild(i.itemImage); // for example

Hey MSGhero !

I have been trying to make something very similar of what you told me, and I'm getting errors everywhere.

Let me tell you what I did and I hope we can find a solution:

(I end creating one property of the item, lets do it like that for now)

I create a file called Item and it's the same as yours, but only one var: _name

Ok I have another file called Items, I created an item very similar like yours, but only 1 property ("gun")

In the main file, I imported both files, and inside the constructor I just trace(Item.GUN) and successfuly traces [object Items] but if I trace a property from it (GUN._name) returns a 1178 error, (Attempted access of inaccessible property _name through a reference with static type Item)

What can this be?

Thanks once again man !!

MiloticMaster
MiloticMaster
  • Member since: Oct. 26, 2010
  • Offline.
Forum Stats
Member
Level 12
Blank Slate
Response to Disabling hitTestObject from object 2012-08-25 17:59:45 Reply

The ._name property is a private variable, meaning that it cannot be accessed outside the Item class.


There are redundant words here.

jeteran
jeteran
  • Member since: Feb. 10, 2011
  • Offline.
Forum Stats
Member
Level 01
Game Developer
Response to Disabling hitTestObject from object 2012-08-25 18:03:48 Reply

At 8/25/12 05:59 PM, MiloticMaster wrote: The ._name property is a private variable, meaning that it cannot be accessed outside the Item class.

What a Noob !! Thanks so much Milotic that worked out !!

I'm going to keep working on the rest !!

Happy coding !!

jeteran
jeteran
  • Member since: Feb. 10, 2011
  • Offline.
Forum Stats
Member
Level 01
Game Developer
Response to Disabling hitTestObject from object 2012-08-25 18:07:28 Reply

At 8/25/12 05:59 PM, MiloticMaster wrote: The ._name property is a private variable, meaning that it cannot be accessed outside the Item class.

Hey another Q, why, if I don't import both files to the main class, still works?

Thanks so much !!

jeteran
jeteran
  • Member since: Feb. 10, 2011
  • Offline.
Forum Stats
Member
Level 01
Game Developer
Response to Disabling hitTestObject from object 2012-08-25 18:30:45 Reply

At 8/25/12 05:59 PM, MiloticMaster wrote: The ._name property is a private variable, meaning that it cannot be accessed outside the Item class.

Hey guys.

Another question. I have successfuly import the items and it's properties from the other files. Now in the main file, I have them in the library "Gun", "Sensor" and so on. How can I tell the program that the objects imported belongs to one of those graphics?

The last thing I tried was: public var item:GUN:gun = new gun; but of course is not correct.

Thanks guys ! Almost there !

MSGhero
MSGhero
  • Member since: Dec. 15, 2010
  • Offline.
Forum Stats
Supporter
Level 16
Game Developer
Response to Disabling hitTestObject from object 2012-08-25 18:55:27 Reply

At 8/25/12 06:07 PM, jeteran wrote: Hey another Q, why, if I don't import both files to the main class, still works?

Thanks so much !!

If the files are in the same folder as your .fla or Main.as, it automatically imports them.

Another question. I have successfuly import the items and it's properties from the other files. Now in the main file, I have them in the library "Gun", "Sensor" and so on. How can I tell the program that the objects imported belongs to one of those graphics?

In Flash Pro you mean? If so, when you look at the library item's properties, there will be a spot for "Base Class" or "linkage name" (been a while since I've used Flash Pro). That is where you specify which class it is.

jeteran
jeteran
  • Member since: Feb. 10, 2011
  • Offline.
Forum Stats
Member
Level 01
Game Developer
Response to Disabling hitTestObject from object 2012-08-25 19:04:44 Reply

At 8/25/12 06:55 PM, MSGhero wrote: In Flash Pro you mean? If so, when you look at the library item's properties, there will be a spot for "Base Class" or "linkage name" (been a while since I've used Flash Pro). That is where you specify which class it is.

Great you are totally right, I'm going to try it ;) Thanks once again !!

jeteran
jeteran
  • Member since: Feb. 10, 2011
  • Offline.
Forum Stats
Member
Level 01
Game Developer
Response to Disabling hitTestObject from object 2012-08-25 19:23:25 Reply

One more thing !

Ok I'm right now working on the same basic to create all the missions of the game.

So far so good. Now, I put all the levels of the first mission in a array: mission1[0].

Now, what I want is, when I click an object (nextLevelRight) in the far most of the level, go to next level. If I click an object (nextLevelLeft) in the far most of the level, go to previews level. Both objects are inside each level.

Ok, right now I have it the long way because I couldn't track the actual levels and add or removeChild. So right now I have, for the mission1 that has 3 levels: 4 event listener, one to each nextLevelRight and nextLevelLeft of the levesl.

Ok now, I tried 2 things:
1) Created a flag that tells me in which level I am right now, and add or removeChilld(mission1[flag] when I click both objects. It was great for only the nextLevelRight object, when I try to go back, I can't.
2) I created 2 flags, the same as 1) but counts backwards, and now none of them are working.

You have a better way to do this? I tried to find too the way to removeChild(event.currentTarget) but that leaves me to an error, and that's true because event.CurrentTarget targets nextLevelRight. I try parent, MovieClip(root) and couldn't find mission1[i]

Thanks so much for your careness guys ! Thanks to you I have made this far !!