• 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!

[SOLVED]Couple Problems

First off I promise not to post again until these issues are resolved. :)

This is the code for my collision between my bats and my brains. What I want it to do is the following. The player controlling the bats double clicks on a brain when it is next to it. The brain begins its attack animation and so does the bat. The player keeps clicking on the brain, which causes a "thumping" sound and causes damage indicators to float upward from the brain. There is a damage meter below the bat and as the player takes damage, the meter empties. If the player wants to, he/she can click away from the brain and run to escape (that's in another posting). So the brain (hopefully) gets killed by the bat and then the bat is free to fly around until it runs into another brain.

This is what is happening. The player double clicks on the brain. After a couple clicks the brain starts taking damage and the bat starts its flying animation. Then every click that "hits or does damage" changes the brain object's sprite to the attack sprite for the bat for some reason. As the player clicks on the brain, every hit makes a thumping sound and the damage indicator works as it should. The same for the damage meter. If was player wants to click away from the brain to get away, sometimes it will back up (assuming you are escaping to the rear) and the brain will follow, sometimes it won't do anything. So then the brain gets killed by the bat and then the bat is free to fly around until it runs into another brain.

Phew

Ok. To start, here is the code for collision:
Code:
var play_timer = 0;
var played = true;

var colliderbrain;
var colliderbat;


global.timer_big_brain--;
if (global.timer_big_brain <= 0)
{
    global.timer_big_brain = room_speed/8;

    if (mouse_check_button_released(mb_left))
    {
        show_debug_message("LMB pressed");
   
   
        colliderbrain = instance_position(mouse_x, mouse_y, SimpleBrain);
       
       
        if (instance_exists(colliderbrain))
        {
            show_debug_message("Collider brain exists");
        }
       
   
        if (colliderbrain != noone)
        {
            show_debug_message("Collider Brain initializating collider bat");
            with (colliderbrain)
            {
                show_debug_message("With Colliderbrain");
                colliderbat = instance_position(mouse_x, mouse_y, other)
            }
        }
   
        /////////////////////////COLLIDERBRAIN AND COLLIDER BAT//////////////////////
       
        if (colliderbrain == noone || colliderbat == noone)
        {
            return;
        }
   
        //////////////////////////////////////////////
       
        show_debug_message(object_get_name(colliderbrain) + "shoujld be a brain");
        show_debug_message(object_get_name(colliderbat) + "should be a bat");
       
        ///////////////////////////////////////
   
        //colliderbat = other;//instance_place(mouse_x, mouse_y, SentryBatObject)
        if (colliderbrain != noone)
        {

            show_debug_message("Collider brain is not noone");
            with (colliderbrain)
            {
       
            //    if (point_distance(argument0, argument1, x, y) < 40)
                if (point_distance(argument0, argument1, x, y) < 100)
                {

                    ///colliderbrain is Brain
                    show_debug_message("With colliderbrain");
       
               
                    sprite_index = SimpleBrainAttack;
           
                    hp_minus = irandom_range(10, 30)
                    hp = hp - hp_minus;
       
                    speed =0;
                    under_attack = true;
                    took_a_hit = true;
                    //sprite_index = SentryBatAttack
                    //image_speed = 1;
                    audio_play_sound(BatThumpSound,20,false);
               
                    show_debug_message("Showing Damage Indicator");
                    floater = instance_create_depth(x+10, y-10, -17000, DamageIndicatorObject);
                    floater.text = string(hp_minus);
               
                   
               
                    //killl the brain  
                    if (hp <= 0)
                    {
                        show_debug_message("Kill the brain");
                   
                        global.achievement_gold_counter++;
                        global.achievement_tome_experience += 20;
                        show_debug_message("Dead Brain Ghost and Fading Gem");
                        audio_play_sound(DieingBrainSound, 20, false);
                        instance_create_depth(x, y, -1100,DeadBrainObject);      
                        instance_create_depth(x-150, y-20, -1100, FadingGemObject);
           
                        instance_destroy();
                    }
                }      
       
            }
        }
   
            if (colliderbat != noone)
            {
                with (colliderbat)
                {
                    show_debug_message("Colliderbat is not noone");
       
                    //damage to batq
                    if (!global.group_invincibility)
                    {
                        hp = hp - 1;
                        damage = 1;
                        damage_dealt_to_bat = damage;
                    }
   
                   
                   
                    sprite_index = SentryBatAttack;
                    image_speed = 0;
                    show_debug_message("SentryBatAttack");
                   
   
                    //alarm[5] = room_speed;
           
                    under_attack = true;  
                    took_a_hit = true;
                    //sprite_index = SimpleBrainAttack;
                    //audio_stop_sound(BatWingsMovementSound);
       
                    /* kill the bat */
       
                    if (hp <= 0)
                    {
                        audio_play_sound(BatDeathSound, 20, false);
                        instance_create_depth(x, y, -1100,DeadBatObject);
                        global.num_sentry_killed++;
                        instance_destroy();
                       
           
                    }
                }
            }
I hope this makes sense. colliderbat is the bat you control in the game in this collision. You can have control of multiple different kinds of bats. colliderbrain is is the brain the AI controls in this collision.

Screenshot 1 - sentry bat graphic responding the attacking brain when the sentry bat is attacking the brain
Screenshot 2 - the way the brain should look

Sorry about the long post but I wanted to be thorough
 

Attachments

TheouAegis

Member
Okay Ted, do yourself a favor, and I mean this in a considerate way. since that block of code is now for the time being backed up here on the forum, rewrite that entire script and your project. And as you are doing that, remove any debugging lines, like all those show_debug_message(), remove all the lines that you have commented out unless you think they are the right line. Rewrite your code with only comments to remind you what a particular block of code is supposed to be doing if you need to. Furthermore as you are rewriting that code, look at it and think to yourself, "Are there any blocks of code that I can combine together? Are there any redundancies I can get rid of?" Here's one redundancy you can get rid of: checking if an instance exist AND checking if that instance is not noone. there are situations where those two conditions are separate, but this is not one of them. If the incense does not exist, then the variable is for sure noone.

Don't you have your code rewritten, condensed down, cleaned up, and all that jazz, test it. See if it works. If it doesn't work, do not try to debug it by adding stuff, since clearly that is not helping you out very well.

From that code, it does look like the brain should be using the brain's Sprite, and the bat should be using the bat Sprite, at least to me. Which would suggest that the variables are holding the wrong values or you're withare not set right. But cleaning up your code should help with that.

What are the arguments that you are passing through this script? Obviously they are coordinates, but the coordinates of what?
 
Last edited:
Okay Ted, do yourself a favor, and I mean this in a considerate way. since that block of code is now for the time being backed up here on the forum, rewrite that entire script and your project.
No.I put way too much work into this. Rewriting the collision script is plausible. Rewriting my entire project because of a small part of it is outrageous.

From that code, it does look like the brain should be using the brain's Sprite, and the bat should be using the bat Sprite, at least to me. Which would suggest that the variables are holding the wrong values or you're withare not set right. But cleaning up your code should help with that.
They are using brain's sprite for brain and bat's sprite for bat. That code does not cleaned up.
What are the arguments that you are passing through this script? Obviously they are coordinates, but the coordinates of what?
The coordinates are the x and y of the brain enemy in the collision.
SimpleBrainSentryBatCollision(x,y);

Oh and way to discourage and put somebody down.

I mean.....do you understand how hard it is to develop a game of this scope by yourself. Seriously, it is me and an artist. Yes if I could do it over again I wouldn't have made something so complex, but I already dove into It and not finishing It up (which I am doing ) I don't think worth wasting all of the hours put into it.
 
I mean.....do you understand how hard it is to develop a game of this scope by yourself. Seriously, it is me and an artist.
A lot of us understand exactly this, if not more (where we are the only person working on our projects, not even with any artist). I don't think @TheouAegis is saying scrap and start from scratch again, but take out all the bits that are no longer required, ie: the debugging statements, so that the code is clean and can be clearly understood rather than loads of extraneous lines of commented code that may or may not have anything to do with the project any more.

You're also not the only one who has had to scrap a project and start again because of issues that came down to coding problems/mistakes. I have rewritten chunks of projects repeatedly because of these, and each iteration it gets better and better.
 
T

Taddio

Guest
Well, see the bright side of it. Maybe this time you are hacking through a jungle with a butter knife, I am sure next time around you will:
- use parenting
- name your variables in a meaningful, short and distinguishable way
- use the correct variables scopes
- bring a machete to hack aformentionnrd jungle.

And, I'm preeeeeeetty sure @TheouAegis knows perfectly what it's like to develop a game of this scope ;)

Hang in there brother, I promise I'll try it when it's done :)
 

rIKmAN

Member
Seems to me like you are spreading yourself too thin.
When I checked the forum yesterday or the day before 6 of the first 10 threads on the "New Posts" page were by you.

Try to concentrate on one problem at a time and give it your full attention until you manage to solve it rather than jumping between multiple problems and trying to solve them all at the same time whilst not really focusing yourself 100% on any of them.

I'd also agree with the Theou and BaBiA that it would help you massively to spend a day to clean up your project and code, remove anything that is no longer needed / valid and comment it in a way that makes it clear to you what each piece of code is supposed to do and that help might provide some clarity when stepping through it logically to find any issues.

It can also be beneficial to take a break if you start to get too frustrated with things - sometimes the answer to a problem or a new way to approach a problem will come to mind when you least expect it.
 
Last edited:
I'm not redoing it. I have over a year of code and it is almost finished. I have five bugs that need to be fixed, the IAP, and the code-side is about complete.They are the same bugs I've been posting about. Note I haven't been coming up with new errors I need help with on the forum. It is the same frickin problems. I understand from your perspective it is limited, you don't know the scope of the game, what's done, what isn't done, the game mechanics, the gameplay, etc. If you looked from my perspective I see a project 80% done, a few bugs that are really tough to fix, and a game that with at most another month of coding and art will be ready for beta. I can detail what is done so far and what has to be done yet but I shouldn't have to.

I'd also agree with the Theou and BaBiA that it would help you massively to spend a day to clean up your project and code, remove anything that is no longer needed / valid and comment it in a way that makes it clear to you what each piece of code is supposed to do and that help might provide some clarity when stepping through it logically to find any issues.
@rIKmAN Agreed. I should take a day to do cleanup. Good idea. I've been putting it off.
 

rIKmAN

Member
I'm not redoing it. I have over a year of code and it is almost finished. I have five bugs that need to be fixed, the IAP, and the code-side is about complete.They are the same bugs I've been posting about. Note I haven't been coming up with new errors I need help with on the forum. It is the same frickin problems. I understand from your perspective it is limited, you don't know the scope of the game, what's done, what isn't done, the game mechanics, the gameplay, etc. If you looked from my perspective I see a project 80% done, a few bugs that are really tough to fix, and a game that with at most another month of coding and art will be ready for beta. I can detail what is done so far and what has to be done yet but I shouldn't have to.
I didn't tell you to redo it, I told you to take a breath, clean up the project and then attack one problem at a time rather than trying to fix six at once.
Based off your threads on here you have tied yourself in a few knots and cleaning up the project would help you be able to identify the cause of the issues.

Take the advice or don't, you do you - no need to get defensive.

edit: Seems you weren't replying to me, but without you quoting anyone it seemed you were.
 

TheouAegis

Member
My phone added "and" when i said "in your project." Although cleaning up the rest of your project would still be a good idea, it's just the problem areas that really need focus right now.

a few bugs that are really tough to fix, and a game that with at most another month of coding
And cleaning up problem areas will likely reveal what's causing those bugs. I wasn't even saying back in the battimer threas to rewrite your whole project with arrays so that your bat code is actually sensible, I'm just saying if you had learned to use arrays early on, many of these issues would be nonexistent.

And I think I just found your issue in this code.

Then every click that "hits or does damage" changes the brain object's sprite to the attack sprite for the bat for some reason.
That was the issue you claimed in your first post. Hence why I said it LOOKED like the right instances should be changing to the right sprite, but they aren't -- according to you.

Code:
if (mouse_check_button_released(mb_left))
   {
          colliderbrain = instance_position(mouse_x, mouse_y, SimpleBrain);
   
       if (colliderbrain != noone)
       {
           with (colliderbrain)
           {
               colliderbat = instance_position(mouse_x, mouse_y, other)
           }
       }
What is at mouse_x and mouse_y? A brain. Unless the bat and brain are overlapping at the exact point that the player clicks, only colliderbrain would get set. Since you already know colliderbrain isn't noone, the with is unnecessary. On the other hand, it would make sense if you had
Code:
 with colliderbrain {
    colliderbat = instance_place(x,y,other);
}
And then there may be an issue with other. Who os calling that script? Every bat or every brain? If arguments 0 and 1 are the x,y of a brain, then whybare you checking for a brain at the mouse if you are already passing the brain's coordinates?

BUT IF the script is run FROM A BRAIN's SCOPE, then colliderbrain and colliderbat would be the same instance and that would explain the brain using the bat's attack sprite.
 
Unless the bat and brain are overlapping at the exact point that the player clicks, only colliderbrain would get set.
I'm not following you.

Code:
colliderbrain = instance_position(mouse_x, mouse_y, SimpleBrain);
Is this code t he code you are referring to?
The x,y passed in are the coordinates from a brain object. So the instance_position is to get the instance of a SimpleBrain (colliderbrain). I'm sure there is a better way, I just don't know it.

Code:
with colliderbrain {
    colliderbat = instance_place(x,y,other);
}
I don't know how to get the bat instance in the collision. I'm used to using the event menus. That's the core of it.
I need to get at the colliderbat object. I thought using instance_position with the coordinates of the brain and using other but
now that I look at it it obviously won't work. So the question is, if you have two objects you want to script a collision for, and you have an instance for one, how the heck do you get the instance for the other object in the collision??
 

TheouAegis

Member
What I'm saying with the mouse is your code says get the brain that the mouse is clicking on, then it goes on to say if it got a brain, get the bat that the mouse is clicking on. The only way that's ever going to happen is if where the mouse is at there is a brain pixel overlapping with a bat pixel. Which is possible, but not always going to be likely. So if a brain is clicked on, then it will look for a bat at the exacte same mouse coordinate, which there probably won't be in most cases. If you click on a bat first then there likely won't be a brain there, so colliderbrain is set to noone and colliderbat never gets set. It's just an issue with using instance_position(mouse_x, mouse_y,obj).

you already have access to the x & y coordinates of the brain instance once you get its ID in colliderbrain..there is no need to pass arguments in that script.

and then even if you did get the x & y coordinates of the brain that is underneath the mouse and passed those coordinates to that script, your script is saying check the distance between that brain's x & y coordinates to its own x & y coordinates, then. That's going to make it so the bat attacks too soon.

I have to go shower now.

UPDATE

Begin a brain ideas not your issue, it's getting an ID.But getting the ID of the bat or bats is the issue.if I remember right about your project, don't you have bats that are ranged attackers? In other words, a bat that spits fire or attached with sound waves? in that case, you wouldn't want to find the bat that is actually on top of the brain, you'd want to find the bat that is an attack range. and are you limiting it to just one bat attacking one brain, or do you want all bats that are within range to attack the brain? And either case, once you have your brain, you are going to need to use a with(objSimpleBat) or whatever your bat parent is called 2 1st loop through every single batt on the screen and find the one that is actually within attacking range. Then that bat would be colliderbat.

and in any case, this code would be run from your controller object, since it would be affecting all brains and it would be affecting all bats. He will not be passing any arguments to it whatsoever, because there is nothing that you would need to pass to the script that you cannot find out inside the script itself.

Time for work.
 
Last edited:
Yeah you are right about my project. I have bats whose attacks are projectiles. One that shoots sonic waves, one that throws snowballs, etc. So I guess it is a matter of finding which bats are in attack range for the appropriate bat. I want to be able to select which brain is being attacked by selecting a bat to be the selected bat by clicking on it and then clicking on the brain to attack. So I would iterate through the bat objects, for each bat check distance_to_pointt for all brains and if its say, the sentry bat, that is essentially a pawn and only attacks what's adjacent, .the sentry brain attacks the brain.

So:
1. Left Mouse Click
2. Loop through Bats
3 For each Brain check distance to point
4. If the range for the bat is less than or equal to check distance to point
5. Attack Brain with Bat

Does this sound reasonable?
 

TheouAegis

Member
Something like (again, not sure what objects are your parents, so i'll use objBigBrain and objSimpleBat)
Code:
if mouse_check_button_pressed(mb_left) {
   var n = instance_position(mouse_x,mouse_y, all);
   if n == noone {    //Check if the player is cancelling the attack
      colliderbrain = noone;
      if colliderbat != noone
         colliderbat.attackTarget = noone;    //Tell the currently selected bat to stop focusing a brain (optional)
      colliderbat = noone;    //Neither variable is temporary now, they're local to the controller object
      return 0;   //No point continuing with the script if nothing was clicked on
   }
   if n.object_index == objBigBrain || object_get_parent(n.object_index)==objBigBrain 
   {
      colliderbrain = n;
      colliderbat = noone;    //This may not work for you, but it would force the player to pick a new bat after clicking on a brain
   }
   if n.object_index == objSimpleBat || object_get_parent(n.object_index)==objSimpleBat
      colliderbat = n;
}

//Now that we may have established a brain-bat pairing, we can move on
if !colliderbrain || !colliderbat return 0;    //If either target hasn't been chosen, end the script for now

with colliderbat
   attackTarget = colliderbrain;  

with colliderbrain 
   if attackTarget == noone
      attackTarget = colliderbat;
   else
   if distance_to_object(attackTarget) > attackRange
      attackTarget = colliderbat;

colliderbrain = noone;
colliderbat = noone;
So your bats and brains would have a variable attackRange, which is how close they need to be to the target before engaging in combat. For ranged bats (or brains), this would be higher than for melee bats and brains. The target of each unit's attacks (to determine which one will take damage and where the projectiles will fly to) will be saved in the variables attackTarget that you'd give to all bats and brains.

Your bats would have in their Step Event something like
Code:
if attackTarget != noone {
   if distance_to_object(attackTarget) > attackRange
      move_toward_point(attackTarget.x,attackTarget.y, flyspeed);
   else
   {
      speed=0;
      //do your attacking stuff for the bat and deal damage to attackTarget
   }
}
For the brains, you could either have it move toward its attackTarget, or you could have it continue toward the castle if attackTarget is out of range. Otherwise, it's code would be similar. Have it attack when it's in range and deal its damage to the target bat.

With a structure like this, you'd be able to have multiple bats of different abilities attacking multiple brains. You could even have multiple bats attacking the same brain, or multiple brains attacking the same bat (if you wanted).

I left out the bit about setting attackTarget to noone in either case. Typically that would only happen when attackTarget finally dies.
 
@TheouAegis Awesome! Couple quick questions. How do I set the variable attackTarget. By that what I mean you have attackTarget.x and attackTarget.y. Same thing with n.object_index.
Another example:
Code:
var n = instance_position(mouse_x,mouse_y, all);
Is n.object_index built into the instance_position variable return? Also how is "all" used in this case?

For
Code:
 if n == noone {    //Check if the player is cancelling the attack
That's if the player clicks off of the bats/brains right? It is if the click off on the grass to escape?

Code:
colliderbat = noone;    //This may not work for you, but it would force the player to pick a new bat after clicking on a brain
   }
Why does this force t he player to pick a new bat?

Finally, this is all occuring in my script. Correct? Then the step event is where I actually do the movements?

Oh and I want your castlevania remake. I will pay for it.
 

TheouAegis

Member
In the Create events of brains and bats, default attackTarget to noone.

In the script that handles pairing up targets, as soon as colliderbrain and collider bat are both set, it assigns their ids to each other's attackTarget.

n is to see if the player clicked on anything; it's the id if whatever he clicked on. But you did bring up an issue I overlooked in my code.
if n == noone {
Since I used instance_position(mouse_x, mouse_y, all), n could be some other non-brain or non-bat instance in the room, which wouldn't work. So...
Code:
   var n = instance_position(mouse_x,mouse_y, all);
  
   if n.object_index == objBigBrain || object_get_parent(n.object_index)==objBigBrain
   {
     colliderbrain = n;
     colliderbat = noone;    //This may not work for you, but it would force the player to pick a new bat after clicking on a brain
   }
   else
   if n.object_index == objSimpleBat || object_get_parent(n.object_index)==objSimpleBat
     colliderbat = n;
   else {
      colliderbrain=noone;
      colliderbat=noone;
   }
So now if n is anything OTHER THAN a brain or bat, it will deselect both bat and brain (if any selected).


As for thtat line about picking a new bat, that's just to force the player to pick a brain first and then a bat. I don't rhink that would be a good mechanic after all, so yeah...

Also, sincr colliderbrain and colliderbat are now instance variables in your controller, you can have the controller draw a selection marker on the brain and/or bat.
 
Ok. I don't understand the attackTarget part. I can't do:

with colliderbrain.attackTarget { } can I?

Edit:

Ok I think I coded this right but it isn't selecting the colliderbrain or colliderbat. Its acting like I'm just clicking off - not on the bat or brain.

This is how my script is set up:

Code:
if mouse_check_button_pressed(mb_left) {
    show_debug_message("Mouse Check Button collision pressed");
  var n = instance_position(mouse_x,mouse_y, all);
 
   if n.object_index == BigBrainObject || object_get_parent(n.object_index)==BigBrainObject
   {
       show_debug_message("Big Brain Object is selected");
     colliderbrain = n;
     colliderbat = noone;    //This may not work for you, but it would force the player to pick a new bat after clicking on a brain
   }
   else
   if n.object_index == SentryBatObject || object_get_parent(n.object_index)==SentryBatObject {
     colliderbat = n;
     show_debug_message("Sentry Bat Object is selected");
   }
   else {
       show_debug_message("Click off of sentry bat and brain");
      colliderbrain=noone;
      colliderbat=noone;
   }
  
   with colliderbat
     attackTarget = colliderbrain; 

    with colliderbrain
      if attackTarget == noone
         attackTarget = colliderbat;
      else
      if distance_to_object(attackTarget) > attackRange
         attackTarget = colliderbat;

}

with colliderbrain
{   
    show_debug_message("With colliderbrain");
        with attackTarget
        {
            
            //damage to batq
            if (!global.group_invincibility)
            {
                hp = hp - 1;
                damage = 1;
                damage_dealt_to_bat = damage;
            }
    
        }
    
        ///colliderbrain is Brain
        show_debug_message("With colliderbrain");
        
                
        sprite_index = SimpleBrainAttack;
        
        
        //under_attack = true;
        //took_a_hit = true;
                    //sprite_index = SentryBatAttack
                    //image_speed = 1;
        audio_play_sound(BatThumpSound,20,false);
                
        show_debug_message("Showing Damage Indicator");
                
                    
                
        //killl the brain   
        if (hp <= 0)
        {
            show_debug_message("Kill the brain");
                    
            global.achievement_gold_counter++;
            global.achievement_tome_experience += 20;
            show_debug_message("Dead Brain Ghost and Fading Gem");
            audio_play_sound(DieingBrainSound, 20, false);
            instance_create_depth(x, y, -1100,DeadBrainObject);       
            instance_create_depth(x-150, y-20, -1100, FadingGemObject);
            instance_destroy();
        }
    
}

with colliderbat
{
    sprite_index = SentryBatAttack;
    
    with attackTarget
    {
        hp_minus = irandom_range(10, 50);
        hp = hp - hp_minus;
            
    
        floater = instance_create_depth(x+10, y-10, -17000, DamageIndicatorObject);
        floater.text = string(hp_minus);
    }
        
        
    if (hp <= 0)
    {
        audio_play_sound(BatDeathSound, 20, false);
        instance_create_depth(x, y, -1100,DeadBatObject);
        global.num_sentry_killed++;
        instance_destroy();
                        
            
    }
    
}
And the output is just:

"Click off of sentry bat and brain"
 
Last edited by a moderator:
I'm not using parenting.

The following is the code you gave me to do the pairing:

Code:
if mouse_check_button_pressed(mb_left) {
    show_debug_message("Mouse Check Button collision pressed");
  var n = instance_position(mouse_x,mouse_y, all);
 
   if n.object_index == BigBrainObject || object_get_parent(n.object_index)==BigBrainObject
   {
       show_debug_message("Big Brain Object is selected");
     colliderbrain = n;
     colliderbat = noone;    //This may not work for you, but it would force the player to pick a new bat after clicking on a brain
   }
   else
   if n.object_index == SentryBatObject || object_get_parent(n.object_index)==SentryBatObject {
     colliderbat = n;
     show_debug_message("Sentry Bat Object is selected");
   }
   else {
       show_debug_message("Click off of sentry bat and brain");
      colliderbrain=noone;
      colliderbat=noone;
   }
 
   with colliderbat
     attackTarget = colliderbrain;

    with colliderbrain
      if attackTarget == noone
         attackTarget = colliderbat;
      else
      if distance_to_object(attackTarget) > attackRange
         attackTarget = colliderbat;

}

with colliderbrain
{  
    show_debug_message("With colliderbrain");
        with attackTarget
        {
           
            //damage to batq
            if (!global.group_invincibility)
            {
                hp = hp - 1;
                damage = 1;
                damage_dealt_to_bat = damage;
            }
   
        }
   
        ///colliderbrain is Brain
        show_debug_message("With colliderbrain");
       
               
        sprite_index = SimpleBrainAttack;
       
       
        //under_attack = true;
        //took_a_hit = true;
                    //sprite_index = SentryBatAttack
                    //image_speed = 1;
        audio_play_sound(BatThumpSound,20,false);
               
        show_debug_message("Showing Damage Indicator");
               
                   
               
        //killl the brain  
        if (hp <= 0)
        {
            show_debug_message("Kill the brain");
                   
            global.achievement_gold_counter++;
            global.achievement_tome_experience += 20;
            show_debug_message("Dead Brain Ghost and Fading Gem");
            audio_play_sound(DieingBrainSound, 20, false);
            instance_create_depth(x, y, -1100,DeadBrainObject);      
            instance_create_depth(x-150, y-20, -1100, FadingGemObject);
            instance_destroy();
        }
   
}

with colliderbat
{
    sprite_index = SentryBatAttack;
   
    with attackTarget
    {
        hp_minus = irandom_range(10, 50);
        hp = hp - hp_minus;
           
   
        floater = instance_create_depth(x+10, y-10, -17000, DamageIndicatorObject);
        floater.text = string(hp_minus);
    }
       
       
    if (hp <= 0)
    {
        audio_play_sound(BatDeathSound, 20, false);
        instance_create_depth(x, y, -1100,DeadBatObject);
        global.num_sentry_killed++;
        instance_destroy();
                       
           
    }









On a side note the step event for the bats is:

Code:
if (hp <= 0)
{
    instance_destroy();
}


if attackTarget != noone {
   if distance_to_object(attackTarget) > attackRange
      move_towards_point(attackTarget.x,attackTarget.y, flyspeed);
   else
   {
      speed=0;
      //do your attacking stuff for the bat and deal damage to attackTarget
   }
}

        if (flight == true)
        {  
           
                       
               
           
            if (!global.acceleration)
            {
                if (point_distance(x, y, target_placement_x-100, target_placement_y-100) > 15)
                {
                    play_timer--;
                    if (played == false)
                    {
                        audio_play_sound(BatWingsMovementSound, 20, false);
                        played = true;
                    }
                    if (play_timer <= 0)
                    {
                        played = false;
                        play_timer = room_speed*2;
                    }
               
                    sprite_index = SentryBatWalk;
                    move_towards_point( target_placement_x-100, target_placement_y-100, 10 );  
                    global.dropped_bat = false;
                   
                }
                else
                {
                    speed = 0;
                    flight = false;
                    sprite_index = SentryBatIdle;
                }
            }
           
            else
            {
                if (point_distance(x, y, target_placement_x-100, target_placement_y-100) > 40)
                {
                   
                    play_timer--;
                    if (played == false)
                    {
                        audio_play_sound(BatWingsMovementSound, 20, false);
                        played = true;
                    }
                    if (play_timer <= 0)
                    {
                        played = false;
                        play_timer = room_speed*2;
                    }
               
                   
                                   
                    sprite_index = SentryBatWalk;
                    move_towards_point( target_placement_x-100, target_placement_y-100, 30 );  
                    global.dropped_bat = false;
                }
                else
                {
                    speed = 0;
                    flight = false;
                    sprite_index = SentryBatIdle;
                }
           
           
            }
        }
       
   

    //if invincible
    if (global.group_invincibility == true)
    {
        //if the cross doesn't already exist
        if (!object_exists(AlchemistInvincibleObject))
        {
            //create a cross
            inst = instance_create_depth(x+110, y+110, -1100, AlchemistInvincibleObject);
        }
        //move sentry bats along wi                  th the bat
        //cross
        with (AlchemistInvincibleObject)
        {
            x = other.x;
            y = other.y;
            move_towards_point( other.x-10, other.y-10, 10 );  
        }      
       
    }
   
///////////////////////ACCELERAtion///////////////

//if invincible
    if (global.acceleration)
    {
        //if the cross doesn't already exist
        if (!object_exists(AccelerationBuff))
        {
            //create a lightning bolt
            inst = instance_create_depth(x+110, y+110, -1100,AccelerationBuff);
        }
        //move sentry bats along wi                  th the bat
        //cross
        with (AccelerationBuff)
        {
            //x = other.x;
            //y = other.y;
            if distance_to_point(other.x-10,other.y-10) < 20
            {
                x = other.x-10;
                y = other.y-10;
                speed = 0;
            }
   
           
            move_towards_point( other.x-10, other.y-10, 20 );  
        }      
       
    }

global.SentryBatObject_x = x;
global.SentryBatObject_y = y;
           
       
        //////////DOOOM DIFFICULTY///////////


with(SentryBatObject)
{
   
    doom_timer--;
   
    if (doom_timer <= 0 && global.doom_difficulty)
    {
        hp -= 20; //slowly drains health  
        doom_timer = room_speed;
    }
   
   
}
And the code for the step event for the simple brain

Code:
//SimpleBrainSentryBatCollision(x,y);

if attackTarget != noone {
   if distance_to_object(attackTarget) > attackRange
      move_towards_point(attackTarget.x,attackTarget.y, flyspeed);
   else
   {
      speed=0;
      //do your attacking stuff for the bat and deal damage to attackTarget
   }
}

BrainBatCollision();


//If you collide with the castle vanish
if (path_position == 1)
{
    //reached the castle)
    instance_destroy();
}


//collide with castle
//castle_collision_timer--;

//if (castle_collision_timer <= 0)
//{
if (collision_rectangle( 153,  800, 700, 1300, BigBrainObject, false, false ))
{
   
        show_debug_message("Collide with Castle");
        //sprite_index = BigBrainAttacking;
        //attack the castle
        hp_minus = irandom_range(200, 500);
        global.castle_hp -= hp_minus;

        floater = instance_create_depth(x+10, y-10, -1700, DamageIndicatorObject);
        floater.text = string(hp_minus);
        castle_collision_timer = room_speed*5;
        instance_destroy();
}
//}




//hit the castle
if (x < 200)
{
    instance_destroy();
}


//was hit by a snowball
if (frozen)
{
    path_speed =0;
    speed = 0;
    sprite_index = SnowBatStill;
    alarm[9] = room_speed;
}

//petrified
if (global.petrification)
{
    show_debug_message("Petrified");
    path_speed = 0;
    speed = 0
    sprite_index = PetrifiedBrain;
}

if (global.freeze_brains)
{
    path_speed = 0;
    speed = 0;
    //sprite_index = BigBrainStill;
    alarm[9] = room_speed;
}

//hit by lightning
was_hit_by_lit = false;




//show_debug_message("lit_damage_timera: " + string(lit_damage_timera));
//show_debug_message("lit_damage_timerb: " + string(lit_damage_timerb));
//show_debug_message("lit_damage_timerc: " + string(lit_damage_timerc));

if (global.active == true && collision_line(global.litorigin_x, global.litorigin_y, global.lightning_1_x, global.lightning_1_y, SimpleBrain, false, false))
{
    lit_damage_timera--;
    show_debug_message("lit_damage_timera: " + string(lit_damage_timera));
    if (lit_damage_timera <= 0)
    {
       
        show_debug_message("Lit Timer A fire: ");
        hp_minus = irandom_range(100,400);
        damage = hp_minus;
        hp = hp - hp_minus;
        floater = instance_create_depth(x, y, -17000, DamageIndicatorObject)  
        floater.text = string(damage)
   
        under_attack = true;
        took_a_hit = true;
        was_hit_by_lit = true;
        lit_damage_timera = room_speed*4;
       
    }
}


if (global.active == true && collision_line(global.lightning_1_x, global.lightning_1_y, global.lightning_2_x, global.lightning_2_y, SimpleBrain, false, false))
{
    lit_damage_timerb--;

    if (lit_damage_timerb <= 0)
    {
        show_debug_message("Lit Timer B fire: ");
        hp_minus = irandom_range(100,400);
        damage = hp_minus;
        hp = hp - hp_minus;
        floater = instance_create_depth(x, y, -17000, DamageIndicatorObject)  
        floater.text = string(damage)
   
        under_attack = true;
        took_a_hit = true;
        was_hit_by_lit = true;
        lit_damage_timerb = room_speed*4;
    }
}


if (global.active == true && collision_line(global.lightning_2_x, global.lightning_2_y, global.lightning_3_x, global.lightning_3_y, SimpleBrain, false, false))
{
    lit_damage_timerc--;
    if (lit_damage_timerc <=0)
    {
       
        show_debug_message("Lit Timer C fire: ");
        hp_minus = irandom_range(100,400);
        damage = hp_minus;
        hp = hp - hp_minus;
        floater = instance_create_depth(x, y, -17000, DamageIndicatorObject)  
        floater.text = string(damage)
   
        under_attack = true;
        was_hit_by_lit = true;
        lit_damage_timerc = room_speed*4;
    }
}

if (was_hit_by_lit == true && global.active == false)
{
    under_attack = false;
}
if (position_meeting(x, y, SimpleBrain))
{
    SimpleBrain.y = SimpleBrain.y - 350;
}






/////////////////////////////////
//Poison ZTimer
//


if (poisoned)
{
   
    timer--;
    if (timer <= 0)
    {
        damage = irandom_range(0,20);
        hp_minus = damage;
        timer = 0;
        floater = instance_create_depth(x+10, y-10, -17000, DamageIndicatorObject);
        floater.text = string(hp_minus);
       
        if (hp <= 0)
        {
            show_debug_message("Dead Brain Ghost and Fading Gem");
            instance_create_depth(x, y, -1100,DeadBrainObject);      
            instance_create_depth(x-150, y-20, -1100, FadingGemObject);
            global.achievement_gold_counter++;
           
            global.achievement_tome_experience += 20;
            instance_destroy();
        }
        timer = room_speed;
    }
    under_attack = true;
    took_a_hit = true;
}
   
//////////END OF PATH/////////////////////







if (global.freeze_brains)
{
    path_speed = 0;
}
//else
//{
//    path_speed = 5;

   



//////////////Attack on Castle Wall/////////////////////////

if (point_in_rectangle(x-100, y, 156, 798, 714, 1277))
{
    show_debug_message("Wall Collision");

    castle_wall_timer--;
   
    if (castle_wall_timer <= 0)
    {
        hp_minus = irandom_range(4, 50);
        global.castle_hp = global.castle_hp - hp_minus;
        path_end();
        sprite_index = SimpleBrainAttack;

        castle_wall_timer--;

        number_of_attacks++;

        if (number_of_attacks > 5)
        {
            instance_destroy();
        }
   
   
        castle_wall_timer = room_speed;
       
       
        floater = instance_create_depth(x+10, y-10, -17000, DamageIndicatorObject)    ;
        floater.text = string(hp_minus);  
        show_debug_message("Iterating through step wall timer");
    }



}
//////////////ATTACK ON INNERTUBE//////////////////////////

if (point_in_rectangle(x, y, 46, 552, 346, 847))
{
    show_debug_message("Wall Collision");

    castle_wall_timer--;
   
    if (castle_wall_timer <= 0)
    {
        hp_minus = irandom_range(50, 150);
        global.castle_hp = global.castle_hp - hp_minus;
        path_end();
        sprite_index = SimpleBrainAttack;

        castle_wall_timer--;

        number_of_attacks++;

       
       
        castle_wall_timer = room_speed;
       
       
        floater = instance_create_depth(x+10, y-10, -17000, DamageIndicatorObject)    ;
        floater.text = string(hp_minus);  
        show_debug_message("Iterating through step wall timer");
       
        if (number_of_attacks > 5)
        {
            number_of_attacks = 0;
            instance_destroy();
        }
   
    }



}

///////////////////////////////////////////

mind_timer--;

if (global.mindbreak && mind_timer <= 0)
{
    mind_timer = room_speed*3;
    path_number = irandom_range(0, 4);
    path_end();
    if (path_number == 0)
    {
        x++;
    }
    if (path_number == 1)
    {
        x--;
    }
    if (path_number == 2)
    {
        y++;
    }
    if (path_number == 3)
    {
        y--;
    }
   
   
}
 

TheouAegis

Member
Okay if you are not using parenting, then specifically which objects are you testing this with? Is the player specifically creating an instance of SentryBatObject and not any other kind of bat, and is the enemy specifically creating an instance of BigBrainObject and not any other kind of brain?

Your project is going to have multiple types of bats and possibly multiple types of brains. In order to do that, you need to use parenting, or else you're using some other method to dictate how they are going to attack with different methods.

The issue right now is that neither of the two variables are getting set because the game is not registering that you are clicking on either BigBrainObject or a child of BigBrainObject, nor on SentryBatObject or a child of SentryBatObject. the first time I have to make sure you're you are even using the right objects in your testing.
 
Yes l guess I should use parenting. Right now the player specifically creates an instance of SentryBatObject and no other kind of bat.The enemy creates an instance of BigBrainObject and not any other kind of brain. So the code being tested is just for SentryBatObject and BigBrainObject. And so, yeah, the two variables aren't getting set, I get that much.
 

TheouAegis

Member
Hmmm...

First issue to correct that I missed:
Code:
   with colliderbat
    attackTarget = other.colliderbrain;

   with colliderbrain
     if attackTarget == noone
        attackTarget = other.colliderbat;
     else
     if distance_to_object(attackTarget) > attackRange
        attackTarget = other.colliderbat;

}
I left out the other. prefixes in those lines. That will throw an error once we get past the current issue. lol

Also, you NEED to check if n!=noone, or else the "object_index" checks will crash.
Code:
  var n = instance_position(mouse_x,mouse_y, all);
  if n == noone return 0;
Now, aside from those two errors, both of which were my bad, the code should work. At least, the code should be registering if a brain is clicked on and if a bat is clicked on. I just tested the main block of code in my own simple project, drawing text on-screen if and only if both colliderbrain and colliderbat got set. So then that leads to me consider a few possibilities.

1) The code is in an event that cannot register the mouse, but when that would be, I'm not sure.

2) Your bat and brain have a mask_index that is too small.

3) Your bat and brain have neither a mask_index nor a sprite_index assigned.

4) Your bat and brain's sprites have inappropriately sized bounding boxes.

