It must be something I'm doing wrong, although I don't know what. [SOLVED].

Started by RetroJay, Fri 23/05/2014 03:53:58

Previous topic - Next topic

RetroJay

Hi Peeps.

I have a problem, anyone who knows me would agree.(laugh)
This, however, is a Scripting problem.

In one room I have a number of creatures, on different levels, that walk from left to right and back again, repeatedly.
If any one of these creatures touches the 'Player Character' then a point is deducted from a 'Meter' until the meter is empty.
This is where the player runs away screaming, in theory.

I have created a 'Sanity Monitor' using a GUI and a 'Button'.
The buttons image is the meter and is set to 'Clip Image'

I have created a 'Global Variable' called 'number_of_hearts' an INT set to 218.
In 'Global Script ash' I have...
Code: ags
import function UpdateHeartGUI(int change);

At the very top of 'Global Script asc' I have...
Code: ags
function UpdateHeartGUI(int change) {
number_of_hearts += change;
if (number_of_hearts < 0) number_of_hearts = 0;
if (number_of_hearts > 218) number_of_hearts = 218;
btnHearts.Width = number_of_hearts * 1;
return number_of_hearts;
}

In my 'Room Script' I have...
Code: ags
// room script file

function room_FirstLoad() {
  aWelcome.Play();
}

function room_Load() { 
  // This disables MOUSE controls.
  //------------------------------
  mouse.Visible = false;
  cDan.FaceLocation(0, 360);
  aMystery.Play();
}

function room_RepExec() {
  // SCARE SCRIPT.
  //---------------------------------------------------
  // If the GHOSTS or other CREATURES collide with EGO,
  // they SCARE him.
  
  if (AreThingsOverlapping(ZOMB, DAN)) {
    aScream2.Play();
    if (UpdateHeartGUI(-2) == 0){
      QuitGame(0);
    }
  }
  
  if (AreThingsOverlapping(ZOMB2, DAN)) {
    aScream2.Play();
    if (UpdateHeartGUI(-2) == 0){
      QuitGame(0);
    }
  }
  
  if (AreThingsOverlapping(ZOMB3, DAN)) {
    aScream2.Play();
    if (UpdateHeartGUI(-2) == 0){
      QuitGame(0);
    }
  }
  
  if (AreThingsOverlapping(GHOST, DAN)) {
    aGhostly1.Play();
    if (UpdateHeartGUI(-1) == 0){
      QuitGame(0);
    }
  }
  
  if (AreThingsOverlapping(GHOST2, DAN)) {
    aGhostly1.Play();
    if (UpdateHeartGUI(-1) == 0){
      QuitGame(0);
    }
  }
  // END OF SCARE SCRIPT.
  //---------------------
  
  // This section makes GHOSTS and other CREATURES move.
  //----------------------------------------------------
  if (!cZomb.Moving) {
    if (cZomb.x < 100) {
      // If the Ghost is on the left hand side of the screen,
      // start it moving towards the right.
      cZomb.Walk(600, cZomb.y, eNoBlock, eAnywhere);
      }
      else {
        // Otherwise, move it towards the left
        cZomb.Walk(34, cZomb.y, eNoBlock, eAnywhere);
      }
  }
  
  if (!cZomb2.Moving) {
    if (cZomb2.x < 100) {
      // If the Ghost is on the left hand side of the screen,
      // start it moving towards the right.
      cZomb2.Walk(605, cZomb2.y, eNoBlock, eAnywhere);
      }
      else {
        // Otherwise, move it towards the left.
        cZomb2.Walk(34, cZomb2.y, eNoBlock, eAnywhere);
      }
  }
  
  if (!cZomb3.Moving) {
    if (cZomb3.x < 100) {
      // If the Ghost is on the left hand side of the screen,
      // start it moving towards the right.
      cZomb3.Walk(600, cZomb3.y, eNoBlock, eAnywhere);
      }
      else {
        // Otherwise, move it towards the left.
        cZomb3.Walk(34, cZomb3.y, eNoBlock, eAnywhere);
      }
  }
  
  if (!cGhost.Moving) {
    if (cGhost.x < 100) {
      // If the Ghost is on the left hand side of the screen,
      // start it moving towards the right.
      cGhost.Walk(582, cGhost.y, eNoBlock, eAnywhere);
      }
      else {
        // Otherwise, move it towards the left
        cGhost.Walk(34, cGhost.y, eNoBlock, eAnywhere);
      }
  }
  
  if (!cGhost2.Moving) {
    if (cGhost2.x < 100) {
      // If the Ghost is on the left hand side of the screen,
      // start it moving towards the right.
      cGhost2.Walk(600, cGhost2.y, eNoBlock, eAnywhere);
      }
      else {
        // Otherwise, move it towards the left.
        cGhost2.Walk(34, cGhost2.y, eNoBlock, eAnywhere);
      }
  }
}
  // END OF GHOST AND CREATURE MOVEMENTS SCRIPT.
  //--------------------------------------------


