1 /*---------------------------------------------------------------------------*
2 Project: Dolphin/Revolution gx demo
3 File: smp-toy-anim.c
4
5 Copyright 1998-2006 Nintendo. All rights reserved.
6
7 These coded instructions, statements, and computer programs contain
8 proprietary information of Nintendo of America Inc. and/or Nintendo
9 Company Ltd., and are protected by Federal copyright law. They may
10 not be disclosed to third parties or copied or duplicated in any form,
11 in whole or in part, without the prior written consent of Nintendo.
12 *---------------------------------------------------------------------------*/
13
14 #include <demo.h>
15 #include "toy-stick.h"
16 #include "toy-anim.h"
17
18 #define WALLX_BOUNCE 0.6F
19 #define WALLZ_BOUNCE 0.5F
20 #define OUT_CORNER_BOUNCE 1.2F
21 #define IN_CORNER_BOUNCE 0.4F
22 #define SLOPE_ACCEL 1.01F
23
24 #define BALL_CSIZEX (BALL_SIZEX / 2.0F)
25 #define BALL_CSIZEZ (BALL_SIZEZ / 2.0F)
26
27 #define AX_SCALE 0.01F
28 #define AY_SCALE 0.01F
29 #define VX_FRICTION 0.999F
30 #define VY_FRICTION 0.999F
31
32 /*---------------------------------------------------------------------------*
33 Global variables
34 *---------------------------------------------------------------------------*/
35 /*
36 * Flags for collision
37 */
38 typedef enum
39 {
40 GO = 0,
41 NOGO = 1,
42 TELEPORT = 2,
43 LANDED = 4,
44 ONSLOPE = 8,
45 FLIPA = 16,
46 FLIPB = 32
47 } CollisionType;
48
49 /*
50 * Collision Symbol/Flag relationship
51 */
52 static u32 CollSymTab[][2]=
53 {
54 ' ',NOGO,
55 '.',GO,
56 'a',GO|FLIPA,
57 'b',GO|FLIPB,
58 '-',GO|LANDED,
59 '|',GO|ONSLOPE,
60 '<',GO|TELEPORT|ONSLOPE,
61 '>',GO|TELEPORT|ONSLOPE,
62 '\0',0
63 };
64
65 /*
66 * Collision Grid
67 *
68 * Two levels needed since bridges intersect. In order to make
69 * collision logic easier, sloped bridge is straight in collision grid
70 * and the ball is translated to the proper slope when drawing.
71 */
72 static unsigned char CollisionGrid[2][2*9][2*9] =
73 {
74 {
75 " ",
76 " ",
77 " ...aaaa.bbbb.. ",
78 " ...aaaa.bbbb.. ",
79 " .. .. .. ",
80 " .. .. .. ",
81 " .. .. .. ",
82 " .. .. .. ",
83 " .. ...... .. ",
84 " .. ...... .. ",
85 " .. .. .. ",
86 " .. .. .. ",
87 " .. .. .. ",
88 " .. .. .. ",
89 " ..bbbb.aaaa... ",
90 " ..bbbb.aaaa... ",
91 " ",
92 " "
93 },
94
95 {
96 " ",
97 " ",
98 " ..aaaa.bbbb... ",
99 " ..aaaa.bbbb... ",
100 " .. -- .. ",
101 " .. >> -- .. ",
102 " .. || .. ",
103 " .. || .. ",
104 " .. || .. ",
105 " .. || .. ",
106 " .. || .. ",
107 " .. || .. ",
108 " .. .. .. ",
109 " .. .. .. ",
110 " ...bbbb.aaaa.. ",
111 " ...bbbb.aaaa.. ",
112 " ",
113 " "
114 }
115 };
116
117
118 static Vec CurPos = {90.0F, 0.0F, 10.0F}; // current position
119 static u32 CurMask = 0; // current collision mask at center of sphere
120 static u32 Teleport = 0; // teleporting this frame
121
122
123
124 /*---------------------------------------------------------------------------*
125 Name: GetCurPos
126
127 Description: Get current position
128
129 Arguments: none
130
131 Returns: Vec, current position
132 *---------------------------------------------------------------------------*/
GetCurPos(void)133 Vec GetCurPos( void )
134 {
135 return(CurPos);
136 }
137
138 /*---------------------------------------------------------------------------*
139 Name: OnSlope
140
141 Description: Returns 1 if center of ball is currently on the sloped
142 bridge.
143
144 Arguments: none
145
146 Returns: u32, 1 = on slope, 0 = not on slope
147 *---------------------------------------------------------------------------*/
OnSlope(void)148 u32 OnSlope( void )
149 {
150 return(CurMask & ONSLOPE);
151 }
152
153 /*---------------------------------------------------------------------------*
154 Name: DoTeleport
155
156 Description: Returns 1 if ball will be teleported this tick
157
158 Arguments: none
159
160 Returns: u32, 1 = teleporting, 0 = not teleporting
161 *---------------------------------------------------------------------------*/
DoTeleport(void)162 u32 DoTeleport( void )
163 {
164 return(Teleport);
165 }
166
167 /*---------------------------------------------------------------------------*
168 Name: TestPoint
169
170 Description: Test point for collision
171
172 Arguments: curgrid which collision grid to test
173 x x coordinate to test
174 y y coordinate to test
175
176 Returns: collision mask at point, u32
177 *---------------------------------------------------------------------------*/
TestPoint(u32 curgrid,f32 x,f32 y)178 static u32 TestPoint( u32 curgrid, f32 x, f32 y )
179 {
180 s32 xt; // truncated x coordinate
181 s32 yt; // truncated y coordinate
182 u32 i;
183 u8 tilec;
184
185 // stay inside NOGO border
186 xt = (s32)((x + 20.0) / 10.0);
187 yt = (s32)((y + 20.0) / 10.0);
188
189 // clamp to table size
190 if (xt < 0) xt = 0;
191 if (xt > 17) xt = 17;
192 if (yt < 0) yt = 0;
193 if (yt > 17) yt = 17;
194
195 tilec = CollisionGrid[curgrid][yt][xt];
196
197 for (i = 0; CollSymTab[i][0]; i++)
198 {
199 if (CollSymTab[i][0]==tilec)
200 return(CollSymTab[i][1]);
201 }
202 return(0);
203 }
204
205 /*---------------------------------------------------------------------------*
206 Name: AnimTick
207
208 Description: React to collision. Computes next position and velocity.
209
210 Arguments: none
211
212 Returns: none
213 *---------------------------------------------------------------------------*/
AnimTick(void)214 void AnimTick( void )
215 {
216 static u32 curGrid = 0; // current collision grid
217 static Vec curVel = { 0.0F, 0.0F, 0.0F };
218 // four points to test collision against
219 static Vec offsets[4] = {{-BALL_CSIZEX, 0.0F, -BALL_CSIZEZ},
220 { BALL_CSIZEX, 0.0F, -BALL_CSIZEZ},
221 { BALL_CSIZEX, 0.0F, BALL_CSIZEZ},
222 {-BALL_CSIZEX, 0.0F, BALL_CSIZEZ}};
223 u32 i; // loop variable
224 u32 fullMask; // all flags
225 u32 wallMask = 0; // only GO/NOGO bits
226 Vec tp; // test point
227 Vec nextPos;
228 Vec nextVel;
229
230 // switch collision grids? test center point
231 CurMask = TestPoint(curGrid, CurPos.x, CurPos.z);
232 if (CurMask & FLIPA)
233 curGrid = 0;
234 else if (CurMask & FLIPB)
235 curGrid = 1;
236
237 // all points must be in teleport area in order to teleport
238 Teleport = TELEPORT;
239
240 // build collision detection mask
241 for (i = 0; i < 4; i++)
242 {
243 VECAdd(&CurPos, &curVel, &tp);
244 VECAdd(&tp, &offsets[i], &tp);
245 fullMask = TestPoint(curGrid, tp.x, tp.z);
246 Teleport &= fullMask & TELEPORT;
247 wallMask |= ((fullMask & NOGO) ? 1 : 0) << i;
248 }
249
250 // teleport to the bottom of the ramp
251 if (Teleport)
252 CurPos.x -= (CurPos.z - SLOPE_ZSTART) * SLOPE_SLOPE;
253
254 nextVel = curVel; // default
255
256 switch(wallMask)
257 {
258 case 0x3:
259 case 0xc: // reflect velocity z
260 nextVel.x = curVel.x;
261 nextVel.z = -curVel.z * WALLZ_BOUNCE;
262 break;
263
264 case 0x9:
265 case 0x6: // reflect velocity x
266 nextVel.x = -curVel.x * WALLX_BOUNCE;
267 nextVel.z = curVel.z;
268 break;
269
270 case 0x1:
271 if (curVel.x < 0.0F) nextVel.x = -curVel.x * OUT_CORNER_BOUNCE;
272 if (curVel.z < 0.0F) nextVel.z = -curVel.z * OUT_CORNER_BOUNCE;
273 break;
274
275 case 0x2:
276 if (curVel.x > 0.0F) nextVel.x = -curVel.x * OUT_CORNER_BOUNCE;
277 if (curVel.z < 0.0F) nextVel.z = -curVel.z * OUT_CORNER_BOUNCE;
278 break;
279
280 case 0x4:
281 if (curVel.x > 0.0F) nextVel.x = -curVel.x * OUT_CORNER_BOUNCE;
282 if (curVel.z > 0.0F) nextVel.z = -curVel.z * OUT_CORNER_BOUNCE;
283 break;
284
285 case 0x8:
286 if (curVel.x < 0.0F) nextVel.x = -curVel.x * OUT_CORNER_BOUNCE;
287 if (curVel.z > 0.0F) nextVel.z = -curVel.z * OUT_CORNER_BOUNCE;
288 break;
289
290 case 0x7:
291 case 0xb:
292 case 0xd:
293 case 0xe: // invert velocity
294 nextVel.x = -curVel.x * IN_CORNER_BOUNCE;
295 nextVel.z = -curVel.z * IN_CORNER_BOUNCE;
296 break;
297
298 case 0x0: // no collision
299 break;
300
301 default: // illegal case
302 OSReport("Illegal case in React()\n");
303 break;
304 }
305
306 if ((CurMask & ONSLOPE) && (nextVel.z < 0.0F))
307 nextVel.z *= SLOPE_ACCEL; // accelerate down slope
308
309 VECAdd(&CurPos, &nextVel, &nextPos);
310
311 CurPos = nextPos;
312 curVel = nextVel;
313 curVel.x += -GetAnalogX() * AX_SCALE;
314 curVel.z += GetAnalogY() * AY_SCALE;
315 curVel.x *= VX_FRICTION;
316 curVel.z *= VY_FRICTION;
317 }
318