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

(1.4) Changing sprite_index on button press and release

D

Darumin

Guest
Hello. I tried looking for the solution to this, but I can't find anything.

I have a script to handle movement and a script nested in it that changes the state and the spriteset of the player object as long as a button is held. It works great, they work in tandem and I'm able to turn the new spriteset on and off and activate the state while I'm moving. Here are my issues, though:
  • If I'm standing still and pressing the button, the sprite_index doesn't change UNTIL I move. I want it to immediately default to the new spriteset at image 0.
  • If I release the movement key before I release the key that changes state, it doesn't change back to the default sprite UNTIL I move. I want it to change back as soon as I release the state change key.
I kinda understand why it's happening, but I just can't figure out the logic. I don't have access to my code right now, so here's a flowchart, I will post it later if it's necessary.

/// MOVEMENT SCRIPT

> Call script that sets the user input.
> Call DEFAULT SPRITE SCRIPT..
> Move player object using physics and the default sprite variables.

/// DEFAULT SPRITE SCRIPT

> If button that changes state is being pressed or held, set state variable contained in player object to new state and change the default sprite variables.
> Else set default sprite variables.

/// PLAYER OBJECT

// Create
> Creates all variables necessary.

// Step
> Execute the current state.
 
S

Silver_Mantis

Guest
Hello. I tried looking for the solution to this, but I can't find anything.

I have a script to handle movement and a script nested in it that changes the state and the spriteset of the player object as long as a button is held. It works great, they work in tandem and I'm able to turn the new spriteset on and off and activate the state while I'm moving. Here are my issues, though:
  • If I'm standing still and pressing the button, the sprite_index doesn't change UNTIL I move. I want it to immediately default to the new spriteset at image 0.
  • If I release the movement key before I release the key that changes state, it doesn't change back to the default sprite UNTIL I move. I want it to change back as soon as I release the state change key.
I kinda understand why it's happening, but I just can't figure out the logic. I don't have access to my code right now, so here's a flowchart, I will post it later if it's necessary.

/// MOVEMENT SCRIPT

> Call script that sets the user input.
> Call DEFAULT SPRITE SCRIPT..
> Move player object using physics and the default sprite variables.

/// DEFAULT SPRITE SCRIPT

> If button that changes state is being pressed or held, set state variable contained in player object to new state and change the default sprite variables.
> Else set default sprite variables.

/// PLAYER OBJECT

// Create
> Creates all variables necessary.

// Step
> Execute the current state.
I can't really tell since you don't have any code posted, but it sounds like you are calling your Default Sprite Script inside your user input code instead of having it as an independent block of code.
You should define your inputs, and then assign your inputs variable names so you can use them throughout your code. Then make conditions that change what goes on inside your default sprite script.
 
D

Darumin

Guest
I can't really tell since you don't have any code posted, but it sounds like you are calling your Default Sprite Script inside your user input code instead of having it as an independent block of code.
You should define your inputs, and then assign your inputs variable names so you can use them throughout your code. Then make conditions that change what goes on inside your default sprite script.
I did this already. That's what the "call script that sets the user input" line is, it's calling the key map from a separate script. Sorry for the vague bullet points, but the key assignment isn't my issue.

