GTK+ Forums Forum Index GTK+ Forums
Discussion forum for GTK+ and Programming. Ask questions, troubleshoot problems, view and post example code, or express your opinions.
 
 FAQFAQ   SearchSearch   MemberlistMemberlist   UsergroupsUsergroups   RegisterRegister 
 ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

Need help in developing a simple game - Whack a Mole, GTK

 
Post new topic   Reply to topic    GTK+ Forums Forum Index -> GTK+ Programming
Author Message
jimmyfam
Familiar Face


Joined: 17 Feb 2010
Posts: 17

PostPosted: Wed Feb 17, 2010 2:02 pm    Post subject: Need help in developing a simple game - Whack a Mole, GTK Reply with quote

Hi avid programmers,

I need help in developing a simple game for my school project.

Im stuck in implementing a timer function to this game.
Can anyone help me? Greatly appreciated!! :)

Below is my code:
--------------------------------------------------------------------------------------------------------
Code: (C)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
//Program written by: Jimmy Fam
//           Updated: 24.01.2010
//             Title: Whack a Mole! game

#include <gtk/gtk.h>
#include <stdlib.h>
#include <time.h>
#include <stdio.h>


void increase(GtkWidget *widget, gpointer label)
{
  count++;

  sprintf(buf, "%d", count);
  gtk_label_set_text(label, buf);
}

void decrease(GtkWidget *widget, gpointer label)
{
  count--;

  sprintf(buf, "%d", count);
  gtk_label_set_text(label, buf);
}


void molehit (GtkWidget *widget, gpointer label)
{
  sprintf(buf, "Mole hit!! ");
  gtk_label_set_text(label, buf);
}

void update (GtkWidget *widget, gpointer label3)
{

  //Random number button generator. Number range (0-9)
 
int finalNum = 1;
  finalNum = rand() % (10);
   
  sprintf(buf, "%d", finalNum);
  gtk_label_set_text(label3, buf);
 
}

void wait ( int seconds )
{
  clock_t endwait;
  endwait = clock () + seconds * CLOCKS_PER_SEC ;
  while (clock() < endwait) {}
}



int main(int argc, char** argv) {

  GtkWidget *label;
  GtkWidget *window;
  GtkWidget *frame;
  GtkWidget *plus;
  GtkWidget *minus;

  GtkWidget *button1;
  GtkWidget *button2;
  GtkWidget *button3;
  GtkWidget *button4;
  GtkWidget *button5;
  GtkWidget *button6;
  GtkWidget *button7;
  GtkWidget *button8;
  GtkWidget *button9;


  GtkWidget *label2;
  GtkWidget *label3;

  GdkColor   colorRed;
  GdkColor   colorBlue;
  GdkColor   colorYellow;
  GdkColor   colorOrange;
  GdkColor   colorGreen;

  gdk_color_parse ("yellow", &colorYellow);
  gdk_color_parse ("red", &colorRed);
  gdk_color_parse ("blue", &colorBlue);
  gdk_color_parse ("orange", &colorOrange);
  gdk_color_parse ("green", &colorGreen);
 
  gtk_init(&argc, &argv);

  window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
  gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER);
  gtk_window_set_default_size(GTK_WINDOW(window), 500, 300);
  gtk_window_set_title(GTK_WINDOW(window), "Whack a Mole");

  frame = gtk_fixed_new();
  gtk_container_add(GTK_CONTAINER(window), frame);


  plus = gtk_button_new_with_label("+");
  gtk_widget_set_size_request(plus, 80, 35);
  gtk_fixed_put(GTK_FIXED(frame), plus, 110, 20);

  minus = gtk_button_new_with_label("-");
  gtk_widget_set_size_request(minus, 80, 35);
  gtk_fixed_put(GTK_FIXED(frame), minus, 110, 80);
 
  button1 = gtk_button_new_with_label("Mole1");
  gtk_widget_set_size_request(button1, 80, 35);
  gtk_fixed_put(GTK_FIXED(frame), button1, 110, 140);

  button2 = gtk_button_new_with_label("Rand");
  gtk_widget_set_size_request(button2, 80, 35);
  gtk_fixed_put(GTK_FIXED(frame), button2, 10, 20);

  button3 = gtk_button_new_with_label("Mole3");
  gtk_widget_set_size_request(button3, 80, 35);
  gtk_fixed_put(GTK_FIXED(frame), button3, 10, 80);

  button4 = gtk_button_new_with_label("Mole4");
  gtk_widget_set_size_request(button4, 80, 35);
  gtk_fixed_put(GTK_FIXED(frame), button4, 10, 140);
 
  button5 = gtk_button_new_with_label("Mole5");
  gtk_widget_set_size_request(button5, 80, 35);
  gtk_fixed_put(GTK_FIXED(frame), button5, 210, 20);
 
  button6 = gtk_button_new_with_label("Mole6");
  gtk_widget_set_size_request(button6, 80, 35);
  gtk_fixed_put(GTK_FIXED(frame), button6, 210, 80);


  button7 = gtk_button_new_with_label("Mole7");
  gtk_widget_set_size_request(button7, 80, 35);
  gtk_fixed_put(GTK_FIXED(frame), button7, 210, 140);

         
  label = gtk_label_new("0");
  gtk_fixed_put(GTK_FIXED(frame), label, 380, 58);

  label2 = gtk_label_new("Score");
  gtk_fixed_put(GTK_FIXED(frame), label2, 380, 28);

  label3 = gtk_label_new("0");
  gtk_fixed_put(GTK_FIXED(frame), label3, 380, 88);

  gtk_widget_show_all(window);
 
 

  //C++ game logic starts here..

  // 1) 'Main game timer' begins...
   
 

  // 2) Random number button generator;number range (0-9)...
 
