changeset 131:6a8588df68af

Tank can change direction and navigate on the mud area
author Thinker K.F. Li <thinker@branda.to>
date Wed, 17 Sep 2008 01:30:25 +0800
parents 3a4d6179e6a9
children c65b30e2eda9
files examples/tank/tank_main.c src/X_supp.c src/X_supp.h src/animate.c src/tools.h
diffstat 5 files changed, 236 insertions(+), 81 deletions(-) [+]
line wrap: on
line diff
--- a/examples/tank/tank_main.c	Tue Sep 16 21:23:34 2008 +0800
+++ b/examples/tank/tank_main.c	Wed Sep 17 01:30:25 2008 +0800
@@ -1,5 +1,7 @@
 #include <sys/time.h>
+#include <string.h>
 #include <mb/mb.h>
+#include <mb/tools.h>
 #include "svgs.h"
 
 enum { MUD, ROC, BRI, BSH };
@@ -31,18 +33,183 @@
       MUD, BRI, MUD, BRI, MUD, MUD, MUD, MUD}
 };
 
+#define MAP_W 16
+#define MAP_H 12
+
+/*! \defgroup tank_elf Tank Elf
+ * \brief Tank elf module provides control functions of tanks in game.
+ * @{
+ */
+struct _tank {
+    coord_t *coord_pos;		/*!< \brief coordinate for position */
+    coord_t *coord_rot;		/*!< \brief coordinate for rotation */
+    int map_x, map_y;
+    int direction;
+    mb_progm_t *progm;
+};
+typedef struct _tank tank_t;
+enum { TD_UP = 0, TD_RIGHT, TD_DOWN, TD_LEFT };
+
+static tank_t *tank_new(coord_t *coord_pos,
+			coord_t *coord_rot,
+			int map_x, int map_y,
+			X_MB_runtime_t *mb_rt) {
+    tank_t *tank;
+    redraw_man_t *rdman;
+
+    tank = O_ALLOC(tank_t);
+    if(tank == NULL)
+	return NULL;
+
+    rdman = X_MB_rdman(mb_rt);
+
+    tank->coord_pos = coord_pos;
+    tank->coord_rot = coord_rot;
+    tank->map_x = map_x;
+    tank->map_y = map_y;
+    tank->direction = TD_UP;
+    tank->progm = NULL;
+
+    memset(coord_pos->matrix, 0, sizeof(co_aix[6]));
+    coord_pos->matrix[0] = 1;
+    coord_pos->matrix[2] = map_x * 50;
+    coord_pos->matrix[4] = 1;
+    coord_pos->matrix[5] = map_y * 50;
+    rdman_coord_changed(rdman, coord_pos);
+
+    return tank;
+}
+
+static void tank_free(tank_t *tank, X_MB_runtime_t *xmb_rt) {
+    mb_tman_t *tman;
+
+    if(tank->progm) {
+	tman = X_MB_tman(xmb_rt);
+	mb_progm_abort(tank->progm, tman);
+    }
+    free(tank);
+}
+
+/*! \brief Clean program for a tank.
+ *
+ * It is called when the program is completed.
+ */
+static void clean_tank_progm_handler(event_t *event, void *arg) {
+    tank_t *tank = (tank_t *)arg;
+
+    mb_progm_free(tank->progm);
+    tank->progm = NULL;
+}
+
+#define PI 3.1415926
+
+static void tank_move(tank_t *tank, int direction,
+		    X_MB_runtime_t *xmb_rt) {
+    redraw_man_t *rdman;
+    mb_tman_t *tman;
+    ob_factory_t *factory;
+    /* for the program */
+    mb_progm_t *progm;
+    subject_t *comp_sub;
+    mb_word_t *word;
+    mb_timeval_t start, playing;
+    mb_timeval_t now;
+    /* for position */
+    co_aix sh_x, sh_y;
+    /* for direction */
+    float ang1, ang2;
+    float rot_diff;
+    static co_aix shift_xy[][2] = {{0, -50}, {50, 0}, {0, 50}, {-50, 0}};
+    static int map_shift[4][2] = {{0, -1}, {1, 0}, {0, 1}, {-1, 0}};
+    static float angles[4] = {0, PI / 2, PI , PI * 3 / 2};
+    static float rotations[7] = {PI / 2, PI , -PI / 2,
+				 0, PI / 2, PI , -PI / 2};
+
+    if(tank->progm != NULL)
+	return;
+
+    /*
+     * Keep inside the map.
+     */
+    if(direction == tank->direction) {
+	switch(direction) {
+	case TD_UP:
+	    if(tank->map_y == 0)
+		return;
+	    if(map[tank->map_y - 1][tank->map_x] != MUD)
+		return;
+	    break;
+	case TD_RIGHT:
+	    if(tank->map_x >= (MAP_W - 1))
+		return;
+	    if(map[tank->map_y][tank->map_x + 1] != MUD)
+		return;
+	    break;
+	case TD_DOWN:
+	    if(tank->map_y >= (MAP_H - 1))
+		return;
+	    if(map[tank->map_y + 1][tank->map_x] != MUD)
+		return;
+	    break;
+	case TD_LEFT:
+	    if(tank->map_x == 0)
+		return;
+	    if(map[tank->map_y][tank->map_x - 1] != MUD)
+		return;
+	    break;
+	}
+    }
+
+    rdman = X_MB_rdman(xmb_rt);
+    tman = X_MB_tman(xmb_rt);
+    factory = X_MB_ob_factory(xmb_rt);
+
+    progm = mb_progm_new(1, rdman);
+    tank->progm = progm;
+
+    MB_TIMEVAL_SET(&start, 0, 0);
+    MB_TIMEVAL_SET(&playing, 0, 500000);
+    word = mb_progm_next_word(progm, &start, &playing);
+
+    if(direction == tank->direction) {
+	/* Shift/move */
+	sh_x = shift_xy[direction][0];
+	sh_y = shift_xy[direction][1];
+	mb_shift_new(sh_x, sh_y, tank->coord_pos, word);
+	tank->map_x += map_shift[direction][0];
+	tank->map_y += map_shift[direction][1];
+    } else {
+	/* Change direction */
+	rot_diff = rotations[3 - tank->direction + direction];
+	ang1 = angles[tank->direction];
+	ang2 = ang1 + rot_diff;
+	mb_rotate_new(ang1, ang2, tank->coord_rot, word);
+	tank->direction = direction;
+    }
+
+    /* Clean program when it is completed. */
+    comp_sub = mb_progm_get_complete(progm);
+    subject_add_observer(factory, comp_sub,
+			 clean_tank_progm_handler, tank);
+
+    get_now(&now);
+    mb_progm_start(progm, tman, &now);
+}
+
+/* @} */
+
 typedef struct _tank_rt tank_rt_t;
 
 struct _tank_rt {
-    tank1_t *tank1;
-    tank2_t *tank2;
+    tank_t *tank1;
+    tank1_t *tank1_o;
+    tank_t *tank2;
+    tank2_t *tank2_o;
     int n_enemy;
-    tank_en_t *tank_enemies[10];
+    tank_t *tank_enemies[10];
+    tank_en_t *tank_enemies_o[10];
     void *map[12][16];
     X_MB_runtime_t *mb_rt;
-
-    mb_progm_t *tank1_progm;
-
     observer_t *kb_observer;
 };
 