I just want to be able to refresh the sprite so that it reflects the spriteset I get from pressing the button to change the state (in this case it's mb_left).

To describe what specifically I want my character object to do, I want them to be able to change into a state where they take a broom out. As long as the mouse button is pressed, the broom will be shown. What I want it to do is show the broom sprite on mouse click, and also have the broom disappear as soon as I release the mouse click. I've worked with all the mouse functions and couldn't make it work. It's only showing the broom if I walk AND click, which by itself is fine, but I want it to work while standing still.

I'll post my code a little later today.
 
D

Darumin

Guest
My current scripts:

Code:
/// scriptSpriteDefinitions

defaultPlayerLeft = spriteClaraLeft;
defaultPlayerRight = spriteClaraRight;
defaultPlayerUp = spriteClaraUp;
defaultPlayerDown = spriteClaraDown;
Code:
/// scriptPlayerInput

up_key = keyboard_check(vk_up) or (keyboard_check(ord('W')));
down_key = keyboard_check(vk_down) or (keyboard_check(ord('S')));
left_key = keyboard_check(vk_left) or (keyboard_check(ord('A')));
right_key = keyboard_check(vk_right) or (keyboard_check(ord('D')));

broom_key = mouse_check_button(mb_left);
broom_pressed = mouse_check_button_pressed(mb_left);
broom_release = mouse_check_button_released(mb_left);
Code:
/// scriptMoveState

// Set key press to variables.

scriptPlayerInput();

if (broom_key or broom_pressed)
{
    state = scriptBroomState;
}

else scriptSpriteDefinitions();

var x_axis = (right_key - left_key);
var y_axis = (down_key - up_key);

// Get direction.

dir = point_direction(0, 0, x_axis, y_axis);

// Get length.

if (x_axis == 0 and y_axis == 0)
{
    len = 0;
}
else
{
    len = spd;
}


// Get hspd and vspd.

hspd = lengthdir_x(len, dir);
vspd = lengthdir_y(len, dir);

// Move.

phy_position_x += hspd;
phy_position_y += vspd;

// Control sprite.

image_speed = .2;
if (len == 0) image_index = 0;

// Vertical speed.

if (vspd > 0)
{
    sprite_index = defaultPlayerDown;
}
else if (vspd < 0)
{
    sprite_index = defaultPlayerUp;
}

// Horizontal speed.

if (hspd < 0)
{
    sprite_index = defaultPlayerLeft;
}
else if (hspd > 0)
{
    sprite_index = defaultPlayerRight;
}
Code:
/// scriptBroomState

spd = 2;

defaultPlayerLeft = spriteClaraTest;
defaultPlayerRight = spriteClaraTest;
defaultPlayerUp = spriteClaraTest;
defaultPlayerDown = spriteClaraTest;

scriptMoveState();
My player object:

CREATE
Code:
/// Initialize player object.

event_inherited();

image_speed = 0;
spd = 3;
hspd = 0;
vspd = 0;
len = 0;
dir = 0;

scriptPlayerInput();
state = scriptMoveState;
STEP
Code:
/// Perform current state.

// event_inherited();
script_execute(state);
 
S

Silver_Mantis

Guest
My current scripts:

Code:
/// scriptSpriteDefinitions

defaultPlayerLeft = spriteClaraLeft;
defaultPlayerRight = spriteClaraRight;
defaultPlayerUp = spriteClaraUp;
defaultPlayerDown = spriteClaraDown;
Code:
/// scriptPlayerInput

up_key = keyboard_check(vk_up) or (keyboard_check(ord('W')));
down_key = keyboard_check(vk_down) or (keyboard_check(ord('S')));
left_key = keyboard_check(vk_left) or (keyboard_check(ord('A')));
right_key = keyboard_check(vk_right) or (keyboard_check(ord('D')));

broom_key = mouse_check_button(mb_left);
broom_pressed = mouse_check_button_pressed(mb_left);
broom_release = mouse_check_button_released(mb_left);
Code:
/// scriptMoveState

// Set key press to variables.

scriptPlayerInput();

if (broom_key or broom_pressed)
{
    state = scriptBroomState;
}

else scriptSpriteDefinitions();

var x_axis = (right_key - left_key);
var y_axis = (down_key - up_key);

// Get direction.

dir = point_direction(0, 0, x_axis, y_axis);

// Get length.

if (x_axis == 0 and y_axis == 0)
{
    len = 0;
}
else
{
    len = spd;
}


// Get hspd and vspd.

hspd = lengthdir_x(len, dir);
vspd = lengthdir_y(len, dir);

// Move.

phy_position_x += hspd;
phy_position_y += vspd;

// Control sprite.

image_speed = .2;
if (len == 0) image_index = 0;

// Vertical speed.

if (vspd > 0)
{
    sprite_index = defaultPlayerDown;
}
else if (vspd < 0)
{
    sprite_index = defaultPlayerUp;
}

// Horizontal speed.

if (hspd < 0)
{
    sprite_index = defaultPlayerLeft;
}
else if (hspd > 0)
{
    sprite_index = defaultPlayerRight;
}
Code:
/// scriptBroomState

spd = 2;

defaultPlayerLeft = spriteClaraTest;
defaultPlayerRight = spriteClaraTest;
defaultPlayerUp = spriteClaraTest;
defaultPlayerDown = spriteClaraTest;

scriptMoveState();
My player object:

CREATE
Code:
/// Initialize player object.

event_inherited();

image_speed = 0;
spd = 3;
hspd = 0;
vspd = 0;
len = 0;
dir = 0;

scriptPlayerInput();
state = scriptMoveState;
STEP
Code:
/// Perform current state.

// event_inherited();
script_execute(state);

I might see a solution.

Remove the broom_key variable
Code:
/// scriptPlayerInput

up_key = keyboard_check(vk_up) or (keyboard_check(ord('W')));
down_key = keyboard_check(vk_down) or (keyboard_check(ord('S')));
left_key = keyboard_check(vk_left) or (keyboard_check(ord('A')));
right_key = keyboard_check(vk_right) or (keyboard_check(ord('D')));

//Removed Broom Key...
broom_pressed = mouse_check_button_pressed(mb_left);
broom_release = mouse_check_button_released(mb_left);
Then only change states when used.
With this, it should also always return the character's animation back to the first frame.
Code:
/// scriptMoveState

// Set key press to variables.

scriptPlayerInput();

if (broom_pressed)
{
    if (state != scriptBroomState)
    {
         image_index = 0;
         state = scriptBroomState;
    }
}

if (broom_release)
{
    if (state != scriptMoveState)
    {
         image_index = 0;
         state = scriptMoveState;
    }

}
[EDIT] Wait I just noticed you don't have 2 scripts. You have a random third script that shouldn't be there. You need to declare the default sprites in the movestate, not it's own script.
 
Last edited by a moderator:
D

Darumin

Guest
I might see a solution.

Remove the broom_key variable
Code:
/// scriptPlayerInput

up_key = keyboard_check(vk_up) or (keyboard_check(ord('W')));
down_key = keyboard_check(vk_down) or (keyboard_check(ord('S')));
left_key = keyboard_check(vk_left) or (keyboard_check(ord('A')));
right_key = keyboard_check(vk_right) or (keyboard_check(ord('D')));

//Removed Broom Key...
broom_pressed = mouse_check_button_pressed(mb_left);
broom_release = mouse_check_button_released(mb_left);
Then only change states when used.
With this, it should also always return the character's animation back to the first frame.
Code:
/// scriptMoveState

// Set key press to variables.

scriptPlayerInput();

if (broom_pressed)
{
    if (state != scriptBroomState)
    {
         image_index = 0;
         state = scriptBroomState;
    }
}

if (broom_release)
{
    if (state != scriptMoveState)
    {
         image_index = 0;
         state = scriptMoveState;
    }

}
[EDIT] Wait I just noticed you don't have 2 scripts. You have a random third script that shouldn't be there. You need to declare the default sprites in the movestate, not it's own script.
This won't work because the code is being run in a step event.

If I put my default sprites in the move state, it will always set it to those sprites regardless of what state I'm in. This is partly why that extra script exists.

Also the if statements here will just keep setting the image_index to 0 in a loop, regardless of what spriteset I'm using. Don't want that either.

EDIT: I should clarify that I can't really separate the move state from the broom state since they're used in conjunction with each other. If I did, I would have to duplicate the movement code, which doesn't seem very efficient to me. Unless I'm missing something here.
 
Last edited by a moderator:
S

Silver_Mantis

Guest
EDIT: I should clarify that I can't really separate the move state from the broom state since they're used in conjunction with each other. If I did, I would have to duplicate the movement code, which doesn't seem very efficient to me. Unless I'm missing something here.
You could technically not use any states at all with something this simple. So I'll show you how I would go about that.

scr_PlayerInput:

Code:
/// scriptPlayerInput

up_key = keyboard_check(vk_up) or (keyboard_check(ord('W')));
down_key = keyboard_check(vk_down) or (keyboard_check(ord('S')));
left_key = keyboard_check(vk_left) or (keyboard_check(ord('A')));
right_key = keyboard_check(vk_right) or (keyboard_check(ord('D')));

broom_pressed = mouse_check_button_pressed(mb_left);
broom_release = mouse_check_button_released(mb_left);
Obj_Player:
CREATE
Code:
/// Initialize player object.

event_inherited();

image_speed = 0;
spd = 3;
hspd = 0;
vspd = 0;
len = 0;
dir = 0;

//Added Broom Variable Check
broom_use = false;

state = scr_PlayerController;
STEP
(Leave your step alone)

scr_PlayerController:
(Notice how I changed the sprites for the horizontal and vertical movements.)
Code:
/// scriptMoveState

// Set key press to variables.
scr_PlayerInput();

if (broom_pressed)
{
    if (broom_use == false)
    {
        image_index = 0;
        spd = 2;
        broom_use = true;
    }
}

if (broom_release)
{
    if (broom_use == true)
    {
        image_index = 0;
        spd = 3;
        broom_use = false;
    }
}

var x_axis = (right_key - left_key);
var y_axis = (down_key - up_key);

// Get direction.

dir = point_direction(0, 0, x_axis, y_axis);

// Get length.

if (x_axis == 0 and y_axis == 0)
{
    len = 0;
}
else
{
    len = spd;
}


// Get hspd and vspd.

hspd = lengthdir_x(len, dir);
vspd = lengthdir_y(len, dir);

// Move.

phy_position_x += hspd;
phy_position_y += vspd;

// Control sprite.

image_speed = .2;
if (len == 0) image_index = 0;

// Vertical speed.

if (vspd > 0)
{
    if (broom_use == false)
    {
//Default Animations
    sprite_index = defaultPlayerDown;
    }
    else
    {
//Broom Animations
    sprite_index = spriteClaraTest;
    }
}
else if (vspd < 0)
{
    if (broom_use == false)
    {
//Default Animations
    sprite_index = defaultPlayerUp;
    }
    else
    {
//Broom Animations
    sprite_index = spriteClaraTest;
    }
}

// Horizontal speed.

if (hspd < 0)
{
    if (broom_use == false)
    {
//Default Animations
    sprite_index = defaultPlayerLeft;
    }
    else
    {
//Broom Animations
    sprite_index = spriteClaraTest;
    }
}
else if (hspd > 0)
{
    if (broom_use == false)
    {
//Default Animations
    sprite_index = defaultPlayerRight;
    }
    else
    {
//Broom Animations
    sprite_index = spriteClaraTest;
    }
}
That should work without any additional states! :)
 
