Many times we want to build more complicated games. But
to build a labyrinth game, for example, with what you've read so far,
would not be an easy task. For this we use a scenario.
In the Jplay there is a class called Scene that is used to construct scenarios.
1 - Before start building the code
Before writing any line of code, think about how your
scenario is, which are the static images (not animated), which are the
dynamic images as sprites and animations. The static images will be
those that are included in the file that compose the scene.
Keep in mind that all the scenario images must have the same
dimension, if you have images that are rectangles, then all must be
rectangles.
After that, you are ready to start building the file of your scenario. The sections 2 and 3 take care of this building.
2 - Scenario file organization
In Jplay, information for the construction of the scenario is stored in a file with the extension '.scn'.
The file is organized as follows:
Line 1 - number of images used to construct the scenario (the static images).
Line 2 - path of the first image and its extension
Line 3 - path of the second image and its extension
Line 4 - path of the third image and its extension
Line n+1 - path of the n-th image and its extension
Line n+2 - start of the construction of the matrix
Line m - end of the construction of the matrix that is representedby the '%' character.
Line m+1 - path of the backdrop and its extension.
Obs.: Do not leave any blank line, beacuse this will generate a runtime error.
Example of a '.scn' file.
3
wall.jpg
floor.jpg
star.jpg
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0
0,2,2,2,2,1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,1,0
0,1,2,1,2,1,2,1,1,1,1,1,1,1,1,1,1,1,1,1,2,2,1,0
0,1,2,1,2,2,2,1,2,2,2,2,2,2,2,1,2,2,2,2,2,2,1,0
0,1,2,1,1,1,1,1,2,2,1,1,1,1,1,1,1,1,2,2,2,2,1,0
0,1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,1,0
0,1,2,1,1,1,1,2,2,2,1,1,1,1,1,1,2,2,1,1,1,2,1,0
0,1,2,1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,1,2,2,1,0
0,1,2,1,2,2,2,1,2,2,2,2,2,2,2,1,1,1,1,1,2,2,1,0
0,1,2,1,2,2,2,1,1,1,1,1,1,1,2,1,2,2,2,1,2,2,1,0
0,1,2,1,2,2,2,2,2,2,1,2,2,2,2,1,2,2,2,1,1,1,1,0
0,1,2,1,2,2,2,2,2,2,1,2,2,2,2,1,2,2,2,2,2,2,1,0
0,1,2,1,1,1,2,2,1,1,1,1,1,1,2,1,1,1,1,1,1,1,1,0
0,1,2,2,2,2,2,2,2,2,2,2,2,1,2,2,2,2,2,2,2,2,3,0
0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
%
backdrop.jpg
3 - Building the matrix
The matrix consists of integers separated by commas without spaces between them.
The number 0 (zero) always correspond to the backdrop (the image that will be drawn under the scenario).
Yet the other numbers follow this logic::
1 - represents the wall.jpg image
2 - represents the flor.jpg image
3 - represents the star.jpg image
We put the number 0 (zero) in the edges suggesting that this is a backdrop area.
Number 1 is used as 'wall' and delimits passages.
Number 2 is used as traversable places.
Number 3 is used as final point of arrival.
4 - Building the code to show a scenario
To build the code we will use the followinf methods of the Scene class:
//Class constructor
public Scene();
//Loads the information stored on the '.scn' file.
public void loadFromFile(String fileName);
//Tells Jplay what are the initial coordinates where the picture should be drawn.
public void setDrawStartPos(int drawStartX, int drawStartY);
//Draws the picture on the screen
public void draw();
Example: Showing a scenario on the screen.
package Scenario;
import java.awt.Point;
import java.util.Vector;
import jplay.Keyboard;
import jplay.Scene;
import jplay.TileInfo;
import jplay.Window;
/**
* @author Gefersom Cardoso Lima
* Federal Fluminense University
* Computer Science
*/
public class Scenario {
private Window window;
private Scene scene;
public Scenario()
{
window = new Window(800,600);
scene = new Scene();
scene.loadFromFile("scene.scn");
scene.setDrawStartPos(15, 30);
}
public void run()
{
while(true)
{
scene.draw();
window.update();
}
}
/**
* @param args the command line arguments
*/
public static void main(String[] args) {
Scenario scen = new Scenario();
scen.run();
}
}
5 - Adding an object to the scenario.
To add an object to be controlled by us to the scenario we use the method below:
//Adds any Jplay GameObject to the scenario but, doesn't modifies the
//Matrix that is used to construct the scenario.
public void addOverlay(GameObject overlay);
With the above method we can add a GameImage, an Animation or a Sprite to the scenario.
6 - The auxiliar class TileInfo.
When Jplay reads the scenario input file, it creates, for each
integer value of the matrix stored in the '.scn' file, a TileInfo.
The information stored in TileInfo are: 'id' - numeric value that represents the image and a reference to the image.
All TileInfos are stored in a matrix used internally by the Scene class.
Example:
The image 'wall.jpg' is represented by number 1.
The Jplay creates a TileInfo with ID = 1 and associates this TileInfo to
the image 'wall.jpg' that is stored in another internal structure in the Scene class.
It is through the TileInfo that we can discover where a particular
overlay is located and which are the images overlayed by it or
around it.
7 - Defining traversable areas.
Scene class method used in this section:
//Returns the objects that are between the points passed as parameters.
public Vector getTilesFromRect(Point min, Point max)
If we do not define areas for which the GameObject (added with the
addOverlay() method) can traverse, it will move across all the scenario.
To make the GameObject move only by a few areas, we follow this steps:
1 - We capture the minimum and maximum values for the coordinates of the GameObject.
//Remember that the coordinates of every GameObject on Jplay are numbers in 'double' format
//thus, sometimes we will need to do a cast to an integer number.
//Min position is the position (x,y) of the GameObject
Point playerMin = new Point ((int)gameObject.x, (int)gameObject.y);
//Max position is the posição (x + width, y + height) of the GameObject
Point playerMax = new Point((int)(gameObject.x + player.width), (int)(gameObject.y + gameObject.height));
2 - We capture the images that are in the same area of the GameObject.
//Returns the images that are in the same are of the GameObject (x,y), (x + width, y + height)
Vector tiles = scene.getTilesFromRect(playerMin, playerMax);
3 - For each tile returned, we verify which tile it is from its id, and if the player collided with it.
After the collision test and the id verification, what will be done is a choise of the programmer.
In the section below the GameObject is repositioned only a few
pixels. Since it was meant to have a collision, some pixels need to be
overlayed. If it is not done, the GameObject will collide
infinitely with the TileInfo.
//for all the tiles
for(int i = 0 ; i < tiles.size() ; i++)
{
TileInfo tile = (TileInfo)tiles.elementAt(i);
//if the tile is a wall and the player collided with it
if((tile.id == Constante.TILE_WALL) && player.collided(tile))
{
//if the player is moving on the horizontal
if (player.movedOnHorizontal())
{
//if the player is behind the wall?
if(player.x <= tile.x -1)
player.x = tile.x - player.width;//Repositions the player
else
//if the player is in front of the wall
player.x = tile.x + tile.width;//Repositions the player
}
else
{ //the player is under the wall?
if(player.y >= tile.y + tile.height -1)
player.y = tile.y + tile.height;//Repositions the player
else
//o player está acima da parede
player.y = tile.y - player.height ;//Repositions the player
}
return false;
}
else
//if the player found the star
if(tile.id == Constante.TILE_STAR)
return true;
}
return false;
}
Example:
import jplay.Keyboard;
import jplay.Sprite;
import java.awt.Point;
import java.util.Vector;
import jplay.Keyboard;
import jplay.Scene;
import jplay.TileInfo;
import jplay.Window;
/*----------------------------------------------------------------------------------------------*/
public class Constants
{
public static int TILE_WALL = 1;
public static int TILE_STAR = 3;
}
/*----------------------------------------------------------------------------------------------*/
public class Player extends Sprite
{
private boolean horizontalMoveKeyPressed;
public Player()
{
super("player.png",8);
}
public boolean movedOnHorizontal()
{
return horizontalMoveKeyPressed;
}
public void move(Keyboard keyboard)
{
horizontalMoveKeyPressed = true;
if(keyboard.keyDown(Keyboard.LEFT_KEY) == true)
{
this.x -= 1;
setCurrFrame(2);
}
else
if(keyboard.keyDown(Keyboard.RIGHT_KEY) == true)
{
this.x += 1;
setCurrFrame(3);
}
else
horizontalMoveKeyPressed = false;
if (!horizontalMoveKeyPressed)
{
if(keyboard.keyDown(Keyboard.UP_KEY) == true)
{
this.y -= 1;
setCurrFrame(0);
}
else
if(keyboard.keyDown(Keyboard.DOWN_KEY) == true)
{
this.y += 1;
setCurrFrame(1);
}
}
}
}
/*----------------------------------------------------------------------------------------------*/
public class Scenario
{
private Window window;
private Keyboard keyboard;
private Scene scene;
private Player player;
public Scenario()
{
window = new Window(800,600);
keyboard = window.getKeyboard();
scene = new Scene();
scene.loadFromFile("scene.scn");
scene.setDrawStartPos(15, 30);
player = new Player();
player.x = 454;
player.y = 140;
scene.addOverlay(player);
}
public void run()
{
boolean loop = true;
while(loop)
{
draw();
controlPath();
player.move(keyboard);
if (keyboard.keyDown(Keyboard.ESCAPE_KEY))
loop = false;
window.delay(10);
}
window.exit();
}
public void draw()
{
scene.draw();
window.update();
}
boolean controlPath()
{
//Position min is the (x,y) position of the player
//Position max is the (x + largura, y + altura) position of the player
Point playerMin = new Point ((int)player.x, (int)player.y);
Point playerMax = new Point((int)(player.x + player.width), (int)(player.y + player.height));
//Returns the images that are in the same area of the player (x,y), (x + width, y + height)
Vector tiles = scene.getTilesFromRect(playerMin, playerMax);
//for all the tiles
for(int i = 0 ; i < tiles.size() ; i++)
{
TileInfo tile = (TileInfo)tiles.elementAt(i);
//if the tile is a wall and the player collided with it
if((tile.id == Constant.TILE_WALL) && player.collided(tile))
{
//if the player is moving on the horizontal
if (player.movedOnHorizontal())
{
//the player is behind the wall?
if(player.x <= tile.x -1)
player.x = tile.x - player.width;//Repositions the player
else
//the player is in front of the wall
player.x = tile.x + tile.width;//Repositions the player
}
else
{ //the player is under the wall?
if(player.y >= tile.y + tile.height -1)
player.y = tile.y + tile.height;//Repositions the player
else
//the player is on the wall
player.y = tile.y - player.height ;//Repositions the player
}
return false;
}
else
//if the player found the star
if(tile.id == Constant.TILE_EXIT)
return true;
}
return false;
}
/**
* @param args the command line arguments
*/
public static void main(String[] args) {
Scenario scen = new Scenario();
scen.run();
}
}
8 - All the Scene class methods.
//Class constructor
public Scene();
//Loads the information stored in the '.scn' file.
public void loadFromFile(String sceneFile);
//Adds any GameObject of the Jplay to the scenario, but doesn't change the
//matrix that is used for the scenario construction.
public void addOverlay(GameObject overlay);
//Informs Jplay which are the initial coordinates where the scenario should be drawn initially.
public void setDrawStartPos(int drawStartX, int drawStartY);
//Draws the scenario on the screen
public void draw();
//Returns a tile of the matrix of tiles specified by its row and column in the matrix,
//if the row or column does not exist, returns null.
public TileInfo getTile(int row, int colunm);
//Returns the objects that are between the points passed as parameters.
public Vector getTilesFromRect(Point min, Point max);
//Returns the objects that are between the points passed as parameters
//(must be used replacing the previous function, in side scrolling games).
public Vector getTilesFromPosition(Point min, Point max);
//Removes one tile of the matrix of tiles specified by its row and column.
public void removeTile(int row, int colunm);
//Changes the ID of the tile specified by its row and column with the ID of another tile.
public void changeTile(int row, int colunm, int newID);
//Saves the current state of the Scene in file for later retrieval, the overlays will not be saved.
public void saveToFile(String fileName);
//Moves the scenario so as to centralize the object passed as parameter.
public void moveScene(GameObject object);
//Returns the last scenario offset in the x axis.
public double getXOffset();
//Returns the last scenario offset in the y axis.
public double getYOffset();