Игра: Бомбермен

Первый уровень

Задача: создать игру Бомбермен;
Использованный API: GTK/GDK;
Среда разработки: Visual Studio 2008;

/* Подключаемые библиотеки */
#include <gtk/gtk.h>
#include <gdk/gdkkeysyms.h>
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#define WIDTH 450
#define HEIGHT 400
#define WW 400
#define HH 50
#define RR 40
#define the_bomb_has_been_planted bomb=1 // поставлена бомба
#define the_bomb_has_been_defused bomb=0 // бомбы нет

Создание начального состояния производиться с помощью матрицы начального состояния:

int mtr[10][10] = { 9,0,0,1,2,1,1,0,0,1,
  		    0,2,1,0,2,0,2,2,1,0,
		    1,1,0,2,1,0,1,2,1,2,
	            1,2,0,2,1,2,0,0,0,1,
	 	    0,2,0,0,0,2,2,0,1,1,
	 	    0,0,2,0,1,1,1,0,0,1,
		    1,0,2,0,2,2,0,0,0,2,
		    2,0,1,1,1,2,2,1,2,2,
		    1,1,1,0,0,2,0,1,1,0,
		    2,1,1,0,1,1,0,0,0,5 };

При создании состояния вместо 0 - рисуется просто черный квадрат, 1 - стена кирпичей, 2 - непроходимый блок, 9 - сам бомбермен, 5 - финиш. Прорисовка состояния осуществляется следующей функцией:

gboolean creatboomstate()
{
	int i,j;
	gdk_draw_rectangle(w,gc,TRUE,0,0,WW,HEIGHT);
	for(j=0; j < 10; j++)
	{
		for(i=0; i < 10; i++)
		{
			if(mtr[i][j] == 1) gdk_draw_picture(kp,i*RR,j*RR,RR,RR);
			if(mtr[i][j] == 2) gdk_draw_picture(st,i*RR,j*RR,RR,RR);
			if(mtr[i][j] == 5) gdk_draw_picture(fin,i*RR,j*RR,RR,RR);
			if(mtr[i][j] == 9) 
			{
				gdk_draw_picture(bm,i*RR,j*RR,RR,RR);
				x_m = i; //координата бомбермена (X)
				y_m = j; //координата бомбермена (Y)
			}
		}
	}
 
	boomstatetrue = 1; // состояние создано и можно приступать к игре.
	return TRUE;
}

В этой функции, функция "gdk_draw_picture", отвечает за прорисовку картинки в заданных координатах:

gboolean gdk_draw_picture(GdkPixbuf *picture,gint x,gint y,gint wi,gint hh)
{
	gdk_draw_pixbuf(w,gc,picture,0,0,x,y,wi,hh,GDK_RGB_DITHER_NONE,0,0);
	return TRUE;
}

В меню есть 3 кнопки:
1) Start - Прорисовывает начальное состояние (1 уровень).
2) Rand - Создает случайным образом новый уровень для прохождения.
3) Exit - закрывает игру.

При перемещении бомбермена, осуществляется проверка, возможно ли перемещение в данном направлении (т.е. стоит ли в матрице 0), в следующем коде, представлена проверка на возможность перемещения вправо и собственно само перемещение:

if(x_m < 9 && mtr[x_m+1][y_m] == 0) // x_m - координата "х" бомбермена.
{
        gdk_draw_rectangle(w,gc,TRUE,x_m*RR,y_m*RR,RR,RR);
        mtr[x_m][y_m] = 0;
	x_m = x_m + 1;
	mtr[x_m][y_m] = 9;
	gdk_draw_picture(bm,x_m*RR,y_m*RR,RR,RR);
}

Такая обработка перемещения подходит только для тех случаев, когда не установлена бомба, в противном случае используется следующий код, для обработки состояния "the_bomb_has_been_planted":

