diff options
author | nathan <thenathansmithsmith@gmail.com> | 2023-03-20 06:34:54 +0000 |
---|---|---|
committer | nathan <thenathansmithsmith@gmail.com> | 2023-03-20 06:34:54 +0000 |
commit | dd98918fe32b9dcdfc482a2c68481e93ceb50623 (patch) | |
tree | bf2ea0e4f4e47facde93c0cf277adb2031f7b3ec | |
download | fltk_snake-main.tar.gz fltk_snake-main.tar.bz2 fltk_snake-main.zip |
-rw-r--r-- | Makefile | 4 | ||||
-rw-r--r-- | README.md | 1 | ||||
-rw-r--r-- | images/big_bird.png | bin | 0 -> 121668 bytes | |||
-rw-r--r-- | images/child_person.png | bin | 0 -> 119665 bytes | |||
-rw-r--r-- | images/easter_bunny.png | bin | 0 -> 74939 bytes | |||
-rw-r--r-- | images/friendly_frog.png | bin | 0 -> 157971 bytes | |||
-rw-r--r-- | images/gidget.png | bin | 0 -> 57194 bytes | |||
-rw-r--r-- | images/remy_the_rat.png | bin | 0 -> 127886 bytes | |||
-rw-r--r-- | src/Makefile | 30 | ||||
-rw-r--r-- | src/app_window.cpp | 26 | ||||
-rw-r--r-- | src/app_window.h | 18 | ||||
-rw-r--r-- | src/main.cpp | 79 | ||||
-rw-r--r-- | src/program_data.h | 83 | ||||
-rw-r--r-- | src/snake_map.cpp | 245 | ||||
-rw-r--r-- | src/snake_map.h | 37 | ||||
-rw-r--r-- | src/snake_utils.cpp | 174 | ||||
-rw-r--r-- | src/snake_utils.h | 71 | ||||
-rw-r--r-- | src/top_menu.cpp | 25 | ||||
-rw-r--r-- | src/top_menu.h | 9 |
19 files changed, 802 insertions, 0 deletions
diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..6a2adaf --- /dev/null +++ b/Makefile @@ -0,0 +1,4 @@ +all: + @make -C src +%: + @make -C src $@ diff --git a/README.md b/README.md new file mode 100644 index 0000000..7dd0aeb --- /dev/null +++ b/README.md @@ -0,0 +1 @@ +# Snake... but written with fltk!!! diff --git a/images/big_bird.png b/images/big_bird.png Binary files differnew file mode 100644 index 0000000..6f75edc --- /dev/null +++ b/images/big_bird.png diff --git a/images/child_person.png b/images/child_person.png Binary files differnew file mode 100644 index 0000000..329fdb4 --- /dev/null +++ b/images/child_person.png diff --git a/images/easter_bunny.png b/images/easter_bunny.png Binary files differnew file mode 100644 index 0000000..e259fea --- /dev/null +++ b/images/easter_bunny.png diff --git a/images/friendly_frog.png b/images/friendly_frog.png Binary files differnew file mode 100644 index 0000000..483a144 --- /dev/null +++ b/images/friendly_frog.png diff --git a/images/gidget.png b/images/gidget.png Binary files differnew file mode 100644 index 0000000..427e16f --- /dev/null +++ b/images/gidget.png diff --git a/images/remy_the_rat.png b/images/remy_the_rat.png Binary files differnew file mode 100644 index 0000000..910b866 --- /dev/null +++ b/images/remy_the_rat.png diff --git a/src/Makefile b/src/Makefile new file mode 100644 index 0000000..148001b --- /dev/null +++ b/src/Makefile @@ -0,0 +1,30 @@ +FLCON = fltk-config +COMPILER = $(shell $(FLCON) --cxx) +CFLAGS = $(shell $(FLCON) --use-images --cxxflags) +LDFLAGS = $(shell $(FLCON) --use-images --ldstaticflags) \ + -static-libstdc++ -static-libgcc + +TARGET = ../fltk_snake +DEH = program_data.h +OBJS = main.o app_window.o snake_map.o top_menu.o snake_utils.o + +%.o: %.cpp + @echo compiling $< + @$(COMPILER) $(CFLAGS) -c -o $@ $< +$(TARGET): $(OBJS) + @echo making exe + @$(COMPILER) $(CFLAGS) -o $(TARGET) $(OBJS) $(LDFLAGS) +debug: + $(COMPILER) $(CFLAGS) -c *.cpp -g + $(COMPILER) $(CFLAGS) -o $(TARGET) $(OBJS) $(LDFLAGS) -g + +# Objects. +main.o: *.cpp *.h +app_window.o: app_window.cpp app_window.h snake_map.cpp snake_map.h $(DEH) +snake_map.o: snake_map.cpp snake_map.h snake_utils.cpp snake_utils.h $(DEH) +top_menu.o: top_menu.cpp top_menu.h snake_map.cpp snake_map.h $(DEH) +snake_utils.o: snake_utils.cpp snake_utils.h $(DEH) + +clean: + rm *.o + rm $(TARGET) diff --git a/src/app_window.cpp b/src/app_window.cpp new file mode 100644 index 0000000..b38ebfc --- /dev/null +++ b/src/app_window.cpp @@ -0,0 +1,26 @@ +#include "app_window.h" + +void AppWindow::main_init(MainData * md, int X, int Y, const char * l) { + mdata = md; + + Fl::add_timeout(1.0 / mdata->settings.update_fps, update_cb, (void*)this); + Fl::add_timeout(1.0 / mdata->settings.draw_fps, draw_cb, (void*)this); +} + +void AppWindow::update_cb(void * d) { + AppWindow * win = (AppWindow*)d; + MainData* mdata = win->mdata; + + mdata->snake_map->update(); + + Fl::repeat_timeout(1.0 / win->mdata->settings.update_fps, update_cb, d); +} + +void AppWindow::draw_cb(void * d) { + AppWindow * win = (AppWindow*)d; + MainData* mdata = win->mdata; + + mdata->snake_map->redraw(); + + Fl::repeat_timeout(1.0 / win->mdata->settings.draw_fps, draw_cb, d); +} diff --git a/src/app_window.h b/src/app_window.h new file mode 100644 index 0000000..87f9568 --- /dev/null +++ b/src/app_window.h @@ -0,0 +1,18 @@ +#pragma once + +#include "program_data.h" +#include "snake_map.h" + +class AppWindow : public Fl_Double_Window { + public: + AppWindow(MainData * md, int X, int Y, const char * l=0) : Fl_Double_Window(X, Y, l) { + main_init(md, X, Y, l); + } + private: + MainData * mdata; + + static void update_cb(void * d); + static void draw_cb(void * d); + + void main_init(MainData * md, int X, int Y, const char * l=0); +}; diff --git a/src/main.cpp b/src/main.cpp new file mode 100644 index 0000000..db0e58a --- /dev/null +++ b/src/main.cpp @@ -0,0 +1,79 @@ +#include "program_data.h" +#include "app_window.h" +#include "snake_map.h" +#include "top_menu.h" +#include "snake_utils.h" + +const char image_list[][NAME_MAX] = { + "remy_the_rat.png", + "friendly_frog.png", + "easter_bunny.png", + "gidget.png", + "child_person.png", + "big_bird.png" +}; + +void load_images(MainData * mdata) { + char image_path[NAME_MAX]; + Fl_PNG_Image * new_image = NULL; + + for (auto img : image_list) { + memset(image_path, 0, NAME_MAX); + snprintf(image_path, NAME_MAX, "images/%s", img); + + printf("Loading %s\n", image_path); + + new_image = new Fl_PNG_Image(image_path); + + if (new_image->fail()) + fprintf(stderr, "Error loading %s\n", image_path); + + mdata->images.snack_images.push_back(new_image); + } + + set_snack_images_to_tile_size(mdata); +} + +int main(int argc, char ** argv) { + MainData mdata; + + load_images(&mdata); + + // Create window. + mdata.win = new AppWindow( + &mdata, + Fl::w() / 2, + Fl::h() / 2, + "FLTK snake" + ); + + // Snake map. + mdata.snake_map = new SnakeMap(&mdata); + + // Top menu. + mdata.top_menu = new Fl_Menu_Bar( + 0, + 0, + mdata.win->w(), + mdata.settings.top_menu_height + ); + + // Length output. + mdata.length_output = new Fl_Output( + (mdata.win->w() / 2) - (mdata.settings.output_width / 2), + mdata.top_menu->h(), + mdata.settings.output_width, + mdata.settings.output_height, + "Length" + ); + + mdata.length_output->value("0"); + + add_menu_items(&mdata, mdata.top_menu); + + mdata.win->end(); + mdata.win->resizable(mdata.win); + + mdata.win->show(argc, argv); + return Fl::run(); +} diff --git a/src/program_data.h b/src/program_data.h new file mode 100644 index 0000000..c09e309 --- /dev/null +++ b/src/program_data.h @@ -0,0 +1,83 @@ +#pragma once + +// FLTK headers. +#include <FL/Fl.H> +#include <FL/Fl_Double_Window.H> +#include <FL/Fl_PNG_Image.H> +#include <FL/x.H> +#include <FL/Fl_Menu_Bar.H> +#include <FL/Fl_Menu_Item.H> +#include <FL/Fl_Output.H> +#include <FL/fl_ask.H> +#include <FL/names.h> +#include <FL/fl_draw.H> + +#define _USE_MATH_DEFINES + +// C/C++ headers. +#include <cstdio> +#include <cstdlib> +#include <string> +#include <cstring> +#include <iostream> +#include <random> +#include <cmath> +#include <cstring> +#include <ctime> +#include <climits> +#include <vector> +#include <exception> +#include <cerrno> + +// OS headers. +#include <sys/types.h> +#include <sys/stat.h> + +#ifdef _WIN32 +#include <Windows.h> +#include <Lmcons.h> +#define NAME_MAX MAX_PATH +#else +#include <unistd.h> +#endif + +struct Settings { + // Top menu. + int top_menu_height = 25; + + // Tiles. + int tile_size = 20; + int tile_count_w = 30; + int tile_count_h = 20; + + // speed. + float update_fps = 60.0; + float draw_fps = 60.0; + int snake_speed = 2; + + // Rules. + bool die_when_hit_self = false; + + // Score output. + int output_width = 100; + int output_height = 20; +}; + +struct GameImages { + std::vector<Fl_PNG_Image*> snack_images; + std::vector<Fl_PNG_Image*> snack_images_tile_size; +}; + +struct MainData { + Fl_Double_Window * win = NULL; + class SnakeMap * snake_map = NULL; + Fl_Menu_Bar * top_menu = NULL; + + Fl_Output * length_output = NULL; + + GameImages images; + + bool paused = false; + + Settings settings; +}; diff --git a/src/snake_map.cpp b/src/snake_map.cpp new file mode 100644 index 0000000..8a104eb --- /dev/null +++ b/src/snake_map.cpp @@ -0,0 +1,245 @@ +#include "snake_map.h" + +void SnakeMap::main_init(MainData * md) { + mdata = md; + + end(); + reset_all(); +} + +void SnakeMap::draw() { + fl_rectf(x(), y(), w(), h(), color()); + fl_rect(x(), y(), w(), h(), 0x0); + + draw_snake(mdata, snake_blocks); + draw_snack(mdata, this, snack); +} + +int SnakeMap::handle(int event) { + switch (event) { + case FL_FOCUS: + case FL_UNFOCUS: + return 1; + case FL_KEYDOWN: + + if (mdata->paused) + goto end_of_keydown; + + switch (Fl::event_key()) { + case FL_Right: + if (direction != SNAKE_LEFT) + direction = SNAKE_RIGHT; + + break; + case FL_Left: + if (direction != SNAKE_RIGHT) + direction = SNAKE_LEFT; + + break; + case FL_Up: + if (direction != SNAKE_DOWN) + direction = SNAKE_UP; + + break; + case FL_Down: + if (direction != SNAKE_UP) + direction = SNAKE_DOWN; + + break; + default: + break; + } + +end_of_keydown: // Yes I know. goto sucks. + mdata->win->handle(FL_SHORTCUT); // A hack for keyboard shortcuts. + return 1; + case FL_KEYUP: + return 1; + default: + return 0; + } +} + +void SnakeMap::update() { + int i; + SnakeBlock block_behind; + SNAKE_DIR snake_dir; + + if (mdata->paused) + return; + + // Set head direction. + snake_blocks.front().current_direction = direction; + + // Update snake blocks. + for (i = 0; i < snake_blocks.size(); i++) { + + // Update direction. + snake_dir = snake_blocks[i].current_direction; + + // Go to update_position if head. + if (i == 0) + goto update_position; + + block_behind = snake_blocks[i - 1]; + + switch (block_behind.current_direction) { + case SNAKE_STILL: + break; + case SNAKE_RIGHT: + snake_dir = (snake_blocks[i].y > block_behind.y) ? SNAKE_UP : SNAKE_DOWN; + + // Set to same direction. + if (abs(snake_blocks[i].y - block_behind.y) <= mdata->settings.snake_speed) + snake_dir = SNAKE_RIGHT; + break; + case SNAKE_LEFT: + snake_dir = (snake_blocks[i].y > block_behind.y) ? SNAKE_UP : SNAKE_DOWN; + + if (abs(snake_blocks[i].y - block_behind.y) <= mdata->settings.snake_speed) + snake_dir = SNAKE_LEFT; + break; + case SNAKE_UP: + snake_dir = (snake_blocks[i].x > block_behind.x) ? SNAKE_LEFT : SNAKE_RIGHT; + + if (abs(snake_blocks[i].x - block_behind.x) <= mdata->settings.snake_speed) + snake_dir = SNAKE_UP; + break; + case SNAKE_DOWN: + snake_dir = (snake_blocks[i].x > block_behind.x) ? SNAKE_LEFT : SNAKE_RIGHT; + + if (abs(snake_blocks[i].x - block_behind.x) <= mdata->settings.snake_speed) + snake_dir = SNAKE_DOWN; + break; + default: + break; + } + + // Set new direction value. + snake_blocks[i].current_direction = snake_dir; + put_snake_blocks_side_by_side(mdata->settings.tile_size, &snake_blocks[i], block_behind); + +update_position: + // Update position. + switch (snake_dir) { + case SNAKE_STILL: + break; + case SNAKE_RIGHT: + snake_blocks[i].x += mdata->settings.snake_speed; + break; + case SNAKE_LEFT: + snake_blocks[i].x -= mdata->settings.snake_speed; + break; + case SNAKE_UP: + snake_blocks[i].y -= mdata->settings.snake_speed; + break; + case SNAKE_DOWN: + snake_blocks[i].y += mdata->settings.snake_speed; + break; + default: + break; + } + + // Hit self (but not the first and second block). + if (mdata->settings.die_when_hit_self && i > 2) + if (snake_blocks_hit(mdata->settings.tile_size, snake_blocks.front(), snake_blocks[i])) { + reset_all(); + return; + } + } + + // Check is out of bounds. + if (snake_block_out_of_bounds(snake_blocks.front())) { + reset_all(); + return; + } + + // Eat yummies. + if (snake_block_eat_snack(mdata->settings.tile_size, this, snake_blocks.front(), snack)) { + reset_snack(); + add_snake_block(); + return; + } +} + +void SnakeMap::reset_size() { + w(mdata->settings.tile_size * mdata->settings.tile_count_w); + h(mdata->settings.tile_size * mdata->settings.tile_count_h); + + // Center. + position( + (mdata->win->w() / 2) - (w() / 2), + (mdata->win->h() / 2) - (h() / 2) + ); + + mdata->win->redraw(); +} + +void SnakeMap::reset_snake() { + direction = SNAKE_STILL; + snake_blocks.clear(); + + // Create snake head. + SnakeBlock head_block; + head_block.part = SNAKE_HEAD; + head_block.current_direction = SNAKE_STILL; + + // Center snake. + head_block.x = x() + (w() / 2); + head_block.y = y() + (h() / 2); + + snake_blocks.push_back(head_block); + update_length_output(); +} + +void SnakeMap::reset_snack() { + snack.type = (SNACK_TYPE)random_range(0, SNACK_COUNT); + snack.x = random_range(0, mdata->settings.tile_count_w - 1); + snack.y = random_range(0, mdata->settings.tile_count_h - 1); +} + +void SnakeMap::reset_all() { + reset_size(); + reset_snake(); + reset_snack(); +} + +bool SnakeMap::snake_block_out_of_bounds(SnakeBlock snake_block) { + int tile_size = mdata->settings.tile_size; + + bool x_out = (snake_block.x < x()) | (snake_block.x + tile_size > x() + w()); + bool y_out = (snake_block.y < y()) | (snake_block.y + tile_size > y() + h()); + + return x_out | y_out; +} + +void SnakeMap::add_snake_block() { + SnakeBlock block_behind; + block_behind = snake_blocks.back(); + + if (snake_blocks.size() > 1) + snake_blocks.back().part = SNAKE_BODY; + + // Create new block. + SnakeBlock new_block; + new_block.part = SNAKE_TAIL; + new_block.current_direction = block_behind.current_direction; + + // Set position. + put_snake_blocks_side_by_side(mdata->settings.tile_size, &new_block, block_behind); + + snake_blocks.push_back(new_block); + update_length_output(); +} + +void SnakeMap::update_length_output() { + if (mdata->length_output == NULL) + return; + + char buf[NAME_MAX]; + memset(buf, 0, NAME_MAX); + + snprintf(buf, NAME_MAX, "%d", snake_blocks.size() - 1); // Head does not + // count. + mdata->length_output->value(buf); +} diff --git a/src/snake_map.h b/src/snake_map.h new file mode 100644 index 0000000..a10c123 --- /dev/null +++ b/src/snake_map.h @@ -0,0 +1,37 @@ +#pragma once + +#include "program_data.h" +#include "snake_utils.h" + +class SnakeMap : public Fl_Group { + public: + SnakeMap(MainData * md) : Fl_Group(0, 0, 0, 0) { + main_init(md); + } + + void draw(); + int handle(int event); + void update(); + + // Always reset size first then snake. + void reset_size(); + void reset_snake(); + void reset_snack(); + void reset_all(); + + SNAKE_DIR snake_direction() { return direction; } + void snake_direction(SNAKE_DIR direction) { this->direction = direction; } + + void add_snake_block(); + + void update_length_output(); + private: + MainData * mdata; + SNAKE_DIR direction = SNAKE_STILL; + SnakeSnack snack; + + std::vector<SnakeBlock> snake_blocks; + + void main_init(MainData * md); + bool snake_block_out_of_bounds(SnakeBlock snake_block); +}; diff --git a/src/snake_utils.cpp b/src/snake_utils.cpp new file mode 100644 index 0000000..c8cfa30 --- /dev/null +++ b/src/snake_utils.cpp @@ -0,0 +1,174 @@ +#include "snake_utils.h" + +bool snake_blocks_hit(int tile_size, SnakeBlock b1, SnakeBlock b2) { + return b1.x + tile_size >= b2.x + && b1.x <= b2.x + tile_size + && b1.y + tile_size >= b2.y + && b1.y <= b2.y + tile_size; +} + +bool snake_block_eat_snack(int tile_size, const Fl_Group * snake_map, SnakeBlock snake_block, SnakeSnack snack) { + // Get snack x and y pixel locations. + int snack_x, snack_y; + snack_x = (snack.x * tile_size) + snake_map->x(); + snack_y = (snack.y * tile_size) + snake_map->y(); + + return snake_block.x + tile_size >= snack_x + && snake_block.x <= snack_x + tile_size + && snake_block.y + tile_size >= snack_y + && snake_block.y <= snack_y + tile_size; +} + +int put_snake_blocks_side_by_side(int tile_size, SnakeBlock * b1, SnakeBlock b2) { + if (b1 == NULL) + return -1; + if (b1->current_direction != b2.current_direction) + return -1; + + switch (b1->current_direction) { + case SNAKE_STILL: + break; + case SNAKE_RIGHT: + b1->x = b2.x - tile_size; + b1->y = b2.y; + break; + case SNAKE_LEFT: + b1->x = b2.x + tile_size; + b1->y = b2.y; + break; + case SNAKE_UP: + b1->x = b2.x; + b1->y = b2.y + tile_size; + break; + case SNAKE_DOWN: + b1->x = b2.x; + b1->y = b2.y - tile_size; + break; + default: + break; + } + + return 0; +} + +int random_range(int x, int y) { + std::random_device rd; + std::mt19937 gen(rd()); + std::uniform_int_distribution<> distr(x, y); + + return distr(gen); +} + +void draw_snake_block(MainData * mdata, SnakeBlock snake_block) { + Fl_Color draw_color; + + switch (snake_block.part) { + case SNAKE_HEAD: + draw_color = FL_BLACK; + break; + case SNAKE_BODY: + draw_color = FL_YELLOW; + break; + case SNAKE_TAIL: + draw_color = FL_BLUE; + break; + default: + break; + } + + fl_rectf(snake_block.x, snake_block.y, mdata->settings.tile_size, mdata->settings.tile_size, draw_color); +} + +void draw_snake(MainData * mdata, std::vector<SnakeBlock> snake_blocks) { + for (auto b : snake_blocks) + draw_snake_block(mdata, b); +} + +void draw_snack(MainData * mdata, const Fl_Group * snake_map, SnakeSnack snack) { + Fl_PNG_Image * draw_image; + int draw_x, draw_y; + + draw_image = mdata->images.snack_images_tile_size[snack.type]; + draw_x = (snack.x * mdata->settings.tile_size) + snake_map->x(); + draw_y = (snack.y * mdata->settings.tile_size) + snake_map->y(); + + if (draw_image->fail()) { + fl_rectf( + draw_x, + draw_y, + mdata->settings.tile_size, + mdata->settings.tile_size, + 0x0 + ); + + return; + } + + draw_image->draw(draw_x, draw_y); +} + +int str_to_int(const char * str, size_t n, int * int_value) { + int i; + int cvalue; + int value_muliplier = 1; + int res_value = 0; + int neg = 1; // -1 for negative and 1 for whole. + size_t str_len; // String length. + int end_at = 0; // Where loop should end. + + if (str == NULL || int_value == NULL || n <= 0) + return -1; + + // Get string length + str_len = strnlen(str, n); + + if (str_len <= 0) + return -1; + + // Is negative. + if (str[0] == '-') { + neg = -1; + end_at = 1; // If negative 0 item in 'str' is skipped. + } + + // Do the math. + for (i = str_len - 1; i >= end_at; i--) { + cvalue = char_to_int(str[i]); + + // Character not a number. + if (cvalue == -1) + return -1; + + // Do the same math that is down below. + res_value += cvalue * value_muliplier; + value_muliplier *= 10; + } + + /* + * "436" + * res_value = (6 * 1) + (3 * 10) + (4 * 100) + */ + + *int_value = (res_value * neg); + return 0; +} + +int char_to_int(char c) { + int cvalue = (int)c; + + // Not a number. + // 48 to 57 is 0 to 9 in ascii. + if (cvalue < 48 || cvalue > 57) + return -1; + + return cvalue - 48; // 48 is the value of zero in ascii. +} + +void set_snack_images_to_tile_size(MainData * mdata) { + mdata->images.snack_images_tile_size.clear(); + + for (auto img : mdata->images.snack_images) + mdata->images.snack_images_tile_size.push_back( + (Fl_PNG_Image*)img->copy(mdata->settings.tile_size, mdata->settings.tile_size) + ); +} diff --git a/src/snake_utils.h b/src/snake_utils.h new file mode 100644 index 0000000..d48dbf3 --- /dev/null +++ b/src/snake_utils.h @@ -0,0 +1,71 @@ +#pragma once + +#include "program_data.h" + +enum SNAKE_DIRECTIONS { + SNAKE_STILL, + SNAKE_RIGHT, + SNAKE_LEFT, + SNAKE_UP, + SNAKE_DOWN +}; + +typedef unsigned char SNAKE_DIR; + +enum SNAKE_PARTS { + SNAKE_HEAD, + SNAKE_BODY, + SNAKE_TAIL +}; + +typedef unsigned char SNAKE_PART; + +struct SnakeBlock { + SNAKE_PART part; + SNAKE_DIR current_direction; + int x, y; +}; + +// Please dont sue. Its open source software. +enum SNACKS_TYPES { + REMY_THE_RAT = 0, // From a movie about a rat that cooks which is kind of gross + // when you think about it. + FRIENDLY_FROG = 1, // Something I made up. + EASTER_BUNNY = 2, // Hopefully not copyrighted. If so my childhood was a lie + // )---: + GIDGET_THE_POMERANIAN = 3, // A dogo in a movie made for a generation of childen + // that cant sit through an entire movie. + CHILD_PERSON = 4, // What the hell is a child person? + BIG_BIRD = 5 // A big fat bird that hants peoples nightmears. +}; + +#define SNACK_COUNT 5 + +// You can put your lawers away now, Chairen (I most like messspeld 'Chairen' +// but thats ok because I am a Utard). + +typedef unsigned char SNACK_TYPE; + +struct SnakeSnack { + SNACK_TYPE type; + int x, y; // Tile position on snake map. +}; + +bool snake_blocks_hit(int tile_size, SnakeBlock b1, SnakeBlock b2); +bool snake_block_eat_snack(int tile_size, const Fl_Group * snake_map, SnakeBlock snake_block, SnakeSnack snack); + +int put_snake_blocks_side_by_side(int tile_size, SnakeBlock * b1, SnakeBlock b2); + +int random_range(int x, int y); + +// Drawing. +void draw_snake_block(MainData * mdata, SnakeBlock snake_block); +void draw_snake(MainData * mdata, std::vector<SnakeBlock> snake_blocks); + +// 'Fl_Group * snake_map' is just the SnakeMap. +void draw_snack(MainData * mdata, const Fl_Group * snake_map, SnakeSnack snack); + +int str_to_int(const char * str, size_t n, int * int_value); +int char_to_int(char c); + +void set_snack_images_to_tile_size(MainData * mdata); diff --git a/src/top_menu.cpp b/src/top_menu.cpp new file mode 100644 index 0000000..97b9861 --- /dev/null +++ b/src/top_menu.cpp @@ -0,0 +1,25 @@ +#include "top_menu.h" + + +void new_game_cb(Fl_Widget * w, void * d) { + MainData * mdata = (MainData*)d; + + mdata->snake_map->reset_all(); +} + +void pause_cb(Fl_Widget * w, void * d) { + MainData * mdata = (MainData*)d; + + // Get button. + Fl_Menu_Bar * menu_bar = (Fl_Menu_Bar*)w; + const Fl_Menu_Item * button = menu_bar->mvalue(); + + // Set paused. + mdata->paused = (bool)button->value(); +} + +void add_menu_items(MainData * mdata, Fl_Menu_Bar * top_menu) { + // Game. + top_menu->add("&game/New game", FL_CTRL + 'n', (Fl_Callback*)new_game_cb, (void*)mdata); + top_menu->add("&game/pause", 'p', (Fl_Callback*)pause_cb, (void*)mdata, FL_MENU_TOGGLE | (mdata->paused ? FL_MENU_VALUE : 0x0)); +} diff --git a/src/top_menu.h b/src/top_menu.h new file mode 100644 index 0000000..2919347 --- /dev/null +++ b/src/top_menu.h @@ -0,0 +1,9 @@ +#pragma once + +#include "program_data.h" +#include "snake_map.h" + +void new_game_cb(Fl_Widget * w, void * d); +void pause_cb(Fl_Widget * w, void * d); + +void add_menu_items(MainData * mdata, Fl_Menu_Bar * top_menu); |