2d scrolling and collision

Started by
3 comments, last by TylerHum 12 years, 11 months ago
Ok I've started a 2d game that's supposed to scroll and as it scrolls it'll load the new bits of map, the issue I'm having with that is it's jumping. Everytime the character moves 32 pixels he jumps another 32 and centers on the next tile.
My second issue is that the collision I have setup doesnt register ,it thinks every tile is a wall until Im off the map completely. I only setup the collision on the UP movement to test it otherwise I wouldnt be able to move at all. Weirdest part is the drawing function still see's the floors and draws them properly.

Here is the code I have. I'm using C++ and Allegro 5:

Movement:
//+++Key_UP++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
if(key[KEY_UP])
{
if(levelCurrent[x/32][(y-2)/32].walkable==1 && levelCurrent[(x+(32-1))/32][(y-2)/32].walkable==1)
{
y--;
}
}

//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//

//+++Key_DOWN++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
if(key[KEY_DOWN])
{
y++;
}
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//

//+++Key_LEFT++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
if(key[KEY_LEFT])
{
x--;
}
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//

//+++Key_RIGHT+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
if(key[KEY_RIGHT])
{
x++;
}
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//

//+++Mouse_buttons+++++++++++++++++++++++++++++++++++++++++++++++++++++++//
if(key[MOUSE_1]&&
mouse_x<120&&
mouse_x>100&&
mouse_y<25&&
mouse_y>5)
{
buttons[CHARA]=true;
view=4;
}
else
buttons[CHARA]=false;
}
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//


Drawing:
for(b=0;b<20;b++){
for(c=0;c<20;c++){
if(b+(y/32)<21&&
b+(y/32)>-1&&
c+(x/32)<21&&
c+(x/32)>-1&&
levelCurrent[c+(x/32)][b+(y/32)].walkable==1){
al_draw_bitmap(wall,(c*32)-x,(b*32)-y+32,0);
}
}
}


I'm pretty sure the issue is somewhere in there but I'm having a hard time finding a solution to it. Thanks for the help.
Advertisement
if(levelCurrent[x/32][(y-2)/32].walkable==1 && levelCurrent[(x+(32-1))/32][(y-2)/32].walkable==1)


This is for going up (decreasing y). Why do you check at y-2, if you just go to y-1? Why do you check two tiles? And why do you check only one if x is a multiple of 32?

Other issues:
  • what do you put in levelCurrent? Prove that your tiles are walkable.
  • when do you set and unset key[] flags? Maybe you move more than once per key press.

Omae Wa Mou Shindeiru

I check at y-2 because he moves at a rate of 2 pixels normally. I had changed it just to check a few things.
Tiles have a walkable integer. if its 1 you can walk on it 0 you cant.
Key flags are checked per frame.


Here's the full code if that helps any:

Main.cpp
#include "BL.h"

extern void BuildLevel(Tile LevelCurrent[20][20]);


const float FPS = 60;
const int SCREEN_W = 640;
const int SCREEN_H = 672;
const int bizzle_SIZE = 32;

enum MYKEYS {
KEY_UP, KEY_DOWN, KEY_LEFT, KEY_RIGHT, MOUSE_1
};
enum BUTTONS {
B1,B2,B3,B4,B5,B6,B7,B8,B9,B0,CHARA,INV,SAVE,LOAD,NEW,EXIT
};