5) You are using this code in the Draw GUI event for some reason.

Like I said, it worked for me just now. It required I click on a brain first, then a bat; if I clicked on a bat first, then the brain would cancel the bat and the text wouldn't show; if I clicked on emptiness, the text wouldn't show. So those are the five possibilities I could come up with as to why it's working for me but not you.
 
I agree. @TheouAegis should deserve a medal. Or a donation for all his work with me. I'm still a beginner with GMS2 compared to @TheouAegis . Anyway, accolades aside, the
pairing still isn't working. Out of the debug messages, only "Click off of sentry bat and brain" and "Mouse Check Button collision pressed" shows up

Code:
if mouse_check_button_pressed(mb_left) {
    show_debug_message("Mouse Check Button collision pressed");
  var n = instance_position(mouse_x,mouse_y, all);
  if n == noone return 0;
   if n.object_index == BigBrainObject || object_get_parent(n.object_index)==BigBrainObject
   {
       show_debug_message("Big Brain Object is selected");
     colliderbrain = n;
     colliderbat = noone;    //This may not work for you, but it would force the player to pick a new bat after clicking on a brain
   }
   else
   if n.object_index == SentryBatObject || object_get_parent(n.object_index)==SentryBatObject {
     colliderbat = n;
     show_debug_message("Sentry Bat Object is selected");
   }
   else {
       show_debug_message("Click off of sentry bat and brain");
      colliderbrain=noone;
      colliderbat=noone;
   }
  
   with colliderbat
     attackTarget = other.colliderbrain; 

    with colliderbrain
      if attackTarget == noone
         attackTarget = other.colliderbat;
      else
      if distance_to_object(attackTarget) > attackRange
         attackTarget = other.colliderbat;

}
I"m thinking it is
Code:
var n = instance_position(mouse_x,mouse_y, all);
.Should we be using "all"?

