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

Set 1st, 2nd, 3rd, place at end of alarm

K

Kamon145

Guest
*EDIT* Decided to edit first post with where I'm at now. Test project is very close to working how I want it to, things that I would still like to fix are :
* I have a variable tracking what player is in first, but a ds_list tracking who is last. I would like to get everything on the same track if possible and be able to keep track of each players place.
* currently, ties work just as I wanted them to, where in a game of 4 players if player 2 and 3 are tied, the score would be 1st, 2nd, 2nd, 3rd as opposed to 1st, 3rd, 3rd, 4th, but I would like to check for ties somehow and draw the score differently in that case.
I am posting a link to my test gms2 project if anybody interested in having a look, most of the code is sprawled out throughout this thread but there are some things Ive done differently here. Many thanks to 'the_dude_abides' for helping me get as far along with this as i have, but as with all things, there's always room for improvement!
link to gms2 file: https://we.tl/t-f6n0h6N9U3
 
Last edited by a moderator:
S

spoonsinbunnies

Guest
place=4//set place to last
global.testing=id// test for itself
with player// loop through all players
{
if kills<global.testing.kills//if my score is lower than the one currently testing
global.testing.place-=1// the one curremtly testing did better than me and moves up a place
}

pleas note this saves the place inside the player not as a global variable
 
K

Kamon145

Guest
place=4//set place to last
global.testing=id// test for itself
with player// loop through all players
{
if kills<global.testing.kills//if my score is lower than the one currently testing
global.testing.place-=1// the one curremtly testing did better than me and moves up a place
}

pleas note this saves the place inside the player not as a global variable
Where is global.testing initialized and what is it initially set to? do i put global.testing=id// in the creation event for each player or does that run in the event that I am tallying the scores up?
*EDIT* Okay I think I figured it out, it works good this way but I would like it to bump the last players up if there is a tie if possible... right now if only 1 player scores it puts them at first and the other three at 4, is there a way I can check for ties and bump them up to 2nd?
 
Last edited by a moderator:
I did it this way, using a separate object that just tallys up all the scores. It works for placing them all in order if the scores are not equal, but also treats equal scores so they share the same place.


create event: (object that looks at player instances)
Code:
score_priority = ds_priority_create();
score_list = ds_list_create();
score_list_2 = ds_list_create();
action for when you want to tally up scores:
Code:
with (player)// loop through all players
{ds_priority_add(other.score_priority, id, kills)}
place = 0;
repeat (ds_priority_size(score_priority))
{var is_id = ds_priority_find_max(score_priority);
var is_max = ds_priority_find_priority(score_priority, is_id);
ds_priority_delete_max(score_priority);
if ds_list_find_index(score_list, is_max) == -1 // use this function as a control method to check whether previously added scores are equal - if they are then they will be already on the list, and this will not run
{place += 1;
ds_list_add(score_list, is_max)
}
var result = "place " + string(place) + " = " + string(object_get_name(is_id.object_index)) + ". Kills = " + string(is_max);
ds_list_add(score_list_2, result) // all the spaces here are intentional
}
destroy event:
Code:
ds_priority_destroy(score_priority);
ds_list_destroy(score_list);
ds_list_destroy(score_list_2);
This will give the main object a ds list (score_list_2) with a string for each entry that says:
"place 1 = player_1. Kills = 10"
"place 1 = player_3. Kills = 10"
"place 2 = player_2. Kills = 8"
"place 3 = player_4. Kills = 6"
etc

It's a bit of a long winded way to do it, so it's almost certainly not the best way. But it works, so.....

The ds priority is used to order the results, and hold the id of the player instances. By checking the first list for their score it is being used to see if they are already present. If not: place gets 1 added to it's value, and the score is added to the list. If the score is already present (meaning it is equal to a previous players) then place gets no value added to it.

The second list gets the total result added to it as a string, so it can be read by the main object and display the full information in the correct order.
 
K

Kamon145

Guest
I did it this way, using a separate object that just tallys up all the scores. It works for placing them all in order if the scores are not equal, but also treats equal scores so they share the same place.


create event: (object that looks at player instances)
Code:
score_priority = ds_priority_create();
score_list = ds_list_create();
score_list_2 = ds_list_create();
action for when you want to tally up scores:
Code:
with (player)// loop through all players
{ds_priority_add(other.score_priority, id, kills)}
place = 0;
repeat (ds_priority_size(score_priority))
{var is_id = ds_priority_find_max(score_priority);
var is_max = ds_priority_find_priority(score_priority, is_id);
ds_priority_delete_max(score_priority);
if ds_list_find_index(score_list, is_max) == -1 // use this function as a control method to check whether previously added scores are equal - if they are then they will be already on the list, and this will not run
{place += 1;
ds_list_add(score_list, is_max)
}
var result = "place " + string(place) + " = " + string(object_get_name(is_id.object_index)) + ". Kills = " + string(is_max);
ds_list_add(score_list_2, result) // all the spaces here are intentional
}
destroy event:
Code:
ds_priority_destroy(score_priority);
ds_list_destroy(score_list);
ds_list_destroy(score_list_2);
This will give the main object a ds list (score_list_2) with a string for each entry that says:
"place 1 = player_1. Kills = 10"
"place 1 = player_3. Kills = 10"
"place 2 = player_2. Kills = 8"
"place 3 = player_4. Kills = 6"
etc

