Introduction
Dynamic
This will be a dynamic tutorial, meaning that I will keep changing and editing it on the demand of the users. So this tutorial will probably never finish (Unless I’m getting bored of writing it). Also, this tutorial will probably never be totally finished.
I’m not perfect
I’m not perfect, like almost everybody. First of all, I’ll probably have a large amount of spelling mistakes, and grammar incorrectness. Second, my code might be obsolete and badly written. But at least I can assure you that it will work! If you see anything that I could’ve done different, then please say so! So that I can change the tutorial to a better version
Coverage
I will cover a few aspects of a basic adventure/RPG game. Of course the aspects can be used in almost every game!
Basic thoughts
Classes & Roles
The first thing i mostly do when designing a game, is thinking of a data-flow. Why? Because while doing this it will give you a much better vision what you should do, how you want the data to go, and the most important bit, what classes you will need. Ive made a simple one quickly (Also, my paint skills are medal worthy!
http://img32.imageshack.us/img32/5241/dataflow.png
With send image, i more mean retrieve image. Now we can prepare our classes. As you can see we need a couple of classes:
Main
This class will basically start the whole process. The engine will keep running in the background. Meaning that we will have to make it a threat (multithreading). However we need to start this thread from some place, we will start the thread in the main (you could also do it in the engine class itself, but I like it a bit more ordered. So go ahead, make a new class, and call it main. Now be sure to generate the Main(arg) function with it as well! If, for some reason, you cant generate the Main, copy and paste mine(this is my entire main class):
public class Main{
public static void main(String [] args){
System.out.println("Application, started!");
}
}
Now we’ve got our first class. But in order to start our engine class, we first have to make it multithread compatible. Ill cover this in the next class.
Engine
This class will make sure everything will get updated every tick. And will make sure that the screen will render when its necesary. First of all, engine is a name not used often for this purpose)because an engine could be anything, it could be the engine of a car. Or used for inheritance (being the superclass). So let’s give it a different name, Game would fit for this purpose. So go ahead and make a new class, called Game. First we will have to make it multithreading in some way, there are multiple ways of doing this. You can either extend your class with the class Thread, so you can use its functinos trough inheritance. Or you can implement Runnable. I will go for runnable, there is however no difference between these two(as far as im concerned). So what you have to do now is implement Runnable. Your class should now look something like this:
Public class Game implements Runnable{
}
Now because we implemented runnable, we have a new function to use. Namely run(). This function will have to be a loop, which will update the game according to its game-state. Now for the time being, make It an endless ‘while’ loop, with an println function in it. Just for testing purposes. It should be along the lines of:
public class Game implements Runnable{
public void run(){
while(true)
System.out.println(" While ! ");
}
}
But now we have to start the thread. If you look back to our dataflow, you see that this will be the purpose of my main class. You can start an object of a class really easily! All we have to do is declare our object, and then execute the run() function. The execution of the run function is done a little bit different, instead of using: object.run(); we will use object.start(). This will start the thread and the whole process. You should have this now:
public class Main{
public static void main(String [] args){
Game ex = new Game(); //Creates new object of type Game, and name it ex.
new Thread(ex).start(); //Start this so called ex object.
}
}
Now as you start your application, it will automaticly start the game thread. Which will keep printing out messages as you can see. This is the first step of our tutorial. I will explain what we will do here later on.
Player
This class will be the player, it will react on Key presses (move in the right direction) and it will check for collisions. It will update every tick from the engine. How we will do these things I shall explain later. Before we make our player class, let’s think for a moment what we need in it. First of all we need to be able to retrieve the location of the player (x,y) for drawing purposes. Secondly we need an update function which will move the player, if it has to be moved, which will attack, if it has to attack, and which will check if the player is actually still alive. Thirdly we need 4 functions which can set the directions.
So our class will look like this:
public class Player {
//variables which we will use
private int x, y;
private boolean left, right, up, down;
public void update() {
//In this function we will do the required checking and updates
}
//These 4 functions are able to set the direction
public void setLeft (boolean newLeft ){
left = newLeft;
}public void setUp (boolean newUp ){
up = newUp;
}public void setDown (boolean newDown ){
down = newDown;
}public void setRight(boolean newRight){
right = newRight;
}
//This function will return X as an int.
public int getX(){
return x;
}
//And this function will return Y as an int.
public int getY(){
return y;
}
}
Now we’ve got the basics. But the player wont move with this just yet. For that we need a move function. So lets do this, we will make a simple move function. We will make it private, since there is no need for other classes to acces it, and i twill be of type void ofcourse, since there is nothing to return in this function.
//In this function we will do the required checking and updates
public void update() {
move();
}
//This function will move the player according to its direction
public void move(){
if(left){
x--;
}if(right){
x++;
}if(up){
y--;
}if(down){
y++;
}
}
This will work, will be very buggy, but it will work. I’ll explain a more advanced movement system later on, which wont be very buggy.
Instances
This class will contain the arrayLists to objects. Why? Because we have to retrieve information about our objects somewhere, but at the same time we’ll also need to add new objects to the same arrayList. So we will have to make them static. But we don’t only need arrayLists. We also need to add our player here. Lets do that first. First of all, create a class and name it Instances. You’ll end up with something like this:
public class Instances {
}
Now we have our class. Lets add our first object to it! We want to add the player first. This can be done very easily with the following line:
public static Player player = new Player();
You should add this line in the body of your instances class.
Now we can acces it from anywhere we want. All we have to do is: Instances.player.[function here];.
Later on I will explain what more objects we need in this class, and how we have to handle that. But for now this is enough.
Input Manager
This class will handle the input. We want to make our player move, as soon as we hit the up arrow on the keyboard. But how is this done? Don’t worry! Java has a lot of functions and classes build in already. It even has a class which will handle key input! All we have to do if check if the key input is being pressed or released. And what key this might be. So lets go and make our ButtonHandler class! First in order to use the easy functions, we will have to inherite the java class “KeyAdapter” and we will have to import 2 headers. Your class should now look like this:
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
public class ButtonHandler extends KeyAdapter {
}
Now i like it to have some debugging in it as well, so i added a constructor, with a simple System.out.println(“”); in it. So go ahead and add the following to your class:
public ButtonHandler() {
System.out.println(" Button handler initialised! ");
}
Now as soon as we make an object from this class, a message will pop up in our eclipse.
Now in order to make use of our KeyAdapter, we will have to add 3 functions. 2 of the 3 we will use. Add the following functions:
public void keyTyped(KeyEvent arg0) {
//This one we wont use. Its unreliable for making a game handler
}
//This function will be used as soon as a key is released. they KeyEvent key we can use to determine what key we just released
public void keyReleased(KeyEvent key) {
}
//This function will be used as soon as a key is pressed.
public void keyPressed(KeyEvent key) {
}
Now in order to determine what kind of key we just pressed/released, we will need a couple of statements. Or we could use the switch statement. I prefer to use the switch statement because your program will look much more organised then. Basicaly if we press the left arrow key, then the keycode from ‘key’ from KeyEvent will be equal to VK_LEFT. So we need something along the lines of:
If(key.getKeyCode == VK_LEFT){
Instances.player.setLeft(true);
}
And in the key release function it would be:
If(key.getKeyCode == VK_LEFT){
Instances.player.setLeft(false);
}
So this brings us to the following code:
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
public class ButtonHandler extends KeyAdapter {
public ButtonHandler() {
System.out.println(" Button handler initialised! ");
}
//This function will be used as soon as a key is released.
public void keyPressed(KeyEvent key) {
switch (key.getKeyCode()) {
case KeyEvent.VK_UP:
Instances.player.setUp(true);
break;
case KeyEvent.VK_DOWN:
Instances.player.setDown(true);
break;
case KeyEvent.VK_LEFT:
Instances.player.setLeft(true);
break;
case KeyEvent.VK_RIGHT:
Instances.player.setRight(true);
break;
}
}
//This function will be used as soon as a key is released. they KeyEvent key we can use to determine what key we just released
public void keyReleased(KeyEvent key) {
switch (key.getKeyCode()) {
case KeyEvent.VK_UP:
Instances.player.setUp(false);
System.out.println(" Released UP!");
break;
case KeyEvent.VK_DOWN:
System.out.println(" Released DOWN!");
Instances.player.setDown(false);
break;
case KeyEvent.VK_LEFT:
System.out.println(" Released LEFT!");
Instances.player.setLeft(false);
break;
case KeyEvent.VK_RIGHT:
System.out.println(" Released RIGHT!");
Instances.player.setRight(false);
break;
}
}
public void keyTyped(KeyEvent key) {
}
}
However, we still need to make the object somewhere. We will do this as soon as our screen is getting initialized. I will cover this in the next class.
Draw
Ok, most of the basic game play is done. But now we want to draw it to the screen! First of all we need to make the class. So go ahead and make a new class and call it Draw. Also make a constructor in it, we will use this for setting up everything. It should be like this:
public class Draw{
Draw(){
}
}
Now we will prepare our screen so that we can draw on it. We will do this in Java2D. But you can of course also follow another tutorial for this which will cover other libraries. I wont cover much of the drawing, since its library based. So instead i will post some code and comment it (Unless people really want me to explain in detail). This is what my Draw class looks like(taken from another tutorial on this site, i believe written by either ra4king or riven. props to them! ):
import java.awt.Canvas;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics2D;
import java.awt.image.BufferStrategy;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class Draw{
JFrame frame;
Canvas canvas;
BufferStrategy bufferStrategy;
private int WIDTH = 640;
private int HEIGHT = 480;
Draw(){
//Makes a new window, with the name " Basic game ".
frame = new JFrame("Basic Game");
JPanel panel = (JPanel) frame.getContentPane();
panel.setPreferredSize(new Dimension(WIDTH, HEIGHT));
panel.setLayout(null);
canvas = new Canvas();
canvas.setBounds(0, 0, WIDTH, HEIGHT);
canvas.setIgnoreRepaint(true);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.pack();
//this will make the frame not re-sizable
frame.setResizable(false);
frame.setVisible(true);
//this will add the canvas to our frame
panel.add(canvas);
canvas.createBufferStrategy(2);
bufferStrategy = canvas.getBufferStrategy();
//This will make sure the canvas has focus, so that it can take input from mouse/keyboard
canvas.requestFocus();
//this will set the background to black
canvas.setBackground(Color.black);
// This will add our buttonhandler to our program
canvas.addKeyListener(new ButtonHandler());
}
void render() {
Graphics2D g = (Graphics2D) bufferStrategy.getDrawGraphics();
g.clearRect(0, 0, WIDTH, HEIGHT);
render(g);
g.dispose();
bufferStrategy.show();
}
protected void render(Graphics2D g){
//Here we will render everything
}
}
Now we want to draw a rectangle on the place where our player is. Why a rectangle? Because this is easy to set up, easy to draw and easy for debugging. Later in this tutorial i will explain how to work with images. Java2d has a fairly easy function to draw a rectangle, namely the following:
g.fillRect(X position, Y position, Length, Height)
For this example we will use a fixed length and height, we will set it to 15. Now we also need to give it a color. That can be done by:
g.setColor(Color.white)
Now we need to draw it at the player’s x and y coordinates. How can we do this…?
Remember that we made the player in the Instances class static? we can easily aces it from anywhere now. All we have to do is:
Instances.player.getX();
and
Instances.player.getY();
So lets go ahead and do that. your render(Graphics2D g) should end up looking like this:
protected void render(Graphics2D g){
g.setColor(Color.white);
g.fillRect(Instances.player.getX(), Instances.player.getY(), 15, 15);
}
Now this is done. Lets move on and make sure everything will get updated!
Game-Loops
So we have got our classes now. But now we have to make sure the player gets updated every once in a while. For now, lets do it VERY simple and VERY wrong. This code wont serve well, at all. In my next update I will cover a good game loop, which is stable, efficient and which will have the same effect on all computers, fast or slow.
Remember that we made our Game class? Now go back to there. In the run you’ll find a while(1) System.out.println(“Thread”);
But instead of printing a line to the console, we want to move our player! Remember that our Instances class has a static Player object? we will update this one every 10 milliseconds. It is actually fairly easy. All you have to do is change:
public void run(){
while(true)
System.out.println(" While ! ");
}
into:
public void run(){
while(true){
Instances.player.update();
try {Thread.sleep(10);} catch (InterruptedException e) {e.printStackTrace();}
}
}
Now this is VERY inefficient. Also you will see that it wont work! you wont see the player moving. This is because we also have to draw everything on the screen. For this we will have to make an object of type Draw. this is easily done by adding this in the Game class:
Draw drawing = new Draw();
Now the last thing we have to do, is actually make it render once in 10 seconds as well. This is easily done by adding the following line to our while loop:
drawing.render();
. Our final run function will look like this:
public void run(){
while(true){
Instances.player.update();
drawing.render();
try {Thread.sleep(10);} catch (InterruptedException e) {e.printStackTrace();}
}
}
If enough people comment on this (so that i actually know that people want to know how it goes on) then I’ll have the next part done on Friday!
Also, don’t forget to give me a nice medal if this helped you!
And many thanks for JGO. where i learned a lot about this, and got some code off as well.
Future ideas to implement in the tutorial (i already have written code for this, but its not very efficient. So ill make more efficient code for this):
Map
Drawing a map
Readying from a text file
Map Manager
setting up the map, map manager etc