Last edited by a moderator:
D

Darumin

Guest
You could technically not use any states at all with something this simple. So I'll show you how I would go about that.

scr_PlayerInput:

Code:
/// scriptPlayerInput

up_key = keyboard_check(vk_up) or (keyboard_check(ord('W')));
down_key = keyboard_check(vk_down) or (keyboard_check(ord('S')));
left_key = keyboard_check(vk_left) or (keyboard_check(ord('A')));
right_key = keyboard_check(vk_right) or (keyboard_check(ord('D')));

broom_pressed = mouse_check_button_pressed(mb_left);
broom_release = mouse_check_button_released(mb_left);
Obj_Player:
CREATE
Code:
/// Initialize player object.

event_inherited();

image_speed = 0;
spd = 3;
hspd = 0;
vspd = 0;
len = 0;
dir = 0;

//Added Broom Variable Check
broom_use = false;

state = scr_PlayerController;
STEP
(Leave your step alone)

scr_PlayerController:
(Notice how I changed the sprites for the horizontal and vertical movements.)
Code:
/// scriptMoveState

// Set key press to variables.
scr_PlayerInput();

if (broom_pressed)
{
    if (broom_use == false)
    {
        image_index = 0;
        spd = 2;
        broom_use = true;
    }
}

if (broom_release)
{
    if (broom_use == true)
    {
        image_index = 0;
        spd = 3;
        broom_use = false;
    }
}