int finalNum = 1;
  finalNum = rand() % (10);
 
  //wait(10);

  // 3) Change random button colour to reflect "shown, hit(click) it!"....
 
if (finalNum = 1)
  { gtk_widget_modify_bg (button1, GTK_STATE_NORMAL, &colorRed); }
  if (finalNum = 2)
  { gtk_widget_modify_bg (button2, GTK_STATE_NORMAL, &colorYellow); }
  if (finalNum = 3)
  { gtk_widget_modify_bg (button3, GTK_STATE_NORMAL, &colorBlue); }
  if (finalNum = 4)
  { gtk_widget_modify_bg (button4, GTK_STATE_NORMAL, &colorGreen); }
  if (finalNum = 5)
  { gtk_widget_modify_bg (button5, GTK_STATE_NORMAL, &colorOrange); }
  if (finalNum = 6)
  { gtk_widget_modify_bg (button6, GTK_STATE_NORMAL, &colorYellow); }
  if (finalNum = 7)
  { gtk_widget_modify_bg (button7, GTK_STATE_NORMAL, &colorYellow); }
  if (finalNum = 8)
  { gtk_widget_modify_bg (button8, GTK_STATE_NORMAL, &colorYellow); }
  if (finalNum = 9)
  { gtk_widget_modify_bg (button9, GTK_STATE_NORMAL, &colorYellow); }

  //return 0;

// 4) 'Mole hit timer'(countdown timer) starts once colour of 1 button changes...
//     if mouse click within set time interval, add one point

    /* clock: countdown code */
       

// 5) ELSE  exceed 'mole hit timer' before mouse click, minus one point,

  /* Minus point for missed hit*/
 
       // G_CALLBACK(decrease), label);

  // 6) Reset 'Mole hit timer'(countdown timer)and repeats again until 'Main game counter' finished and display final result "Game Over!".



 
g_signal_connect(window, "destroy",
   G_CALLBACK (gtk_main_quit), NULL);

  g_signal_connect(plus, "clicked",
      G_CALLBACK(increase), label);

  g_signal_connect(minus, "clicked",
      G_CALLBACK(decrease), label);

  g_signal_connect(button1, "clicked",
      G_CALLBACK(molehit), label);

  g_signal_connect(button2, "clicked",
      G_CALLBACK(update),label3);
 
  g_signal_connect(button3, "clicked",
      G_CALLBACK(molehit), label);
 
  g_signal_connect(button4, "clicked",
      G_CALLBACK(molehit), label);

  g_signal_connect(button5, "clicked",
      G_CALLBACK(molehit), label);
 
  g_signal_connect(button6, "clicked",
      G_CALLBACK(molehit), label);

  g_signal_connect(button7, "clicked",
      G_CALLBACK(molehit), label);


  gtk_main();

  return 0;
}
Added CodeBB -dreblen
Back to top
tadeboro
Never Seen the Sunlight


Joined: 23 Jul 2008
Posts: 2114
Location: Slovenia

PostPosted: Thu Feb 18, 2010 5:03 pm    Post subject: Reply with quote

Hello and welcome to the GTK+ forums.

You're having troubles because you use "busy wait loop". Control needs to return to GTK+'s main loop in order for GUI controls to work properly.

If your timing requests are not very strict (couple of ms variance is allowed), you can use g_timeout_add() function to show your "mole". In case of strict timing, you'll probably need to spawn separate thread which will monitor clock and update GUI when appropriate.

Tadej
Back to top
jimmyfam
Familiar Face


Joined: 17 Feb 2010
Posts: 17

PostPosted: Sun Feb 21, 2010 12:29 am    Post subject: Reply with quote

Thks Tadej,

I revise my code to include a 10sec timer...

My flow is like this,

1) button turns yellow colour, timer start
2) click button before timer stops (10sec) add point, [count ++]
3) if did not click button and timer exceed 10 secs, button turn red.

Can you help me revise my code into this format?? Many thanks!!

Code below:
-----------------------------------------------------------------------------------
Code: (C)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
#include <gtk/gtk.h>
#include <glib.h>
#include <time.h>
#include <stdio.h>
#include <stdlib.h>


gint count = 0;
char buf[5];

gboolean callback (gpointer data) {
      int timeout = GPOINTER_TO_INT (data);
      printf ("callback called at: %lu\n", time (NULL));
      sleep (timeout);
      printf ("callback returns at: %lu\n", time (NULL));
      g_timeout_add_seconds (20, callback, GINT_TO_POINTER (timeout));
      return FALSE;
}

void increase(GtkWidget *widget, gpointer label)
{
  count++;

  sprintf(buf, "%d", count);
  gtk_label_set_text(label, buf);
}


