Animation frame event

Started by smartastreacle, Sat 17/07/2021 10:26:36

Previous topic - Next topic

smartastreacle

Hi,

I am brand new to this so please be understanding.  :)

I have a room with an animation of 7 frames with 5 second delay on erepeat, enoblock. The animation works fine. I also have a health bar. Initially, I would like every time frame 5 comes round for 10 points to be knocked off the health bar so that decreases say from 150 down to 10 at which point the player gets knocked back to a previous room. I have read the manual and looked through the forums, I still don't know how best to achieve this. I have tried so many different things that I am shy at putting code up because there are so many versions of it. I am sure this is easy to achieve. Any ideas would be very much appreciated.
Once I can do the basics I would like for the 10 points to be knocked off randomly so at each cycle it's hit or miss if the reduction happens. In fact I would ideally like for successful random hits to happen in any of three frames - say 1, 3 and 6 of frames 0 through 7 occur. I would also have random hit sounds.
While this happens the player has to achieve something to stop the attack and win. This I can do.

Many thanks. This is my first post. Hi!  8-)



Cassiebsg

#1
Hi smartastreacle and welcome to the forum. :)

My first question is: How do you set up this animation? Is it BG animation, object or something else? Since you mention you have 7 frames, I'm going to assume it's an object.  :)

Answering your last question first (because it's easier): Just add the sounds on the view. Open view->Locate the Loop-> click the frame (1) and in the properties you can set up a sound for that frame. Repeate for any frame you want sound.

For random, all you need is... Random.  (laugh)

From the manual:
Spoiler

Random (int max)
Returns a random number between 0 and MAX. This could be useful to do various effects in your game. MAX must be a positive value in range 0-32767.

NOTE: Because of the way Random is implemented in AGS, the return value will never be higher than 32767.

NOTE: The range returned is inclusive - i.e. if you do Random(3); then it can return 0, 1, 2 or 3.

Example:

int ran=Random(2);
if (ran==0) cEgo.ChangeRoom(1);
else if (ran==1) cEgo.ChangeRoom(2);
else cEgo.ChangeRoom(3);
will change the current room to room 1,2 or 3 depending on a random result.
[close]

And for checking which frame your loop is on, you'll need to check in repeatedly_execute ( or room_RepExec() - you need to use the room Events to connect the function) and check for the Object.Loop.

Code: ags

if (oAnimation.Loop==5) // oAnimation is whatever name you gave your object.
{
    // do stuff, like decrease the health bar, etc
}


Hope it helps.  :)
There are those who believe that life here began out there...

smartastreacle

Hey Cassiebsg

Many thanks for the welcome -  :-D - and the suggestions. I am trying them out in-between sessions of watching sport.

Yes it's an object animation. Let's say the animation is an npc tank, let's call it oNpc. If the player destroys oNpc before being destroyed him/her self, they can move on, otherwise they get knocked back two rooms for repairs. oNpc has 7 frames. On frame 5 it fires. The shot hits or misses. If it hits the player loses 10 on the health bar, if it misses player loses nothing and so on. Health bar starts at 110. I tried (oNpc.Loop==5) but does this give the frame number or the loop? I changed it for (oNpc.frame==5) and that did give the frame so I could knock the health off at frame 5. Trouble is it does not stop. As so as we reach frame 5 it keeps taking off ten until we are down to negative health which causes an error as the health is tied to a gui width which can't be negative. I can put a condition in to stop at 10 and avoid that error. So, the question is: how do I sync 10 points off each cycle instead of losing all health at frame 5 in cycle 1?

I have so far:

function room_AfterFadeIn()
{
    object[0].SetView(9);
    object[0].Animate(0, 25, eRepeat, eNoBlock);   
}   

function room_RepExec()

  if(oNpc.Frame == 5)
  gcarhealth.Width = gcarhealth.Width - 10;   
}