It's a bit of a long winded way to do it, so it's almost certainly not the best way. But it works, so.....

The ds priority is used to order the results, and hold the id of the player instances. By checking the first list for their score it is being used to see if they are already present. If not: place gets 1 added to it's value, and the score is added to the list. If the score is already present (meaning it is equal to a previous players) then place gets no value added to it.

The second list gets the total result added to it as a string, so it can be read by the main object and display the full information in the correct order.
Thanks so much for the reply! Ive been at it all night and I'm still stumped so i was just about to ask for more help haha. However Im still quite new to ds_lists and am not quite sure how to access the information and display it where needed, currently each player has a "place" variable and that dosen't appear to change when iI tally the scores, so the variables are stored in the control object? How would i go about drawing them next to the players name? Thanks again for your help and for keeping me from going crazy :p
 
The way I presented it was based on the idea of one object having the list, and the information stored in such a way that it covered the details of the player. If you want the player instance itself to know that info:

Code:
with (player)// loop through all players
{ds_priority_add(other.score_priority, id, kills)}
place = 0;
repeat (ds_priority_size(score_priority))
{var is_id = ds_priority_find_max(score_priority);
var is_max = ds_priority_find_priority(score_priority, is_id);
ds_priority_delete_max(score_priority);
if ds_list_find_index(score_list, is_max) == -1 // use this function as a control method to check whether previously added scores are equal - if they are then they will be already on the list, and this will not run
{place += 1;
ds_list_add(score_list, is_max)
}
is_id.is_position = "place = " + string(place) + ". Kills = " + string(is_max);
}
If you give the player instances a variable called 'is_position', then the above change would set that variable to hold a string that says their position and number of kills. I haven't called it 'place' because it may cause an issue with the same named variable in the main object (it may not cause a problem - I'm going off a dim recollection rather than 100% testing this)

Remove also the second ds list (score_list_2) as it would be unnecessary if done this way.

EDIT:
Though, having said that, you may want to keep it for something like drawing a score screen at the end of a game. Set both the ds list,and the player variable, at the same time.Then you would have the info for the player, and have the full info stored in a way that can be easily accessed, as well as already presented to show.
 
Last edited:
K

Kamon145

Guest
The way I presented it was based on the idea of one object having the list, and the information stored in such a way that it covered the details of the player. If you want the player instance itself to know that info:

Code:
with (player)// loop through all players
{ds_priority_add(other.score_priority, id, kills)}
place = 0;
repeat (ds_priority_size(score_priority))
{var is_id = ds_priority_find_max(score_priority);
var is_max = ds_priority_find_priority(score_priority, is_id);
ds_priority_delete_max(score_priority);
if ds_list_find_index(score_list, is_max) == -1 // use this function as a control method to check whether previously added scores are equal - if they are then they will be already on the list, and this will not run
{place += 1;
ds_list_add(score_list, is_max)
}
is_id.is_position = "place = " + string(place) + ". Kills = " + string(is_max);
}
If you give the player instances a variable called 'is_position', then the above change would set that variable to hold a string that says their position and number of kills. I haven't called it 'place' because it may cause an issue with the same named variable in the main object (it may not cause a problem - I'm going off a dim recollection rather than 100% testing this)

Remove also the second ds list (score_list_2) as it would be unnecessary if done this way.

EDIT:
Though, having said that, you may want to keep it for something like drawing a score screen at the end of a game. Set both the ds list,and the player variable, at the same time.Then you would have the info for the player, and have the full info stored in a way that can be easily accessed, as well as already presented to show.
Im still running into a bit of trouble somewhere.. I set up a new test project with only two objects to try and figure this out, a player object and control object, the control objects code is as follows:
Code:
//CREATE EVENT
score_priority = ds_priority_create();
score_list = ds_list_create();

