Making the character attack ONCE

Hey everyone, I am having some trouble with making my character “punch” once and then stop.

Right now what I am doing is, if the punch button is pressed it sets “punching” to true, then in the game loop, if punching is true, and the Fist rectangle intersects the enemy, then take 1 away from the enemies health, but the problem is if the person holds down punch the fist is just always out, like walking around with your hand sticking out, and it takes 1 away the entire time the rectangles are intersecting.

I figured out a way to fix this and that was by setting the Punching variable to false once the intersection occurred and then taking away 1 from the health and this worked fine however a problem with the animation occurs because in the player class, if punching is true it draws the punching frame. So if we make punching false right after the rectangles intersect it happens so fast that it never gets a chance to show the character punching.

So I guess the problem lies in my animation, I am wondering how I would make it so that on a button press it plays the Punch animation ( show punch frame, then back to standing)…That way I can also have it so when i press Z it will do a punch and then stop so the player wont be able to run around holding the punch and destroying everything.

Hope this makes sense, if it doesnt please ask and I will try to clear it up.

Am not sure I understood 100% but from what I gather you can probably just solve your problem by keeping a gameState…

		final int FIGHTING = 0;
		final int PUNCHING_ANI = 1;
                int gameState=FIGHTING;

ie… When punch button is pressed, set your game state to PUNCHING_ANI, do the punch animation… When punch animation finished set back to FIGHTING (and of course only allow punches if gameState is FIGHTING)… Or somet like that…

You should probably detect button edges (ie. presses or releases) rather than just using the down/up state directly. And have some kind of state machine like mentioned above.

Hmm yes I was thinking of having something similar to that, but wasnt sure exactly how to go about it, thank you!!

One problem is that for my punch animation, its not really an “Animation” what it is, just a boolean, so if punching then it draws the punching picture (one frame) and then if its not punching it just draws the normal standing frame.

Im guessing, if i do add frames to it, i can just wait for the loop to cycle through all frames of the animation and then set the Animation to false and allow it to punch again. And if the punch hits the enemy, set Attacking to false and only allow a Punch and damage to be taken from player is Attacking? :persecutioncomplex: but in this case I would have a variable Punching_Ani for the animation, and Attacking for the collision detection and taking health, that way once the punch is hit, it will set it to false and take away 1 HP, rather than take away 1 the entire time the punch is hitting…

I would make a punchtimer ( 1 second? ) that activates when you punch. When active no punching allowed and draw the punch anim/frame. After 1 second go back to normal state.

or you could just it wait until someone releases the key.

This ain’t easy stuff. But I’m just on the go to release a beta of THE GAME (M.U.G.E.N-like) for the sf3jswing project.
I 've achieved about 90% of this game, now I’m right dealing with this exact same issue.
What would be my advice, is focusing on Animation timing and KeyStroke’s stacks. I done something like this :
Animation is XX frames length and should play until the time length is gone, or the program calls stop(). Anyway it should stop whenever it is required. A Fighter is a collections of Animation so that it’s not possible to have full control over the Animation’s. That is, only a KeyStroke or a AI method such as doDefend() - doAttack() can change the state of that Fighter. Hence, writing the perfect loop is the goal. It should scan for remaining KeyStroke over time and state of each individual keystroke AND check for the Animation.STATE (PLAYING|STOPPED|LOOP).
Subsequently, Fighter is needed to have a Stack of KeyStroke events, ordered ascendingly to time and the current Animation. Plus, the Animation that is linked to the IDLE state.

Here it is : Fighter reads one sequence of, say, 3 Keystrokes (that be Punch-key pressed repeatly) and the IDLE Animation (call it “stance”) LOOPING. read 3 KeyStrokes, the first is checked for CONSUMED and left off the stack because it’s not needed anymore, then you can call doAttack(PUNCH) for that read keyStoke. It will then immediately check for the play time of that animation, whether it should return to the IDLE Animation or continue with Punch Animation.

Resulting in 2 classes : Fighter{int currentAnimationHash, Stack<KeyStroke{int state=CONSUMED|FREE}>, int state=IDLE|ATTACK|DEFEND|MOVE} and Animation{int state = PLAYING,STOPPED,LOOPING}.
8) enjoy!

Typically I attach actions to animations. An Animation object has a bunch of frames in it, pauses between frames, and AnimationEvent’s that can be fired any time during a frame. The AnimationEvent is just an interface with a perform() method, so pretty much it can do whatever I want it to. Each Entity has its own AnimationSet which is basically a HashMap of Animation’s, and then each Animation in the set has a priority of some kind. So, only certain Animations can interrupt other ones, and you can’t interrupt one Animation with itself. As a result, if you hold the punch button (or rapidly press it), it will still only go as fast as it Animates. Plus the Animation will be able to finish unless it is interrupted by something with higher priority (like Death would interrupt Punch).