Also, is this kosher? (It's right under the the pairing code)

Code:
with colliderbrain
{   
    show_debug_message("With colliderbrain");
        with attackTarget
        {
            
            //damage to batq
            if (!global.group_invincibility)
            {
                hp = hp - 1;
                damage = 1;
                damage_dealt_to_bat = damage;
            }
    
        }
    
        ///colliderbrain is Brain
        show_debug_message("With colliderbrain");
        
                
        sprite_index = SimpleBrainAttack;
        
        
        //under_attack = true;
        //took_a_hit = true;
                    //sprite_index = SentryBatAttack
                    //image_speed = 1;
        audio_play_sound(BatThumpSound,20,false);
                
        show_debug_message("Showing Damage Indicator");
                
                    
                
        //killl the brain   
        if (hp <= 0)
        {
            show_debug_message("Kill the brain");
                    
            global.achievement_gold_counter++;
            global.achievement_tome_experience += 20;
            show_debug_message("Dead Brain Ghost and Fading Gem");
            audio_play_sound(DieingBrainSound, 20, false);
            instance_create_depth(x, y, -1100,DeadBrainObject);       
            instance_create_depth(x-150, y-20, -1100, FadingGemObject);
            instance_destroy();
        }
    
}
I'm just trying to explore all the possibilities.
 

TheouAegis

Member
Right now I'm just trying to figure out why you can't click on anything. Right now you can't even get to the "kosher" code. We can worry about that when we get to it. And no it can't be that all because like I said, it works just fine for me. So verify the five points that I listed in the last post. Check your sprites, check your object properties, check what event the code is in.
 
Hmmm...

First issue to correct that I missed:
Code:
   with colliderbat
    attackTarget = other.colliderbrain;

   with colliderbrain
     if attackTarget == noone
        attackTarget = other.colliderbat;
     else
     if distance_to_object(attackTarget) > attackRange
        attackTarget = other.colliderbat;

}
I left out the other. prefixes in those lines. That will throw an error once we get past the current issue. lol