//KEY PRESSED SPACE
with (player)// loop through all players
{ds_priority_add(other.score_priority, id, points)}
place = 0;
repeat (ds_priority_size(score_priority))
{var is_id = ds_priority_find_max(score_priority);
var is_max = ds_priority_find_priority(score_priority, is_id);
ds_priority_delete_max(score_priority);
if ds_list_find_index(score_list, is_max) == -1 // use this function as a control method to check whether previously added scores are equal - if they are then they will be already on the list, and this will not run
{place += 1;
ds_list_add(score_list, is_max)
}
is_id.is_position = "place = " + string(place) + ". Points = " + string(is_max);
}
and my player object is
Code:
//CREATE EVENT
points = 0;
place = 4;
is_position = 4;
//MOUSE BUTTON LEFT
points+=1
//DRAW
draw_self();
draw_text(x,y-32,points);
draw_text(x,y+4,string(place))
I have 4 of these in the room and when clicked their individual scores go up, however when i click the space nothing seems to change about their place, Ive tried drawing variable place and variable is_position and neither one seem to change when i press space.. am I not accessing the variable correctly? or did i mess something else up along the way?
 
Code:
is_id.place = "place = " + string(place) + ". Kills = " + string(is_max);
It is fine to set the variable 'place' in the player instance like this. I have no issue, so I would hazard a guess this is the problem:
Code:
draw_text(x,y+4,string(place))
because that variable wasn't actually being set in the player instance. The above code will set it.

I don't think you want to use key pressed, even if this is just for testing purposes (?), as it registers continuously within the event. But my suggestion is based on only being called once at the end of a match. Key released would ensure it only runs once for the purposes of testing it once.

The reason I say this is because I'm not resetting the ds list that controls it. It's presumed to run once, at the end, so there is nothing in there clearing off the entries. Run it more than once and all the previous entries will still be included, whereas it ought to be cleared after every use if intended to be run multiple times.

Code:
//KEY RELEASED SPACE
with (player)// loop through all players - note that I'm assuming this is what the object is called...it should be the object name of whatever you've called the player
{ds_priority_add(other.score_priority, id, points)}
place = 0;
ds_list_clear(score_list) // clears the list (if it's empty it doesn't matter, but will be necessary if run more than once)
repeat (ds_priority_size(score_priority))
{var is_id = ds_priority_find_max(score_priority);
var is_max = ds_priority_find_priority(score_priority, is_id);
ds_priority_delete_max(score_priority);
if ds_list_find_index(score_list, is_max) == -1 // use this function as a control method to check whether previously added scores are equal - if they are then they will be already on the list, and this will not run
{place += 1;
ds_list_add(score_list, is_max)
}
is_id.place = "place = " + string(place) + ". Points = " + string(is_max);
}
 
Last edited:
K

Kamon145

Guest
Code:
is_id.place = "place = " + string(place) + ". Kills = " + string(is_max);
It is fine to set the variable 'place' in the player instance like this. I have no issue, so I would hazard a guess this is the problem:
Code:
draw_text(x,y+4,string(place))
because that variable wasn't actually being set in the player instance. The above code will set it.

I don't think you want to use key pressed, even if this is just for testing purposes (?), as it registers continuously within the event. But my suggestion is based on only being called once at the end of a match. Key released would ensure it only runs once for the purposes of testing it once.

The reason I say this is because I'm not resetting the ds list that controls it. It's presumed to run once, at the end, so there is nothing in there clearing off the entries. Run it more than once and all the previous entries will still be included, whereas it ought to be cleared after every use if intended to be run multiple times.

Code:
//KEY RELEASED SPACE
with (player)// loop through all players - note that I'm assuming this is what the object is called...it should be the object name of whatever you've called the player
{ds_priority_add(other.score_priority, id, points)}
place = 0;
ds_list_clear(score_list) // clears the list (if it's empty it doesn't matter, but will be necessary if run more than once)
repeat (ds_priority_size(score_priority))
{var is_id = ds_priority_find_max(score_priority);
var is_max = ds_priority_find_priority(score_priority, is_id);
ds_priority_delete_max(score_priority);
if ds_list_find_index(score_list, is_max) == -1 // use this function as a control method to check whether previously added scores are equal - if they are then they will be already on the list, and this will not run
{place += 1;
ds_list_add(score_list, is_max)
}
is_id.place = "place = " + string(place) + ". Points = " + string(is_max);
}
Its still not changing.. at least not in the draw event, is it possible it has something to do with how the variables are set in the player create event? I've tried changing the values to place = 4, is_position = 4, is position = 1, is_position = 0 but that dosent seem to matter too much.. I appreciate all the help, sorry if I'm being a pain lol I just really wanna get this to work and I feel like its so close!
 
It's not happening for me, so it's tricky to say. I have four different objects, with the same parent. They have specific values for kills, so that I can check that the outcome is as expected. That is the result that I'm seeing for when there is an equal value, and for when there isn't. The project is set up for when a key is released, the same as yours. And it's now configured for multiple uses, if for example you wanted to use random numbers and really test that it always works.

If isn't working for you then I'm not sure why. The only thing I could imagine happening is that you have a global effect for the mouse button release that adds onto 'points'. If that were true then all the instances with that code would end up with the same amount of points after each press, and give the same result. But if that were the case then you should still see 'place' going up by 1, and all of the player instances should be showing it.