@@ -54,64 +221,38 @@
 	rdman_coord_changed(rdman, (g)->root_coord);	\
     } while(0)
 
-static void free_progm_handler(event_t *event, void *arg) {
-    tank_rt_t *tank_rt = (tank_rt_t *)arg;
-
-    mb_progm_free(tank_rt->tank1_progm);
-    tank_rt->tank1_progm = NULL;
-}
-
 static void keyboard_handler(event_t *event, void *arg) {
     X_kb_event_t *xkey = (X_kb_event_t *)event;
     tank_rt_t *tank_rt = (tank_rt_t *)arg;
-    redraw_man_t *rdman;
-    mb_tman_t *tman;
-    mb_word_t *word;
-    ob_factory_t *factory;
-    subject_t *comp_sub;
-    mb_timeval_t start_tm, playing, now;
-
-    if(tank_rt->tank1_progm != NULL)
-	return;
+    int direction;
 
-    rdman = X_MB_rdman(tank_rt->mb_rt);
-    tman = X_MB_tman(tank_rt->mb_rt);
-
-    tank_rt->tank1_progm = mb_progm_new(2, rdman);
-    comp_sub = mb_progm_get_complete(tank_rt->tank1_progm);
-    factory = rdman_get_ob_factory(rdman);
-    subject_add_observer(factory, comp_sub,
-			 free_progm_handler,
-			 tank_rt);
-
-    MB_TIMEVAL_SET(&start_tm, 0, 0);
-    MB_TIMEVAL_SET(&playing, 0, 500000);
-    word = mb_progm_next_word(tank_rt->tank1_progm,
-			      &start_tm, &playing);
+    if(xkey->event.type != EVT_KB_PRESS)
+	return;
 
     switch(xkey->sym) {
     case 0xff51:		/* left */
-	mb_shift_new(-50, 0, tank_rt->tank1->root_coord, word);
+	direction = TD_LEFT;
 	break;
 
     case 0xff52:		/* up */
-	mb_shift_new(0, -50, tank_rt->tank1->root_coord, word);
+	direction = TD_UP;
 	break;
 
     case 0xff53:		/* right */
-	mb_shift_new(50, 0, tank_rt->tank1->root_coord, word);
+	direction = TD_RIGHT;
 	break;
 
     case 0xff54:		/* down */
-	mb_shift_new(0, 50, tank_rt->tank1->root_coord, word);
+	direction = TD_DOWN;
 	break;
 
     case 0x20:			/* space */
     case 0xff0d:		/* enter */
-	break;
+    default:
+	return;
     }
-    get_now(&now);
-    mb_progm_start(tank_rt->tank1_progm, tman, &now);
+
+    tank_move(tank_rt->tank1, direction, tank_rt->mb_rt);
 }
 
 static void init_keyboard(tank_rt_t *tank_rt) {
@@ -130,19 +271,39 @@
 	subject_add_observer(factory, kbevents, keyboard_handler, tank_rt);
 }
 
