1 /*--License:
2 Kyra Sprite Engine
3 Copyright Lee Thomason (Grinning Lizard Software) 2001-2005
4 www.grinninglizard.com/kyra
5 www.sourceforge.net/projects/kyra
6
7 Kyra is provided under the LGPL.
8
9 I kindly request you display a splash screen (provided in the HTML documentation)
10 to promote Kyra and acknowledge the software and everyone who has contributed to it,
11 but it is not required by the license.
12
13 --- LGPL License --
14
15 This library is free software; you can redistribute it and/or
16 modify it under the terms of the GNU Lesser General Public
17 License as published by the Free Software Foundation; either
18 version 2.1 of the License, or (at your option) any later version.
19
20 This library is distributed in the hope that it will be useful,
21 but WITHOUT ANY WARRANTY; without even the implied warranty of
22 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
23 Lesser General Public License for more details.
24
25 You should have received a copy of the GNU Lesser General Public
26 License along with this library; if not, write to the Free Software
27 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
28
29 The full text of the license can be found in lgpl.txt
30 */
31
32
33
34 #include "SDL.h"
35 #include "demos.h"
36 #include "space.h"
37 #include <math.h>
38
39
SpaceGame(SDL_Surface * screen,bool _tracking)40 SpaceGame::SpaceGame( SDL_Surface* screen, bool _tracking )
41 {
42 random.SetSeed( 0 );
43
44 GlFixed camera = -50;
45 for( int i=0; i<NUM_SCALES; ++i )
46 {
47 int z = ( i * MAXDEPTH / ( NUM_SCALES - 1 ) );
48 GlFixed scale = GlFixed( z - camera ) / GlFixed( BIGDEPTH - camera );
49 scalesToUse[i] = scale;
50 }
51
52 tracking = _tracking;
53 engine = new KrEngine( screen );
54 GLASSERT( engine );
55
56 if ( !engine->Vault()->LoadDatFile( "space.dat" ) )
57 {
58 #ifdef DEBUG
59 GLOUTPUT(( "Error loading 'space.dat'!\n" ));
60 GLASSERT( 0 );
61 #endif
62 exit(100);
63 }
64
65 // Calculate the size of the space field and fill
66 // it with space tiles.
67 field.min.x = -engine->ScreenBounds().Width() * 3;
68 field.max.x = engine->ScreenBounds().Width();
69 field.min.y = engine->ScreenBounds().min.y;
70 field.max.y = engine->ScreenBounds().max.y;
71
72 xResetAt = -engine->ScreenBounds().Width() * 2;
73 xResetTo = engine->ScreenBounds().Width() / 2;
74
75 // // Only useful if the demo runs past the end of the screen.
76 // // For a "real" app, this should be set to 0 because the
77 // // background shouldn't show through.
78 // KrRGBA black;
79 // black.Set( 0, 0, 0, 255 );
80 // engine->FillBackground( &black );
81 engine->FillBackground( 0 ); // Turn off background.
82
83 // We use 2 container ImNodes:
84 // - one for the starfield
85 // - one for everything else.
86 starfieldNode = new KrImNode;
87 mainNode = new KrImNode;
88
89 engine->Tree()->AddNode( 0, starfieldNode );
90 engine->Tree()->AddNode( 0, mainNode );
91
92 AddStarfield();
93 AddShips();
94
95 TrackCamera();
96 }
97
98
~SpaceGame()99 SpaceGame::~SpaceGame()
100 {
101 delete engine;
102 }
103
104
TrackCamera()105 void SpaceGame::TrackCamera()
106 {
107 // Find the tracker object and put it on the right side of the screen.
108 KrImNode* node;
109
110 node = engine->Tree()->FindNodeByName( "track" );
111 if ( node )
112 {
113 // We scoll the screen to position the node in the view.
114 // We want the ship to end up at 3/4 width and 1/2 height.
115 // (the height doesn't change, so we only have to play
116 // with the x)
117
118 int desiredX = engine->ScreenBounds().Width() * 3 / 4;
119 int offsetX = node->X() - desiredX;
120 engine->Tree()->Root()->SetPos( -offsetX, 0 );
121 }
122 }
123
124
AddStarfield()125 void SpaceGame::AddStarfield()
126 {
127 int x, y;
128 KrTileResource* starRes = engine->Vault()->GetTileResource( "STARS" );
129 GLASSERT( starRes );
130 // GlFixed scalex = 1.3;
131 // GlFixed scaley = 1.3;
132 // starRes->CacheScale( scalex, scaley );
133
134 for( x = field.min.x; x <= field.max.x; x += starRes->Size() )
135 {
136 for( y = field.min.y; y <= field.max.y; y += starRes->Size() )
137 {
138 KrTile* tile = new KrTile( starRes );
139 GLASSERT( tile );
140
141 tile->SetRotation( random.Rand( 8 ) );
142 tile->SetPos( x, y );
143 engine->Tree()->AddNode( starfieldNode, tile );
144 // tile->SetScale( scalex, scaley );
145 }
146 }
147 }
148
149
GetScale(int z)150 GlFixed SpaceGame::GetScale( int z )
151 {
152 if ( z == BIGDEPTH ) return 1;
153
154 GlFixed camera = -50;
155 GlFixed scale = GlFixed( z - camera ) / GlFixed( BIGDEPTH - camera );
156
157 int index = 0;
158 int error = abs( scale.v - scalesToUse[0].v );
159
160 for( int i=1; i<NUM_SCALES; ++i )
161 {
162 int thisError = abs( scale.v - scalesToUse[i].v );
163 if ( thisError < error )
164 {
165 error = thisError;
166 index = i;
167 }
168 }
169 return scalesToUse[ index ];
170 }
171
172
AddShips()173 void SpaceGame::AddShips()
174 {
175 // Put one big ship in, some random med size, and a bunch of
176 // small ones.
177
178 KrSpriteResource* bigRes;
179 KrSpriteResource* medRes;
180 KrSpriteResource* smallRes;
181 KrSprite* sprite;
182 KrSprite* insignia;
183 int i, x, y;
184
185 GlFixed scale;
186
187 bigRes = engine->Vault()->GetSpriteResource( "LARGE" );
188 GLASSERT( bigRes );
189 medRes = engine->Vault()->GetSpriteResource( "MED" );
190 GLASSERT( medRes );
191 smallRes = engine->Vault()->GetSpriteResource( "SMALL" );
192 GLASSERT( smallRes );
193
194 // Cache scale the ships.
195 for( i=0; i<NUM_SCALES; ++i )
196 {
197 medRes->CacheScale( scalesToUse[i], scalesToUse[i] );
198 smallRes->CacheScale( scalesToUse[i], scalesToUse[i] );
199 }
200
201 // Big ship. Noting that the big ship is 2 sprites: the
202 // body and the tail.
203 sprite = new KrSprite( bigRes );
204 sprite->SetPos( field.min.x + engine->ScreenBounds().Width() * 3 / 2,
205 engine->ScreenBounds().Height() / 2 );
206 sprite->SetZDepth( BIGDEPTH );
207 sprite->SetNodeName( "track" );
208 sprite->SetAction( "BODY" );
209
210 engine->Tree()->AddNode( mainNode, sprite );
211
212 KrSprite* tail = new KrSprite( bigRes );
213 tail->SetAction( "TAIL" );
214 engine->Tree()->AddNode( sprite, tail );
215
216 // Med ships. These are a little special because they
217 // each have a triangle insignia on them that is a child
218 // node which is color transformed.
219 for( i=0; i<NUM_MED; i++ )
220 {
221 // The ship:
222 x = random.Rand( field.Width() );
223 y = random.Rand( field.Height() );
224
225 sprite = new KrSprite( medRes );
226 sprite->SetPos( field.min.x + x, field.min.y + y );
227 sprite->SetZDepth( random.Rand( MAXDEPTH ) );
228 scale = GetScale( sprite->ZDepth() );
229 sprite->SetScale( scale, scale );
230 sprite->SetAction( "BODY" );
231
232 engine->Tree()->AddNode( mainNode, sprite );
233
234 // The insignia. It will move with the ship
235 // since it is a child, so we don't set coordinates.
236 insignia = new KrSprite( medRes );
237 insignia->SetAction( "INSIGNIA" );
238
239 KrColorTransform color;
240 switch( random.Rand( 3 ) )
241 {
242 case 0:
243 color.TintBlue( 200 );
244 break;
245 case 1:
246 color.TintRed( 200 );
247 break;
248 case 2:
249 color.TintGreen( 200 );
250 break;
251 }
252 insignia->SetColor( color );
253 engine->Tree()->AddNode( sprite, insignia );
254 }
255
256 // Small ships.
257 for( i=0; i<NUM_SMALL; i++ )
258 {
259 x = random.Rand( field.Width() );
260 y = random.Rand( field.Height() );
261
262 sprite = new KrSprite( smallRes );
263 sprite->SetPos( field.min.x + x, field.min.y + y );
264 sprite->SetZDepth( random.Rand( MAXDEPTH ) );
265 scale = GetScale ( sprite->ZDepth() );
266 sprite->SetScale( scale, scale );
267 engine->Tree()->AddNode( mainNode, sprite );
268 }
269 }
270
271
DrawFrame()272 void SpaceGame::DrawFrame()
273 {
274 AddText( engine );
275
276 // Move ships
277 GlInsideNodeIt<KrImNode*> it = mainNode->ChildTreeIterator();
278
279 const float SPEED_MED = 2.f;
280 const float SPEED_SMALL = 3.f;
281
282 for ( it.Begin(); !it.Done(); it.Next() )
283 {
284 KrSprite* sprite = it.CurrentData()->ToSprite();
285 if ( sprite )
286 {
287 //int bonus = ( sprite->ZDepth() > BIGDEPTH ) ? 1 : 0;
288
289 if ( sprite->SpriteResource()->ResourceName() == "LARGE" )
290 {
291 sprite->DeltaPos( -1, 0 );
292 }
293 else if ( sprite->SpriteResource()->ResourceName() == "MED" )
294 {
295 GlFixed scale = GetScale( sprite->ZDepth() );
296 float speed = SPEED_MED * scale.ToFloat();
297 int d = (int)(speed * (float)(Frame()-1) ) - (int)(speed * Frame() );
298 sprite->DeltaPos( d, 0 );
299
300 //sprite->DeltaPos( -2 - bonus, 0 );
301 }
302 else if ( sprite->SpriteResource()->ResourceName() == "SMALL" )
303 {
304 GlFixed scale = GetScale( sprite->ZDepth() );
305 float speed = SPEED_SMALL * scale.ToFloat();
306 int d = (int)(speed * (float)(Frame()-1) ) - (int)(speed * Frame() );
307 sprite->DeltaPos( d, 0 );
308
309 //sprite->DeltaPos( -3 - bonus , 0 );
310 }
311
312 // Reset the ships, so the demo can keep running.
313 // Regrettably, different logic for tracking and not-tracking.
314 if ( tracking )
315 {
316 if ( sprite->SpriteResource()->ResourceName() == "LARGE" )
317 {
318 if ( sprite->X() < xResetAt )
319 sprite->SetPos( xResetTo, sprite->Y() );
320 }
321 else
322 {
323 if ( sprite->X() < xResetAt - engine->ScreenBounds().Width() )
324 sprite->SetPos( xResetTo + engine->ScreenBounds().Width(), sprite->Y() );
325 }
326 }
327 else
328 {
329 if ( sprite->X() < field.min.x )
330 sprite->SetPos( field.max.x, sprite->Y() );
331 }
332 }
333 }
334
335 if ( tracking )
336 TrackCamera();
337
338 engine->Draw();
339 }
340
341