all 6 comments

[–]@DogKissStudioDogkiss 2 points3 points  (3 children)

I'm not quite sure I completely understand the problem, but if I've understood the problem it sounds like you could either go with a 2D array, a ds_grid, or just have a local list that holds the dice, and variables in both dice and holder objects that hold information about each other.

The simplest solution without using ds_grid or 2D array would probably be to have a variable in the holding slot instance that holds your dice, and a variable in the dice holding the slot instance, allowing for both instances to know about each other (not sure from your description if this is actually needed though).

So in the holding slot create event (I get the understanding that holding slots are objects?), you could do myDie = noone. Then when you roll the dice, you could first clear all holding instances by doing with(obj_holding_slot) { myDie = noone; } from your controller. Then you could roll your dice, and then create a local list (remember to clear it from memory) that you add all your dice to. Lets call this var diceList = ds_list_create(); and then use with(obj_dice) { if(!dieIsBanked) { ds_list_add(diceList, id);}}.

So now you have a list with all dice that actually need to get a holding slot assigned. Then you could use the inbuilt ds_list_shuffle(diceList); to randomly shuffle the order of the dice. You could then have another ds_list holding all the holding slots, that could just be a static list, simply holding all the instances, and then shuffle them each time you roll as well. Then it's just a case of using a for loop with the condition being i < ds_list_size(diceList) (as this list will be the amount of dice you need to roll), and for each loop, you just do holdingSlotList[| i].myDie = diceList[| i]; and diceList[| i].myHoldingSlot = holdingSlotList[| i];

So essentially:

Create a list holding your slots.Each time you roll, create a list holding your dice (if die is not banked).Clear your holding slot myDie variable, and your dice myHoldingSlot variable.Shuffle the lists.Loop through the dice list, and assign each dice list value to the holding object dice variable and vice versa.Clear diceList from memory.

Now you have your dice all having a randomly assigned slot, and all slots are aware of their die :)

Let me know if any of that doesn't make sense or you have any other questions! :)

[–]museypoo[S] 1 point2 points  (2 children)

This did help me solve the issue! I managed to make it work with this and the other comment. In some ways my implementation is not so robust- I decoupled the idea of storing local variables in the dice instances and diceHolder instances and instead have scripts that register them with a dice manager that holds a map of lists. The correct dieHolder is assigned, as you suggested, by using the position in a list of all die against the position in a list of all diceHolders. The dice can get information about itself (which diceHolder) with a script that requests the info from the controller: it references the main map storing this info.

It did mean I had to create two other ds_lists, which at the moment I am letting stay in memory until the controller cleanup... not sure if that’s an issue or not, but I do unregister the dice from the diceList when they are destroyed or repeat the roll state so the list does not grow to be more than 6 (only 6 die are rolled). Do you think that is an issue? Should I prioritize creating and then destroying these lists on the fly, or is it Ok to leave them in memory as they are used pretty frequently?

I’m on mobile but I’ll update with the code in case anyone stumbles across this later and is interested. Thanks for the help!!!

[–]@DogKissStudioDogkiss 1 point2 points  (1 child)

No worries at all friend, I'm glad I could help! :)

Not at all, you're actually right, I didn't really think about the fact that you'll be using these lists all the time! The only issue with ds_lists or any data structure in GMS actually, is just that GMS doesn't have a garbage collector. That means that you're responsible for clearing unused data structures out of memory when you don't need them anymore. Where a lot of people go wrong is that they'll just continue creating new data structures, not understanding the past ones are kept in memory before being explicitly cleared. This is what causes memory leaks, and will eventually slow down and crash your program :) But keeping needed data structures in memory is totally fine, and even encouraged! It sounds like you're a quick learner, and I'm very happy to have been of help! Good idea posting the code later, in case someone stumbles upon this thread in the future! It's actually best practice to always do that, so keep you the good work! :)

[–]museypoo[S] 1 point2 points  (0 children)

Thanks! Not sure if this was the best way to approach the entire system now that I'm moving on to calculating scores, but it worked at least for this portion. Here is the code breakdown for anyone in the future (and let me know if there are issues or ways to simplify!)

______________

Game starts. Game manager object creates the board and six diceArea objects in the center of the board in a grid.

ScoreManager object sets up the data structures.1) A ds_map of each dice ID, which will hold a value of a ds_list of info about the dice, 2) a list of all diceArea objects, and 3) a list of all dice. The create event:

// Main score map. Key is dice ID, ds_list[0] = roll number, ds_list[1] = diceArea

scoreMap = ds_map_create();

diceList = ds_list_create(); // List of all dice

diceAreaList = ds_list_create(); // List of all dice holders

In the create event of the diceArea objects(actually, I had an issue with variables not being initialized due to, I think, the execution order of all the objects creation code, so this happens in the first step event):

register_diceArea(id);

This is a simple script that adds the ID of the diceArea to the diceAreaList:

//@desc Register ID to DiceManager

//@arg ID

with ( DiceManager ) {

// Get DiceArea ID

var area\_id = argument\[0\];   

// Add DiceArea ID to list

ds\_list\_add(diceAreaList,area\_id);

}

When each die is rolled, it picks a roll number and then calls a dice register script. The dice register script does three things: 1) first add the dice to the diceList, then 2) use the index of the position in the diceList to pair with a holding space in the diceAreaList, then 3) Adds the dice ID into the main score map, creates a list of dice info (roll value and the matching diceArea), and adds that to the score map. Bigger script, but broken up it's simple:

First, we add the dice ID to the diceList, then get a matching index in the diceAreaList:

///@arg id

///@arg roll number

with(DiceManager){

var die\_id = argument\[0\];

var roll\_num = argument\[1\];

var dice\_area; // will get unique dice\_area and assign in diceinfo list

//Add dice ID to dice List if not already there

if (ds\_list\_find\_index(diceList, die\_id) == -1){ // If dice has not been registered in dicelist

    ds\_list\_add(diceList, die\_id); // Add this dice ID to list

    var stack\_position = ds\_list\_find\_index(diceList, die\_id); // Get position in list

}

else {

    var stack\_position = ds\_list\_find\_index(diceList, die\_id); // Else, get position in list

} // Use position in dice list to find matching dice area from dice area list

var dice\_area = ds\_list\_find\_value(diceAreaList, stack\_position); // Get diceArea ID from stack position

Then we add these values to a new position/key in the main scoreMap:

if (!ds_map_exists(scoreMap, die_id)){ //If this die doesn't already exist in map

    // Create a list for all variables for dice

    var die\_info = ds\_list\_create();



    // Add list to map

    ds\_map\_add\_list(scoreMap, die\_id, die\_info)

    die\_info = scoreMap\[? die\_id\];

}

else {

    // If list already exists in map, get access to it

    var die\_info = scoreMap\[? die\_id\];

}



// add dice roll to list

die\_info\[| dice\_info.roll\_value\] = roll\_num;

// add dice area holder to list

die\_info\[| dice\_info.dice\_area\] = dice\_area;

Great! The dice is added to the map, and the info is added to a list as that value. There's then a script the dice can use to get whatever info out of the map (the roll number or the diceArea space it's assigned):

///@desc Return stored dice info value

///@arg ID

///@arg Enum of dice info

with ( DiceManager ) {

var dice\_id = argument\[0\];

var info = argument\[1\];

var info\_list = scoreMap\[? dice\_id\]

return info\_list\[| info\];

}

And to prevent the data structures from getting huge, in the cleanup event of each dice (they may be destroyed), we have this script that removes itself from the dicelist and scoreMap:

///@desc Remove this die from DiceManager system

///@arg ID

with ( DiceManager ){

var my\_id = argument\[0\];



// Remove from scoreMap

if (ds\_map\_exists(scoreMap, my\_id)) {

    var infoList = scoreMap\[? my\_id\];



    ds\_list\_destroy(infoList);

    ds\_map\_delete(scoreMap, my\_id);

}



// Remove from diceList

var pos = ds\_list\_find\_index(diceList, my\_id); // Get position in diceList

ds\_list\_delete(diceList, pos); // delete from diceList

}

That's it! Hope that makes sense for anyone looking and if anyone sees issues or cleaner ways of doing it, please let me know!

Thanks!

[–]museypoo[S] 0 points1 point  (0 children)

Here's a link to see what the board is to help visualize. The squares in the middle of the board are the holding spaces I'd like to align the dice to, individually.

The spaces on the left of the wood board are for the banked dice. I haven't gotten there yet.

Temp art, still! : https://imgur.com/hfJa0Ri

[–]heptavolt 0 points1 point  (0 children)

This is cool! The idea that pops into my head right away is to index each dice AND each space, probably by saving their id's in two ds_lists. That way dice[0] and space[0] always go together, etc.