What is a right way for multiple instance events?

A

Ari-Antti

Guest
I face this kind of problem very often with multiple object instances.. and i am sure there is better way handling this than what i use. I just don't know what it is and can not find answer in documents..
I give an simple example where this could happen, and how i solve this.

We have 10 instances of object Ball, 9 blue Balls and 1 red Ball.
All 10 balls are flying around aimlessly bouncing and they can overlap each other.
User should click red ball, doesn't matter if he hits same time blue ball or not as long he hits red one.

How i would solve this:
I would make Tap event for object Ball, and there look if Balls sprite color is blue or red.
if it would be red.. that would be easy.. case closed.
If its blue ball however.. i would need to use global variable, lets call it Timeout.
I need to set it to 5 for example if ball is blue.

Then i would go in Step event and make code:
If(Timeout>0)
{
Timeout--;
if(Timeout==0)
{
//here i can safely say that user did not hit Red ball, just one or more blue balls.
}
}

So problem is that if there would be situation where user hits red ball, but same time hits one or more blue balls..
My way of programming does work.. but thats just ugly!
Need to make global variable just for this, need to recognize this situation in multiple events..
There must be better way?

Can i somehow peak in Tap event that is there going to be more Tap events pending?
In that case i could just ignore blue ball, except if its last Tap handle.. then i can safely say that "nope, didnt hit red ball"
 

Rob

Member
What about a "with" statement, that checks the location of all the ball
I face this kind of problem very often with multiple object instances.. and i am sure there is better way handling this than what i use. I just don't know what it is and can not find answer in documents..
I give an simple example where this could happen, and how i solve this.

We have 10 instances of object Ball, 9 blue Balls and 1 red Ball.
All 10 balls are flying around aimlessly bouncing and they can overlap each other.
User should click red ball, doesn't matter if he hits same time blue ball or not as long he hits red one.

How i would solve this:
I would make Tap event for object Ball, and there look if Balls sprite color is blue or red.
if it would be red.. that would be easy.. case closed.
If its blue ball however.. i would need to use global variable, lets call it Timeout.
I need to set it to 5 for example if ball is blue.

Then i would go in Step event and make code:
If(Timeout>0)
{
Timeout--;
if(Timeout==0)
{
//here i can safely say that user did not hit Red ball, just one or more blue balls.
}
}

So problem is that if there would be situation where user hits red ball, but same time hits one or more blue balls..
My way of programming does work.. but thats just ugly!
Need to make global variable just for this, need to recognize this situation in multiple events..
There must be better way?

Can i somehow peak in Tap event that is there going to be more Tap events pending?
In that case i could just ignore blue ball, except if its last Tap handle.. then i can safely say that "nope, didnt hit red ball"
So you just want to check to see if the player hit a red ball or not (regardless of whether or not there are blue ones?)
 
A

Ari-Antti

Guest
@Rob Comparing red balls x-y coordinates (+hit box) with mouse x,y, we can see if there is collision. True.
At least this method does not need global variables.. thanks, thats sure is better than what i suggested!
But still there might be even better way..

So problem is that if i detect that user hits a ball (ball object Tap/click event) and i see its a blue ball.. then i have no idea if
1. user did hit only one or more blue balls
2. user hit one or more blue balls but also he did hit red one.
3. he just hit this ball. blue one.

I know that in ~1 millisecond tho.. right after i get this blue-balls tap event call, i will get a next tap call...if there will be one... might be red-ball.
thats why i did use timeout.

By exploring documents i can see solution might be in ds_map:

"When a gesture event is recognised, it will trigger one or more of the available sub-events, and the sub-event triggered will depend on the type of gesture that has been detected. In every case, however, a DS Map will be generated for you and stored in the built-in variable event_data. The keys available will depend on which kind of event it has been created by and are shown in each of the sub-sections below."

I have never used these ready generated ds maps.. so i struggle to know what is "id" and what is "key" in these cases.
Can anybody say is there something like:

var a=ds_map_find_value(event_data,"total_count_of_this_event") //called in tap event (Ball object)
and "a" value would be 3 if i do hit 3 ball instances at same time?
 

TheouAegis

Member
with obj_ball if position_meeting(mouse_x, mouse_y,id) if color == red {
global.Timeout = 0;
break; }
else global.Timeout = 5;
 

Rob

Member
The red ball has something that's different than the blue ball, right?

