Making a LibGDX Roguelike Survival Game Part 4 – I need a hero #gamedev #indiedev

Screen Shot 2017-08-02 at 21.28.51
[ Full source code for this tutorial ]

Most games will have a main character or a hero, for the moment ours will be this little person, they can be replaced later if necessary.

The hero will need a new class that extends Entity, it will need a new texture and ENUM type. We will need to change the keyboard inputs to move the Hero Entity and have the camera follow them.

Enums.java
A new enum is needed for entities, for now we only have one type of HERO:

public enum ENTITYTYPE {
  HERO
}

Entity.java
This new enum type and speed can be added to Entity as class variables:

public ENTITYTYPE type;
public float speed;

Media.java
Add the hero image to a new folder; “assets/entities/hero/hero.png”

Add a new Texture to this class and in the load_assets function initialise it:

// HERO
public static Texture hero;
  ...
  hero = new Texture("entities/hero/hero.png");

Hero.java
The public constructor for our hero class sets the type to the newly defined HERO, we set the dimensions, texture, speed and position. The position is a Vector2, this has a x and y value and denotes the hero position on the map, the initial position is passed as a variable (pos) to the class.

public Hero(Vector2 pos){
  type = ENTITYTYPE.HERO;
  width = 8;
  height = 8;
  this.pos.x = pos.x;
  this.pos.y = pos.y;
  texture = Media.hero;
  speed = 1;
}

Previously we stored the on screen location in some temporary variables, these will now be tracked within our hero class and updated every frame:

public void update(Control control) {
  dir_x=0;
  dir_y=0;

  if (control.down) dir_y = -1 ;
  if (control.up) dir_y = 1 ;
  if (control.left) dir_x = -1;
  if (control.right) dir_x = 1;

  pos.x += dir_x * speed;
  pos.y += dir_y * speed;
}

We pass the control instance into the public update function and use the same logic as before to set the x and y values for the Hero Entity.

gameclass.java
Variables to remove from class:

// Temp x and y co-ords
int x, y;

// For Movement
int direction_x, direction_y;
int speed = 1;

Add an instance of Hero to the class:

Hero hero;

Initialise the hero instance passing in the Island.java centre tile, we will need to make this variable public in order to access it.

// Hero
hero = new Hero(island.centre_tile.pos);

Now we have the Hero class we can also remove code from the render function of the gameclass:

// This now exists in the Hero class
direction_x=0;
direction_y=0;
if (control.down) direction_y = -1 ;
if (control.up) direction_y = 1 ;
if (control.left) direction_x = -1;
if (control.right) direction_x = 1;

// Camera position will need to use the hero Vector2
camera.position.x += direction_x * speed;
camera.position.y += direction_y * speed;

The new render code to update the hero, camera position and draw our hero:

hero.update(control);
camera.position.x = hero.pos.x;
camera.position.y = hero.pos.y;
camera.update();
.....

hero.draw(batch);

We call the Hero update function every frame and pass in the control instance so we can check the WASD or arrow keys are pressed and change the positions accordingly. The draw function for the Hero is the default function held in the Entity class. If everything is correct we should now be able to move our hero around the screen, the camera position is set to that of the hero:

hero
This appears ok but the camera position is incorrect, the image below shows that snapping to the x and y positions of the hero the camera is placed at the bottom left of the image.

hero_align
To overcome this we can add new functions to the Hero class that return the correct values and call these from the render function of the gameclass:

// Hero.java
public float get_camera_x() {
  return pos.x + width/2;
}

public float get_camera_y() {
  return pos.y + height/2;
}

// Render Loop for gameclass.java
camera.position.x = hero.get_camera_x();
camera.position.y = hero.get_camera_y();

To take this one step further lets look at a function available on the camera position called Lerp. Further reading on Interpolation. This basically moves the camera toward the Hero’s position slower than the hero has moved, so we get a nice smooth/delayed camera movement.

Rather than setting the x and y values of the camera.position we can call camera.position.lerp, this requires a Vector3 rather than Vector2 so we will need to make some small changes.

Entity.java
Add a new Vector3 variable, a Vector3 holds x,y and z values, we wont need the z value so can just set this to 0 and ignore it.

public class Entity {
  public Vector2 pos;
  public Vector3 pos3;

  ...
  // initialise the new variable in the public constructor
  pos3 = new Vector3();

When we call the Hero update function we can set the Vector3 variable using the Vector2 that has already been updated after checking the for keyboard inputs:

pos3.x = pos.x;
pos3.y = pos.y;

Moving back to gameclass.java after the hero.update function is called we can set the camera position using the new Vector3 variable:

// GAME LOGIC
hero.update(control);
camera.position.lerp(hero.pos3, .1f);
camera.update();

The .1f defines the speed at which the camera catches up with the hero position, 0.1 (f stands for float) should give a steady speed, as long as the speed is less than the hero’s speed we will see some delay.

Final resultlerp.gif

We now have a randomly sized island in the sea, a hero that can move and a camera that follows, next we will look at using Box2D to handle our collisions and make sure our hero cannot walk on water.

 

 

 

 

 

 

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s