Also, you NEED to check if n!=noone, or else the "object_index" checks will crash.
Code:
  var n = instance_position(mouse_x,mouse_y, all);
  if n == noone return 0;
Now, aside from those two errors, both of which were my bad, the code should work. At least, the code should be registering if a brain is clicked on and if a bat is clicked on. I just tested the main block of code in my own simple project, drawing text on-screen if and only if both colliderbrain and colliderbat got set. So then that leads to me consider a few possibilities.

1) The code is in an event that cannot register the mouse, but when that would be, I'm not sure.

2) Your bat and brain have a mask_index that is too small.

3) Your bat and brain have neither a mask_index nor a sprite_index assigned.

4) Your bat and brain's sprites have inappropriately sized bounding boxes.

5) You are using this code in the Draw GUI event for some reason.

Like I said, it worked for me just now. It required I click on a brain first, then a bat; if I clicked on a bat first, then the brain would cancel the bat and the text wouldn't show; if I clicked on emptiness, the text wouldn't show. So those are the five possibilities I could come up with as to why it's working for me but not you.
Ok. So.

1) I don't know how to check that.
2) The masks are rectangles that encompass the entire sprite
3) Don't know how to check this.
4) See 2.
5) Not in a Draw GUI. I never use Draw GUI.

Boy I feel dumb now..


