diff examples/tank/tank_main.c @ 154:6ce68c1f7405

Tank can fire bullet. 1. Add the redraw subject on redraw_man_t. 2. mb_c_source.m4 & mb_c_header.m4 are changed to free & remove shapes. 3. Add rdman_coord_subtree_free() to remove a subtree of coords. 4. Fix bug of rdman_remove_shape().
author Thinker K.F. Li <thinker@branda.to>
date Tue, 30 Sep 2008 02:44:06 +0800
parents 9870b049b7f6
children 6749f6639924
line wrap: on
line diff
--- a/examples/tank/tank_main.c	Sat Sep 27 02:40:42 2008 +0800
+++ b/examples/tank/tank_main.c	Tue Sep 30 02:44:06 2008 +0800
@@ -40,17 +40,32 @@
  * \brief Tank elf module provides control functions of tanks in game.
  * @{
  */
+struct _tank_bullet {
+    redraw_man_t *rdman;
+    coord_t *coord_pos;
+    coord_t *coord_rot;
+    bullet_t *bullet_obj;
+    int start_map_x, start_map_y;
+    int direction;
+    mb_progm_t *progm;
+    mb_timeval_t start_time;
+    observer_t *ob_redraw;
+};
+typedef struct _tank_bullet tank_bullet_t;
+enum { BU_UP = 0, BU_RIGHT, BU_DOWN, BU_LEFT };
+
 struct _tank {
     coord_t *coord_pos;		/*!< \brief coordinate for position */
     coord_t *coord_rot;		/*!< \brief coordinate for rotation */
+    coord_t *coord_center;
     int map_x, map_y;
     int direction;
     mb_progm_t *progm;
+    tank_bullet_t *bullet;
 };
 typedef struct _tank tank_t;
 enum { TD_UP = 0, TD_RIGHT, TD_DOWN, TD_LEFT };
 
-
 /* @} */
 
 typedef struct _tank_rt tank_rt_t;
@@ -92,6 +107,7 @@
     tank->map_y = map_y;
     tank->direction = TD_UP;
     tank->progm = NULL;
+    tank->bullet = NULL;
 
     memset(coord_pos->matrix, 0, sizeof(co_aix[6]));
     coord_pos->matrix[0] = 1;
@@ -233,6 +249,174 @@
 
 /* @} */
 
+/*! \brief Make coord objects for bullet elfs. */
+static void make_bullet_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] = -5;
+    (*coord_center)->matrix[5] = +15;
+    rdman_coord_changed(rdman, *coord_center);
+}
+
+static tank_bullet_t *tank_bullet_new(redraw_man_t *rdman,
+				      int map_x, int map_y,
+				      int direction) {
+    tank_bullet_t *bullet;
+    coord_t *coord_center;
+    co_aix *matrix;
+    static float _sins[] = { 0, 1, 0, -1};
+    static float _coss[] = { 1, 0, -1, 0};
+    float _sin, _cos;
+
+    bullet = O_ALLOC(tank_bullet_t);
+    bullet->rdman = rdman;
+
+    make_bullet_elf_coords(rdman, &bullet->coord_pos,
+			   &bullet->coord_rot,
+			   &coord_center);
+    bullet->bullet_obj = bullet_new(rdman, coord_center);
+    
+    bullet->start_map_x = map_x;
+    bullet->start_map_y = map_y;
+    bullet->direction = direction;
+    bullet->progm = NULL;
+
+    matrix = bullet->coord_pos->matrix;
+    matrix[2] = map_x * 50;
+    matrix[5] = map_y * 50;
+    rdman_coord_changed(rdman, bullet->coord_pos);
+
+    _sin = _sins[direction];
+    _cos = _coss[direction];
+    matrix = bullet->coord_rot->matrix;
+    matrix[0] = _cos;
+    matrix[1] = -_sin;
+    matrix[3] = _sin;
+    matrix[4] = _cos;
+
+    return bullet;
+}
+
+static void tank_bullet_free(tank_bullet_t *bullet) {
+    bullet_free(bullet->bullet_obj);
+    rdman_coord_subtree_free(bullet->rdman, bullet->coord_pos);
+}
+
+static void bullet_go_out_map_and_redraw(event_t *event, void *arg) {
+    tank_t *tank = (tank_t *)arg;
+    tank_bullet_t *bullet;
+    ob_factory_t *factory;
+    subject_t *redraw;
+
+    bullet = tank->bullet;
+    mb_progm_free(bullet->progm);
+    rdman_force_clean(bullet->rdman);
+    factory = rdman_get_ob_factory(bullet->rdman);
+    redraw = rdman_get_redraw_subject(bullet->rdman);
+    subject_remove_observer(factory, redraw, bullet->ob_redraw);
+    tank_bullet_free(tank->bullet);
+    tank->bullet = NULL;
+}
+
+static void bullet_go_out_map(event_t *event, void *arg) {
+    tank_t *tank = (tank_t *)arg;
+    tank_bullet_t *bullet;
+    redraw_man_t *rdman;
+    subject_t *redraw;
+    ob_factory_t *factory;
+    
+    /*! \todo Simplify the procdure of using observer pattern. */
+    bullet = tank->bullet;
+    rdman = bullet->rdman;
+    factory = rdman_get_ob_factory(rdman);
+    redraw = rdman_get_redraw_subject(rdman);
+    bullet->ob_redraw =
+	subject_add_observer(factory, redraw,
+			     bullet_go_out_map_and_redraw, tank);
+}
+
+static void tank_fire_bullet(tank_rt_t *tank_rt, tank_t *tank) {
+    X_MB_runtime_t *xmb_rt;
+    redraw_man_t *rdman;
+    int map_x, map_y;
+    int shift_x, shift_y;
+    int shift_len;
+    int dir;
+    tank_bullet_t *bullet;
+    mb_progm_t *progm;
+    mb_word_t *word;
+    mb_action_t *act;
+    mb_timeval_t start, playing;
+    mb_timeval_t now;
+    ob_factory_t *factory;
+    mb_tman_t *tman;
+    subject_t *subject;
+    static int map_xy_adj[][2] = {{0, -1}, {1, 0}, {0, 1}, {-1, 0}};
+
+    if(tank->bullet != NULL)
+	return;
+
+    xmb_rt = tank_rt->mb_rt;
+    rdman = X_MB_rdman(xmb_rt);
+    tman = X_MB_tman(xmb_rt);
+
+    dir = tank->direction;
+    map_x = tank->map_x + map_xy_adj[dir][0];
+    map_y = tank->map_y + map_xy_adj[dir][1];
+    tank->bullet = tank_bullet_new(rdman, map_x, map_y, dir);
+    bullet = tank->bullet;
+
+    switch(dir) {
+    case TD_UP:
+	shift_len = map_y + 1;
+	shift_x = 0;
+	shift_y = -shift_len * 50;
+	break;
+    case TD_RIGHT:
+	shift_len = 16 - map_x;
+	shift_x = shift_len * 50;
+	shift_y = 0;
+	break;
+    case TD_DOWN:
+	shift_len = 12 - map_y;
+	shift_x = 0;
+	shift_y = shift_len * 50;
+	break;
+    case TD_LEFT:
+	shift_len = map_x + 1;
+	shift_x = -shift_len * 50;
+	shift_y = 0;
+	break;
+    }
+
+    progm = mb_progm_new(2, rdman);
+    MB_TIMEVAL_SET(&start, 0, 0);
+    MB_TIMEVAL_SET(&playing, shift_len / 4, (shift_len % 4) * 250000);
+    word = mb_progm_next_word(progm, &start, &playing);
+    act = mb_shift_new(shift_x, shift_y, bullet->coord_pos, word);
+    bullet->progm = progm;
+    
+    subject = mb_progm_get_complete(progm);
+    factory = rdman_get_ob_factory(rdman);
+    subject_add_observer(factory, subject, bullet_go_out_map, tank);
+
+    get_now(&now);
+    MB_TIMEVAL_CP(&bullet->start_time, &now);
+    mb_progm_start(progm, tman, &now);
+}
+
 #define CHANGE_POS(g, x, y) do {			\
 	(g)->root_coord->matrix[0] = 1.0;		\
 	(g)->root_coord->matrix[2] = x;			\
@@ -271,6 +455,7 @@
 	break;
 
     case 0x20:			/* space */
+	tank_fire_bullet(tank_rt, tank_rt->tank1);
 	break;
     case 0xff0d:		/* enter */
     default: