How do I create a random item spawner with no repeats? - game-maker

I am currently working on a rogue-like game in GameMaker Studio 2 and i would like to have an item spawner where no items are repeated.
I have tried multiple different ideas of what i think would work, such as giving items and id variable and only spawning items which hasn't had it's id called, although it doesn't seem to work.
The code I have right now is basic, but that is because it's the only way I've been able to spawn an item, there is repeating items with what i have and i would like to stop that from happening.
Here is the Create code of the object:
// Items
var items = choose(
obj_homing,
obj_tracking,
obj_bounce,
obj_double_xp,
obj_shotgun,
obj_orbit,
obj_firefaster,
obj_scattershot,
obj_damageboost,
obj_explosive
);
instance_create_layer(x, y, "Items", choose(items));
I haven't had any actually crashes in the game, although the errors i have faced are multiple of the same object spawning twice when i would like items to not repeat.

One option is to modify the items array after each call to remove the spawned item, and re-initialize it as full only at the start of each game or when the array is empty.
The problem I'm seeing in looking through the Game Maker Language Documentation is that I cannot find a way to delete an object from an existing array and resize the array.

You're placing choose on both defining the var, and when creating the layer.
Now, I don't know exactly what choose does, but I assume it's choosing randomly a selection from the array.
So Items would only return a single chosen item from the array, maybe it's better to remove the choose function from the Items, and only decide that when creating the object.
So the Items should become an array:
var items = [
obj_homing,
obj_tracking,
obj_bounce,
obj_double_xp,
obj_shotgun,
obj_orbit,
obj_firefaster,
obj_scattershot,
obj_damageboost,
obj_explosive
];

Just save the random instance in a variable, then when you create a random instance, check if equals to the instance that you have created previously, and if it is, call again the function until the previous instance is different from the new generated instance.

If you want to spawn every item only once, how about changing the current spawned object in the array to "noone".
And at every spawn cycle, you would check, if the selected item is noone and if so, select the next item (array[i++]).
Also do not forget to randomize the seed, somewhere in the beginning of your game with randomize().

Related

Foreach inside asp.net mvc5 view

I'm in need of a little help in here . I'm getting results that come from virtual property , but one row displays in multiple rows in view. How to display a record inside a row , and not in multiple records
#foreach (var item in Model.Event.Id)
appears to be your problem. You're looping over the event ID, which since it's a string, will be treated like an array of characters. Therefore it prints one character from the ID on each line, and then, because of the rest of the code, repeats all the other details of that event on each line.
Since you only appear to have one single Event in your Model, it seems that you do not need any kind of loop here at all.
However it's not entirely clear what your intentions are - perhaps you intended to loop over something else in your model which is not shown. If so, please clarify the question and possibly the answer could be expanded.

Game Maker Studio Score, My Score resets when going to the next room

I'm having a problem regarding the scores in my game, My game is about answering questions using jumbled letters and when the player gets one correct answer, the game should add +1 to the game score and move to the next level (which is in the next room) and will generate another question, and keeping your last score which is 1. My problem is, the score just keeps on resetting to a value of 0 when moved into the next room. I want it to continuously add +1 even when I go to the next rooms. Thankyou in advance.
There are many solutions.
1) Set your score controller object as persistent
This is the best, as you don't need to do anything else, and in fact, it's a good rule to have one object as a persistent controller.
2) You can save your score to the file and load it each time this object (that stores the variable) is being created
This requires save\load manipulation, and in some cases (e.g you don't want to have ANY persistent objects) can be better, but I highly doubt.
You are not giving enough details about how are you storing the score value.
That may be cause by many issue in the way you are making the game, so im going to try to give all solutions to all possible scenarios:
1) Storing Score in Object Variable
This way may have two different sub scenarios:
a) Going to Next Room after Right answer
b) Restart the same room
This completly reset the variable on the object because the object is destroyed and then created again initilizing again the variables it hold when the room is created.
For this the solution is simply: set persistent true, you can do it from the form object properties (the interface that pop up when you open a object) or using gml on the create event of the object:
object: CREATE event
persistent = true;
This will make the object even if is repeated on the room created to no to create it again, so the event CREATE will no be never repeated again.
2) Storing the Score in variable of the room using Room Creation Event
In this scenario happeng the same that above, its just a local variable the room but exists only for the room and will only exists during the room until its restarted or leaved.
In this case the best is to transform this variable to a global instance in the following way:
global.points = 0;
And this is the best way to store score for you game.
Just remember no to put it in a create event of a not persistent object or it will be reseted to ZERO everything that object is created.
In that case you can check if the variable exists and then if not initializing it:
if (variable_global_exists("points") == true) {
global.points = 0;
}
Now if you want to save it you need to use file functions which is another question.