Either a different sprite, sub-image or variable.

Just check for that in your with statement

Code:
//When LMB is pressed

with (obj_balls){
   if (sprite_index == spr_red){
      if (mouse_x && mouse_y are within bounding box of ball){
      //you got the red ball!
      break; //because we found the one we want
      }
   }
}
I think using the with statement to check through all your balls (haha) won't be a bad thing optimization-wise because you don't have hundreds/thousands of them.
 
A

Ari-Antti

Guest
@Rob if i hit 5 balls at same time, (one being red). it will go thru this code 5 times.
so you find the red ball 5 times.

So i can not do something like "score+=1;" because score goes +5 in that case.
Of course i can use timeout again:

if(Timeout==0)
{
score+=1;
Timeout=5;
}
And reduce Timeout in step event..

But again,, too many global variables and much more "hard way" just to find your balls! (haha)

I feel there is somehow way to "peak in future", so you could write something like:

//in tap event of ball
Is this blue_srite_ball?

if(yes)
{
is there going to be more event already triggered or is this the last one?
if( yes)
{
// i dont need to do anything until last one
}
else
{
//user didnt hit red ball !

}
}
else
{
//user did hit red ball
}

and even if this code is gone thru 5 times (4 blue balls and 1 red) it finds 1 red if there is one.
but how to do that
"is there going to be more event already triggered or is this the last one?"
What would give me value 4 in first time, saying "yea, there is 4 more balls user did hit at the same time..
 
Last edited by a moderator:

TheouAegis

Member
@Rob if i hit 5 balls at same time, (one being red). it will go thru this code 5 times.
so you find the red ball 5 times.

So i can not do something like "score+=1;" because score goes +5 in that case.
Of course i can use timeout again:

if(Timeout==0)
{
score+=1;
Timeout=5;
}
And reduce Timeout in step event..

But again,, too many global variables and much more "hard way" just to find your balls! (haha)

I feel there is somehow way to "peak in future", so you could write something like:

//in tap event of ball
Is this blue_srite_ball?

if(yes)
{
is there going to be more event already triggered or is this the last one?
if( yes)
{
// i dont need to do anything until last one
}
else
{
//user didnt hit red ball !

}
}
else
{
//user did hit red ball
}

and even if this code is gone thru 5 times (4 blue balls and 1 red) it finds 1 red if there is one.
but how to do that
"is there going to be more event already triggered or is this the last one?"
What would give me value 4 in first time, saying "yea, there is 4 more balls user did hit at the same time..
Now that you've dissected his code, go back and look at my code. By the sounds of it, it doesn't matter if user hits a red ball and a blue ball at the same time, all that matters is the red ball has priority over the other balls. Your timeout variable gets set when you hit a blue ball, but as soon as you hit a red ball, you clear that timeout variable and stop looking through the balls. That's what my code does.
 
A

Ari-Antti

Guest
Now that you've dissected his code, go back and look at my code. By the sounds of it, it doesn't matter if user hits a red ball and a blue ball at the same time, all that matters is the red ball has priority over the other balls. Your timeout variable gets set when you hit a blue ball, but as soon as you hit a red ball, you clear that timeout variable and stop looking through the balls. That's what my code does.
@TheouAegis You are right, that does work.
Quite similar approach i had in my original post.
In this example it works like a charm!

However i feel there must be better way. Document says that it is via ds_map, but i struggle to find example or anything how to implement it.
Problem with global timeout is that code readability suffers in this and hits me in the angle when creating larger projects.

I feel like there is always same kind of situation no matter whatkind of game:
"instance event has occured! Ohh, it was not quite what i was looking for.. i need to react or not react depending on is there more events triggerd from other instances.. lets have a timeout and find out."

I quess only way to solve it is to somehow see inside of tap event that how many pending tap events are waiting for prosessing.
From that value you can do so much more inside of tap event, leading to reduce amount of global variables.
 

TheouAegis

Member
You can put the code inside each other ball objects, but then you would need to set a global variable to true when the red ball is found. Either way you're going to have to loop through every single ball until a red ball checks that the mouse clicks on it. If your balls are distinct separate objects,you can set it so you process red balls first.

If you want to try to work with that map thing, then the ID of the map is event_data.
 

Rob

Member
@Rob if i hit 5 balls at same time, (one being red). it will go thru this code 5 times.
so you find the red ball 5 times.

