Fire off an event once from changes of two booleans

Hello there. Currently, I am trying to make a script where the moment a change from these booleans is detected (IsLightsOn? and IsDoorOpened?), it would fire off a custom event once where a sound queue would play four times with a 2 second pause between each play, all coming from an Audio Component that I already have prepared. Right now, I currently have the sound play script be dependent on the blueprint’s Event Tick, but when I tested the audio playing with just the Play Sound at Location and Report Noise Event node, it would seem to fire off at every frame.

Is there anyway I can do to try and fix this problem? I’m a bit of a beginner with blueprints, so i don’t really know how to implement the solution.




These are the current screenshots for the Event Tick script that I have made for this blueprint. There are four routes for this Event Tick to regularly execute, based on the states the two booleans have.

Hi,
Delays inside the tick doesn’t make much sense because, as you noticed, it triggers everyframe. By the rule of thumb you dont ever need a delay inside the tick function. You could use DoOnce or other helpers, but I would suggest you a different approach that will help you maintain clarity of the code.

Create a new boolean and name it something like “SoundSequenceTriggered”.
Create a new custom event named “SoundSequence” or something, and move your sound-playing sequence there. At the very beginning tough, set SoundSequenceTriggered boolean to true.
Then, use a tick to detect if the condition is changed (isDoorOpenend?, isLightsOn?), then trigger your new custom event but only, if the SoundSequenceTriggered boolean is false.
Also make sure SoundSequenceTriggered default value is false.

at the end it should look something like this:

Let me know if this works.

By setting the SoundSequenceTriggered boolean to true from the beginning, do you mean by setting the default value to True or adding a Set Boolean node from the beginning of the event tick? Likely before it splits off into 4 separate states?

EDIT: For now, I’ve decided to put the SoundSequenceTriggered (named AlarmSequence for my blueprint) boolean check within the end of three of the four states that my Event Tick would be in, based off of the two deciding booleans’ status. It doesn’t really seem like the scripting would reach the AlarmSequence event that I made based off of your example.


I meant this part: “At the very beginning tough, set SoundSequenceTriggered boolean to true.” in the context of making a new custom event. So at the start of your game it should be false (becuase the alarm didnt go off yet) but as soon as its triggered - set it to true.

So by the start of my game, you mean place it on the Event BeginPlay node?

I’ve tried that and it only seems to fire once when switching a state. Which in the question’s case, yes, that technically fulfills what I asked. But i was more talking about the SoundSequence event firing off once everytime the event tick’s ‘state’ changes.

Like for example, if I were to put it in an interactable sequence:
→ BP goes from state 1 (bottom) (False/False) to state 2 (lower middle) (False/True)
→ SoundQueue fires once
→ BP goes from state 2 (lower middle) (False/True) to state 4 (top) (True/True)
→ SoundQueue fires again, but only once
→ BP goes from state 4 (True/True) back to state 1 (False/False)
→ SoundQueue fires again

Sorry if I didn’t make that clear.

Ok, I see.

So by the start of my game, you mean place it on the Event BeginPlay node?

I would set a default variable value in the details, like so:
image

Before I answer the second part, what would be a desired effect if the alarm would be called again before the one before was ended? (false/false state → alarm goes off, before it ends the state changes to false/true). Should it break the currently playing alarm and start new one, should they play both simoultanesly, or should the second one be ignored or maybe something else?

The desired effect would break the currently playing alarm and start a new one. That’s what I need it to do, and why I have a SoundComponent whose sound would be set depending on the event tick state the BP is in.

I’ve also set the default value for the boolean as false, like you suggested.

In that case, boolean won’t be enough because it can only store two different states (on/off), so you should probably add an additional two integer variables which will store an information about latest and current state triggered.
You can set it to 1/2/3/4 in different states, then instead of the branch with SoundSequenceTriggered boolean you would check if the current state is different then last triggered state. Remember to set the current and latest state to 0 as the default in details panel.
like so:

explanation:
you are setting your last triggered state to some value (ie 1, if its true/true), then you check if its the same as the currently playing. at the begining current value will be 0, so it will be True and the sequene will be played, however after statritng the sequence, it will set the current value to 1 as well, so next tick, it won’t fire the alarm sequence again (becuase latest state == 1 and current state == 1). however, if it goes to different state (like true/false) then the last state will be changed to 2, so it will be true again (2 != 1) and alarm sequence will be triggered again.

