• Hey Guest! Ever feel like entering a Game Jam, but the time limit is always too much pressure? We get it... You lead a hectic life and dedicating 3 whole days to make a game just doesn't work for you! So, why not enter the GMC SLOW JAM? Take your time! Kick back and make your game over 4 months! Interested? Then just click here!

GML How do you get inst ID's of object within a given range?

A

anthropus

Guest
Hi all. I have a 'bomb' type object in my game, and I want this bomb to deal different damage to enemies depending on enemies' distance to the bomb object--the closer they are the more damage, the farther away the less damage, etc.

My problem is I dont know how to make the bomb 'speak' to all the specific enemy instances within a certain range, and all the specific enemy instances within another range, and so on. I know how to make the bomb 'speak' to all instances of an object, or the instance it collides with, but not to specific instances within specific ranges. I really need help with this, my noob level makes the solution invisible to.

I'm guessing I need to make a variable that holds all the instances' IDs of different ranges to the bomb object, but HOW do I make such a variable? Is that even what I should do?

something like this i think:
var enemies_within_close_range=... //how do i make that kind of variable?
var enemies_within_far_range =...//how do i make that kind of variable?

then I would just put
with (enemies_within_close_range)
{
blah blah blah //this part I can do.
}
//etc
thanks!
 
  • Wow
Reactions: Mut
C

CptChuckles

Guest
first just get all the enemies within the whole range, add them all to a ds_list, and then loop through the list for each damage range, applying damage as necessary.

Code:
/// Bomb explosion event (an alarm, most likely)

//make a list to hold all the enemies within the largest radius
enemies = ds_list_create();

//now run the following check on ALL enemy types.
//oEnemyBaseClass should be a parent object to all enemy types.
with(oEnemyBaseClass)
{
    if(distance_to_point(other.x, other.y) <= other.longest_range)
        ds_list_add(other.enemies, id);
}

 //so check if there were any enemies in the biggest range...
if(!ds_list_empty(enemies))
{
    //damage each enemy by 10 points for every range closer it is
    //so furthest range is 10, mid range is 20, closest is 30
    for(var i=0; i<=ds_list_size(enemies); i++)
    {
        var enemy = ds_list_find_value(enemies, i);
        var dist = distance_to_point(enemy.x, enemy.y);
     //we already know if an enemy was in this list, then it's at least
          //within the furthest range. damage it 10.
        enemy.hp -= 10;
          //now if it's in mid-range, damage it again
        if(dist <= middle_range) enemy.hp -= 10;
          //and once more for closest range
        if(dist <= closest_range) enemy.hp -= 10;
    }
}

//now get rid of the list
ds_list_destroy(enemies);
 
S

Silver_Mantis

Guest
Within your enemies, create a long range and a close range variable.

Create Event:
Code:
long_range = 100
close_range = 50
Then within your enemy state, add something similar to this:
Step Event:
Code:
//Bomb Distance
   
