Fri May 23, 2014 9:20 pm
Sat May 24, 2014 1:30 am
Sat May 24, 2014 1:54 am
Sat May 24, 2014 2:40 am
ripper121 wrote:The best is, you use Paint with Black(0,0,0), White(255,255,255), Grey(190,190,190)
and a size of 84x48 Pixel for Fullscree, 64x28 Pixel for Logo, 8x8 Sprite.
Sat May 24, 2014 10:05 am
Sat May 24, 2014 6:28 pm
rodot wrote:Looks good!
The bitmaps width have to be a mutliple of 8, it'll be specified in the reference. Also my bitmap converter automatically enlarge the bitmap width for it to be a multiple of 8. I think you should add that in yours ripper121
You may want to take a look at crabator's source code for a moving world of tiles. Not sure if it's really readable though... what I did is that the world itself is not moving, it's the "camera" which follows the character. Also it's toroidal world (it warps around like in asteroids) so you feel like it's super large, but it's only 16x12 tiles wide.
Sun May 25, 2014 12:00 pm
Sun May 25, 2014 11:13 pm
rodot wrote:Yeah, crabator is not well commented and probably not the most elegant code you can find :/
But this game's purpose was to showcase Gamebuino, not to be a tutorial. For now I prefer to work on very simple examples to show each feature separately in the reference.
Mon May 26, 2014 4:54 pm
DFX2KX wrote:I've learned more about C in the previous 4 days then I've learned in as many years
Mon May 26, 2014 9:51 pm
//Armored Steel, by DFX2KX
#include <SPI.h>
#include <Gamebuino.h>
Gamebuino gb;
#include <EEPROM.h>
#include <avr/pgmspace.h>
//useful constants
const int NORTH = 0;
const int SOUTH = 1;
const int EAST = 2;
const int WEST = 3;
const int LEVEL_CSIZE = 10;
const int LEVEL_RSIZE = 5;
const int LEVEL1MAP = 0;
const int LEVEL2MAP = 1;
const int LEVEL3MAP = 2;
const int DONTFLIP = 1;
//some globals for the blasted tilset renderer
int global_current_c =0;
int global_current_r =0;
//bitmap assets
//road tile bitmaps
//road, straight (rotate for ew)
static unsigned char PROGMEM road_0_0[] =
{
16,16,
B10000001,B10000001,
B10000001,B10000001,
B10000001,B10000001,
B10000000,B00000001,
B10000000,B00000001,
B10000001,B10000001,
B10000001,B10000001,
B10000001,B10000001,
B10000001,B10000001,
B10000001,B10000001,
B10000001,B10000001,
B10000000,B00000001,
B10000000,B00000001,
B10000001,B10000001,
B10000001,B10000001,
B10000001,B10000001,
};
//curved road (SE rotate WS WN NE)
static unsigned char PROGMEM road_0_1[] =
{
16,16,
B00000000,B01111111,
B00000011,B10000000,
B00000100,B00000000,
B00001000,B00000000,
B00010000,B00000000,
B00100000,B00000000,
B01000000,B00000000,
B01000000,B00001111,
B01000000,B00111111,
B10000000,B01110000,
B10000000,B11100000,
B10000000,B11000000,
B10000001,B10000000,
B10000001,B10000000,
B10000001,B10000000,
B10000001,B10000001,
};
//Road, three-way (ews rotate for NSW, WEN)
static unsigned char PROGMEM road_0_2[] =
{
16,16,
B11111111,B11111111,
B00000000,B00000001,
B00000000,B00000000,
B00000000,B00000001,
B00000000,B00000000,
B00000000,B00000001,
B00000000,B00000000,
B10000000,B00000001,
B10000000,B00000001,
B00000000,B00000000,
B10000000,B00000000,
B00000000,B00000000,
B10000000,B00000000,
B00000000,B00000000,
B10000000,B00000000,
B10000001,B10101011,
};
//Road four-way
static unsigned char PROGMEM road_0_3[] =
{
16,16,
B11010101,B10000001,
B00000000,B00000001,
B00000000,B00000000,
B00000000,B00000001,
B00000000,B00000000,
B00000000,B00000001,
B00000000,B00000000,
B10000000,B00000001,
B10000000,B00000001,
B00000000,B00000000,
B10000000,B00000000,
B00000000,B00000000,
B10000000,B00000000,
B00000000,B00000000,
B10000000,B00000000,
B10000001,B10101011,
};
//road, dead end (rotate for east, west, and south)
static unsigned char PROGMEM road_0_4[] =
{
16,16,
B10000001,B10000001,
B10000001,B10000001,
B10000001,B10000001,
B10000001,B10000001,
B10000001,B10000001,
B10000001,B10000001,
B10000001,B10000001,
B10000001,B10000001,
B10000000,B00000001,
B10000000,B00000001,
B10000000,B00000001,
B01000000,B00000010,
B00100000,B00000100,
B00110000,B00001100,
B00001100,B00110000,
B00000011,B11000000,
};
/*
const int PROGMEM tilemap_Level3[][LEVEL_CSIZE]={
{1,1,1,1,1,1,1,1,1,1},
{1,0,0,1,0,0,1,0,0,1},
{1,1,1,1,1,1,1,1,1,1},
{1,0,0,1,0,0,1,0,0,1},
{1,1,1,1,1,1,1,1,1,1}
};
*/
//tilemap handling functions
int func_getTilemapTile(int mapselect, int collum, int row){
//the maps (yay) must exist inside of this functions
const int PROGMEM tilemap_Level1[][LEVEL_CSIZE]={
{1,1,1,1,1,1,1,1,1,1},
{1,0,0,1,0,0,1,0,0,1},
{1,1,1,1,1,1,1,1,1,1},
{1,0,0,1,0,0,1,0,0,1},
{1,1,1,1,1,1,1,1,1,1}
};
const int PROGMEM tilemap_Level2[][LEVEL_CSIZE]={
{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,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},
};
const int PROGMEM tilemap_Level3[][LEVEL_CSIZE]={
{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,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},
};
//case statement deciding what map to look at
int output;
int * const r = &row;
int * const c = &collum;
//arrays do not like variables passed from functions to work as arguments for their pointers or []'s. a switch statment will be needed, with cases for every reasionable row or collum to be used. Arrays are awful
switch (mapselect){
case 0:
output = tilemap_Level1[*r][*c];
break;
case 1:
output = tilemap_Level2[*r][*c];
break;
case 2:
output = tilemap_Level3[*r][*c];
break;
};
if (output != 0) {
output = true;
};
return output;
};
void func_drawRoadTile(int x, int y, int tilesize, int north, int south, int east, int west){
//draws a tile of type tiletype, at x,y, with shape fitting matching tiles to north/south/east/west
//add all of the sides up, to get a number from 0-4, this ballparks what tile we'll need, and saves us mindlessly checking EVERYTHING.
switch (north + south + east + west){
case 0:
//no sides, an orphan tile, no tile is in the testfile, so we'll just draw a placeholder
gb.display.drawRect(x,y,tilesize,tilesize);
break;
case 1:
//single side is attached, so deadend tile
if(north == true){
//north facing tile
gb.display.drawBitmap(x, y, road_0_4, NOROT, 0);
}
else
{
//not north, let's try east
if(east == true){
//east facing tile
gb.display.drawBitmap(x, y, road_0_4, ROTCCW, 0);
}
else
{
//not not east, lets try south
if(south == true){
//south facing tile
gb.display.drawBitmap(x, y, road_0_4, ROT180, 0);
}
else
{
//if not south, let's try west
if(west == true){
//west facing tile
gb.display.drawBitmap(x, y, road_0_4, ROTCW, 0);
};
};
};
};
break;
case 2:
//two sides are matched to this tile, so either a straight, or a turn. let's use some if's to see which of these it is.
if((east + west == 2) || (north + south == 2)){
//a straight road! from hear it's easy to draw the right tile
if(north == true){
//north south road
gb.display.drawBitmap(x, y, road_0_0, NOROT, 0);
}
else
{
//east west straight road
gb.display.drawBitmap(x, y, road_0_0, ROTCW, 0);
};
}
else
{
//a curve, there are fout ways this can be drawn. The defualt of this sprite is south and east
if(south + east == 2){
//curve from south to east
gb.display.drawBitmap(x, y, road_0_1, NOROT, 0);
}
else
{
//let's try east north, or rotccw
if(north + east == 2){
//east to north curve
gb.display.drawBitmap(x, y, road_0_1, ROTCCW, 0);
}
else
{
//not north and east, let's try west and north, or rot180
if(north + west == 2){
//north to west curve
gb.display.drawBitmap(x, y, road_0_1, ROT180, 0);
}
else
{
//only other curve we've got is west/south, or rot cw
gb.display.drawBitmap(x, y, road_0_1, ROTCW, 0);
};
};
};
};
break;
case 3:
//t roads, can be checked for with one two way check, and a further check for the extra side
//does this t have an east/west connection?
if(east + west == 2){
//yes it does, check south gb.display.drawBitmap(x, y, road_0_2, NO, NOFLIP);
if(south == true){
//it does have a south connection, standard sprite shall do
gb.display.drawBitmap(x-1, y, road_0_2, NOROT, DONTFLIP);
}
else
{
//nope, rotate the sprite 180 degrees
gb.display.drawBitmap(x-1, y, road_0_2, ROT180, DONTFLIP);
};
}
else
{
//it doesn't have an east/west combo, so lets check which of those two it DOES have, the road has to be north/south/x
if(east == true){
//it has an east connection, meaning north/south/east sprite is rotccw
gb.display.drawBitmap(x-1, y, road_0_2, ROTCW, DONTFLIP);
}
else
{
//it's notth/south/west, so rotcw
gb.display.drawBitmap(x-1, y, road_0_2, ROTCCW, DONTFLIP);
};
};
break;
case 4:
//easy, it's an intersection!
gb.display.drawBitmap(x-1, y, road_0_3, NOROT, DONTFLIP);
break;
};
};
void func_draw_tailemap(int mapselect, int camera_x, int camera_y, int viewport_w, int viewport_h){
//draw the tiles, based on selected map, the position of the camera in world space, and the width and height of the viewport (the actual region of the screen to be drawn) the camera's point in viewport space is the center
int current_c = 0;
int current_r = 0;
int tilex;
int tiley;
int screenx;
int screeny;
int north;
int south;
int east;
int west;
int curtype;
int tilesize = 16;
boolean draw;
//okay, some constant pointers, so things don't break
int * const ref_c = ¤t_c;
int * const ref_r = ¤t_r;
int * const ref_t = &curtype;
// four quick variables representing the worldspace bounds
int view_world_left = camera_x - (viewport_w/2);
int view_world_right = camera_x + (viewport_w/2);
int view_world_top = camera_y - (viewport_h/2);
int view_world_bottom = camera_y + (viewport_h/2);
for(current_r; current_r <= (LEVEL_RSIZE-1); current_r += 1){
//repeat for each row in the standard level
global_current_r = current_r;
for(current_c; current_c <= (LEVEL_CSIZE-1); current_c += 1){
global_current_c = current_c;
//repeat ths loop for each collum in row
//get the tile's x and y, check if it's visible
tilex = current_c * tilesize;
tiley = current_r * tilesize;
//replaced with always true, so that we can test other things
if ((((tilex + tilesize -1 ) >= view_world_left) && ((tilex - 1) <= view_world_right) && ((tiley + tilesize + 1 ) >= view_world_top) && ((tiley + 1) <= view_world_bottom))){
//visible, so let's do some math
screenx = (tilex - view_world_left);
screeny = (tiley - view_world_top);
//we know where it is, let's see what it should look like (the map we're on now affaects what we draw)
curtype = func_getTilemapTile(LEVEL1MAP, *ref_c, *ref_r);
//not on an empty tile
if(*ref_t != 0){
//if there is no tile here skip and set north to false, otherwise, run the following checks
if((*ref_r - 1) > -1){
//check the tile to the north
north = func_getTilemapTile(mapselect, *ref_c, *ref_r-1);
if(north == *ref_t){
//north matches, set it to true
north = true;
}
else
{
//no match, set false
north = false;
};
}
else
{
//outside of map, north is false
north = false;
};
//if these's no tiles south, skip this check and set it false as well
if((*ref_r + 1) < LEVEL_RSIZE){
//check the tile to the south
south = func_getTilemapTile(mapselect, *ref_c, *ref_r+1);
if(south == *ref_t){
//north matches, set it to true
south = true;
}
else
{
//no match, set false
south = false;
}
}
else
{
//outside of map, south is false
south = false;
};
//check now to the west, set west to false if outside of the map
if((*ref_c - 1) > -1){
//check the tile to the west
west = func_getTilemapTile(mapselect, *ref_c-1, *ref_r);
if(west == *ref_t){
//north matches, set it to true
west = true;
}
else
{
//no match, set false
west = false;
};
}
else
{
//outside of map, west is false
west = false;
};
//if these's no tiles south, skip this check and set it false as well
if((*ref_c + 1) < LEVEL_CSIZE){
//check the tile to the south
east = func_getTilemapTile(mapselect, *ref_c+1, *ref_r);
if(east == *ref_t){
//north matches, set it to true
east = true;
}
else
{
//no match, set false
east = false;
};
}
else
{
//outside of map, north is false
east = false;
};
//okay, time to draw the appropriate tile! Finally!
//run different tile drawing functions for differant types of tile
switch (*ref_t){
//road tiles it will pick the right road bitmap to draw
case 1:
func_drawRoadTile(screenx,screeny, 16, north, south, east, west);
break;
case 0:
gb.display.drawRect(screenx,screeny,16,16);
};
};
};
};
//reset current_c with 0 after drawing of collum is complete
current_c = 0;
};
current_r = 0;
};
//a function that simply changes the value of the camera by whatever you want, unless it's hit the extent of the world, at which case it pins to the edge of the map
int func_moveCameraX(int startx,int moveby, int viewport_w){
//calculate motion. this is always ADDED to the starting postion. Negative numbers for moving right
int targetx = startx + moveby;
int view_world_left = targetx - (viewport_w/2);
int view_world_right = targetx + (viewport_w/2);
int world_size_x = LEVEL_CSIZE * 16;
//check if we're trying to look off the map any
if((view_world_left < 0) || (view_world_right > (world_size_x))){
return startx;
}
else
{
return targetx;
};
};
int func_moveCameraY(int starty,int moveby, int viewport_h){
//calculate motion. this is always ADDED to the starting postion. Negative numbers for moving up
int targety = starty + moveby;
int view_world_top = targety - (viewport_h/2);
int view_world_bottom = targety + (viewport_h/2);
int world_size_y = LEVEL_RSIZE * 16;
//check if we're trying to look off the map any
//gb.display.println(view_world_bottom);
if((view_world_top < 0) || (view_world_bottom >= (world_size_y+1))){
return starty;
}
else
{
return targety;
};
};
char inttochar(int c){
//because everyone needs this, makes a charstring out of an integer
char b[1];
String str;
str=String(c);
str.toCharArray(b,1);
return b[1];
};
void setup(){
// initialize the Gamebuino object
gb.begin(F("Armored Steel"));
gb.popup(F("map test go!"), 30);
};
void loop(){
if(gb.update()){
static int tilesize = 16;
static int viewport_w=LCDWIDTH;
static int viewport_h=LCDHEIGHT;
//center the camera
static int camera_x = (LEVEL_CSIZE*16)/2;
static int camera_y = (LEVEL_RSIZE*16)/2;
//test tile rendering, and viewports
if(gb.buttons.repeat(BTN_UP,2)){
camera_y = func_moveCameraY(camera_y,-1,viewport_h);
};
if(gb.buttons.repeat(BTN_DOWN,2)){
camera_y = func_moveCameraY(camera_y,1,viewport_h);
};
if(gb.buttons.repeat(BTN_LEFT,2)){
camera_x = func_moveCameraX(camera_x,-1,viewport_w);
};
if(gb.buttons.repeat(BTN_RIGHT,2)){
camera_x = func_moveCameraX(camera_x,1,viewport_w);
};
//we have the camera code, let's render the tiles
func_draw_tailemap(LEVEL1MAP, camera_x, camera_y, viewport_w, viewport_h);
};
};