home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Collection of Education
/
collectionofeducationcarat1997.iso
/
GAMES
/
CAROM10.ZIP
/
CAROMSRC.ZIP
/
BALLFULL.C
< prev
next >
Wrap
C/C++ Source or Header
|
1994-08-13
|
16KB
|
533 lines
/*
Copyright (c) 1994 Csaba Mßrkus. All rights reserved.
E-mail: ethcms@duna.ericsson.se
Addr.: H-9600 Sßrvßr, Szatmßr u. 4, Hungary
Permission to use, copy, modify, and distribute this software and its
documentation for any purpose, without fee, and without written agreement
is hereby granted, provided that the above copyright notice and the
following two paragraphs appear in all copies of this software.
IN NO EVENT SHALL THE AUTHOR BE LIABLE TO ANY PARTY FOR
DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE AUTHOR HAS
BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
THE AUTHOR DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
THE SOFTWARE PROVIDED HEREUNDER IS ON AN "AS IS" BASIS, AND THE AUTHOR HAS
NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS
OR MODIFICATIONS.
*/
/* File: ballfull.c
Purpose: This file emulates the physics of the balls.
*/
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <windows.h>
#include "ballfull.h"
#include "trigo.h"
extern HGLOBAL hglbShotHistory;
/* SQRT3
*/
#define SQRT3 1.732050808
/* sqrt(2.0/5.0), which is the vspeed/vrotation_on_surface ratio if
moving with the speed 'vspeed' and revolving with 'vrotation_on_surface'
surface speed represent the same energy.
*/
#define SQRT_2OVER5 0.632455532
/* Macro to convert a positive float number into an unsigned by muliplying
it with 16 and rounding:
*/
#define FIXED(x) ((unsigned) (floor((x) * FIXED_MULT + 0.5)))
ball_data ball[] = {
/* This is the cue ball of the first player: white ball:
*/
{ BOTTOMR_SPOT_X, BOTTOMR_SPOT_Y, /* Position */
BALL_RADIUS, BALL_MASS, /* Radius and mass */
"White", "Cue Ball #1", /* Colour and name */
0, 0, /* Speed and direction of moving */
0, 0, /* Speed and direction of rolling */
0 }, /* Speed of revolving */
/* This is the cue ball of the other player: white ball with spot:
*/
{ BOTTOMM_SPOT_X, BOTTOMM_SPOT_Y, /* Position */
BALL_RADIUS, BALL_MASS, /* Radius and mass */
"Yellow", "Cue Ball #1", /* Colour and name */
0, 0, /* Speed and direction of moving */
0, 0, /* Speed and direction of rolling */
0 }, /* Speed of revolving */
/* And this is the common ball: red ball:
*/
{ TOP_SPOT_X, TOP_SPOT_Y, /* Position */
BALL_RADIUS, BALL_MASS, /* Radius and mass */
"Red", "Cue Ball #1", /* Colour and name */
0, 0, /* Speed and direction of moving */
0, 0, /* Speed and direction of rolling */
0 } /* Speed of revolving */
};
/* Global variables used for recognizing the event of a "carom".
*/
int iscarom[N];
int cushion_counter;
/* Global variables to maintain the first collision:
*/
int no_collision;
int collision_first_ball;
/* develop_balls
This is the heart of the "biliardness" of the program.
*/
int develop_balls(ball_data *ball, int n, int cueball,
unsigned char *cush_beep,unsigned char *ball_beep)
{
int i, j, jj, collision;
float ox, oy, nx, ny, r;
unsigned a;
float dx, dy;
unsigned ca, ai, aj;
float vip, vio, vjp, vjo;
float mi, mj, vion, vjon;
float total_speed = 0;
float hv, vv;
float dist, cosa, sina, discr, t, t1, q;
/* No collision-beeps yet at this move:
*/
*cush_beep = *ball_beep = 0;
for (i=0; i<n; i++) {
/* Process ith ball: Compute its parameters at the next phase
*/
collision = 0;
r = ball[i].r;
a = ball[i].a;
ox = ball[i].x;
oy = ball[i].y;
cosa = tcos(a);
sina = tsin(a);
dist = (TIME_SLOT * ball[i].v) + r;
/* Check collision with other ball
*/
for (t = RIGHT - LEFT, jj = -1, j = 0; j < n; j++) {
if (j != i &&
fabs(dx = ball[j].x - ox) <= dist + ball[j].r &&
fabs(dy = ball[j].y - oy) <= dist + ball[j].r) {
q = dx * cosa + dy * sina;
discr = (q * q) -((dx * dx) + (dy * dy) -
(r + ball[j].r) * (r + ball[j].r));
if (discr > 0 && (t1 = q - sqrt(discr)) > 0 &&
t1 < dist - r && t1 < t) {
t = t1;
jj = j;
}
}
}
if (jj >= 0) {
j = jj;
/* Compute exact place of collision (nx,ny). This position, however,
may be outside of the valid area:
*/
nx = ox + (t * cosa);
ny = oy + (t * sina);
if (nx - r >= LEFT && nx + r <= RIGHT &&
ny - r >= BOTTOM && ny + r <= TOP) {
/* Place of collision is inside: mark that there is a collision,
develop ball to this position and analyse collision:
*/
/* Yes, there is a collision:
*/
(*ball_beep)++;
collision = 1;
ball[i].x = nx;
ball[i].y = ny;
/* Distances:
*/
dx = nx - ball[j].x;
dy = ny - ball[j].y;
/* Process first ball:
*/
ca = tatan2(dy, dx); /* Angle of collision line */
ai = ball[i].a - ca;
vip = ball[i].v * tsin(ai); /* This component remains */
vio = ball[i].v * tcos(ai); /* This component will exchange */
/* Process second ball:
*/
aj = ball[j].a - ca;
vjp = ball[j].v * tsin(aj); /* This component remains */
vjo = ball[j].v * tcos(aj); /* This component will exchange */
/* Check if they are really getting closer:
*/
if (vjo > vio) {
/* Yes, they were really getting closer.
Create new speed vectors. First ball:
*/
mi = ball[i].m;
mj = ball[j].m;
vion = (mi * vio + 2 * mj * vjo - mj * vio) / (mi + mj);
vjon = (mj * vjo + 2 * mi * vio - mi * vjo) / (mj + mi);
ball[i].v = sqrt((vip * vip) + (vion * vion));
if (ball[i].v > 0) {
ai = tatan2(vip, vion) + ca;
ball[i].a = ai;
}
/* Second ball:
*/
ball[j].v = sqrt((vjp * vjp) + (vjon * vjon));
if (ball[j].v > 0) {
aj = tatan2(vjp, vjon) + ca;
ball[j].a = aj;
}
/* If the cue ball is one of the two balls that
collide, the other ball must be signed to
have been collided with the cue ball. This is
important to recognize the event of a "carom".
Additionally, if this is the first collision,
store the id of the non-cueball. This is also
needed because the first carom of a frame must
be made from the red ball.
*/
if (i == cueball || j == cueball) {
iscarom[i] = 1;
iscarom[j] = 1;
if (no_collision) {
no_collision = 0;
collision_first_ball = i == cueball ? j : i;
}
}
}
}
}
/* Develop ball in straight line unless it has collided:
*/
if (!collision) {
ball[i].x += TIME_SLOT * ball[i].v * cosa;
ball[i].y += TIME_SLOT * ball[i].v * sina;
nx = ball[i].x;
ny = ball[i].y;
/* Check collision with cushion
*/
if ((nx - r <= LEFT) && (a > S_PI_2) && (a < 3 * S_PI_2)) {
/* Yes, there's a collision with the left cushion.
*/
/* Place ball next to cushion, mirror angle (direction) of moving.
*/
ball[i].y = oy + (ny - oy) * (ox - (LEFT + r)) / (ox - nx);
ball[i].x = LEFT + r;
nx = ball[i].x;
ny = ball[i].y;
ball[i].a = S_PI - ball[i].a;
#ifdef SPIN_REFLECTION
ball[i].sa = S_PI - ball[i].sa;
#else
ball[i].sv = 0;
#endif
/* Update rotation if there's any:
*/
if (ball[i].rv != 0) {
hv = ball[i].v * tcos(ball[i].a);
vv = ball[i].v * tsin(ball[i].a);
vv += ROTATION_CONVERT_RATIO * ball[i].rv * SQRT_2OVER5;
ball[i].v = sqrt((hv * hv) + (vv * vv));
ball[i].a = tatan2(vv, hv);
ball[i].rv -= ROTATION_CONVERT_RATIO * ball[i].rv;
}
(*cush_beep)++;
if ((i == cueball) &&
(iscarom[0] + iscarom[1] + iscarom[2] < 3)) {
/* !!! In this condition we assumed that there are
exactly 3 balls (N==3) !!!
*/
cushion_coun