├── README.md ├── appinfo.json ├── resources ├── 0_deg.png ├── 10_deg.png ├── 20_deg.png ├── ground.png ├── neg_10_deg.png ├── neg_20_deg.png ├── neg_30_deg.png ├── neg_50_deg.png ├── neg_70_deg.png ├── neg_90_deg.png └── normal_bird.png ├── src ├── bird │ ├── bird.c │ └── bird.h ├── flappy-bird.c ├── game.c ├── game.h ├── ground │ ├── ground.c │ └── ground.h ├── score │ ├── score.c │ └── score.h ├── title │ ├── title.c │ └── title.h └── tube │ ├── tube.c │ └── tube.h └── wscript /README.md: -------------------------------------------------------------------------------- 1 | Tiny Bird 2 | ========= 3 | 4 | Flappy Bird clone for pebble. 5 | 6 | Ideas 7 | ------- 8 | 9 | - Option to share scores via facebook / twitter -- possibly using http://setpebble.com/ 10 | - Try doing bird rotation via RotBitmapLayer's API instead of switching between custom-made bitmaps. 11 | 12 | Issues 13 | ------- 14 | 15 | - Collision detection is off 16 | - The screen will pause every once in a while 17 | -------------------------------------------------------------------------------- /appinfo.json: -------------------------------------------------------------------------------- 1 | { 2 | "uuid": "2edff9df-4d60-47db-9962-437d40c5f1e2", 3 | "shortName": "Tiny Bird", 4 | "longName": "Tiny Bird", 5 | "companyName": "StuartHa", 6 | "versionCode": 1, 7 | "versionLabel": "1.0", 8 | "watchapp": { 9 | "watchface": false 10 | }, 11 | "appKeys": { 12 | "dummy": 0 13 | }, 14 | "resources": { 15 | "media": [ 16 | { 17 | "type": "png", 18 | "name": "IMAGE_20_DEG", 19 | "file": "20_deg.png" 20 | }, 21 | { 22 | "type": "png", 23 | "name": "IMAGE_10_DEG", 24 | "file": "10_deg.png" 25 | }, 26 | { 27 | "type": "png", 28 | "name": "IMAGE_0_DEG", 29 | "file": "0_deg.png", 30 | "menuIcon" : true 31 | }, 32 | { 33 | "type": "png", 34 | "name": "IMAGE_NEG_10_DEG", 35 | "file": "neg_10_deg.png" 36 | }, 37 | { 38 | "type": "png", 39 | "name": "IMAGE_NEG_20_DEG", 40 | "file": "neg_20_deg.png" 41 | }, 42 | { 43 | "type": "png", 44 | "name": "IMAGE_NEG_30_DEG", 45 | "file": "neg_30_deg.png" 46 | }, 47 | { 48 | "type": "png", 49 | "name": "IMAGE_NEG_50_DEG", 50 | "file": "neg_50_deg.png" 51 | }, 52 | { 53 | "type": "png", 54 | "name": "IMAGE_NEG_70_DEG", 55 | "file": "neg_70_deg.png" 56 | }, 57 | { 58 | "type": "png", 59 | "name": "IMAGE_NEG_90_DEG", 60 | "file": "neg_90_deg.png" 61 | }, 62 | { 63 | "type": "png", 64 | "name": "IMAGE_GROUND", 65 | "file": "ground.png" 66 | } 67 | 68 | ] 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /resources/0_deg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/StuartHa/tiny_bird/64301d1b82029558e59a64b4a08820b0a2e07011/resources/0_deg.png -------------------------------------------------------------------------------- /resources/10_deg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/StuartHa/tiny_bird/64301d1b82029558e59a64b4a08820b0a2e07011/resources/10_deg.png -------------------------------------------------------------------------------- /resources/20_deg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/StuartHa/tiny_bird/64301d1b82029558e59a64b4a08820b0a2e07011/resources/20_deg.png -------------------------------------------------------------------------------- /resources/ground.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/StuartHa/tiny_bird/64301d1b82029558e59a64b4a08820b0a2e07011/resources/ground.png -------------------------------------------------------------------------------- /resources/neg_10_deg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/StuartHa/tiny_bird/64301d1b82029558e59a64b4a08820b0a2e07011/resources/neg_10_deg.png -------------------------------------------------------------------------------- /resources/neg_20_deg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/StuartHa/tiny_bird/64301d1b82029558e59a64b4a08820b0a2e07011/resources/neg_20_deg.png -------------------------------------------------------------------------------- /resources/neg_30_deg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/StuartHa/tiny_bird/64301d1b82029558e59a64b4a08820b0a2e07011/resources/neg_30_deg.png -------------------------------------------------------------------------------- /resources/neg_50_deg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/StuartHa/tiny_bird/64301d1b82029558e59a64b4a08820b0a2e07011/resources/neg_50_deg.png -------------------------------------------------------------------------------- /resources/neg_70_deg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/StuartHa/tiny_bird/64301d1b82029558e59a64b4a08820b0a2e07011/resources/neg_70_deg.png -------------------------------------------------------------------------------- /resources/neg_90_deg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/StuartHa/tiny_bird/64301d1b82029558e59a64b4a08820b0a2e07011/resources/neg_90_deg.png -------------------------------------------------------------------------------- /resources/normal_bird.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/StuartHa/tiny_bird/64301d1b82029558e59a64b4a08820b0a2e07011/resources/normal_bird.png -------------------------------------------------------------------------------- /src/bird/bird.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "bird.h" 3 | 4 | static void s_init(void); 5 | 6 | static GBitmap* s_pos_20_deg; 7 | static GBitmap* s_pos_10_deg; 8 | static GBitmap* s_pos_0_deg; 9 | static GBitmap* s_neg_pos_10_deg; 10 | static GBitmap* s_neg_pos_20_deg; 11 | static GBitmap* s_neg_30_deg; 12 | static GBitmap* s_neg_50_deg; 13 | static GBitmap* s_neg_70_deg; 14 | static GBitmap* s_neg_90_deg; 15 | 16 | void bird_draw(bird_t *bird, GContext *ctx) { 17 | if (!s_pos_20_deg) { 18 | s_init(); 19 | } 20 | int y = bird->y_mp / 10; 21 | 22 | if(bird->v_mp < -6){ 23 | graphics_draw_bitmap_in_rect(ctx, s_pos_20_deg, (GRect) {.origin = {10, y}, .size = {30, 19}}); 24 | } 25 | else if(bird->v_mp < 0) { 26 | graphics_draw_bitmap_in_rect(ctx, s_pos_10_deg, (GRect) {.origin = {10, y}, .size = {30, 19}}); 27 | } 28 | else if(bird->v_mp < 6) { 29 | graphics_draw_bitmap_in_rect(ctx, s_pos_0_deg, (GRect) {.origin = {10, y}, .size = {30, 19}}); 30 | } 31 | else if(bird->v_mp < 13) { 32 | graphics_draw_bitmap_in_rect(ctx, s_neg_pos_10_deg, (GRect) {.origin = {10, y}, .size = {30, 19}}); 33 | } 34 | else if(bird->v_mp < 17) { 35 | graphics_draw_bitmap_in_rect(ctx, s_neg_pos_20_deg, (GRect) {.origin = {10, y}, .size = {30, 19}}); 36 | } 37 | else if(bird->v_mp < 22) { 38 | graphics_draw_bitmap_in_rect(ctx, s_neg_30_deg, (GRect) {.origin = {10, y}, .size = {30, 19}}); 39 | } 40 | else if(bird->v_mp < 27) { 41 | graphics_draw_bitmap_in_rect(ctx, s_neg_50_deg, (GRect) {.origin = {10, y}, .size = {30, 19}}); 42 | } 43 | else if(bird->v_mp < 32) { 44 | graphics_draw_bitmap_in_rect(ctx, s_neg_70_deg, (GRect) {.origin = {10, y}, .size = {30, 19}}); 45 | } 46 | else { 47 | graphics_draw_bitmap_in_rect(ctx, s_neg_90_deg, (GRect) {.origin = {10, y}, .size = {30, 19}}); 48 | } 49 | } 50 | 51 | void bird_update_state(bird_t *bird, int delta_t) { 52 | int y = bird->y_mp / 10; 53 | 54 | if(y >= 141) { 55 | bird->y_mp = 141 * 10; 56 | } else { 57 | int y_accel_mp = 1; 58 | bird->y_mp += bird->v_mp * delta_t + y_accel_mp * delta_t * delta_t; 59 | bird->v_mp += y_accel_mp * delta_t; 60 | } 61 | 62 | 63 | } 64 | 65 | void bird_flap(bird_t *bird) { 66 | bird->v_mp = -26; 67 | } 68 | 69 | bird_t *bird_create(int x, int y, int v) { 70 | bird_t *new_bird = malloc(sizeof(bird_t)); 71 | new_bird->x_mp = x * 10; 72 | new_bird->y_mp = y * 10; 73 | new_bird->v_mp = v * 10; 74 | 75 | return new_bird; 76 | } 77 | 78 | void bird_delete(bird_t *bird) { 79 | free(bird); 80 | } 81 | 82 | static void s_init(void) { 83 | s_pos_20_deg = gbitmap_create_with_resource(RESOURCE_ID_IMAGE_20_DEG); 84 | s_pos_10_deg = gbitmap_create_with_resource(RESOURCE_ID_IMAGE_10_DEG); 85 | s_pos_0_deg = gbitmap_create_with_resource(RESOURCE_ID_IMAGE_0_DEG); 86 | s_neg_pos_10_deg = gbitmap_create_with_resource(RESOURCE_ID_IMAGE_NEG_10_DEG); 87 | s_neg_pos_20_deg = gbitmap_create_with_resource(RESOURCE_ID_IMAGE_NEG_20_DEG); 88 | s_neg_30_deg = gbitmap_create_with_resource(RESOURCE_ID_IMAGE_NEG_30_DEG); 89 | s_neg_50_deg = gbitmap_create_with_resource(RESOURCE_ID_IMAGE_NEG_50_DEG); 90 | s_neg_70_deg = gbitmap_create_with_resource(RESOURCE_ID_IMAGE_NEG_70_DEG); 91 | s_neg_90_deg = gbitmap_create_with_resource(RESOURCE_ID_IMAGE_NEG_90_DEG); 92 | } -------------------------------------------------------------------------------- /src/bird/bird.h: -------------------------------------------------------------------------------- 1 | // 10 mp = 1 pixel 2 | typedef struct { 3 | int x_mp; 4 | int y_mp; 5 | int v_mp; 6 | } bird_t; 7 | 8 | void bird_draw(bird_t *bird, GContext *ctx); 9 | void bird_flap(bird_t *bird); 10 | void bird_update_state(bird_t *bird, int delta_t); 11 | 12 | bird_t *bird_create(int x_mp, int y_mp, int v_mp); 13 | void bird_delete(bird_t *bird); 14 | 15 | 16 | -------------------------------------------------------------------------------- /src/flappy-bird.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "game.h" 3 | 4 | static Window *window; 5 | static Layer *layer; 6 | 7 | static void click_config_provider(void *context) { 8 | window_single_click_subscribe(BUTTON_ID_UP, game_up_click_handler); 9 | } 10 | 11 | static void window_load(Window *window) { 12 | Layer *window_layer = window_get_root_layer(window); 13 | GRect bounds = layer_get_bounds(window_layer); 14 | layer = layer_create(bounds); 15 | layer_add_child(window_layer, layer); 16 | 17 | game_init(); 18 | game_start(layer); 19 | } 20 | 21 | static void init(void) { 22 | window = window_create(); 23 | window_set_click_config_provider(window, click_config_provider); 24 | window_set_window_handlers(window, (WindowHandlers) { 25 | .load = window_load 26 | }); 27 | const bool animated = true; 28 | window_set_fullscreen(window, true); 29 | window_stack_push(window, animated); 30 | } 31 | 32 | static void deinit(void) { 33 | window_destroy(window); 34 | } 35 | 36 | int main(void) { 37 | init(); 38 | app_event_loop(); 39 | deinit(); 40 | } 41 | -------------------------------------------------------------------------------- /src/game.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "bird/bird.h" 3 | #include "title/title.h" 4 | #include "tube/tube.h" 5 | #include "ground/ground.h" 6 | #include "score/score.h" 7 | 8 | #define SCORE_PERSIST_KEY (42) 9 | 10 | static bird_t *s_bird; 11 | static ground_t *s_ground; 12 | static tube_t *s_tube1; 13 | static tube_t *s_tube2; 14 | 15 | static int s_best_score; 16 | static int s_current_score; 17 | 18 | static bool s_on_title_screen; 19 | static bool s_in_beginning_stage; 20 | static bool s_collision_occurred; 21 | 22 | static Layer *s_game_layer; 23 | static AppTimer *s_game_over_time; 24 | static AppTimer *s_beginning_stage_time; 25 | 26 | static void s_exit_no_tube_stage(void *data); 27 | static bool s_has_collision_occured(void); 28 | static void s_go_to_title_screen(void *data); 29 | static void s_reset_game_state(void); 30 | 31 | void game_init(void) { 32 | s_reset_game_state(); 33 | srand(time(NULL)); 34 | 35 | if(persist_exists(SCORE_PERSIST_KEY)) { 36 | s_best_score = persist_read_int(SCORE_PERSIST_KEY); 37 | } 38 | } 39 | 40 | void game_up_click_handler(ClickRecognizerRef recognizer, void *context) { 41 | if (s_on_title_screen) { 42 | s_on_title_screen = false; 43 | s_in_beginning_stage = true; 44 | bird_flap(s_bird); 45 | 46 | s_beginning_stage_time = app_timer_register(4000, s_exit_no_tube_stage, NULL); 47 | } else { 48 | if (!s_collision_occurred) { 49 | bird_flap(s_bird); 50 | } 51 | } 52 | } 53 | 54 | void game_render(Layer *layer, GContext *ctx) { 55 | if (s_on_title_screen) { 56 | title_draw(ctx, &s_best_score); 57 | } else { 58 | bird_draw(s_bird, ctx); 59 | if (!s_in_beginning_stage) { 60 | tube_draw(s_tube1, ctx); 61 | tube_draw(s_tube2, ctx); 62 | } 63 | score_draw(ctx, 100, 7, s_current_score); 64 | } 65 | ground_draw(s_ground, ctx); 66 | } 67 | 68 | void game_state_update(void *data) { 69 | int delta_t = (int)data; 70 | 71 | if (!s_on_title_screen) { 72 | bird_update_state(s_bird, delta_t); 73 | 74 | if(s_bird->y_mp == 141 * 10 && !s_game_over_time) { 75 | s_game_over_time = app_timer_register(1000, s_go_to_title_screen, NULL); 76 | } 77 | if (!s_collision_occurred) { 78 | ground_update_state(s_ground, delta_t); 79 | 80 | if (!s_in_beginning_stage) { 81 | int tube1_old_x = s_tube1->x; 82 | tube_update_state(s_tube1, delta_t); 83 | tube_update_state(s_tube2, delta_t); 84 | 85 | if (s_tube1->x < 17 && tube1_old_x > 17) { 86 | s_current_score++; 87 | } 88 | 89 | if (s_tube1->x < -20) { 90 | tube_delete(s_tube1); 91 | s_tube1 = s_tube2; 92 | s_tube2 = tube_create(144, 15 + rand() % 65); 93 | } 94 | } 95 | 96 | if (s_has_collision_occured()) { 97 | vibes_short_pulse(); 98 | s_collision_occurred = true; 99 | } 100 | } 101 | if (s_ground->x < -11) { 102 | s_ground->x = 0; 103 | } 104 | } 105 | 106 | app_timer_register(50, game_state_update, data); 107 | layer_mark_dirty(s_game_layer); 108 | } 109 | 110 | void game_start(Layer *game_layer) { 111 | s_game_layer = game_layer; 112 | 113 | layer_set_update_proc(s_game_layer, game_render); 114 | 115 | int *time_step = (int *)3; 116 | app_timer_register(50, game_state_update, time_step); 117 | } 118 | 119 | static bool s_has_collision_occured(void) { 120 | int y = s_bird->y_mp / 10; 121 | if(y >= 141) 122 | return true; 123 | if(s_in_beginning_stage || s_on_title_screen) 124 | return false; 125 | if(s_tube1->x < 10 + 19 && s_tube1->x > 10 && y >= 158 - s_tube1->y) 126 | return true; 127 | if(s_tube1->x < 10 + 19 && s_tube1->x > 10 && y < 158 - s_tube1->y - 20 - 55) 128 | return true; 129 | if(s_tube1->x - 2 < 10 + 19 && s_tube1->x +25 + 2 > 10 + 19 && y < 158 - s_tube1->y && y >= 158 - s_tube1->y - 10) 130 | return true; 131 | if(s_tube1->x - 2 < 10 + 19 && s_tube1->x + 25 + 2 > 10 + 19 && y + 18 < 158 - s_tube1->y && y + 18>= 158 - s_tube1->y - 10) 132 | return true; 133 | if(s_tube1->x - 2 < 10 + 19 && s_tube1->x +25 +2 > 10 + 19 && y <= 158 - s_tube1->y - 10 - 55 && y > 158 - s_tube1->y - 10 - 55 - 10) 134 | return true; 135 | 136 | return false; 137 | } 138 | 139 | static void s_exit_no_tube_stage(void *data) { 140 | s_in_beginning_stage = false; 141 | s_tube1 = tube_create(144, 15 + rand() % 65); 142 | s_tube2 = tube_create(230, 15 + rand() % 65); 143 | } 144 | 145 | static void s_go_to_title_screen(void *data) { 146 | if (s_current_score > s_best_score) { 147 | s_best_score = s_current_score; 148 | persist_write_int(SCORE_PERSIST_KEY, s_best_score); 149 | } 150 | 151 | s_reset_game_state(); 152 | } 153 | 154 | static void s_reset_game_state(void) { 155 | s_on_title_screen = true; 156 | s_collision_occurred = false; 157 | s_game_over_time = NULL; 158 | s_current_score = 0; 159 | 160 | bird_delete(s_bird); 161 | ground_delete(s_ground); 162 | if (!s_in_beginning_stage) { 163 | tube_delete(s_tube1); 164 | tube_delete(s_tube2); 165 | } 166 | 167 | app_timer_cancel(s_beginning_stage_time); 168 | 169 | s_bird = bird_create(10, 50, 0); 170 | s_ground = ground_create(0, 158); 171 | 172 | s_in_beginning_stage = false; 173 | } -------------------------------------------------------------------------------- /src/game.h: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | void game_init(void); 4 | void game_up_click_handler(ClickRecognizerRef recognizer, void *context); 5 | void game_start(Layer *game_layer); -------------------------------------------------------------------------------- /src/ground/ground.c: -------------------------------------------------------------------------------- 1 | #include "ground.h" 2 | 3 | static GBitmap *s_ground; 4 | 5 | static void s_init(void); 6 | 7 | void ground_draw(ground_t *ground, GContext *ctx) { 8 | if (!s_ground) { 9 | s_init(); 10 | } 11 | 12 | graphics_draw_bitmap_in_rect(ctx, s_ground, (GRect) {.origin = {ground->x, ground->y}, .size = {170, 10}}); 13 | } 14 | 15 | //TODO: calculate using delta_t 16 | void ground_update_state(ground_t *ground, int delta_t) { 17 | ground->x -= 2; 18 | } 19 | 20 | ground_t *ground_create(int x, int y) { 21 | ground_t *new_ground = malloc(sizeof(ground_t)); 22 | new_ground->x = x; 23 | new_ground->y = y; 24 | 25 | return new_ground; 26 | } 27 | 28 | void ground_delete(ground_t *ground) { 29 | free(ground); 30 | } 31 | 32 | static void s_init(void) { 33 | s_ground = gbitmap_create_with_resource(RESOURCE_ID_IMAGE_GROUND); 34 | 35 | } -------------------------------------------------------------------------------- /src/ground/ground.h: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | typedef struct { 4 | int x; 5 | int y; 6 | } ground_t; 7 | 8 | void ground_draw(ground_t *ground, GContext *ctx); 9 | void ground_update_state(ground_t *ground, int delta_t); 10 | ground_t *ground_create(int x, int y); 11 | void ground_delete(ground_t *ground); -------------------------------------------------------------------------------- /src/score/score.c: -------------------------------------------------------------------------------- 1 | #include "score.h" 2 | 3 | static char s_score_text[3]; 4 | 5 | void score_draw(GContext *ctx, int x, int y, int score) { 6 | graphics_fill_rect(ctx, (GRect) {.origin = {100, 7 }, .size = {35, 25}}, 2, GCornersAll); 7 | snprintf(s_score_text, 3, "%i", score); 8 | graphics_draw_text(ctx, s_score_text, fonts_get_system_font(FONT_KEY_ROBOTO_CONDENSED_21), (GRect) {.origin = {100,7}, .size = {35,25}}, GTextOverflowModeWordWrap, GTextAlignmentCenter, NULL); 9 | } -------------------------------------------------------------------------------- /src/score/score.h: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | void score_draw(GContext *ctx, int x, int y, int score); -------------------------------------------------------------------------------- /src/title/title.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "title.h" 3 | 4 | static GBitmap *s_bird; 5 | static GBitmap *s_ground; 6 | static char s_score_text[20]; 7 | 8 | void title_draw(GContext* ctx, int *score) { 9 | if (!s_bird || !s_ground) { 10 | s_bird = gbitmap_create_with_resource(RESOURCE_ID_IMAGE_20_DEG); 11 | s_ground = gbitmap_create_with_resource(RESOURCE_ID_IMAGE_GROUND); 12 | } 13 | 14 | graphics_context_set_text_color(ctx, GColorBlack); 15 | 16 | graphics_draw_text(ctx, "Tiny Bird", fonts_get_system_font(FONT_KEY_BITHAM_30_BLACK), (GRect) {.origin = {0,0}, .size = {144, 40}}, GTextOverflowModeWordWrap, GTextAlignmentCenter, NULL); 17 | graphics_draw_text(ctx, "PRESS UP", fonts_get_system_font(FONT_KEY_GOTHIC_24_BOLD), (GRect) {.origin = {0,95}, .size = {144, 40}}, GTextOverflowModeWordWrap, GTextAlignmentCenter, NULL); 18 | 19 | graphics_draw_bitmap_in_rect(ctx, s_bird, (GRect) {.origin = {10, 50}, .size = {30, 19}}); 20 | graphics_draw_bitmap_in_rect(ctx, s_ground, (GRect) {.origin = {0, 158}, .size = {170, 10}}); 21 | 22 | if(score) { 23 | snprintf(s_score_text, 20, "Best: %i", *score); 24 | graphics_draw_text(ctx, s_score_text, fonts_get_system_font(FONT_KEY_GOTHIC_24_BOLD), (GRect) {.origin = {0,125}, .size = {144, 40}}, GTextOverflowModeWordWrap, GTextAlignmentCenter, NULL); 25 | } 26 | } -------------------------------------------------------------------------------- /src/title/title.h: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | void title_draw(GContext* ctx, int *score); -------------------------------------------------------------------------------- /src/tube/tube.c: -------------------------------------------------------------------------------- 1 | #include "tube.h" 2 | 3 | void tube_draw(tube_t *tube, GContext *ctx) { 4 | graphics_context_set_fill_color(ctx, GColorBlack); 5 | graphics_fill_rect(ctx, (GRect) {.origin = {tube->x, 158 - tube->y}, .size = {25, tube->y}}, 0, GCornerNone); 6 | graphics_fill_rect(ctx, (GRect) {.origin = {tube->x - 2, 158 - tube->y - 10}, .size = {29, 10}}, 0, GCornerNone); 7 | 8 | graphics_fill_rect(ctx, (GRect) {.origin = {tube->x, 0}, .size = {25, 158 - tube->y - 20 - 55}}, 0, GCornerNone); 9 | graphics_fill_rect(ctx, (GRect) {.origin = {tube->x - 2, 158 - tube->y - 20 - 55}, .size = {29, 10}}, 0, GCornerNone); 10 | 11 | // 12 | // graphics_fill_rect(ctx, (GRect) {.origin = {tube_x2, 158 - tube_y2}, .size = {25, tube_y2}}, 0, GCornerNone); 13 | // graphics_fill_rect(ctx, (GRect) {.origin = {tube_x2 - 2, 158 - tube_y2 - 10}, .size = {29, 10}}, 0, GCornerNone); 14 | // 15 | // graphics_fill_rect(ctx, (GRect) {.origin = {tube_x2, 0}, .size = {25, 158 - tube_y2 - 20 - 55}}, 0, GCornerNone); 16 | // graphics_fill_rect(ctx, (GRect) {.origin = {tube_x2 - 2, 158 - tube_y2 - 20 - 55}, .size = {29, 10}}, 0, GCornerNone); 17 | } 18 | 19 | // TODO: This delta_x won't work for different delta_t 20 | void tube_update_state(tube_t *tube, int delta_t) { 21 | int delta_x = delta_t * 2 / 3; 22 | tube->x -= delta_x; 23 | } 24 | 25 | tube_t *tube_create(int x, int y) { 26 | tube_t *new_tube = malloc(sizeof(tube_t)); 27 | new_tube->x = x; 28 | new_tube->y = y; 29 | 30 | return new_tube; 31 | } 32 | 33 | void tube_delete(tube_t *tube) { 34 | free(tube); 35 | } 36 | 37 | -------------------------------------------------------------------------------- /src/tube/tube.h: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | typedef struct { 4 | int x; 5 | int y; 6 | } tube_t; 7 | 8 | void tube_draw(tube_t *tube, GContext *ctx); 9 | void tube_update_state(tube_t *tube, int delta_t); 10 | tube_t *tube_create(int x, int y); 11 | void tube_delete(tube_t *tube); -------------------------------------------------------------------------------- /wscript: -------------------------------------------------------------------------------- 1 | 2 | # 3 | # This file is the default set of rules to compile a Pebble project. 4 | # 5 | # Feel free to customize this to your needs. 6 | # 7 | 8 | import os.path 9 | 10 | top = '.' 11 | out = 'build' 12 | 13 | def options(ctx): 14 | ctx.load('pebble_sdk') 15 | 16 | def configure(ctx): 17 | ctx.load('pebble_sdk') 18 | 19 | def build(ctx): 20 | ctx.load('pebble_sdk') 21 | 22 | ctx.pbl_program(source=ctx.path.ant_glob('src/**/*.c'), 23 | target='pebble-app.elf') 24 | 25 | if os.path.exists('worker_src'): 26 | ctx.pbl_worker(source=ctx.path.ant_glob('worker_src/**/*.c'), 27 | target='pebble-worker.elf') 28 | ctx.pbl_bundle(elf='pebble-app.elf', 29 | worker_elf='pebble-worker.elf', 30 | js=ctx.path.ant_glob('src/js/**/*.js')) 31 | else: 32 | ctx.pbl_bundle(elf='pebble-app.elf', 33 | js=ctx.path.ant_glob('src/js/**/*.js')) 34 | --------------------------------------------------------------------------------