if(x_m < 9 && mtr[x_m+1][y_m] == 0)
{
	if(bomb) // если установлена бомба
	{
		if(step == 1) // после установки бомбы, есть 2 хода, чтобы уйти от взрыва. Ход 1:
		{
			step = step - 1; // ходов больше нет.
                        /* Перемещение */
			mtr[x_m][y_m] = 0;
			gdk_draw_rectangle(w,gc,TRUE,x_m*RR,y_m*RR,RR,RR);
	        	gdk_draw_picture(bb,x_b*RR,y_b*RR,RR,RR);
			x_m = x_m + 1;
			gdk_draw_picture(bm,x_m*RR,y_m*RR,RR,RR);
			mtr[x_m][y_m] = 9;
 
			return TRUE;
		}
		else // ходов больше нет.
		{
			gdk_draw_rectangle(w,gc,TRUE,x_m*RR,y_m*RR,RR,RR);
			mtr[x_m][y_m] = 0;
			x_m = x_m + 1;
			gdk_draw_picture(bm,x_m*RR,y_m*RR,RR,RR);
			mtr[x_m][y_m] = 9;
 
                        /* Если в радиусе поражения бомбы есть бомбермен, игра окончена */
        		if(mtr[x_b][y_b] == 9 || mtr[x_b + 1][y_b] == 9 || mtr[x_b - 1][y_b] == 9 || mtr[x_b][y_b + 1] == 9 || mtr[x_b][y_b - 1] == 9)
			{
				gdk_draw_picture(go,0,0,WW,HEIGHT);
				boomstatetrue = 0;
				the_bomb_has_been_defused;
				return TRUE;
			}
 
                        /* Проверяем на возможность взыва и взрываем окрестность бомбы: */
			gdk_draw_rectangle(w,gc,TRUE,x_b*RR,y_b*RR,RR,RR);
			mtr[x_b][y_b] = 0;
			if(mtr[x_b + 1][y_b] == 0 || mtr[x_b + 1][y_b] == 1) // или пусто, или кирпичная стена.
			{
				if(x_b < 9)
				{
					gdk_draw_rectangle(w,gc,TRUE,(x_b+1)*RR,y_b*RR,RR,RR);
					mtr[x_b + 1][y_b] = 0;
				}
			}
			if(mtr[x_b - 1][y_b] == 0 || mtr[x_b - 1][y_b] == 1) 
			{
				if(x_b > 0)
				{
					gdk_draw_rectangle(w,gc,TRUE,(x_b-1)*RR,y_b*RR,RR,RR);
					mtr[x_b - 1][y_m] = 0;
				}
			}
			if(mtr[x_b][y_b + 1] == 0 || mtr[x_b][y_b + 1] == 1) 
			{
				if(y_b < 9)
				{
					gdk_draw_rectangle(w,gc,TRUE,x_b*RR,(y_b+1)*RR,RR,RR);
					mtr[x_b][y_b + 1] = 0;
				}
			}
			if(mtr[x_b][y_b - 1] == 0 || mtr[x_b][y_b - 1] == 1) 
			{
				if(y_b > 0)
				{
					gdk_draw_rectangle(w,gc,TRUE,x_b*RR,(y_b-1)*RR,RR,RR);
					mtr[x_b][y_b - 1] = 0;
				}
			}
 
			the_bomb_has_been_defused;
			return TRUE;
		}
 
                /* Перемещение */		
		mtr[x_m][y_m] = 0;
		gdk_draw_rectangle(w,gc,TRUE,x_m*RR,y_m*RR,RR,RR);
		gdk_draw_picture(bb,x_b*RR,y_b*RR,RR,RR);
		x_m = x_m + 1;
		mtr[x_m][y_m] = 9;
		gdk_draw_picture(bm,x_m*RR,y_m*RR,RR,RR);
	}
}

Основная задача состоит в том, чтобы добраться бомберменом до красных флажков (финиша). Но, это не всегда так просто, как кажется на первый взгяд. Есть несколько видов препятствий, например обычные стены и непроходимые блоки. Но есть так же и невидимые препятствия, которые могут остаться после взрыва кирпичных стен. У них есть одна особенность, убрать их можно только одним способом - взорвать бомбу с определенной стороны невидимого препятствия. Так же есть "обманки", которые маскируют себя под кирпичные стены или непроходимые блоки, хотя бомбермен проходит их без особых усилий. "Обманки" легко взрываются бомбой, чтобы можно было дальше продолжать путь. У бомбермена есть 2 типа бомб, выбирать между которыми вам нельзя, они появляются с определенной частотой:
1) Обычная бомба, которая взрывается после 2х ходов (вероятность: 99%).
2) Быстрая бомба, которая взрывается после 1,5 ходов, т.е. уйти от неё затруднительно (вероятность: 1%).

Картинки, используемые в данной игре, лежат в папке "state", и подключаются следующей функцией, для дальнейшего использования:

GtkWidget *mm1;
GdkPixbuf *m1;
mm1 = gtk_image_new_from_file("state//m1.jpg");
m1 = gtk_image_get_pixbuf(GTK_IMAGE(mm1));

Так же производится обработка нажатия правой кнопки на мышке:

gboolean on_click(GtkWidget *Window, GdkEventButton *event, gpointer data)
{
	if(x_mouse > HEIGHT - HH && y_mouse > 0 && y_mouse < HH) // Область "Start"
	{
		int i,j;
		for(i=0; i < 10; i++)
		{
			for(j=0; j < 10; j++)
			{
				mtr[i][j] = std[i][j]; // std - это матрица, хранящее начальное состояние.
			}
		}
		step = 1;
		the_bomb_has_been_defused;
		creatboomstate(); // создаем состояние на экране.
	}
	else if(x_mouse > HEIGHT - HH && y_mouse > HH && y_mouse < HH*2) // Область "Rand"
	{
		step = 1;
		the_bomb_has_been_defused;
		creatrandomboomstate(); // создает случайное состояние.
	}
	else if(x_mouse > HEIGHT - HH && y_mouse > HH*2 && y_mouse < HH*3) // // Область "Exit"
	{
		gtk_main_quit();
	}
 
	return TRUE;
}

Создание случайного состояния обеспечивает следующая функция:

gboolean creatrandomboomstate()
{
	int i,x1,x2,y1,y2,temp,j;
	for(i=0; i < 10; i++)
	{
		for(j=0; j < 10; j++)
		{
			mtr[i][j] = std[i][j];
		}
	}
 
	for(i=0; i < 100; i++) // случайное перемещение эклементов начального состояния (100 раз)
	{
		x1 = rand()%10;
		y1 = rand()%10;
		x2 = rand()%10;
		y2 = rand()%10;
 
		temp = mtr[x1][y1];
		mtr[x1][y1] = mtr[x2][y2];
		mtr[x2][y2] = temp;
	}
 
	creatboomstate(); // отрисовываем полученное состояние.
	return TRUE;
}

Приятной игры.

Ключевые слова: 
Игра, Бомбермен
ВложениеРазмер
bomberman.rar337.68 кб