Making a LibGDX Roguelike Survival Game Part 3 – Loading Media refactored #gamedev

LibGDX offers an asset manager that can help take care of loading and getting textures etc, feel free to take a look at this, the wiki page shows exactly how it is used. The main benefit is the asynchronous loading of assets and the ability to display a loading bar:

“Loading of most resources is done asynchronously, so you can display a reactive loading screen while things load”

Screen Shot 2017-08-02 at 15.43.37.png

[ Full source code for this tutorial ]

Our game has very few assets which are all very small in size, for now we can move the loading of Textures to a new class. In the main package uk.co.carelesslabs we will add a new file Media.java, we will move all of the Textures defined in Island.java into this new class.

Media.java

// TILE
// class variables

public static Texture grass_01, grass_02, grass_03, grass_04;
public static Texture grass_left, grass_right;
public static Texture grass_left_upper_edge, grass_right_upper_edge;
public static Texture grass_top, grass_top_right, grass_top_left;
public static Texture water_01, water_02, water_03, water_04;
public static Texture cliff, water;

There is a static function in the Media class (load_assets) which will initialise all of our textures both are defined as static:

public static void load_assets(){
  grass_01 = new Texture("8x8/grass/grass_01.png");
  grass_02 = new Texture("8x8/grass/grass_02.png");
  ...

These images will not change and we only want to load them once, as they are so small there is no need to dispose of them mid game, we can call this method from are main gameclass.java in the Create() method and our images will be ready to use:

Media.load_assets();

Island.java

We can remove the old reference to loading images (also remove the function form this calss) so the public function now looks like this:

public Island(){
  setup_tiles();
  code_tiles();
}

To fix all of the references to the textures that are no longer declared in this class we reference them via the Media class (not an instance of it):

tile.secondary_texture = Media.grass_top_right;

Once all of the references are updated the game should run as it did previously, going forward this will make the assets a little easier to manage as they will all be in one place.

This class will make it easy to add new textures and even switch between different tile sets without having to change the island, chunk or tile classes at all.

 

Advertisements

Making a LibGDX Roguelike Survival Game Part 2 – Adding a simple Island #gamedev

The tiles used for this game are available here Open Game Art tile set, Open Game Art has some really great tile sets worth using; especially when you are prototyping. This is an example from the site showing what can be achieved with this tile set:

[ Full source code for this tutorial ]

For this part of the tutorial we will review the new classes, Entity, Chunk, Tile and Island, these are used to generate a simple island/ map which can be rendered to the screen.

Entity
The key variables for the entity class are as follows:

public Vector2 pos;
public Texture texture;
public float width;
public float height;

Almost all objects have position, width, height and a texture, this is enough information to draw an image to the screen at a certain and co-ordinate. The class has a simple draw function which can be called by classes we create that extend Entity, we can override this method if more logic etc is needed in the draw function:

public void draw(SpriteBatch batch){
  batch.draw(texture, pos.x, pos.y, width, height);
}

An Enums class was created to hold all the enumerators we will need, at the moment we only need some TILETYPE‘s so we can set the type of our tiles, grass, water and cliff.

The three new classes for defining, generating and drawing the island are added to a new package named “map”. Packages are used to organise related classes (like a folder), even a small game can become over loaded with classes quite quickly.

Tile.java
This holds information on an individual tile (square space) which extends Entity; giving access to all of the properties of that class:

public class Tile extends Entity {

When we initiate a new tile we pass in its location, size, type and texture, the size is basically the scale, if we decide on a smaller/larger tile size later we can easily experiment changing only the size. Calling super() will initiate the Entity (calls the Entity public function).

public Tile(float x, float y, int size, TILETYPE type, Texture texture){
  super();
  pos.x = x*size;
  pos.y = y*size;
  this.size = size;
  this.texture = texture;
  this.col = (int) x;
  this.row = (int) y;
  this.type = type;
  this.code = "";
}

There are a number of boolean functions that make testing tiles more readable e.g tile.is_grass() or tile.is_water(), is_passable(), this becomes useful when we have a lot of code that checks a tile is passable, changes to the passable logic can be maintained in place e.g:

public boolean is_grass() {
  return type == TILETYPE.GRASS;
}

Chunk.java
A chunk will hold an array of arrays of tiles, it can useful to split the chunk into rows for rendering order and for selecting tiles, you do not have to do this and could just have one big array of tiles; ArrayList, the structure:

Chunk
        Row
                Tile, Tile, Tile
        Row
                Tile, Tile, Tile
        Row
                Tile, Tile , Tile

Chunk public constructor accepts the number of rows, columns and the size of the tiles (tiles are square):

public Chunk(int number_rows, int number_cols, int tile_size ){
  tiles = new ArrayList<ArrayList>();
  this.number_rows = number_rows;
  this.number_cols = number_cols;
  this.tile_size = tile_size;
}

We have some useful functions in the chunk class, both require a row and column integer; get_tile returns a tile and get_tile_code returns the code for a tile. Later when we allow interaction with tiles or need to check the tile the hero is on we can calculate the row and column by the cursor or hero x and y positions.

Tile Code
Creating a code to describe a tiles neighbours allows us to make graphic and logic decisions. The centre tile show below has a code of “111000000”, we read the code left to right one row at a time, the three tiles above are all passable so get set to 1, the cliffs and water are all 0’s.

tilecode

This method can be repeated to achieve all sorts, for example you could find all grass touching water and turn it into sand.

Island.java
This class will create a new chunk and populate it with tiles, there is logic to first fill the chunk with water tiles, then find the centre and create a grass island. There is some code present which can be refactored and moved into other classes later. Often the first draft or prototype code is messy especially in a game jam or challenge.

To hide some of the complexity the public constructor for the island class calls three functions:

public Island(){
setup_images();
setup_tiles();
code_tiles();
}

* Not everyone will like the naming conventions I use, I work with Ruby, Go, PHP, VB.net, C# and Java so use a mixture sorry! :Fixed in part 5 *

The images should really be loaded in another class, this will be address in the next part of this series. We setup our images as LibGDX Textures. Further information on loading files available on the wiki, when you are writing a game for mobile or HTML you will need to look at the File Handler, we can get away with a relative path for our images though:

grass_01 = new Texture("8x8/grass/grass_01.png");

The next step is to create a chunk and fill it with tiles. For now we will go with a chunk size of 33 (a random number I selected, we can revisit this), the tiles are size 8, to create an island we:

  • Generate a random number 5 to 8 for half the height and width in tiles
  • Find the centre row and column
  • Calculate first and last row and columns

This defines a randomly (within set bounds) sized square which we can place in the middle of the chunk.

chunk = new Chunk(33,33, 8);

int current_row = 0;
int rng_w = MathUtils.random(5,8);
int rng_h = MathUtils.random(5,8);

int centre_tile_row = chunk.number_rows / 2;
int centre_tile_col = chunk.number_cols /2;
int first_tile_row = centre_tile_row - (rng_h);

int max_row = centre_tile_row + rng_h;
int min_row = centre_tile_row - rng_h;
int max_col = centre_tile_col + rng_w;
int min_col = centre_tile_col - rng_w;

To create all the tiles we can use a two for loops, for example:

int rows = 2;
int columns = 2;

for (int r = 0; r < rows; r++){ // Loop for rows
  for (int c = 0; c < columns; c++){ // loop for columns
    // CREATE TILES HERE
    System.out.println("Row: " + r + " Column: " + c);
  }
}

This would output (2 x 2 map, 8 tiles):

Row: 0 Column: 0
Row: 0 Column: 1
Row: 1 Column: 0
Row: 1 Column: 1

The map generation works the same, its starts by creating a new tile inside of second for loop and making that WATER by default, random_water() is called to set the texture, this makes the map more interesting by varying the water image used, as the random int is 0 to 20 and only 2, 3, 4 select alternative images most water tiles will be water_01 texture.

// Create TILE
Tile tile = new Tile(col, row, chunk.tile_size, TILETYPE.WATER, random_water());

// Random Texture
private Texture random_water(){
Texture water;

int tile = MathUtils.random(20);
switch (tile) {
    case 1: water = water_01;
        break;
    case 2: water = water_02;
        break;
    case 3: water = water_03;
        break;
    case 4: water = water_04;
        break;
    default: water = water_01;
        break;
    }
    return water;
}

When looping through the tiles the max and min columns and row variables can be used to check if the current row and column are inside of values, if they are then the tile can be changed to GRASS

if(row > min_row && row < max_row && col > min_col && col < max_col){
    tile.texture = random_grass();
    tile.type = TILETYPE.GRASS;
    ..........
}

We store the lowest row of grass tiles, if we are currently processing those they we can make the type a CLIFF:

if(row == first_tile_row + 1){
  tile.texture = cliff;
  tile.type = TILETYPE.CLIFF;
} else {
  // Chance to add trees etc
}

We have to use first_tile_row + 1 as we have row > min_row and not  row >= min_row.

The code for adding the tiles to a row and adding the rows to the chunk works like this:

if current row
        add new tile to the row array
if current row and column are the final then add the row array to the chunk
else
        set current row number
        add row to chunk
        clear array row (new array)
        add tile to array row

Here is the actual code that builds the array of array of tiles:

// ADD TILE TO CHUNK
if(current_row == row){
  // Add tile to current row
  chunk_row.add(tile);

  // Last row and column?
  if (row == chunk.number_rows - 1 && col == chunk.number_cols - 1){
    chunk.tiles.add(chunk_row);
  }
} else {
  // New row
  current_row = row;

  // Add row to chunk
  chunk.tiles.add(chunk_row);

  // Clear chunk row
  chunk_row = new ArrayList();

  // Add first tile to the new row
  chunk_row.add(tile);
}

Now that the tiles all of the tiles exist the tile codes can be calculated,

for(ArrayList row : chunk.tiles){
  for(Tile tile : row){
    // Check all surrounding tiles and set 1 for pass 0 for non pass
    // 0 0 0
    // 0 X 0
    // 0 0 0

    int[] rows = {1,0,-1};
    int[] cols = {-1,0,1};

    for(int r: rows){
      for(int c: cols){
        tile.code += chunk.get_tile_code(tile.row + r, tile.col + c);
        update_image(tile);
      }
    }
  }
}

As we only have one chunk at the moment we loop all tiles in the array’s of rows, when we have multiple chunks we would need another for loop to do this for each chunk. For each tile we need to get all of the neighbouring tiles, int[] rows = {1,0,-1} these numbers are used to represent one row above, same row and the row below the current, we have the came for columns, two for loops allows us to get a reference to all eight surrounding tiles plus itself.

Once the Tile object has a code we can check if it requires an additional image, we do this by checking if the tiles code matches any in the arrays created in the earlier.

if(Arrays.asList(a_grass_left).contains(tile.code)){
  tile.secondary_texture = grass_left;
} else if (Arrays.asList(a_grass_right).contains(tile.code)){
  tile.secondary_texture = grass_right;
....

When we allow non square island shapes these arrays will be extended and more arrays needed for other edges that will be required.

Going back to the main class we need to make some changes and use this new Island class to create our map.

// Lower speed to 1
int speed = 1;

// A new Class variable Island
Island island;

// Render Loop, clear BLACK
Gdx.gl.glClearColor(0, 0, 0, 0);

// draw code - loop chunks and draw tiles
batch.begin();
// Draw all tiles in the chunk / chunk rows
for(ArrayList row : island.chunk){
  for(Tile tile : row){
    batch.draw(tile.texture, tile.pos.x, tile.pos.y, tile.size, tile.size);
    if (tile.secondary_texture != null) batch.draw(tile.secondary_texture, tile.pos.x, tile.pos.y, tile.size, tile.size);
  }
}
batch.end();

There is no culling, all tiles will be rendered, this can be addressed when there are more chunks. With the changes the main gameclass running the app should produce a map that you can move around using the arrow keys or WASD:

island

In part 3 we will refactor the images into a new class and add our hero.

Remember to check out the full source code: [ Github Repository ]

Making a LibGDX Roguelike Survival Game Part 1 #gamedev

After failing to complete the 7 Day Roguelike challenge I was left with some working code for a simple pixel art game that had the basics that might help new game developers.

I plan on developing this game further, demonstrating some basic techniques and hopefully motivate people to make their own games.

source code for this post is available on Github

Screen Shot 2017-03-16 at 00.34.48

7DRL Game

To start you will need to download LibGDX setup application and generate a new project, there is information on getting setup on the LibGDX website. I will be using Eclipse Luna as my editor.

Here is my project setup, to keep this less complicated I am only launching this application on the desktop, I used a random name generator which came up with EvoScape.

libgdx_setup.png

Once you have created and imported your project into Eclipse (Gradle Porject) or your preferred editor run the application as a Java App, you should see this:

first_run.png

If you have worked with LibGDX previously I am sure you have seen this screen many times! There are only three files changed / created for this first part of the tutorial:

DesktopLauncher.java

Add these two lines to the launcher so the game height and width are set:

config.width = 800;
config.height = 600;

gameclass.java

Apart from the standard Texture and Spritebatch variables that LibGDX add as default these class variables are defined:

OrthographicCamera camera;
Control control;

// Display Size
private int displayW;
private int displayH;

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

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

Control is our own class used to handle keyboard input, the Orthographic-camera will handle the viewport, other variables are used to hold the screen size and some temporary values to track the position of the camera.

// CAMERA
displayW = Gdx.graphics.getWidth();
displayH = Gdx.graphics.getHeight();

// For 800x600 we will get 266*200
int h = (int) (displayH/Math.floor(displayH/160));
int w = (int) (displayW/(displayH/ (displayH/Math.floor(displayH/160))));

camera = new OrthographicCamera(w,h);
camera.zoom = .4f;

// Used to capture Keyboard Input
control = new Control(displayW, displayH, camera);
Gdx.input.setInputProcessor(control);

Gdx.graphics is used to get the width and height of the screen, we have set the screen size to 800 by 600 but we can allow the user to resize the screen or go full screen, these values can later be updated when the screen size changes.

There are many ways to set up the OrthographicCamera, depending on the type of game you may want different sized viewports, check the LibGDX wiki for additional information. It is also worth looking at the viewport options but for the moment this simple setup is fine. The camera also has the ability to zoom in/out.

Before looking at the render loop of the main game class lets take a look at Control.java:

public class Control extends InputAdapter implements InputProcessor {

It is important the class that handles keyboard input extends and implements the above classes, the editor will ask us to add the unimplemented methods after we change our class to extent and implement the LibGDX classes, keyDown and keyUp are what we will use at this point. Using a simple switch statement the class booleans can be set or functions called when certain buttons are pressed/released:

switch (keycode) {
  case Keys.DOWN:
    down = false;
    break;
  case Keys.UP:
    up = false;
    break;
....

WASD and the arrow keys set the up,down,left, right values to true on press and false on release, these boolean values can be used to determine if movement should occur. Backspace is used to toggle debug, this will be useful for displaying collision hit-boxes and displaying debug info later on and esc key is set to exit the application. The other functions already added will be explained in another post.

Looking back to the gameclass.java file and the render funciton:

// GAME LOGIC
// Reset the direction values
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.x += direction_x * speed;
camera.position.y += direction_y * speed;
camera.update();

// GAME DRAW
batch.setProjectionMatrix(camera.combined);
batch.setBlendFunction(GL20.GL_SRC_ALPHA, GL20.GL_ONE_MINUS_SRC_ALPHA);

batch.begin();
batch.draw(img, 0, 0);
batch.end();

The render function is called 60 times every second, LibGDX defaults to 60 FPS. Here we reset the current direction in x (horizontal) and y (vertical) to 0, then given up, down, left, right are pressed (checked via the Control Class) the direction variables are set accordingly, the camera x and y positions are added to using the value and a speed multiplier. After changing the camera in anyway we have to call .update() for the changes to be applied to the camera.

The SpriteBatch projection is then set to that of the camera before drawing the default LibGDX logo, running the application you should be able to move the camera arond and exit using esc:

controls.gif

In part two we will look at creating a small island, using a simple chunk system.

 

 

 

Zero Hour Gamedev

I have been toying with Java game code for a few years now, entered a few game jams and started multiple projects that are all on hold, this has all been a learning expereince but it is time to create a game how ever long that takes! With a young baby to care for I only find the odd hour to write code.

I would like to make a top down shooter, inspired by retro games such as Chaos Engine, Universal Warrior, Micro Machines, GTA 1 but also newer titles like Nuclear Throne. At the moment I have the start of some systems; vehicle (7 types), lighting, chunk/map, player, inventory and time.

All the Gifs!

Box2D is a great 2D physics engine ported to LiGDX, I followed this tutorial to make a vehicle, well a box with 4 wheels that sort of acted like a car. Here you are seeing two scenes being rendered, Box2D’s debug renderer showing the outlines of bodies and also a separate 3D camera overlaying 3D objects:

I then created some vehicles to replace the debug lines, these are just concepts at the moment and need work:

I have never really played with 3D but as I only really need to use 3D as a visual overlay its not too difficult. I implemented a cube builder which creates a cube made up of many other smaller cubes, the function shown here generates a cube split by a random number, I considered a Minecraft style method of building the environment, tested out culling/caching models so this would run for large cities. Once I have a clearer vision for the style of the game then I can create some 3D objects and texture/skin them.

Damage is not currently visible but I have deferred the Box2D listener events to the car class collision object, this captures what was collided with and the speed of the collison. I then got carried away with Box2D joints and started to make all sorts of weird trailers and trains but only shared the caravan, it handles terrible but will have some purpose in the game:

Next I experimented with lighting, Box2D lights is simply to use and works well with Box2D objects had some fun revisiting trig to calulate the position of the light in relation to the car:

Not sure the lighting suits a pixel art game, I posted on Java Gaming for some advice with Nuclear Throne style lights, Orange Pascal the developer behind so many great games (orangepixel.net) linked me to a tutorial he had posted, I have not really experimneted much with this but it works. There is a day/night cycle in place at the moment, I have to keep the 2D and 3D lighting in sync to achive this but that is pretty straight forward.

This is all I have at the moment, had a lot of fun prototyping, a long way to go but feel this is worth this is the type of game I would like to commit too.

It is ok to fail #7DRL

After noticing some Twitter friends were taking part in a seven day rogue-like challenge I decided to give it a go, knowing that I would fail from the start. I have a 6 month old daughter who takes up all of my time but I do have the odd hour to dev at night… rather than sleep!

My idea was a simple rogue-like, as you play and level up a random island that you start on grows in size and spawns new items and resources.

I created a simple chunk manager which only held one chunk; an array of tiles. Each tile has a texture(s) and also a box2D collision box. I decided to use box2D to manage the collisions rather than roll my own solution.

Found a nice Tileset on Open Game Art and started replacing water and grass tile placeholders; made a good start at using all of the tileset:

Made a start adding random items to the map (trees) and notifying the objects of collisions via box2D collision listeners:

Screen Shot 2017-03-16 at 00.34.48

Given I was only spending an hour or two each evening working on this I made some decent progress and made sure the code was clean and efficient, only actually managed 3/4 days out of the seven but am happy with what I got done and will work on this along side other prototypes.

I enjoyed starting a project from scratch and learning more about box2D collisions, there are some great tutorials available at iForce2D, worth checking out. There is no harm in starting something you know you will fail from the start given you learn by doing so.

Hacking my baby cam (Motorola MBP853)

Late August my daughter was born, I bought a wifi webcam to put into her room, one which boasted a feature packed mobile phone app for remote viewing, pan, tilt, room temperature and more.

motorola-focus-85-wi-fi-camera

The mobile app to control this webcam was broken from day one, the service did come back online a few days later and has worked quite well since but I had to question what I would do if the camera connectivity software failed.

I decided to find out how to use the camera as a dedicated IP device, there was no information from the manual or the supplier so I went digging.

 

Find the IP
My first step was to check my router maintenance page to identify the device IP address, this was the only unknown item in the list:

Screen Shot 2017-01-11 at 22.07.21.png

Using the Mac Network Utiliy I scanned the IP and discovered a web service on port 80:

Port Scan has started…

Port Scanning host: 192.168.0.30

Open TCP Port: 80     http

screen-shot-2017-01-11-at-22-07-55

Test Page
After playing (tried a few obvious page names) about I discovered a file “http://192.168.0.30/test.html“, this appeared to be a test page for the webcam, probably used at the factory to ensure the camera is fully functioning, although the video did not load I was able to move the camera, although the move function had no auto stop and the servo sounded like it might break!

screen-shot-2017-01-11-at-22-08-54

Clicking the centre arrow stopped the camera from trying to over rotate, at this point I was a little worried that a page existed with full access to a camera which would be pointed at my child, all you needed was access to the local network.

Viewing the source of the page its quite easy to see the available functions and how to control the camera:
screen-shot-2017-01-11-at-22-10-36

The send_command function code: AJAX_get(‘/?action=command&command=’+ cmd)

The video player which did not function showed us the URL required to watch the stream although it is hardcoded “rtsp://192.168.193.1:6667/blinkhd”.

screen-shot-2017-01-11-at-22-11-12
Updating the IP I was unable to view the video as it was secured, I put the URL into Google and came across an article with much more detail about hacking the a similar Motorola camera http://atom0s.com/forums/viewtopic.php?t=45

Wifi Setup
 It is possible to configure the network settings via wifisetup.html:

Screen Shot 2017-01-11 at 22.28.33.png

Viewing the Video on a Mobile

The article tells you that the video can be viewed if you pass the credentials: rtsp://user:pass@192.168.137.36:6667/blinkhd

The Real Time Streaming Protocol (RTSP) is a network control protocol designed for use in entertainment and communications systems to control streaming media servers. The protocol is used for establishing and controlling media sessions between end points.

wikipedia

Searching the Apple App Store for RTSP you will find several viewers, adding the correct URL to the app I installed on my iPhone made it possible to view the camera feed, while a username and password was required it was very insecure and every device would have the same config.

image_uploaded_from_ios_1024

Conclusion
I now have a method to use and configure my webcam without relying on the Hubble software, this is especially useful when the service is down or if it is every pay to use.

The device needs to be made more secure, I will look into changing the username and password or contact the supplier to see if they will provide firmware updates, these test files should not have been left on the device.

I have the option to use the feed on a spare monitor in my study which will be useful or even produce my own apps.

 

 

 

#Octobit Pixel Art – A month of pixels

I have been away from game development for a while, created the odd pixel art for the daily challenge but have had other work keeping me away. With said work about to finish I can finally get back to the hobbies I love, pixels and code!

To celebrate my return and to get back into the creative mood I am going to give #Octobit a go (31 days of pixels). I will try to throw in some simple LibGDX browser protypes along the way.

I have had a look back at some work I am most proud of:

Scuba – I made this in about 15 minutes, its one of my more viewed pieces due to being shared by 8BitPorn.
View on Twitter

When Ron Gilbert re-tweeted this think I smiled for a week!
View on Twitter

My first game attempt, part wrote my own Java server which cost me some money (AWS free is not free when you thrash the bandwidth) one day I will revisit this game but it will not be multiplayer.
View on Twitter

Ben Porter’s Moonman for Pixel Dailies – you should take a look at Ben on Twitter, look forward to playing this game!
View on Twitter

Was a big fan of Nucleur Throne and Vlambeer pixel art style
View on Twitter

Really loved the Lion King movie, starburst colours for pixel daily.
View on Twitter

Next project – Working on a simple browser game, a tiny island that grows as you progress. At the moment just an art concept and small amount of code.
View on Twitter