Created
January 4, 2016 13:09
-
-
Save naezith/14cb45d2afe7b276c62c to your computer and use it in GitHub Desktop.
Snake and Mouse game and this time, you're the mouse! Full C Source Code
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| // Snake and Mouse game, you're the mouse. Eat cheese to get points and watch out for the snake! | |
| // Written by naezith, you can use/change the code however you want. | |
| #include <stdio.h> | |
| #include <conio.h> | |
| #include <windows.h> | |
| #include <math.h> | |
| #include <time.h> | |
| #define MAP_WIDTH 20 | |
| #define MAP_HEIGHT 20 | |
| #define SNAKE_SIZE 8 | |
| void init(); | |
| void input(); | |
| void draw(); | |
| void logic(); | |
| int onPlayer(int, int); | |
| int onCheese(int, int); | |
| int onSnake(int, int); | |
| void spawnCheese(); | |
| void spawnSnake(); | |
| int rand_i(); | |
| int rand_j(); | |
| typedef struct S_COORD { int i, j; } MAP_COORD; | |
| // Game variables | |
| unsigned frameNumber = 0; | |
| int paused = 0; | |
| // Snake variables | |
| float snake_pos_i, snake_pos_j, snake_speed = 0.15f; | |
| MAP_COORD snake_body[SNAKE_SIZE]; | |
| // Player and cheese variables | |
| int player_score, highest_score = 0; | |
| MAP_COORD player_pos, cheese_pos; | |
| // Returns random position on the level | |
| int rand_i() { return rand() % MAP_HEIGHT; } | |
| int rand_j() { return rand() % MAP_WIDTH; } | |
| // Check if position is on player | |
| int onPlayer(int i, int j) { return i == player_pos.i && j == player_pos.j; } | |
| // Check if position is on cheese | |
| int onCheese(int i, int j) { return i == cheese_pos.i && j == cheese_pos.j; } | |
| // Check if position is on snake, if yes, return the body part number | |
| int onSnake(int i, int j) { | |
| int k; | |
| for (k = 0; k < SNAKE_SIZE; ++k) if (i == snake_body[k].i && j == snake_body[k].j) return k + 1; | |
| return 0; | |
| } | |
| void spawnCheese() { | |
| // Find a proper random place for cheese: not on another cheese, not on the player and not on the snake | |
| int i, j; | |
| do { i = rand_i(); j = rand_j(); | |
| } while (onCheese(i, j) || onPlayer(i, j) || onSnake(i, j) == 1); | |
| // Then place it there | |
| cheese_pos.i = i; | |
| cheese_pos.j = j; | |
| } | |
| void spawnSnake() { | |
| // Put snake to the top left | |
| int i; | |
| for (i = 0; i < SNAKE_SIZE; ++i) { | |
| snake_body[i].i = 0; | |
| snake_body[i].j = i; | |
| } | |
| // Set his head position to float position holder | |
| snake_pos_i = (float)snake_body[SNAKE_SIZE-1].i; | |
| snake_pos_j = (float)snake_body[SNAKE_SIZE-1].j; | |
| } | |
| void moveSnake() { | |
| MAP_COORD head = snake_body[SNAKE_SIZE-1], new_pos; | |
| // Calculate the distance vector | |
| float d_i = (float)(player_pos.i - head.i); | |
| float d_j = (float)(player_pos.j - head.j); | |
| // Calculate the length of the distance vector | |
| float mag = sqrtf(d_i*d_i + d_j*d_j); | |
| // Add the unit vector to our position | |
| snake_pos_i += snake_speed * d_i / mag; | |
| snake_pos_j += snake_speed * d_j / mag; | |
| // Iterate the snake body parts when position is really changed as integer | |
| new_pos.i = (int)snake_pos_i; | |
| new_pos.j = (int)snake_pos_j; | |
| if (new_pos.i != head.i || new_pos.j != head.j) { | |
| int k; | |
| for (k = 0; k < SNAKE_SIZE-1; ++k) snake_body[k] = snake_body[k + 1]; | |
| snake_body[k] = new_pos; | |
| } | |
| } | |
| void main(void) { | |
| int fps = 60; // 30 to 60 fps is common for rendering graphics. | |
| int sleepTime = 1000 / fps; // To get 60 fps, we have to redraw graphics every 1000/60=17 miliseconds | |
| srand((unsigned int)time(0)); | |
| init(); // Do your initialization before the infinite loop starts. | |
| // This is the structure used in programming most games. | |
| // An infinite loop is run with the game logic and graphics being updated at each iteration. | |
| while (1) { | |
| // Check if there is any input, update your variables accordingly. | |
| input(); | |
| // Do not refresh graphics when paused, it causes unnecessary flicker. | |
| if (paused == 0) { | |
| // Refresh graphics. | |
| draw(); | |
| // Update variables accordingly. | |
| logic(); | |
| // At each iteration, we sleep for a predetermined amount of time. | |
| // There are better ways of doing this (multi-threading). | |
| Sleep(sleepTime); | |
| } | |
| } | |
| } | |
| void init() { | |
| // Stop the game | |
| paused = 1; | |
| // Reset current score | |
| player_score = 0; | |
| // Put player in a safe field | |
| player_pos.i = (MAP_HEIGHT + rand_i()) / 2; | |
| player_pos.j = rand_j(); | |
| spawnSnake(); | |
| spawnCheese(); | |
| draw(); | |
| } | |
| void input() { | |
| char input; | |
| // _kbhit() checks if there is a character in the buffer, i.e. if you hit any buttons during Sleep(). | |
| if (_kbhit()) { | |
| // Since a character is already in the buffer, it is loaded to the variable instantly. | |
| // In other words, this getch() does not stall the program and wait for your response. | |
| input = _getch(); | |
| // Pause | |
| if (input == 'p') paused = !paused; | |
| // Exit | |
| else if (input == 'x') exit(0); | |
| // Move up | |
| else if (input == 'w' && player_pos.i > 0) --player_pos.i; | |
| // Move down | |
| else if (input == 's' && player_pos.i + 1 < MAP_HEIGHT) ++player_pos.i; | |
| // Move left | |
| else if (input == 'a' && player_pos.j > 0) --player_pos.j; | |
| // Move right | |
| else if (input == 'd' && player_pos.j + 1 < MAP_WIDTH) ++player_pos.j; | |
| // Resume the game if key is not p | |
| if (input != 'p') paused = 0; | |
| } | |
| } | |
| // This is where the magic happens. You should update game related variables here | |
| char curr_color[1] = "F"; // Console start color | |
| void logic() { | |
| frameNumber++; | |
| // Eat cheese | |
| if (onCheese(player_pos.i, player_pos.j)) { | |
| spawnCheese(); | |
| if (++player_score > highest_score) highest_score = player_score; | |
| } | |
| moveSnake(); | |
| // Snake hits player, restart. | |
| if (onSnake(player_pos.i, player_pos.j)) init(); | |
| // Change console color for fun | |
| if (frameNumber % 5 == 0) { | |
| char color[9] = "color 0"; | |
| strcat_s(color, 9, curr_color); | |
| system(color); | |
| // Cycle colors F to A | |
| if (curr_color[0] == 'A') curr_color[0] = 'F'; | |
| else --curr_color[0]; | |
| } | |
| } | |
| // Note that we have to redraw the entire image | |
| // This is the case for all practical graphics engines. | |
| void draw() { | |
| int i, j; | |
| // Clears the command line, note that this is platform specific, i.e. will not work on UNIX etc. | |
| system("cls"); | |
| printf("\n #"); | |
| for (i = 0; i < MAP_WIDTH; ++i) printf("="); | |
| printf("# Pause(p) Exit(x) Move(w, a, s, d)\n"); | |
| for (i = 0; i < MAP_HEIGHT; i++) { | |
| printf(" |"); | |
| for (j = 0; j < MAP_WIDTH; j++) { | |
| int is_snake_body_part = onSnake(i, j); // Which part of snake? | |
| // Print player | |
| if (onPlayer(i, j)) printf("@"); | |
| // Print Head | |
| else if (is_snake_body_part == SNAKE_SIZE) printf("%c", 219); | |
| // Print Body | |
| else if (is_snake_body_part) printf("%c", is_snake_body_part % 2 == 0 ? 176 : 177); | |
| // Print Cheese | |
| else if (onCheese(i, j)) printf("%c", 207); | |
| // Print Empty field | |
| else printf(" "); | |
| } | |
| printf("|\n"); | |
| } | |
| printf(" #"); | |
| for (i = 0; i < MAP_WIDTH; ++i) printf("="); | |
| printf("# Score : %d Highest : %d", player_score, highest_score); | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment