main
7
Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
e53121a0bb |
Let a behavior hear a song, pattern or sound come to its end (#373)
A game should be able to start the next piece of music when one is over, or wait for a sound before it goes on. Until now a behavior could start and stop music and sounds, but never learn that they had ended. - Two new events: On music finished with the fields Song and Pattern and the input playback, and On sound finished with the field Sound and the input voice. Both give out what ended and stopped. - Two new data nodes, Music playing and Sound playing, ask whether something is still heard. - Over means nothing is heard any more: no tail of the effects, and a fade-out has run down. - stopped is on for Stop song, pattern or sound, when the behavior that owns it ends and on a scene change. For a sound also when a newer voice needs its place or the file does not load. - Only what the Play nodes of this run started is heard, across scene changes too. Previews in the tabs, compositions and notes of instruments do not count. - Switch song ends nothing. The number goes on, and the end is told under the song heard last. - Playbacks and the SoundLibrary tell each end once to a new PlayedEnds per run. The AudioSwitch passes them on from both sinks. Found and fixed: a pattern whose last bar ends in silence counted as done up to one planning window before its end. In e2e 65 the next pattern started after 1.962 s instead of 2 s. Scheduler.done now also wants the playhead to have reached the end. Cleaning up done playbacks therefore comes a few tenths of a second later. One test that expected the early end is adjusted. Tests: - Unit: 23 new (played-ends 12, sound-library 5, node catalog 5, audio-switch 1), all green. - Counter-probes: 19 bends, all red. One was green at first for want of a case, which is added now. - e2e 65 on atx: ALL PASSED, 78 checks. New 65k6: the event came once with stopped off, and the second pattern started 2.051 s after the stinger. Stop song gave exactly one end with stopped on, and the switch from 65k3 gave none. - Gate on atx: CHECK EXIT 0, 337 files, 5222 tests. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> |
||
|
|
b17a924157 |
Let a behavior play, pause and seek a video and hear it end (#410)
A game should be able to stop a video on a sprite, jump to a spot in it and start it again, and react when it has run out. Until now a video on a sprite either ran free on its own or followed a composition, and no behavior could touch it. - Five new nodes: Play video, Pause video and Seek video (time in s from the clip start), On video finished with a Video field, and the data node Video time with time, length and playing. - Play, Pause and Seek act on the owner when object is not linked. - On video finished with an empty field hears every video. A chosen video also hears its clips. - A new VideoSystem keeps a clock for every sprite with a video. It counts from the moment the sprite appears, as long as it is on. For a Driven sprite the clock is its Video time. A paused game holds all clocks. - A free sprite that one of the nodes touches gets the clock "steered" at run time. It then has its own player, and other sprites with the same clip play on. Pause of the game and sound go the existing Driven way. - On a Driven sprite and in the editor run the nodes do nothing and write a line to the log. - Until its own player has a frame, a steered sprite shows the frame of the shared player. Without that it would blink out on the first Pause video. - Play at the end of a clip without loop starts it from the start. The issue does not say, this is my choice. Found, not fixed: with a Driven sprite in the scene the run waits up to 3 s for its frame at the start. The world does not tick then, but the free videos already play. Their clocks lag behind the picture by that wait, so On video finished comes that much late. Tests: - Unit: 23 new (video-steer 16, node catalog 7), affected groups 4820/4820. - Counter-probes: 16 bends, all red. - e2e 66 on atx: ALL PASSED, 39 checks. New 66s: Pause at 0.15 s held its own player at 0.2 s, the picture stayed red for 1 s. Seek landed on 0.5 s exactly, green, held. Play showed green, blue, white, and white stayed at the end. On video finished came once. Without the clock "steered" all three 66s checks are red. - Gate on atx: CHECK EXIT 0, 336 files, 5199 tests. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> |
||
|
|
a6a41b6b69 |
Let a behavior follow the beat, bar and markers of the music (#338)
Stage 2 of #338. A game that syncs to its music has to know where the music is heard. This stage reads that on the audio clock and hands it to behaviors as events and as a position. - New event nodes On beat (playback, bar, beat, late), On bar (playback, bar, late) and On song marker (playback, marker, name, late). - New data node Song position with bar, beat, fraction, seconds and playing. - The nodes have the fields Song and Pattern. With neither picked, every playback counts. A linked playback input picks that one. Compositions do not count. - The Marker field offers the markers of all songs as Song / Marker, as a sound field offers its clips. - Everything follows what is heard: the audio clock minus the output latency. That holds for baked songs and for Play pattern too. - Only the last beat since the frame before fires, and only when it is at most half a beat late, 0.15 s at most. Bars and markers alike. - A copied song gets markers with ids of its own, so a Marker field never names two songs. - The audio clock is only asked while something plays. Asked in every frame, it made the AudioContext without a user gesture (#436). Tests: - beats 14 and music-events 6 new, 4 in song-play, 2 in song-markers, 2 catalog cases, the touched groups 756/756 - 16 counter-probes, all compile, all red - e2e 65 on atx: ALL PASSED, 71 checks, 65k2 new: 11 beats 1.1 to 2.4 and 2.1 again, none missing or twice, across the pause too. late 0.015 to 0.027 s. Counter-probe without the last position: red - gate on atx: CHECK EXIT 0, 334 files, 5121 tests Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> |
||
|
|
0334d2508d |
Place compositions in scenes and play them from behaviors (#417)
A composition can now sit in a scene like a container and play there. Its items become real objects while they run, so behaviors, colliders and events work on them as on any other object. - A composition is placeable with its own symbol, transform and render layer. The scene view shows its picture at frame 0. A click on that picture selects the placement, not a single item. - CompositionSystem spawns each item as an object under the placement when it begins, with the id <placement>~<item>. On start and the other events run. The object is destroyed when the item ends. - The top track lies in front no matter which item started first. World.arrange() orders the entity list and the scene objects. - Clips and driven videos follow the same rules as compositionAt(). Loop, restart, stop and the game pause work. - New nodes: Play composition (with restart), Stop composition and the event On composition finished. They were planned for step 4 but come now, because without autoplay nothing could play otherwise. - The editor run ignores Play composition and says so in the log. It writes into the saved project, and the items would stay behind. - contentId() moved to instance.ts. The animation system uses it for nested ids too. - Compositions get no "Sort with parent" for now. Tests: the gate passed with 301 files and 4643 tests, 18 more than step 1. 13 of them are in tests/core/composition-play.test.ts. The first gate run failed in event-order.test.ts, which counts the event nodes and now finds 19. Five counter-checks each turned exactly their test red. Two order tests stayed green without the fix at first and were rebuilt. e2e 68 is new and passed with 5 own checks. Its counter-check without arrange() failed as expected. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> |
||
|
|
ded0022903 |
Run behaviors on a fixed step with an On fixed update node
Adding up the frame's dt in On update makes anything that counts in steps depend on the frame rate. A pitch sweep sounds a little different on every run. On fixed update runs 60 times per second of game time with dt exactly 1/60, so the same graph gives the same result every time. - fixedSteps in src/core/time.ts is the one rule for the fixed step: spend the frame in steps of 1/60, keep the rest, catch up 8 steps at most after a hitch. - The physics now counts its steps with fixedSteps too. It behaves as before, and On fixed update runs exactly as often as the engine steps. - The steps run after On mouse wheel and before On update, each as a kind of its own with the usual Order setting. - Each step gets its own context, so a node inside that reads dt (Time, Move, Apply force) gets 1/60 rather than the frame. - A paused game has no steps, also for a behavior that runs while paused. - The engine still takes all of a frame's steps before the behaviors run. A force set in On fixed update acts from the next frame on. Tests: - fixed-update.test.ts (new): 5 tests. Step counting, uneven frames adding up to 60 steps a second, the hitch cap, two steps at 30 Hz before On update with dt 1/60 for the event and for Time, one step every other frame at 120 Hz, none while paused. - event-order, node-catalog, physics-system, game-pause: 430 tests together with the new file, all green. - Counter-check: with the frame's dt inside a step and without the pause guard both world tests fail. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> |
||
|
|
46c620ae3b |
Give a behavior more ways in and out, and hear it as an event (#294)
A behavior run by another one had a single flow port at its Start and at its End, so it could not branch for its caller. And it could not be used as an event: a call needs a pulse at its flow input, and the events of a called graph never fire. An input like "Confirm" (Space or Enter) had to be built again in every graph. - A declared port of a Start or an End node can be of the kind Flow. It sits above the values and shares their names, exec stays reserved. Only these two nodes declare one, a struct does not. - Run behavior shows a flow port of the Start as a further flow input. A call arriving through it leaves the Start through the output of that name and not through exec. - Run behavior shows a flow port of the End as a further flow output. The call goes on through the one the End was reached by last, and then through exec. exec fires always, as before. - On behavior is a new event node without a flow input. The behavior it names runs at the node for as long as the behavior around it runs, with all of its own events and one set of variables per node. - Its outputs are those of the End. It fires once the inner pulse is through, by the output the End was reached by last, exec only for End.exec. A pulse that never reaches the End is not seen. - The value ports of the Start are its inputs, read anew for each inner pulse. The Start itself never fires there. - It nests to any depth. Under a Run behavior it stays silent. A behavior hearing itself, however far round, is not started and the node says "A behavior cannot listen to itself". - The palette offers every other behavior with an End once more as "On <name>". A node naming one without End says so. - An On node removed while the game runs ends its behavior with On disable and On destroy. The sounds of the entity end only with the behavior placed on it. - Renaming and deleting a declared port follows the edges at On behavior nodes as it does at Run behavior nodes. - The flow outputs of the Start of a behavior placed on an object never fire, like its exec. - The engine prompt of the benchmark names flow ports and On behavior. Tests: - Gate on melektaus-atx right before this commit: 215 files, 3319 tests (3278 + 41), exit 0. - e2e 19 on melektaus-atx: 39 checks (+4), all pass. e2e 1-6,17-24,26,36,51: 628 checks, all pass. - 19 unit tests in flow-ports.test.ts, 19 in on-behavior.test.ts on a real world, the rest in the node catalog. - Four new e2e checks in module 19: a flow port declared by mouse at the End, On Confirm in the graph, the call leaving through the further output while playing, Enter and Space on a real keyboard. - 19 unit counter-probes all fail their tests. One did not at first (a removed node kept its instance), a test was added. Two browser counter-probes fail their checks. - One screenshot looked at: On Confirm with exec and pressed, the second flow pin at the calling node. - The e2e sum of 1680 is counted (1676 + 4), the full suite and the smokes did not run. - Not seen in the browser: flow inputs at the Start, nesting, the ring, values through On behavior, the palette entry. No test holds that the sounds of the entity go on when a heard behavior ends. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> |
||
|
|
5fbc6eb088 |
Set the order in which event nodes run across behaviors (#264)
Which of two events ran first depended on hidden lists: the order of the behavior instances and the order in which nodes were created. A graph had no way to say that one On update must run before another, and an On update of one behavior could run before a key event of another. - A frame now runs event kind by event kind over all behaviors: On disable and On enable, key down, key up, key held, timer, collision enter, stay and exit, animation finished, click, mouse wheel and at last On update. - All 17 event nodes have a field Order, a whole number, default 0, negative allowed. Within one kind a lower Order runs earlier, no matter which behavior holds the node. - On a tie the current hierarchy decides from top to bottom, then the order in which the nodes were created. The old rule that a behavior enabled later goes to the end is gone. - The node shows Order: 5 only when the value is not 0, so existing graphs look the same. - The rule lives as pure functions in core/graph/eventOrder.ts. The interpreter can now fire a single event node. Changes in existing projects: - An object destroyed in a frame gets no further event in that frame. On disable and On destroy still come at the end of the frame. - New instances get all their On start first, then all On enable. Teardown runs all On disable first, then all On destroy. - State events follow right after the event kind that caused them. - Four unit tests had fixed the old order and are adjusted: two in behavior-events, one in physics-system, one in key-repeat. Tests: - ./check.sh: 191 files, 2784 tests, CHECK EXIT 0. - GM_STEPS=1-6: ALL PASSED, 280 checks. - Full e2e run (local): ALL PASSED, 1551 checks, measured. - tests/core/event-order.test.ts: 11 tests for the rule, the field on all 17 nodes, order across behaviors, key before update, two nodes in one graph, On start, hierarchy after late enable and reorder at runtime, state events, save and load. - e2e 6z-viii, 2 checks with real mouse and keyboard: Order -1 set in the inspector shows on the node, and a run logs B, A although B is lower in the hierarchy. - Counter-checks: 5 in unit tests and 1 in the browser, all fail as expected. The originals were restored and checked with cmp. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> |