Realm asObservable() emit only new items

I'm new to RxJava, and trying to use the Realm Observable feature.
When doing this
realm.where(Intake.class)
.findAllSorted("time", Sort.DESCENDING)
.asObservable()
I get the full list of items, but when soemthing changes (ie item added), I get the full list again.
What is the RxJava-way to get only the new items?
Thanks in advance
You are currently observing the query results. Because your query can contain multiple items (findAllSorted()), you're always observing the RealmResults that will emit all sorted items when there's a change (see docs).
You can do something like this:
realm.where(Intake.class)
.findAllSorted("time", Sort.DESCENDING)
.asObservable()
.flatMapIterable(results -> results)
.distinct();
This does 2 more things:
convert your RealmResults to singular Intake instances
only let distinct items pass through (make sure your Intake implements equals() correctly)
This does however impose some extra CPU load, because each time the query passes on a new RealmResult, processing is done to filter out the distinct items.
In the above example, sorting will work on the initial set of emitted Intake objects. However, any subsequent emitted items could be observed out of order because they are new and emitted after the initial results.

modify field value in a crossfilter after insertion

I need to modify a field value for all records in a crossfilter before inserting new records.
The API doesn't say anything about it. Is there a way to do that ?
Even if it's a hack that would be really useful to me.
Looking at the code, the data array is held as a private local variable inside the crossfilter function so there's no way to get at it directly.
With that said, it looks like Crossfilter really tries to minimize the number of copies of the data it makes. So callback functions like the ones passed into crossfilter.dimension or dimension.filter are passed the actual records themselves from the data array (using the native Array.map) so any changes to make to the records will be made to the main records.
With that said, you obviously need to be very careful that you're not changing anything that is relied on by the existing dimensions, filters or groups. Otherwise you'll end up with data that doesn't agree with the internal Crossfilter structures and chaos will ensue.
The cool thing about .remove is it only removes entries that match the currently applied filters. So if you create a 'unique dimension' that returns a unique value for every entry in your dataset (like an ID column), you can have a function like this:
function editEntry(id, changes) {
uniqueDimension.filter(id); // filter to the item you want to change
var selectedEntry = uniqueDimension.top(1)[0]; // get the item
_.extend(selectedEntry, changes); // apply changes to it
ndx.remove(); // remove all items that pass the current filter (which will just be the item we are changing
ndx.add([selectedEntry]); // re-add the item
uniqueDimension.filter(null); // clear the filter
dc.redrawAll(); // redraw the UI
}
At the least you could do a cf.remove() then readd the adjusted data with cf.add().

Looping a list and adjusting it

I want to say that my code works correctly but i don't know why it is working like that. So to make it clear, here is my code:
List<NewsFlash> newsfl = tsm.getNewsFlashes();
foreach (NewsFlash item in newsfl)
{
item.smartform.dtDate = item.smartform.dtDate.ToShortDateString();
}
//Get all the newsFlash items and bind to the repeater
rptNewsFlash.DataSource = newsfl;
rptNewsFlash.DataBind();
Like you can see, I am looping the list newsfl and I am editing item.smartform.dtDate. What is weird for me is, when I edit item.smartform.dtDate, then the property dtDate in the list newsfl is also changed. This is what I want, but it is kind of weird I think, because item within the foreach loop has nothing to do with the list newsfl?
Hope you understand my question.
Thanks
Each item in the foreach is just a reference to the item at a specific index within newsfl - so when your loop is done, you've updated all the item's in the list, and those items hang onto those changes. This makes sense because each item is not a copy of the original, it is the original.
So, imagine item and newsfl[n] as two doors to the same room, you end up in the same place - and it doesn't matter which door I arrive through, if I start moving furniture around, it is also moved for anyone who comes in through either door.
On another note, if this didn't happen, then what would you expect to happen? Since you make changes to item, surely you want to keep them?
In the line foreach (NewsFlash item in newsfl) you take a reference, called item, to each of the entries in newsfl. This doesn't create a copy of the item, just a reference to the item in the list.
That way if you update a value on item, the entry in newfl will also be updated.
Why shouldn't it be changed? The object "item" in your foreach loop is exactly the same object as the one in your "newsfl" list. Actually the object "item" only points to the correct object in the list.

Resources