If need be I will just link the file, but I copied the code exactly here and only changed the info of the object in the with statement.

EDIT:
Code:
draw_text(x,y+4,string(place))
'place' is already a string so this isn't needed. Don't know if that makes a difference.
Code:
draw_text(x,y+4, place)
EDIT EDIT:
It makes no difference. I can still see the result for 'place', and it is working on randomly generated results.
 
Last edited:
K

Kamon145

Guest
It's not happening for me, so it's tricky to say. I have four different objects, with the same parent. They have specific values for kills, so that I can check that the outcome is as expected. That is the result that I'm seeing for when there is an equal value, and for when there isn't. The project is set up for when a key is released, the same as yours. And it's now configured for multiple uses, if for example you wanted to use random numbers and really test that it always works.

If isn't working for you then I'm not sure why. The only thing I could imagine happening is that you have a global effect for the mouse button release that adds onto 'points'. If that were true then all the instances with that code would end up with the same amount of points after each press, and give the same result. But if that were the case then you should still see 'place' going up by 1, and all of the player instances should be showing it.

If need be I will just link the file, but I copied the code exactly here and only changed the info of the object in the with statement.
Yeah if its not too much trouble could you post it? I just went through everything again and double checked and its all exactly as you have it, except changing the word player to my object player name. I still don't know what the heck I'm doing wrong, but if you post it I'll compare them side by side and see what my problem is.. Very strange that it's not working for me xP
 
S

spoonsinbunnies

Guest
Where is global.testing initialized and what is it initially set to? do i put global.testing=id// in the creation event for each player or does that run in the event that I am tallying the scores up?
*EDIT* Okay I think I figured it out, it works good this way but I would like it to bump the last players up if there is a tie if possible... right now if only 1 player scores it puts them at first and the other three at 4, is there a way I can check for ties and bump them up to 2nd?
a little late to the party as it was bed time here but if you want to go back to my code changing the place at the beginning to 5 and < to <= will make all the players round up there position. You have to change it to 5 because when looping through all the players it will tie itself moving it up by one. This should give you what you wanted.

Edit: this will actually make it so if two people tie for second it will be first, two at second and then fourth, to get around this would require two ds lists and a little work but if you want that Ill try to write one through for you.
 
K

Kamon145

Guest
a little late to the party as it was bed time here but if you want to go back to my code changing the place at the beginning to 5 and < to <= will make all the players round up there position. You have to change it to 5 because when looping through all the players it will tie itself moving it up by one. This should give you what you wanted.

Edit: this will actually make it so if two people tie for second it will be first, two at second and then fourth, to get around this would require two ds lists and a little work but if you want that Ill try to write one through for you.
I still get weird results with this, if i were to check it every time a player got a point, it would go like this right?
Code:
points+=1
place=5//set place to last
global.testing=id// test for itself
with player// loop through all players
{
if points<=global.testing.points//if my score is lower than the one currently testing
global.testing.place-=1// the one curremtly testing did better than me and moves up a place. I would like to see this work though cause the code seems more familiar to me but its still not quite working.
}
This seems to keep players tied even after a player has gotten another point, as in if player 1 and 2 both had 4 it says place 1, and stays the same even after a player has gotten one more point, they need to get two more for it to change places.
You shouldn't have to do that - GMS 2 ought to be able to import the file without any issues. I'm just making sure it's all correct, and then I'll upload a link.
i tried importing it into gms2 but it just showed a blank project, might just be a mac glitch. im gonna switch over windows and try loading it up on gms1.
 
K

Kamon145

Guest
Hmm.. Seems the download may be corrupted.. I tried importing it into gms2 on mac and windows and got a blank project, downloaded gms1.4 and tried opening it on there and it says none of the sprites or objects can be found, so I get an unidentified sprite and 5 unidentified objects, just curious, is this code meant to work with 4 seperate player objects or 4 instances of the same object? I'm working with 4 of the same so I'm wondering if thats where the confusion is coming from.. I'm gonna try to throw that code into gms1 and see if that makes any difference, it seems like it should work the same on gms1 and gms2 but hey its worth a shot!
*EDIT* So i put it together in gms1 and it works now.. huh.. must have had a typo somewhere in my gms2 project, but it works now so that's awesome!! My last question is totally optional, but is there a way to reset the list and have this code run each time the player gets a point so players can see what place their in throughout the game? This will work just fine on its own if not, and I'm really grateful for you helping me get this figured out, you really are the dude!
 
Last edited by a moderator:
There's no reason that you can't do it in a step event and remove the key pressed element. You'd have to be constantly accessing the player instances one way, or the other, so I'm not sure this activity can be limited to a precise response. Whether you're constantly checking to see if the kill / place has changed, or just running it all the time, it's tomato / tomato as far as any difference goes IMO :)