+/*! \brief Make coord objects for elfs (tanks). */
+static void make_elf_coords(redraw_man_t *rdman, coord_t **coord_pos,
+			    coord_t **coord_rot, coord_t **coord_center) {
+    coord_t *coord_back;
+
+    *coord_pos = rdman_coord_new(rdman, rdman->root_coord);
+
+    coord_back = rdman_coord_new(rdman, *coord_pos);
+    coord_back->matrix[2] = 25;
+    coord_back->matrix[5] = 25;
+    rdman_coord_changed(rdman, coord_back);
+
+    *coord_rot = rdman_coord_new(rdman, coord_back);
+
+    *coord_center = rdman_coord_new(rdman, *coord_rot);
+    (*coord_center)->matrix[2] = -25;
+    (*coord_center)->matrix[5] = -25;
+    rdman_coord_changed(rdman, *coord_center);
+}
+
 void
 initial_tank(tank_rt_t *tank_rt, X_MB_runtime_t *mb_rt) {
     redraw_man_t *rdman;
-    mb_tman_t *tman;
+    /* for map areas */
     mud_t *mud;
     brick_t *brick;
     rock_t *rock;
     bush_t *bush;
-    mb_word_t *word;
-    mb_timeval_t start, playing;
-    mb_timeval_t mbtv;
-    subject_t *comp_sub;
-    ob_factory_t *factory;
+    /* for tanks */
+    coord_t *coord_center, *coord_pos, *coord_rot;
+    tank1_t *tank1_o;
+    tank2_t *tank2_o;
+    tank_en_t *tank_en_o;
     int i, j;
 
     rdman = X_MB_rdman(mb_rt);
@@ -175,41 +336,25 @@
 	}
     }
 
-    tank_rt->tank1 = tank1_new(rdman, rdman->root_coord);
-    CHANGE_POS(tank_rt->tank1, 5 * 50, 11 * 50);
-    tank_rt->tank2 = tank2_new(rdman, rdman->root_coord);
-    CHANGE_POS(tank_rt->tank2, 10 * 50, 11 * 50);
+    make_elf_coords(rdman, &coord_pos, &coord_rot, &coord_center);
+    tank1_o = tank1_new(rdman, coord_center);
+    tank_rt->tank1 = tank_new(coord_pos, coord_rot, 5, 11, mb_rt);
+    tank_rt->tank1_o = tank1_o;
+
+    make_elf_coords(rdman, &coord_pos, &coord_rot, &coord_center);
+    tank2_o = tank2_new(rdman, coord_center);
+    tank_rt->tank2 = tank_new(coord_pos, coord_rot, 10, 11, mb_rt);
+    tank_rt->tank2_o = tank2_o;
+
     for(i = 0; i < 3; i++) {
-	tank_rt->tank_enemies[i] = tank_en_new(rdman, rdman->root_coord);
-	CHANGE_POS(tank_rt->tank_enemies[i], (2 + i * 3) * 50, 0);
+	make_elf_coords(rdman, &coord_pos, &coord_rot, &coord_center);
+	tank_en_o = tank_en_new(rdman, coord_center);
+	tank_rt->tank_enemies[i] = tank_new(coord_pos, coord_rot,
+					    i * 3 + 3, 0, mb_rt);
+	tank_rt->tank_enemies_o[i] = tank_en_o;
     }
     tank_rt->n_enemy = i;
 