int main(int argc, char **argv)
{
ALLEGRO_DISPLAY *display = NULL;
ALLEGRO_EVENT_QUEUE *event_queue = NULL;
ALLEGRO_TIMER *timer = NULL;

ALLEGRO_BITMAP *bizzle_spr = NULL;
ALLEGRO_BITMAP *healthbar = NULL;
ALLEGRO_BITMAP *manabar = NULL;
ALLEGRO_BITMAP *expbar = NULL;
ALLEGRO_BITMAP *wall = NULL;
ALLEGRO_BITMAP *background = NULL;
ALLEGRO_BITMAP *buffer = NULL;
ALLEGRO_BITMAP *FlyCan = NULL;
ALLEGRO_BITMAP *Textbox = NULL;
ALLEGRO_BITMAP *Buttons = NULL;
ALLEGRO_BITMAP *Logo = NULL;
ALLEGRO_BITMAP *Map = NULL;

ALLEGRO_FONT *font = NULL;

//Bizzle's stats//
Bizzle bizzle;

char *hpC=new char[5];
char *mpC=new char[5];
char *xpC=new char[2];
char *strC=new char[5];
char *dexC=new char[5];
char *lodmgC=new char[5];
char *hidmgC=new char[5];
char *intelC=new char[5];
char *conC=new char[5];
char *defC=new char[5];
char *statsC=new char[5];
char *fireC=new char[5];
char *waterC=new char[5];
char *windC=new char[5];
char *earthC=new char[5];

//==DEBUGGY!===================//
char *debugx=new char[5];
char *debugy=new char[5];
char *debugofflevelx=new char[5];
char *debugofflevely=new char[5];
char *debugwalk=new char[5];
//============================//

//=============//

//Level stuff//
int levelnum;
Tile levelCurrent[20][20];
Enemy *enemy = new Enemy[200];
std::vector<Item> item;
//========//

bool key[5] = { false, false, false, false,false };
bool buttons[16] = {false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false};
bool redraw = true;
bool doexit = false;
bool makelevelCurrent = false;
bool turn=true;

int wait = 0;
int direction=0;
int x=0,y=0,levelx=0,levely=0;
int a,b,c;
int d=0;
int onlevel=1;
int view=1;//view: 1=Main menu, 2=Game, 3=Inventory, 4=Character sheet, 5=Pause, 6=Spellbook

float mouse_y,mouse_x;

sprintf(xpC,"%d",bizzle.xp);

a=b=c=0;

al_init();
al_install_keyboard();
al_install_mouse();
al_init_image_addon();
al_init_font_addon();
al_init_ttf_addon();

timer = al_create_timer(1.0 / FPS);
display = al_create_display(SCREEN_W, SCREEN_H);

//bitmap creation
healthbar = al_create_bitmap(100,10);
manabar = al_create_bitmap(100,10);
expbar = al_create_bitmap(100,10);
buffer = al_create_bitmap(SCREEN_W,SCREEN_H);
Textbox = al_create_bitmap(SCREEN_W,64);
Map = al_create_bitmap(40,40);

//bitmap loading
bizzle_spr = al_load_bitmap("bizzle.png");
wall = al_load_bitmap("wall.bmp");
background = al_load_bitmap("background.bmp");
FlyCan = al_load_bitmap("flycan.bmp");
Buttons = al_load_bitmap("button_sheet.png");
Logo = al_load_bitmap("Logo.png");

//font loading
font = al_load_font("courbd.ttf",12,0);

al_set_target_bitmap(healthbar);
al_clear_to_color(al_map_rgb(255,0,0));

al_set_target_bitmap(manabar);
al_clear_to_color(al_map_rgb(0,0,255));

al_set_target_bitmap(expbar);
al_clear_to_color(al_map_rgb(0,255,0));

al_set_target_bitmap(Textbox);
al_clear_to_color(al_map_rgb(255,255,255));

al_set_target_bitmap(Map);
al_clear_to_color(al_map_rgb(127,0,127));

al_set_target_bitmap(buffer);

event_queue = al_create_event_queue();

al_register_event_source(event_queue, al_get_display_event_source(display));

al_register_event_source(event_queue, al_get_timer_event_source(timer));

al_register_event_source(event_queue, al_get_keyboard_event_source());

al_register_event_source(event_queue, al_get_mouse_event_source());

al_clear_to_color(al_map_rgb(255,255,255));

al_flip_display();

al_start_timer(timer);

while(!doexit)
{
ALLEGRO_EVENT ev;
al_wait_for_event(event_queue, &ev);

if(ev.type == ALLEGRO_EVENT_TIMER) {

//++++++++Main Menu++(View 1)+++++++++++++++++++++++++++++++++++++++++++++++++++//
if(view==1){
if(buttons[NEW]||makelevelCurrent){
BuildLevel(levelCurrent);
a=0;
makelevelCurrent = false;
view=2;
}

if(key[MOUSE_1]&&
mouse_x<350&&
mouse_x>290&&
mouse_y<336&&
mouse_y>316)
{
buttons[NEW]=true;
}
else
buttons[NEW]=false;

if(key[MOUSE_1]&&
mouse_x<350&&
mouse_x>290&&
mouse_y<386&&
mouse_y>356)
{
buttons[EXIT]=true;
}
else
buttons[EXIT]=false;

if(buttons[EXIT])
{
doexit=true;
}
}
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//

//++++++++Game++(View 2)+++++++++++++++++++++++++++++++++++++++++++++++++++//
if(view==2){

//+++Key_UP++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
if(key[KEY_UP])
{
if(levelCurrent[x/32][(y-2)/32].walkable==1 && levelCurrent[(x+(32-1))/32][(y-2)/32].walkable==1)
{
y-=2;
}
}

//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//

//+++Key_DOWN++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
if(key[KEY_DOWN])
{
y+=2;
}
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//

//+++Key_LEFT++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
if(key[KEY_LEFT])
{
x-=2;
}
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//

//+++Key_RIGHT+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
if(key[KEY_RIGHT])
{
x+=2;
}
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//

//+++Mouse_buttons+++++++++++++++++++++++++++++++++++++++++++++++++++++++//
if(key[MOUSE_1]&&
mouse_x<120&&
mouse_x>100&&
mouse_y<25&&
mouse_y>5)
{
buttons[CHARA]=true;
view=4;
}
else
buttons[CHARA]=false;
}
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//

//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
redraw = true;
}



else if(ev.type == ALLEGRO_EVENT_DISPLAY_CLOSE) {
break;
}
else if(ev.type == ALLEGRO_EVENT_KEY_DOWN) {
switch(ev.keyboard.keycode) {
case ALLEGRO_KEY_UP:
key[KEY_UP] = true;
break;

case ALLEGRO_KEY_DOWN:
key[KEY_DOWN] = true;
break;

case ALLEGRO_KEY_LEFT:
key[KEY_LEFT] = true;
break;

case ALLEGRO_KEY_RIGHT:
key[KEY_RIGHT] = true;
break;
}
}
else if(ev.type == ALLEGRO_EVENT_KEY_UP) {
switch(ev.keyboard.keycode) {
case ALLEGRO_KEY_UP:
key[KEY_UP] = false;
break;

case ALLEGRO_KEY_DOWN:
key[KEY_DOWN] = false;
break;

case ALLEGRO_KEY_LEFT:
key[KEY_LEFT] = false;
break;

case ALLEGRO_KEY_RIGHT:
key[KEY_RIGHT] = false;
break;

case ALLEGRO_KEY_ESCAPE:
doexit = true;
break;
}
}
else if(ev.type==ALLEGRO_EVENT_MOUSE_BUTTON_DOWN)
{
switch(ev.mouse.button){
case 1:
key[MOUSE_1] = true;
mouse_x=ev.mouse.x;
mouse_y=ev.mouse.y;
break;
}
}
else if(ev.type==ALLEGRO_EVENT_MOUSE_BUTTON_UP)
{
switch(ev.mouse.button){
case 1:
key[MOUSE_1] = false;
break;
}
}


if(redraw && al_is_event_queue_empty(event_queue)) {
redraw = false;

al_set_target_bitmap(buffer);
al_clear_to_color(al_map_rgb(0,0,0));

//++++++++Main Menu++(View 1)++++++++++++++++++++++++++++++++++++++++++++++//
if(view==1)
{
al_draw_bitmap(Logo,120,120,0);
if(buttons[NEW])
al_draw_bitmap_region(Buttons,60,20,60,20,290,316,0);
else
al_draw_bitmap_region(Buttons,0,20,60,20,290,316,0);

if(buttons[EXIT])
al_draw_bitmap_region(Buttons,60,60,60,20,290,356,0);
else
al_draw_bitmap_region(Buttons,0,60,60,20,290,356,0);
}
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//

//++++++++Game++(View 2)+++++++++++++++++++++++++++++++++++++++++++++++++++//
if(view==2)
{
al_draw_bitmap(background,0,32,0);

al_set_target_bitmap(Map);
al_clear_to_color(al_map_rgb(0,0,127));
for(b=0;b<20;b++){
for(c=0;c<20;c++){
if(b+(y/32)<21&&
b+(y/32)>-1&&
c+(x/32)<21&&
c+(x/32)>-1&&
levelCurrent[c+(x/32)][b+(y/32)].walkable==1){
al_draw_pixel(c,b,al_map_rgb(0,127,255));
}
}
}
al_set_target_bitmap(buffer);

//draw levelCurrent chunk
for(b=0;b<20;b++){
for(c=0;c<20;c++){
if(b+(y/32)<21&&
b+(y/32)>-1&&
c+(x/32)<21&&
c+(x/32)>-1&&
levelCurrent[c+(x/32)][b+(y/32)].walkable==1){
al_draw_bitmap(wall,(c*32)-x,(b*32)-y+32,0);
}
}
}

al_draw_bitmap(bizzle_spr, 320, 352, 0);
al_draw_bitmap(healthbar,0,0,0);
al_draw_bitmap(manabar,0,10,0);
al_draw_bitmap(expbar,0,20,0);

al_set_target_bitmap(Map);
al_draw_pixel(20,20,al_map_rgb(127,255,127));
al_set_target_bitmap(buffer);
//Button drawing//
if(buttons[CHARA])
al_draw_bitmap_region(Buttons,80,0,20,20,100,5,0);
else
al_draw_bitmap_region(Buttons,20,0,20,20,100,5,0);

//=============//

al_draw_text(font,al_map_rgb(255,255,255),50,20,0,xpC);



al_set_target_bitmap(buffer);
al_draw_bitmap(Map,SCREEN_W-40,0,0);
}
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//

//++++DEBUGGY!++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
sprintf(debugx,"%d",x);
sprintf(debugy,"%d",y);
sprintf(debugofflevelx,"%d",x/32);
sprintf(debugofflevely,"%d",y/32);
sprintf(debugwalk,"%d",levelCurrent[x/32][(y-2)/32].walkable);

al_draw_text(font,al_map_rgb(255,0,0),0,32,0,debugx);
al_draw_text(font,al_map_rgb(255,0,0),0,52,0,debugy);
al_draw_text(font,al_map_rgb(255,0,0),0,72,0,debugofflevelx);
al_draw_text(font,al_map_rgb(255,0,0),0,92,0,debugofflevely);
al_draw_text(font,al_map_rgb(255,0,0),0,112,0,debugwalk);
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//

al_set_target_bitmap(al_get_backbuffer(display));
al_draw_bitmap(buffer,0,0,0);

al_flip_display();
}
}

al_destroy_bitmap(bizzle_spr);
al_destroy_timer(timer);
al_destroy_display(display);
al_destroy_event_queue(event_queue);

delete enemy;

return 0;
}