The latter is probably a bit more costly, as it's using and clearing the data structures once per step.

The former could be done with a second variable in the player instances? (probably the least costly way to do it, at a guess), and then having the player instances constantly checking this new variable to see if it's not tallying with 'points'. If it's different then it activates main object to go on and redo the place function.

create event: player instances
Code:
cur_point = 0; // new variable
points = 0;
etc
step event: player instances
Code:
if cur_point != points
{if main_object.active == false // dunno if really need? makes sure that main_object isn't already active, to avoid overwriting any current activity.
// Not sure that would happen anyway, but like this it definitely won't.
{
main_object.active = true;
}
}
event: main object
Code:
if active
{with (player)
{ds_priority_add(other.score_priority, id, points)}
place = 0;
ds_list_clear(score_list)
repeat (ds_priority_size(score_priority))
{var is_id = ds_priority_find_max(score_priority);
var is_max = ds_priority_find_priority(score_priority, is_id);
ds_priority_delete_max(score_priority);
if ds_list_find_index(score_list, is_max) == -1 
{place += 1;
ds_list_add(score_list, is_max)
}
is_id.place = "place = " + string(place) + ". Points = " + string(is_max);
is_id.cur_point = is_max; // <<<<< setting all instances "old value" of 'cur_point' to current 'points' value
}
active = false; // main object switches itself off having done task
}
??
It is setting 'cur_point' for each instance when 'active' is true, so the instance that called it should be reset (cur_point = points) and not activate the main object until the circumstances change again. So it limits how often main object rechecks only to when it's required.
 
Last edited:
K

Kamon145

Guest
There's no reason that you can't do it in a step event and remove the key pressed element. You'd have to be constantly accessing the player instances one way, or the other, so I'm not sure this activity can be limited to a precise response. Whether you're constantly checking to see if the kill / place has changed, or just running it all the time, it's tomato / tomato as far as any difference goes IMO :)

The latter is probably a bit more costly, as it's using and clearing the data structures once per step.

The former could be done with a second variable in the player instances? (probably the least costly way to do it, at a guess), and then having the player instances constantly checking this new variable to see if it's not tallying with 'points'. If it's different then it activates main object to go on and redo the place function.

create event: player instances
Code:
cur_point = 0; // new variable
points = 0;
etc
step event: player instances
Code:
if cur_point != points
{if main_object.active == false // dunno if really need? makes sure that main_object isn't already active, to avoid overwriting any current activity.
// Not sure that would happen anyway, but like this it definitely won't.
{
main_object.active = true;
}
}
event: main object
Code:
if active
{with (player)
{ds_priority_add(other.score_priority, id, points)}
place = 0;
ds_list_clear(score_list)
repeat (ds_priority_size(score_priority))
{var is_id = ds_priority_find_max(score_priority);
var is_max = ds_priority_find_priority(score_priority, is_id);
ds_priority_delete_max(score_priority);
if ds_list_find_index(score_list, is_max) == -1
{place += 1;
ds_list_add(score_list, is_max)
}
is_id.place = "place = " + string(place) + ". Points = " + string(is_max);
is_id.cur_point = is_max; // <<<<< setting all instances "old value" of 'cur_point' to current 'points' value
}
active = false; // main object switches itself off having done task
}
??
It is setting 'cur_point' for each instance when 'active' is true, so the instance that called it should be reset (cur_point = points) and not activate the main object until the circumstances change again. So it limits how often main object rechecks only to when it's required.
Is the player step event essentially just checking to see if their score has gone up? I think i got it to work by triggering a user event in the main control object, the other thing i had to change was is_id.is_position = place, not sure why it wasnt working the other way. now my user event in my control object reads,
Code:
with (obj_player)// loop through all players
{ds_priority_add(other.score_priority, id, kills)}
place = 0;
ds_list_clear(score_list)
repeat (ds_priority_size(score_priority))
{var is_id = ds_priority_find_max(score_priority);
var is_max = ds_priority_find_priority(score_priority, is_id);
ds_priority_delete_max(score_priority);
if ds_list_find_index(score_list, is_max) == -1 // use this function as a control method to check whether previously added scores are equal - if they are then they will be already on the list, and this will not run
{place += 1;
ds_list_add(score_list, is_max)
}
is_id.is_position = place
}
and so far, everything works exactly as it should! Many thanks for helping me get this figured out, I've been struggling with it for a few days now and haven't found much resources covering the topic. on a final note, where is the best place to destroy the lists? it is a persistent object that is around for the entire game so would it make a difference if i put it in the "end game" event or the "destroy" event? or should I stick it in "Cleanup"?
 
I'm not sure why you needed to change anything to get this working, as it was fine for me. But if it is working, and you feel you understand why, then fair enough :)