So, BrainBatCollision() in SimpleBrain's step event is where I put the following:

Code:
if mouse_check_button_pressed(mb_left) {
    show_debug_message("Mouse Check Button collision pressed");
  var n = instance_position(mouse_x,mouse_y, all);
  if n == noone return 0;
   if n.object_index == BigBrainObject || object_get_parent(n.object_index)==BigBrainObject
   {
       show_debug_message("Big Brain Object is selected");
     colliderbrain = n;
     colliderbat = noone;    //This may not work for you, but it would force the player to pick a new bat after clicking on a brain
   }
   else
   if n.object_index == SentryBatObject || object_get_parent(n.object_index)==SentryBatObject {
     colliderbat = n;
     show_debug_message("Sentry Bat Object is selected");
   }
   else {
       show_debug_message("Click off of sentry bat and brain");
      colliderbrain=noone;
      colliderbat=noone;
   }
  
   with colliderbat
     attackTarget = other.colliderbrain; 

    with colliderbrain
      if attackTarget == noone
         attackTarget = other.colliderbat;
      else
      if distance_to_object(attackTarget) > attackRange
         attackTarget = other.colliderbat;

}

with colliderbrain
{   
    show_debug_message("With colliderbrain");
        with attackTarget
        {
            
            //damage to batq
            if (!global.group_invincibility)
            {
                hp = hp - 1;
                damage = 1;
                damage_dealt_to_bat = damage;
            }
    
        }
    
        ///colliderbrain is Brain
        show_debug_message("With colliderbrain");
        
                
        sprite_index = SimpleBrainAttack;
        
        
        //under_attack = true;
        //took_a_hit = true;
                    //sprite_index = SentryBatAttack
                    //image_speed = 1;
        audio_play_sound(BatThumpSound,20,false);
                
        show_debug_message("Showing Damage Indicator");
                
                    
                
        //killl the brain   
        if (hp <= 0)
        {
            show_debug_message("Kill the brain");
                    
            global.achievement_gold_counter++;
            global.achievement_tome_experience += 20;
            show_debug_message("Dead Brain Ghost and Fading Gem");
            audio_play_sound(DieingBrainSound, 20, false);
            instance_create_depth(x, y, -1100,DeadBrainObject);       
            instance_create_depth(x-150, y-20, -1100, FadingGemObject);
            instance_destroy();
        }
    
}

