Released v1.6.4
This update adds the following:
- Adds $init_after: attribute that allows specifying a custom init order for elements
- Dispatches document_loaded event on DOMContentLoaded
- Calls to setAttribute() trigger on_set_attr
- Stdlib: +Array#zip, +Array#min, +Array#max, +Math#perc, +RezBasicObject#unmap_attr
- Stdlib: +Rez.D4, +Rez.D6, +Rez.D8, +Rez.D10, +Rez.D12, +Rez.D20, +Rez.D100
- Stdlib: -Number#chance
The two biggest changes are the new on_set_attr
handler behaviour and the on_document_loaded
behaviour.
For example I have something like this:
@skill base_skill {
value: 1
potential: 4
score: 3
on_set_attr: (obj, params) => {
const {attrName, oldValue, newValue} = params;
if(attrName == "value" || attrName == "potential") {
obj.setAttribute("score", skill.value + ((0.5 * skill.potential).roundp()), false);
}
}
}
I could have defined score
as:
score: ^p{
return this.value + (0.5*this.potential).roundp();
}
and it would have been fine but it felt wasteful given that score is getting read a lot but changed very infrequently. I could also have provided a special method for changing the value
or potential
fields. But it felt error prone. So, now you can respond to changes to attributes.
Next I wanted to create a progress dialog that tracks the progress of my world builder while it is generating the sector and its history. This process takes quite a few seconds and blocks the UI.
Rez includes Alpine.JS which makes this pretty easy with setTimeout scheduling the work:
<div id="progress-container" x-data="{message: 'Initializing simulation...',progress: 0}">
<div class="box mt-6">
<h3 class="title is-4">
<span x-show="progress<100" class="icon-text">
<span class="icon">
<i class="fas fa-spinner fa-spin"></i>
</span>
</span>
Building the Galaxy
</h3>
<p class="mb-4" x-text="message"></p>
<progress
class="progress is-primary"
x-bind:value="progress"
max="100"
x-text="Math.round(progress) + '%'">
</progress>
</div>
</div>
However there is one big problem. Alpine.js has to be loaded with defer
which means it’s not available when the Game.start()
method is called and the view gets painted. So using the regular event handlers Rez makes available don’t help.
Enter the on_document_loaded
handler. This is triggered by the DOMContentLoaded
event and ensures that the Alpine
reference is available.
@card c_world_building {
...
simulate: function() {
const progressData = Alpine.$data(document.getElementById("progress-container"));
if(this.cur_year < this.end_year) {
this.cur_year += 1;
const progress = (100 * (this.cur_year - this.start_year) / (this.end_year - this.start_year)).roundp();
progressData.message = `Simulating ${this.cur_year}`;
progressData.progress = progress;
this.world_builder.simulate_year(this.cur_year);
setTimeout(this.simulate.bind(this));
} else {
progressData.message = "Finished";
setTimeout(() => {$game.startSceneWithId("sc_academy")}, 1500);
}
}
on_document_loaded: (card) => {
card.cur_year = card.start_year;
card.simulate();
}
...
}
The card has painted the display but the simulator doesn’t get started until after the document load is finished.