If you don't want the Room Persistence approach, you could also do enums.
@NightFrost explained this already, but if you don't know how it works exactly, I've also written out an expanded version of it and how it might look once the code is fully written out.
Have an enum called "state" and specify "alive" and "dead". Mark a key for the object that the game will save along with what state the object is at all times. In the beginning, the object (enemy) will be alive. If you kill the enemy instance, the state changes from "alive" to "dead" and saves the key so that when you return from a different room, it remembers the state the instance was last in and doesn't respawn it. And yes, it does use ds_maps as
@NightFrost stated.
First, create your ds_map and create a enum called "States" with the different types of states you want in the game. Best to place this in some controller object that stays persistent throughout the game.
obj_game_manager: Create
GML:
///Game Data
//Save data
save_data = ds_map_create();
//Check enum states
enum States{
//Enemy
alive,
dead
}
Next, we need to write some scripts telling the game to save the state information of any object in question into the ds_map. We use our controller object to save the object based the room, the name of the object, and its coordinates in said room. There are other ways we could change it up (like object ID) but for now this is the more common route.
Script - save_data_get_value
GML:
///save_data_get_value(key)
with(obj_game_manager) //WHATEVER YOUR CONTROLLER OBJECT NAME IS
return save_data[? argument[0]];
Script - save_data_generate_key
GML:
///save_data_generate_key()
//Creates a key for the current item to use for save data.
return room_get_name(room)+object_get_name(object_index)+string(x)+string(y);
Script - save_data_set_value
GML:
///save_data_set_value(key,value)
with(obj_game_manager) //CHANGE TO YOUR CONTROLLER OBJECT
ds_map_replace(save_data,argument[0],argument[1]);
Then we specify in our enemy code what state it begins in. If we have some save data for that object already, it'll keep the enemy dead (imitates room persistence). Otherwise, it starts it off alive.
Create
GML:
//Identify state
key = save_data_generate_key();
var _save_data = save_data_get_value(key);
if(!is_undefined(_save_data) && _save_data==1)
{ //Enemy is dead
state=States.dead;
}
else { //Enemy starts off alive
state=States.alive;
}
Finally, we change the state of the object based on certain triggers. If I want the enemy to execute this script when it dies from a bullet, for example, this would go in my Collision event (although I'd highly recommend it going in the Step event if possible). In my conditional statement, I would say something like
if hp <= 0
or whatever to make it change into the dead state. I can tell it what I want to do right as it's entering the dead state. Maybe increase my score, drop an item, create an explosion effect, whatever. Lastly, I'd have the instance destroyed after I've declared the enemy dead. THIS IS IMPORTANT because whenever you return to the room, the game will come back to find this state event. Even though the game knows what state the enemy is in, it'll want to know what to do if the enemy data returns "dead". Hence why I did all my dead code during the transition (middle of this code) and just have it destroying the instance if enemy is saved in dead state.
Event Action (Step, Collision with weapon, etc.)
GML:
///Define states
switch(state)
{
case States.alive:
{
//State what happens right as enemy dies
if (SET CONDITION TO WHAT MAKES YOUR ENEMY DEAD) {
state = States.dead;
save_data_set_value(key,true);
}
}
}break;
case States.dead:
{
instance_destroy(); //Note: this may change depending where code is being called from
} break;
}
Also....
The ? symbol in the code is an
accessor. For data structures (ds_), each type has their own accessor. Since we used ds_maps, that accessor is a ?. Think of it as a shortcut for writing ds code.
You can find an example of how to use it easily here.
Hope that explains is more.