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

Unlockable levels

J

Jonathan Nguyen

Guest
I want to implement unlockable levels but I dont know what to do,currently i have a global.level for each level with each set to false
Code:
/// @description Insert description here
with (o_btn_lvl1)
{
    selected = false;
}

with (o_btn_lvl3)
{
    selected = false;
}
if (global.level2_unlocked)
{
selected = false;

if global.level2_unlocked = true
room_goto(r_level2)
}
this is the code for the button
Code:
global.level2_unlocked = false;
global.level3_unlocked = false;
and this is the code in my initialiser object

I dont know where to set global.level2_unlocked = true
I only want the level to unlock if the player finishes lvl 1 and goes to lvl 2
 
D

DarthTenebris

Guest
I assume you have a level select room and separate level rooms? If so, simply set the global variable to true after finishing a level. For example, finishing room_level_1 unlocks level 2, level 2 unlocks level 3, and so on.

Hope I helped :)
 
J

Jonathan Nguyen

Guest
Like i dont know what to write for the global.level = true I dont know where to write the code and how i register it as finished level
 

Rob

Member
Like i dont know what to write for the global.level = true I dont know where to write the code and how i register it as finished level
If you go from room to room after completing a level, you can set the global just before you change rooms, or in the creation code of the new room.

I think that second method might be the smartest based o what you've described.

If you unlock a level (room) by reaching it, setting the global in the creation code of the room will work.
 
J

Jonathan Nguyen

Guest
You finish a level by coming into collision with an object and when u do it will take you to the next level
 
J

Jonathan Nguyen

Guest
upload_2019-6-23_10-26-11.pngupload_2019-6-23_10-26-34.png
Code:
with (o_btn_lvl1)
{
    selected = false;
}

with (o_btn_lvl3)
{
    selected = false;
}
if (global.level2_unlocked = false) {
image_index = 0;
selected = false;
}
else
{
if ( global.level2_unlocked = true) {
image_index = 1;
selected = true;
room_goto(r_level2);
}
}
 
D

Deleted member 16767

Guest
I would suggest you learn ini files. That will easily make f.ex. if you press on "Next Level" in some kind of interface, it will take you to the next level and get saved. This is just one example of many things you can do with ini files.
 
J

Jonathan Nguyen

Guest
I would suggest you learn ini files. That will easily make f.ex. if you press on "Next Level" in some kind of interface, it will take you to the next level and get saved. This is just one example of many things you can do with ini files.
Code:
if (file_exists("Save.sav")) file_delete("Save.sav");
ini_open("Save.sav");
var SavedRoom =  room;
ini_write_real("Save1", "room", SavedRoom);
ini_close();
I have this code but i dont know where i would put it to enable a unlockable level
 

Gamebot

Member
Why don't you keep ONE global and save the last completed level. You can loop or check all other levels to see if they are <= to global.level to allow players in them.

Create of controller object:
if (file ! exists) global.level = 1;
else
global.level = file

Saving Pseudocode:
When touch object: global.level++;

Loading pseudocode game:
Load data
Loop through and use an array to "unlock" any levels that are <= global.level (Assuming you need correct sprites to do so)

That one global can easily be checked in many different ways to see if you can continue or play a last level. Also you don't have to worry about code in the rooms themselves.

Last minute thought:
I was thinking maybe you could have secrets within previous levels but need items from later ones to do so?
 
Last edited:
J

Jonathan Nguyen

Guest
Why don't you keep ONE global and save the last completed level. You can loop or check all other levels to see if they are <= to global.level to allow players in them.

Create of controller object:
if (file ! exists) global.level = 1;
else
global.level = file

Saving Pseudocode:
When touch object: global.level++;

Loading pseudocode game:
Load data
Loop through and use an array to "unlock" any levels that are <= global.level (Assuming you need correct sprites to do so)

That one global can easily be checked in many different ways to see if you can continue or play a last level. Also you don't have to worry about code in the rooms themselves.

Last minute thought:
I was thinking maybe you could have secrets within previous levels but need items from later ones to do so?
I dont know how to use arrays properly
 

Rob

Member
You might of missed it but... in the create event of your levels, set the unlocked global for that level to true. If the player visits that room, the global will be set to true.

Initialise all the unlock globals as false in the first room via a controller object.
 
Last edited:
J

Jonathan Nguyen

