summaryrefslogtreecommitdiff
path: root/pong
diff options
context:
space:
mode:
authorPrajwal Mohan <prajwal.karur.mohan@intel.com>2012-04-27 15:45:31 -0700
committerPrajwal Mohan <prajwal.karur.mohan@intel.com>2012-04-27 15:45:31 -0700
commitb7ef78844736699e9b96ecfb89853b0ceb6133f9 (patch)
tree69c7f426404fc2dfbe020984a4722fcbf1a61114 /pong
downloadclutter-toys-b7ef78844736699e9b96ecfb89853b0ceb6133f9.tar.gz
clutter-toys-b7ef78844736699e9b96ecfb89853b0ceb6133f9.tar.bz2
clutter-toys-b7ef78844736699e9b96ecfb89853b0ceb6133f9.zip
Initial Import
Diffstat (limited to 'pong')
-rw-r--r--pong/Makefile15
-rw-r--r--pong/pong-ball.pngbin0 -> 1089 bytes
-rw-r--r--pong/pong-bat.pngbin0 -> 972 bytes
-rw-r--r--pong/pong2.c412
4 files changed, 427 insertions, 0 deletions
diff --git a/pong/Makefile b/pong/Makefile
new file mode 100644
index 0000000..3555e3f
--- /dev/null
+++ b/pong/Makefile
@@ -0,0 +1,15 @@
+LIBS=`pkg-config --libs clutter-1.0`
+INCS=`pkg-config --cflags clutter-1.0`
+CFLAGS="-lm"
+
+.c.o:
+ $(CC) -g -Wall $(CFLAGS) $(INCS) -c $*.c
+
+all: pong2
+
+
+pong2: pong2.o
+ $(CC) -g -Wall $(CFLAGS) -o $@ pong2.o $(LIBS)
+
+clean:
+ rm -fr *.o pong2
diff --git a/pong/pong-ball.png b/pong/pong-ball.png
new file mode 100644
index 0000000..d80af4c
--- /dev/null
+++ b/pong/pong-ball.png
Binary files differ
diff --git a/pong/pong-bat.png b/pong/pong-bat.png
new file mode 100644
index 0000000..1415dd3
--- /dev/null
+++ b/pong/pong-bat.png
Binary files differ
diff --git a/pong/pong2.c b/pong/pong2.c
new file mode 100644
index 0000000..3a57c34
--- /dev/null
+++ b/pong/pong2.c
@@ -0,0 +1,412 @@
+#include <clutter/clutter.h>
+#include <cairo/cairo.h>
+#include <math.h>
+
+#define PADDLE_SIZE 48.0
+#define PADDLE_THICKNESS 8.0
+#define PADDLE_SPEED 4
+#define BALL_SIZE 12.0
+#define DASH_LENGTH 12.0
+#define ARENA_WIDTH 320.0
+#define ARENA_HEIGHT 240.0
+#define FPS 60.0
+#define MINPOS (PADDLE_THICKNESS * 2)
+#define MAXPOS (ARENA_HEIGHT - PADDLE_SIZE - (PADDLE_THICKNESS * 2))
+
+/*
+ * NOTE: This is a completely brain-dead way to implement pong, but helped
+ * me familiarise with Clutter paths and such.
+ */
+
+static const ClutterColor green = { 0x0, 0xff, 0x0, 0xff };
+
+typedef struct {
+ /* First paddle */
+ gint score1;
+ gint position1;
+ ClutterActor *paddle1;
+ gboolean up1;
+ gboolean down1;
+
+ /* Second paddle */
+ gint score2;
+ gint position2;
+ ClutterActor *paddle2;
+ gboolean up2;
+ gboolean down2;
+
+ /* Paddle independent */
+ gdouble angle;
+ gdouble speed;
+ ClutterActor *ball;
+ ClutterActor *arena;
+ ClutterTimeline *timeline;
+ ClutterAlpha *alpha;
+ ClutterBehaviour *behaviour;
+ ClutterPath *path;
+ ClutterKnot start;
+ ClutterKnot end;
+ gboolean pause;
+} PongData;
+
+static ClutterActor *
+pong_arena_actor_create (PongData *data)
+{
+ ClutterActor *group, *actor;
+ ClutterGeometry geom;
+ gint i;
+
+ group = clutter_group_new ();
+
+ /* Top border */
+ actor = clutter_rectangle_new_with_color (&green);
+ geom.x = 0; geom.y = 0;
+ geom.width = ARENA_WIDTH; geom.height = PADDLE_THICKNESS;
+ clutter_actor_set_geometry (actor, &geom);
+ clutter_actor_show (actor);
+ clutter_group_add (CLUTTER_GROUP (group), actor);
+
+ /* Bottom border */
+ actor = clutter_rectangle_new_with_color (&green);
+ geom.y = ARENA_HEIGHT - PADDLE_THICKNESS;
+ clutter_actor_set_geometry (actor, &geom);
+ clutter_actor_show (actor);
+ clutter_group_add (CLUTTER_GROUP (group), actor);
+
+ /* Dotted line down the middle */
+ geom.x = (ARENA_WIDTH / 2) - (PADDLE_THICKNESS / 2);
+ geom.width = PADDLE_THICKNESS;
+ geom.height = PADDLE_THICKNESS * 2;
+ for (i = 0; i < ARENA_HEIGHT / (PADDLE_THICKNESS * 2); i+= 2) {
+ geom.y = i * PADDLE_THICKNESS * 2;
+ actor = clutter_rectangle_new_with_color (&green);
+ clutter_actor_set_geometry (actor, &geom);
+ clutter_actor_show (actor);
+ clutter_group_add (CLUTTER_GROUP (group), actor);
+ }
+
+ return group;
+}
+
+static ClutterActor *
+pong_ball_actor_create (PongData *data)
+{
+ ClutterActor *actor, *group;
+ cairo_t *cr;
+
+ actor = clutter_cairo_texture_new (BALL_SIZE, BALL_SIZE);
+ cr = clutter_cairo_texture_create (CLUTTER_CAIRO_TEXTURE (actor));
+
+ /* Clear */
+ cairo_set_operator (cr, CAIRO_OPERATOR_CLEAR);
+ cairo_paint(cr);
+
+ cairo_set_operator (cr, CAIRO_OPERATOR_OVER);
+ cairo_set_source_rgba (cr, 0, 1.0, 0, 1.0);
+
+ cairo_new_path (cr);
+ cairo_arc (cr, BALL_SIZE/2.0, BALL_SIZE/2.0,
+ BALL_SIZE/2.0, 0, 2*M_PI);
+ cairo_fill (cr);
+
+ cairo_destroy (cr);
+
+ group = clutter_group_new ();
+ clutter_group_add (CLUTTER_GROUP (group), actor);
+ clutter_actor_set_position (actor, -BALL_SIZE/2, -BALL_SIZE/2);
+ clutter_actor_show (actor);
+
+ return group;
+}
+
+static ClutterActor *
+pong_paddle_actor_create (PongData *data)
+{
+ ClutterGeometry geom;
+ ClutterActor *actor;
+
+ actor = clutter_rectangle_new_with_color (&green);
+ geom.x = 0; geom.y = 0;
+ geom.width = PADDLE_THICKNESS;
+ geom.height = PADDLE_SIZE;
+ clutter_actor_set_geometry (actor, &geom);
+
+ return actor;
+}
+
+static void
+pong_ball_path_calculate (PongData *data, gdouble ax, gdouble ay, gdouble w,
+ gdouble h)
+{
+ gdouble x, y, dx, dy, angle;
+
+ x = clutter_actor_get_x (data->ball);
+ y = clutter_actor_get_y (data->ball);
+
+ data->start.x = x;
+ data->start.y = y;
+
+ /* Work out destination */
+ if (data->angle < M_PI * 0.5) {
+ /* Travelling up-right */
+ dx = x + (tan (data->angle) * (y - ay - (BALL_SIZE/2)));
+ if (dx > w - (BALL_SIZE/2)) {
+ dx = w - (BALL_SIZE/2);
+ dy = y - ((dx - x) / tan (data->angle));
+ } else {
+ dy = ay + (BALL_SIZE / 2);
+ }
+ } else if (data->angle < M_PI) {
+ /* Travelling down-right */
+ angle = M_PI - data->angle;
+ dx = x + (tan (angle) * (h - y));
+ if (dx > w - (BALL_SIZE/2)) {
+ dx = w - (BALL_SIZE/2);
+ dy = y + ((dx - x) / tan (angle));
+ } else {
+ dy = h - (BALL_SIZE/2);
+ }
+ } else if (data->angle < M_PI * 1.5) {
+ /* Travelling down-left */
+ angle = data->angle - M_PI;
+ dx = x - (tan (angle) * (h - y));
+ if (dx < (BALL_SIZE/2)) {
+ dx = (BALL_SIZE/2);
+ dy = y + ((x - ax) / tan (angle));
+ } else {
+ dy = h - (BALL_SIZE/2);
+ }
+ } else {
+ /* Travelling up-left */
+ angle = (M_PI * 2) - data->angle;
+ dx = x - (tan (angle) * (y - ay - (BALL_SIZE/2)));
+ if (dx < (BALL_SIZE/2)) {
+ dx = (BALL_SIZE/2);
+ dy = y - ((x - ax) / tan (angle));
+ } else {
+ dy = ay + (BALL_SIZE / 2);
+ }
+ }
+
+ clutter_timeline_set_duration (data->timeline, MAX (1000/FPS,
+ (guint)(1000 * (ABS (dx - x)/w) * data->speed)));
+ data->end.x = (gint)dx;
+ data->end.y = (gint)dy;
+}
+
+static void
+pong_path_end_cb (ClutterTimeline *timeline,
+ PongData *data)
+{
+ /* Figure out the new angle of the ball after a collision */
+ gint x, y;
+
+ x = clutter_actor_get_x (data->ball);
+ y = clutter_actor_get_y (data->ball);
+
+ /*g_debug ("%d, %d, %lf", x, y, data->angle);*/
+
+ /* Work out new travel angle after collisions */
+ if ((x >= (ARENA_WIDTH - (BALL_SIZE/2))) ||
+ (x <= (BALL_SIZE/2)))
+ data->angle = -data->angle;
+
+ while (data->angle > M_PI*2) data->angle -= M_PI*2;
+ while (data->angle < 0) data->angle += M_PI*2;
+
+ if (y <= PADDLE_THICKNESS + (BALL_SIZE/2)) {
+ if (data->angle < M_PI * 0.5) {
+ data->angle = M_PI - data->angle;
+ } else if (data->angle > M_PI * 1.5) {
+ data->angle = M_PI +
+ ((M_PI * 2.0) - data->angle);
+ }
+ } else if (y >= ARENA_HEIGHT - PADDLE_THICKNESS -
+ (BALL_SIZE/2)) {
+ if (data->angle < M_PI) {
+ data->angle = M_PI - data->angle;
+ } else if (data->angle < M_PI * 1.5) {
+ data->angle = (M_PI * 2.0) -
+ (data->angle - M_PI);
+ }
+ }
+
+ while (data->angle > M_PI*2) { data->angle -= M_PI*2; }
+ while (data->angle < 0) { data->angle += M_PI*2; }
+
+ pong_ball_path_calculate (data,
+ 0, PADDLE_THICKNESS,
+ ARENA_WIDTH,
+ ARENA_HEIGHT - PADDLE_THICKNESS);
+
+ clutter_path_clear (data->path);
+ clutter_path_add_move_to (data->path, data->start.x, data->start.y);
+ clutter_path_add_line_to (data->path, data->end.x, data->end.y );
+
+ clutter_timeline_start (data->timeline);
+
+ /*g_debug ("%d, %d, %lf", data->end.x,
+ data->end.y, data->angle);*/
+}
+
+static void
+pong_key_press_event_cb (ClutterStage *stage, ClutterEvent *event,
+ PongData *data)
+{
+ guint key_symbol = clutter_event_get_key_symbol (event);
+
+ if ((key_symbol != CLUTTER_p) && (data->pause)) {
+ data->pause = FALSE;
+ clutter_timeline_start (data->timeline);
+ }
+
+ switch (key_symbol)
+ {
+ case CLUTTER_Escape:
+ case CLUTTER_q:
+ clutter_main_quit ();
+ break;
+ case CLUTTER_a:
+ data->up1 = TRUE;
+ break;
+ case CLUTTER_z:
+ data->down1 = TRUE;
+ break;
+ case CLUTTER_k:
+ data->up2 = TRUE;
+ break;
+ case CLUTTER_m:
+ data->down2 = TRUE;
+ break;
+ case CLUTTER_p:
+ data->pause = !data->pause;
+ if (data->pause) {
+ clutter_timeline_pause (data->timeline);
+ } else
+ clutter_timeline_start (data->timeline);
+ default:
+ break;
+ }
+}
+
+static void
+pong_key_release_event_cb (ClutterStage *stage, ClutterEvent *event,
+ PongData *data)
+{
+ guint key_symbol = clutter_event_get_key_symbol (event);
+
+ switch (key_symbol)
+ {
+ case CLUTTER_a:
+ data->up1 = FALSE;
+ break;
+ case CLUTTER_z:
+ data->down1 = FALSE;
+ break;
+ case CLUTTER_k:
+ data->up2 = FALSE;
+ break;
+ case CLUTTER_m:
+ data->down2 = FALSE;
+ break;
+ default:
+ break;
+ }
+}
+
+static void
+pong_new_frame_cb (ClutterTimeline *timeline, gint frame_num,
+ PongData *data)
+{
+ if (data->up1 ^ data->down1) {
+ data->position1 = MAX (MINPOS, MIN (MAXPOS, data->position1 +
+ (data->down1 ? PADDLE_SPEED : 0) -
+ (data->up1 ? PADDLE_SPEED : 0)));
+ clutter_actor_set_position (data->paddle1, PADDLE_THICKNESS,
+ data->position1);
+ }
+
+ if (data->up2 ^ data->down2) {
+ data->position2 = MAX (MINPOS, MIN (MAXPOS, data->position2 +
+ (data->down2 ? PADDLE_SPEED : 0) -
+ (data->up2 ? PADDLE_SPEED : 0)));
+ clutter_actor_set_position (data->paddle2, ARENA_WIDTH -
+ (PADDLE_THICKNESS * 2), data->position2);
+ }
+}
+
+int
+main (int argc, char **argv)
+{
+ PongData data;
+ ClutterActor *stage;
+ const ClutterColor stage_color = { 0x00, 0x00, 0x00, 0xff };
+
+ clutter_init (&argc, &argv);
+
+ data.arena = pong_arena_actor_create (&data);
+ data.paddle1 = pong_paddle_actor_create (&data);
+ data.paddle2 = pong_paddle_actor_create (&data);
+ data.ball = pong_ball_actor_create (&data);
+
+ clutter_actor_set_position (data.paddle1, PADDLE_THICKNESS,
+ PADDLE_THICKNESS * 2);
+ clutter_actor_set_position (data.paddle2,
+ ARENA_WIDTH - (PADDLE_THICKNESS * 2),
+ PADDLE_THICKNESS * 2);
+
+ data.up1 = FALSE;
+ data.down1 = FALSE;
+ data.up2 = FALSE;
+ data.down2 = FALSE;
+ data.pause = TRUE;
+ data.position1 = 0;
+ data.position2 = 0;
+
+ data.timeline = clutter_timeline_new (2000);
+ data.alpha = clutter_alpha_new_full (data.timeline, CLUTTER_LINEAR);
+ data.path = clutter_path_new();
+ data.behaviour = clutter_behaviour_path_new (data.alpha, data.path);
+
+ data.angle = ((M_PI * 1.8));
+ data.speed = 2;
+
+ clutter_actor_set_position (data.ball, ARENA_WIDTH/2, ARENA_HEIGHT/2);
+
+ stage = clutter_stage_get_default ();
+ clutter_stage_set_color (CLUTTER_STAGE (stage), &stage_color);
+
+ clutter_group_add (CLUTTER_GROUP (stage), data.arena);
+ clutter_group_add (CLUTTER_GROUP (stage), data.paddle1);
+ clutter_group_add (CLUTTER_GROUP (stage), data.paddle2);
+ clutter_group_add (CLUTTER_GROUP (stage), data.ball);
+
+ clutter_actor_show_all (CLUTTER_ACTOR (stage));
+ clutter_actor_set_scale (CLUTTER_ACTOR (stage),
+ CLUTTER_STAGE_WIDTH () / ARENA_WIDTH,
+ CLUTTER_STAGE_HEIGHT () / ARENA_HEIGHT);
+
+ pong_ball_path_calculate (&data,
+ 0, PADDLE_THICKNESS,
+ ARENA_WIDTH,
+ ARENA_HEIGHT - PADDLE_THICKNESS);
+ clutter_behaviour_apply (data.behaviour, data.ball);
+
+ clutter_path_add_move_to (data.path, data.start.x, data.start.y);
+ clutter_path_add_line_to (data.path, data.end.x, data.end.y );
+
+ g_signal_connect_after (data.timeline, "completed",
+ G_CALLBACK (pong_path_end_cb), &data);
+ g_signal_connect (data.timeline, "new_frame",
+ G_CALLBACK (pong_new_frame_cb), &data);
+
+ g_signal_connect (stage, "key-press-event",
+ G_CALLBACK (pong_key_press_event_cb), &data);
+ g_signal_connect (stage, "key-release-event",
+ G_CALLBACK (pong_key_release_event_cb), &data);
+
+ clutter_main ();
+
+ return 0;
+}
+