There probably are tutorials etc covering elements of this, and maybe even offering better solutions, but this was a specific case. So finding a tutorial that covers the exact same scenario is always going to be unlikely. My game AI had to be built entirely from scratch, as it uses various methods in a particular way. If there was a tutorial for it, it would have saved me 5 years (and a lot of headaches) programming it..... ;) Your best hope for something "exotic" (not really, just different) is that a forum user can fill in whatever gaps your code / understanding has.

"cleanup" sounds like it's a GMS 2 only function, so I wouldn't know when that is activated, or why it is necessary. I guess the difference between "end game" and "destroy" comes down to whether it will actually exist until the game ends. If you only cleared up data structures in the "game end" event, and the object is destroyed before the game ends, then it would result in memory leaks. If the object lasts until the game ends, then presumably either would suffice. But having it in "destroy" would remove any doubt.

Well, anyway, happy to help with getting it closer to being finished!
 
K

Kamon145

Guest
I'm not sure why you needed to change anything to get this working, as it was fine for me. But if it is working, and you feel you understand why, then fair enough :)

There probably are tutorials etc covering elements of this, and maybe even offering better solutions, but this was a specific case. So finding a tutorial that covers the exact same scenario is always going to be unlikely. My game AI had to be built entirely from scratch, as it uses various methods in a particular way. If there was a tutorial for it, it would have saved me 5 years (and a lot of headaches) programming it..... ;) Your best hope for something "exotic" (not really, just different) is that a forum user can fill in whatever gaps your code / understanding has.

"cleanup" sounds like it's a GMS 2 only function, so I wouldn't know when that is activated, or why it is necessary. I guess the difference between "end game" and "destroy" comes down to whether it will actually exist until the game ends. If you only cleared up data structures in the "game end" event, and the object is destroyed before the game ends, then it would result in memory leaks. If the object lasts until the game ends, then presumably either would suffice. But having it in "destroy" would remove any doubt.

Well, anyway, happy to help with getting it closer to being finished!
..Okay one last question lol. I went back and added the second list back in, I like your idea of having it all stored in a single object as well to display final score. My control object, user event 0 triggered after player scores, is now revised to
Code:
with (obj_player)// loop through all players
{ds_priority_add(other.score_priority, id, kills)}
place = 0;
ds_list_clear(score_list)
repeat (ds_priority_size(score_priority))
{var is_id = ds_priority_find_max(score_priority);
var is_max = ds_priority_find_priority(score_priority, is_id);
ds_priority_delete_max(score_priority);
if ds_list_find_index(score_list, is_max) == -1 // use this function as a control method to check whether previously added scores are equal - if they are then they will be already on the list, and this will not run
{place += 1;
ds_list_add(score_list, is_max)
}
is_id.is_position = place
}
var result = "place " + string(place) + " = " + string(object_get_name(is_id.object_index)) + ". Kills = " + string(is_max);
ds_list_add(score_list_2, result) // all the spaces here are intentional
My final question is on how I go about drawing the "results" at the end, im not sure how to pull the stored variables out of the list to be drawn. i tried
list = ds_list_find_index(score_list_2,result);
draw_text(32,32,list)
&&
{
list = ds_list_read(score_list_2,result);
draw_text(32,32,list)
}
but both of those give me errors saying variable result hasn't been established, this happens even when i set an alarm and wait to draw results till after players have scored so I assume I'm just not pulling the variable correctly
*EDIT*
Im getting closer, got it to draw at least part of the list on the screen :)
Code:
if !ds_list_empty(score_list_2)
{
var pos = ds_list_find_value(score_list_2,0)
draw_text(room_width/2,room_height/6,pos)
}
This seems to draw the values of whichever player is in last place, I am resetting it the same as i do with list 1 each time somebody scores. Do i need 4 separate lists for each position or is there a way to add all players values to the list simultaneously and have them saved to different positions? Right now if i put anything other than 0 in the list find, it comes up as undefined, regardless of if i reset the list.
 
Last edited by a moderator:
Code:
with (obj_player)// loop through all players
{ds_priority_add(other.score_priority, id, kills)}
place = 0;
ds_list_clear(score_list)
repeat (ds_priority_size(score_priority))
{var is_id = ds_priority_find_max(score_priority);
var is_max = ds_priority_find_priority(score_priority, is_id);
ds_priority_delete_max(score_priority);
if ds_list_find_index(score_list, is_max) == -1
{place += 1;
ds_list_add(score_list, is_max)
}
is_id.is_position = place
}
var result = "place " + string(place) + " = " + string(object_get_name(is_id.object_index)) + ". Kills = " + string(is_max);
ds_list_add(score_list_2, result)
^^^^^ The last two lines are placed wrong. You haven't got them in the repeat loop, therefore they are only done once, which will add a value to position "0" in the list. So you will only have one entry for each time it's run. The others are all undefined because there are no other entries, and by looking past position 0 you have actually exceeded the size of the list. Those positions don't exist, so have no value, and so "undefined" is what you get.