int main (int argc, char **argv) {

  GtkWidget *label;
  GtkWidget *window;
  GtkWidget *frame;
  GtkWidget *plus;

  GdkColor   colorYellow;
  gdk_color_parse ("yellow", &colorYellow);

  //10 secs timer countdown
 
int timeout = 10;
  gtk_init(&argc, &argv);

  window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
  gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER);
  gtk_window_set_default_size(GTK_WINDOW(window), 500, 300);
  gtk_window_set_title(GTK_WINDOW(window), "Whack a Mole");

  frame = gtk_fixed_new();
  gtk_container_add(GTK_CONTAINER(window), frame);

  plus = gtk_button_new_with_label("+");
  gtk_widget_set_size_request(plus, 80, 35);
  gtk_fixed_put(GTK_FIXED(frame), plus, 110, 20);

  label = gtk_label_new("0");
  gtk_fixed_put(GTK_FIXED(frame), label, 380, 58);

  gtk_widget_show_all(window);



      //10 secs timer countdown
     
callback (GINT_TO_POINTER (timeout));
      gtk_widget_modify_bg (plus, GTK_STATE_NORMAL, &colorYellow);




  g_signal_connect(window, "destroy",
   G_CALLBACK (gtk_main_quit), NULL);

  g_signal_connect(plus, "clicked",
      G_CALLBACK(increase), label);


      gtk_main ();

  return 0;
}
Added CodeBB -dreblen
Back to top
tadeboro
Never Seen the Sunlight


Joined: 23 Jul 2008
Posts: 2114
Location: Slovenia

PostPosted: Mon Feb 22, 2010 11:58 am    Post subject: Reply with quote

Hello.

