Mercurial > MadButterfly
comparison examples/tank/enemy.c @ 1100:fb79175e6cc3
Add AI for enemy tanks
author | Thinker K.F. Li <thinker@codemud.net> |
---|---|
date | Sun, 05 Dec 2010 12:23:29 +0800 |
parents | |
children | dbea3e42bf93 |
comparison
equal
deleted
inserted
replaced
1096:c18ad321844d | 1100:fb79175e6cc3 |
---|---|
1 #include <stdio.h> | |
2 #include <stdlib.h> | |
3 #include <string.h> | |
4 #include "tank.h" | |
5 | |
6 struct _enemy { | |
7 tank_rt_t *tank_rt; | |
8 tank_t *tank; | |
9 int memory[4]; | |
10 }; | |
11 typedef struct _enemy enemy_t; | |
12 | |
13 /* \brief Fire and move to the target tank if they are in a row or column. | |
14 */ | |
15 static int | |
16 try_fire(tank_t *me, tank_t *target, tank_rt_t *tank_rt) { | |
17 int x, y; | |
18 int *tracer = NULL; | |
19 int target_value; | |
20 int target_dir; | |
21 | |
22 if(me->map_x == target->map_x) { /* In a row */ | |
23 tracer = &y; | |
24 target_value = target->map_y; | |
25 if(me->map_y < target->map_y) | |
26 target_dir = TD_DOWN; | |
27 else | |
28 target_dir = TD_UP; | |
29 } | |
30 if(me->map_y == target->map_y) { /* In a column */ | |
31 tracer = &x; | |
32 target_value = target->map_x; | |
33 if(me->map_x < target->map_x) | |
34 target_dir = TD_RIGHT; | |
35 else | |
36 target_dir = TD_LEFT; | |
37 } | |
38 | |
39 if(tracer == NULL) | |
40 return 0; /* Not in a row or column */ | |
41 | |
42 /* Check obstacles between tanks */ | |
43 x = me->map_x; | |
44 y = me->map_y; | |
45 if(*tracer < target_value) { | |
46 while(++*tracer < target_value) { | |
47 if(map[y][x] != MUD) | |
48 break; | |
49 } | |
50 } else { | |
51 while(--*tracer > target_value) { | |
52 if(map[y][x] != MUD) | |
53 break; | |
54 } | |
55 } | |
56 | |
57 if(*tracer == target_value) { /* No any obstacle between tanks */ | |
58 /* Fire and move to target */ | |
59 if(me->direction == target_dir && me->bullet == NULL) | |
60 tank_fire_bullet(tank_rt, me); | |
61 tank_move(me, target_dir, tank_rt); | |
62 return 1; | |
63 } | |
64 | |
65 return 0; /* Find one or more obstacles */ | |
66 } | |
67 | |
68 #define NOTHING 0 | |
69 #define SOMETHING 1 | |
70 | |
71 static void | |
72 move_tank(enemy_t *enemy, tank_rt_t *tank_rt) { | |
73 tank_t *me; | |
74 tank_t **tanks, *tank; | |
75 static const int shift_xy[4][2] = { | |
76 {1, 0}, {0, 1}, | |
77 {-1, 0}, {0, -1}}; | |
78 int status[4]; | |
79 int x, y; | |
80 int i, tank_i; | |
81 int dir, chk_dir; | |
82 int possibles; | |
83 int which_dir; | |
84 | |
85 me = enemy->tank; | |
86 tanks = tank_rt->tanks; | |
87 | |
88 /* Collect status */ | |
89 for(i = 0; i < 4; i++) { | |
90 x = me->map_x + shift_xy[i][0]; | |
91 y = me->map_y + shift_xy[i][1]; | |
92 | |
93 /* Check obstacles */ | |
94 if(x == -1 || y == -1 || x >= MAP_W || y >= MAP_H) { | |
95 /* Out of range */ | |
96 status[i] = SOMETHING; | |
97 continue; | |
98 } | |
99 if(map[y][x] == MUD) | |
100 status[i] = NOTHING; | |
101 else | |
102 status[i] = SOMETHING; | |
103 | |
104 /* Check tanks */ | |
105 for(tank_i = 0; tank_i < tank_rt->n_tanks; tank_i++) { | |
106 tank = tanks[tank_i]; | |
107 if(tank->map_x == x && tank->map_y == y) { | |
108 status[i] = SOMETHING; | |
109 break; | |
110 } | |
111 } | |
112 } | |
113 | |
114 /* Try the same direction if status is not changed. */ | |
115 for(i = 0; i < 4; i++) { | |
116 if(status[i] != enemy->memory[i]) | |
117 break; | |
118 } | |
119 if(i == 4) { /* Status is not changed */ | |
120 tank_move(me, me->direction, tank_rt); | |
121 return; | |
122 } | |
123 | |
124 memcpy(enemy->memory, status, sizeof(int) * 4); | |
125 | |
126 /* Check possible directions except backward. */ | |
127 switch(me->direction) { | |
128 case TD_UP: | |
129 dir = 3; | |
130 break; | |
131 case TD_RIGHT: | |
132 dir = 0; | |
133 break; | |
134 case TD_DOWN: | |
135 dir = 1; | |
136 break; | |
137 case TD_LEFT: | |
138 dir = 2; | |
139 break; | |
140 } | |
141 | |
142 possibles = 0; | |
143 for(i = 0; i < 3; i++) { | |
144 chk_dir = (dir - 1 + i) % 4; | |
145 if(status[chk_dir] == NOTHING) | |
146 possibles++; | |
147 } | |
148 | |
149 if(possibles == 0) { /* Only can move backward */ | |
150 switch(me->direction) { | |
151 case TD_UP: | |
152 tank_move(me, TD_DOWN, tank_rt); | |
153 break; | |
154 case TD_RIGHT: | |
155 tank_move(me, TD_LEFT, tank_rt); | |
156 break; | |
157 case TD_DOWN: | |
158 tank_move(me, TD_UP, tank_rt); | |
159 break; | |
160 case TD_LEFT: | |
161 tank_move(me, TD_RIGHT, tank_rt); | |
162 break; | |
163 } | |
164 return; | |
165 } | |
166 | |
167 which_dir = rand() % possibles; | |
168 for(i = 0; i < 3; i++) { | |
169 chk_dir = (dir - 1 + i) % 4; | |
170 if(status[chk_dir] == NOTHING) { | |
171 if(which_dir == 0) | |
172 break; | |
173 which_dir--; | |
174 } | |
175 } | |
176 switch(chk_dir) { | |
177 case 0: | |
178 tank_move(me, TD_RIGHT, tank_rt); | |
179 break; | |
180 case 1: | |
181 tank_move(me, TD_DOWN, tank_rt); | |
182 break; | |
183 case 2: | |
184 tank_move(me, TD_LEFT, tank_rt); | |
185 break; | |
186 case 3: | |
187 tank_move(me, TD_UP, tank_rt); | |
188 break; | |
189 } | |
190 } | |
191 | |
192 static void | |
193 _drive_enemy_tank(enemy_t *enemy) { | |
194 tank_rt_t *tank_rt; | |
195 tank_t *me, *tank1, *tank2; | |
196 int r; | |
197 | |
198 tank_rt = enemy->tank_rt; | |
199 tank1 = tank_rt->tank1; | |
200 tank2 = tank_rt->tank2; | |
201 me = enemy->tank; | |
202 | |
203 r = try_fire(me, tank1, tank_rt); | |
204 if(r) | |
205 return; | |
206 r = try_fire(me, tank2, tank_rt); | |
207 if(r) | |
208 return; | |
209 | |
210 move_tank(enemy, tank_rt); | |
211 } | |
212 | |
213 static enemy_t *enemies = NULL; | |
214 static mb_timer_man_t *timer_man; | |
215 | |
216 /*! \brief Drive every enemy tanks. | |
217 */ | |
218 static void | |
219 enemy_tank_driver(int hdl, const mb_timeval_t *tmo, | |
220 const mb_timeval_t *now, void *data) { | |
221 tank_rt_t *tank_rt = (tank_rt_t *)data; | |
222 int n_enemy; | |
223 mb_timeval_t timeout, addend; | |
224 int i; | |
225 | |
226 n_enemy = tank_rt->n_enemy; | |
227 for(i = 0; i < n_enemy; i++) { | |
228 _drive_enemy_tank(enemies + i); | |
229 } | |
230 | |
231 get_now(&timeout); | |
232 MB_TIMEVAL_SET(&addend, 0, 300000); | |
233 MB_TIMEVAL_ADD(&timeout, &addend); | |
234 mb_timer_man_timeout(timer_man, &timeout, enemy_tank_driver, tank_rt); | |
235 } | |
236 | |
237 /*! \brief Start a timer for enemy tank driver. | |
238 */ | |
239 static void | |
240 start_enemy_tank_timer(tank_rt_t *tank_rt) { | |
241 mb_timeval_t timeout, addend; | |
242 | |
243 timer_man = mb_runtime_timer_man(tank_rt->mb_rt); | |
244 | |
245 get_now(&timeout); | |
246 MB_TIMEVAL_SET(&addend, 0, 300000); | |
247 MB_TIMEVAL_ADD(&timeout, &addend); | |
248 mb_timer_man_timeout(timer_man, &timeout, enemy_tank_driver, tank_rt); | |
249 } | |
250 | |
251 void | |
252 init_enemies(tank_rt_t *tank_rt) { | |
253 int n_enemy; | |
254 tank_t **tank_enemies; | |
255 tank_t *tank; | |
256 int i, j; | |
257 | |
258 n_enemy = tank_rt->n_enemy; | |
259 tank_enemies = tank_rt->tank_enemies; | |
260 | |
261 enemies = (enemy_t *)malloc(sizeof(enemy_t) * n_enemy); | |
262 | |
263 for(i = 0; i < n_enemy; i++) { | |
264 tank = tank_enemies[i]; | |
265 enemies[i].tank_rt = tank_rt; | |
266 enemies[i].tank = tank; | |
267 for(j = 0; j < 4; j++) | |
268 enemies[i].memory[j] = SOMETHING; | |
269 } | |
270 | |
271 start_enemy_tank_timer(tank_rt); | |
272 } |