3 define PI=3.14159265358979323846;
4 define BOX_TOLERANCE=0.5;
6 define max_version_code_supported=0;
7 define version_name="0.0";
8 //This string should be no longer than 15 characters
12 //Coordinates are in units of pixels
13 //Velocity is in units of pixels per frame
14 //A frame is defined as 1/LOGICAL_FPS seconds, or one iteration of g_frame()
16 define LOGICAL_FPS=512;
17 //is really 512, but this is for testing
18 //define DRAWN_FPS=60;
20 enum GameLineType {regular,speed,slow,decor};
21 enum GameFloorOrCeiling {floor,ceiling,both};
23 enum GameVehicleType {none, ball};
28 GameFloorOrCeiling floor_or_ceiling;
31 //complicated vehicles that can't be described by a single location/velocity need something
32 // so the camera will center on it.
37 void OnSerialize(IOChannel channel)
40 channel.Put(location);
41 channel.Put(velocity);
44 void OnUnserialize(IOChannel channel)
48 GameVehicleType vtype;
52 GameBall::OnUnserialize(class(GameBall), this, channel);
56 this = GameVehicle { };
61 channel.Get(location);
62 channel.Get(velocity);
65 virtual void Update(Game game);
67 class GameBall : GameVehicle {
73 double angle_velocity;
75 void OnSerialize(IOChannel channel)
77 GameVehicle::OnSerialize(channel);
79 channel.Put(elasticity);
81 channel.Put(angle_velocity);
84 void OnUnserialize(IOChannel channel)
87 GameVehicle::OnUnserialize(channel);
89 channel.Get(elasticity);
91 channel.Get(angle_velocity);
94 //support backtracing if ball is within box for line
95 void Update(Game game) {
96 //TODO: check for collision with other balls
98 BallLineReturn soonest = {INF,{0,0}};
99 GameLine *soonest_line;
101 BallLineReturn bl_result;
102 uint max_collisions_per_frame=16;
105 double x0 = location.x - radius;
106 double y0 = location.y - radius;
107 double x1 = location.x + radius;
108 double y1 = location.y + radius;
118 game.FindLinesInBox(x0,y0,x1,y1, true);
120 for (i:game.linesInBox)
124 //TODO: check for floor/ceiling/decor
127 vb = {i.x1-i.x0,i.y1-i.y0};
128 vp = {i.x0-location.x,i.y0-location.y};
130 BallLineCollide(bl_result,radius,velocity,vb,vp);
133 //TODO: Find a better way to deal with the teleport problem when ball sits in weird situations
134 // Currently, I'm just filtering out outrageously low negative ts (negative ts don't exactly make sense, but they keep the ball from falling through lines)
135 //if (t<=time_left && t<soonest.t) {
136 if (t>-100.0 && t<=time_left && t<soonest.t) {
139 //printf("Collide with line %ld Q=(%f,%f,%f,%f) L=(%f,%f,%f,%f)\n", soonest_line-game.lines.array, x0,y0,x1,y1, );
144 Vector2D v_parallel, v_normal;
145 Vector2D v_parallel_normalized;
147 double elasticity_cur;
148 bool clockcont = false; //if positive angle velocity contributes to speed toward parallel of ball velocity
150 //printf("COLLIDE! (location=(%f, %f), p = <%f, %f>)\n",location.x, location.y, soonest_line->x0-location.x,soonest_line->y0-location.y);
153 // PrintLn("Negative time ", soonest.t);
154 //if (soonest.t>=0.0 && soonest.t<0.01)
155 // PrintLn("Negative time after subtract", soonest.t);
157 soonest.t-=0.01; //don't fall all the way in, or we'll have multiple collisions after this
159 //compensate for the time taken to get to the collision
160 location.x += velocity.x*soonest.t;
161 location.y += velocity.y*soonest.t;
162 time_left -= soonest.t;
164 //decompose into parallel and normal vectors (with relation to line of collision)
165 v_parallel = soonest.s;
166 dp = DotProduct(velocity, soonest.s);
169 v_normal.Sub(velocity, v_parallel);
171 /* //elastic collision: v' = vp-e*vn;
172 v_normal.x *= elasticity;
173 v_normal.y *= elasticity;
174 velocity.Sub(v_parallel,v_normal);
177 if (v_normal.y!=0.0 && v_parallel.x!=0.0) {
178 if ((v_normal.y>0 && v_parallel.x>0) || (v_normal.y<0 && v_parallel.x<0))
181 if ((v_normal.x<0 && v_parallel.y>0) || (v_normal.x>0 && v_parallel.y<0))
185 //we need a reference to this before v_normal gets zeroed if elasticity_cur is 0.
186 v_parallel_normalized = {-v_normal.y, v_normal.x};
187 v_parallel_normalized.Normalize();
189 elasticity_cur = -elasticity;
190 if (soonest_line->type != regular)
191 elasticity_cur *= 0.3; //to make speed lines easier to use
193 //elastic collision: multiply the normal by negative elasticity
194 v_normal.x *= elasticity_cur;
195 v_normal.y *= elasticity_cur;
197 //an attempt at the effects of angular velocity and friction
199 double gs; //goal velocity squared
200 double g; //goal velocity
201 double gsfa; //goal velocity contributed by angular velocity
202 bool gneg = false; //g is negative
203 double dampener = 0.01;
205 gs = 3*DotProduct(v_parallel,v_parallel);
206 gsfa = 2*angle_velocity*angle_velocity*PI*radius*radius*radius;
208 if (angle_velocity<0)
214 gs /= 3+(2*PI*radius*dampener);
222 g *= 0.9993; //energy loss
223 v_parallel = v_parallel_normalized;
225 v_parallel.x = -v_parallel.x;
226 v_parallel.y = -v_parallel.y;
231 angle_velocity = g/radius;
233 angle_velocity = -g/radius;
236 velocity.Add(v_parallel, v_normal);
238 //at last, we'll handle speed/slow lines by simply changing the angular velocity
239 if (soonest_line->type == slow)
240 angle_velocity -= 0.001;
241 else if (soonest_line->type == speed)
242 angle_velocity += 0.001;
245 location.Add(location,velocity);
246 if (!max_collisions_per_frame--)
248 } while (soonest_line);
249 velocity.Add(velocity, game.gravity);
250 angle += angle_velocity;
251 if (angle<0 || angle>=2*3.1415926535897932384626)
252 angle = fmod(angle,2*3.1415926535897932384626); //prevents angle from accumulating an insanely high or low value
259 Array<GameLine> lines {};
260 Array<GameLine> linesInBox {};
261 Array<uint> linesInBoxIndices {};
262 Array<GameVehicle> vehicles {};
265 uint version_code; //which version of OpenRider to act like
267 version_code = max_version_code_supported;
269 ~Game() { FreeAll(); }
273 //we don't need to worry about the other things because they are automatically freed
276 void OnUnserialize(IOChannel channel)
280 channel.Get(gravity);
282 channel.Get(vehicles);
285 void OnSerialize(IOChannel channel)
287 channel.Put(gravity);
289 channel.Put(vehicles);
293 gravity = {0, 0.002};
299 version_code = max_version_code_supported;
301 void ResetBall(void) {
306 vehicles[0] = GameBall {
307 location = {-300+32,-200+32};
308 velocity = {0.0, 0.0};
310 elasticity = 0.3; //if this is 0, the ball rolls the wrong way for some reason
312 angle_velocity = 0.0;
323 void FrameMulti(uint count) {
327 //parameters are the camera's field of vision or bigger
328 void DrawFrame(double x0, double y0, double x1, double y1) {
329 FindLinesInBox(x0,y0,x1,y1, true);
334 DrawBall(master, (GameBall)i);
338 void AddLineSeries(double c_array[],uint count) {
344 lines.Add({c[0],c[1],c[2],c[3],regular,floor});
347 //returns true if any lines were erased
348 bool EraseAtBox(double x0, double y0, double x1, double y1) {
350 FindLinesInBox(x0,y0,x1,y1, false);
351 //the linesInBoxIndices array is assumed to be sorted
352 for (i:linesInBoxIndices) {
354 //FindLinesInBox only gives us an estimate of lines in the box, so we will do a finer check here
355 if (!LineReallyInBox(lines[i].x0, lines[i].y0, lines[i].x1, lines[i].y1, x0,y0,x1,y1))
357 //lines.Remove((IteratorPointer)(lines.array+i-erasures));
358 memmove(lines.array+r, lines.array+r+1, (lines.size-r-1)*sizeof(*lines.array));
361 lines.size -= erasures;
365 //used for efficiency, not for precision
366 //This only checks for lines in box by looking at the bounding boxes of lines in question
367 void FindLinesInBox(double x0, double y0, double x1, double y1, bool tolerance) {
368 #define Swap(a,b) {tmp=a;a=b;b=tmp;}
380 linesInBox.minAllocSize = lines.count;
381 linesInBoxIndices.minAllocSize = lines.count;
382 linesInBox.RemoveAll();
383 linesInBoxIndices.RemoveAll();
385 double lx0=i.x0,ly0=i.y0,lx1=i.x1,ly1=i.y1;
390 if (lx0>x1 || ly0>y1 || x0>lx1 || y0>ly1)
393 linesInBoxIndices.Add(&i - lines.array);
398 virtual void Instance::DrawLine(GameLine line);
399 virtual void Instance::DrawBall(GameBall ball);
405 void g_frame_multi(uint count);
406 void g_draw_frame(void);
408 void g_add_line(double x0,double y0,double x1,double y1,char type,char floor_or_ceiling);