This game intrigued me enough to write a simple whack-a-mole game. But since I don't want to be the one who writes your school projects, I haven't commented my code. Feel free to reuse my code anyway you find suitable, but just make yourself a favor and dissect it until you understand what each part of the code does (apart from some GObject specifics, it's relatively simple code with only cca. 500 lines of code).

You can compile this code like this:
Code: (Plaintext)
1
2
3
gcc -Wall $(pkg-config --cflags gtk+-2.0) -c mymole.c -o mymole.o
gcc -Wall $(pkg-config --cflags gtk+-2.0) -c test_mole.c -o test_mole.o
gcc -Wall -o test_mole test_mole.o mymole.o $(pkg-config --libs gtk+-2.0)

mymole.h
Code: (C)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
#ifndef __MY_MOLE_H__
#define __MY_MOLE_H__

#include <gtk/gtk.h>

G_BEGIN_DECLS

#define MY_TYPE_MOLE \
    ( my_mole_get_type() )
#define MY_MOLE( obj ) \
    ( G_TYPE_CHECK_INSTANCE_CAST( ( obj ), MY_TYPE_MOLE, MyMole ) )
#define MY_MOLE_CLASS( klass ) \
    ( G_TYPE_CHECK_CLASS_CAST( ( klass ), MY_TYPE_MOLE, MyMoleClass ) )
#define MY_IS_MOLE( obj ) \
    ( G_TYPE_CHECK_INSTANCE_TYPE( ( obj ), MY_TYPE_MOLE ) )
#define MY_IS_MOLE_CLASS( klass ) \
    ( G_TYPE_CHECK_CLASS_TYPE( ( klass ), MY_TYPE_MOLE ) )
#define MY_MOLE_GET_CLASS( obj ) \
    ( G_TYPE_INSTANCE_GET_CLASS( ( obj ), MY_TYPE_MOLE, MyMoleClass ) )

typedef struct _MyMole        MyMole;
typedef struct _MyMoleClass   MyMoleClass;
typedef struct _MyMolePrivate MyMolePrivate;

struct _MyMole
{
    GtkDrawingArea parent;

    /*< Private >*/
   
MyMolePrivate *priv;
};

struct _MyMoleClass
{
    GtkDrawingAreaClass parent_class;

    /* Signals */
   
void (* whacked)( MyMole *mole );
    void (* missed) ( MyMole *mole );
};

GType      my_mole_get_type     ( void ) G_GNUC_CONST;
GtkWidget *my_mole_new          ( void );

guint      my_mole_get_timeout  ( MyMole   *mole );
void       my_mole_set_timeout  ( MyMole   *mole,
                                  guint     timeout );

gboolean   my_mole_get_busy     ( MyMole   *mole );

void       my_mole_activate     ( MyMole   *mole );

G_END_DECLS

#endif /* __MY_MOLE_H__ */

mymole.c
Code: (C)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
#include "mymole.h"

/* Time (in miliseconds) that state indicator stays shown */
#define STATE_TIMEOUT 1000

/* Signals */
enum
{
    WHACKED,
    MISSED,
    LAST_SIGNAL
};

/* Properties */
enum
{
    PROP_0,
    PROP_TIMEOUT,
    PROP_BUSY
};

/* States */
enum
{
    S_NORMAL,
    S_UP,
    S_WHACKED,
    S_MISSED
};

/* Private structure */
#define MY_MOLE_GET_PRIVATE( obj ) \
    ( G_TYPE_INSTANCE_GET_PRIVATE( ( obj ), MY_TYPE_MOLE, MyMolePrivate ) )

struct _MyMolePrivate
{
    gboolean busy;
    gint     timeout;
    gint     state;
    guint    source_id;
};

/* Overriden methods */
static void     my_mole_get_property( GObject        *object,
                                      guint           param_id,
                                      GValue         *value,
                                      GParamSpec     *pspec );
static void     my_mole_set_property( GObject        *object,
                                      guint           param_id,
                                      const GValue   *value,
                                      GParamSpec     *pspec );
static gboolean my_mole_button_press( GtkWidget      *widget,
                                      GdkEventButton *event );
static gboolean my_mole_expose      ( GtkWidget      *widget,
                                      GdkEventExpose *event );

/* Private functions */
static gboolean my_mole_timeout_cb  ( MyMole         *mole );
static gboolean my_mole_clean_state ( MyMole         *mole );


static guint mole_signals[LAST_SIGNAL] = { 0 };

G_DEFINE_TYPE( MyMole, my_mole, GTK_TYPE_DRAWING_AREA )

static void
my_mole_class_init( MyMoleClass *klass )
{
    GParamSpec     *pspec;
    GObjectClass   *gobject_class = G_OBJECT_CLASS( klass );
    GtkWidgetClass *widget_class  = GTK_WIDGET_CLASS( klass );

    gobject_class->get_property = my_mole_get_property;
    gobject_class->set_property = my_mole_set_property;

    widget_class->button_press_event = my_mole_button_press;
    widget_class->expose_event       = my_mole_expose;

    /* Properties */
   
pspec = g_param_spec_uint( "timeout",
                               "Timeout",
                               "Amount of time mole is visible",
                               100, G_MAXUINT, 2000,
                               G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS );
    g_object_class_install_property( gobject_class, PROP_TIMEOUT, pspec );

    pspec = g_param_spec_boolean( "busy",
                                  "Busy",
                                  "Is mole currently busy?",
                                  FALSE,
                                  G_PARAM_READABLE | G_PARAM_STATIC_STRINGS );
    g_object_class_install_property( gobject_class, PROP_BUSY, pspec );

    /* Signals */
   
mole_signals[WHACKED] =
           g_signal_new( "whacked",
                      G_OBJECT_CLASS_TYPE( klass ),
                      G_SIGNAL_RUN_FIRST,
                      G_STRUCT_OFFSET( MyMoleClass, whacked ),
                      NULL, NULL,
                      g_cclosure_marshal_VOID__VOID,
                      G_TYPE_NONE, 0 );

    mole_signals[MISSED] =
        g_signal_new( "missed",
                      G_OBJECT_CLASS_TYPE( klass ),
                      G_SIGNAL_RUN_FIRST,
                      G_STRUCT_OFFSET( MyMoleClass, missed ),
                      NULL, NULL,
                      g_cclosure_marshal_VOID__VOID,
                      G_TYPE_NONE, 0 );

    /* Private data */
   
g_type_class_add_private( gobject_class, sizeof( MyMolePrivate ) );
}

static void
my_mole_init( MyMole *mole )
{
    mole->priv = MY_MOLE_GET_PRIVATE( mole );

    /* Default values */
   
mole->priv->busy      = FALSE;
    mole->priv->timeout   = 2000;
    mole->priv->state     = S_NORMAL;
    mole->priv->source_id = 0;

    /* Add events */
   
gtk_widget_add_events( GTK_WIDGET( mole ), GDK_BUTTON_PRESS_MASK );
}

static void
my_mole_get_property( GObject    *object,
                      guint       prop_id,
                      GValue     *value,
                      GParamSpec *pspec )
{
    MyMolePrivate *priv = MY_MOLE( object )->priv;

    switch( prop_id )
    {
        case PROP_TIMEOUT:
           
g_value_set_uint( value, priv->timeout );
            break;

        case PROP_BUSY:
           
g_value_set_boolean( value, priv->busy ? TRUE : FALSE );
            break;

        default:
            G_OBJECT_WARN_INVALID_PROPERTY_ID( object, prop_id, pspec );
            break;
    }
}

static void
my_mole_set_property( GObject      *object,
                      guint         prop_id,
                      const GValue *value,
                      GParamSpec   *pspec )
{
    MyMolePrivate *priv = MY_MOLE( object )->priv;

    switch( prop_id )
    {
        case PROP_TIMEOUT:
           
priv->timeout = g_value_get_uint( value );
            break;

        default:
            G_OBJECT_WARN_INVALID_PROPERTY_ID( object, prop_id, pspec );
            break;
    }
}

static gboolean
my_mole_expose( GtkWidget      *widget,
                GdkEventExpose *event )
{
    gboolean  r_val = TRUE;
    cairo_t  *cr;

    cr = gdk_cairo_create( event->window );
    switch( MY_MOLE( widget )->priv->state )
    {
        case S_NORMAL:
           
r_val = FALSE;
            break;

        case S_UP:
           
cairo_set_source_rgb( cr, 0, 0, 1 );
            cairo_paint( cr );
            break;

        case S_WHACKED:
           
cairo_set_source_rgb( cr, 0, 1, 0 );
            cairo_paint( cr );
            break;

        case S_MISSED:
           
cairo_set_source_rgb( cr, 1, 0, 0 );
            cairo_paint( cr );
            break;
    }
    cairo_destroy( cr );

    return( r_val );
}

static gboolean
my_mole_button_press( GtkWidget      *widget,
                      GdkEventButton *event )
{
    MyMolePrivate *priv = MY_MOLE( widget )->priv;

    if( priv->state == S_UP )
    {
        g_source_remove( priv->source_id );
        g_signal_emit( widget, mole_signals[WHACKED], 0 );
        priv->state = S_WHACKED;
        gtk_widget_queue_draw( widget );
        gdk_threads_add_timeout( STATE_TIMEOUT,
                                 (GSourceFunc)my_mole_clean_state,
                                 MY_MOLE( widget ) );
    }

    return( TRUE );
}

/* Private functions */
static gboolean
my_mole_timeout_cb( MyMole *mole )
{
    MyMolePrivate *priv = mole->priv;

    priv->source_id = 0;
    priv->state     = S_MISSED;
    gtk_widget_queue_draw( GTK_WIDGET( mole ) );
    g_signal_emit( mole, mole_signals[MISSED], 0 );
    gdk_threads_add_timeout( STATE_TIMEOUT,
                             (GSourceFunc)my_mole_clean_state,
                             mole );

    return( FALSE );
}

static gboolean
my_mole_clean_state( MyMole *mole )
{
    MyMolePrivate *priv = mole->priv;

    priv->state = S_NORMAL;
    priv->busy  = FALSE;
    gtk_widget_queue_draw( GTK_WIDGET( mole ) );

    return( FALSE );
}

/* Public API */
GtkWidget *
my_mole_new( void )
{
    return( g_object_new( MY_TYPE_MOLE, NULL ) );
}

guint
my_mole_get_timeout( MyMole *mole )
{
    g_return_val_if_fail( MY_IS_MOLE( mole ), 0 );

    return( mole->priv->timeout );
}

void
my_mole_set_timeout( MyMole *mole,
                     guint   timeout )
{
    g_return_if_fail( MY_IS_MOLE( mole ) );

    mole->priv->timeout = timeout;
}

gboolean
my_mole_get_busy( MyMole *mole )
{
    g_return_val_if_fail( MY_IS_MOLE( mole ), FALSE );

    return( mole->priv->busy );
}

void
my_mole_activate( MyMole *mole )
{
    MyMolePrivate *priv;

    g_return_if_fail( MY_IS_MOLE( mole ) );
    priv = mole->priv;
    g_return_if_fail( ! priv->busy );

    priv->busy = TRUE;
    priv->state = S_UP;
    gtk_widget_queue_draw( GTK_WIDGET( mole ) );
    priv->source_id = gdk_threads_add_timeout( priv->timeout,
                                               (GSourceFunc)my_mole_timeout_cb,
                                                 mole );
}

test_mole.c
Code: (C)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
#include "mymole.h"

#define NO_MOLES 2

typedef struct _Data
{
    MyMole    *moles[9]; /* All moles */
   
GtkLabel  *l_hits,   /* Hits label */
               
*l_miss;   /* Miss label */
   
GtkWidget *button;   /* Start game button */
   
gint       hits,     /* Hits counter */
               
miss;     /* Miss counter */
}
Data;

static gboolean
show_mole( Data *data )
{
    gint val;

    /* Loop that ensures we don't re-activate already active mole */
   
do
   
{
        val = g_random_int_range( 0, 9 );
    }
    while( my_mole_get_busy( data->moles[val] ) );

    my_mole_activate( data->moles[val] );

    return( FALSE );
}

static void
cb_clicked( GtkButton *button,
            Data      *data )
{
    gint i;
    gint timeout = 1000;

    gtk_widget_set_sensitive( GTK_WIDGET( button ), FALSE );

    for( i = 0; i < NO_MOLES; i++, timeout += 700 )
    {
        g_timeout_add( timeout, (GSourceFunc)show_mole, data );
    }
}

static void
cb_whacked( MyMole *mole,
            Data   *data )
{
    gchar *text;

    text = g_strdup_printf( "Hits: %d", ++data->hits );
    gtk_label_set_label( data->l_hits, text );
    g_free( text );

    g_timeout_add( 1300, (GSourceFunc)show_mole, data );
}

static void
cb_missed( MyMole *mole,
           Data   *data )
{
    gchar *text;

    text = g_strdup_printf( "Misses: %d", ++data->miss );
    gtk_label_set_label( data->l_miss, text );
    g_free( text );

    g_timeout_add( 1000, (GSourceFunc)show_mole, data );
}

int
main( int    argc,
      char **argv )
{
    GtkWidget *window,
              *vbox,
              *table,
              *mole,
              *hbox,
              *button,
              *label;
    gint       i,
               j;
    Data      *data;

    gtk_init( &argc, &argv );

    data = g_slice_new0( Data );

    window = gtk_window_new( GTK_WINDOW_TOPLEVEL );
    g_signal_connect( G_OBJECT( window ), "destroy",
                      G_CALLBACK( gtk_main_quit ), NULL );

    vbox = gtk_vbox_new( FALSE, 5 );
    gtk_container_add( GTK_CONTAINER( window ), vbox );

    table = gtk_table_new( 3, 3, TRUE );
    gtk_box_pack_start( GTK_BOX( vbox ), table, TRUE, TRUE, 0 );

    for( i = 0; i < 3; i++ )
    {
        for( j = 0; j < 3; j++ )
        {
            mole = my_mole_new();
            g_signal_connect( G_OBJECT( mole ), "whacked",
                              G_CALLBACK( cb_whacked ), data );
            g_signal_connect( G_OBJECT( mole ), "missed",
                              G_CALLBACK( cb_missed ), data );
            gtk_widget_set_size_request( mole, 50, 50 );
            gtk_table_attach_defaults( GTK_TABLE( table ), mole,
                                       j, j + 1, i, i + 1 );
            data->moles[i * 3 + j] = MY_MOLE( mole );
        }
    }

    hbox = gtk_hbox_new( FALSE, 5 );
    gtk_box_pack_start( GTK_BOX( vbox ), hbox, FALSE, FALSE, 0 );

    button = gtk_button_new_with_label( "Start game" );
    g_signal_connect( G_OBJECT( button ), "clicked",
                      G_CALLBACK( cb_clicked ), data );
    gtk_box_pack_start( GTK_BOX( hbox ), button, FALSE, FALSE, 0 );
    data->button = button;

    label = gtk_label_new( "Hits: 0" );
    gtk_box_pack_start( GTK_BOX( hbox ), label, FALSE, FALSE, 0 );
    data->l_hits = GTK_LABEL( label );
   
    label = gtk_label_new( "Misses: 0" );
    gtk_box_pack_start( GTK_BOX( hbox ), label, FALSE, FALSE, 0 );
    data->l_miss = GTK_LABEL( label );

    gtk_widget_show_all( window );
    gtk_main();

    g_slice_free( Data, data );

    return( 0 );
}

Tadej
Back to top
jimmyfam
Familiar Face


Joined: 17 Feb 2010
Posts: 17

PostPosted: Wed Feb 24, 2010 4:03 pm    Post subject: Reply with quote

Hi Tadej,

Wow, thanks for helping out in a sample code.
Deeply appreciate!

Complied this code and it works!
I will study this code closely.. and further modified it to make it more fun.
Will try to replace colors with picture animation if possible.

Will update soon in this thread
Thanks again!

Regards,
Jimmy
Back to top
jimmyfam
Familiar Face


Joined: 17 Feb 2010
Posts: 17

PostPosted: Tue Mar 09, 2010 9:29 am    Post subject: Reply with quote

Hi Tadej,

I cant figure out how to show pictures for clicking.
I understand your program uses Cairo to draw the colored squares. Can you help me out?

Thanks!!

Jimmy
Back to top
jimmyfam
Familiar Face


Joined: 17 Feb 2010
Posts: 17

PostPosted: Wed Mar 10, 2010 12:27 am    Post subject: Reply with quote

I have written the program flow below:

Whack A Mole!

To begin, Click on Game Icon, Program excutes and load user "Game diffculty selection screen"

User have to chose between 3 difficulty levels. "Easy, Normal, Hard".

When User selects "Easy" mode. The game begins with 9 holes. 1 mole will pop out randomly from the the holes for the user to click within the time interval of 4 secs. Success hit will display a pic of a Mole been hit. A Miss hit will display a pic of a Mole smiling and a Miss word on top of its head.

When User selects "Normal" mode. The game begins with 16 holes. 3 moles will pop out randomly from the the holes for the user to click within the timeinterval of 2 secs. Success hit will display a pic of a Mole been hit. A Miss hit will display a pic of a Mole smiling and a Miss word on top of its head.

When User selects "Hard" mode. The game begins with 25 holes. 5 mole will pop out randomly from the the holes for the user to click within the interval of 2 secs. Success hit will display a pic of a Mole been hit. A Miss hit will display a pic of a Mole smiling and a Miss word on top of its head.

All 3 levels have a master timer of 30 secs. When timer ends, Screen display the full score earned, the number of hits and misses. Game recycle back to "Game diffculty selection screen" upon clicking ok. The game can be played again.
Back to top
jimmyfam
Familiar Face


Joined: 17 Feb 2010
Posts: 17

PostPosted: Fri Apr 02, 2010 7:28 am    Post subject: Reply with quote

Hi Tadej,

I have studied & used your code to develop it further. You can see my code as posted below.

I encounter some problems, on line 220 of test_mole.c, is it possible to create the tables only after i select one of the radio buttons(Game Diffculty) in page 2?

I want to have the ability to select and set a 4 x 4, 5 x 5 squares, instead of the 3 x 3 squares as default in your sample program.


test_mole.c

Code: (Plaintext)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
#include <gtk/gtk.h>
#include <string.h>
#include "mymole.h"
#include <gdk/gdkkeysyms.h>

//Declarations
gint moleint;
gint tableint;
gint holesint;

//MyMole *moles[9];
GtkLabel *l_hits, *l_miss;
GtkWidget *button;
gint hits,miss;

//Game Defaults (Easy mode)
moleint = 2;
tableint = 3;
holesint = 9;

//No codes before this line
typedef struct _Data
{
//MyMole    *moles[holesint];
    MyMole    *moles[9]; /* All moles */
}
Data;

static void button_clicked (GtkButton*, GtkAssistant*);
static void assistant_cancel (GtkAssistant*, gpointer);
static void assistant_close (GtkAssistant*, gpointer);
static void cb_toggled (GtkToggleButton*, GtkAssistant*);

typedef struct
{
    GtkWidget *widget;
    gint index;
    const gchar *title;
    GtkAssistantPageType type;
    gboolean complete;
} PageInfo;

//Cairo graphics declaration
cairo_surface_t *surface1;
cairo_surface_t *surface2;
cairo_surface_t *surface3;
cairo_surface_t *surface4;

static void create_surfaces() {
 
  //Insert and edit images here

  //NOT UP
  surface4 = cairo_image_surface_create_from_png("mole hole.png");
  //UP
  surface1 = cairo_image_surface_create_from_png("mole up.png");
  //WHACKED
  surface2 = cairo_image_surface_create_from_png("mole hit.png");
  //MISSED
  surface3 = cairo_image_surface_create_from_png("mole smile2.png");

}

static void destroy_surfaces() {
  g_print("destroying surfaces");
  cairo_surface_destroy(surface1);
}

static gboolean
show_mole( Data *data )
{
    gint val;

    //Loop that ensures we don't re-activate already active mole
    do
    {
        val = g_random_int_range( 0, 9);
        g_print("val = %d pressed\n",val);
        g_print("moleint = %d \n",moleint);
        g_print("tableint = %d \n",tableint);
        g_print("holesint = %d \n",holesint);
    }
    while( my_mole_get_busy( data->moles[val] ) );

    my_mole_activate( data->moles[val] );

    return( FALSE );
}


static void
cb_clicked( GtkButton *button,
            Data      *data )
{
    gint i;
    gint timeout = 1000;

    gtk_widget_set_sensitive( GTK_WIDGET( button ), FALSE );
   
    for( i = 0; i < moleint; i++, timeout += 700 ) //0.7sec
    //for( i = 0; i < NO_MOLES; i++, timeout += 700 )
    {
        g_timeout_add( timeout, (GSourceFunc)show_mole, data );
    }
}

static void
cb_whacked( MyMole *mole,
            Data   *data )
{
    gchar *text;
    text = g_strdup_printf( "Hits: %d", ++hits);
    gtk_label_set_label( l_hits, text );
    g_free( text );

    g_timeout_add( 1300, (GSourceFunc)show_mole, data );
}

static void
cb_missed( MyMole *mole,
           Data   *data )
{
    gchar *text;

    text = g_strdup_printf( "Misses: %d", ++miss );
    gtk_label_set_label( l_miss, text );
    g_free( text );

    g_timeout_add( 1000, (GSourceFunc)show_mole, data );
}



int main (int argc,
          char *argv[])
{
  GtkWidget *assistant, *radio1,*radio2,*radio3,*hbox, *vbox, *label;

  GtkWidget   *table,
              *mole;
             

    gint       i,
               j;
//    Data      *data;

    //gint       i;
    //gchar      label[] = "Radio ";   

//guint i;
  PageInfo page[5] = {
      { NULL, -1, "Introduction",             GTK_ASSISTANT_PAGE_INTRO,   TRUE},
      { NULL, -1, "Diffculty Selection page", GTK_ASSISTANT_PAGE_CONTENT, FALSE},
      { NULL, -1, "Game Start",               GTK_ASSISTANT_PAGE_CONTENT, FALSE},
      { NULL, -1, "Click the Button",         GTK_ASSISTANT_PAGE_PROGRESS, FALSE},
      { NULL, -1, "Confirmation",             GTK_ASSISTANT_PAGE_CONFIRM, TRUE},
  };

  gtk_init (&argc, &argv);

  Data *data = g_slice_new0( Data );

  hits = 0;
  miss = 0;

  /* Create a new assistant widget with no pages. */
  assistant = gtk_assistant_new ();
  gtk_widget_set_size_request (assistant, 450, 300);
  gtk_window_set_title (GTK_WINDOW (assistant), "Whack a Mole");
 
  g_signal_connect (G_OBJECT (assistant), "destroy",
                    G_CALLBACK (gtk_main_quit), NULL);
 
  page[0].widget = gtk_label_new ("This is an example of a Whack a Mole. By\n"\
                                  "clicking the forward button, you can continue\n"\
                                  "to the next section!");
  page[1].widget = gtk_vbox_new(FALSE, 5);
  page[2].widget = table = gtk_vbox_new(FALSE, 5);
  page[3].widget = gtk_alignment_new (0.5, 0.5, 0.0, 0.0);
  page[4].widget = gtk_label_new ("Text has been entered in the label and the\n"\
                                  "combo box is clicked. If you are done, then\n"\
                                  "it is time to leave!");
 
   //Game Diffculty Selection page
   /* Create three radio buttons where the second two join radio1's group. */
   radio1 = gtk_radio_button_new_with_label (NULL, "Easy");
   radio2 = gtk_radio_button_new_with_label_from_widget (GTK_RADIO_BUTTON (radio1),
                                                        "Normal!");
   radio3 = gtk_radio_button_new_with_label_from_widget (GTK_RADIO_BUTTON (radio2),
                                                        "Hard");
 
   /* Create the necessary widgets for the second page. */
   vbox = gtk_vbox_new(FALSE, 5);

   g_signal_connect( radio1, "toggled", G_CALLBACK( cb_toggled ), (gpointer) assistant );
   g_object_set_data( G_OBJECT( radio1 ), "id", 1);
   g_signal_connect( radio2, "toggled", G_CALLBACK( cb_toggled ), (gpointer) assistant );
   g_object_set_data( G_OBJECT( radio2 ), "id", 2);
   g_signal_connect( radio3, "toggled", G_CALLBACK( cb_toggled ), (gpointer) assistant );
   g_object_set_data( G_OBJECT( radio3 ), "id", 3);

   gtk_box_pack_start (GTK_BOX (page[1].widget), radio1, FALSE, FALSE, 5);
   gtk_box_pack_start (GTK_BOX (page[1].widget), radio2, FALSE, FALSE, 5);
   gtk_box_pack_start (GTK_BOX (page[1].widget), radio3, FALSE, FALSE, 5);

   
    //Begin 3rd page
    //Draw table, must select diffculty option before this step
    //Added
   
    create_surfaces();
    vbox = gtk_vbox_new( FALSE, 5 );
    //gtk_container_add( GTK_CONTAINER(assistant), vbox );

    //Must update tableint here....how??
    g_print("Printing table now!!!!");
   
    table = gtk_table_new( tableint, tableint, TRUE );
    gtk_box_pack_start( GTK_BOX( page[2].widget ), table, TRUE, TRUE, 0 );

    for( i = 0; i < tableint; i++ )
    {
        for( j = 0; j < tableint; j++ )
        {
            mole = my_mole_new();
            g_signal_connect( G_OBJECT( mole ), "whacked",
                              G_CALLBACK( cb_whacked ), data);
            g_signal_connect( G_OBJECT( mole ), "missed",
                              G_CALLBACK( cb_missed ), data);
            gtk_widget_set_size_request( mole, 50, 50 );
            gtk_table_attach_defaults( GTK_TABLE( table ), mole,
                                       j, j + 1, i, i + 1 );
            //Must be 3 if not error!
            data->moles[i * tableint + j] = MY_MOLE( mole );
        }
    }

    hbox = gtk_hbox_new( FALSE, 5 );
    gtk_box_pack_start( GTK_BOX(page[2].widget), hbox, FALSE, FALSE, 0 );
    button = gtk_button_new_with_label( "Start game" );
   
    g_signal_connect( G_OBJECT(button), "clicked",
                      G_CALLBACK( cb_clicked ), data);

    gtk_box_pack_start( GTK_BOX( hbox ), button, FALSE, FALSE, 0 );
    button = button;

    label = gtk_label_new( "Hits: 0" );
    gtk_box_pack_start( GTK_BOX( hbox ), label, FALSE, FALSE, 0 );
    l_hits = GTK_LABEL( label );
   
    label = gtk_label_new( "Misses: 0" );
    gtk_box_pack_start( GTK_BOX( hbox ), label, FALSE, FALSE, 0 );
    l_miss = GTK_LABEL( label );

  /* Add five pages to the GtkAssistant dialog. */
  for (i = 0; i < 5; i++)
  {
    page[i].index = gtk_assistant_append_page (GTK_ASSISTANT (assistant),
                                               page[i].widget);
    gtk_assistant_set_page_title (GTK_ASSISTANT (assistant),
                                  page[i].widget, page[i].title);
    gtk_assistant_set_page_type  (GTK_ASSISTANT (assistant),
                                  page[i].widget, page[i].type);

    /* Set the introduction and conclusion pages as complete so they can be
     * incremented or closed. */
    gtk_assistant_set_page_complete (GTK_ASSISTANT (assistant),
                                     page[i].widget, page[i].complete);
  }
   
  g_signal_connect (G_OBJECT (button), "clicked",
                    G_CALLBACK (button_clicked), (gpointer) assistant);
                   
  g_signal_connect (G_OBJECT (assistant), "cancel",
                    G_CALLBACK (assistant_cancel), NULL);
  g_signal_connect (G_OBJECT (assistant), "close",
                    G_CALLBACK (assistant_close), NULL);

  gtk_widget_show_all (assistant);

  gtk_main ();

    destroy_surfaces();

  return 0;
}

static void
button_clicked (GtkButton *button,
                GtkAssistant *assistant)
{
  GtkWidget *page;
  gtk_widget_set_sensitive (GTK_WIDGET (button), FALSE);
  page = gtk_assistant_get_nth_page (assistant, 3);
  gtk_assistant_set_page_complete (assistant, page, TRUE);
}

/* If the dialog is cancelled, delete it from memory and then clean up after
 * the Assistant structure. */
static void
assistant_cancel (GtkAssistant *assistant,
                  gpointer data)
{
  gtk_widget_destroy (GTK_WIDGET (assistant));
}

/* This function is where you would apply the changes and destroy the assistant. */
static void
assistant_close (GtkAssistant *assistant,
                 gpointer data)
{
  g_print ("You would apply your changes now!\n");
  gtk_widget_destroy (GTK_WIDGET (assistant));
}

//Functions
void
cb_toggled( GtkToggleButton *radio1,
            GtkAssistant *assistant)

{
  int button_id = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(radio1),"id"));
  if( gtk_toggle_button_get_active( radio1 ) )
    g_print("\nRadio %d pressed\n",button_id);

  switch(button_id){
    case 1:
      moleint = 2;
      tableint = 3;
      holesint = 9;
      //g_print("\nEasy mode selected!");
      break;
    case 2:
      moleint = 3;
      tableint = 4;
      holesint = 16;
      //g_print("\nNormal mode selected!");
      break;
    case 3:
      moleint = 5;
      tableint = 5;
      holesint = 25;
      //g_print("\nHard mode selected!");
  };

  gint num = gtk_assistant_get_current_page (assistant);
  GtkWidget *page = gtk_assistant_get_nth_page (assistant, num);
 
  gtk_assistant_set_page_complete (assistant, page, TRUE);
}
Back to top
Display posts from previous:   
Post new topic   Reply to topic    GTK+ Forums Forum Index -> GTK+ Programming All times are GMT
Page 1 of 1

 


Powered by phpBB © 2001, 2005 phpBB Group
CodeBB 1.0 Beta 2
Protected by Anti-Spam ACP