From c1dc49a9dc1595b3b099c32c91e76dab28fafe98 Mon Sep 17 00:00:00 2001 From: Antonio Carzaniga Date: Wed, 28 Dec 2022 18:50:12 +0100 Subject: [PATCH] GUI controls for restitution coefficient and gravity field --- balls.cc | 27 ++++------- balls.h | 1 - gravity.cc | 66 +++++++++++++++------------ gravity.h | 3 +- main.cc | 132 +++++++++++++++++++++++++++++++++++++++-------------- 5 files changed, 144 insertions(+), 85 deletions(-) diff --git a/balls.cc b/balls.cc index 5f107ee..565d33b 100644 --- a/balls.cc +++ b/balls.cc @@ -23,8 +23,6 @@ unsigned int n_balls = 50; // C_r == 0.0 ==> perfectly inelastic collisions // static double C_r = 1.0; -static int c_r_display_countdown = 0; -static int c_r_display_init = 300; void restitution_coefficient_set (double c) { C_r = c; @@ -44,27 +42,18 @@ void restitution_coefficient_change (double d) { C_r = 1.0; else if (C_r < 0.0) C_r = 0.0; - restitution_coefficient_show (); } -void restitution_coefficient_show () { - c_r_display_countdown = c_r_display_init; -}; - void restitution_coefficient_draw (cairo_t * cr) { static const double margin = 20; - if (c_r_display_countdown != 0) { - cairo_save(cr); - cairo_new_path(cr); - cairo_move_to(cr, margin, margin); - cairo_line_to(cr, margin + (width - 2*margin)*C_r, margin); - cairo_set_source_rgb(cr, 1.0, 1.0, 0.0); - cairo_set_line_width(cr, margin/2); - cairo_stroke(cr); - if (c_r_display_countdown > 0) - --c_r_display_countdown; - cairo_restore(cr); - } + cairo_save(cr); + cairo_new_path(cr); + cairo_move_to(cr, margin, margin); + cairo_line_to(cr, margin + (width - 2*margin)*C_r, margin); + cairo_set_source_rgb(cr, 1.0, 1.0, 0.0); + cairo_set_line_width(cr, margin/2); + cairo_stroke(cr); + cairo_restore(cr); } static vec2d random_velocity() { diff --git a/balls.h b/balls.h index d98a7c8..0abd824 100644 --- a/balls.h +++ b/balls.h @@ -43,7 +43,6 @@ extern void ball_ball_collision (ball * p, ball * q); extern void ball_reposition (ball * b); extern void balls_draw (cairo_t * cr); -extern void restitution_coefficient_show (); extern void restitution_coefficient_draw (cairo_t * cr); extern void restitution_coefficient_set (double c); extern double restitution_coefficient_get (); diff --git a/gravity.cc b/gravity.cc index aeada86..259a6c6 100644 --- a/gravity.cc +++ b/gravity.cc @@ -1,19 +1,20 @@ -#include +#include +#include +#include #include #include "gravity.h" #include "game.h" -static vec2d g{.x = 0, .y = 20}; +static const double constant_field_increment = 1.0; +static const double newton_field_increment = 1000.0; +static vec2d g{.x = 0, .y = 20}; static double g_r = 50; static double g_g = 10000000; static int constant_field = 1; -static int gravity_vector_countdown = 0; -static int gravity_vector_init = 300; - void gravity_constant_field (double x, double y) { constant_field = 1; g.x = x; @@ -28,23 +29,36 @@ void gravity_newton_field (double r, double g) { void gravity_draw (cairo_t * cr) { if (constant_field) { - if (gravity_vector_countdown != 0) { - cairo_save(cr); - cairo_new_path(cr); - cairo_move_to(cr, width/2, height/2); - cairo_line_to(cr, width/2 + g.x, height/2 + g.y); - cairo_set_source_rgb(cr, 1.0, 1.0, 1.0); - cairo_set_line_width(cr, 1.0); - cairo_stroke(cr); - cairo_arc(cr, width/2 + g.x, height/2 + g.y, 3, 0, 2*M_PI); - cairo_fill(cr); - if (gravity_vector_countdown > 0) - --gravity_vector_countdown; - cairo_restore(cr); - } - } else { + cairo_save(cr); + cairo_new_path(cr); + cairo_move_to(cr, width/2, height/2); + cairo_line_to(cr, width/2 + g.x, height/2 + g.y); cairo_set_source_rgb(cr, 1.0, 1.0, 1.0); + cairo_set_line_width(cr, 1.0); + cairo_stroke(cr); + cairo_arc(cr, width/2 + g.x, height/2 + g.y, 3, 0, 2*M_PI); + cairo_fill(cr); + cairo_restore(cr); + } else { + std::ostringstream output; + output << (g_g/1000) << "K"; cairo_save (cr); + cairo_set_source_rgb (cr, 1.0, 1.0, 1.0); + cairo_select_font_face (cr, "sans-serif", CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_NORMAL); + cairo_set_font_size (cr, 16); + std::string output_str = output.str(); + cairo_text_extents_t extent; + cairo_text_extents (cr, output_str.c_str(), &extent); + cairo_move_to (cr, width/2 - extent.width/2, height/2 + extent.height/2); + cairo_show_text (cr, output_str.c_str()); + cairo_restore (cr); + } +} + +void gravity_draw_visible_field (cairo_t * cr) { + if (!constant_field) { + cairo_save (cr); + cairo_set_source_rgb(cr, 1.0, 1.0, 1.0); cairo_new_path (cr); cairo_arc (cr, width/2, height/2, g_r, 0, 2*M_PI); cairo_set_line_width(cr, 3.0); @@ -53,19 +67,13 @@ void gravity_draw (cairo_t * cr) { } } -void gravity_show () { - if (constant_field) - gravity_vector_countdown = gravity_vector_init; -}; - void gravity_change (double dx, double dy) { if (constant_field) { - g.x += dx; - g.y += dy; - gravity_show (); + g.x += dx*constant_field_increment; + g.y += dy*constant_field_increment; } else { g_r += dx; - g_g += dy; + g_g -= dy*newton_field_increment; } } diff --git a/gravity.h b/gravity.h index 226e536..9fcd110 100644 --- a/gravity.h +++ b/gravity.h @@ -8,9 +8,10 @@ extern void gravity_newton_field (double r, double g); extern vec2d gravity_vector (const ball * b); +extern void gravity_draw_visible_field (cairo_t * cr); + extern void gravity_draw (cairo_t * cr); extern void gravity_change (double dx, double dy); -extern void gravity_show (); extern void gravity_collisions (ball * begin, ball * end); diff --git a/main.cc b/main.cc index eb47274..57db190 100644 --- a/main.cc +++ b/main.cc @@ -62,27 +62,101 @@ void game_destroy () { balls_destroy (); } -static guint timeout_source_id = 0; -gboolean timeout (gpointer user_data); +static guint animation_timeout_id = 0; +gboolean animation_timeout (gpointer user_data); static bool game_paused () { - return timeout_source_id == 0; + return animation_timeout_id == 0; } void game_animation_on_off () { - if (timeout_source_id == 0) { - timeout_source_id = g_timeout_add (delta * 1000, timeout, canvas); + if (animation_timeout_id == 0) { + animation_timeout_id = g_timeout_add (delta * 1000, animation_timeout, canvas); } else { - g_source_remove (timeout_source_id); - timeout_source_id = 0; + g_source_remove (animation_timeout_id); + animation_timeout_id = 0; } } +struct param_controls { + void (*draw) (cairo_t * cr); + gint (*keyboard_input) (GdkEventKey *event); + gboolean (*mouse_scroll) (GtkWidget *widget, GdkEvent *event, gpointer user_data); +}; + +gint gravity_controls_keyboard_input (GdkEventKey *event) { + switch(event->keyval) { + case GDK_KEY_Up: + gravity_change (0, -10); + return TRUE; + case GDK_KEY_Down: + gravity_change (0, 10); + return TRUE; + case GDK_KEY_Left: + gravity_change (-10, 0); + return TRUE; + case GDK_KEY_Right: + gravity_change (10, 0); + return TRUE; + } + return FALSE; +} + +param_controls gravity_control = { + .draw = gravity_draw, + .keyboard_input = gravity_controls_keyboard_input, +}; + +gint restitution_coefficient_controls_keyboard_input (GdkEventKey *event) { + switch(event->keyval) { + case GDK_KEY_Up: + restitution_coefficient_change (0.01); + return TRUE; + case GDK_KEY_Down: + restitution_coefficient_change (-0.01); + return TRUE; + case GDK_KEY_Left: + restitution_coefficient_change (-0.01); + return TRUE; + case GDK_KEY_Right: + restitution_coefficient_change (0.01); + return TRUE; + } + return FALSE; +} + +param_controls restitution_coefficient_control = { + .draw = restitution_coefficient_draw, + .keyboard_input = restitution_coefficient_controls_keyboard_input, +}; + + + +static param_controls * param_control = nullptr; +static guint param_control_timeout_id = 0; +static const guint param_control_active_ms = 3000; + +gboolean param_control_timeout (gpointer user_data) { + param_control = nullptr; + param_control_timeout_id = 0; + gtk_widget_queue_draw(canvas); + return FALSE; +} + +void param_control_activate (struct param_controls * ctrl) { + if (param_control) + g_source_remove (param_control_timeout_id); + param_control = ctrl; + param_control_timeout_id = g_timeout_add (param_control_active_ms, param_control_timeout, canvas); + gtk_widget_queue_draw(canvas); +} + gboolean draw_frame (GtkWidget * widget, cairo_t *cr, gpointer data) { cairo_set_source_rgba(cr, 0.0, 0.0, 0.0, 1.0); cairo_paint(cr); - gravity_draw (cr); - restitution_coefficient_draw (cr); + if (param_control) + param_control->draw (cr); + gravity_draw_visible_field (cr); balls_draw (cr); spaceship_draw (cr); return FALSE; @@ -104,33 +178,21 @@ gint configure_event (GtkWidget *widget, GdkEventConfigure * event) { gint keyboard_input (GtkWidget *widget, GdkEventKey *event) { if (event->type != GDK_KEY_PRESS) return FALSE; - if (! game_paused ()) { - switch(event->keyval) { - case GDK_KEY_Up: - gravity_change (0, -10); - return TRUE; - case GDK_KEY_Down: - gravity_change (0, 10); - return TRUE; - case GDK_KEY_Left: - gravity_change (-10, 0); - return TRUE; - case GDK_KEY_Right: - gravity_change (10, 0); - return TRUE; - case GDK_KEY_R: - restitution_coefficient_change (0.01); - return TRUE; - case GDK_KEY_r: - restitution_coefficient_change (-0.01); - return TRUE; - case GDK_KEY_G: - case GDK_KEY_g: - gravity_show (); - return TRUE; - } + if (param_control && param_control->keyboard_input (event)) { + gtk_widget_queue_draw(canvas); + g_source_remove (param_control_timeout_id); + param_control_timeout_id = g_timeout_add (param_control_active_ms, param_control_timeout, canvas); + return TRUE; } switch(event->keyval) { + case GDK_KEY_R: + case GDK_KEY_r: + param_control_activate (&restitution_coefficient_control); + return TRUE; + case GDK_KEY_G: + case GDK_KEY_g: + param_control_activate (&gravity_control); + return TRUE; case GDK_KEY_P: case GDK_KEY_p: game_animation_on_off (); @@ -201,7 +263,7 @@ gboolean draw_event (GtkWidget *widget, cairo_t * cr, gpointer data) { return FALSE; } -gboolean timeout (gpointer user_data) { +gboolean animation_timeout (gpointer user_data) { if (stats_sampling > 0) { guint64 start = g_get_monotonic_time (); update_state();