I don't really have any more tutorial ideas, so for now, I'm just sticking to making games. My current project is a top-down shooter. It's in very early stages. I've already thought up most of the game mechanics, but have yet to implement them.
The game is called Psytech because apparently people in the future have
some kind of psychic abilities, although weak. Psytechs are soldiers
with strong psychic abilities amplified by technology.
This is a sort of single player horde mode, where you have to survive a certain number of waves to finish a match. You always start out at level 1, and gain exp by killing enemies. Every level up boosts your stats. You may also earn skill points.
The skills have a tree structure, so you need to plan out which path down the skill tree to take. You can focus on passive abilities to boost weapon damage, or spec for offensive Psykinetic abilities. Weapons and their attachments are also suited to different play styles.
Like I said, every match starts the player at level 1. However, there is also persistent rank. This is the exp you gain after a match. Higher rank means more weapons and attachments. I haven't fully thought this out yet so I'm not sure. This is kinda far into the future.
My next goal is to get the skill system working.
Sunday, March 23, 2014
Monday, March 17, 2014
Block Bunny
This is a tutorial game for getting familiar with Box2D basics and LibGDX's Tiled API.
The point of the game is to get the bunny to the end by jumping and switching block colors. You can only run over blocks that are the same color you currently have selected in the top left.
Press Z to jump, and X to change color.
I only put 5 maps in there, but you can make your own. To make maps, you need three tile layers named "red", "green", and "blue" and two object layers named "crystals" and "spikes". Put all your red/green/blocks in the appropriate layer. You can simply place any object in the crystals and spikes layer to add them. The only thing I grab from these objects is their position.
You can watch the tutorial if you want:
https://www.youtube.com/watch?v=85A1w1iD2oA
Game:
https://dl.dropboxusercontent.com/u/59779278/libgdxtutorials/Block%20Bunny/Block%20Bunny%20Game.rar
Source code:
https://dl.dropboxusercontent.com/u/59779278/libgdxtutorials/Block%20Bunny/Block%20Bunny%20Full.rar
The point of the game is to get the bunny to the end by jumping and switching block colors. You can only run over blocks that are the same color you currently have selected in the top left.
Press Z to jump, and X to change color.
I only put 5 maps in there, but you can make your own. To make maps, you need three tile layers named "red", "green", and "blue" and two object layers named "crystals" and "spikes". Put all your red/green/blocks in the appropriate layer. You can simply place any object in the crystals and spikes layer to add them. The only thing I grab from these objects is their position.
You can watch the tutorial if you want:
https://www.youtube.com/watch?v=85A1w1iD2oA
Game:
https://dl.dropboxusercontent.com/u/59779278/libgdxtutorials/Block%20Bunny/Block%20Bunny%20Game.rar
Source code:
https://dl.dropboxusercontent.com/u/59779278/libgdxtutorials/Block%20Bunny/Block%20Bunny%20Full.rar
Friday, February 21, 2014
LibGDX + Box2D + Tiled
Well, it's been a while. I just finished the LibGDX Asteroids game.
I probably won't be going back to Java 2D. I said that I would try to get a LibGDX Box2D and Tiled tutorial up and running, but of course, before I start my tutorials, I need to actually have a game for it. I'm still in the process of figuring out the best way to integrate Box2D and Tiled maps.
The game I'm going to use for this future tutorial is this simple, get-to-the-end-of-the-level, platformer: GIF 1.6MB
Some of the things I want to cover in the tutorial are:
- how to use the Tiled software
- how to use the LibGDX Tiled API to read the Tiled maps
- how to use Box2D (this is the big one)
---- adding bodies to the world
---- creating and customizing fixtures
---- converting to Box2D units
---- filter collision
---- contact listeners
I got most of the main game mechanics already finished. I should have the game done soon, or at least enough of it done to start recording the tutorial.
I probably won't be going back to Java 2D. I said that I would try to get a LibGDX Box2D and Tiled tutorial up and running, but of course, before I start my tutorials, I need to actually have a game for it. I'm still in the process of figuring out the best way to integrate Box2D and Tiled maps.
The game I'm going to use for this future tutorial is this simple, get-to-the-end-of-the-level, platformer: GIF 1.6MB
Some of the things I want to cover in the tutorial are:
- how to use the Tiled software
- how to use the LibGDX Tiled API to read the Tiled maps
- how to use Box2D (this is the big one)
---- adding bodies to the world
---- creating and customizing fixtures
---- converting to Box2D units
---- filter collision
---- contact listeners
I got most of the main game mechanics already finished. I should have the game done soon, or at least enough of it done to start recording the tutorial.
Saturday, October 5, 2013
Camera Scrolling
This is the second part of the TileMap in depth explanation.
A preface first: I want to say that in retrospect, I should have probably created a Camera class rather than rely on the TileMap to be the camera. The scrolling concept remains the same though.
I just remembered, I created an image explanation for scrolling.
The basic concept is that there are two different coordinates: the game coordinates, and the screen coordinates. Whenever I draw to the screen, I first have to translate everything over from game position to screen position.
So instead of drawing at say:
g.drawImage(image, x, y, null);
I draw at:
g.drawImage(image, x - cameraX, y - cameraY, null);
If anyone's ever done OpenGL, it's similar to applying the (model)view matrix to transform game coordinates to camera space.
A preface first: I want to say that in retrospect, I should have probably created a Camera class rather than rely on the TileMap to be the camera. The scrolling concept remains the same though.
I just remembered, I created an image explanation for scrolling.
The basic concept is that there are two different coordinates: the game coordinates, and the screen coordinates. Whenever I draw to the screen, I first have to translate everything over from game position to screen position.
So instead of drawing at say:
g.drawImage(image, x, y, null);
I draw at:
g.drawImage(image, x - cameraX, y - cameraY, null);
If anyone's ever done OpenGL, it's similar to applying the (model)view matrix to transform game coordinates to camera space.
TileMap in depth
I didn't really explain how my TileMap class works, so I'll go into more detail here. If you want to follow along, I'm using the TileMap class from: https://dl.dropboxusercontent.com/u/59779278/Dragon%20Tale%20Tutorial%20P02.rar
First, I'll go over the fields.
// position
private double x;
private double y;
This is self-explanatory. These two variables indicate the top left corner of the TileMap. As the player moves to the right, the TileMap moves to the left, ie: x decreases.
// bounds
private int xmin;
private int ymin;
private int xmax;
private int ymax;
These are the minimum and maximum bounds of the map. The position (x, y) cannot go further than these limits. This prevents the "camera" from scrolling past the edges of the TileMap.
private double tween;
This is a factor between 0 and 1 that indicates the speed in which the TileMap's position changes. A tween of 1 means that the TileMap will move to a given position instantly, where as a tween of 0.1 means that the TileMap will move 10% towards a given position. This gives a smoother scrolling effect.
// map
rivate int map[][];
private int tileSize;
private int numRows;
private int numCols;
private int width;
private int height;
The map is simply a 2d array of integers, where each integer represents a tile from the tileset. The tileSize is the size of a single tile in pixels. numRows and numCols are the number of rows and columns of the map. width and height are the dimensions of the map in pixels.
// tileset
private BufferedImage tileset;
private int numTilesAcross;
private Tile[][] tiles;
The tileset is the entire tileset image. From that, I read each individual tile subimage, and store it in the tiles array. The numTilesAcross is used to calculate the "id number" of the tiles.
// drawing
private int rowOffset;
private int colOffset;
private int numRowsToDraw;
private int numColsToDraw;
These are for drawing. They indicate the row and column that drawing should start, and how many rows and columns to draw. This is so that only part of the TileMap on the screen gets drawn, rather than the entire TileMap. (With respect to drawing, these variables aren't important because the Graphics object has a device clip, which prevents any drawing from happening outside of the Graphics' device's visible region. But from a complexity point of view, it does reduce the time from O(n^2).)
The constructor is simple. It sets the tileSize, the tween, and the number of rows and columns to draw.
The loadTiles(String s) method reads in the tileset and cuts out each individual tile to put into the tiles array. My TileMap class isn't very scalar, in that it has a specific way of handling tilesets. The tileset image must always have 2 rows of tiles. The top row are all the non-blocked tiles, and the bottom row are all the blocked tiles.
The loadMap(String s) methods fills in all the field variables under // map. The map file contains the number of rows and columns of the map, and the map itself, a 2d array of integers. I get the numRows, numCols, width, height, and bounds of the map.
Then there are a few getters and setters. Simple.
Next is the setPosition(double x, double y) method. This method tries to move the TileMap's (x, y) position to the given destination (x, y). This is where tween kicks in to smoothly move the TileMap to the destination. Then I make sure the position doesn't go past the bounds using fixBounds() and then calculate the row and column offsets to know where to start drawing.
The last thing is the draw(Graphics2D g) method. This is a straight forward 2d array loop. I loop through the map array starting with the rowOffset and colOffset, up to the specified numRowsToDraw and numColsToDraw. Now remember the map array contains integers of tileset "id numbers." I have to calculate, say, the id number 24 into row 2 column 4 (see tileset image above.) Since I know the numTilesAcross of the tileset, I can easily translate the id number using:
int idNumber = map[row][col];
int translatedRow = idNumber / numTilesAcross;
int translatedCol = idNumber % numTilesAcross;
Then I just draw the given tile at the correct position and that's it.
Hopefully, this answers some questions about the TileMap. I'll make a separate post about the "camera" scrolling.
First, I'll go over the fields.
// position
private double x;
private double y;
This is self-explanatory. These two variables indicate the top left corner of the TileMap. As the player moves to the right, the TileMap moves to the left, ie: x decreases.
// bounds
private int xmin;
private int ymin;
private int xmax;
private int ymax;
These are the minimum and maximum bounds of the map. The position (x, y) cannot go further than these limits. This prevents the "camera" from scrolling past the edges of the TileMap.
private double tween;
This is a factor between 0 and 1 that indicates the speed in which the TileMap's position changes. A tween of 1 means that the TileMap will move to a given position instantly, where as a tween of 0.1 means that the TileMap will move 10% towards a given position. This gives a smoother scrolling effect.
// map
rivate int map[][];
private int tileSize;
private int numRows;
private int numCols;
private int width;
private int height;
The map is simply a 2d array of integers, where each integer represents a tile from the tileset. The tileSize is the size of a single tile in pixels. numRows and numCols are the number of rows and columns of the map. width and height are the dimensions of the map in pixels.
// tileset
private BufferedImage tileset;
private int numTilesAcross;
private Tile[][] tiles;
The tileset is the entire tileset image. From that, I read each individual tile subimage, and store it in the tiles array. The numTilesAcross is used to calculate the "id number" of the tiles.
// drawing
private int rowOffset;
private int colOffset;
private int numRowsToDraw;
private int numColsToDraw;
These are for drawing. They indicate the row and column that drawing should start, and how many rows and columns to draw. This is so that only part of the TileMap on the screen gets drawn, rather than the entire TileMap. (With respect to drawing, these variables aren't important because the Graphics object has a device clip, which prevents any drawing from happening outside of the Graphics' device's visible region. But from a complexity point of view, it does reduce the time from O(n^2).)
The constructor is simple. It sets the tileSize, the tween, and the number of rows and columns to draw.
The loadTiles(String s) method reads in the tileset and cuts out each individual tile to put into the tiles array. My TileMap class isn't very scalar, in that it has a specific way of handling tilesets. The tileset image must always have 2 rows of tiles. The top row are all the non-blocked tiles, and the bottom row are all the blocked tiles.
The loadMap(String s) methods fills in all the field variables under // map. The map file contains the number of rows and columns of the map, and the map itself, a 2d array of integers. I get the numRows, numCols, width, height, and bounds of the map.
Then there are a few getters and setters. Simple.
Next is the setPosition(double x, double y) method. This method tries to move the TileMap's (x, y) position to the given destination (x, y). This is where tween kicks in to smoothly move the TileMap to the destination. Then I make sure the position doesn't go past the bounds using fixBounds() and then calculate the row and column offsets to know where to start drawing.
The last thing is the draw(Graphics2D g) method. This is a straight forward 2d array loop. I loop through the map array starting with the rowOffset and colOffset, up to the specified numRowsToDraw and numColsToDraw. Now remember the map array contains integers of tileset "id numbers." I have to calculate, say, the id number 24 into row 2 column 4 (see tileset image above.) Since I know the numTilesAcross of the tileset, I can easily translate the id number using:
int idNumber = map[row][col];
int translatedRow = idNumber / numTilesAcross;
int translatedCol = idNumber % numTilesAcross;
Then I just draw the given tile at the correct position and that's it.
Hopefully, this answers some questions about the TileMap. I'll make a separate post about the "camera" scrolling.
Friday, September 27, 2013
State Based AI
I want to explain a little bit about FSM based AI. The concept is simple: an AI has a set of behaviors, and acts on a behavior depending on certain conditions. The enemies in Cranky Rampage all use this method.
The Sentry is your basic cannon fodder enemy. It can be in any of three states:
private int state;
private final int MOVING_TO_PLAYER = 0;
private final int SHOOTING = 1;
private final int COOLDOWN = 2;
When in the MOVING_TO_PLAYER state, the Sentry will simply try to get closer to the player. Once it reaches a certain proximity, it will move on to the SHOOTING state. Here, it will stop moving and fire a bullet. Then it will move into the COOLDOWN state where it will wait for some time. I have to find the edges in this FSM, meaning I have to find which states can transition to which other states.
MOVING_TO_PLAYER transitions to SHOOTING, SHOOTING transitions to COOLDOWN, and COOLDOWN can either go back to MOVING_TO_PLAYER or SHOOTING. So here's our list of edges for the graph:
MOVING_TO_PLAYER --> SHOOTING : if within range
SHOOTING --> COOLDOWN
COOLDOWN --> MOVING_TO_PLAYER : if out of range
COOLDOWN --> SHOOTING : if within range
Now coding the Sentry's AI is simple.
if(state == MOVING_TO_PLAYER) {
if(player.getx() < x) {
left = true;
right = false;
}
else if(player.getx() > x) {
left = false;
right = true;
}
if(Math.abs(player.getx() - x) < range) {
state == SHOOTING;
}
}
else if(state == SHOOTING) {
left = right = false;
GameObjectFactory.createBullet(...);
state = COOLDOWN;
}
else if(state == COOLDOWN) {
timer++;
if(timer > time) {
timer = 0;
if(Math.abs(player.getx() - x) < range) {
state = SHOOTING;
}
else {
state = MOVING_TO_PLAYER;
}
}
}
This is an easy way to give your NPCs some behavior. State based AI is simple to implement and can be effective.
The Sentry is your basic cannon fodder enemy. It can be in any of three states:
private int state;
private final int MOVING_TO_PLAYER = 0;
private final int SHOOTING = 1;
private final int COOLDOWN = 2;
When in the MOVING_TO_PLAYER state, the Sentry will simply try to get closer to the player. Once it reaches a certain proximity, it will move on to the SHOOTING state. Here, it will stop moving and fire a bullet. Then it will move into the COOLDOWN state where it will wait for some time. I have to find the edges in this FSM, meaning I have to find which states can transition to which other states.
MOVING_TO_PLAYER transitions to SHOOTING, SHOOTING transitions to COOLDOWN, and COOLDOWN can either go back to MOVING_TO_PLAYER or SHOOTING. So here's our list of edges for the graph:
MOVING_TO_PLAYER --> SHOOTING : if within range
SHOOTING --> COOLDOWN
COOLDOWN --> MOVING_TO_PLAYER : if out of range
COOLDOWN --> SHOOTING : if within range
Now coding the Sentry's AI is simple.
if(state == MOVING_TO_PLAYER) {
if(player.getx() < x) {
left = true;
right = false;
}
else if(player.getx() > x) {
left = false;
right = true;
}
if(Math.abs(player.getx() - x) < range) {
state == SHOOTING;
}
}
else if(state == SHOOTING) {
left = right = false;
GameObjectFactory.createBullet(...);
state = COOLDOWN;
}
else if(state == COOLDOWN) {
timer++;
if(timer > time) {
timer = 0;
if(Math.abs(player.getx() - x) < range) {
state = SHOOTING;
}
else {
state = MOVING_TO_PLAYER;
}
}
}
This is an easy way to give your NPCs some behavior. State based AI is simple to implement and can be effective.
Sunday, September 22, 2013
Cranky Rampage
I seriously never would have thought my channel would get so many subscribers. As of this post, I'm sitting at 865. I remember back when I posted a few videos about setting up a game with only a few video views and a couple subs. I was pretty content with that. It's just been crazy now.
Unfortunately I don't have any more tutorial ideas. So this is probably the end of that run. The only thing left is to just make some games.
I recently got started on a new game: Cranky Rampage. It's about a guy who just wants to get some sleep, but the alien invasion is making too much noise, so he decides to do something about it. This game is a throwback to arcade platform shoot em ups.
I'm hoping to get a demo + source released soon.
Lol nope. I've stopped working on it. Here's the source. You can dissect it if you want.
https://dl.dropboxusercontent.com/u/59779278/games/Cranky%20Rampage.rar
Unfortunately I don't have any more tutorial ideas. So this is probably the end of that run. The only thing left is to just make some games.
I recently got started on a new game: Cranky Rampage. It's about a guy who just wants to get some sleep, but the alien invasion is making too much noise, so he decides to do something about it. This game is a throwback to arcade platform shoot em ups.
https://dl.dropboxusercontent.com/u/59779278/games/Cranky%20Rampage.rar
Subscribe to:
Posts (Atom)