This works just fine... However.
The audio files that I have within my room script play over and over again.
Obviously this is because they are within the 'Repeatedly Execute' section.
I don't know how to cure this.

I have tried many ways of getting the sound files to play outside of 'Repeatedly Execute'.
My game Compiles but no sound is played when the character collides with an NPC.

If anyone can see my error or even a better way to do what I am trying to do then please help.
I have been trying to do this for the past week now, without help, and have got nowhere.

Yours.
Jay.   

Ghost

The problem is in the "IsThingsOverlapping". As long as they are, the sound is started over and over again.

The most basic solution involves the new audio system. I suggest you create an audio channel, and test against it using IsSoundPlaying. That way, you can play the sound only if its channel is currently not playing.

This can surely be fine-tuned even more but the basic idea is sound.

RetroJay

Hi Ghost.

Thanks.
I will try that, if I can work out what you mean, Tomorrow or Today, as it is now.
Please forgive me. My Brain hurts.???

When I'm firing on all eight cylinders I will let you know how things went.

But the rest of what I have done looks ok, Yes?
Or can I accomplish what I am after a better way?

Yours.
Jay.

Slasher

Hi,

Do you mean:

If the player gets too close to a creature a point is deducted, a sound plays and he runs away?

I had a similar thing and I did this:

1: I used the PPCollision Module for if player collides with something.
2; Made a global bool (in global pane) and set to false and add it to your PPCollision script (in room rep exec).
3: When collision happens set bool to true and use if bool is true
4: Add events after touching.
5: set bool back to false
6: If sound does not stop make it stop after running away with the Stop() command.

Something along those lines is an alternative method.

Edit:

I also have the dreaded Zombies, copycat (laugh)

I used AddWaypoint (they ignore Walkable areas though) to have Zombies patrol back and forth:

Code: ags
function repeatedly_execute_always()
{
  if (cZombie1.walking == false && cZombie1.View==111){
  cZombie1.AddWaypoint(488, 1892); //First place to walk to x y
  cZombie1.AddWaypoint(600, 1892); //Second place to walk to x y
 //This will keep repeating back and forth non blocking with game.
}
}


I don't use if characters collide in my game but if I did it may be like this:

Code: ags

function room_RepExec()
{
  if (PPColliding.CWithC(cCharles, cZombie1)){ // The 2 characters that if collide.
  aScream.Play(); // Sound to play whilst running away
  cCharles.SayBackground("Aghhhhhhhhhhhhhhhhhhhhhhh"); // SayBackground so non blocking.
  cCharles.Walk(cCharles.x-200, cCharles.y, eBlock, eWalkableAreas); Runs away to x y position blocking.
  cCharles.SayBackground(""); // Deletes the previous SayBackground.
  aScream.Stop(); // Stops sound if required.
  // Of course you may also subtract a point after collision.
}  
}


Anyhow, this may help.....




RetroJay

Hi Ghost.

Sorry, but after hours of tinkering with Audio Channels the sounds still plays over and over.
Although it must be said that I don't really understand what you mean. :-[

Thanks for your help, Though.

Yours.
Jay.


RetroJay

Hi Slasher.