So i can not do something like "score+=1;" because score goes +5 in that case.
Of course i can use timeout again:

if(Timeout==0)
{
score+=1;
Timeout=5;
}
And reduce Timeout in step event..

But again,, too many global variables and much more "hard way" just to find your balls! (haha)

I feel there is somehow way to "peak in future", so you could write something like:

//in tap event of ball
Is this blue_srite_ball?

if(yes)
{
is there going to be more event already triggered or is this the last one?
if( yes)
{
// i dont need to do anything until last one
}
else
{
//user didnt hit red ball !

}
}
else
{
//user did hit red ball
}

and even if this code is gone thru 5 times (4 blue balls and 1 red) it finds 1 red if there is one.
but how to do that
"is there going to be more event already triggered or is this the last one?"
What would give me value 4 in first time, saying "yea, there is 4 more balls user did hit at the same time..
No - that's where the break comes into it. If you find a ball with the right sprite/whatever you break the with loop. I think the main issue is where I would put this code.

I wouldn't put this in a ball object. If you have a controller object, put it in its step event or make an obj_mouse that follows the mouse_x/ mouse_y and do that.

Whatever code you want to make run when you find the red ball you put it just before the break point. It will run once.

I feel like there is always same kind of situation no matter whatkind of game:
"instance event has occured! Ohh, it was not quite what i was looking for.. i need to react or not react depending on is there more events triggerd from other instances.. lets have a timeout and find out."

I quess only way to solve it is to somehow see inside of tap event that how many pending tap events are waiting for prosessing.
From that value you can do so much more inside of tap event, leading to reduce amount of global variables.
If you want to find one instance among the others you want to find its id. The with statement can be used for just that purpose and if you need to save that instance's id you can say:

Code:
//Inside the with statement
other.targetBall = id;
A lot (not all) of the collision functions will return an id too so you can say:

Code:
if (collision_rectangle(x1, y1, x2, y2, obj_ball, false, false)){
   targetBall = collision_rectangle(x1, y1, x2, y2, obj_ball, false, false);
}
Then you can do this:

Code:
targetBall.hp -= 10;
Or this:

Code:
with targetBall{
   x += 10;
   y -= 20;
}
 
Last edited:
A

Ari-Antti

Guest
Thanks for responses guys!

@Rob by code running 5 times i ment that if u hit 5 obj_ball instanses at once.. game maker will call Tap function 5 times.
No matter what code you have inside of Tap event that will happen. (at least i think so)

If you have then inside of Tap event
with(obj_ball)
{
if(position_meeting... find instance with red sprite...

}
you will find that red ball 5 times..
Ofc you can deal with that.. but need global variables again etc..

Controller objects might be something to think about... i have not much used them.
MIght make life easier =)

By looking at documents several times i don't think event_data will help me with this issue.. =(
 
Last edited by a moderator:

Rob

Member
Thanks for responses guys!

@Rob by code running 5 times i ment that if u hit 5 obj_ball instanses at once.. game maker will call Tap function 5 times.
No matter what code you have inside of Tap event that will happen. (at least i think so)

If you have then inside of Tap event
with(obj_ball)
{
if(position_meeting... find instance with red sprite...

}
you will find that red ball 5 times..
Ofc you can deal with that.. but need global variables again etc..

Controller objects might be something to think about... i have not much used them.
MIght make life easier =)

By looking at documents several times i don't think event_data will help me with this issue.. =(
Ehh I didn't even know until now that there were mobile events. I always just check for a mouse click.

By using that event (and having it on all your ball objects) then yeah it will run 5 times, you're correct. When you were talking about your recurrent problems, it's probably because you're using events to check for collision (rather than coding it yourself). If you had a separate object you could put the collision code into that and then it will only be run once. You won't need any extra variables.

I understand your issue (and pain) because I had similar ones before I moved away from those kinds of events.

If you made an object called obj_mouse you could put this in its step event:

Code:
//step event of obj_mouse

x = mouse_x;
y = mouse_y;

if (mouse_check_button_pressed(mb_left)){
  
   if collision_point(x, y, obj_ball, false, false){
      ball = collision_point(x, y, obj_ball, false, false);
      if ball.sprite_index = spr_red{
          //increase score
      }
   }

}
I haven't used the gesture events at all so you know more about it than I do, this is just how I would tackle the problem
 
Top