with colliderbat
{
    sprite_index = SentryBatAttack;
    
    with attackTarget
    {
        hp_minus = irandom_range(10, 50);
        hp = hp - hp_minus;
            
    
        floater = instance_create_depth(x+10, y-10, -17000, DamageIndicatorObject);
        floater.text = string(hp_minus);
    }
        
        
    if (hp <= 0)
    {
        audio_play_sound(BatDeathSound, 20, false);
        instance_create_depth(x, y, -1100,DeadBatObject);
        global.num_sentry_killed++;
        instance_destroy();
                        
            
    }
    
}
Also in Simple Brain's step I put:
Code:
if attackTarget != noone {
   if distance_to_object(attackTarget) > attackRange
      move_towards_point(attackTarget.x,attackTarget.y, flyspeed);
   else
   {
      speed=0;
      //do your attacking stuff for the bat and deal damage to attackTarget
   }
}
Also in Sentry Bat's step I put:

Code:
if attackTarget != noone {
   if distance_to_object(attackTarget) > attackRange
      move_towards_point(attackTarget.x,attackTarget.y, flyspeed);
   else
   {
      speed=0;
      //do your attacking stuff for the bat and deal damage to attackTarget
   }
}
 

TheouAegis

Member
BatBrainCollision should be called inside of a separate, controller object, neither in the bat nor the brain.

I'm not sure why that would affect anyting, but that is the basis of the logic of the code.
 
BatBrainCollision should be called inside of a separate, controller object, neither in the bat nor the brain.

I'm not sure why that would affect anyting, but that is the basis of the logic of the code.
I have separate controllers for the brains and for the bats. I don't know....should I create a separate controller just for the BatBrainCollisions..? IDK
 

TheouAegis

Member
Yes. At least it won't hurt for now. If there is still an issue even with that, then at least we ruled it out. but the reason you don't want that code inside of either brain or the bat is because if you have more than one brain or more than one bat active than that code is going to get run multiple times needlessly.

As for point 3, you'd probably k ow if sprite_index is not set, as you would have to use a Draw event just to even see the bat or brain.
 
Alright @TheouAegis . I created an object for a controller called MasterController. I put a call to the function BrainBatCollision in the step event of MasterControlller. I added MasterController to the Level One Room. This is what happened w hen I ran it:

upload_2019-4-11_0-52-44.png
 

TheouAegis

Member
Cuz you left this line out from my code:


if !colliderbrain || !colliderbat return 0; //If either target hasn't been chosen, end the script for now
 
Hi @TheouAegis . So I fixed that mistake of mine. I have created a Master Controller that calls your script (the pairing script) in the step event. I put the Master Controller object in the game room.
So I got a an error saying that:

___________________________________________
############################################################################################
FATAL ERROR in
action number 1
of Step Event0
for object MasterController:
Variable MasterController.colliderbrain(100046, -2147483648) not set before reading it.
at gml_Script_BrainBatCollision (line 44) - with colliderbrain
############################################################################################
--------------------------------------------------------------------------------------------
stack frame is
gml_Script_BrainBatCollision (line 44)
called from - gml_Object_MasterController_Step_0 (line 2) - BrainBatCollision();
It said that for both. So I added colliderbrain = noone and colliderbat = noone to the top of the script.
My sentrybat isn't attacking and when Itry to retreat it lets me retreat somewhat but then gets stuck. I can
only retreat backwards, not upwards or on any angles.

So does this attack code in the script look right?

Code:
//test

//colliderbrain = noone;
//colliderbat = noone;
//test
if mouse_check_button_pressed(mb_left) {
    show_debug_message("Mouse Check Button collision pressed");
  var n = instance_position(mouse_x,mouse_y, all);
  if n == noone return 0;
   if n.object_index == BigBrainObject || object_get_parent(n.object_index)==BigBrainObject
   {
       show_debug_message("Big Brain Object is selected");
     colliderbrain = n;
     colliderbat = noone;    //This may not work for you, but it would force the player to pick a new bat after clicking on a brain
   }
   else
   if n.object_index == SentryBatObject || object_get_parent(n.object_index)==SentryBatObject {
     colliderbat = n;
     show_debug_message("Sentry Bat Object is selected");
   }
   else {
       show_debug_message("Click off of sentry bat and brain");
      colliderbrain=noone;
      colliderbat=noone;
   }
 
   //Now that we may have established a brain-bat pairing, we can move on
    if !colliderbrain || !colliderbat return 0;    //If either target hasn't been chosen, end the script for now
 
   with colliderbat
     attackTarget = other.colliderbrain;

    with colliderbrain
      if attackTarget == noone
         attackTarget = other.colliderbat;
      else
      if distance_to_object(attackTarget) > attackRange
         attackTarget = other.colliderbat;

}

with colliderbrain
{  
    show_debug_message("With colliderbrain");
        with attackTarget
        {
           
            //damage to batq
            if (!global.group_invincibility)
            {
                hp = hp - 1;
                damage = 1;
                damage_dealt_to_bat = damage;
            }
   
        }
   
        ///colliderbrain is Brain
        show_debug_message("With colliderbrain");
       
               
        sprite_index = SimpleBrainAttack;
       
       
        //under_attack = true;
        //took_a_hit = true;
                    //sprite_index = SentryBatAttack
                    //image_speed = 1;
        audio_play_sound(BatThumpSound,20,false);
               
        show_debug_message("Showing Damage Indicator");
               
                   
               
        //killl the brain  
        if (hp <= 0)
        {
            show_debug_message("Kill the brain");
                   
            global.achievement_gold_counter++;
            global.achievement_tome_experience += 20;
            show_debug_message("Dead Brain Ghost and Fading Gem");
            audio_play_sound(DieingBrainSound, 20, false);
            instance_create_depth(x, y, -1100,DeadBrainObject);      
            instance_create_depth(x-150, y-20, -1100, FadingGemObject);
            instance_destroy();
        }
   
}

with colliderbat
{
    sprite_index = SentryBatAttack;
   
    with attackTarget
    {
        hp_minus = irandom_range(10, 50);
        hp = hp - hp_minus;
           
   
        floater = instance_create_depth(x+10, y-10, -17000, DamageIndicatorObject);
        floater.text = string(hp_minus);
    }
       
       
    if (hp <= 0)
    {
        audio_play_sound(BatDeathSound, 20, false);
        instance_create_depth(x, y, -1100,DeadBatObject);
        global.num_sentry_killed++;
        instance_destroy();
                       
           
    }
   
}
And can you verify the step events In the Sentry bat?

Code:
if (hp <= 0)
{
    instance_destroy();
}


