Vastly less error-prone animation lifecycle
This commit is contained in:
1 parent
9a836effda
commit
4b9d90efc8
1 file changed
+66
-43
+66
-43
@@ -72,7 +72,7 @@ static uint8_t s_selected_indices[3] = {9, 9, 9};
|
|||||||
static uint8_t s_secs_since_last_input;
|
static uint8_t s_secs_since_last_input;
|
||||||
static uint8_t s_shake_cooldown;
|
static uint8_t s_shake_cooldown;
|
||||||
static uint8_t s_zap_cooldown;
|
static uint8_t s_zap_cooldown;
|
||||||
static uint8_t s_countdown_int = 0;
|
static uint8_t s_countdown_int;
|
||||||
static bool s_continuous_zap_on_first_triangle;
|
static bool s_continuous_zap_on_first_triangle;
|
||||||
static char s_countdown_buf[4];
|
static char s_countdown_buf[4];
|
||||||
static char s_progress_buf[8];
|
static char s_progress_buf[8];
|
||||||
@@ -107,8 +107,11 @@ static const VibePattern s_first_triangle_vibe_pattern = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// animation stuff
|
// animation stuff
|
||||||
|
#define ANIMATION_DURATION 350
|
||||||
static GRect s_left_door_starting_grect = GRect(-(PBL_DISPLAY_WIDTH / 2), s_small_top_bar_height, PBL_DISPLAY_WIDTH / 2, PBL_DISPLAY_HEIGHT - s_small_top_bar_height - s_bottom_bar_grect.size.h);
|
static GRect s_left_door_starting_grect = GRect(-(PBL_DISPLAY_WIDTH / 2), s_small_top_bar_height, PBL_DISPLAY_WIDTH / 2, PBL_DISPLAY_HEIGHT - s_small_top_bar_height - s_bottom_bar_grect.size.h);
|
||||||
static GRect s_right_door_starting_grect = GRect(PBL_DISPLAY_WIDTH, s_small_top_bar_height, PBL_DISPLAY_WIDTH / 2, PBL_DISPLAY_HEIGHT - s_small_top_bar_height - s_bottom_bar_grect.size.h);
|
static GRect s_right_door_starting_grect = GRect(PBL_DISPLAY_WIDTH, s_small_top_bar_height, PBL_DISPLAY_WIDTH / 2, PBL_DISPLAY_HEIGHT - s_small_top_bar_height - s_bottom_bar_grect.size.h);
|
||||||
|
static bool s_door_correct;
|
||||||
|
static Animation *s_door_anim;
|
||||||
|
|
||||||
// alarm drop menu options
|
// alarm drop menu options
|
||||||
static const char *s_options_function[3];
|
static const char *s_options_function[3];
|
||||||
@@ -515,54 +518,69 @@ static void door_layer_green_update_proc(Layer *layer, GContext *ctx) {
|
|||||||
graphics_fill_rect(ctx, layer_get_bounds(layer), 0, GCornerNone);
|
graphics_fill_rect(ctx, layer_get_bounds(layer), 0, GCornerNone);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void door_closed_fail_animation_handler(Animation *animation, bool finished, void *context) {
|
static void door_closed_animation_stopped_handler(Animation *a, bool finished, void *ctx) {
|
||||||
if (s_current_triangle_num > 1) {
|
if (!finished)
|
||||||
|
return;
|
||||||
|
if (s_door_correct)
|
||||||
|
s_current_triangle_num++;
|
||||||
|
else if (s_current_triangle_num > 1)
|
||||||
s_current_triangle_num--;
|
s_current_triangle_num--;
|
||||||
}
|
|
||||||
right_triangle_layer_regen(s_triangle_layer);
|
right_triangle_layer_regen(s_triangle_layer);
|
||||||
update_for_new_triangle();
|
update_for_new_triangle();
|
||||||
}
|
}
|
||||||
|
|
||||||
static void door_closed_success_animation_handler(Animation *animation, bool finished, void *context) {
|
static void door_animation_stopped_handler(Animation *a, bool finished, void *ctx) {
|
||||||
s_current_triangle_num++;
|
animation_destroy(a);
|
||||||
right_triangle_layer_regen(s_triangle_layer);
|
s_door_anim = NULL;
|
||||||
update_for_new_triangle();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void destroy_animation_handler(Animation *animation, bool finished, void *context) {
|
|
||||||
animation_destroy(animation);
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO:
|
|
||||||
// reuse some of these animations, if possible
|
|
||||||
// add iconography to door halves
|
|
||||||
static void play_door_animation(bool correct) {
|
static void play_door_animation(bool correct) {
|
||||||
PropertyAnimation *left_door_prop_anim = property_animation_create_layer_frame(s_left_door_layer, &s_left_door_starting_grect, &GRect(0, s_left_door_starting_grect.origin.y, s_left_door_starting_grect.size.w, s_left_door_starting_grect.size.h));
|
// prevent from playing if an instance is already running and not yet finished;
|
||||||
PropertyAnimation *right_door_prop_anim = property_animation_create_layer_frame(s_right_door_layer, &s_right_door_starting_grect, &GRect(PBL_DISPLAY_WIDTH / 2, s_left_door_starting_grect.origin.y, s_left_door_starting_grect.size.w, s_left_door_starting_grect.size.h));
|
// prevents instances where the user is punished if the timer expires AFTER the submission
|
||||||
Animation *left_door_close_anim = property_animation_get_animation(left_door_prop_anim);
|
if (s_door_anim) {
|
||||||
Animation *right_door_close_anim = property_animation_get_animation(right_door_prop_anim);
|
return;
|
||||||
animation_set_duration(left_door_close_anim, 500);
|
|
||||||
animation_set_duration(right_door_close_anim, 500);
|
|
||||||
Animation *left_door_open_anim = animation_clone(left_door_close_anim);
|
|
||||||
Animation *right_door_open_anim = animation_clone(right_door_close_anim);
|
|
||||||
animation_set_reverse(left_door_open_anim, true);
|
|
||||||
animation_set_reverse(right_door_open_anim, true);
|
|
||||||
Animation *door_close_spawn_anim = animation_spawn_create(left_door_close_anim, right_door_close_anim, NULL);
|
|
||||||
Animation *door_open_spawn_anim = animation_spawn_create(left_door_open_anim, right_door_open_anim, NULL);
|
|
||||||
animation_set_delay(door_open_spawn_anim, 100);
|
|
||||||
if (correct) {
|
|
||||||
layer_set_update_proc(s_left_door_layer, door_layer_green_update_proc);
|
|
||||||
layer_set_update_proc(s_right_door_layer, door_layer_green_update_proc);
|
|
||||||
animation_set_handlers(door_close_spawn_anim, (AnimationHandlers){.stopped = door_closed_success_animation_handler}, NULL);
|
|
||||||
} else {
|
|
||||||
layer_set_update_proc(s_left_door_layer, door_layer_red_update_proc);
|
|
||||||
layer_set_update_proc(s_right_door_layer, door_layer_red_update_proc);
|
|
||||||
animation_set_handlers(door_close_spawn_anim, (AnimationHandlers){.stopped = door_closed_fail_animation_handler}, NULL);
|
|
||||||
}
|
}
|
||||||
Animation *seq = animation_sequence_create(door_close_spawn_anim, door_open_spawn_anim, NULL);
|
|
||||||
animation_set_handlers(seq, (AnimationHandlers){.stopped = destroy_animation_handler}, NULL);
|
// reset shake cooldown here so it is guaranteed
|
||||||
animation_schedule(seq);
|
// to be in effect while an animation is playing
|
||||||
};
|
s_shake_cooldown = SHAKE_COOLDOWN_SECS;
|
||||||
|
|
||||||
|
// ensure door layers are correct color
|
||||||
|
s_door_correct = correct;
|
||||||
|
layer_set_update_proc(s_left_door_layer, correct ? door_layer_green_update_proc : door_layer_red_update_proc);
|
||||||
|
layer_set_update_proc(s_right_door_layer, correct ? door_layer_green_update_proc : door_layer_red_update_proc);
|
||||||
|
|
||||||
|
// create base close animations
|
||||||
|
PropertyAnimation *l = property_animation_create_layer_frame(s_left_door_layer, &s_left_door_starting_grect, &GRect(0, s_left_door_starting_grect.origin.y, s_left_door_starting_grect.size.w, s_left_door_starting_grect.size.h));
|
||||||
|
PropertyAnimation *r = property_animation_create_layer_frame(s_right_door_layer, &s_right_door_starting_grect, &GRect(PBL_DISPLAY_WIDTH / 2, s_left_door_starting_grect.origin.y, s_left_door_starting_grect.size.w, s_left_door_starting_grect.size.h));
|
||||||
|
Animation *lc = property_animation_get_animation(l), *rc = property_animation_get_animation(r);
|
||||||
|
animation_set_duration(lc, ANIMATION_DURATION);
|
||||||
|
animation_set_duration(rc, ANIMATION_DURATION);
|
||||||
|
|
||||||
|
// duplicate and reverse for open animations
|
||||||
|
Animation *lo = animation_clone(lc), *ro = animation_clone(rc);
|
||||||
|
animation_set_reverse(lo, true);
|
||||||
|
animation_set_reverse(ro, true);
|
||||||
|
|
||||||
|
// create spawn animations
|
||||||
|
Animation *close = animation_spawn_create(lc, rc, NULL);
|
||||||
|
Animation *open = animation_spawn_create(lo, ro, NULL);
|
||||||
|
animation_set_delay(open, 100);
|
||||||
|
|
||||||
|
// set door close handler
|
||||||
|
animation_set_handlers(close, (AnimationHandlers){.stopped = door_closed_animation_stopped_handler}, NULL);
|
||||||
|
|
||||||
|
// create sequence
|
||||||
|
s_door_anim = animation_sequence_create(close, open, NULL);
|
||||||
|
|
||||||
|
// set stopped handler;
|
||||||
|
// even though the SDK auto-destroys after finished, we destroy manually
|
||||||
|
// since we already need a stopped handler to NULL it for the check in alarm_window_unload()
|
||||||
|
animation_set_handlers(s_door_anim, (AnimationHandlers){.stopped = door_animation_stopped_handler}, NULL);
|
||||||
|
|
||||||
|
// play animation sequence;
|
||||||
|
animation_schedule(s_door_anim);
|
||||||
|
}
|
||||||
|
|
||||||
static void increment_secs_since_last_input() {
|
static void increment_secs_since_last_input() {
|
||||||
if (s_secs_since_last_input < MAX_SECS_WITHOUT_INPUT) {
|
if (s_secs_since_last_input < MAX_SECS_WITHOUT_INPUT) {
|
||||||
@@ -674,7 +692,8 @@ static void accel_tap_handler(AccelAxisType axis, int32_t direction) {
|
|||||||
|
|
||||||
if (s_countdown_int > 0) {
|
if (s_countdown_int > 0) {
|
||||||
if (s_current_triangle_num == settings.TriangleCount) {
|
if (s_current_triangle_num == settings.TriangleCount) {
|
||||||
tick_timer_service_unsubscribe(); // alarm is fully disarmed - prevent stimulus in confirmation window
|
tick_timer_service_unsubscribe(); // prevent stimulus in confirmation window
|
||||||
|
accel_tap_service_unsubscribe(); // don't listen for shakes in confirmation window
|
||||||
wakeup_service_subscribe(NULL); // ignore wakeup events to avoid overwriting new alarm
|
wakeup_service_subscribe(NULL); // ignore wakeup events to avoid overwriting new alarm
|
||||||
if (schedule_alarm(WAKE_ALARM)) {
|
if (schedule_alarm(WAKE_ALARM)) {
|
||||||
push_status_window(STATUS_CONFIRMATION);
|
push_status_window(STATUS_CONFIRMATION);
|
||||||
@@ -683,8 +702,6 @@ static void accel_tap_handler(AccelAxisType axis, int32_t direction) {
|
|||||||
play_door_animation(true);
|
play_door_animation(true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
s_shake_cooldown = SHAKE_COOLDOWN_SECS;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void alarm_click_config_provider(void *ctx) {
|
static void alarm_click_config_provider(void *ctx) {
|
||||||
@@ -913,6 +930,12 @@ static void alarm_window_load() {
|
|||||||
static void alarm_window_unload() {
|
static void alarm_window_unload() {
|
||||||
tick_timer_service_unsubscribe();
|
tick_timer_service_unsubscribe();
|
||||||
accel_tap_service_unsubscribe();
|
accel_tap_service_unsubscribe();
|
||||||
|
if (s_door_anim) {
|
||||||
|
// unschedule and destroy if unload occurs while an animation is running;
|
||||||
|
// e.g. if the alarm reset button is used from the phone-side
|
||||||
|
animation_destroy(s_door_anim);
|
||||||
|
s_door_anim = NULL;
|
||||||
|
}
|
||||||
layer_destroy(s_right_door_layer);
|
layer_destroy(s_right_door_layer);
|
||||||
layer_destroy(s_left_door_layer);
|
layer_destroy(s_left_door_layer);
|
||||||
text_layer_destroy(s_progress_txt_layer);
|
text_layer_destroy(s_progress_txt_layer);
|
||||||
|
|||||||
Reference in new issue
Block a user