After looking at the Script you showed, it got me thinking.
Messing around with your script I finally ended up with this...
Code: ags
function room_RepExec() {
  
  // SCARE SCRIPT.
  //---------------------------------------------------
  // If the GHOSTS or other CREATURES collide with EGO,
  // they SCARE him.
  if (AreThingsOverlapping(ZOMB, DAN)) {
    UpdateHeartGUI(-40);
    aScream.Play();
    cDan.StopMoving();
    Wait(40);
    aScream.Stop();
    
    if (UpdateHeartGUI(-0) == 0){
      QuitGame(0); // More stuff happens before Quit
    }
  }

  if (AreThingsOverlapping(ZOMB2, DAN)) {
    UpdateHeartGUI(-40);
    aScream.Play();
    cDan.StopMoving();
    Wait(40);
    aScream.Stop();
    
    if (UpdateHeartGUI(-0) == 0){
      QuitGame(0); // More stuff happens before Quit
    }
  }
  
  if (AreThingsOverlapping(ZOMB3, DAN)) {
    UpdateHeartGUI(-40);
    aScream.Play();
    cDan.StopMoving();
    Wait(40);
    aScream.Stop();
    
    if (UpdateHeartGUI(-0) == 0){
      QuitGame(0); // More stuff happens before Quit
    }
  }
  
  if (AreThingsOverlapping(GHOST, DAN)) {
    UpdateHeartGUI(-20);
    aGhostly.Play();
    cDan.StopMoving();
    Wait(40);
    aScream.Stop();
    
    if (UpdateHeartGUI(-0) == 0){
      QuitGame(0); // More stuff happens before Quit
    }
  }
  
  if (AreThingsOverlapping(GHOST2, DAN)) {
    UpdateHeartGUI(-20);
    aGhostly.Play();
    cDan.StopMoving();
    Wait(40);
    aScream.Stop();
    
    if (UpdateHeartGUI(-0) == 0){
      QuitGame(0); // More stuff happens before Quit
    }
  }
}
  // END OF SCARE SCRIPT.
  //---------------------

function repeatedly_execute_always() {
    // This section makes GHOSTS and other CREATURES move.
  //----------------------------------------------------
  if (!cZomb.Moving) {
    if (cZomb.x < 100) {
      // If the Ghost is on the left hand side of the screen,
      // start it moving towards the right.
      cZomb.Walk(600, cZomb.y, eNoBlock, eAnywhere);
      }
      else {
        // Otherwise, move it towards the left
        cZomb.Walk(34, cZomb.y, eNoBlock, eAnywhere);
      }
  }
  
  if (!cZomb2.Moving) {
    if (cZomb2.x < 100) {
      // If the Ghost is on the left hand side of the screen,
      // start it moving towards the right.
      cZomb2.Walk(605, cZomb2.y, eNoBlock, eAnywhere);
      }
      else {
        // Otherwise, move it towards the left.
        cZomb2.Walk(34, cZomb2.y, eNoBlock, eAnywhere);
      }
  }
  
  if (!cZomb3.Moving) {
    if (cZomb3.x < 100) {
      // If the Ghost is on the left hand side of the screen,
      // start it moving towards the right.
      cZomb3.Walk(600, cZomb3.y, eNoBlock, eAnywhere);
      }
      else {
        // Otherwise, move it towards the left.
        cZomb3.Walk(34, cZomb3.y, eNoBlock, eAnywhere);
      }
  }
  
  if (!cGhost.Moving) {
    if (cGhost.x < 100) {
      // If the Ghost is on the left hand side of the screen,
      // start it moving towards the right.
      cGhost.Walk(582, cGhost.y, eNoBlock, eAnywhere);
      }
      else {
        // Otherwise, move it towards the left
        cGhost.Walk(34, cGhost.y, eNoBlock, eAnywhere);
      }
  }
  
  if (!cGhost2.Moving) {
    if (cGhost2.x < 100) {
      // If the Ghost is on the left hand side of the screen,
      // start it moving towards the right.
      cGhost2.Walk(600, cGhost2.y, eNoBlock, eAnywhere);
      }
      else {
        // Otherwise, move it towards the left.
        cGhost2.Walk(34, cGhost2.y, eNoBlock, eAnywhere);
      }
  }
}
  // END OF GHOST AND CREATURE MOVEMENTS SCRIPT.
  //--------------------------------------------


