I've come across an interesting problem and would like all of your opinions on my planned solution.
The game I've been working on is a 2D Tile-based RPG with the mechanics of Dragon Warrior for the NES.
Wikipedia:
http://en.wikipedia.org/wiki/Dragon_warrior
Youtube:
http://www.youtube.com/watch?v=IihWAERWDDE
If you watch that video for a bit ( or skip about a minute into it ) you will see that, each step, the screen scrolls on tile. I like this type of movement for many reasons. Also, each frame, the NPC's are animated and randomly move. They move even if the character is moving. I think mimicking this would be a fun challenge. My plan is this:
Each frame, instead of calling a function like the one in my last post (
http://forum.thegamecreators.com/?m=forum_view&t=131895&b=22 ), I should make a queue. For instance, if the right arrow key is pressed, set the bool queuedMovementRight to true. Then, before the end of the main GDK loop, have a loop to handle any queued functions. Here is an attempt at demonstrating what I mean. It is a lot of code, but plenty of comments on the main section. Also, the definition of cTileMap is included afterward.
EDIT: The formatting is screwed up, so you can download the attached file with source for the first snippet.
#include <DarkGDK.h>
#include "Map.h"
#include "Sprite Resources.h"
void DarkGDK ( void )
{
dbSyncOn ( );
dbSyncRate ( 60 );
dbSetDisplayMode ( 640, 480, 32 );
dbSetDir ( "Data" );
//This command loads the images for use as sprites.
load_sprite_resources ( );
//This makes an object of the cTileMap class I have defined.
//Its basic functions shouldn't need much explaining.
cTileMap map ( 32, 32 );
//This loads a map of tiles from a pre-made tile map.
map.load_map ( "map3.dat" );
//Draws the tile map.
map.draw_map ( 0, 0 );
//You'll see what these are for soon.
int scroll_speed = 2;
int iter_control;
int start_x;
int start_y;
bool queueUpScroll = false;
bool queueRightScroll = false;
bool queueLeftScroll = false;
bool queueDownScroll = false;
bool queueNPCProc = true;
while ( LoopGDK ( ) )
{
//Here, we start setting the queues.
if ( dbUpKey ( ) )
queueUpScroll = true;
else if ( dbRightKey ( ) )
queueRightScroll = true;
else if ( dbLeftKey ( ) )
queueLeftScroll = true;
else if ( dbDownKey ( ) )
queueDownScroll = true;
if ( dbEscapeKey ( ) && queueNPCProc )
queueNPCProc = false;
else if ( dbEscapeKey ( ) && !queueNPCProc )
queueNPCProc = true;
//Now, we can start a loop to handle the above requests.
//First off, we set iter_control to one. This is unecessary at this point,
//but, it will be useful when more items are to be processed.
iter_control = 1;
start_x = map.get_map_x_position ( );
start_y = map.get_map_y_position ( );
for ( int i = 0; iter_control; i++ )
{
iter_control = 0;
iter_control += ( queueUpScroll +
queueRightScroll +
queueLeftScroll +
queueDownScroll +
queueNPCProc );
//The above list is redundant, since only one can be active at a time.
//But, I did so to demonstrate how the variable could handle many requests.
//The same goes for the below if statements.
//I'll explain only the first of the if statements, as they are all the same.
//The if statement checks to see if its function is up for queue. If so, it
//starts by checking how many times i has incremented. If it has incremented
//to over 32 ( the tile size ), it decrements iter_control, marking the end
//of its run. Otherwise, it re-draws the map at a slightly different position.
if ( queueUpScroll )
{
if ( i > 32 )
iter_control--;
else
map.draw_map ( start_x, start_y - i );
}
if ( queueRightScroll )
{
if ( i > 32 )
iter_control--;
else
map.draw_map ( start_x + i, start_y );
}
if ( queueLeftScroll )
{
if ( i > 32 )
iter_control--;
else
map.draw_map ( start_x - i, start_y );
}
if ( queueUpScroll )
{
if ( i > 32 )
iter_control--;
else
map.draw_map ( start_x, start_y - i );
}
//Finally, the last item is the NPC processing. I have no clue how I'm going to
//handle that, yet. So, it shall be left empty for now.
if ( queueNPCProc )
{
//No clue what to put here, yet.
}
//Then, before the end of each iteration, we call dbSync.
dbSync ( );
}
//And, I'm not sure, but I think leaving out dbSync at the end of the main loop would
//be best.
//dbSync ( );
}
return;
}
And, as promised, cTileMap's definitions. A fair bit of code. You might as well just skip it. Not really worth looking at.
#pragma once
#include <vector>
struct sTile
{
int type;
bool solid;
};
class cTileMap
{
protected:
int screen_tile_w;
int screen_tile_h;
int tile_width;
int tile_height;
int map_x_position;
int map_y_position;
std::vector<std::vector<sTile>> vTileMap;
public:
cTileMap ( ) { };
cTileMap ( int tile_width, int tile_height );
int get_type ( int x, int y ) { return vTileMap[x][y].type; }
int get_solid ( int x, int y ) { return vTileMap[x][y].solid; }
void set_type ( int x, int y, int value ) { vTileMap[x][y].type = value; }
void set_solid ( int x, int y, bool value ) { vTileMap[x][y].solid = value; }
int get_tile_width ( ) { return tile_width; }
int get_tile_height ( ) { return tile_height; }
int get_map_x_position ( ) { return map_x_position; }
int get_map_y_position ( ) { return map_y_position; }
void size_map ( int size );
int get_size ( ) { return ( int ) vTileMap.size ( ); }
void draw_map ( int x_start, int y_start );
void scroll_map ( int x_end, int y_end, int speed );
void scroll_map ( int x_start, int y_start, int x_end, int y_end, int speed );
void save_map ( char* file_name );
void load_map ( char* file_name );
};
#include <DarkGDK.h>
#include "Map.h"
cTileMap::cTileMap ( int tile_width, int tile_height )
{
this->tile_width = tile_width;
this->tile_height = tile_height;
screen_tile_w = dbScreenWidth ( ) / tile_width;
screen_tile_h = dbScreenHeight ( ) / tile_height;
}
void cTileMap::size_map ( int size )
{
if ( vTileMap.size ( ) < size )
{
vTileMap.resize ( size );
for ( int i = 0; i < size; i++ )
vTileMap[i].resize ( size );
}
}
#include <DarkGDK.h>
#include "Map.h"
void cTileMap::draw_map ( int x_start, int y_start )
{
if ( vTileMap.size ( ) )
{
int n = 50;
int map_size = ( int ) vTileMap.size ( );
for ( int x = 0; x < map_size; x++ )
{
for ( int y = 0; y < map_size; y++ )
{
dbSprite ( n, x * tile_width + x_start, y * tile_height + y_start, vTileMap[y][x].type );
n++;
}
}
map_x_position = x_start;
map_y_position = y_start;
}
}
#include <iostream>
#include <fstream>
#include <math.h>
#include "Map.h"
using namespace std;
void cTileMap::save_map ( char* file_name )
{
ofstream output ( file_name, ios_base::binary | ios_base::trunc );
int map_size = ( int ) vTileMap.size ( );
for ( int x = 0; x < map_size; x++ )
{
for ( int y = 0; y < map_size; y++ )
output.write ( ( char * ) &vTileMap[x][y], sizeof vTileMap[x][y] );
}
output.close ( );
}
void cTileMap::load_map ( char* file_name )
{
ifstream input ( file_name, ios_base::binary );
long start, end, length;
start = input.tellg ( );
input.seekg ( 0, ios::end );
end = input.tellg ( );
length = end - start;
int num_tiles = length / ( sizeof sTile );
double grid_size = sqrt ( ( double ) num_tiles );
input.seekg ( 0 );
if ( ( int ) vTileMap.size ( ) > grid_size )
vTileMap.clear ( );
size_map ( grid_size );
for ( int x = 0; x < grid_size; x++ )
{
for ( int y = 0; y < grid_size; y++ )
input.read ( ( char * ) &vTileMap[x][y], sizeof vTileMap[x][y] );
}
input.close ( );
}
Any comments/opinions on this would be appreciated.