var dis = point_distance (x, y, obj_Bomb.x, obj_Bomb.y);
    if (dis > close_range && dis <= long_range)
    {
        if (//Condition when bomb explodes I.E bomb_explode = true)
        {
        // Add long range damage here
        }
    }
   
    if (dis <= close_range)
    {
        if (//Condition when bomb explodes I.E bomb_explode = true)
        {
        // Add close range damage here
        }
    }
Pretty sure that'll work.
 

hippyman

Member
There's actually a couple scripts on GMLScripts that can give you exactly what you need. I personally would use collision_circle_list.

This returns a list with the id's of all the instances colliding with the circle. Just remember to destroy the list after you're done with it or you'll get a memory leak.

In your case, you could use the collision list function to check the long range hits and then loop through all the hits and individually check if they're within the close range collision.
 

samspade

Member
There are multiple methods that would work, but the simplest to understand I think is that you want the enemies to check when they get hit by the bomb and then deal damage to themselves accordingly rather than for the bomb to check what enemies it hits and them deal damage to them. Then the problem becomes a lot easier to deal. All you have to figure out is:

1. How the enemy detects that it has been hit by the bomb. There are many methods of doing this. You could do it with global variables, collision masks, etc.
2. How you want to calculate damage.

For example, when the bomb explodes you could change its sprite to spr_explosion drawn from the center. Under each enemy you could have a collision event for the bomb that only runs if other.sprite_index == spr_explosion (I can't remember if sprite_index is the right function). If the enemy is in contact with the bomb while it is exploding (e.g. it's sprite == spr_explosion) then the enemy checks its distance to the center of the explosion and save it to a variable with dist_to_explosion = distance_to_point(x, y, other.x, other.y). The enemy then takes damage based upon that distance.

This could be done with some simple straight forward variables e.g. if (dist_to_explosion < 50) {enemy_hp -= damage_short_range} (where damage_short_range is a pre-set variable. You could also do it mathematically such as enemy_hp -= (1 - (dist_to_explosion / spr_explosion_width)) * bomb_damage // (where spr_explosion_width is a preset variable equal to the width of the explosion sprite and bomb_damage is a preset variable equal to the max bomb damage). In that case, assuming my math is correct, the enemy will lose hp equivalent to the inverse of the percentage remaining to the center of the bomb explosion. Or put it another way. If the object is 50 away from the center of spr_explosion and the spr_explosion is 200 wide, then 50 / 200 = .25. 1 - .25 = .75 and damage dealt will be equal to 75% of the max bomb damage.

The short version: if you detect the explosion from within the enemy object you can have the enemy object calculate it's own distance and apply damage to itself accordingly. It is possible to do it the other way (detect the distance of the enemy object within the explosion) but its more complicated (I think) and probably not more useful most of the time.
 

samspade

Member
first just get all the enemies within the whole range, add them all to a ds_list, and then loop through the list for each damage range, applying damage as necessary.

Code:
/// Bomb explosion event (an alarm, most likely)

//make a list to hold all the enemies within the largest radius
enemies = ds_list_create();

//now run the following check on ALL enemy types.
//oEnemyBaseClass should be a parent object to all enemy types.
with(oEnemyBaseClass)
{
    if(distance_to_point(other.x, other.y) <= other.longest_range)
        ds_list_add(other.enemies, id);
}

 //so check if there were any enemies in the biggest range...
if(!ds_list_empty(enemies))
{
    //damage each enemy by 10 points for every range closer it is
    //so furthest range is 10, mid range is 20, closest is 30
    for(var i=0; i<=ds_list_size(enemies); i++)
    {
        var enemy = ds_list_find_value(enemies, i);
        var dist = distance_to_point(enemy.x, enemy.y);
     //we already know if an enemy was in this list, then it's at least
          //within the furthest range. damage it 10.
        enemy.hp -= 10;
          //now if it's in mid-range, damage it again
        if(dist <= middle_range) enemy.hp -= 10;
          //and once more for closest range
        if(dist <= closest_range) enemy.hp -= 10;
    }
}

//now get rid of the list
ds_list_destroy(enemies);
This is cool and not that complicated once you understand ds_list (and for statements). And neither are that complicated to learn. I'm new to programming in general, not just GML, and I didn't know GML had this system in it.
 
C

CptChuckles

Guest
The short version: if you detect the explosion from within the enemy object you can have the enemy object calculate it's own distance and apply damage to itself accordingly. It is possible to do it the other way (detect the distance of the enemy object within the explosion) but its more complicated (I think) and probably not more useful most of the time.
b-but encapsulation...! [heavy breathing] Let the weapon worry about dealing damage. When adding new weapons and damage effects, it's just bad practice to make the other objects hurt themselves. They should just worry about being themselves, and the damage effects can worry about hurting them. This reduces coding labor, redundancy, and ensures no damage effect gets left unaccounted for.
 

sp202

Member
I agree with @CptChuckles, encapsulation is important. I'm not a fan of using ds_lists for something as simple as this. The "with" statement should be all you need.
Code:
//BOMB EVENT
with (objEnemy)
{
dist=point_distance(x,y,other.x,other.y)
//if dist is within bomb range
{
//damage calculation
}
}
 
C

CptChuckles

Guest
That is a lot simpler. Actually I started out thinking ds_list was the way to go because I was originally planning on looping through it three times, deleting each index along the way so it would be smaller each time. And then I put the damage in a single loop, but I didn't see my way out of the ds_list so quickly. Everything can simply happen in the with() block.
 
Top