Code:
with (obj_player)// loop through all players
{ds_priority_add(other.score_priority, id, kills)}
place = 0;
ds_list_clear(score_list)
repeat (ds_priority_size(score_priority))
{
var is_id = ds_priority_find_max(score_priority);
var is_max = ds_priority_find_priority(score_priority, is_id);
ds_priority_delete_max(score_priority);
if ds_list_find_index(score_list, is_max) == -1
{
place += 1;
ds_list_add(score_list, is_max)
}
is_id.is_position = place
var result = "place " + string(place) + " = " + string(object_get_name(is_id.object_index)) + ". Kills = " + string(is_max);
ds_list_add(score_list_2, result)
}
The final bracket is now ending the repeat block, and the last two lines are in it. So it will now get 'place' for each time the block is repeated, and also the details to be added to the second ds list.

drawing a ds list:
Code:
var size = ds_list_size(score_list_2);
if  size > 0
{
for (var a = 0; a < size; a++)
{
draw_text(20, 20 + (20 * a), ds_list_find_value(score_list_2, a)) // change these x / y positions to whatever you want
}
}
In this code it is looping through the list, and drawing all of the results. This is one of the most basic ways to do it. You have a start y position, and that has a value being multiplied by 'a' (20 * 0, 20 * 1, 20 * 2 etc) being added to it. A difference of 20 pixels is enough to ensure each line has the vertical space for the default sized font. If you go with a bigger font then you would want to change the value from 20, to the font size plus some extra space.

Done in this fashion it can cover as many entries that will fit on the screen (and beyond), but requires some additions. Such as: the first 20 is the x position in the room, since in my projects the port and view are always the same width as the room (that is not important as to why, and is just my choice to do so). When you have the view scaled you would want the x position to be drawn relative to the view. And the same for the y position.

If you didn't loop through the list then you could just "define" where you want particular lines being drawn (maybe alternating the first being left of the screen center, and the second being right, the third is left, fourth is right etc) Either way you can have the same effects, just as long as you know exactly how many entries there and arrange it accordingly.

Manually:
Code:
draw_set_colour(c_green);
draw_text( whatever, whatever, ds_list_find_value(score_list_2, 0));
draw_set_colour(c_yellow);
draw_text( something, something, ds_list_find_value(score_list_2, 1));
draw_set_colour(c_orange);
draw_text( a different something, a different something, ds_list_find_value(score_list_2, 2));
draw_set_colour(c_red);
draw_text( a different whatever, a different whatever, ds_list_find_value(score_list_2, 3));
OR

For loop:
Code:
var size = ds_list_size(score_list_2);
if  size > 0
{
for (var a = 0; a < size; a++)
{
switch (a)
{
case 0:
draw_set_colour(c_green);
draw_text( whatever, whatever, ds_list_find_value(score_list_2, a));
break;
case 1:
draw_set_colour(c_yellow);
draw_text( something, something, ds_list_find_value(score_list_2, a));
break;
case 2:
draw_set_colour(c_orange);
draw_text( a different something, a different something, ds_list_find_value(score_list_2, a));
break;
case 3:
draw_set_colour(c_red);
draw_text( a different whatever, a different whatever, ds_list_find_value(score_list_2, a))
break;
}
}
}
And if you wanted entries with the same 'place' value to share the same colour / font etc......well.......I'll leave you to figure that out :)
 
Last edited:
K

Kamon145

Guest
Code:
with (obj_player)// loop through all players
{ds_priority_add(other.score_priority, id, kills)}
place = 0;
ds_list_clear(score_list)
repeat (ds_priority_size(score_priority))
{var is_id = ds_priority_find_max(score_priority);
var is_max = ds_priority_find_priority(score_priority, is_id);
ds_priority_delete_max(score_priority);
if ds_list_find_index(score_list, is_max) == -1
{place += 1;
ds_list_add(score_list, is_max)
}
is_id.is_position = place
}
var result = "place " + string(place) + " = " + string(object_get_name(is_id.object_index)) + ". Kills = " + string(is_max);
ds_list_add(score_list_2, result)
^^^^^ The last two lines are placed wrong. You haven't got them in the repeat loop, therefore they are only done once, which will add a value to position "0" in the list. So you will only have one entry for each time it's run. The others are all undefined because there are no other entries, and by looking past position 0 you have actually exceeded the size of the list. Those positions don't exist, so have no value, and so "undefined" is what you get.

