Structs
COP-3223H
Table of Contents
Structs bundle variables
Instead of having to define separate variables for one player, e.g.,
int player_x; int player_y; char player_c;
Bundle these instead a single variable
struct { int x; int y; char c; } player;
Accessing struct fields
Structs create namespaces, e.g., x can be used both in the struct and as a local variable.
struct { int x; int y; char c; } player; player.x = 2; int x = 10;
Struct declarations create new datatypes
// datatype is int name is x int x; // datatype is a new struct name is sprite struct { int x; int y; char c; } sprite;
Reusing struct datatypes
You can name a struct and use it for many variables.
// the new struct type is called "sprite". no variable name needed struct sprite { int x; int y; char c; }; // no need to repeat the full struct declaration to use it struct sprite player; struct sprite enemy; // now all variable have the same constituent variables player.x = 1; player.y = 10 enemy.x = 2; enemy.y = 3;
Chase game with structs
// https://sourceware.org/glibc/manual/latest/html_mono/libc.html#Noncanon-Example #include <stdio.h> #include <stdbool.h> #include "term.c" int main(int argc, char **argv) { set_input_mode (); printf("\033[?25l"); // hide cursor int width = 40; int height = 20; struct character { int state; int x; int y; }; struct character player; struct character enemy; enum { vulnerable, invincible, dead }; player.state = vulnerable; player.x = width / 2; player.y = height / 2; enum { chasing, running, defeated }; enemy.state = chasing; enemy.x = 1; enemy.y = 1; struct { struct character character; int counter; int random; } potion; enum { available, using, done }; potion.character.state = available; potion.character.x = 29; potion.character.y = 11; potion.counter = 0; potion.random = 1; while (1) { printf("\x1b[2J"); printf("\x1b[H"); // 0 available // 1 using // 2 done // initial state is 0 // switch (potion_state) { // case 0: // } switch (potion.character.state) { case available: printf("\033[%d;%dH", potion.character.y, potion.character.x); printf("/\\"); printf("\033[%d;%dH", potion.character.y + 1, potion.character.x); printf("\\/"); break; case using: // intentionally empty break; } printf("\033[%d;%dH", enemy.y, enemy.x); switch (enemy.state) { case chasing: // case 0: putchar('@'); break; case running: // case 1: putchar('@'); break; case defeated: // case 2: putchar('X'); } printf("\033[%d;%dH", player.y, player.x); switch (player.state) { case vulnerable: putchar('h'); break; case invincible: putchar('H'); break; case dead: printf(":("); } // debugging output printf("\033[%d;%dH", height + 1, 0); printf("player.y: %d\n", player.y); printf("player.x: %d\n", player.x); printf("enemy.y: %d\n", enemy.y); printf("enemy.x: %d\n", enemy.x); printf("potion.character.y: %d\n", potion.character.y); printf("potion.character.x: %d\n", potion.character.x); // read input int direction_x = 0; int direction_y = 0; bool valid = true; do { char c = '\0'; scanf("%c", &c); switch (c) { case 'i': direction_y = -2; break; case 'k': direction_y = 2; break; case 'j': direction_x = -2; break; case 'l': direction_x = 2; break; default: valid = false; break; } } while (! valid); switch(player.state) { case vulnerable: // case 0: player.x += direction_x; player.y += direction_y; break; case invincible: // case 1: player.x += direction_x; player.y += direction_y; if (enemy.x - 1 <= player.x && player.x <= enemy.x + 1 && enemy.y - 1 <= player.y && player.y <= enemy.y + 1) { player.state = vulnerable; enemy.state = defeated; potion.character.state = done; } break; } switch (enemy.state) { case chasing: // chasing if (player.x > enemy.x) { enemy.x += 1; } if (player.x < enemy.x) { enemy.x -= 1; } if (player.y > enemy.y) { enemy.y += 1; } if (player.y < enemy.y) { enemy.y -= 1; } if ((player.x == enemy.x || player.x == enemy.x + 1) && (player.y == enemy.y || player.y == enemy.y + 1)) { player.state = dead; } break; case running: if (player.x > enemy.x) { enemy.x -= 1; } if (player.x < enemy.x) { enemy.x += 1; } if (player.y > enemy.y) { enemy.y -= 1; } if (player.y < enemy.y) { enemy.y += 1; } if (enemy.x < 0) { enemy.x = 0; } if (enemy.x > width) { enemy.x = width; } if (enemy.y < 0) { enemy.y = 0; } if (enemy.y > height) { enemy.y = height; } break; } switch (potion.character.state) { case available: if ((player.x == potion.character.x || player.x == potion.character.x + 1) && (player.y == potion.character.y || player.y == potion.character.y + 1)) { player.state = invincible; enemy.state = running; potion.character.state = using; potion.counter = 10; } break; case using: potion.counter -= 1; if (potion.counter == 1) { player.state = vulnerable; enemy.state = chasing; potion.character.state = available; potion.random = (potion.random * 97) % 65533; potion.character.x = potion.random % width; potion.random = (potion.random * 97) % 65533; potion.character.y = potion.random % height; } break; } } }