Stopping from a jump

Hi, this is my first post here.
I’m developing my own 2D platform game. I’m only at the beginning. Now I’m trying to make the player jump.
The jump itself works fine but I’m not able to stop the player. Here is some code:

	public void tick() {
		[ some code ]
		
		if (_status == JUMPING) {
			jumpAnimator.tick();
			position.y = jumpAnimator.getValue();
		}
	}

jumpAnimator is an object that calculates the current y position. It works very well and the jump follows a realistic curve.
I want the player jumping, falling and when he reaches the bottom of the screen, stopping.
To stop the jump my idea was to set the _status variable to STOPPED when the player reaches the bottom of the screen.

public void tick() {
		[ some code ]
		
		if (_status == JUMPING) {
			jumpAnimator.tick();
			position.y = jumpAnimator.getValue();
		}

		if ( /*reached the bottom*/ ) {
			_status = STOPPED;
		}
	}

If I add those lines, the player won’t jump anymore because he starts to jump and immediately set his _status to STOPPED.

Any idea?

if(){

}else if(){

}

-.-

Very helpful.

I can’t see the problem because your hiding some code there. what happens in the “if” where you check if the player reached the bottom?

If you mean

		if (_status == JUMPING) {
			jumpAnimator.tick();
			position.y = jumpAnimator.getValue();
		} else if (/* reached the bottom */) {
			_status = STOPPED;
		}

It doesn’t work. It doesn’t change the state to STOPPED.

Well, at the moment the if statement is not very nice. But here it is:

public void tick() {
      [ some code ]
      
      if (_status == JUMPING) {
         jumpAnimator.tick();
         position.y = jumpAnimator.getValue();
      }

      /* check if the player reached the bottom */
      if (position.y >= (int) 512 * 3 / 4 - 32) {
         _status = STOPPED;
      }
   }

Where 512 * 3 / 4 is the height of the screen and 32 is the height of the player.

Prepare a boolean, let’s say if true then jump else not. Jump is assumed to be decreasing Y value every tick. Anytime when you need it to stop, just set the boolean to false. Ofc you need “if(jump) then jump” check every tick.

My first suggestion would be to create separate variables for your actions. There are many ways to do it, and you could go elegant and use bit-masks and enumerations (static finals) so that your _status variable could contain many statuses at the same time. You seem to have a jumpAnimator object, so I’m guessing you may just keep your variables in there. Since games are time/frame based, you’ll probably want to allow impulse for a certain amount of time, and after that, you could switch into fall or no-collision mode. You can end fall mode when a collision occurs. You could stop your jumps on collisions, but for certain collision types you may not want that behavior, say if you jump through a collectible object.

Jumping can require a lot of checking. In games like Super Mario Bros. you jump higher based on how long you hold down the button, and if you end up hitting the ground while still having the button held down, you need to account for that too so the player doesn’t repeatedly jump. If the player is in the air you don’t want them to jump again on repeated button presses unless you allow a double jump, or are in water and swimming.

You should have a maximum impulse that you allow, and if you reach that, the jump is over until the button is let go and it is established your are on the ground again. If you collide with an object of the right type, the jump is over. I keep a variable called jump_counter to know how many frames in I am so I can keep track of the impulse. At first you might not even want to distinguish between top and bottom collisions. In the end the world just needs to work, and that can be very difficult.

The best advice I could give is to spend the time and figure out why it doesn’t work. It isn’t particularly helpful advice, but game programming can be done in wildly different ways, and as long as it works it is right. You should view yourself as the guru, because ultimately you will be providing most of the answers.

@Antiharpist Thank you for the reply. This is the code I written. It works for now.

These are the enums:

	private static enum XMovement {
		MOVING, STOPPING, STOPPED;
	}
	
	private static enum YMovement {
		JUMPING, FALLING, LANDED;
	}
	
	private XMovement xMovement = XMovement.STOPPED;
	private YMovement yMovement = YMovement.LANDED;

I had to break the _jumpAnimator in two pieces:

  • The first is named _jumpAnimator and it calculates the y position from the beginning to the vertex of the parabola;
  • The second is named _fallAnimator and it calculates the y position from the vertex of the parabola to the end.