Now when a Ghost or other such nasty beastie collides with character he stops and screams, Only once, the meter goes down and then you continue along your merry way.
This may not be the prettiest way or even the correct way but it seems to work, to a fashion.

If anyone knows of a better way then please enlighten me.:)

Thank you Slasher for giving me the Idea, much appreciated.

Yours.
Jay.

Ghost

I don't know any details about your game, but the multiple Wait(40) commands sound like a bad idea. You're blocking the whole game for a second there, and that can seriously upset user input if a collision repeats or if there are many characters on screen. I think nobody would like to play a sequence that relies on "speedy control" and have the control taken away regularly. Imagine playing Super Mario, and each time a coin jingle play, the game freezes. ;)

__
A very hacky idea. Use an attack animation. Start playing that once a collision happens. Assign the attack sound to a frame in the animation (in the view editor). You will still need to take care that the animation is not started over and over again, but you avoid the whole sound issue.

RetroJay

Hi Ghost.

Believe me, I'm not happy about the whole thing.;)
This was only supposed to be a simple game to take my mind off of my main project.
And now it's developed into a large pain in my butt.(laugh)

Mind you. That Idea you have had, regarding the attack sound on a frame, might just work.
I will continue tinkering and let you know how it goes.

Thank you for your help.
Jay. 

Khris

There are two ways to approach this:

1. only play a sound when there's currently no sound playing (will keep playing the sound during overlap, but in sequence)
2. only play the next sound after the player has not overlapped another character in the meantime (will only play the sound once)


Code: ags
bool CheckEnemy(int id, int hploss) {
  bool r = AreThingsOverlapping(id, DAN);
  if (r && UpdateHeartGUI(hploss) == 0) QuitGame(0);
  return r;
}

bool was_colliding;
AudioClip *collision_sound;
AudioChannel *collision;

function room_RepExec() {

  bool is_colliding = false;

  if (CheckEnemy(ZOMB, -2) || CheckEnemy(ZOMB2, -2) || CheckEnemy(ZOMB3, -2)) {
    collision_sound = aScream2;
    is_colliding = true;
  }
  if (CheckEnemy(GHOST, -1) || CheckEnemy(GHOST2, -1)) {
    collision_sound = aGhostly1;
    is_colliding = true;
  }
  
  // method 1
  if (is_colliding && (collision == null || !collision.IsPlaying))
    collision = collision_sound.Play();

  // method 2
  if (is_colliding && !was_colliding) collision_sound.Play();

  was_colliding = is_colliding;
}


Edit: code fixed

RetroJay

Hi Khris.

Long time, no speak.
It's great to hear from my mentor.;-D

This looks like it maybe exactly what I'm looking for.
I have printed out your script so I can take it to work with me and try it over this Bank Holiday.
Unfortunately I won't be able to tell you how things go until Tuesday Evening.:(

Thank you ever so much, I really appreciate you taking the time to look at this for me.

Yours.
Jay.

RetroJay

Hi Khris.

I completely forgot about the megabytes, I still have left on my phone.
So here I am sitting at work typing this message to let you know that your script works beautifuly.:)

I had to use Method 2, which is a shame, because Method 1 wouldn't work.
I receive this message...
Error running function
'Room_RepExec':
Error Null pointer referenced.

When I am home I will post the complete script here.
It maybe useful to other people.

Thank you for your help.
As always it is much appreciated.

Yours.
Jay.

Khris

Hi Jay,

stupid mistake on my part; method 1 will try to play the sound as long as the channel is free but doesn't check whether there even was an actual collision...
Code: ags
  // method 1
  if (is_colliding && (collision == null || !collision.IsPlaying))
    collision = collision_sound.Play();

RetroJay

Hi Khris.

Yep, that's cured it.;-D
Actually, I think that Method 1 works better for what I need.

Thank you for your help, Khris.
It's much appreciated.

Yours.
Jay.

SMF spam blocked by CleanTalk