The above works great for beat-em-ups, but probably wouldn’t translate well to a 2-player fighter because its precision is limited by the FPS. You could always adapt it so that AnimationEvent’s only occur on a fixed timestep, and that would likely do the trick.

Wow thanks a lot broumbroum and demonpants for the explanation!! Really gave me some good ideas and a good direction to go in!

Also Demonpants a beat em up is what I am going for so I think your method will work great if I can get it implemented, although if it isnt too much trouble do you have any code examples or resources that I can read up on this method some more?

Thanks

Hello

Just a question : is this problem really that complicated?

From what I understand Swattkidd7 only has 2 pictures in his animation ; one for punching and one for normal stance. So the suggestion of J Dick (just add a timer) should do the trick.

Here is a simple way to do it :


boolean punchIsPressed = false;
int punchTimer = 0;
final int animationTime = 1000;

public void keyPressed(KeyEvent e){
	if(e.getKeyCode() == punchKey && !punchIsPressed && punchTimer == 0){
		punchTimer = animationTime;
		punchIsPressed = true;
	}
}

public void keyReleased(KeyEvent e){
	if(e.getKeyCode() == punchKey){
		punchIsPressed = false;
	}
}


public void update(int deltaTime){

	while(punchTimer > 0){
		//indicate that we draw the punch picture
		punchTimer -= deltaTime;
	}
	if(punchTimer < 0){
		punchTimer = 0;
	}
}

Well, tell me if I didn’t understand the problem correctly.

You’re probably right. All he really needs to do is keep the concept of a state in mind.

Hmm, well I’d have to pull the Animation stuff out from my code and clean it up a bit, which would take a little too long given that it doesn’t appear you need it.
However, in you want to see the implementation in action, you can have a look at this game I was making last year for the Retro Remakes contest (was too ambitious given my amount of free time, unfortunately, so I never finished):

All the punches and kicks in that video send events at their apex, and the event notifies anything within the damage radius (on an opposing team) to take a certain amount of damage.

So basically it’s like this, in pseudo-code:


class Animation
{
    //Has a String array of frames that reference the names of sprites already loaded into a HashMap
    //Has an int/float array of delays between each frame
    //Has an array of AnimationEvents.
    //Has an int priority value so it knows what it can interrupt
    //Has a looping enum, can be either: PLAY_ONCE, PLAY_AND_CLAMP, LOOP, or PING_PONG
        //PLAY_ONCE plays the animation once, then becomes interruptible by anything after completion (used for most animations).
        //PLAY_AND_CLAMP plays the animation once, then clamps on the final frame. Can only be interrupted as normal (used for death animations, etc.).
        //LOOP goes back to frame 0 after the animation has finished. It will only ever be interrupted by higher priority actions (used for idle/stance animations).
        //PING_PONG is the same as LOOP except it begins to traverse downward instead of going back to 0 (can often get away with less frames than LOOP).
    
    update()
    {
        if (now - lastFrameStart >= delays[currentFrame])
        {
            lastFrameStart = now;
            if (animationType == PING_PONG && pingPongingDown)
            {
                currentFrame--;
                if (currentFrame < 0)
                {
                    currentFrame = 1;
                    pingPongingDown = false;
                }
            }
            else
            {
                currentFrame++;
                if (currentFrame >= frames.length)
                {
                    if (animationType == PLAY_ONCE || animationType == PLAY_AND_CLAMP)
                    {
                        currentFrame = frames.length-1;
                        isFinished = (animationType == PLAY_ONCE);
                    }
                    else if (animationType == PING_PONG)
                    {
                        currentFrame = frames.length-2;
                        pingPongingDown = true;
                    }
                    else if (animationType == LOOP)
                    {
                        currentFrame = 0;
                    }
                }
            }
        }

        //Fire the animation event for this frame.
        if (animationEvents[currentFrame] != null)
        {
            animationEvents[currentFrame].fire();
        }
    }
}

Does that help?

Marvelous game demo Demonpants ! :smiley: Is it running on LWJGL, JOGL ?

        //PLAY_AND_CLAMP plays the animation once, then clamps on the final frame. Can only be interrupted as normal (used for death animations, etc.).

this Animation.state is what I’m missing in my code. But it can be handled if Animation is stopped or paused at last.

Yeah, you certainly don’t need PLAY_AND_CLAMP, I rarely use it (typically only for death animations, but even then you could just have a PLAY_ONCE and do a bit more work).

Thanks, I’m glad you liked the demo. It’s running in LWJGL - I originally did it in Java2D but it couldn’t handle so many squares. In hindsight I probably could have had one BufferedImage for all those pixel effects, but either way Java2D was too weak for what I wanted to do.

Yes demonpants that helps a lot! Thank you! I am well on my way to getting this problem sorted out now…

Also, @Gudradain, You are right the problem isnt all that complicated, I think the problem I have been having is I wasnt thinking of attacking and their animation playing as seperate things. I based showing the punch frame if the button was pressed, rather than if the button is pressed play the punch animation for a second and go back to standing.

Thank you all for your input and help