This is the code of interest in the tick() method.


		if (_controls.getKey(Controls.JUMP_BUTTON).isDown)
			if (yMovement == YMovement.LANDED) {
				yMovement = YMovement.JUMPING;
				_jumpAnimator = new JumpAnimator(JUMP_DURATION, JUMP_HEIGHT, position.y);
			}
		
		if (yMovement == YMovement.FALLING) {
			_fallAnimator.tick();
			position.y = _fallAnimator.getValue();
		}
		
		if (yMovement == YMovement.JUMPING) {
			_jumpAnimator.tick();
			position.y = _jumpAnimator.getValue();
			
			if (_jumpAnimator.finished()) {
				_fallAnimator = new FallAnimator(JUMP_DURATION, JUMP_HEIGHT, position.y);
				yMovement = YMovement.FALLING;
			}
		}
		
		if (yMovement == YMovement.FALLING) {
			/* For testing the ground is at y = 200 */
			if (position.y >= 200) /* This is ugly. The fall animator returns double values and it's hard that the value returned it's equal to 200.00 */
				position.y = 200;
				yMovement = YMovement.LANDED;
		}

It works, but I don’t think it’s what that can be said beautiful code.
Every comment/suggestion is appreciated. I want to make good code first.

Some possibilities:

  • You could set up a state machine for this, with states for MOVING, STOPPING, FALLING, etc. instead of numerous if-statements
  • Do collision checking with the environment instead using coordinates.
  • Before updating positions, let the collision detector verify the new position, upon approval do the update
  • Calculate collision check points of your game entities, based on the current entities heading direction, like if someone is moving to the left, check the right hand side

This is an interesting point. Can you elaborate more on that?

This is my first game and the coordinates check was for testing purposes. Clearly I will implement collision detection with environment objects.

In my top-down-shooter there are entities like droids and bullets.
Each entity is always in one state like moving or waiting.
Basic collision detection for example, is the same for both kinds of entities, so the detection invocation goes into the parent state class. But the reaction on collision is different: droids just stop at walls whereas bullets explode. And if a droid happens to run into a closed door, the door shall be opened.
So, there are additional inherited state classes for droids and bullets for handling events.
Relatively easy to implement different behaviours and easier to test.

Look up for finite state machines or keep asking :slight_smile:

I googled up “finite state machines” and now I’m asking. :slight_smile: (dear administrator, smileys in this site are ugly :()
I found some examples on how to implement finite state machines in Java, but how can I implement them in a game? Can you (or someone else) give me a 10-lines example for the states JUMPING, FALLING, LANDED, please?


EDIT:

I mean an example of finite state machine coded into classes.

Here is a rough sketch:


public interface State {
   void enter();  
   void process();
   void exit();	
   void onInputEvent();	
}

public class Actor {

   private State state;
  
   public Actor() {
      state = new StoppedState();
   }
  
   public void act(){
      state.process();
   }
  
   public void setState(State newState) {
      state.exit();
      state = newState;
      state.enter();  
  }
}

Actor#act() is called repeatedly from the game loop
In State#process() do whatever you need to do: update actor positions, do collision checks, perform state changes, look for the meaning of life…

For example, a FallingState would calculate a new y-coordinate, asks the opinion of the collision detector about. In case of ground collision, a state change would be done:

StoppedState state = new StoppedState();
actor.setState(state);

Now, in StoppedState#enter() any movement/velocity/heading would be cleared, and in StoppedState#process() no position updates are necessary. But, in case of incoming input events and upon approval of the collision detector, a state change to WalkingState or whatever is done.

Input events should be delegated from actor to state in order to keep the state encapsulated.

Basic principle is very simple. However, as always, details can be tricky ;D

Is it a good thing to implement the frame management inside a State object?

I mean…

When the player jumps, the jump animation is needed. When the player falls, the fall animation is needed. The jump and fall animation are 4-5 frames long. I wonder if it is a good thing to encapsulate the frame-changing mechanism inside the State object. The State interface will be like this:

public interface State {
   void enter();  
   void process();
   void exit();   
   void onInputEvent();   
   BufferedImage getCurrentFrame();
}

Is this a violation of the State Pattern?

No, I wouldn’t put no image stuff into states.
However, states could decide the current look of the character and store in the character.


public FallingState {
   public void enter() {
      actor.setLook(LookEnum.FALLING);
   }

That’s clear. Thank you a lot for your replys. I think it’s all right for the moment.
You and _Riven (on IRC) helped me a lot. Thank you again!