if attackTarget != noone {
   if distance_to_object(attackTarget) > attackRange
      move_towards_point(attackTarget.x,attackTarget.y, flyspeed);
   else
   {
      speed=0;
      //do your attacking stuff for the bat and deal damage to attackTarget
   }
}

        if (flight == true)
        {  
           
                       
               
           
            if (!global.acceleration)
            {
                if (point_distance(x, y, target_placement_x-100, target_placement_y-100) > 15)
                {
                    play_timer--;
                    if (played == false)
                    {
                        audio_play_sound(BatWingsMovementSound, 20, false);
                        played = true;
                    }
                    if (play_timer <= 0)
                    {
                        played = false;
                        play_timer = room_speed*2;
                    }
               
                    sprite_index = SentryBatWalk;
                    move_towards_point( target_placement_x-100, target_placement_y-100, 10 );  
                    global.dropped_bat = false;
                   
                }
                else
                {
                    speed = 0;
                    flight = false;
                    sprite_index = SentryBatIdle;
                }
            }
           
            else
            {
                if (point_distance(x, y, target_placement_x-100, target_placement_y-100) > 40)
                {
                   
                    play_timer--;
                    if (played == false)
                    {
                        audio_play_sound(BatWingsMovementSound, 20, false);
                        played = true;
                    }
                    if (play_timer <= 0)
                    {
                        played = false;
                        play_timer = room_speed*2;
                    }
               
                   
                                   
                    sprite_index = SentryBatWalk;
                    move_towards_point( target_placement_x-100, target_placement_y-100, 30 );  
                    global.dropped_bat = false;
                }
                else
                {
                    speed = 0;
                    flight = false;
                    sprite_index = SentryBatIdle;
                }
           
           
            }
        }
       
   

    //if invincible
    if (global.group_invincibility == true)
    {
        //if the cross doesn't already exist
        if (!object_exists(AlchemistInvincibleObject))
        {
            //create a cross
            inst = instance_create_depth(x+110, y+110, -1100, AlchemistInvincibleObject);
        }
        //move sentry bats along wi                  th the bat
        //cross
        with (AlchemistInvincibleObject)
        {
            x = other.x;
            y = other.y;
            move_towards_point( other.x-10, other.y-10, 10 );  
        }      
       
    }
   
///////////////////////ACCELERAtion///////////////

//if invincible
    if (global.acceleration)
    {
        //if the cross doesn't already exist
        if (!object_exists(AccelerationBuff))
        {
            //create a lightning bolt
            inst = instance_create_depth(x+110, y+110, -1100,AccelerationBuff);
        }
        //move sentry bats along wi                  th the bat
        //cross
        with (AccelerationBuff)
        {
            //x = other.x;
            //y = other.y;
            if distance_to_point(other.x-10,other.y-10) < 20
            {
                x = other.x-10;
                y = other.y-10;
                speed = 0;
            }
   
           
            move_towards_point( other.x-10, other.y-10, 20 );  
        }      
       
    }

global.SentryBatObject_x = x;
global.SentryBatObject_y = y;
           
        
   
}
And simple brain step event
Code:
//SimpleBrainSentryBatCollision(x,y);

if attackTarget != noone {
   if distance_to_object(attackTarget) > attackRange
      move_towards_point(attackTarget.x,attackTarget.y, flyspeed);
   else
   {
      speed=0;
      //do your attacking stuff for the bat and deal damage to attackTarget
   }
}
 

TheouAegis

Member
I added colliderbrain = noone and colliderbat = noone to the top of the script.
You only set colliderbrain and colliderbat to noone in the Create Event and when the player clicks on something other than a brain or bat. You do NOT want to reset them every time the script is called, since the player needs time to click on one instance and then another.

if mouse_check_button_pressed(mb_left) {
...
...
}

with colliderbrain

You MUST put the conditional I mentioned back in here. You took it out when you tried to optimize my code, but it was one part of my code that was critical.

Code:
if mouse_check_button_pressed(mb_left) {
...
...
} 

if !colliderbrain || !colliderbat return 0;

with colliderbrain...
 
Ok. The conditional is put back in. The colliderbat and colliderbrain are only set to noone when player clicks on something other than a brain or bat or in the create event of the controller. I'm clicking on the bat then the brain then on the bat then on the brain and so on. I'm not sure if the pairing is working or if its the attack code. suggestions?
 

TheouAegis

Member
The required order is brain then bat. If you go bat then brain, you would need to click on the bat again. Of course you can change this around a little bit by changing the structure of that very first block.

The way I tested my code was I had a GUI draw event in the controller object. I had it draw the values of colliderbrain and colliderbat at all times. If I clicked on a brain, I would see that brain's ID. If I then clicked on a bat, I would also see that bat's ID. Since in my demo I didn't do anything at that point, the two numbers stayed on my screen. Then I clicked onthe room somewhere other than either a brain or a bat, and both numbers went to -4. I then clicked on a bat, the bat ID showed up. then I clicked on the brain and the Brain ID showed up but the bat ID was reset to -4. And I clicked on the bat again and the bat ID showed back up and again both the brain ID and the bat ID were drawn in my GUI. after that I knew that my code was properly setting the variables colliderbrain and colliderbat. It is at that point when colliderbrain and colliderbat are both set to IDs that they are technically paired.

So do that, use the GUI event in the controller object to verify in real time on screen that the brain and/or bat are getting selected and he selected properly. I will try to look through the rest of your code in the meantime. I've got the flu or something right now - although the doctor says it's not the flu but it doesn't feel like a freaking cold either - so I'm not spending too much time on GM stuff this week.

Side note:
that conditional that I had you put back in which I said was critical is the conditional which checks if they are paired. The reason it was a critical conditional is because it follows the logic pattern

If A then B;
If A then not C;
If C then D;
If B and D then E

But you took out that conditional, which left you with

If A then B;
If A then not C;
If C then D;
B and D;
Therefor E

By removing that conditional, the code became presumptuous that both variables had been set, which is not how the code works.
 
The required order is brain then bat. If you go bat then brain, you would need to click on the bat again. Of course you can change this around a little bit by changing the structure of that very first block.

The way I tested my code was I had a GUI draw event in the controller object. I had it draw the values of colliderbrain and colliderbat at all times. If I clicked on a brain, I would see that brain's ID. If I then clicked on a bat, I would also see that bat's ID. Since in my demo I didn't do anything at that point, the two numbers stayed on my screen. Then I clicked onthe room somewhere other than either a brain or a bat, and both numbers went to -4. I then clicked on a bat, the bat ID showed up. then I clicked on the brain and the Brain ID showed up but the bat ID was reset to -4. And I clicked on the bat again and the bat ID showed back up and again both the brain ID and the bat ID were drawn in my GUI. after that I knew that my code was properly setting the variables colliderbrain and colliderbat. It is at that point when colliderbrain and colliderbat are both set to IDs that they are technically paired.

So do that, use the GUI event in the controller object to verify in real time on screen that the brain and/or bat are getting selected and he selected properly. I will try to look through the rest of your code in the meantime. I've got the flu or something right now - although the doctor says it's not the flu but it doesn't feel like a freaking cold either - so I'm not spending too much time on GM stuff this week.

Side note:
that conditional that I had you put back in which I said was critical is the conditional which checks if they are paired. The reason it was a critical conditional is because it follows the logic pattern

If A then B;
If A then not C;
If C then D;
If B and D then E

But you took out that conditional, which left you with

If A then B;
If A then not C;
If C then D;
B and D;
Therefor E

By removing that conditional, the code became presumptuous that both variables had been set, which is not how the code works.

Ok. So where should I put the main script? The GUI event or the Step Event? And how do I access the colliderbrain and batbrain in the GUI? FOr example:

Draw GUI:

Code:
BrainBatCollision();
draw_text_transformed_color(400, 100, "colliderbat: " + string(colliderbat.object_index), 2, 2, 0, c_black, c_black, c_black, c_black, 1);
draw_text_transformed_color(400, 100, "colliderbrain: " + string(colliderban.object_index), 2, 2, 0, c_black, c_black, c_black, c_black, 1);
 

TheouAegis

Member
BrainBatCollision() goes in the Step Event.

The GUI event needs to account for colliderbat/brain being noone sometimes.
Code:
if colliderbat==noone draw_text(400,100,"Colliderbat: Not Selected");
else draw_text(400,100,"Colliderbat: Selected")
if colliderbrain==noone
draw_text(400,132,"Colliderbrain: Not Selected")
else draw_text(400,132,"Colliderbrain: Selected");
 

TheouAegis

Member
Is it showiing

Colliderbat: Selected
Colliderbrain: Selected

or is it showing

Colliderbat: Not Selected
Collider Brain: Not Selected

? Do either of them ever come up as "Selected" or are they always "Not Selected"?


Two issues I have with your code, now that I've looked over the rest of it again:
  1. You aren't setting colliderbrain and colliderbat back to noone after they have been paired. This is fine for debugging things, because you can't see them paired if you're clearing them immediately after pairing; but it's still a part of my original code.
  2. That block of code that you asked if it was "kosher" should NOT be part of BatBrainCollision(); it should go inside the bat and brain objects respectively. By including that "kosher?" block of code inside the script. you are forcing the game to essentially say, "So long as this bat and this brain are currently selected, then only this bat and this brain are able to do any combat and all other bats and brains must wait until I click them again." That...is a very unusual game mechanic. The typical mechanic is you tell the bat which brain will be its target and then you let the bat attack its target; you then tell the brain which bat is trying to attack it so it can counterattack the bat targeting it. Whether or not you allow multiple bats to attack a single brain is another issue, but the point is the bat and brain are allowed to carry on outside of the script. The sole purpose of the script itself is simply to generate attacker-defender pairs. (And typing this out, it seems more logical to force the player to click on the bat first and THEN click on a brain for the bat to attack, rather than the brain first.)
 