-    tank_rt->tank1_progm = mb_progm_new(4, rdman);
-
-    MB_TIMEVAL_SET(&start, 1, 0);
-    MB_TIMEVAL_SET(&playing, 3, 0);
-    word = mb_progm_next_word(tank_rt->tank1_progm, &start, &playing);
-
-    mb_shift_new(0, -150, tank_rt->tank1->root_coord, word);
-    mb_shift_new(0, -150, tank_rt->tank2->root_coord, word);
-
-    MB_TIMEVAL_SET(&start, 5, 0);
-    MB_TIMEVAL_SET(&playing, 3, 0);
-    word = mb_progm_next_word(tank_rt->tank1_progm, &start, &playing);
-
-    mb_shift_new(0, 150, tank_rt->tank1->root_coord, word);
-    mb_shift_new(0, 150, tank_rt->tank2->root_coord, word);
-
-    /* Free program after program completed. */
-    comp_sub = mb_progm_get_complete(tank_rt->tank1_progm);
-    factory = rdman_get_ob_factory(rdman);
-    subject_add_observer(factory, comp_sub, free_progm_handler, tank_rt);
-
-    tman = X_MB_tman(mb_rt);
-    get_now(&mbtv);
-    mb_progm_start(tank_rt->tank1_progm, tman, &mbtv);
-
     init_keyboard(tank_rt);
 }
 
--- a/src/X_supp.c	Tue Sep 16 21:23:34 2008 +0800
+++ b/src/X_supp.c	Wed Sep 17 01:30:25 2008 +0800
@@ -489,3 +489,10 @@
 mb_tman_t *X_MB_tman(X_MB_runtime_t *xmb_rt) {
     return xmb_rt->tman;
 }
+
+ob_factory_t *X_MB_ob_factory(X_MB_runtime_t *xmb_rt) {
+    ob_factory_t *factory;
+
+    factory = rdman_get_ob_factory(xmb_rt->rdman);
+    return factory;
+}
--- a/src/X_supp.h	Tue Sep 16 21:23:34 2008 +0800
+++ b/src/X_supp.h	Wed Sep 17 01:30:25 2008 +0800
@@ -29,5 +29,6 @@
 extern subject_t *X_MB_kbevents(X_MB_runtime_t *xmb_rt);
 extern redraw_man_t *X_MB_rdman(X_MB_runtime_t *xmb_rt);
 extern mb_tman_t *X_MB_tman(X_MB_runtime_t *xmb_rt);
+extern ob_factory_t *X_MB_ob_factory(X_MB_runtime_t *xmb_rt);
 
 #endif
--- a/src/animate.c	Tue Sep 16 21:23:34 2008 +0800
+++ b/src/animate.c	Wed Sep 17 01:30:25 2008 +0800
@@ -332,6 +332,7 @@
 }
 
 void mb_progm_abort(mb_progm_t *progm, mb_tman_t *tman) {
+    /*! \todo Make sure abort release resources. */
 }
 
 /*! \brief Return event subject for completion of a program.
--- a/src/tools.h	Tue Sep 16 21:23:34 2008 +0800
+++ b/src/tools.h	Wed Sep 17 01:30:25 2008 +0800
@@ -1,7 +1,6 @@
 #ifndef __TOOLS_H_
 #define __TOOLS_H_
 
-
 typedef struct _elmpool elmpool_t;
 
 extern elmpool_t *elmpool_new(int elm_sz, int inc_num);
@@ -64,6 +63,8 @@
     } while(0)
 
 
+#include <stdlib.h>
+
 #define O_ALLOC(type) ((type *)malloc(sizeof(type)))
 
 #define OFFSET(type, mem) (((void *)&((type *)NULL)->mem) - NULL)