|
Опубликовано Илья Фаист в Вс, 02/19/2012 - 15:21
|
Игра очень проста. Нужна поймать как можно больше фруктов. Каждый фрукт это определенное кол-во очков, которое зависит от выбранного уровня.Так же падают овощи. Если Вы ловите их, то они отнимают у Вас определенное кол-во очков. И фрукты и овощи падают с разной скоростью, которая зависит от уровня. Так же есть 2 бонуса: +50 и EndGame. Если Вы словили + 50 то ваши очки в корзине увеличились на 50 очков, если словили EndGame, то Вы проиграли. Эти 2 бонуса всегда падают быстрее.
Алгоритм таков: Генерируется случайное число, для оси y, затем еще одно для выбора фрукта или овоща. В зависимости от заданных параметров фрукт или овощ летит вниз с определенной скоростью. Проверяется столкновение с корзиной, или промах.
Файл main.cpp
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <gtk/gtk.h>
#include <gdk/gdkkeysyms.h> // Коды клавиш
#include"engine.h" // Подключаем наш движок
int main (int argc, char *argv[])
{
GtkWidget *wind = NULL;
gtk_init(&argc, &argv);
wind = gtk_window_new(GTK_WINDOW_TOPLEVEL); // Создаем окно
gtk_window_set_title(GTK_WINDOW(wind), "CatchTheFruit");
gtk_window_set_position(GTK_WINDOW(wind), GTK_WIN_POS_CENTER);
gtk_widget_set_size_request(wind, BG_WIDTH, BG_HEIGHT);
gtk_window_set_resizable(GTK_WINDOW(wind), FALSE);
srand(time(0));
game *Game = (game*) malloc(sizeof(game)); // Создание динамической структуры
// ВЫБОР УРОВНЯ[SIMPLE, MIDDLE, ADVANCED]
LEVEL = MIDDLE;
Init(wind, Game); // Запускаем инициализацию
g_signal_connect(G_OBJECT(wind), "expose_event", G_CALLBACK(draw), (gpointer)Game);
g_signal_connect(wind, "key_press_event", G_CALLBACK(Keys), (gpointer)Game);
g_signal_connect(G_OBJECT(wind), "destroy", G_CALLBACK(gtk_main_quit), NULL);
gtk_widget_show_all(wind);
gtk_main();
Exit(Game);// Очистка памяти
return 0;
}
Далее файл structs.h
#ifndef STRUCTS_H_INCLUDED
#define STRUCTS_H_INCLUDED
typedef struct basket basket;
typedef struct fruits fruits;
typedef struct game game;
typedef enum boolean
{
false,
true
} bool;
enum level
{
SIMPLE,
MIDDLE,
ADVANCED
} LEVEL;
// Структура нашей корзины
struct basket
{
GdkPixbuf *basket_image;
int width, height;
float x, y;
int score;
};
struct fruits
{
float vY; // Вектор направления по Y
float x, y;
int width, height;
GdkPixbuf *image;
float mass;
int score;
float grav; // Гравитация
};
struct game
{
GtkWidget *window;
GdkPixbuf *bg_image; // Фоновое изображение
GdkPixbuf *bg_image_loose; // Фоновое изображение когда проиграл
basket *Basket;
fruits *Fruits;
char Score[3]; // Место хранения очков
char MaxScore[50];
int count;
int allow_count; // Макс кол-во разрешенных падающих мимо фруктов
int max_score;
GdkFont *ScoreFont;
bool flag;
bool is_game; // Флаг идет ли игра?
};
#endif // STRUCTS_H_INCLUDED
Далее файл инициализации Init.h
#ifndef INIT_H_INCLUDE2
#define INIT_H_INCLUDED
#include "structs.h"
// Установка параметров в зависимости от Левела
float GetLevelConf(game *Game, char *PARAM)
{
/*
basket_score - Начальное кол-во очков
allow_score - Макс. допустимое кол-во пропущенных фруктов
*/
switch(LEVEL)
{
case SIMPLE:
{
if(!strcmp(PARAM, "basket_score"))
return 20.0;
if(!strcmp(PARAM, "allow_score"))
return 4.0;
if(!strcmp(PARAM, "mass_apple"))
return 0.1;
if(!strcmp(PARAM, "apple_score"))
return 10.0;
if(!strcmp(PARAM, "mass_banana"))
return 0.1;
if(!strcmp(PARAM, "banana_score"))
return 5.0;
if(!strcmp(PARAM, "mass_cherry"))
return 0.1;
if(!strcmp(PARAM, "cherry_score"))
return 15.0;
if(!strcmp(PARAM, "mass_orange"))
return 0.1;
if(!strcmp(PARAM, "orange_score"))
return 20.0;
if(!strcmp(PARAM, "mass_pear"))
return 0.1;
if(!strcmp(PARAM, "pear_score"))
return 25.0;
if(!strcmp(PARAM, "mass_cabbage"))
return 0.1;
if(!strcmp(PARAM, "cabbage_score"))
return -5.0;
if(!strcmp(PARAM, "mass_carrot"))
return 0.1;
if(!strcmp(PARAM, "carrot_score"))
return -3.0;
if(!strcmp(PARAM, "mass_cucumber"))
return 0.1;
if(!strcmp(PARAM, "cucumber_score"))
return -7.0;
break;
}
case MIDDLE:
{
if(!strcmp(PARAM, "basket_score"))
return 10.0;
if(!strcmp(PARAM, "allow_score"))
return 2.0;
if(!strcmp(PARAM, "mass_apple"))
return 0.1;
if(!strcmp(PARAM, "apple_score"))
return 15.0;
if(!strcmp(PARAM, "mass_banana"))
return 0.1;
if(!strcmp(PARAM, "banana_score"))
return 7.0;
if(!strcmp(PARAM, "mass_cherry"))
return 0.2;
if(!strcmp(PARAM, "cherry_score"))
return 20.0;
if(!strcmp(PARAM, "mass_orange"))
return 0.2;
if(!strcmp(PARAM, "orange_score"))
return 20.0;
if(!strcmp(PARAM, "mass_pear"))
return 0.2;
if(!strcmp(PARAM, "pear_score"))
return 25.0;
if(!strcmp(PARAM, "mass_cabbage"))
return 0.2;
if(!strcmp(PARAM, "cabbage_score"))
return -10.0;
if(!strcmp(PARAM, "mass_carrot"))
return 0.2;
if(!strcmp(PARAM, "carrot_score"))
return -5.0;
if(!strcmp(PARAM, "mass_cucumber"))
return 0.1;
if(!strcmp(PARAM, "cucumber_score"))
return -20.0;
break;
}
case ADVANCED:
{
if(!strcmp(PARAM, "basket_score"))
return 0.0;
if(!strcmp(PARAM, "allow_score"))
return 1.0;
if(!strcmp(PARAM, "mass_apple"))
return 0.2;
if(!strcmp(PARAM, "apple_score"))
return 20.0;
if(!strcmp(PARAM, "mass_banana"))
return 0.2;
if(!strcmp(PARAM, "banana_score"))
return 15.0;
if(!strcmp(PARAM, "mass_cherry"))
return 0.1;
if(!strcmp(PARAM, "cherry_score"))
return 15.0;
if(!strcmp(PARAM, "mass_orange"))
return 0.2;
if(!strcmp(PARAM, "orange_score"))
return 25.0;
if(!strcmp(PARAM, "mass_pear"))
return 0.1;
if(!strcmp(PARAM, "pear_score"))
return 30.0;
if(!strcmp(PARAM, "mass_cabbage"))
return 0.2;
if(!strcmp(PARAM, "cabbage_score"))
return -20.0;
if(!strcmp(PARAM, "mass_carrot"))
return 0.2;
if(!strcmp(PARAM, "carrot_score"))
return -30.0;
if(!strcmp(PARAM, "mass_cucumber"))
return 0.2;
if(!strcmp(PARAM, "cucumber_score"))
return -35.0;
break;
}
default:
{}
}
}
void SaveRecord(game *Game) // Сохраняем МАКС очки
{
FILE *file;
char* file_name = "records.msr";
int s = 0, m = 0, a = 0;
if(!(file = fopen(file_name, "r")))
{
file = fopen(file_name, "w");
if(LEVEL == SIMPLE)
fprintf(file, "%d|%d|%d", Game ->max_score, m, a);
else if(LEVEL == MIDDLE)
fprintf(file, "%d|%d|%d", s, Game ->max_score, a);
else
fprintf(file, "%d|%d|%d", s, m, Game ->max_score);
}
else
{
file = fopen(file_name, "r");
fscanf(file, "%d|%d|%d", &s, &m, &a);
file = fopen(file_name, "w");
if(LEVEL == SIMPLE)
fprintf(file, "%d|%d|%d", Game ->max_score, m, a);
else if(LEVEL == MIDDLE)
fprintf(file, "%d|%d|%d", s, Game ->max_score, a);
else
fprintf(file, "%d|%d|%d", s, m, Game ->max_score);
}
fclose(file);
}
int GetRecord(game *Game) // Получаем МАКС очки
{
FILE *file;
char* file_name = "records.msr";
int score = 0;
int s = 0, m = 0, a = 0;
if(!(file = fopen(file_name, "r")) )
score = 0;
else
{
if(LEVEL == SIMPLE)
fscanf(file, "%d|%d|%d", &score, &m, &a);
else if(LEVEL == MIDDLE)
fscanf(file, "%d|%d|%d", &s, &score, &a);
else
fscanf(file, "%d|%d|%d", &s, &m, &score);
}
fclose(file);
return score;
}
// Инициализируем игру
void Init(GtkWidget *wind, game *Game)
{
Game ->window = wind;
Game ->bg_image = gdk_pixbuf_new_from_file("img/bg.jpg", NULL);
Game ->bg_image_loose = gdk_pixbuf_new_from_file("img/bg_loose.jpg", NULL);
Game ->Basket = (basket*) malloc(sizeof(basket));
Game ->Fruits = (fruits*) malloc(sizeof(fruits));
Game ->Basket ->basket_image = gdk_pixbuf_new_from_file("img/basket.png", NULL);
Game ->Basket ->width = 117;
Game ->Basket ->height = 85;
Game ->Basket ->x = BG_WIDTH / 2 - 65;
Game ->Basket ->y = BG_HEIGHT - 70.0;
Game ->Basket ->score = (int)GetLevelConf(Game, "basket_score"); // Начальное кол-во очков
Game ->count = 0;
Game ->allow_count = (int)GetLevelConf(Game, "allow_score"); // Разрешенное кол-во пропущенных подряд фруктов
Game ->Fruits ->image = NULL;
Game ->Fruits ->vY = 0.0;
Game ->Fruits ->mass = 0.0;
Game ->ScoreFont = gdk_font_load("Comic Sans MS");
Game ->flag = false;
Game ->is_game = true;
Game ->max_score = GetRecord(Game); // Считываем Макс кол-во очков
return;
}
#endif // INIT_H_INCLUDED
Ну и сам движок
#ifndef ENGINE_H_INCLUDED
#define ENGINE_H_INCLUDED
#define BG_WIDTH 700 // Ширина окна
#define BG_HEIGHT 525 // Высота окна
#define STEP 70.0 // Шаг корзины
#define G 9.80665
#define FRICTION 0.010
#define N 10 // Кол-во фруктов и овощeй
#include "init.h"
void ShowMaxScore(game *Game)
{
GdkColor Color;
GdkGC *GC = Game->window->style->fg_gc[GTK_WIDGET_STATE (Game->window)];
gdk_color_parse("#ffffff", &Color);
gdk_gc_set_rgb_fg_color(GC, &Color);
sprintf(Game ->MaxScore, "[Max. Score: %d][LastScore:%d]", Game ->max_score, Game ->Basket ->score);
gdk_draw_string(Game ->window ->window,
Game ->ScoreFont,
GC,
430.0,
20.0,
Game ->MaxScore);
}
void ShowPoints(game *Game)
{
GdkColor Color;
GdkGC *GCC = Game->window->style->fg_gc[GTK_WIDGET_STATE (Game->window)];
gdk_color_parse("#ffffff", &Color);
gdk_gc_set_rgb_fg_color(GCC, &Color);
sprintf(Game ->Score, "%d", Game ->Basket ->score);
gdk_draw_string(Game ->window ->window,
Game ->ScoreFont,
GCC,
Game ->Basket ->x + 55.0,
Game ->Basket ->y + 55.0,
Game ->Score);
}
// Функция проверки столкновения с корзиной и падения в пропасть
void OnThePlace(game *Game)
{
// КОРЗИНА
/*-----> */ if(Game ->Fruits ->y >= Game ->Basket ->y - Game ->Fruits ->height / 2 &&
Game ->Fruits ->x > Game ->Basket ->x - Game ->Fruits ->width / 2 &&
Game ->Fruits ->x < Game ->Basket ->x + Game ->Basket ->width)
{
// Если поймай END GAME
if(Game ->Fruits ->score == 0)
{
Game ->is_game = false;
Game ->count = Game ->allow_count;
}
Game ->Basket ->score += Game ->Fruits ->score;
Game ->Fruits ->y = 0.0;
Game ->Fruits ->x = 0.0;
Game ->Fruits ->vY = 0.0;
Game ->flag = false;
if(Game ->Basket ->score > Game ->max_score) // Вычисляет МАКС очки
Game ->max_score = Game ->Basket ->score;
}
// МИМО
/*-----> */ if(Game ->Fruits ->y >= BG_HEIGHT)
{
if(Game ->Fruits ->score > 0) // Если фрукты
{
if(Game ->Fruits ->score != 50)
{
Game ->Basket ->score -= Game ->Fruits ->score;
Game ->count++; // Кол-во подряд пропущенных фруктов
}
}
else
Game ->count = 0;
Game ->Fruits ->y = 0.0;
Game ->Fruits ->x = 0.0;
Game ->Fruits ->vY = 0.0;
Game ->flag = false;
}
}
gboolean Start(gpointer data)
{
/*
PLACE_X - Случайная координата X
TYPE - Случайный фрукт/овощь
*/
game *Game = (game*) data;
int TYPE, PLACE_X;
if(!Game ->flag)
{
TYPE = rand() % N + 1; // Выбирает тип падающего объекта
switch(TYPE)
{
// ЯБЛОКО
case 1:
{
Game ->Fruits ->image = gdk_pixbuf_new_from_file("img/fruits/apple.png", NULL);
Game ->Fruits ->width = 50;
Game ->Fruits ->height = 50;
Game ->Fruits ->mass = GetLevelConf(Game, "mass_apple");
Game ->Fruits ->score = (int)GetLevelConf(Game, "apple_score");
PLACE_X = (rand()%((BG_WIDTH - Game ->Fruits ->width)-15+1)+15);
Game ->Fruits ->x = PLACE_X;
Game ->Fruits ->y = 0.0;
Game ->Fruits ->grav = (G * Game ->Fruits ->mass) * FRICTION;
Game ->flag = true;
break;
}
// Банан
case 2:
{
Game ->Fruits ->image = gdk_pixbuf_new_from_file("img/fruits/banana.png", NULL);
Game ->Fruits ->width = 70;
Game ->Fruits ->height = 47;
Game ->Fruits ->mass = GetLevelConf(Game, "mass_banana");
Game ->Fruits ->score = (int)GetLevelConf(Game, "banana_score");
PLACE_X = (rand()%((BG_WIDTH - Game ->Fruits ->width)-15+1)+15);
Game ->Fruits ->x = PLACE_X;
Game ->Fruits ->y = 0.0;
Game ->Fruits ->grav = (G * Game ->Fruits ->mass) * FRICTION;
Game ->flag = true;
break;
}
// Вишня
case 3:
{
Game ->Fruits ->image = gdk_pixbuf_new_from_file("img/fruits/cherry.png", NULL);
Game ->Fruits ->width = 50;
Game ->Fruits ->height = 61;
Game ->Fruits ->mass = GetLevelConf(Game, "mass_cherry");
Game ->Fruits ->score = (int)GetLevelConf(Game, "cherry_score");
PLACE_X = (rand()%((BG_WIDTH - Game ->Fruits ->width)-15+1)+15);
Game ->Fruits ->x = PLACE_X;
Game ->Fruits ->y = 0.0;
Game ->Fruits ->grav = (G * Game ->Fruits ->mass) * FRICTION;
Game ->flag = true;
break;
}
// Апельсин
case 4:
{
Game ->Fruits ->image = gdk_pixbuf_new_from_file("img/fruits/orange.png", NULL);
Game ->Fruits ->width = 50;
Game ->Fruits ->height = 49;
Game ->Fruits ->mass = GetLevelConf(Game, "mass_orange");
Game ->Fruits ->score = (int)GetLevelConf(Game, "orange_score");
PLACE_X = (rand()%((BG_WIDTH - Game ->Fruits ->width)-15+1)+15);
Game ->Fruits ->x = PLACE_X;
Game ->Fruits ->y = 0.0;
Game ->Fruits ->grav = (G * Game ->Fruits ->mass) * FRICTION;
Game ->flag = true;
break;
}
// Груша
case 5:
{
Game ->Fruits ->image = gdk_pixbuf_new_from_file("img/fruits/pear.png", NULL);
Game ->Fruits ->width = 50;
Game ->Fruits ->height = 70;
Game ->Fruits ->mass = GetLevelConf(Game, "mass_pear");
Game ->Fruits ->score = (int)GetLevelConf(Game, "pear_score");
PLACE_X = (rand()%((BG_WIDTH - Game ->Fruits ->width)-15+1)+15);
Game ->Fruits ->x = PLACE_X;
Game ->Fruits ->y = 0.0;
Game ->Fruits ->grav = (G * Game ->Fruits ->mass) * FRICTION;
Game ->flag = true;
break;
}
// КАПУСТА
case 6:
{
Game ->Fruits ->image = gdk_pixbuf_new_from_file("img/vegetables/cabbage.png", NULL);
Game ->Fruits ->width = 90;
Game ->Fruits ->height = 60;
Game ->Fruits ->mass = GetLevelConf(Game, "mass_cabbage");
Game ->Fruits ->score = (int)GetLevelConf(Game, "cabbage_score");
PLACE_X = (rand()%((BG_WIDTH - Game ->Fruits ->width)-15+1)+15);
Game ->Fruits ->x = PLACE_X;
Game ->Fruits ->y = 0.0;
Game ->Fruits ->grav = (G * Game ->Fruits ->mass) * FRICTION;
Game ->flag = true;
break;
}
// Морковь
case 7:
{
Game ->Fruits ->image = gdk_pixbuf_new_from_file("img/vegetables/carrot.png", NULL);
Game ->Fruits ->width = 60;
Game ->Fruits ->height = 77;
Game ->Fruits ->mass = GetLevelConf(Game, "mass_carrot");
Game ->Fruits ->score = (int)GetLevelConf(Game, "carrot_score");
PLACE_X = (rand()%((BG_WIDTH - Game ->Fruits ->width)-15+1)+15);
Game ->Fruits ->x = PLACE_X;
Game ->Fruits ->y = 0.0;
Game ->Fruits ->grav = (G * Game ->Fruits ->mass) * FRICTION;
Game ->flag = true;
break;
}
// Огурец
case 8:
{
Game ->Fruits ->image = gdk_pixbuf_new_from_file("img/vegetables/cucumber.png", NULL);
Game ->Fruits ->width = 40;
Game ->Fruits ->height = 96;
Game ->Fruits ->mass = GetLevelConf(Game, "mass_cucumber");
Game ->Fruits ->score = (int)GetLevelConf(Game, "cucumber_score");
PLACE_X = (rand()%((BG_WIDTH - Game ->Fruits ->width)-15+1)+15);
Game ->Fruits ->x = PLACE_X;
Game ->Fruits ->y = 0.0;
Game ->Fruits ->grav = (G * Game ->Fruits ->mass) * FRICTION;
Game ->flag = true;
break;
}
// END GAME(BONUS)
case 9:
{
Game ->Fruits ->image = gdk_pixbuf_new_from_file("img/end_game.png", NULL);
Game ->Fruits ->width = 100;
Game ->Fruits ->height = 50;
Game ->Fruits ->mass = 0.3;
Game ->Fruits ->score = 0;
PLACE_X = (rand()%((BG_WIDTH - Game ->Fruits ->width)-15+1)+15);
Game ->Fruits ->x = PLACE_X;
Game ->Fruits ->y = 0.0;
Game ->Fruits ->grav = (G * Game ->Fruits ->mass) * FRICTION;
Game ->flag = true;
break;
}
// +50 (BONUS)
case 10:
{
Game ->Fruits ->image = gdk_pixbuf_new_from_file("img/50.png", NULL);
Game ->Fruits ->width = 100;
Game ->Fruits ->height = 50;
Game ->Fruits ->mass = 0.7;
Game ->Fruits ->score = 50;
PLACE_X = (rand()%((BG_WIDTH - Game ->Fruits ->width)-15+1)+15);
Game ->Fruits ->x = PLACE_X;
Game ->Fruits ->y = 0.0;
Game ->Fruits ->grav = (G * Game ->Fruits ->mass) * FRICTION;
Game ->flag = true;
break;
}
default:
{}
}
}
else
{
Game ->Fruits ->vY += Game ->Fruits ->grav; // Увеличиваем вектор
Game ->Fruits ->y += Game ->Fruits ->vY;
gdk_draw_pixbuf(Game ->window ->window,
Game ->window->style ->black_gc,
Game ->Fruits ->image,
0, 0,
Game ->Fruits ->x,
Game ->Fruits ->y,
Game ->Fruits ->width,
Game ->Fruits ->height,
GDK_RGB_DITHER_NONE, 0, 0);
OnThePlace(Game); // Проверяем столкновения
}
return 1;
}
// Функция прорисовки
gint draw(GtkWidget *win, GdkEventExpose *event, gpointer data)
{
game *Game = (game*)data;
// Если игры нет
if(!Game ->is_game)
{ // Рисуем фон проиграли
gdk_draw_pixbuf(win->window,
win->style ->black_gc,
Game ->bg_image_loose,
0, 0, 0, 0, BG_WIDTH, BG_HEIGHT,
GDK_RGB_DITHER_NONE, 0, 0);
ShowMaxScore(Game);
}
else
{
// Рисуем фон
gdk_draw_pixbuf(win->window,
win->style ->black_gc,
Game ->bg_image,
0, 0, 0, 0, BG_WIDTH, BG_HEIGHT,
GDK_RGB_DITHER_NONE, 0, 0);
// Рисуем корзину
gdk_draw_pixbuf(win->window,
win->style ->black_gc,
Game ->Basket ->basket_image,
0, 0,
Game ->Basket ->x,
Game ->Basket ->y,
Game ->Basket ->width,
Game ->Basket ->height,
GDK_RGB_DITHER_NONE, 0, 0);
ShowPoints(Game);
if(Game ->Basket ->score < 0 || Game ->count == Game ->allow_count) // Если очки < 0 или пропустил подряд ENDCOUNT
Game ->is_game = false;
Start(Game); // Начало игры
}
gtk_widget_queue_draw(win);
return 1;
}
gboolean Keys(GtkWidget *wid, GdkEventKey *Key, gpointer data)
{
game *Game = (game*)data;
switch(Key ->keyval)
{
case GDK_Right:
{
if(Game ->Basket ->x + Game ->Basket ->width >= BG_WIDTH) // Проверка выхода корзины за правый край
Game ->Basket ->x = BG_WIDTH - Game ->Basket ->width;
Game ->Basket ->x += STEP;
break;
}
case GDK_Left:
{
if(Game ->Basket ->x <= 0.0) // Проверка выхода корзины за левый край
Game ->Basket ->x = 0.0;
Game ->Basket ->x -= STEP;
break;
}
case GDK_Up:
{
if(Game ->Basket ->score < 0 || Game ->count == Game ->allow_count) // Если очки =< 0 или пропустил подряд ENDCOUNT
{
Game ->is_game = true; // !! Меняем флаг, то есть разрешаем запускать игру
Game ->flag = false;
Game ->Basket ->score = (int)GetLevelConf(Game, "basket_score");
Game ->count = 0;
}
break;
}
case GDK_Down:
{
if(Game ->Basket ->score < 0 || Game ->count == Game ->allow_count) // Если очки = 0 или пропустил подряд ENDCOUNT
{
Game ->is_game = true;
Game ->flag = false;
Game ->Basket ->score = (int)GetLevelConf(Game, "basket_score");
Game ->count = 0;
}
break;
}
}
return 1;
}
gboolean Exit(game *Game)
{
SaveRecord(Game);
/* Освобождаем память! */
free(Game ->Basket);
free(Game ->Fruits);
free(Game);
return 0;
}
#endif // ENGINE_H_INCLUDED
Вот и все.Версия не совсем оптимизированная, и к сожалению без меню. Законченная осталась на сломанном винте;)
Спасибо за внимание.
Ключевые слова:
Игра, gtk, c, c++, поймай фрукт, catch the fruit, уроки по c
|
|