Thunder and Lightning Effect

OurJud
18 Dec 2016, 20:37

NB: This code is only relevant to those using a black or dark background in their game. In this example the background is set to #111111 (one shade up from black)

You will need: A thunder clap mp3 file.

For this tutorial we will use the room name cellar but of course you will need to substitute the room name for your own.


Step 1: Create a room and call it thunderlightning
Step 2: In the room, switch to Run script and insert the following script

HideCommandBar
SetBackgroundColour ("White")
SetTimeout (2) {
  play sound ("thunder.mp3", false, false)
  SetTimeout (2) {
    SetBackgroundColour ("#111111")
    ShowCommandBar
    MoveObject (player, cellar)
  }
}

(The HideCommandBar / ShowCommandBar rule only applies to those who hide it for their game)

Step 3: In the room where you want the thunder and lightning, use the following script:

msg ("You're in the cellar bla bla bla bla bla")
SetTimeout (3) {
  MoveObject (player, thunderlightning)
}

Of course the first script could be included within the room itself, but this just feel cleaner and less fussy.

This is my first tutorial. If anyone more experienced can see any potential dangers or better ways to do this, please feel free to amend.


hegemonkhan
19 Dec 2016, 20:31

awesome, nicely done OurJud, another library for quest users, and media one for weather/thunder/lightning effect!


OurJud
21 Dec 2016, 15:21

Thanks :)


Dcoder
21 Dec 2016, 23:26

Know of a way to create a flickering effect (to simulate lightning)?


OurJud
22 Dec 2016, 01:57

Probably JavaScript because it can handle milliseconds. Quest's wait can only handle full seconds, so even though you could flick between the two background colours the quickest you can go is one second, so it wouldn't really be a flicker.

The Pixie could do a much better lightning effect - although I'm not volunteering her/him.


Dcoder
22 Dec 2016, 02:28

Thanks


The Pixie
22 Dec 2016, 12:27

Flicker code with JavaScript. Add this attribute to your game object in full code view (f9) (so only with the off-line editor unfortunately):

    <js><![CDATA[
    <script>
      events = [0];
      onColour = 'white';
      offColour = 'black';
      state = false;
      startTime = 0;
      active = null;
      
      function setTimer(col, s) {
        if (active) return;
        
        offColour = $('body').css('background-color');
        events = [0];
        onColour = col;
        d = new Date();
        startTime = d.getTime();
        active = setInterval(myTimer, 10);
        ary = s.split(';');
        count = 0;
        for (i = 0; i < ary.length; i++) {
          count += parseInt(ary[i]);
          events.push(count);
        }
        counter = events.length;
      }

      function myTimer() {
        timeNow = new Date();
        lapsed = timeNow.getTime() - startTime;
        for (var i = 0; i < events.length; i++) { 
          if (events[i] < lapsed) {
            if (state) {
              $('body').css('background-color', offColour);
            } else {
              $('body').css('background-color', onColour);
            }
            state = !state;
            events[i] = 9999999999;
            counter--;
          }
        }
        if (counter < 1) {
          clearInterval(active);
          active = null;
        }
      }      
    </script>
]]></js>

In the game start script, add this:

      JS.addText (game.js)

Now you can have flick effects, by doing something like this:

JS.eval ("setTimer('white', '50;20;50');")

Obviously "white" is the colour you want it to change to. The other three numbers are the time intervals in milliseconds; you can have as many as you like, but best to have an odd number.

It changes the body element, by the way. If you try to start a sequence when one is already running, it will get ignored.


OurJud
22 Dec 2016, 22:44

Can't get this to work, TP. I know that must come as a massive shock to everyone, but there you go.

I've got my test game background set to #111 (almost black.

I then opened my game code and pasted your main block of JS just before the </start> and </game> tags.

Then I went to game in the UI >> script >> Start script, and added the call script.

Finally I created a room with the command test and have it run a script, into which I added your JS.eval line.

When I run the game and type test nothing happens.


The Pixie
22 Dec 2016, 23:01

It needs to go after and before tags.


OurJud
22 Dec 2016, 23:11

So I put the code in twice?

After and before what tags?