BuildLevel.cpp
#include "BL.h"

void BuildLevel(Tile LevelCurrent[20][20])
{
for(int i=0; i<20; i++)
{
for(int e=0; e<20; e++)
{
if(i>=8&&i<=12||e>=8&&e<=12)
LevelCurrent[e].walkable=1;
else if(i<8||i>12||e<8||e>12)
LevelCurrent[e].walkable=0;
LevelCurrent[e].Collision.x=e*32;
LevelCurrent[e].Collision.y=i*32;
LevelCurrent[e].Collision.height=32;
LevelCurrent[e].Collision.width=32;
}
}
return;
}


BL.h
#ifndef __BL_H
#define __BL_H

#include <stdio.h>
#include <vector>
#include <fstream>
#include <cmath>
#include <ctime>
#include <allegro5/allegro.h>
#include <allegro5/allegro_image.h>
#include <allegro5/allegro_font.h>
#include <allegro5/allegro_ttf.h>

struct Object{
unsigned int x, y;
unsigned int width,height;
};

struct Bizzle{
int hp,mp,xp;
int str,dex,intel,con,def,stats;
int fire,water,wind,earth;
int abeast,afly,aundead,adragon,amagic,agiant,ahunger,aplant;
int dbeast,dfly,dundead,ddragon,dmagic,dgiant,dhunger,dplant;
int lodmg,hidmg;
Object Collision;
};

