#include <stdio.h>
#include <gtk/gtk.h>
#include <math.h>
// 游戏区域的定义
#define GAME_WIDTH 500
#define GAME_LENGTH 600
struct Ball
{
int x, y; // 小球的坐标(圆心)
int speed_x, speed_y; // 小球的速度
int radius; // 半径
};
struct Baffle
{
int x, y; // 挡板的坐标(挡板左上角)
int width, length; // 挡板的长和宽
};
struct Bricks
{
int matrix[8][12]; // 记录砖块群信息的矩阵
int width, length; // 每一块砖块的长和宽
};
// 全局变量
struct Ball ball; // 小球
struct Baffle baffle; // 挡板
struct Bricks bricks; // 砖块
GtkWidget *window = NULL; // 游戏主窗口
GktWidget *lose = NULL; // 游戏失败提示窗口
GtkWidget *win = NULL; // 游戏胜利窗口
int pause = 1; // 处理暂停的变量。0代表游戏继续,1代表游戏暂停
// 函数声明
void init(void);
static gboolean expose_handler(GtkWidget * widget,
GdkEventExpose * event, gpointer data);
static gboolean time_handler(GtkWidget *widget);
void press_handler(GtkWidget *widget, GdkEventKey *event);
int main(int argc, char **argv)
{
init();
gtk_init(&argc,&argv);
window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
g_signal_connect(G_OBJECT(window), "destroy", G_CALLBACK(gtk_main_quit),
NULL);
g_signal_connect(G_OBJECT(window), "expose_event", G_CALLBACK(expose_handler),
NULL);
g_signal_connect ( G_OBJECT ( window) , "key_press_event" ,
G_CALLBACK (press_handler) , NULL ) ;
gtk_window_set_position ( GTK_WINDOW ( window) ,
GTK_WIN_POS_CENTER) ;
gtk_window_set_default_size ( GTK_WINDOW ( window) , GAME_LENGTH, GAME_WIDTH ) ;
gtk_widget_set_app_paintable ( window, TRUE ) ;
gtk_widget_show_all(window) ;
g_timeout_add(10, (GSourceFunc)time_handler, NULL);
gtk_main() ;
return 0;
}
/*
*
* name: init
* @param
* @return
*
* 完成初始化
*/
void init()
{
int i,j;
// 挡板的初始化
baffle.length = 100;
baffle.width = 10;
baffle.x = GAME_LENGTH / 2 - baffle.length / 2;
baffle.y = GAME_WIDTH - baffle.width;
// 小球的初始化
ball.radius = 5;
ball.x = GAME_LENGTH / 2;
ball.y = baffle.y - ball.radius;
ball.speed_x = 1;
ball.speed_y = -1;
// 砖块群的初始化
bricks.length = 50;
bricks.width = 20;
for(i = 0; i < 8; i++)
{
for(j = 0; j < 12; j++)
bricks.matrix[i][j] = 1;
}
}
static gboolean expose_handler(GtkWidget * widget,
GdkEventExpose * event, gpointer data)
{
cairo_t *cr;
int i,j;
cr = gdk_cairo_create(widget ->window);
// 先画出挡板(矩形)
cairo_set_line_width(cr, 2);
cairo_set_source_rgb(cr, 0.69, 0.19, 0);
cairo_rectangle(cr, baffle.x, baffle.y, baffle.length, baffle.width);
cairo_stroke_preserve(cr);
cairo_set_source_rgb(cr, 0.3, 0.4, 0.6);
cairo_fill(cr);
// 再画出小球
cairo_set_line_width(cr, 0);
cairo_arc(cr, ball.x, ball.y, ball.radius, 0, 2 * M_PI);
cairo_stroke_preserve(cr);
cairo_set_source_rgb(cr, 1, 0, 0);
cairo_fill(cr);
// 画出砖块群
for(i = 0; i < 8; i++)
{
for(j = 0; j < 12; j++)
{
if(bricks.matrix[i][j] != 0)
{
cairo_set_line_width(cr, 1);
cairo_set_source_rgb(cr, 1, 1, 0);
cairo_rectangle(cr, j * bricks.length, i * bricks.width, bricks.length, bricks.width);
cairo_stroke_preserve(cr);
cairo_set_source_rgb(cr, 0.4, 0.8, 0.2);
cairo_fill(cr);
}
}
}
cairo_destroy(cr);
return FALSE;
}
static gboolean time_handler(GtkWidget *widget)
{
int top_ball, bottom_ball, right_ball, left_ball;
int virtual_x, virtual_y;
if(pause == 1)
return TRUE;
ball.x += ball.speed_x;
ball.y += ball.speed_y;
if(ball.x <= 0 + ball.radius || ball.x >= GAME_LENGTH - ball.radius)
ball.speed_x = -ball.speed_x;
if(ball.y <= 0 + ball.radius)
ball.speed_y = -ball.speed_y;
if(ball.y >= GAME_WIDTH - baffle.width - ball.radius)
{
if(ball.x >= baffle.x && ball.x <= baffle.x + baffle.length)
ball.speed_y = -ball.speed_y;
}
// 小球落入最下方,停止游戏
if(ball.y >= GAME_WIDTH - ball.radius)
return FALSE;
// 检测碰撞
// 当小球向右下方移动时,小球的右方和下方可能碰到砖块
if(ball.speed_x > 0 && ball.speed_y > 0)
{
bottom_ball = ball.y + ball.radius;
virtual_x = ball.x / bricks.length;
virtual_y = bottom_ball / bricks.width;
// 小球下方碰撞到砖块
if(virtual_x >= 0 && virtual_x <= 11 && virtual_y >= 0 && virtual_y <= 7)
{
if(bricks.matrix[virtual_y][virtual_x] != 0) // 该砖块存在
{
bricks.matrix[virtual_y][virtual_x]--;
ball.speed_y = -ball.speed_y;
}
}
right_ball = ball.x + ball.radius;
virtual_x = right_ball / bricks.length;
virtual_y = ball.y / bricks.width;
if(virtual_x >= 0 && virtual_x <= 11 && virtual_y >= 0 && virtual_y <= 7)
{
if(bricks.matrix[virtual_y][virtual_x] != 0)
{
bricks.matrix[virtual_y][virtual_x]--;
ball.speed_x = -ball.speed_x;
}
}
}
// 当小球向右上方移动时
else if(ball.speed_x > 0 && ball.speed_y < 0)
{
top_ball = ball.y - ball.radius;
virtual_x = ball.x / bricks.length;
virtual_y = top_ball / bricks.width;
// 小球上方碰撞到砖块
if(virtual_x >= 0 && virtual_x <= 11 && virtual_y >= 0 && virtual_y <= 7)
{
if(bricks.matrix[virtual_y][virtual_x] != 0) // 该砖块存在
{
bricks.matrix[virtual_y][virtual_x]--;
ball.speed_y = -ball.speed_y;
}
}
right_ball = ball.x + ball.radius;
virtual_x = right_ball / bricks.length;
virtual_y = ball.y / bricks.width;
// 小球右方碰撞到砖块
if(virtual_x >= 0 && virtual_x <= 11 && virtual_y >= 0 && virtual_y <= 7)
{
if(bricks.matrix[virtual_y][virtual_x] != 0) // 该砖块存在
{
bricks.matrix[virtual_y][virtual_x]--;
ball.speed_x = -ball.speed_x;
}
}
}
// 当小球向左下方移动时
else if(ball.speed_x < 0 && ball.speed_y > 0)
{
bottom_ball = ball.y + ball.radius;
virtual_x = ball.x / bricks.length;
virtual_y = bottom_ball / bricks.width;
// 小球下方碰撞到砖块
if(virtual_x >= 0 && virtual_x <= 11 && virtual_y >= 0 && virtual_y <= 7)
{
if(bricks.matrix[virtual_y][virtual_x] != 0) // 该砖块存在
{
bricks.matrix[virtual_y][virtual_x]--;
ball.speed_y = -ball.speed_y;
}
}
left_ball = ball.x - ball.radius;
virtual_x = left_ball / bricks.length;
virtual_y = ball.y / bricks.width;
// 小球左方碰撞到砖块
if(virtual_x >= 0 && virtual_x <= 11 && virtual_y >= 0 && virtual_y <= 7)
{
if(bricks.matrix[virtual_y][virtual_x] != 0) // 该砖块存在
{
bricks.matrix[virtual_y][virtual_x]--;
ball.speed_x = -ball.speed_x;
}
}
}
// 当小球向左上方移动时
else
{
top_ball = ball.y - ball.radius;
virtual_x = ball.x / bricks.length;
virtual_y = top_ball / bricks.width;
// 小球下方碰撞到砖块
if(virtual_x >= 0 && virtual_x <= 11 && virtual_y >= 0 && virtual_y <= 7)
{
if(bricks.matrix[virtual_y][virtual_x] != 0) // 该砖块存在
{
bricks.matrix[virtual_y][virtual_x]--;
ball.speed_y = -ball.speed_y;
}
}
left_ball = ball.x - ball.radius;
virtual_x = left_ball / bricks.length;
virtual_y = ball.y / bricks.width;
// 小球左方碰撞到砖块
if(virtual_x >= 0 && virtual_x <= 11 && virtual_y >= 0 && virtual_y <= 7)
{
if(bricks.matrix[virtual_y][virtual_x] != 0) // 该砖块存在
{
bricks.matrix[virtual_y][virtual_x]--;
ball.speed_x = -ball.speed_x;
}
}
}
gdk_window_invalidate_rect(window ->window, NULL, FALSE);
return TRUE ;
}
void press_handler(GtkWidget *widget, GdkEventKey *event)
{
switch(event ->keyval)
{
case 65361: // 左键
if(baffle.x > 0)
baffle.x -= 10;
break;
case 65363: // 右键
if(baffle.x < 600 - baffle.length)
baffle.x += 10;
break;
case 32: // 空格(暂停)
pause = 1;
break;
case 65293: // 回车
pause = 0;
break;
default:
break;
}
}