I added the code before the </game> and </start> tags, and also after </start> but before </game> (won't let me put it after </game>) but it still doesn't work.

Sorry, I must sound like a troll at times.


The Pixie
23 Dec 2016, 07:52

No, it just goes in once. Look for the </game>and insert it just before that.


OurJud
23 Dec 2016, 17:05

Yes, that's what I did the first time. Just checked it all again and everything is per your instructions, but it still doesn't trigger.


OurJud
23 Dec 2016, 21:53

Have you tested this, TP, or are you just relying on your coding knowledge?


The Pixie
24 Dec 2016, 12:51

I did test it, but I now realise there was an error (offColor needs to be set inside the function). I have updated the code.

Here is a complete game; typer RED, YELLOW or WHITE to see the flash.

<!--Saved by Quest 5.6.6108.15891-->
<asl version="550">
  <include ref="English.aslx" />
  <include ref="Core.aslx" />
  <game name="flash-effect">
    <gameid>0b330506-44ce-4b60-9e4a-6c9c0b46a180</gameid>
    <version>1.0</version>
    <firstpublished>2016</firstpublished>
    <js><![CDATA[
    <script>
      events = [0];
      onColour = 'black';
      offColour = 'white';
      state = false;
      startTime = 0;
      active = null;
      
      function setTimer(col, s) {
        if (active) return;
        
        offColour = $('body').css('background-color');
        events = [0];
        onColour = col;
        d = new Date();
        startTime = d.getTime();
        active = setInterval(myTimer, 10);
        ary = s.split(';');
        count = 0;
        for (i = 0; i < ary.length; i++) {
          count += parseInt(ary[i]);
          events.push(count);
        }
        counter = events.length;
      }

      function myTimer() {
        timeNow = new Date();
        lapsed = timeNow.getTime() - startTime;
        for (var i = 0; i < events.length; i++) { 
          if (events[i] < lapsed) {
            if (state) {
              $('body').css('background-color', offColour);
            } else {
              $('body').css('background-color', onColour);
            }
            state = !state;
            events[i] = 9999999999;
            counter--;
          }
        }
        if (counter < 1) {
          clearInterval(active);
          active = null;
        }
      }
    </script>
    ]]></js>
    <start type="script">
      JS.addText (game.js)
      JS.eval ("$('body').css('background-color', 'black');")
      JS.eval ("$('#gamePanesRunning').css('background-color', 'transparent');")
      JS.eval ("$('#gamePanes').css('background-color', 'transparent');")
    </start>
    <defaultbackground>Black</defaultbackground>
    <defaultforeground>LightGray</defaultforeground>
  </game>
  <object name="room">
    <inherit name="editor_room" />
    <object name="player">
      <inherit name="editor_object" />
      <inherit name="editor_player" />
    </object>
  </object>
  <command>
    <script>
      JS.eval ("setTimer('red', '50;20;50');")
    </script>
    <pattern>red</pattern>
  </command>
  <command>
    <script>
      JS.eval ("setTimer('yellow', '150;80;150');")
    </script>
    <pattern>yellow</pattern>
  </command>
  <command>
    <pattern>white</pattern>
    <script>
      JS.eval ("setTimer('white', '100;100;100;100;100;100;100');")
    </script>
  </command>
</asl>

OurJud
24 Dec 2016, 14:04

Man that's good! I so wish I'd asked for this before releasing my game, instead of trying to do it myself.

I love how you can not only vary the speed of the flashes, but increase the overall duration by just adding more figures to the command script.

I take it when I use this in my next game (and I will) I just need the JS code from your demo?

I still couldn't get your original to work.


OurJud
24 Dec 2016, 14:13

I tried adding this to an existing game and couldn't trigger it, so assumed it was something I'd done with the settings. For that reason I created a brand new test game and STILL couldn't get it to work.

Then I realised it's because I'm using a custom width, which results in the affected background being pushed off either side of the screen. And therein lies the problem. Your demo only affects the background BEHIND the pane / window in which the game is set.

Is it not possible to add the flash to the actual gameplay area of the screen as well?


OurJud
24 Dec 2016, 18:31

Can't quite believe I worked this out myself, but...

Set your game with a custom width of 1300* (this ensure the 'game window' takes up the whole width of the browser window)

And then in TP's JS code, change the three instances of body to #gameBorder (the forth instance of body can be ignored or even removed completely, as it's setting the background which is no longer visible)

*add left and right margins of about 250 while setting the custom width, otherwise the words will stretch off screen too.


The Pixie
24 Dec 2016, 19:32

You have it set up a little odd so the gameBorder div hides the body element. Replace "body" with "#gameBorder" three times and it should work (and have an odd number of intervals).


OurJud
24 Dec 2016, 21:47

o0 I think you missed my last post, above yours, and my revised thread with my findings, but thanks all the same.

I did try to target both the body and #gameBorder elements so that the custom width wasn't necessary, but couldn't figure out how to do it.

I tried:

offColour = $('body', '#gameBorder').css('background-color');

But it didn't work.


The Pixie
24 Dec 2016, 22:50

I have to admit, having looked at your code, I do not get why it is not working. I will look some more, but it is late on Christmas Eve and I have had a bit to drink, so may not be soon...


OurJud
24 Dec 2016, 22:59

:D I'd say you've had TOO much to drink. I got it working four posts ago, at around 6:30 this evening.

Or are you now specifically referring to why this isn't working?

offColour = $('body', '#gameBorder').css('background-color');

RicaIii
10 Jan 2017, 17:05

Hi..i am a new user here. In my case i have the switch, which will obviously turn on the lights. If you create object switch and tick the switchable option under features, you will have an option to run a script when object is turned on. In this script, I add a message to tell the player the light switch is flipped and I also make each object in the room visible. Then, in the turn off script I just do the opposite.


OurJud
10 Jan 2017, 19:40

This thread concerns a lightning effect, Ricalii, as in thunder and lightning, not lighting in general.


Davewoody55
15 Jan 2017, 14:43

This is just genius! Hope it's okay if i "steal" this code for use in my own game. It's perfect for when my wizard appears in the room :)


OurJud
15 Jan 2017, 17:39

Go ahead, that's what TP created it for. Combine it with a clap of thunder sound file and it looks incredible (remember to have a slight delay before the thunder clap, though - light traveling faster than sound etc) :)