I have delay at 25 so I can watch what happens. So how to sync room_RepExec() cycles to the object animation cycles and delete 10 each time we go round.
I know this is noob stuff but I am tearing my hair out.
  :~(

newwaveburritos

#3
Do you want to add, like, a chance to hit?  So that there's only an X% chance of hitting every frame 5 instead of it hitting every frame five? If that's the case you could just add something like:

Code: ags

int HitChance; //I'm not actually sure if you can declare variables in RepeatedlyExectue but you'll want to declare that somewhere.
HitChance = Random(3);  //this is a one in four chance

if (HitChance == 3)&&(oNpc.Frame == 5){
  gcarhealth.Width = gcarhealth.Width - 10;   
}

Cassiebsg

Yes, sorry it was Frame.  (nod) But glad you found it.  :-D

Code: ags

function room_RepExec()
{ 
  if(oNpc.Frame == 5 && gcarhealth.Width>=1) 
  gcarhealth.Width = gcarhealth.Width - 10;   
}

There are those who believe that life here began out there...

smartastreacle

Thank you newwaveburritos (they sound tasty)

I will definitely go down this road. The more chaos the better  :-D

And thank you for the confirmation Cassiebsg.

Still losing all health in one cycle though. If I fix it I will let you know how.

The treacle  :P


Khris

I guess the problem here is the animation delay, which causes the .Frame to be 5 for multiple loops on end. One easy alternative is to remove 2 instead of 10 health points. Another solution is to use a variable to make sure the HP is decreased only once each time the frame is 5.

Code: ags
int prevFrame;

function room_RepExec() {
  if (cNpc.Frame == 5 && prevFrame == 4) {
    gcarhealth.Width = gcarhealth.Width - 10;
  }
  prevFrame = cNpc.Frame;
}

smartastreacle

Thank you so much for this. I will try it. As a work around fudge, as the delay between frames is 5 as you pointed out, I stuck a wait of 5 at the end and it all synced up. Can't tell if that interferes with the mouse at the moment. I got to this:

function room_RepExec()
{
  int HitChance;
  HitChance = Random(2);
  if(oNpc.Frame == 5)
  if(HitChance == 2){
  gcarhealth.Width -= 10;
  Wait(5);
  if(gcarhealth.Width < 15)
    cme.ChangeRoom(18);
  }

A bit like fighter planes syncing their machine gune to fire between the blades. Not too sophisticated. I wanted, as you suggest, to use a variable. I was thinking of a boolean. I will try yours. Ideally I will change the hit chance to coincide with a random sound, clunk = miss, bash - hit and get the random points deduction from that.
Sometimes the mouse pointer appears outside the screen but not on it. What causes that?

I like this place. Thank you.   (nod)

Cassiebsg

QuoteSometimes the mouse pointer appears outside the screen but not on it. What causes that?

I'm not sure what you mean by this? Elaborate or provide a picture (better yet, both  ;) ).

Also, to show the code format please use [ code=ags ] your code in here [ /code ] with no spaces inside the [ ] . Or click the # button below font face and above the similes.  :)
There are those who believe that life here began out there...

smartastreacle

I think I got stuck in a function in global script which took away control of the mouse. If I see it again I will demonstrate. Thanks for the tip on the code. My way was a bit scrappy huh?  (laugh)

Khris

Calling Wait(5) blocks the game for 1/8 of a second, meaning no mouse clicks or keyboard input will work, the mouse cursor switches to the wait mode, etc.
Not a good idea :)

smartastreacle

Ah, thanks, Khris. I had a hunch that might be the case. The variable works way better. I had to give it a value of 4 though to kick it off. Should it have worked without that?

Code: ags

function room_RepExec()
{
  int prevFrame;
  prevFrame = 4;
  int HitChance;
  HitChance = Random(2);

  if(oNpcn.Frame == 5 && prevFrame == 4){
  if(HitChance == 2)
  gcarhealth.Width -= 10;
  prevFrame = oNpc.Frame;
  
  if(gcarhealth.Width < 15)
    cProf.ChangeRoom(18);
  
  else if(street_number == product)
    streetNo();
  }    
}

Khris

You moved the declaration inside the function, which will not work at all, at least not how it's supposed to.
I deliberately declared it above the function so it retains its value. Yours will simply always be 4, so it's completely pointless to have the  prevFrame  variable in the first place.

The idea is to detect the exact moment when AGS switches the frame from 4 to 5, to avoid running the code during multiple frames.
Because after the  oNpcn.Frame == 5 && prevFrame == 4  condition is true, prevFrame will be 5 during the next 1/40th of a second, meaning the health bar will no longer decrease multiple times on end.

smartastreacle

Got it, thank you. I'm a noob. I'll get there.  :)

SMF spam blocked by CleanTalk