Last edited:
Is it showiing

Colliderbat: Selected
Colliderbrain: Selected

or is it showing

Colliderbat: Not Selected
Collider Brain: Not Selected

? Do either of them ever come up as "Selected" or are they always "Not Selected"?


Two issues I have with your code, now that I've looked over the rest of it again:
  1. You aren't setting colliderbrain and colliderbat back to noone after they have been paired. This is fine for debugging things, because you can't see them paired if you're clearing them immediately after pairing; but it's still a part of my original code.
  2. That block of code that you asked if it was "kosher" should NOT be part of BatBrainCollision(); it should go inside the bat and brain objects respectively. By including that "kosher?" block of code inside the script. you are forcing the game to essentially say, "So long as this bat and this brain are currently selected, then only this bat and this brain are able to do any combat and all other bats and brains must wait until I click them again." That...is a very unusual game mechanic. The typical mechanic is you tell the bat which brain will be its target and then you let the bat attack its target; you then tell the brain which bat is trying to attack it so it can counterattack the bat targeting it. Whether or not you allow multiple bats to attack a single brain is another issue, but the point is the bat and brain are allowed to carry on outside of the script. The sole purpose of the script itself is simply to generate attacker-defender pairs. (And typing this out, it seems more logical to force the player to click on the bat first and THEN click on a brain for the bat to attack, rather than the brain first.)
It is showing:

Colluderbat: Not Selected
Collider brain: Not Selected.
They are always selected.

Parts I'm not quite getting:

1. Why woujld the two be set back to noone after they have been paired. I thought the whole idea was to assign a bat and brain to colliderbrain and colliderbat so that the two can attack each other?
2. So should that " kosher" code go in the step events of the bats and brains. If so, how do I get to the colliderbrain and colliderbat pairs from the "kosher" code. Is that the point of this?
Shouldn't I pair a colliderbrain and colliderbat and then when the "kosher" code in the step event fires in the bat for instance, the brain code would cause damage to the colliderbat. Then when
the bat code "kosher" in the step event would fire and the bat would cause damage to the colliderbrain.

Am I in the in the right ballpark?

-TW
 

TheouAegis

Member
You don't use colliderbrain and colliderbat outside of the controller object. The two variables are strictly for the controller object to keep track of when a suitable pair has been clicked. Once a pair has been properly clicked (in the current situation, brain first then bat), the controller object (via this script) tells the bat whose ID is stored in its colliderbat which brain to attack via the bat's own attackTarget variable, then tells the brain which bat to attack via the brain's own attackTarget variable. And then the controller resets colliderbrain and colliderbat back to noone because it's done with the two varaibles until the next time a pairing needs to be made. The bat and the brain act on their own accordingly to each one's attackTarget.

If you remove the "kosher?" code completely for not (or just comment it all out), then the pairing should work just fine, resulting in "Selected" being shown when you click on a bat or brain.

As for what the "kosher?" code should do, it should check if the brain or bat is in attack range of attackTarget and if it is, perform its attack animation and deal damage to attackTarget. Every bat will have its own attackTarget. Every brain will have its own attackTarget. The "kosher" code should simply say, "move toward attackTarget until the distance to attackTarget is less than my attackRange and then attack, dealing damage to attackTarget." The brain doesn't control the bat. The bat doesn't control the brain. The controller object doesn't even control either of them, it just directs them to what the player wants them to do.
 
Ok. Well that makes sense. Except I don't know how the GUI event can access colliderbrain and colliderbat's pairing. I removed the "kosher?"" code a while back. I think I understand everything but the pairing isn't happening. So there must be something wrong with how i'm doing the pairing.I have a controller object with the GUI code you told me to write and I call the pairing script in the step event. At this point I'm just trying to get them to pair so right now I don't have any other related code.

@Edwin This is complicated stuff.
 

TheouAegis

Member
Except I don't know how the GUI event can access colliderbrain and colliderbat's pairing.
The GUI event is inside the same object that's calling BatBrainCollision(), so colliderbat and colliderbrain are accessible in all the events of that controller object. The pairing itself doesn't exist, it's just an aspect of the bats and brains. I'll try to make the GUI a little clearer farther down this post.

Code:
if mouse_check_button_pressed(mb_left) {
   show_debug_message("Mouse Check Button collision pressed");
  var n = instance_position(mouse_x,mouse_y, all);
  if n == noone return 0;
   if n.object_index == BigBrainObject || object_get_parent(n.object_index)==BigBrainObject
   {
      show_debug_message("Big Brain Object is selected");
    colliderbrain = n;
    colliderbat = noone;    //This may not work for you, but it would force the player to pick a new bat after clicking on a brain
   }
   else
   if n.object_index == SentryBatObject || object_get_parent(n.object_index)==SentryBatObject {
    colliderbat = n;
    show_debug_message("Sentry Bat Object is selected");
   }
   else {
      show_debug_message("Click off of sentry bat and brain");
     colliderbrain=noone;
     colliderbat=noone;
   }

   //Now that we may have established a brain-bat pairing, we can move on
   if !colliderbrain || !colliderbat return 0;    //If either target hasn't been chosen, end the script for now

   with colliderbat
       attackTarget = other.colliderbrain;

   with colliderbrain
     if attackTarget == noone
        attackTarget = other.colliderbat;
     else
     if distance_to_object(attackTarget) > attackRange
        attackTarget = other.colliderbat;
}
So is this code the ONLY code inside BatBrainCollision() now?

Once we get this better figured out, you need to change this line:
Code:
if n == noone return 0;
to this instead:
Code:
if n == noone {
    colliderbrain = noone;
    colliderbat = noone;
}
else
I had put in that "if n==noone return 0;" line to avoid a missing object error. What I didn't realize at the time that I wrote it was it limited the other part that resets colliderbrain and colliderbat to only work when clicking on non-bat and non-brain objects, but wasn't allowing them to get reset when clicking on no objects at all. So now it's just one long chain of if-else-if-else: If we didn't click on anything, reset the variables; else if we clicked on a bat, set colliderbat; else if we clicked on a brain, set colliderbrain; else [if we clicked on anything else] reset the variables.

Now, right after this part of the code:
Code:
with colliderbrain
     if attackTarget == noone
        attackTarget = other.colliderbat;
     else
     if distance_to_object(attackTarget) > attackRange
        attackTarget = other.colliderbat;
Add these two lines to reset colliderbat and colliderbrain (this is all still inside the main if mouse_check_button_pressed(mb_left) conditional block):
Code:
colliderbat = noone;
colliderbrain = noone;
This is what you need to make it so after the "pairing" (like I said, it's an aspect of two instances and doesn't actually exist) the selections are reset.
So now the full code should look like
Code:
if mouse_check_button_pressed(mb_left) {
   show_debug_message("Mouse Check Button collision pressed");
  var n = instance_position(mouse_x,mouse_y, all);
  if n == noone
  {
      show_debug_message("Click on empty space")
      colliderbrain = noone;
      colliderbat = noone;
   }
   if n.object_index == BigBrainObject || object_get_parent(n.object_index)==BigBrainObject
   {
      show_debug_message("Big Brain Object is selected");
      colliderbrain = n;
      colliderbat = noone;    //This may not work for you, but it would force the player to pick a new bat after clicking on a brain
   }
   else
   if n.object_index == SentryBatObject || object_get_parent(n.object_index)==SentryBatObject
   {
      colliderbat = n;
      show_debug_message("Sentry Bat Object is selected");
   }
   else
   {
      show_debug_message("Click wrong object type");
     colliderbrain=noone;
     colliderbat=noone;
   }

   //Now that we may have established a brain-bat pairing, we can move on
   if !colliderbrain || !colliderbat return 0;    //If either target hasn't been chosen, end the script for now

   with colliderbat
       attackTarget = other.colliderbrain;

   with colliderbrain
     if attackTarget == noone
        attackTarget = other.colliderbat;
     else
     if distance_to_object(attackTarget) > attackRange
        attackTarget = other.colliderbat;

    colliderbat = noone;
    colliderbrain = noone;
}

Now to help you visualize the pairing, assuming there isn't some other underlying issue elsewhere. Go into the GUI event, delete that old code I had you use, and then add this code:
Code:
with SentryBatObject if attackTarget != noone {
    draw_text(400,100,string(id)+" PAIRED WITH "+string(attackTarget));
    break;
}
Now when you click on a brain and then click on a bat, text similar to 1000145 PAIRED WITH 1000148 should appear on the screen. Then you will know at least those two instances are paired up.

If you run the game with these changes and you cannot get that message to pop up at all no matter what you do, then your problem is outside of this script itself, because this final script works insofar as it pairs up a brain and a bat.
 
Well the script isn't working. I don't get a "PAIRED WITH" at all. Does that mean that attackTarget == no one?
Otherwise *something* should show up.
 

TheouAegis

Member
Post the full object info for that controller object.

Also post the object properties (not the code) for your brain and bat.

How fast are your bat and brain moving? Try making them not move at all so they are easier to click on.
 
Top