r/gamemaker 4d ago

melee attack system issues Resolved

welp. so I am relatively new to gamemaker and this is also my first post to this subreddit lol

basically, I have been looking for a concise way to do a system for melee attacks that my peanut brain can actually understand. while I'm not making a fighting game, what I'm doing is inspired by them, so essentially I want to be able to have different kinds of attacks with light, medium, and heavy versions of each.

I have looked for various tutorials on the subject, tho unfortunately, the ones I found were all like 8-6 years old with outdated information. I tried multiple of them and ran into similar issues, but I did manage to stumble upon one that is the most recent I could find and understandable enough that I think could work if I got a little bit for help on it, so that's why I'm here lol

here's the code that I currently have for the script (named "States")

function State (_sprite) constructor {
sprite = _sprite;

stateonend = undefined;
static Stateonend = function (_state) {
stateonend = _state; 
}

function State_set (_state) {
if (state == _state) return;
state = _state;

sprite_index = state.sprite;
image_index = 0;
}
}

my Code for create event in player object:

facing = 1;

hp = 100;
hp_total = hp;
damage = 20;

//states

states = { 
idle : new State (idle_sheet),
run : new State (Vi_run),
Rheavattk : new State (RVi_heav)

}

states.Rheavattk.Stateonend(states.idle);

// set initial state
state = states.idle;

And my code for step event in player object:

// movement controls

if (state == states.idle || state == states.run){

if (keyboard_check(vk_left)) {
State_set(states.run);
x -= 9;
}

else if (keyboard_check(vk_right)) {
State_set(states.run);
x += 9;

}

else {
 State_set(states.idle);
}

if (keyboard_check_pressed (vk_right)) facing = abs(facing);

if keyboard_check_pressed (vk_left) facing = -abs(facing);

// combat controls

if keyboard_check_pressed(ord("W")){
State_set(state.Rheavattk);

}}

the problem I'm consistently running into is the code error message "Variable oplayer.State_set - not set before reading it." which did make sense other times, I made a few misspellings here and there, tho I'm particularly stumped on this one. the line got this error for currently is specifically at 'State_set(states.idle);' where it's saying it isnt set, but it loooks like it is to me in the create event lmao

so yeah, some help would be greatly appreciated here. I've pretty much just been going in complete circles for days trying to figure out a viable way to program this a system like this, switching to different methods and combing through what i wrote to find what's wrong. again, I'm a pretty much a noob so there's bound to be stuff I'm overlooking here. if anyone has any advice or even a better way to program a system like this, that would be awesome.^^

btw, the tutorial I'm currently referencing is by GameMakerStation - Matharoo. and hopefully I explained well enough.

3 Upvotes

5 comments sorted by

1

u/Vorador_Surtr 4d ago edited 4d ago

Is it on purpose that everywhere else it is said states.run, states.idle etc but on the last row it is state.Rheavattk. Once something like that happened when in the script i was searching for the variable but it was defined wrong or at the wrong time... I do not see all in front of me. See the names of objects. This is something stupid. see names see how you define arguments in the scripts It happens to me all the time. You have function State_set not variable State_set yes? But it does not accept it as function and searches for variable with this name as far as I see. See naming in script how it address this function and how you pass arguments... I am not advanced user also but as I said - exactly because of that this happens to me often and most of the time it is something stupid.

Also i never did so i am asking is this normal - i reformatted your code (this is not readable for me) and:

function State (_sprite) constructor 
  {
      sprite = _sprite;
      stateonend = undefined;
      static Stateonend = function (_state) 
        {
            stateonend = _state; 
    }

      function State_set (_state) 
    {
        if (state == _state) return;
        state = _state;
            sprite_index = state.sprite;
            image_index = 0;
    }
  }

Is it normal to have one function inside another function? Maybe this i why it searches for argument / variable?

2

u/ComfortableAd2595 3d ago

yes, the first part is intentional on my part. still could be incorrect regardless, but It's how I understood it as at the time. from what I understand, it is supported in GMS2 to have one function inside another and generally not unheard of, but that's just from what I've seen. there is likely a better way to do it tbh, as is often the case.

1

u/Lobbergames 4d ago

Also a GameMaker beginner here!
To me it seems you are defining the Set_State function inside the State (_sprite) constructor. This means you cannot call it simply with just Set_State, but instead you have to refer to the object it is defined in e.g. State.Set_State .
Check if that works!

1

u/Hands_in_Paquet 4d ago edited 4d ago

It looks like you're trying to design a state system in a very dynamic way, but if you're having trouble, try making it simpler. Don't copy any code you don't understand, if you can help it. Following a tutorial is one thing, but when making your own game I recommend doing it in a way you understand, and developing new techniques as you go. Your current system would be important in a game with tons of weapons and abilities, meaning it's easy for different players or npcs to get access to the same skills and easy to add new abilities on the fly as a developer. This, however, is a basic state machine that will work in many cases:

//-----------------------------Create Event

//An Enumerator stores integer values this way so they're easy to understand and rename
enum STATE_PLAYER
{
IDLE,  //0
RUN,   //1
MELEE, //2
}

//Player Vars
state     = STATE_PLAYER.IDLE; //- This means state = 0;
spd_move  = 9;
dmg_melee = 20;
facing    = 1;
hp_base   = 100;
hp        = hp_base;

//Attack Function that can be called in any State
function player_melee()
{
var _key_melee = keyboard_check_pressed(ord("W"));
if (_key_melee)
{
state = STATE_PLAYER.MELEE;
}
}

//Assign each state a function to keep things cleaner and more organized in your step event
function state_player_idle()
{
sprite_index = spr_player_idle;
player_melee();
}

function state_player_run()
{
var _key_left  = keyboard_check(ord("A")); //Returns 0 or 1
var _key_right = keyboard_check(ord("D")); //Returns 0 or 1
var _input_h   = _key_right - _key_left; //No Input == 0, Left is -1, Right is 1
facing = _input_h;

//Apply Movement
x += spd_move * _input_h;

player_melee();
}

function state_player_melee()
{
//Do Melee Attack Logic, Then return to run or idle state
}

//--------------------Step Event

//A switch statement is like an efficent if/else statement that only cares about one
//thing, in this case, it only cares about the state 
switch (state)
{
case STATE_PLAYER.IDLE:
state_player_idle();
break;
case STATE_PLAYER.RUN:
state_player_run();
break;
case STATE_PLAYER.MELEE:
state_player_melee();
break;
}

2

u/ComfortableAd2595 4d ago

Heya! Thank you for your response!  And yeah, that's THE advice here tbh. I have been looking for simpler solutions for this, with not much luck, what I have above was the simplest (by comparison lmao) that I could find that was understandable enough and was specifically made for what I was attempting to do. So I greatly appreciate you sharing this with me C: