GUI controls for restitution coefficient and gravity field

This commit is contained in:
Antonio Carzaniga 2022-12-28 18:50:12 +01:00
parent 19125826bd
commit c1dc49a9dc
5 changed files with 144 additions and 85 deletions

View File

@ -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,16 +42,10 @@ 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);
@ -61,11 +53,8 @@ void restitution_coefficient_draw (cairo_t * cr) {
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);
}
}
static vec2d random_velocity() {
double r2;

View File

@ -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 ();

View File

@ -1,19 +1,20 @@
#include <math.h>
#include <string>
#include <sstream>
#include <cmath>
#include <gtk/gtk.h>
#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,7 +29,6 @@ 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);
@ -38,13 +38,27 @@ void gravity_draw (cairo_t * cr) {
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 {
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);
}
} else {
cairo_set_source_rgb(cr, 1.0, 1.0, 1.0);
}
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;
}
}

View File

@ -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);

122
main.cc
View File

@ -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 ()) {
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_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);
param_control_activate (&restitution_coefficient_control);
return TRUE;
case GDK_KEY_G:
case GDK_KEY_g:
gravity_show ();
param_control_activate (&gravity_control);
return TRUE;
}
}
switch(event->keyval) {
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();