File: wall.C

package info (click to toggle)
flying 6.20-6
  • links: PTS
  • area: main
  • in suites: etch, etch-m68k, lenny
  • size: 752 kB
  • ctags: 1,873
  • sloc: cpp: 10,966; makefile: 189
file content (256 lines) | stat: -rw-r--r-- 6,038 bytes parent folder | download | duplicates (4)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
#ifndef _global_h
#	include "global.h"
#endif

#ifndef _wall_h
#	include "wall.h"
#endif
#ifndef _ball_h
#	include "ball.h"
#endif
#ifndef _game_h
#	include "game.h"
#endif

//
// -------------------------------------------------------------------------
//   class Wall:  Begrenzungs-Objekt
// -------------------------------------------------------------------------
//

Wall::Wall( double x1, double y1, double x2, double y2 )
: p1(x1,y1), p2(x2,y2)
{
	d  = p2-p1;               	// Richtungsvektor der Wand
	ds = d.TurnLeft().Norm1();	// normierter senkrechter Vektor zur Richtung
}
Wall::Wall( const Vec2 &v1, const Vec2 &v2 )
: p1(v1), p2(v2)
{
	d  = p2-p1;               	// Richtungsvektor der Wand
	ds = d.TurnLeft().Norm1();	// normierter senkrechter Vektor zur Richtung
}


Wall::~Wall() { }

void Wall::Info() {
	printf( "%02d: Wall:       %08lx: (%4.1f,%4.1f) - (%4.1f,%4.1f)\n",
				Object::id, (unsigned long)this,
				(double)p1.X(), (double)p1.Y(),
				(double)p2.X(), (double)p2.Y() );
}

Real Wall::HitFromBall( Ball *b ) {
	if (b->IsIdle())		return MAX_TIME;

#if (EasyWall)
Real		t1, l1;
Vec2	direct_v;
Vec2	balls_edge;

	b->V().Split( ds, &direct_v );
	if (direct_v.X()==0.0&&direct_v.Y()==0.0)	return NO_HIT;
	balls_edge = b->P() + direct_v.Norm1()*b->R();

	if (Vec2::Solve( p1, d, balls_edge, direct_v, &t1 ))	return NO_HIT;
#if (ABORT_CALC_WALL)
	if	( t1>b->collision_time-current_time+EPS )				return NOT_REACHABLE;
#endif

	if (t1<-EPS)					return NO_HIT;
	if (d.X()!=0.0) {
		l1 = ( balls_edge.X() + t1*b->VX() - p1.X() ) / d.X();
	}
	else if (d.Y()!=0.0) {
		l1 = ( balls_edge.Y() + t1*b->VY() - p1.Y() ) / d.Y();
	}
	else 								return NO_HIT;	// Wand ohne Lnge ??
	if ( l1>=0.0 && l1<=1.0 )	return t1;
	return NO_HIT;

#else
Real	A,B,C;	// Hilfsvariablen
Real	l1, t1;	// erste Lsung des Gleichungssystems
Real	l2, t2;	// zweite Lsung des Gleichungssystems

//
// erste Variante des Gleichungssystems, nur lsbar wenn VX() ungleich 0
//
	if ( d.X() != 0.0 ) {

		A = b->VY() - ( b->VX()/d.X()*d.Y() );
		if ( A!=0.0 )	{

			B = p1.Y()-b->PY() + ( b->PX()-p1.X() )/d.X()*d.Y();
			C = b->R() * (ds.Y() - (ds.X()/d.X()*d.Y()));
	//
	// eine Kollision findet statt, wenn beide Zeiten grer/gleich 0
	//
			t1 = (B+C)/A;
			if ( t1<-EPS )		return NO_HIT;
			t2 = (B-C)/A;
			if ( t2<-EPS )		return NO_HIT;
	//
	// fr die kleinere Zeit mu l? zwischen 0 und 1 liegen
	//
			if ( t1<t2 ) {
#if (ABORT_CALC_WALL)
				if	( t1>b->collision_time-current_time+EPS ) {
					DBG2(AbortCalc,"    WallHit from %d to %d aborted.\n",b->Object::id,id);
					return NOT_REACHABLE;
				}
#endif
				l1 = ( b->PX() + t1*b->VX() - p1.X() - b->R()*ds.X() ) / d.X();
				if ( l1>=0.0 && l1<=1.0 )	return t1;
				else								return NO_HIT;
			}
			else {
#if (ABORT_CALC_WALL)
				if	( t2>b->collision_time-current_time+EPS ) {
					DBG2(AbortCalc,"    WallHit from %d to %d aborted.\n",b->Object::id,id);
					return NOT_REACHABLE;
				}
#endif
				l2 = ( b->PX() + t2*b->VX() - p1.X() + b->R()*ds.X() ) / d.X();
				if ( l2>=0.0 && l2<=1.0 )	return t2;
				else								return NO_HIT;
			}
		}
	}

//
// Zweite Variante des Gleichungssystems, nur lsbar, wenn VY() ungleich 0.
//
	if ( d.Y() != 0.0 ) {

		A = b->VX() - ( b->VY()/d.Y()*d.X() );
		if ( A!=0.0 )	{

			B = p1.X()-b->PX() + ( b->PY()-p1.Y() )/d.Y()*d.X();
			C = b->R() * (ds.X() - (ds.Y()/d.Y()*d.X()));
	//
	// eine Kollision findet statt, wenn beide Zeiten grer/gleich 0
	//
			t1 = (B+C)/A;
			if ( t1<-EPS )		return NO_HIT;
			t2 = (B-C)/A;
			if ( t2<-EPS )		return NO_HIT;
	//
	// fr die kleinere Zeit mu l? zwischen 0 und 1 liegen.	//
			if ( t1<t2 ) {
				l1 = ( b->PY() + t1*b->VY() - p1.Y() - b->R()*ds.Y() ) / d.Y();
				if ( l1>=0.0 && l1<=1.0 )	return t1;
				else								return NO_HIT;
			}
			else {
				l2 = ( b->PY() + t2*b->VY() - p1.Y() + b->R()*ds.Y() ) / d.Y();
				if ( l2>=0.0 && l2<=1.0 )	return t2;
				else								return NO_HIT;
			}
		}
	}

//
// keine Lsung mglich ?
//
	return NO_HIT;
#endif
}


