Related
As a school project, I've made the classic snake game using SDL2 and C++.
I've already implemented the growing, moving features for the Snake but it was required to make the movement based on a grid, but when I implemented the grid feature, the self-collision was always triggering whenever grow one part, so every time I start the game, and eat the first fruit, the snake dies.
I've been trying for a while now, from placing a delay to the adding of the tail and delaying the collision check, but to no avail, it's always colliding with itself even though it is not.
I can't see what is wrong with the self collision, I would gladly appreciate it if someone can point out what's wrong.
Snake.h
#include "GameObject.h"
#include "common.h"
#include "draw.h"
#include "Food.h"
#include "util.h"
#include <vector>
struct Segment {
int x;
int y;
Segment(int posx, int posy) {
x = posx;
y = posy;
}
};
class Snake :
public GameObject
{
public:
~Snake();
void start();
void update();
void draw();
void outOfBoundsCheck();
void move();
void addSegment(int x, int y);
void selfCollisionCheck(bool hasEaten);
void setHasMoved(bool a);
void setIsAlive(bool a);
int getX();
int getY();
int getWidth();
int getHeight();
bool getIsAlive();
bool getHasMoved();
std::vector<Segment*> const& getV() const;
private:
std::vector<Segment*> body;
SDL_Texture* headTexture;
SDL_Texture* bodyTexture;
int x;
int y;
int width;
int height;
int dx;
int dy;
int tempX;
int tempY;
bool isAlive;
bool hasMoved;
};
Snake.cpp
Snake::~Snake()
{
}
void Snake::start()
{
// Load Texture
headTexture = loadTexture("gfx/player.png");
bodyTexture = loadTexture("gfx/body.png");
tempX = 0;
tempY = 0;
x = 0;
y = 0;
dx = 0;
dy = 0;
isAlive = true;
hasMoved = false;
width = 0;
height = 0;
SDL_QueryTexture(headTexture, NULL, NULL, &width, &height);
addSegment(x, y);
}
void Snake::update()
{
std::cout << "Head" << body[0]->x << std::endl;
if (body.size() > 1) {
std::cout << "2nd Segment" << body[1]->x << std::endl;
if (body.size() > 2) {
std::cout << "3nd Segment" << body[2]->x << std::endl;
}
}
move();
outOfBoundsCheck();
}
void Snake::draw()
{
if (!isAlive) return; // Cancel the render if player dies
for (int i = 0; i < body.size(); i++) {
blit(headTexture, body[i]->x, body[i]->y);
}
}
void Snake::outOfBoundsCheck()
{
for (int i = 0; i < body.size(); i++) {
if (body[i]->x > SCREEN_WIDTH) {
body[i]->x = 0;
}
if (body[i]->x < 0) {
body[i]->x = SCREEN_WIDTH;
}
if (body[i]->y > SCREEN_HEIGHT) {
body[i]->y = 0;
}
if (body[i]->y < 0) {
body[i]->y = SCREEN_HEIGHT;
}
}
}
void Snake::move()
{
if (app.keyboard[SDL_SCANCODE_W] && dy != 5) {
dx = 0;
dy = -5;
}
if (app.keyboard[SDL_SCANCODE_A] && dx != 5) {
dx = -5;
dy = 0;
}
if (app.keyboard[SDL_SCANCODE_S] && dy != -5) {
dx = 0;
dy = 5;
}
if (app.keyboard[SDL_SCANCODE_D] && dx != -5) {
dx = 5;
dy = 0;
}
Segment* snakeHead = *(body.begin()); //Grid
tempX += dx;
tempY += dy;
if (tempX % 25 == 0) {
snakeHead->x += tempX;
tempX = 0;
}
if (tempY % 25 == 0) {
snakeHead->y += tempY;
tempY = 0;
}
for (int i = body.size() - 1; i > 0; i--) { //For the other parts to follow
body[i]->x = body[i - 1]->x;
body[i]->y = body[i - 1]->y;
}
}
void Snake::addSegment(int x, int y)
{
Segment* seg = new Segment(x, y );
body.push_back(seg);
}
void Snake::selfCollisionCheck(bool hasEaten) // Fail
{
Segment* head = body[0];
if (hasEaten == false) {
for (int i = 1; i < body.size(); i++) {
if (head->x == body[i]->x && head->y == body[i]->y) {
isAlive = false;
break;
}
}
}
else {
return;
}
}
void Snake::setHasMoved(bool a)
{
hasMoved = a;
}
void Snake::setIsAlive(bool a)
{
isAlive = a;
}
int Snake::getX()
{
return x;
}
int Snake::getY()
{
return y;
}
int Snake::getWidth()
{
return width;
}
int Snake::getHeight()
{
return height;
}
bool Snake::getIsAlive()
{
return isAlive;
}
bool Snake::getHasMoved()
{
return hasMoved;
}
std::vector<Segment*> const& Snake::getV() const
{
// TODO: insert return statement here
return body;
}
GameScene.h
#include "Scene.h"
#include "GameObject.h"
#include "Snake.h"
#include "Food.h"
#include "util.h"
#include "text.h"
#include "SoundManager.h"
class GameScene : public Scene
{
public:
GameScene();
~GameScene();
void start();
void draw();
void update();
void spawnFood();
void collisionLogic();
void selfCollision();
void despawnFood(Food* food);
private:
Snake* snake;
Food* food;
int points;
std::vector<Food*> spawnedFood;
};
GameScene.cpp
#include "GameScene.h"
GameScene::GameScene()
{
// Register and add game objects on constructor
snake = new Snake();
this->addGameObject(snake);
points = 0;
}
GameScene::~GameScene()
{
delete snake;
delete food;
}
void GameScene::start()
{
Scene::start();
// Initialize any scene logic here
initFonts();
spawnFood();
}
void GameScene::draw()
{
Scene::draw();
drawText(110, 20, 255, 255, 255, TEXT_CENTER, "POINTS: %03d", points);
if (snake->getIsAlive() == false) {
drawText(SCREEN_WIDTH / 2, SCREEN_HEIGHT / 2, 255, 255, 255, TEXT_CENTER, "GAME OVER!");
}
}
void GameScene::update()
{
Scene::update();
if (spawnedFood.size() == 0 && spawnedFood.size() != 1) {
spawnFood();
}
collisionLogic();
selfCollision();
}
void GameScene::spawnFood()
{
int random = rand() % 720;
if (random % 25 != 0) {
random = rand() % 720;
}
else {
Food* food = new Food();
this->addGameObject(food);
food->setPosition(rand() % SCREEN_WIDTH, rand() % SCREEN_HEIGHT);
spawnedFood.push_back(food);
}
}
void GameScene::collisionLogic()
{
Segment* head = snake->getV()[0];
std::vector<Segment*> snakeBody = snake->getV();
for (int i = 0; i < objects.size(); i++) {
Food* food = dynamic_cast<Food*>(objects[i]);
if (food != NULL) {
int collision = checkCollision(
head->x, head->y, snake->getWidth(), snake->getHeight(),
food->getX(), food->getY(), food->getWidth(), food->getHeight()
);
if (collision == 1) {
despawnFood(food);
snake->addSegment(snakeBody[snakeBody.size() - 1]->x, snakeBody[snakeBody.size() - 1]->y); //Adds a part to the snake
points++;
break;
}
}
}
}
void GameScene::selfCollision()
{
std::vector<Segment*> body = snake->getV();
Segment* head = snake->getV()[0];
for (int i = 1; i < snake->getV().size(); i++) {
if (head->x == body[i]->x && head->y == body[i]->y) {
snake->setIsAlive(false);
break;
}
}
}
void GameScene::despawnFood(Food* food)
{
int index = -1;
for (int i = 0; i < spawnedFood.size(); i++) {
if (food == spawnedFood[i]) {
index = i;
break;
}
}
if (index != -1) {
spawnedFood.erase(spawnedFood.begin() + index);
delete food;
}
}
It seems that I had some logical errors when it comes to the grid movement because when I re-coded everything and changed the grid movement into cell based instead of using modulo condition by dividing the screen width and height to the pixel size of my snake and using that as the coordinates for my movement, everything went back to normal and the collision bug disappeared.
Instead of doing this for the grid movement
Old Grid Movement Code
tempX += dx;
tempY += dy;
if (tempX % 25 == 0) {
snakeHead->x += tempX;
tempX = 0;
}
if (tempY % 25 == 0) {
snakeHead->y += tempY;
tempY = 0;
}
I defined this as a permanent value in my defs.h
defs.h
#define CELL_SIZE 25 // Size of the segment
#define CELL_WIDTH SCREEN_WIDTH / CELL_SIZE
#define CELL_HEIGHT SCREEN_HEIGHT / CELL_SIZE
After that, since I'm still going to render the picture with the default resolution, I multiplied CELL_SIZE to the dest variable of my blit function
draw.cpp
void blit(SDL_Texture* texture, int x, int y)
{
SDL_Rect dest;
dest.x = x * CELL_SIZE;
dest.y = y * CELL_SIZE;
SDL_QueryTexture(texture, NULL, NULL, &dest.w, &dest.h);
SDL_RenderCopy(app.renderer, texture, NULL, &dest);
}
This results to the snake and any other thing that I'm going to render to follow a grid and by assigning the x and y values with the CELL_WIDTH and CELL_HEIGHT as substitution to the resolution, I accomplished the grid movement with no conflict with my collision check.
I have been working in a zombie arcade game, I am experimenting an strange problem. I created a class called GameObject and a class called Human that inherits from GameOBject, then I declared two more called; Zombie and Player. The problem is that when I create two or more characters (instances) of this four classes the game stops working, I detected that in the classes Zombie and Player the problem only occurs when I call the method update (only these classes use it). This method is supposed to control the activities of each character.
The graphics and animated sprites are managed separately from the character, they (the characters) only call some methods to control the sprite update, those orders are processed when updating the screen.
I just want you to tell me what is happening, I think the problem is in the update method of the classes Zombie and Player.
The project is divided in different files.
I don't think this matters but I am using CodeBlocks and tdm-gcc.
main.cpp:
#include "game_classes.h"
bool working = true, redraw = true;
int main(){
init_game_classes();
Player player(200, 200);
std::vector<Zombie *> zombie_list;
for(unsigned int i = 0; i < 2; i++){
Zombie *zombie = new Zombie(i * 100, 12, &player);
zombie_list.push_back(zombie);
}
while(working){
input();
if(event.type == ALLEGRO_EVENT_TIMER){//main loop
player.update();
for(unsigned int i = 0; i < zombie_list.size(); i++){
zombie_list[i]->update();
}
redraw = true;
}
else if(event.type == ALLEGRO_EVENT_DISPLAY_CLOSE){
working = false;
}
if(redraw and al_is_event_queue_empty(event_queue)){//updating display
update_animated_models();
blit_models();
update_display();
redraw = false;
}
}
for(unsigned int i = 0; i < zombie_list.size(); i++)
delete zombie_list[i];
quit();
return 0;
}
render.h:
#include <vector>
#include <stdio.h>
#include <allegro5/allegro.h>
#include <allegro5/allegro_image.h>
int global_ticks_per_frame = 0;
ALLEGRO_BITMAP *map_background = NULL;
class Model;
std::vector<Model *> model_list;
class Model{
protected:
int x = 0, y = 0, width, height;
int source_x = 0, source_y = 0, source_width, source_height;
public:
ALLEGRO_BITMAP *sheet = NULL;
bool hide = false;
int flags = 0;
Model(const char *path, int width, int height){
this->sheet = al_load_bitmap(path);
al_convert_mask_to_alpha(this->sheet, al_map_rgb(255, 0, 255));
this->source_width = al_get_bitmap_width(this->sheet);
this->source_height = al_get_bitmap_height(this->sheet);
this->width = width;
this->height = height;
model_list.insert(model_list.begin(), this);
}
Model(ALLEGRO_BITMAP *image, int width, int height){
this->sheet = image;
al_convert_mask_to_alpha(this->sheet, al_map_rgb(255, 0, 255));
this->source_width = al_get_bitmap_width(this->sheet);
this->source_height = al_get_bitmap_height(this->sheet);
this->width = width;
this->height = height;
model_list.insert(model_list.begin(), this);
}
~Model(){
al_destroy_bitmap(this->sheet);
model_list.erase(model_list.begin() + this->index());
}
void show(){
if(not this->hide){
al_draw_scaled_bitmap(this->sheet, this->source_x, this->source_y, this->source_width, this->source_height, x, y, width, height, this->flags);
}
}
void set_x(int x){
this->x = x;
}
unsigned int index(){
for(unsigned int i = 0; i < model_list.size(); i++){
if(model_list[i] == this)
return i;
}
}
bool set_y(int y){
this->y = y;
model_list.erase(model_list.begin() + this->index());
int this_relative_y = this->y + this->height;
unsigned int i = 0;
while(i < model_list.size()){
int from_list_relative_y = model_list[i]->y + model_list[i]->height;
if(this_relative_y < from_list_relative_y){
model_list.insert(model_list.begin() + i, this);
return false;
}
i += 1;
}
model_list.push_back(this);
return false;
}
int get_y(){
return this->y;
}
int get_x(){
return this->x;
}
unsigned int get_width(){
return this->width;
}
unsigned int get_height(){
return this->height;
}
};
void blit_models(){
for(unsigned int i = 0; i < model_list.size(); i++)
model_list[i]->show();
}
class AnimatedModel;
std::vector<AnimatedModel *> animated_model_list;
class AnimatedModel : public Model{
private:
unsigned int ticks_per_frame, ticks_counter = 0;
unsigned int current_frame = 0, frame_count;
public:
bool stop = false;
void set_speed(unsigned int new_speed){
this->ticks_per_frame = new_speed;
}
AnimatedModel(const char *path, unsigned int frames, unsigned int ticks_per_frame, int width, int height) : Model(path, width, height){
this->ticks_per_frame = ticks_per_frame;
this->frame_count = frames;
this->source_width /= frames;
animated_model_list.push_back(this);
}
AnimatedModel(ALLEGRO_BITMAP *image, unsigned int frames, unsigned int ticks_per_frame, int width, int height) : Model(image, width, height){
this->ticks_per_frame = ticks_per_frame;
this->frame_count = frames;
this->source_width /= frames;
animated_model_list.push_back(this);
}
~AnimatedModel(){
for(unsigned int i = 0; i < animated_model_list.size(); i++){
if(animated_model_list[i] == this){
animated_model_list.erase(animated_model_list.begin() + i);
}
}
}
void fix_sheet_looking(){
if(not this->stop)
this->source_x = this->current_frame*this->source_width;
}
void play(){
if(this->ticks_counter >= this->ticks_per_frame + global_ticks_per_frame){
this->current_frame += 1;
if(this->current_frame >= this->frame_count)
this->current_frame = 0;
this->ticks_counter = 0;
}
else{
this->ticks_counter += 1;
}
}
void update(){
if(not this->stop){
this->play();
this->fix_sheet_looking();
}
}
void set_frame(unsigned int i){
this->current_frame = i;
}
unsigned int get_frame(){
return this->current_frame;
}
};
void update_animated_models(){
for(unsigned int i = 0; i < animated_model_list.size(); i++)
animated_model_list[i]->update();
}
game_classes.h:
#include "render.h"
#include "touch.h"
#include "window_control.h"
#include <string>
#include <iostream>
ALLEGRO_BITMAP *zombie_sprite = NULL;
ALLEGRO_BITMAP *human_sprite = NULL;
void init_game_classes(){
init_window_control();
zombie_sprite = al_load_bitmap("textures/zombie/sprite.png");
human_sprite = al_load_bitmap("textures/human/sprite.png");
}
int control_key_up = ALLEGRO_KEY_UP, control_key_down = ALLEGRO_KEY_DOWN, control_key_right = ALLEGRO_KEY_RIGHT, control_key_left = ALLEGRO_KEY_LEFT;
int control_key_run = ALLEGRO_KEY_Z;
HitBoxList character_body_reg;
HitBoxList item_body_reg;
class GameObjec{
protected:
unsigned int walking_speed;
HitBoxList *last_coll_test = NULL;
int last_x, last_y;
int body_high;
int left_distance;
public:
HitBox *body = NULL;
AnimatedModel *sprite = NULL;
void set_x(int x){
this->sprite->set_x(x);
this->last_x = this->body->x;
this->body->x = x + this->left_distance;
}
void set_y(int y){
this->sprite->set_y(y);
this->last_y = this->body->y;
this->body->y = y + this->body_high;
}
int get_x(){
return this->sprite->get_x();
}
int get_y(){
return this->sprite->get_y();
}
void slide_x(short int direction){
character_body_reg.pop(this->body);
this->last_coll_test = this->body->slide_x(this->walking_speed*direction, &character_body_reg);
character_body_reg.push(this->body);
this->set_x(this->body->x - this->left_distance);
}
void slide_y(short int direction){
character_body_reg.pop(this->body);
this->last_coll_test = this->body->slide_y(this->walking_speed*direction, &character_body_reg);
character_body_reg.push(this->body);
this->set_y(this->body->y - this->body_high);
}
void show_hitbox(){
al_draw_rectangle(this->body->x, this->body->y, this->body->x + this->body->width, this->body->y + this->body->height, al_map_rgb(255, 0, 0), 1);
}
GameObjec(int x, int y, unsigned int walking_speed, const char *sprite_image_path, int frames, int ticks_per_frame, int sprite_width, int sprite_height, int body_high, int body_len){
this->walking_speed = walking_speed;
this->body_high = body_high;
this->sprite = new AnimatedModel(sprite_image_path, frames, ticks_per_frame, sprite_width, sprite_height);
this->left_distance = (this->sprite->get_width() - body_len)/2;
this->body = new HitBox;
this->sprite->set_x(x);
this->sprite->set_y(y);
this->body->width = body_len;
this->body->height = this->sprite->get_height() - this->body_high;
this->body->x = x + left_distance;
this->body->y = y + this->body_high;
this->last_x = this->body->x;
this->last_y = this->body->y;
character_body_reg.push(this->body);
}
~GameObjec(){
delete this->sprite;
character_body_reg.pop(this->body);
delete this->body;
}
void draw_hitbox(){
al_draw_rectangle(this->body->x, this->body->y, this->body->x + this->body->width, this->body->y + this->body->height, al_map_rgb(255, 0, 0), 0);
}
};
class Human : public GameObjec{
protected:
bool walking = false;
public:
Human(int x, int y, const char *sprite_image_path) : GameObjec(x, y, 2, sprite_image_path, 2, 7, 64, 80, 60, 32){}
~Human(){}
void walk_down(){
this->slide_y(1);
this->sprite->stop = false;
this->walking = true;
}
void walk_up(){
this->slide_y(-1);
this->sprite->stop = false;
this->walking = true;
}
void walk_right(){
this->slide_x(1);
this->sprite->stop = false;
this->sprite->flags = 0;
this->walking = true;
}
void walk_left(){
this->slide_x(-1);
this->sprite->stop = false;
this->sprite->flags = ALLEGRO_FLIP_HORIZONTAL;
this->walking = true;
}
};
class Player : public Human{
public:
Player(int x, int y) : Human(x, y, "textures/human/sprite.png"){
}
void control(){
if(get_key(control_key_down))
this->walk_down();
else if(get_key(control_key_up))
this->walk_up();
if(get_key(control_key_right))
this->walk_right();
else if(get_key(control_key_left))
this->walk_left();
if(not this->walking){
this->sprite->set_frame(0);
this->sprite->fix_sheet_looking();
this->sprite->stop = true;
}
if(this->last_x == this->body->x and this->last_y == this->body->y)
this->walking = false;
}
void update(){
this->control();
}
};
class Zombie : public Human{
private:
//Player *to_kill;
int to_kill_x, to_kill_y;
unsigned int walk_ticks_counter = 0, follow_ticks_counter = 0;
public:
Player *to_kill;
void fix_to_kill_position(){
if(this->to_kill){
this->to_kill_x = this->to_kill->body->x;
this->to_kill_y = this->to_kill->body->y;
}
else{
this->to_kill_x = this->body->x;
this->to_kill_y = this->body->y;
}
}
Zombie(int x, int y, Player *to_kill) : Human(x, y, "textures/zombie/sprite.png"){
this->sprite->set_speed(23);
this->walking_speed = 1;
this->to_kill = to_kill;
this->fix_to_kill_position();
}
void control(){
if(this->body->y < to_kill_y)
this->walk_down();
else if(this->body->y > to_kill_y)
this->walk_up();
if(this->body->x < to_kill_x)
this->walk_right();
else if(this->body->x > to_kill_x)
this->walk_left();
if(not this->walking){
this->sprite->set_frame(0);
this->sprite->fix_sheet_looking();
this->sprite->stop = true;
}
}
void update(){
if(this->follow_ticks_counter == 78){
this->fix_to_kill_position();
this->follow_ticks_counter = 0;
}
else{
this->follow_ticks_counter += 1;
}
if(this->walk_ticks_counter == 2){
this->control();
this->walk_ticks_counter = 0;
}
else{
this->walk_ticks_counter += 1;
}
if(this->last_x == this->body->x and this->last_y == this->body->y)
this->walking = false;
}
};
I'm wondering if anyone can point me in the right direction for this error.
I am learning 2D game programming using Allegro 5 installed in Visual Studio 2010.
I have been following a tutorial series and everything has been fine until the last lesson.
The final code will build successfully. The executable will load but will crash out when I hit the space bar to fire a bullet (it's a side shooter game). I get the following error:
"Assertion failed: spl, file allegro-git\addons\audio\kgm_sample.c line 321"
It obviously has something to do with the bullet sample sound linked in with the key press.
If I comment out the line: al_play_sample(shot, 1, 0, 1, ALLEGRO_PLAYMODE_ONCE, 0); in the FireBullet() function, then the game will play fine (without the bullet sound).
I have searched everywhere and cannot find a solution.
Here is the complete code for the game:
#include <allegro5\allegro.h>
#include <allegro5\allegro_primitives.h>
#include <allegro5\allegro_font.h>
#include <allegro5\allegro_ttf.h>
#include <allegro5\allegro_image.h>
#include <allegro5\allegro_audio.h>
#include <allegro5\allegro_acodec.h>
#include "objects.h"
//GLOBALS==============================
const int WIDTH = 800;
const int HEIGHT = 400;
const int NUM_BULLETS = 5;
const int NUM_COMETS = 10;
const int NUM_EXPLOSIONS = 5;
enum STATE{TITLE, PLAYING, LOST};
enum KEYS{UP, DOWN, LEFT, RIGHT, SPACE};
bool keys[5] = {false, false, false, false, false};
SpaceShip ship;
Bullet bullets[NUM_BULLETS];
Comet comets[NUM_COMETS];
Explosion explosions[NUM_EXPLOSIONS];
ALLEGRO_SAMPLE *shot = NULL;
ALLEGRO_SAMPLE *boom = NULL;
ALLEGRO_SAMPLE *song = NULL;
ALLEGRO_SAMPLE_INSTANCE *songInstance = NULL;
//prototypes
void InitShip(SpaceShip &ship, ALLEGRO_BITMAP *image);
void ResetShipAnimation(SpaceShip &ship, int position);
void DrawShip(SpaceShip &ship);
void MoveShipUp(SpaceShip &ship);
void MoveShipDown(SpaceShip &ship);
void MoveShipLeft(SpaceShip &ship);
void MoveShipRight(SpaceShip &ship);
void InitBullet(Bullet bullet[], int size);
void DrawBullet(Bullet bullet[], int size);
void FireBullet(Bullet bullet[], int size, SpaceShip &ship);
void UpdateBullet(Bullet bullet[], int size);
void CollideBullet(Bullet bullet[], int bSize, Comet comets[], int cSize, SpaceShip &ship, Explosion explosions[], int eSize);
void InitComet(Comet comets[], int size, ALLEGRO_BITMAP *image);
void DrawComet(Comet comets[], int size);
void StartComet(Comet comets[], int size);
void UpdateComet(Comet comets[], int size);
void CollideComet(Comet comets[], int cSize, SpaceShip &ship, Explosion explosions[], int eSize);
void InitExplosions(Explosion explosions[], int size, ALLEGRO_BITMAP *image);
void DrawExplosions(Explosion explosions[], int size);
void StartExplosions(Explosion explosions[], int size, int x, int y);
void UpdateExplosions(Explosion explosions[], int size);
void InitBackground(Background &back, float x, float y, float velX, float velY, int width, int height, int dirX, int dirY, ALLEGRO_BITMAP *image);
void UpdateBackground(Background &back);
void DrawBackground(Background &back);
void ChangeState(int &state, int newState);
int main(void)
{
//primitive variable
bool done = false;
bool redraw = true;
const int FPS = 60;
int state = -1;
//object variables
Background BG;
Background MG;
Background FG;
//Allegro variables
ALLEGRO_DISPLAY *display = NULL;
ALLEGRO_EVENT_QUEUE *event_queue = NULL;
ALLEGRO_TIMER *timer = NULL;
ALLEGRO_FONT *font18 = NULL;
ALLEGRO_BITMAP *shipImage;
ALLEGRO_BITMAP *cometImage;
ALLEGRO_BITMAP *expImage;
ALLEGRO_BITMAP *title = NULL;
ALLEGRO_BITMAP *lost = NULL;
ALLEGRO_BITMAP *bgImage = NULL;
ALLEGRO_BITMAP *mgImage = NULL;
ALLEGRO_BITMAP *fgImage = NULL;
//Initialization Functions
if(!al_init()) //initialize Allegro
return -1;
display = al_create_display(WIDTH, HEIGHT); //create our display object
if(!display) //test display object
return -1;
al_init_primitives_addon();
al_install_keyboard();
al_init_font_addon();
al_init_ttf_addon();
al_init_image_addon();
al_install_audio();
al_init_acodec_addon();
event_queue = al_create_event_queue();
timer = al_create_timer(1.0 / FPS);
shipImage = al_load_bitmap("spaceship_by_arboris.png");
al_convert_mask_to_alpha(shipImage, al_map_rgb(255, 0, 255));
cometImage = al_load_bitmap("asteroids.png");
expImage = al_load_bitmap("explosion.png");
title = al_load_bitmap("Shooter_Title.png");
lost = al_load_bitmap("Shooter_Lose.png");
bgImage = al_load_bitmap("starBG.png");
mgImage = al_load_bitmap("starMG.png");
fgImage = al_load_bitmap("starFG.png");
al_reserve_samples(10);
shot = al_load_sample("shot.ogg");
boom = al_load_sample("explosion.wav");
song = al_load_sample("war.wav");
songInstance = al_create_sample_instance(song);
al_set_sample_instance_playmode(songInstance, ALLEGRO_PLAYMODE_LOOP);
al_attach_sample_instance_to_mixer(songInstance, al_get_default_mixer());
srand(time(NULL));
ChangeState(state, TITLE);
InitShip(ship, shipImage);
InitBullet(bullets, NUM_BULLETS);
InitComet(comets, NUM_COMETS, cometImage);
InitExplosions(explosions, NUM_EXPLOSIONS, expImage);
InitBackground(BG, 0, 0, 1, 0, 800, 400, -1, 1, bgImage);
InitBackground(MG, 0, 0, 2, 0, 2400, 400, -1, 1, mgImage);
InitBackground(FG, 0, 0, 4, 0, 2400, 400, -1, 1, fgImage);
font18 = al_load_font("arial.ttf", 18, 0);
al_register_event_source(event_queue, al_get_keyboard_event_source());
al_register_event_source(event_queue, al_get_timer_event_source(timer));
al_register_event_source(event_queue, al_get_display_event_source(display));
al_start_timer(timer);
while(!done)
{
ALLEGRO_EVENT ev;
al_wait_for_event(event_queue, &ev);
if(ev.type == ALLEGRO_EVENT_TIMER)
{
redraw = true;
if(keys[UP])
MoveShipUp(ship);
else if(keys[DOWN])
MoveShipDown(ship);
else
ResetShipAnimation(ship, 1);
if(keys[LEFT])
MoveShipLeft(ship);
else if(keys[RIGHT])
MoveShipRight(ship);
else
ResetShipAnimation(ship, 2);
if(state == TITLE)
{}
else if(state == PLAYING)
{
UpdateBackground(BG);
UpdateBackground(MG);
UpdateBackground(FG);
UpdateExplosions(explosions, NUM_EXPLOSIONS);
UpdateBullet(bullets, NUM_BULLETS);
StartComet(comets, NUM_COMETS);
UpdateComet(comets, NUM_COMETS);
CollideBullet(bullets, NUM_BULLETS, comets, NUM_COMETS, ship, explosions, NUM_EXPLOSIONS);
CollideComet(comets, NUM_COMETS, ship, explosions, NUM_EXPLOSIONS);
if(ship.lives <= 0)
ChangeState(state, LOST);
}
else if(state == LOST)
{}
}
else if(ev.type == ALLEGRO_EVENT_DISPLAY_CLOSE)
{
done = true;
}
else if(ev.type == ALLEGRO_EVENT_KEY_DOWN)
{
switch(ev.keyboard.keycode)
{
case ALLEGRO_KEY_ESCAPE:
done = true;
break;
case ALLEGRO_KEY_UP:
keys[UP] = true;
break;
case ALLEGRO_KEY_DOWN:
keys[DOWN] = true;
break;
case ALLEGRO_KEY_LEFT:
keys[LEFT] = true;
break;
case ALLEGRO_KEY_RIGHT:
keys[RIGHT] = true;
break;
case ALLEGRO_KEY_SPACE:
keys[SPACE] = true;
if(state == TITLE)
ChangeState(state, PLAYING);
else if(state ==PLAYING)
FireBullet(bullets, NUM_BULLETS, ship);
else if(state == LOST)
ChangeState(state, PLAYING);
break;
}
}
else if(ev.type == ALLEGRO_EVENT_KEY_UP)
{
switch(ev.keyboard.keycode)
{
case ALLEGRO_KEY_ESCAPE:
done = true;
break;
case ALLEGRO_KEY_UP:
keys[UP] = false;
break;
case ALLEGRO_KEY_DOWN:
keys[DOWN] = false;
break;
case ALLEGRO_KEY_LEFT:
keys[LEFT] = false;
break;
case ALLEGRO_KEY_RIGHT:
keys[RIGHT] = false;
break;
case ALLEGRO_KEY_SPACE:
keys[SPACE] = false;
break;
}
}
if(redraw && al_is_event_queue_empty(event_queue))
{
redraw = false;
if(state == TITLE)
{
al_draw_bitmap(title, 0, 0, 0);
}
else if(state == PLAYING)
{
DrawBackground(BG);
DrawBackground(MG);
DrawBackground(FG);
DrawShip(ship);
DrawBullet(bullets, NUM_BULLETS);
DrawComet(comets, NUM_COMETS);
DrawExplosions(explosions, NUM_EXPLOSIONS);
al_draw_textf(font18, al_map_rgb(255, 0, 255), 5, 5, 0, "Player has %i lives left. Player has destroyed %i objects", ship.lives, ship.score);
}
else if(state == LOST)
{
al_draw_bitmap(lost, 0, 0, 0);
al_draw_textf(font18, al_map_rgb(0, 255, 255), WIDTH - 10, 20, ALLEGRO_ALIGN_RIGHT, "Final Score: %i", ship.score);
}
al_flip_display();
al_clear_to_color(al_map_rgb(0,0,0));
}
}
al_destroy_sample(shot);
al_destroy_sample(boom);
al_destroy_sample(song);
al_destroy_sample_instance(songInstance);
al_destroy_bitmap(bgImage);
al_destroy_bitmap(mgImage);
al_destroy_bitmap(fgImage);
al_destroy_bitmap(title);
al_destroy_bitmap(lost);
al_destroy_bitmap(expImage);
al_destroy_bitmap(cometImage);
al_destroy_bitmap(shipImage);
al_destroy_event_queue(event_queue);
al_destroy_timer(timer);
al_destroy_font(font18);
al_destroy_display(display); //destroy our display object
return 0;
}
void InitShip(SpaceShip &ship, ALLEGRO_BITMAP *image = NULL) {
ship.x = 20;
ship.y = HEIGHT / 2;
ship.ID = PLAYER;
ship.lives = 3;
ship.speed = 6;
ship.boundx = 10;
ship.boundy = 12;
ship.score = 0;
ship.maxFrame = 3;
ship.curFrame = 0;
ship.frameCount = 0;
ship.frameDelay = 50;
ship.frameWidth = 44;
ship.frameHeight = 41;
ship.animationColumns = 3;
ship.animationDirection = 1;
ship.animationRow = 1;
if(image != NULL)
ship.image = image;
}
void ResetShipAnimation(SpaceShip &ship, int position)
{
if(position == 1)
ship.animationRow = 1;
else
ship.curFrame = 0;
}
void DrawShip(SpaceShip &ship)
{
int fx =(ship.curFrame % ship.animationColumns) * ship.frameWidth;
int fy = ship.animationRow * ship.frameHeight;
al_draw_bitmap_region(ship.image, fx, fy, ship.frameWidth,
ship.frameHeight, ship.x - ship.frameWidth / 2, ship.y - ship.frameHeight / 2, 0);
/*al_draw_filled_rectangle(ship.x - ship.boundx, ship.y - ship.boundy, ship.x + ship.boundx,
ship.y + ship.boundy, al_map_rgba(255, 0, 255, 100));*/
}
void MoveShipUp(SpaceShip &ship)
{
ship.animationRow = 0;
ship.y -= ship.speed;
if(ship.y < 0)
ship.y = 0;
}
void MoveShipDown(SpaceShip &ship)
{
ship.animationRow = 2;
ship.y += ship.speed;
if(ship.y > HEIGHT)
ship.y = HEIGHT;
}
void MoveShipLeft(SpaceShip &ship)
{
ship.curFrame = 2;
ship.x -= ship.speed;
if(ship.x < 0)
ship.x = 0;
}
void MoveShipRight(SpaceShip &ship)
{
ship.curFrame = 1;
ship.x += ship.speed;
if(ship.x > 300)
ship.x = 300;
}
void InitBullet(Bullet bullet[], int size)
{
for(int i = 0; i < size; i++)
{
bullet[i].ID = BULLET;
bullet[i].speed = 10;
bullet[i].live = false;
}
}
void DrawBullet(Bullet bullet[], int size)
{
for( int i = 0; i < size; i++)
{
if(bullet[i].live)
al_draw_filled_circle(bullet[i].x, bullet[i].y, 2, al_map_rgb(255, 255, 255));
}
}
void FireBullet(Bullet bullet[], int size, SpaceShip &ship)
{
for( int i = 0; i < size; i++)
{
if(!bullet[i].live)
{
bullet[i].x = ship.x + 17;
bullet[i].y = ship.y;
bullet[i].live = true;
al_play_sample(shot, 1, 0, 1, ALLEGRO_PLAYMODE_ONCE, 0);
break;
}
}
}
void UpdateBullet(Bullet bullet[], int size)
{
for(int i = 0; i < size; i++)
{
if(bullet[i].live)
{
bullet[i].x += bullet[i].speed;
if(bullet[i].x > WIDTH)
bullet[i].live = false;
}
}
}
void CollideBullet(Bullet bullet[], int bSize, Comet comets[], int cSize, SpaceShip &ship, Explosion explosions[], int eSize)
{
for(int i = 0; i < bSize; i++)
{
if(bullet[i].live)
{
for(int j =0; j < cSize; j++)
{
if(comets[j].live)
{
if(bullet[i].x > (comets[j].x - comets[j].boundx) &&
bullet[i].x < (comets[j].x + comets[j].boundx) &&
bullet[i].y > (comets[j].y - comets[j].boundy) &&
bullet[i].y < (comets[j].y + comets[j].boundy))
{
bullet[i].live = false;
comets[j].live = false;
ship.score++;
StartExplosions(explosions, eSize, bullet[i].x, bullet[i].y);
al_play_sample(boom, 1, 0, 1, ALLEGRO_PLAYMODE_ONCE, 0);
}
}
}
}
}
}
void InitComet(Comet comets[], int size, ALLEGRO_BITMAP *image = NULL)
{
for(int i = 0; i < size; i++)
{
comets[i].ID = ENEMY;
comets[i].live = false;
comets[i].speed = 5;
comets[i].boundx = 35;
comets[i].boundy = 35;
comets[i].maxFrame = 143;
comets[i].curFrame = 0;
comets[i].frameCount = 0;
comets[i].frameDelay = 2;
comets[i].frameWidth = 96;
comets[i].frameHeight = 96;
comets[i].animationColumns = 21;
if(rand() % 2)
comets[i].animationDirection = 1;
else
comets[i].animationDirection = -1;
if(image != NULL)
comets[i].image = image;
}
}
void DrawComet(Comet comets[], int size)
{
for(int i = 0; i < size; i++)
{
if(comets[i].live)
{
int fx = (comets[i].curFrame % comets[i].animationColumns) * comets[i].frameWidth;
int fy = (comets[i].curFrame / comets[i].animationColumns) * comets[i].frameHeight;
al_draw_bitmap_region(comets[i].image, fx, fy, comets[i].frameWidth,
comets[i].frameHeight, comets[i].x - comets[i].frameWidth / 2, comets[i].y - comets[i].frameHeight / 2, 0);
/*al_draw_filled_rectangle(comets[i].x - comets[i].boundx, comets[i].y - comets[i].boundy, comets[i].x + comets[i].boundx,
comets[i].y + comets[i].boundy, al_map_rgba(255, 0, 255, 100));*/
}
}
}
void StartComet(Comet comets[], int size)
{
for(int i = 0; i < size; i++)
{
if(!comets[i].live)
{
if(rand() % 500 == 0)
{
comets[i].live = true;
comets[i].x = WIDTH;
comets[i].y = 30 + rand() % (HEIGHT - 60);
break;
}
}
}
}
void UpdateComet(Comet comets[], int size)
{
for(int i = 0; i < size; i++)
{
if(comets[i].live)
{
if(++comets[i].frameCount >= comets[i].frameDelay)
{
comets[i].curFrame += comets[i].animationDirection;
if(comets[i].curFrame >= comets[i].maxFrame)
comets[i].curFrame = 0;
else if( comets[i].curFrame <= 0)
comets[i].curFrame = comets[i].maxFrame - 1;
comets[i].frameCount = 0;
}
comets[i].x -= comets[i].speed;
}
}
}
void CollideComet(Comet comets[], int cSize, SpaceShip &ship, Explosion explosions[], int eSize)
{
for(int i = 0; i < cSize; i++)
{
if(comets[i].live)
{
if(comets[i].x - comets[i].boundx < ship.x + ship.boundx &&
comets[i].x + comets[i].boundx > ship.x - ship.boundx &&
comets[i].y - comets[i].boundy < ship.y + ship.boundy &&
comets[i].y + comets[i].boundy > ship.y - ship.boundy)
{
ship.lives--;
comets[i].live = false;
StartExplosions(explosions, eSize, ship.x, ship.y);
al_play_sample(boom, 1, 0, 1, ALLEGRO_PLAYMODE_ONCE, 0);
}
else if(comets[i].x < 0)
{
comets[i].live = false;
ship.lives--;
}
}
}
}
void InitExplosions(Explosion explosions[], int size, ALLEGRO_BITMAP *image = NULL)
{
for(int i = 0; i < size; i++)
{
explosions[i].live = false;
explosions[i].maxFrame = 31;
explosions[i].curFrame = 0;
explosions[i].frameCount = 0;
explosions[i].frameDelay = 1;
explosions[i].frameWidth = 128;
explosions[i].frameHeight = 128;
explosions[i].animationColumns = 8;
explosions[i].animationDirection = 1;
if(image != NULL)
explosions[i].image = image;
}
}
void DrawExplosions(Explosion explosions[], int size)
{
for(int i = 0; i < size; i++)
{
if(explosions[i].live)
{
int fx = (explosions[i].curFrame % explosions[i].animationColumns) * explosions[i].frameWidth;
int fy = (explosions[i].curFrame / explosions[i].animationColumns) * explosions[i].frameHeight;
al_draw_bitmap_region(explosions[i].image, fx, fy, explosions[i].frameWidth,
explosions[i].frameHeight, explosions[i].x - explosions[i].frameWidth / 2, explosions[i].y - explosions[i].frameHeight / 2, 0);
}
}
}
void StartExplosions(Explosion explosions[], int size, int x, int y)
{
for(int i = 0; i < size; i++)
{
if(!explosions[i].live)
{
explosions[i].live = true;
explosions[i].x = x;
explosions[i].y = y;
break;
}
}
}
void UpdateExplosions(Explosion explosions[], int size)
{
for(int i = 0; i < size; i++)
{
if(explosions[i].live)
{
if(++explosions[i].frameCount >= explosions[i].frameDelay)
{
explosions[i].curFrame += explosions[i].animationDirection;
if(explosions[i].curFrame >= explosions[i].maxFrame)
{
explosions[i].curFrame = 0;
explosions[i].live = false;
}
explosions[i].frameCount = 0;
}
}
}
}
void InitBackground(Background &back, float x, float y, float velx, float vely, int width, int height, int dirX, int dirY, ALLEGRO_BITMAP *image)
{
back.x = x;
back.y = y;
back.velX = velx;
back.velY = vely;
back.width = width;
back.height = height;
back.dirX = dirX;
back.dirY = dirY;
back.image = image;
}
void UpdateBackground(Background &back)
{
back.x += back.velX * back.dirX;
if(back.x + back.width <= 0)
back.x = 0;
}
void DrawBackground(Background &back)
{
al_draw_bitmap(back.image, back.x, back.y, 0);
if(back.x + back.width < WIDTH)
al_draw_bitmap(back.image, back.x + back.width, back.y, 0);
}
void ChangeState(int &state, int newState)
{
if(state == TITLE)
{}
else if(state == PLAYING)
{
al_stop_sample_instance(songInstance);
}
else if(state == LOST)
{}
state = newState;
if(state == TITLE)
{}
else if(state == PLAYING)
{
InitShip(ship);
InitBullet(bullets, NUM_BULLETS);
InitComet(comets, NUM_COMETS);
InitExplosions(explosions, NUM_EXPLOSIONS);
al_play_sample_instance(songInstance);
}
else if(state == LOST)
{}
}
Check that a pointer you are using is not NULL when you try to load the file. If it stays NULL then that exception is always thrown because the system will try to read from memory address 0x0 which frankly does not exist
I am attempting to make a simple scrolling shooter game with SDL2. I have a moving player on a screen, and I am trying to make the player shoot a bullet using an array (so they can shoot multiple bullets) however, when I press the space bar, nothing happens, and instead the bullet image sort of flashes in the top left corner.
Heres the same code in codepad: http://codepad.org/rOhE1AqY
#include <SDL.h>
#include <stdio.h> //use for things like printf, same as cout
#include <iostream>
#include <string>
#include <time.h>
using namespace std;
//screend dimensions& sprtie dimensions
const int SCREEN_HEIGHT = 600;
const int SCREEN_WIDTH = 400;
const int SPRITE_WIDTH = 60;
const int SPRITE_HEIGHT = 80;
const int MAX_BULLETS = 50;
SDL_Window* Window = NULL;//the window rendering to
SDL_Surface* ScreenSurface = NULL;//surface contained by window
SDL_Surface* Background = NULL;
SDL_Surface* Player = NULL;
SDL_Surface* Enemy = NULL;
SDL_Surface* Bullet = NULL;
SDL_Surface* newBullet = NULL;
SDL_Rect posPlayer, posEnemy, posBullet, posnewBullet;
const Uint8* keystate = SDL_GetKeyboardState(NULL);
SDL_Event event;
class thePlayer
{
public:
thePlayer();
void player_movement();
void show_player();
private:
};
class theBullet
{
public:
theBullet();
bool isActive;
int x_position;
int y_position;
void bullet_movement();
void add_new_bullet();
void show_bullet();
private:
};
theBullet arrayofBullets[MAX_BULLETS];
class theEnemy
{
public:
theEnemy();
void enemy_movement();
void show_enemy();
private:
};
thePlayer::thePlayer()
{
posPlayer.x = 170;
posPlayer.y = SCREEN_HEIGHT;
posPlayer.w = 20;
posPlayer.h = 30;
}
void thePlayer::player_movement()
{
if(keystate[SDL_SCANCODE_LEFT])
{
posPlayer.x -= 2;
}
if(keystate[SDL_SCANCODE_RIGHT])
{
posPlayer.x += 2;
}
if(keystate[SDL_SCANCODE_UP])
{
posPlayer.y -= 2;
}
if(keystate[SDL_SCANCODE_DOWN])
{
posPlayer.y += 2;
}
if ((posPlayer.x + SPRITE_WIDTH) > SCREEN_WIDTH)
{
posPlayer.x = (SCREEN_WIDTH - SPRITE_WIDTH);
}
if ((posPlayer.y + SPRITE_HEIGHT) > SCREEN_HEIGHT)
{
posPlayer.y = (SCREEN_HEIGHT - SPRITE_HEIGHT);
}
}
void thePlayer::show_player()
{
SDL_BlitSurface(Player, NULL, ScreenSurface, &posPlayer);
SDL_SetColorKey(Player, SDL_TRUE, SDL_MapRGB(Player->format, 255, 255, 255));
}
theBullet::theBullet()
{
/*posBullet.x;
posBullet.y;
posBullet.w = 10;
posBullet.h = 15;*/
}
void theBullet::bullet_movement()
{
/*if(keystate[SDL_SCANCODE_SPACE])
{
posBullet.x = posPlayer.x + 25;
posBullet.y = posPlayer.y + 10;
}
posBullet.y -= 2;
if(posBullet.y < 0)
{
posBullet.y = -50;
}*/
}
void theBullet::show_bullet()
{
//SDL_BlitSurface(Bullet, NULL, ScreenSurface, &posBullet);
//SDL_SetColorKey(Bullet, SDL_TRUE, SDL_MapRGB(Player->format, 255, 255, 255));//removes white background
}
theEnemy::theEnemy()
{
srand (time(NULL));
posEnemy.x = rand() % 300 + 50;
posEnemy.y =0;
posEnemy.w = 35;
posEnemy.h = 60;
}
void theEnemy::enemy_movement()
{
posEnemy.y += 1;
if(posEnemy.y > SCREEN_HEIGHT)
{
posEnemy.y = SCREEN_HEIGHT +50;
}
}
void theEnemy::show_enemy()
{
SDL_BlitSurface(Enemy, NULL, ScreenSurface, &posEnemy);
SDL_SetColorKey(Enemy, SDL_TRUE, SDL_MapRGB(Player->format, 255, 255, 255));
}
bool initialise()
{
bool success = true;
if (SDL_Init(SDL_INIT_EVERYTHING) !=0)
{
cout<<"SDL_Init Error."<<SDL_GetError()<<endl;
success = false;
}
else
{
//create the window for game
Window = SDL_CreateWindow("Scrolling Shooter Game", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, SCREEN_WIDTH, SCREEN_HEIGHT, SDL_WINDOW_SHOWN);
if (Window == NULL)
{
cout<<"Window Error"<<SDL_GetError()<<endl;
success = false;
}
else
{
//get window surface
ScreenSurface = SDL_GetWindowSurface(Window);
}
}
return success;
}
bool LoadingMedia()
{
bool success = true;
Background = SDL_LoadBMP("background.bmp");
if (Background == NULL)
{
cout<<"Error in loading background."<<SDL_GetError()<<endl;
success = false;
}
Player = SDL_LoadBMP("spaceship.bmp");
if (Player == NULL)
{
cout<<"Error in loading player."<<SDL_GetError()<<endl;
success = false;
}
Enemy = SDL_LoadBMP("enemy.bmp");
if (Enemy == NULL)
{
cout<<"Error in loading enemy."<<SDL_GetError()<<endl;
success = false;
}
Bullet = SDL_LoadBMP("bullet.bmp");
if (Bullet == NULL)
{
cout<<"Error in loading bullet."<<SDL_GetError()<<endl;
success = false;
}
return success;
}
void closedown()
{
SDL_FreeSurface(Background);
Background = NULL;
SDL_FreeSurface(Player);
Player = NULL;
SDL_FreeSurface(Enemy);
Enemy = NULL;
SDL_DestroyWindow(Window);
Window = NULL;
SDL_Quit();
}
int main(int argc, char** argv)
{
bool quit = false;
thePlayer myPlayer;
theEnemy myEnemy;
theBullet myBullet;
if (!initialise())
{
cout<<"Failed to initialise"<<SDL_GetError()<<endl;
}
else
{
if (!LoadingMedia())
{
cout<<"Error loading media"<<SDL_GetError()<<endl;
}
}
//makes all bullets false
for (int i=0; i<MAX_BULLETS; i++)
{
arrayofBullets[i].isActive = false;
}
//GAME LOOP
while (quit == false)
{
SDL_BlitSurface(Background, NULL, ScreenSurface, NULL);
myPlayer.show_player();
myPlayer.player_movement();
while (SDL_PollEvent(&event))
{
if( event.type == SDL_QUIT )
{
quit = true;
break;
}
if(keystate[SDL_SCANCODE_SPACE])
{
for (int i=0; i<MAX_BULLETS; i++)
{
if (arrayofBullets[i].isActive == false)
{
arrayofBullets[i].x_position = posPlayer.x + 25;
arrayofBullets[i].y_position = posPlayer.y + 10;
arrayofBullets[i].isActive = true;
break;
}
}
}
//update game objects
for (int i=0; i<MAX_BULLETS; i++)
{
if (arrayofBullets[i].isActive == true)
{
arrayofBullets[i].y_position -= 2;
if (arrayofBullets[i].y_position < 0)
{
arrayofBullets[i].isActive = false;
}
}
}
for (int i=0; i<MAX_BULLETS; i++)
{
if (arrayofBullets[i].isActive == true)
{
SDL_BlitSurface(Bullet, NULL, ScreenSurface, NULL);
}
}
}
//myPlayer.show_player();
//myBullet.show_bullet();
//myEnemy.show_enemy();
//myPlayer.player_movement();
//myBullet.bullet_movement();
//myEnemy.enemy_movement();
SDL_UpdateWindowSurface(Window); //updates screen
}
closedown();
return 0;
}
SDL_BlitSurface(Bullet, NULL, ScreenSurface, NULL);
You haven't specified destination rect, so it will blit on left-top corner.
It should be
SDL_Rect dstrect;
dstrect.x = arrayofBullets[i].x_position;
dstrect.y = arrayofBullets[i].y_position;
dstrect.w = Bullet->w;
dstrect.h = Bullet->h;
SDL_BlitSurface(Bullet, NULL, ScreenSurface, &dstrect);
Here is the code of draw()
My problem is that it draws things only once, then it draws the same.
I am using SLD_Flip(surface) after it.
sqrbmp, applebmp, blank are surfaces with BMP loaded
des is a rectangle
screen is main surface
It is supposed to draw a game map.
Where is my bad?
// includes, defines etc.
const int mapx = 32; // 640 / 20(bmp size)
const int mapy = 24; // 480 / 20
//nothing important
SDL_Event keys;
SDL_Surface * screen = NULL;
SDL_Surface * blank = NULL;
SDL_Surface * sqrbmp = NULL;
SDL_Surface * applebmp = NULL;
SDL_Rect des;
int map[mapy][mapx];
// nothing important
// nothing important
struct square
{
square(int xt, int yt, int dirt);
int x;
int y;
int dir;
};
std::vector <square> snake;
square::square(int xt, int yt, int dirt)
{
x = xt;
y = yt;
dir = dirt;
snake.push_back(*this);
}
bool squareontile(int x, int y)
{
// returns true if there is square on that tile
}
void draw()
{
for(int yt = 0 ; yt < mapy; yt++)
{
for(int xt = 0 ; xt < mapx; xt++)
{
des.y = yt * 20;
des.x = xt * 20;
if(squareontile(xt,yt) == 1)
{
SDL_BlitSurface(sqrbmp, NULL, screen, &des);
}
else
{
switch(map[yt][xt])
{
case 5:
SDL_BlitSurface(applebmp, NULL, screen, &des);
break;
default:
SDL_BlitSurface(blank, NULL, screen, &des);
break;
}
}
}
}
}
// nothing important
void checkmap()
{
for(int yt = 0 ; yt < mapy; yt++)
{
for(int xt = 0 ; xt < mapx; xt++)
{
if(squareontile(xt,yt) == 0 && map[yt][xt] != 5)
{
map[yt][xt] = 0;
}
}
}
}
bool checksnake()
{
for(int a = 0; a < snake.size() ; a++)
{
for(int b = 0; b < snake.size() ; b++)
{
if(snake[a].y == snake[b].y && snake[a].x == snake[b].x && a != b)
{
return true;
}
}
}
}
// nothing important
void apple()
{
if(!appleisonmap())
{
int y;
int x;
do
{
y = rand() % mapy;
x = rand() % mapx;
} while(squareontile(x,y));
map[y][x] = 5;
}
}
// nothing important
int main( int argc, char * args[] )
{
// nothing important
SDL_Init( SDL_INIT_EVERYTHING );
screen = SDL_SetVideoMode( 640, 480, 24, SDL_SWSURFACE );
applebmp = SDL_LoadBMP("apple.bmp"); // 20x20
blank = SDL_LoadBMP("blank.bmp"); // 20x20
sqrbmp = SDL_LoadBMP( "sqr.bmp" ); // 20x20
for(int b = 7 ; b > 0 ; b--)
{
square(5,b,1);
}
while(!exitv && !game_over)
{
draw();
game_over = checksnake();
SDL_Flip( screen );
SDL_Delay(100);
while( SDL_PollEvent( & keys ) )
{
if( keys.type == SDL_QUIT )
{
exitv = true;
}
// detecting other keys, input for moving, ya know
}
checkmap();
apple();
checksquare();
}
SDL_FreeSurface( sqrbmp );
SDL_FreeSurface( applebmp );
SDL_FreeSurface( blank );
SDL_Quit();
return 0;
}
Ahh found the error. I just forgot 1 function and the snake wasnt moving.