Just wanted to add, this is getting more and more convuluted, so I would shrink the graph to smaller chunks and functions, but this won’t affect the functionality, only clarity, so I don’t want to bother you with that atm. but If you’d like to know how could we make it more readable and clean we can do it after it’s working as you want it to.

I gave your solution a try. But it doesn’t really seem like the LastState interger is doing anything to help differentiate between the two different states. At most, it just reaches the final branch then stops there, due to the two compared CurrentState intergers being the same once compared with each other. Meanwhile, the LastState integer just stays as 0.


Also, I would love to have you help me in terms of making this code more readable. Because it’s starting to feel way too convoluted for me to handle.

Oh you’re right of course, that’s my bad. I’ve added Current State != Current State and it will obviously always be false, it was supposed to be like this:


Replace these sets with Last State. Current State should be overwritten only if the alarm goes off.

Sure, we’ll try to make it nice after we get it working. I don’t won’t to start refactoring until we are on the same page with the functionality.

Capture11

Okay! This is getting very close to what I intend in terms of functionality. All that’s needed now s to make sure too much of it isn’t being called upon at a time. Those 4 prints each of Cue 4 and Cue 2 should best be filtered into simply 1 print each of Cue 4 and Cue 2 at most.

Would that end up convoluting the scripting further, though?

Can it be you have 4 actors with the same script? It would mean every blueprint is correctly calling the cue once, but it ends up calling 4 different instances of the event.

For debbuging purposes you can add to your Print String an actor name like so:

This way we’ll be sure it’s called from one or more actors

Oh. Yeah. Now that I think about it, I do have 4 instances/actors with the same script. Nevermind then.

Okay! If thats the case, then I feel like the script is good enough in terms of function.

Now how can I make it so it’s less convoluted to read? Because I’ll have to document it later down the line.

If you have 4 instances that should always behave similarly, you should probably make an AlarmManager blueprint which handles the “going on and off” part, but doesn’t have a light. Instead, a new blueprint (like AlarmLight) would have a light. It wouldn’t check any of the conditions, becuase the Alarm Manager would tell it when to go loud.
But I won’t mess with your setup more than necessery, you’ll decide if you need that.

As for the clarity - first thing is to find everything that looks more or less the same but is called in different places (like our Set Last State node).
In case of my small blueprint I’ve sent you, it would be this part:


because its basically the same nodes but with only one parameter changing (the actual value of Last State)
You can grab these nodes, click Right Mouse Button and click Collapse To Function

(be mindfull what you are selecting)
Functions typically start with a verb (because it DOES something), so lets name it something like TriggerAlarmSequenceIfNewState.
The name is up to you (I’m not sure mine is good), but the general idea is: the shorter the better, but long names are not bad as long as they are not too convuluted and are descriptive. In the future you want to read your code node by node and understand what is it doing without the need of going inside the functions.
Now, create a new input inside a function. You can do it easily with dragging the pin from Set node into the top of the start of the function node, like so:

Now you can change your other branches into your new function, but change the Last State input in every branch, like this:

This already looks much better in my opinion, and more importantly, if you would need to add some more conditions or other stuff to do, you can now to do it inside this function instead of copy-pasting it 4 times.

Now, I know you have more functionality, maybe you can try to do similar stuff yourself, for example with your light color and sound. You can create a new function, like SetAlarmParameters, and set light color and sound to be inputs (similar to Last State in my example).

Let me know if it’s clear! ( I might be out for couple of hours, but will be back later)


Oh my god, this already looks so much better compared to before. Thank you SO MUCH. I didn’t even know you could even grab parts of the nodes and collapse them to a particular function, thus making the main event graph much simpler. I’ll make sure to keep that in mind for the rest of my code, just in case.

As for the AlarmManager blueprint, it might actually come in handy for cases like this, since these blueprints are supposed to be used as multiple lights upon a ceiling. Maybe you could try to show me how I could do it and see if I can try to replicate it without much trouble.

Create a Function.
Every time one of the values changes call this function.
Function compares the two values. If they match the result you want call an event.
Have the Custom Event set a state noting it has been triggered. Check that state prior to executing the rest of the logic…play sound etc.

1 Like

This topic was automatically closed 30 days after the last reply. New replies are no longer allowed.