void Wall::CollideWithBall( Ball *b ) {
Vec2	o, p;

	g->HitWall(b);
	b->V().Split(ds,&o,&p);
	b->SetV(p-o);
}

//
// -------------------------------------------------------------------------
//   class XWall:  Wand ohne Begrenzung
// -------------------------------------------------------------------------
//

XWall::~XWall()	{ }

Real XWall::HitFromBall( Ball *b )
{
	if (b->IsIdle())		return MAX_TIME;

Real	min_t;					// ausgerechnete Zeit
Real	sx=p1.X()-b->PX();		// zurckzulegende Strecke (ohne Radius)

	if (( sx > 0.0 ) && ( b->VX() > 0.0 )) {
		sx -= b->R();				// Kugelradius bercksichtigen
	}
	else if ( sx < 0.0 ) {
		if ( b->VX() >= 0.0 )		return NO_HIT;
		sx += b->R();				// Kugelradius bercksichtigen
	}
	else if (b->VX()==0.0)			return NO_HIT;

	min_t = sx / b->VX();

#ifdef DEBUG
	if (debug&XWallHit) {
		printf( "XWall-Hit in %g secs\n", (double)min_t );
		Info();
		b->Info();
	}
#endif

	if (min_t<-EPS)	return NO_HIT;
	else						return min_t;
}

void XWall::CollideWithBall( Ball *b )
{
	g->HitWall(b);
	b->SetV(Vec2( - b->VX(), b->VY() ));
}

//
// -------------------------------------------------------------------------
//   class YWall:  Wand ohne Begrenzung
// -------------------------------------------------------------------------
//

YWall::~YWall()	{ }

Real YWall::HitFromBall( Ball *b )
{
	if (b->IsIdle())		return MAX_TIME;

Real	min_t;					// ausgerechnete Zeit
Real	sy=p1.Y()-b->PY();		// zurckzulegende Strecke (ohne Radius)

	if (( sy > 0.0 ) && ( b->VY() > 0.0 )) {
		sy -= b->R();				// Kugelradius bercksichtigen
	}
	else if ( sy < 0.0 ) {
		if ( b->VY() >= 0.0 )		return NO_HIT;
		sy += b->R();				// Kugelradius bercksichtigen
	}
	else if (b->VY()==0.0)			return NO_HIT;

	min_t = sy / b->VY();

#ifdef DEBUG
	if (debug&YWallHit) {
		printf( "YWall-Hit in %g secs\n", (double)min_t );
		Info();
		b->Info();
	}
#endif

	if (min_t<-EPS)	return NO_HIT;
	else						return min_t;
}

void YWall::CollideWithBall( Ball *b )
{
	g->HitWall(b);
	b->SetV(Vec2( b->VX(), - b->VY() ));
}