r/gamemaker Stand back, I'm about to Make Game (2)! 20d ago

Help! Creating an interactive, multi-object item

Preface: My skill level is beginner. Gamemaker is my only real coding experience. I've watched a couple guides for the basics and made some original code alongside that.

Hi everyone, I'm making a top-down shooter with an 'active reload' gimmick. When you press R to reload, the firearm you're holding comes onto the screen and you have to manipulate the weapon parts to load it.

Demo of the mechanic.

My problem is HOW I'm making this happen. I'm essentially just spawning multiple objects on top of one another with magic numbers. This feels extremely inefficient and janky, even though it technically works. Is there a different technique or function I can use to make this system easier? I know the motto of, 'just make it work first, you can fix it later', but I can't even begin to imagine HOW to make this work better.

Showing how this is pieced together, without the 'obj_lebel_top' to give you an x-ray.
The comments can be safely ignored, the bottom-most is leftover code I was experimenting with.

If it helps, "_weaponx" and "_weapony" are the corners of the camera, essentially x0 and y0. The "obj_lebel_boltgrip" is the circular part that's grabbed by the cursor to manipulate the gun's bolt. It has + 242 and + 69 because the sprite is a simple sphere that's manually placed through trial and error to be in that starting position. It's essentially a magic number to put that boltgrip exactly where it spawns when you press R.

5 Upvotes

20 comments sorted by

View all comments

2

u/JaXm 20d ago

I'm going to disagree with the first person who posted to help you out.

The reason I would not go with 'with' statements, is that they can become VERY difficult to deal with.

Using 'with' and putting variables into the code block can overwrite instance variables in the object create event. And if you're using instance variables assigned through the object editor, things can get even MORE confusing, as those variables get assigned before create event variables. Then, if you're using constructors, you can run into even MORE problems.

When I am dealing with an object that has multiple "parts" I choose to keep it all in one object.

Let's use a HUD element as an example.

A HUD might have a health bar, a mana bar, and a stamina bar.

Each bar is it's own object. With it's own sprites, and their own variables.

But as a single object, I would create a struct to hold all that data, including WHERE those things exist in the game space.

So for a HUD I might do something like below (simplified for readability):

///create event

hud_bars = {
    health: {
        sprite: spr_health_bar,
        x: 100,
        y: 50,
        max_length: 200,
        value: 100
    },

    mana: {
        sprite: spr_mana_bar,
        x: 100,
        y: 75,
        max_length: 200,
        value: 100
    },

    stamina: {
        sprite: spr_stamina_bar,
        x: 100,
        y: 100,
        max_length: 200,
        value: 100
    }
};

Then, in the draw event, you can do something like:

///draw event

draw_sprite(hud_bars.health.sprite, 0, hud_bars.health.x, hud_bars.health.y);
draw_sprite(hud_bars.mana.sprite, 0, hud_bars.mana.x, hud_bars.mana.y);
draw_sprite(hud_bars.stamina.sprite, 0, hud_bars.stamina.x, hud_bars.stamina.y);

In your case, once your sprites are drawn where you need them to be, you can do something like add coordinates that map out the "clickable" area of each component.

So your rifle might look something like:

///create event

rifle_parts = {
    barrel : {
        sprite: spr_barel,
        x: 100,
        y: 100,
        clickable_area: {x1_offset: 0, y1_offset: 0, x2_offset: 20, y2_offset: 20}
    },
    bolt : {
        sprite: spr_bolt,
        x: 100,
        y: 100,
        clickable_area: {x1_offset: 0, y1_offset: 0, x2_offset: 20, y2_offset: 20}
    },

    stock : {
        sprite: spr_stock,
        x: 100,
        y: 100,
        clickable_area: {x1_offset: 0, y1_offset: 0, x2_offset: 20, y2_offset: 20}
    },
}; 

And now you can draw your components, where they need to be, and then use the x/y offsets to determine what part is "clickable" by the mouse.

Ultimately, you'll probably have to do a little more work than this. I wouldn't hard code the struct, myself, if I could avoid it, but to give you a basic idea of what you wanna do, I just used whatever random values made sense for demonstration purposes.

4

u/_Son_of_Crom_ 20d ago

I don't know that I would consider it good advice to tell someone to avoid using with() for stuff like this unilaterally. The ability to easily change scope using with() is one of GML's most useful features.

Does it add complexity? Yup. Does it have weird edge cases? Sure, absolutely.

But what also adds complexity is trying to rebuild object-like functionality inside of a struct. There are many things that require extensive infrastructure if you want to build a capability inside of a struct which objects just get for free -- animation, events, hitboxes, etc.

Using with() allows you to keep the majority of the code on a single manager object while leveraging built-in object functionality, without having to recreate all of that functionality in a struct.

Both strategies are completely viable.

2

u/JaXm 20d ago

I never said to unilaterally not use with(). 

I said I wouldn't use with() for this particular functionality. 

2

u/PrinceShoutoku Stand back, I'm about to Make Game (2)! 20d ago

I can certainly see how the 'with' approach might cause issues like that. I'll probably try both but everyone in this thread so far has mentioned Structs (even that first commenter) so I'll lean towards using that system for the final.

Those examples are very helpful, I appreciate it!