Guest
You might of missed it but... in the create event of your levels, set the unlocked global for that level to true. If the player visits that room, the global will be set to global.
That was done however it doesnt work
 
Last edited by a moderator:

Gamebot

Member
I didn't have time to answer your question completely last night....just a few suggestions. There is a difference between objects and instances, the main point is to use one object for all of your locked and unlocked levels. The setup is a bit more complicated code but overall you won't need anywhere near that many objects or that much code. Which means no more complicated if / else and true / false statements. Iv'e also been on a huge ds_map kick lately so let's look into saving that info into a map.

You will only need two objects: obj_cntrl, obj_levels
I see now two sprites: sprite_locked, spr_unlocked (Unless it's all one sprite) ????

OBJ_CNTRL

Create:
Code:
// Check if file exists if so load if not create one
// As always maps need to be created in the begining and destroyed when done!
if (file_exists("myfile"))
{
 var map = ds_map_create();
 map = ds_map_secure_load("myfile");
 global.level = ds_map_find_value(map, "levels");
 ds_map_destroy(map);
}
else
{
 global.level = 1;
 var map = ds_map_create();
 ds_map_add(map, "levels", global.level);
 ds_map_secure_save(map, "myfile");
 ds_map_destroy(map);
}

/* Variables i and j (Our counters for the columns and rows respectively)
   wid and height to get the width and height of our sprite being used
*/
var i, j;
var wid = sprite_get_width(spr_levels); hei = sprite_get_height(spr_levels);

// The double loop (or double counter)
for (i = 0; i < 5; i++){
 for (j = 0; j < 2; j++){
 
var inst = instance_create_depth(x + (i * wid + (wid /2)), y + (j * hei + (hei/2)), 0, obj_level_selector);
with(inst){
 
  if (j = 0) {lvl = i + 1}
  else       {lvl = i + 6}
 
  if (lvl <= global.level) {sprite_index = spr_unlocked;}
  else {sprite_index = spr_locked;}
 
 image_index = global.level - 1;
}
 }
}

OBJ_LEVELS

Create:
Code:
lvl = -1;
image_speed = 0;
Left pressed:
Code:
// Check if we can click on an unlocked button checking lvl with global.level

if (lvl <= global.level) {show_message( "room_goto(level" + string(lvl) + ")" )}
else {show_message( "This Level is Still Locked!")}

// Actual code
if (lvl <= global.level) { room_goto(rm_lvl) }
else {exit}
Right pressed:
Code:
/* This is so you can test unlocking and reloading unlocked levels 
   This code would actually go into your collision object. Starting with line at global.level ++;
*/

if (lvl  = global.level + 1)
{
 image_index = 0;
 global.level++;
 var map = ds_map_create();
 map = ds_map_secure_load("myfile");
 ds_map_replace(map, "levels", global.level)
 ds_map_secure_save(map, "myfile")
 ds_map_destroy(map);
}
else
{exit;}
Now start this up. Left click on a locked one can't open it right? Now right click on the next level up. One more time. Exit game. Now start game. Did it save? Should have.
 
Last edited:
J

Jonathan Nguyen

Guest
I didn't have time to answer your question completely last night....just a few suggestions. There is a difference between objects and instances, the main point is to use one object for all of your locked and unlocked levels. The setup is a bit more complicated code but overall you won't need anywhere near that many objects or that much code. Which means no more complicated if / else and true / false statements. Iv'e also been on a huge ds_map kick lately so let's look into saving that info into a map.

You will only need two objects: obj_cntrl, obj_levels
I see now two sprites: sprite_locked, spr_unlocked (Unless it's all one sprite) ????

OBJ_CNTRL

Create:
Code:
// Check if file exists if so load if not create one
// As always maps need to be created in the begining and destroyed when done!
if (file_exists("myfile"))
{
 var map = ds_map_create();
 map = ds_map_secure_load("myfile");
 global.level = ds_map_find_value(map, "levels");
 ds_map_destroy(map);
}
else
{
 global.level = 1;
 var map = ds_map_create();
 ds_map_add(map, "levels", global.level);
 ds_map_secure_save(map, "myfile");
 ds_map_destroy(map);
}

/* Variables i and j (Our counters for the columns and rows respectively)
   wid and height to get the width and height of our sprite being used
*/
var i, j;
var wid = sprite_get_width(spr_levels); hei = sprite_get_height(spr_levels);

// The double loop (or double counter)
for (i = 0; i < 5; i++){
 for (j = 0; j < 2; j++){
 
var inst = instance_create_depth(x + (i * wid + (wid /2)), y + (j * hei + (hei/2)), 0, obj_level_selector);
with(inst){
 
  if (j = 0) {lvl = i + 1}
  else       {lvl = i + 6}
 
  if (lvl <= global.level) {sprite_index = spr_unlocked;}
  else {sprite_index = spr_locked;}
 
 image_index = global.level - 1;
}
 }
}

OBJ_LEVELS

Create:
Code:
lvl = -1;
image_speed = 0;
Left pressed:
Code:
// Check if we can click on an unlocked button checking lvl with global.level

if (lvl <= global.level) {show_message( "room_goto(level" + string(lvl) + ")" )}
else {show_message( "This Level is Still Locked!")}

// Actual code
if (lvl <= global.level) { room_goto(rm_lvl) }
else {exit}
Right pressed:
Code:
/* This is so you can test unlocking and reloading unlocked levels
   This code would actually go into your collision object. Starting with line at global.level ++;
*/

if (lvl  = global.level + 1)
{
 image_index = 0;
 global.level++;
 var map = ds_map_create();
 map = ds_map_secure_load("myfile");
 ds_map_replace(map, "levels", global.level)
 ds_map_secure_save(map, "myfile")
 ds_map_destroy(map);
}
else
{exit;}
Now start this up. Left click on a locked one can't open it right? Now right click on the next level up. One more time. Exit game. Now start game. Did it save? Should have.
would i need to make another save code and would i need to make new sprites? And would I put the object in the level select room
 

Gamebot

Member
I wrote somewhere in that mess that I noticed you had two different sprites. Now I see it's more. Should have been more attentive on my end sorry. In the obj_cntrl second to last paragraph I wrote:

Code:
if (lvl <= global.level) {sprite_index = spr_unlocked;}
else {sprite_index = spr_locked;}

image_index = global.level - 1;
First off your sprites can be condensed into one sprite (In two different ways), though the code above assumes two which might be easier for you to understand. There are many ways to handle this but a quick, excuse the terrible quick drawings as i'm running out of time, example as follows:

spr_locked

unlock screens.png

Each image is called an image_index which without any code would animate. However, my code stops the animation and automatically selects the correct sprite (spr_locked and spr_unlocked) along with the proper sprite_index (The level). You would do the same for spr_unlocked. (As I mentioned above my very talented drawings should never be used, seeing yours are much better.)

Also the code above has 10 levels with the first five (1 - 5 ) on top and second five ( 6 - 10 ) on the bottom. If you don't need ten or are only doing a few let me know. I'll rewrite the code in simpler form. Cheers!
 
J

Jonathan Nguyen

Guest
I’m only doing 3 Levels and wouldn’t sprite unlocked be the picture without the lock. Also when placing in the code it saids obj_level_selector is only referenced once same goes with spr_levels. And can i ask where this object would be placed
 
Last edited by a moderator:
J

Jonathan Nguyen

Guest
I wrote somewhere in that mess that I noticed you had two different sprites. Now I see it's more. Should have been more attentive on my end sorry. In the obj_cntrl second to last paragraph I wrote:

Code:
if (lvl <= global.level) {sprite_index = spr_unlocked;}
else {sprite_index = spr_locked;}

image_index = global.level - 1;
First off your sprites can be condensed into one sprite (In two different ways), though the code above assumes two which might be easier for you to understand. There are many ways to handle this but a quick, excuse the terrible quick drawings as i'm running out of time, example as follows:

spr_locked

View attachment 25402

Each image is called an image_index which without any code would animate. However, my code stops the animation and automatically selects the correct sprite (spr_locked and spr_unlocked) along with the proper sprite_index (The level). You would do the same for spr_unlocked. (As I mentioned above my very talented drawings should never be used, seeing yours are much better.)

Also the code above has 10 levels with the first five (1 - 5 ) on top and second five ( 6 - 10 ) on the bottom. If you don't need ten or are only doing a few let me know. I'll rewrite the code in simpler form. Cheers!
I only need it for 3-4 levels
 

Gamebot

Member
As I mentioned above you will need to do the same for your spr_unlocked with all the levels within your unlocked sprite as well. I also fixed my typo with obj_level_selector using obj_levels. However, in either case this is your locked and unlocked "buttons" therefore only need an object. You can call that object whatever you want and replace obj_level_selector / obj_levels with whatever object you want. Also this would change the code in your control object with only 3 levels:

obj_cntrl
Code:
// Check if file exists if so load if not create one
// As always maps need to be created in the begining and destroyed when done!
if (file_exists("myfile"))
{
 var map = ds_map_create();
 map = ds_map_secure_load("myfile");
 global.level = ds_map_find_value(map, "levels");
 ds_map_destroy(map);
}
else
{
 global.level = 1;
 var map = ds_map_create();
 ds_map_add(map, "levels", global.level);
 ds_map_secure_save(map, "myfile");
 ds_map_destroy(map);
}

/* Variables i and j (Our counters for the columns and rows respectively)
   wid and height to get the width and height of our sprite being used
*/
var i, j;
var wid = sprite_get_width(spr_levels); hei = sprite_get_height(spr_levels);

for (i = 0; i < 3; i++){     //The middle number is how many levels you want. If you want four change three to four...
var inst = instance_create_depth(x + (i * wid + (wid /2)), y, 0, obj_levels);   // The (wd/2) within the i * structure is how many pixels in between each level button.
with(inst){
if (lvl <= global.level) {sprite_index = spr_unlocked;}
else {sprite_index = spr_locked;}
 
 image_index = global.level - 1;
}
 }
}
The rest should work assuming you have two sprites one for locked and one for unlocked. Each sprite should have all levels needed within them as I referenced above simply showing the image indexes for one. You should be able to test it temporarily with right clicking on the next level, leaving the game and then comming back.

**** It should be noted at the moment once you test this by right clicking on a level or using a collision there is no way to reset your levels for final game play. I would just add this code of line once per reset to delete the entire file then create a new one by inserting this to the very first line of your control object:

obj_cntrl
Code:
if (file_exists("myfile"))
{
 file_delete("myfile")
}
 
J

Jonathan Nguyen

Guest
As I mentioned above you will need to do the same for your spr_unlocked with all the levels within your unlocked sprite as well. I also fixed my typo with obj_level_selector using obj_levels. However, in either case this is your locked and unlocked "buttons" therefore only need an object. You can call that object whatever you want and replace obj_level_selector / obj_levels with whatever object you want. Also this would change the code in your control object with only 3 levels:

obj_cntrl
Code:
// Check if file exists if so load if not create one
// As always maps need to be created in the begining and destroyed when done!
if (file_exists("myfile"))
{
 var map = ds_map_create();
 map = ds_map_secure_load("myfile");
 global.level = ds_map_find_value(map, "levels");
 ds_map_destroy(map);
}
else
{
 global.level = 1;
 var map = ds_map_create();
 ds_map_add(map, "levels", global.level);
 ds_map_secure_save(map, "myfile");
 ds_map_destroy(map);
}

/* Variables i and j (Our counters for the columns and rows respectively)
   wid and height to get the width and height of our sprite being used
*/
var i, j;
var wid = sprite_get_width(spr_levels); hei = sprite_get_height(spr_levels);

for (i = 0; i < 3; i++){     //The middle number is how many levels you want. If you want four change three to four...
var inst = instance_create_depth(x + (i * wid + (wid /2)), y, 0, obj_levels);   // The (wd/2) within the i * structure is how many pixels in between each level button.
with(inst){
if (lvl <= global.level) {sprite_index = spr_unlocked;}
else {sprite_index = spr_locked;}
 
 image_index = global.level - 1;
}
 }
}
The rest should work assuming you have two sprites one for locked and one for unlocked. Each sprite should have all levels needed within them as I referenced above simply showing the image indexes for one. You should be able to test it temporarily with right clicking on the next level, leaving the game and then comming back.

**** It should be noted at the moment once you test this by right clicking on a level or using a collision there is no way to reset your levels for final game play. I would just add this code of line once per reset to delete the entire file then create a new one by inserting this to the very first line of your control object:

obj_cntrl
Code:
if (file_exists("myfile"))
{
 file_delete("myfile")
}
I implemented this however it saids var j is only referenced once and what would spr_levels be
 
Last edited by a moderator:

Gamebot

Member
J doesn't matter. Anything referenced once isn't needed. You can delete j or run as is. As far as spr_levels I think it was a typo try using spr_locked or spr_unlocked...doesn't matter as long as they are the same width.
 
Top