var x_axis = (right_key - left_key);
var y_axis = (down_key - up_key);

// Get direction.

dir = point_direction(0, 0, x_axis, y_axis);

// Get length.

if (x_axis == 0 and y_axis == 0)
{
    len = 0;
}
else
{
    len = spd;
}


// Get hspd and vspd.

hspd = lengthdir_x(len, dir);
vspd = lengthdir_y(len, dir);

// Move.

phy_position_x += hspd;
phy_position_y += vspd;

// Control sprite.

image_speed = .2;
if (len == 0) image_index = 0;

// Vertical speed.

if (vspd > 0)
{
    if (broom_use == false)
    {
//Default Animations
    sprite_index = defaultPlayerDown;
    }
    else
    {
//Broom Animations
    sprite_index = spriteClaraTest;
    }
}
else if (vspd < 0)
{
    if (broom_use == false)
    {
//Default Animations
    sprite_index = defaultPlayerUp;
    }
    else
    {
//Broom Animations
    sprite_index = spriteClaraTest;
    }
}

// Horizontal speed.

if (hspd < 0)
{
    if (broom_use == false)
    {
//Default Animations
    sprite_index = defaultPlayerLeft;
    }
    else
    {
//Broom Animations
    sprite_index = spriteClaraTest;
    }
}
else if (hspd > 0)
{
    if (broom_use == false)
    {
//Default Animations
    sprite_index = defaultPlayerRight;
    }
    else
    {
//Broom Animations
    sprite_index = spriteClaraTest;
    }
}
That should work without any additional states! :)
I tried this just now. It runs identical to my original code. Doesn't quite snap in and out of the "state." I must have tried every approach to this, so I think I'll have to shelve this functionality while I work on something else. I think the solution will come to me eventually as I get used to working with GML...

Thanks for your help, though!
 
Top