Sunday, June 26, 2016

Game Maker Tip: Collision and Instances

Wondering why your collision code isn't working, despite the fact that your code is written exactly like the documentation suggests?  I was, too.  Five hours of my life down the drain, bashing my head against my keyboard in the hopes I'd hit the "fix my code plz" button we all secretly fantasize exists somewhere.  Bad news, I did not find this fabled button.  Good news, reading the docs until my eyes blurred did reveal this one snippet of information tucked away in the place_meeting function page:

#%&@#%

There it is.  "... this function can check... for collision... using the collision mask of the instance that runs the code for the check [because duh, why would the function itself let you decide?]"  Emphasis and commentary mine, of course.  I mean, how else would collision functions work-- by giving you a clear idea of what objects you're checking?  Or maybe the opportunity to set both objects?  Hah!  Foolish peasant, bow to the glory of the rabbit hole of obscured instancing!

Ahem.  Sorry about that.  Needed to get it all out.  To be a little more serious-- and hopefully helpful-- here's the problem I was having.  Since I love functions and want to offer both mouse and gamepad support for the project I'm working on, I decided to write a script to handle shooting.  The key press detection code is in the Player Object, and thus the Shoot script technically gets called by said Player Object.  So far so good, right?

However, I want to do some fancy shooting.  I made a sprite to act as a "cone of vision" that could be scaled depending on how much of a range the currently equipped weapon has.  So instead of shooting out a projectile, I want the Shoot script to detect any enemies that are under this cone and act on them accordingly.  I used the built-in place_meeting function to do this, as I remembered this function working pretty well for this purpose before.  Long story short, this did not work in my setup.  After much struggling, I finally realized that this place_meeting call was using the Player Object when it checked for collision with my enemies.  After some additional struggling, I figured out that this is the intended function of GameMaker and I had just glossed over the part of the documentation that stated this fact.

To be fair, it makes sense.  The place_meeting function only allows you to specify one of the objects you're checking for, so logically the code has to be getting the other object from somewhere.  Unfortunately, I would vastly prefer it not just assume the other objects is the one calling the function, and that the person writing the code is aware of this.  Clear code is happy code, after all.

Ultimately, I just added a with clause to the chunk of code checking collision and the issue cleared right up.  It also let me delete about 50 lines of code I had scrambled together trying to fix what technically wasn't broken, so now my code looks pretty again.  Hooray!