struct Enemy{
int hp,ap,name,graphic,xp,type1,type2,element;
int x,y;
bool moved;
Object Collision;
};

struct Item{
int type; //1=weapon,2=armor,3=consumable,4=parts
int loDmg,hiDmg; //damage buffs
int dex,str,con,intel,def; //stat buffs
int Rdex,Rstr,Rcon,Rintel; //required stats for use
int fire,water,earth,wind; //Weapons: element buffs | Armor: element resistance
int beast,fly,undead,dragon,magic,giant,hunger,plant; //Weapons: type buffs | Armor: type resistance
int hp,mp;
int x,y;
Object Collision;
};

struct Tile{
Object Collision;
unsigned short int walkable;
};
#endif
[font="Arial"]



al_set_target_bitmap(Map);
al_clear_to_color(al_map_rgb(0,0,127));
for(b=0;b<20;b++){
for(c=0;c<20;c++){
if(b+(y/32)<21&&
b+(y/32)>-1&&
c+(x/32)<21&&
c+(x/32)>-1&&
levelCurrent[c+(x/32)][b+(y/32)].walkable==1){
al_draw_pixel(c,b,al_map_rgb(0,127,255));
}
}
}
al_set_target_bitmap(buffer);

//draw levelCurrent chunk
for(b=0;b<20;b++){
for(c=0;c<20;c++){
if(b+(y/32)<21&&
b+(y/32)>-1&&
c+(x/32)<21&&
c+(x/32)>-1&&
levelCurrent[c+(x/32)][b+(y/32)].walkable==1){
al_draw_bitmap(wall,(c*32)-x,(b*32)-y+32,0);
}
}
}