Code:
with (obj_player)// loop through all players
{ds_priority_add(other.score_priority, id, kills)}
place = 0;
ds_list_clear(score_list)
repeat (ds_priority_size(score_priority))
{
var is_id = ds_priority_find_max(score_priority);
var is_max = ds_priority_find_priority(score_priority, is_id);
ds_priority_delete_max(score_priority);
if ds_list_find_index(score_list, is_max) == -1
{
place += 1;
ds_list_add(score_list, is_max)
}
is_id.is_position = place
var result = "place " + string(place) + " = " + string(object_get_name(is_id.object_index)) + ". Kills = " + string(is_max);
ds_list_add(score_list_2, result)
}
The final bracket is now ending the repeat block, and the last two lines are in it. So it will now get 'place' for each time the block is repeated, and also the details to be added to the second ds list.

drawing a ds list:
Code:
var size = ds_list_size(score_list_2);
if  size > 0
{
for (var a = 0; a < size; a++)
{
draw_text(20, 20 + (20 * a), ds_list_find_value(score_list_2, a)) // change these x / y positions to whatever you want
}
}
In this code it is looping through the list, and drawing all of the results. This is one of the most basic ways to do it. You have a start y position, and that has a value being multiplied by 'a' (20 * 0, 20 * 1, 20 * 2 etc) being added to it. A difference of 20 pixels is enough to ensure each line has the vertical space for the default sized font. If you go with a bigger font then you would want to change the value from 20, to the font size plus some extra space.

Done in this fashion it can cover as many entries that will fit on the screen (and beyond), but requires some additions. Such as: the first 20 is the x position in the room, since in my projects the port and view are always the same width as the room (that is not important as to why, and is just my choice to do so). When you have the view scaled you would want the x position to be drawn relative to the view. And the same for the y position.

If you didn't loop through the list then you could just "define" where you want particular lines being drawn (maybe alternating the first being left of the screen center, and the second being right, the third is left, fourth is right etc) Either way you can have the same effects, just as long as you know exactly how many entries there and arrange it accordingly.

Manually:
Code:
draw_set_colour(c_green);
draw_text( whatever, whatever, ds_list_find_value(score_list_2, 0));
draw_set_colour(c_yellow);
draw_text( something, something, ds_list_find_value(score_list_2, 1));
draw_set_colour(c_orange);
draw_text( a different something, a different something, ds_list_find_value(score_list_2, 2));
draw_set_colour(c_red);
draw_text( a different whatever, a different whatever, ds_list_find_value(score_list_2, 3));
OR

For loop:
Code:
var size = ds_list_size(score_list_2);
if  size > 0
{
for (var a = 0; a < size; a++)
{
switch (a)
{
case 0:
draw_set_colour(c_green);
draw_text( whatever, whatever, ds_list_find_value(score_list_2, a));
break;
case 1:
draw_set_colour(c_yellow);
draw_text( something, something, ds_list_find_value(score_list_2, a));
break;
case 2:
draw_set_colour(c_orange);
draw_text( a different something, a different something, ds_list_find_value(score_list_2, a));
break;
case 3:
draw_set_colour(c_red);
draw_text( a different whatever, a different whatever, ds_list_find_value(score_list_2, a))
break;
}
}
}
And if you wanted entries with the same 'place' value to share the same colour / font etc......well.......I'll leave you to figure that out :)
Ahh you are the best. I haven't gotten a chance to test it yet cause I'm supposed to be rehearsing and my bandmates are yelling at me :p but from what I can tell by reading through it it looks like you've solved all my problems. I will update this post when I get a chance to put it together tonight and hopefully report victory! And you sir are getting a major thank you in my game, you've been such a big help and i appreciate the time you've spent helping me get this to work, cheers friend!
 
Hmmm, well, thanks are nice...but they don't pay the bills, or put food in my stomach, or get me any closer to my dream of buying a toilet that's made out of 24 carat gold and encrusted with jewels and gems.

Royalties would be better, if I'm ever to achieve the ultimate social status symbol my heart craves ;)
 
K

Kamon145

Guest
Hmmm, well, thanks are nice...but they don't pay the bills, or put food in my stomach, or get me any closer to my dream of buying a toilet that's made out of 24 carat gold and encrusted with jewels and gems.

Royalties would be better, if I'm ever to achieve the ultimate social status symbol my heart craves ;)
Lol sounds good, if I ever start making money on anything using this code, you will be the first to know! Now I just gotta get the dang thing finished.. Hey once i get your score system implemented I'll send you a link so you can be one of the first to test it out!
*EDIT* Just tested your code in the test project and its perfect, works just as I hoped it would. Will get that test project to you tomorrow but as of now Ive been up for idk how many hours or days or what.. but I'm exhausted and am finally crashing. I know my brain is stuck in a for loop and I just keep repeating myself but thanks a million and I will get ahold of you with a demo soon
 
Last edited by a moderator:
No worries. I've had the odd night, or three, where I felt compelled to code for a ridiculous length of time. Let your brain cells refresh for a while.

I'd be happy to give your project a spin if you want it being tested.
 
Top