#include "common.h"
//win32下的延时函数支持
#ifdef WIN32
#include <windows.h>
#define SLEEP_TIME_1 Sleep(1000*0.003);
#define SLEEP_TIME_2 Sleep(1000*0.001);
#else
#define SLEEP_TIME_1 usleep(1000*1000*0.003);
#define SLEEP_TIME_2 usleep(1000*1000*0.001);
#endif
//键值定义
#ifndef GDK_KEY_space
#define GDK_KEY_space GDK_space
#endif
#ifndef GDK_KEY_P
#define GDK_KEY_P GDK_P
#endif
#ifndef GDK_KEY_p
#define GDK_KEY_p GDK_p
#endif
#ifndef GDK_KEY_Control_L
#define GDK_KEY_Control_L GDK_Control_L
#endif
#ifndef GDK_KEY_Control_R
#define GDK_KEY_Control_R GDK_Control_R
#endif
//人物跳跃函数
void* man_jump(void *man){
Man *pMan = (Man*)man;
if(pMan->status == JUMP){
return NULL;
}
pMan->status = JUMP;
for(int i = 0;i<50;i++){
pMan->y -= 1;
SLEEP_TIME_1
}
for(int i = 0;i<50;i++){
pMan->y += 1;
SLEEP_TIME_2
}
pMan->status = RUN;
}
//按键检测
void my_key_press(GtkWidget* widget,GdkEventKey *event,gpointer data){
switch(event->keyval){
case GDK_KEY_Control_L:
case GDK_KEY_Control_R:
game_start();
break;
case GDK_KEY_space:
g_thread_create(man_jump,(void*)&man_0,FALSE,NULL);
break;
case GDK_KEY_p:
case GDK_KEY_P:
game_pause_continue();
break;
}
}
//游戏画面绘制
gboolean show_graph(GtkWidget *widget){
cairo_t *cr;
cr = gdk_cairo_create (widget->window);
//background
cairo_set_source_rgb(cr,0,0,0);
cairo_move_to(cr,0, 0);
cairo_line_to(cr,X_WIDTH,0);
cairo_line_to(cr,X_WIDTH,X_HEIGHT);
cairo_line_to(cr,0,X_HEIGHT);
cairo_stroke_preserve(cr);
cairo_fill(cr);
//road
cairo_set_source_rgb(cr,0.6,0.4,0);
cairo_move_to(cr,0, 110);
cairo_line_to(cr,X_WIDTH,110);
cairo_stroke(cr);
for(int i = 0;i<10;i++){
cairo_set_source_rgb(cr,0.2,0.4,0.6);
cairo_move_to(cr,roads[i].startPointX, roads[i].startPointY);
cairo_line_to(cr,roads[i].endPointX,roads[i].endPointY);
cairo_stroke(cr);
}
//obstacle
for(int i = 0;i<5;i++){
cairo_set_source_rgb(cr,obstacles[i].r,obstacles[i].g,obstacles[i].b);
cairo_move_to(cr,obstacles[i].x-5, 110);
cairo_line_to(cr,obstacles[i].x-5,90);
cairo_line_to(cr,obstacles[i].x+10,90);
cairo_line_to(cr,obstacles[i].x+10,110);
cairo_line_to(cr,obstacles[i].x-5,110);
cairo_stroke_preserve(cr);
cairo_fill(cr);
//printf("%d \n",obstacles[i].x);
}
//score
char strScore[10] = {'\0'};
cairo_set_source_rgb(cr,0.2,0.9,0.4);
cairo_set_font_size(cr,14);
cairo_move_to(cr,X_WIDTH-70, 30);
sprintf(strScore,"score:%d",score);
cairo_show_text(cr,strScore);
cairo_stroke(cr);
//time
char strTime[10] = {'\0'};
cairo_set_source_rgb(cr,0.4,0.4,0.7);
cairo_set_font_size(cr,14);
cairo_move_to(cr,20, 30);
sprintf(strTime,"Time:%d",timeElapse);
cairo_show_text(cr,strTime);
cairo_stroke(cr);
//game speed
char strSpeed[10] = {'\0'};
cairo_set_source_rgb(cr,0.7,0.4,0.6);
cairo_set_font_size(cr,14);
cairo_move_to(cr,110, 30);
sprintf(strSpeed,"speed:%d",gameSpeed-1);
cairo_show_text(cr,strSpeed);
cairo_stroke(cr);
//man
cairo_set_line_width(cr,0.1);
cairo_set_source_rgb(cr,1,1,0);
cairo_arc(cr,man_0.x, man_0.y,6,0,360);
cairo_stroke_preserve(cr);
cairo_fill(cr);
cairo_destroy(cr);
return true;
}
void init_road(){
for(int i=0;i<10;i++){
roads[i].startPointY = rand()%2?120:130;
roads[i].startPointX = rand()%X_WIDTH;
roads[i].endPointX = roads[i].startPointX + rand()%2+10;
roads[i].endPointY = roads[i].startPointY;
}
}
//路移动
gboolean move_road(){
for(int i = 0;i<10;i++){
roads[i].startPointX -= gameSpeed;
roads[i].endPointX -= gameSpeed;
if(roads[i].endPointX<0){
roads[i].startPointY = rand()%2?120:130;
roads[i].startPointX = X_WIDTH;
roads[i].endPointX = roads[i].startPointX + rand()%2+10;
roads[i].endPointY = roads[i].startPointY;
}
}
return true;
}
void init_obstacle(){
obstacles[0].x = X_WIDTH+20;
obstacles[0].r = (float)(rand()%100)/100;
obstacles[0].g = (float)(rand()%100)/100;
obstacles[0].b = (float)(rand()%100)/100;
for(int i = 1;i<5;i++){
obstacles[i].x = obstacles[i-1].x + rand()%50 +100;
obstacles[i].r = (float)(rand()%100)/100;
obstacles[i].g = (float)(rand()%100)/100;
obstacles[i].b = (float)(rand()%100)/100;
}
}
//障碍物移动
gboolean move_obstacle(){
for(int i = 0;i<5;i++){
obstacles[i].x -= gameSpeed;
if(obstacles[i].x<0){
int xMax = 0;
for(int j =0;j<5;j++){
if(obstacles[j].x>xMax){
xMax = obstacles[j].x;
}
}
obstacles[i].x = xMax + rand()%50 +100;
obstacles[i].r = (float)(rand()%100)/100;
obstacles[i].g = (float)(rand()%100)/100;
obstacles[i].b = (float)(rand()%100)/100;
score++;
}
}
if(hit_check()){
game_over();
}
return true;
}
gboolean set_time(){
timeElapse += 1;
return true;
}
gboolean set_game_speed(){
if(gameSpeed < MAX_GAME_SPEED){
gameSpeed++;
}
return true;
}
//游戏开始
void game_start(){
if(gameStatus != STOP){
return;
}
gameStatus = GOING;
score = 0;
timeElapse = 0;
gameSpeed = 2;
man_0.x = 30;
man_0.y = 100;
init_road();
init_obstacle();
timer_0 = g_timeout_add(30,(GSourceFunc)show_graph,window);
timer_1 = g_timeout_add(30,(GSourceFunc)move_road,NULL);
timer_2 = g_timeout_add(30,(GSourceFunc)move_obstacle,NULL);
timer_score = g_timeout_add(1000,(GSourceFunc)set_time,NULL);
timer_game_speed = g_timeout_add(20000,(GSourceFunc)set_game_speed,NULL);
}
//暂停/继续
void game_pause_continue(){
if(gameStatus == PAUSE){
gameStatus = GOING;
timer_0 = g_timeout_add(30,(GSourceFunc)show_graph,window);
timer_1 = g_timeout_add(30,(GSourceFunc)move_road,NULL);
timer_2 = g_timeout_add(30,(GSourceFunc)move_obstacle,NULL);
timer_score = g_timeout_add(1000,(GSourceFunc)set_time,NULL);
timer_game_speed = g_timeout_add(20000,(GSourceFunc)set_game_speed,NULL);
}else if(gameStatus == GOING){
gameStatus = PAUSE;
g_source_remove(timer_0);
g_source_remove(timer_1);
g_source_remove(timer_2);
g_source_remove(timer_score);
g_source_remove(timer_game_speed);
}
}
//游戏结束
void game_over(){
gameStatus = STOP;
g_source_remove(timer_0);
g_source_remove(timer_1);
g_source_remove(timer_2);
g_source_remove(timer_score);
g_source_remove(timer_game_speed);
//
cairo_t *crr;
crr = gdk_cairo_create (window->window);
cairo_set_source_rgb(crr,0.5,0.7,0.9);
cairo_set_font_size(crr,24);
cairo_move_to(crr,50, 60);
cairo_show_text(crr,"game over");
cairo_stroke(crr);
cairo_destroy(crr);
}
//开始界面
gboolean start_window(GtkWidget *widget){
cairo_t *cr;
cr = gdk_cairo_create (widget->window);
//background
cairo_set_source_rgb(cr,0.6,0,0.7);
cairo_move_to(cr,0, 0);
cairo_line_to(cr,X_WIDTH,0);
cairo_line_to(cr,X_WIDTH,X_HEIGHT);
cairo_line_to(cr,0,X_HEIGHT);
cairo_stroke_preserve(cr);
cairo_fill(cr);
//game reference
//char info[1000] = {'\0'};
//sprintf(info,"Ctrl to start\nspace to jump\n p to pause/continue\n");
cairo_set_source_rgb(cr,0.0,0.7,0.3);
cairo_set_font_size(cr,24);
cairo_move_to(cr,30, 40);
cairo_show_text(cr,"Ctrl to start");
cairo_move_to(cr,30, 90);
cairo_show_text(cr,"Space to jump");
cairo_move_to(cr,20, 130);
cairo_show_text(cr,"p to pause/continue");
cairo_stroke(cr);
cairo_destroy(cr);
//run only once
return false;
}
//碰撞检测
gboolean hit_check(){
gint nearestObstacleID;
gint nearestDistance = 65535;
for(int i=0;i<5;i++){
if(abs(man_0.x-obstacles[i].x)<nearestDistance){
nearestObstacleID = i;
nearestDistance = abs(man_0.x-obstacles[i].x);
}
}
//printf("%d\n",nearestObstacleID);
//检测碰撞最近的障碍物
if((man_0.x-obstacles[nearestObstacleID].x)*(man_0.x-obstacles[nearestObstacleID].x)+(man_0