When you draw the map, why are you adding the players grid position to the map grid position in your checks? Don't you want to draw the entire mini map the whole time?
Ie...

for (b = 0 ; b < 20 ; ++b) {
for (c = 0 ; c < 20 ; ++c) {
if (levelCurrent[c].walkable == 1) {
al_draw_pixel(c , b , al_map_rgb(0,127,255));
}
}
}


Next, to clean up your map drawing, you need to set up a camera and have it follow your player's position on the map.

int camx = 0;
int camy = 0;

// whenever you set the position of your player, reset your cameras position as well
// center on the player's center
camx = player_x + player_width/2 - view_width/2;
camy = player_y + player_height/2 - view_height/2;
// make sure the camera stays over the map
if (camx < 0) {camx = 0;}
if (camy < 0) {camy = 0;}
if (camx > (map_width - view_width)) {camx = map_width - view_width;}
if (camy > (map_height - view_height)) {camy = map_height - view_height;}


Now you draw your walls based on the camera position :

int start_tile_x = camx/tile_width;
int offset_x = -(camx%tile_width);
int start_tile_y = camy/tile_height;
int offset_y = -(camy%tile_height);
int num_tiles_wide = view_width/tile_width + 1;
int num_tiles_tall = view_height/tile_height + 1;

for (b = start_tile_y ; b < start_tile_y + num_tiles_tall ; ++b) {
int drawy = (b - start_tile_y)*tile_height + offset_y;
for (c = start_tile_x ; c < start_tile_x + num_tiles_wide ; ++c) {
int drawx = (c - start_tile_x)*tile_width + offset_x;
if (levelCurrent[c].walkable == 0) {
al_draw_bitmap(wall , drawx , drawy , 0);
}
}
}


I don't know why your code caused the map to 'skip' a tile here and there, but this code shouldn't suffer from the same problem.

Now when you draw your player, you will need to subtract the camera position from the player position to get the screen position :

int player_screen_x = player_x - camx;
int player_screen_y = player_y - camy;
al_draw_bitmap(player , player_screen_x , player_screen_y , 0);


To use this code, you'll have to substitute in values for tile width and height and view width and height. A better idea would be to keep them as variables though instead of hard coded constants in case you ever change your mind about how big your tiles or your view should be. It would also be nice to see better variable names instead of things like b and c and x and y. If you have any questions, just ask ,and I'll explain as best I can.
[/font]
Awesome it finally works. Thank you for your help sir.

This topic is closed to new replies.

Advertisement