Gromov

Untitled

Oct 25th, 2018
108
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 14.35 KB | None | 0 0
  1. program Game;
  2. {$MODE OBJFPC}
  3.  
  4. uses
  5. SDL, FGL, Math;
  6.  
  7. type
  8. TThing = class
  9. public
  10. X, Y: Integer;
  11. OX, OY: Single;
  12. Img: PSDL_Surface;
  13. end;
  14.  
  15. PEnemy = ^TEnemy;
  16. TEnemy = class(TThing)
  17. public
  18. TOX, TOY: Single;
  19. Direction: Integer;
  20. end;
  21.  
  22. TProjectile = class(TThing)
  23. public
  24. FX, FY, DX, DY: Single;
  25. PHarm, EHarm: Boolean;
  26. Life: Integer;
  27. end;
  28.  
  29. TThingList = specialize TFPGObjectList<TThing>;
  30. TEnemyList = specialize TFPGObjectList<TEnemy>;
  31. TProjectileList = specialize TFPGObjectList<TProjectile>;
  32.  
  33. var
  34. Surface, RealSurface: PSDL_Surface;
  35. Running: Boolean = True;
  36. KeyState: array [0..1024] of Boolean;
  37. Background, LifeImg, PlayerImg, PlayerHitImg, PlayerDeadImg, PlayerShootImg,
  38. RetryImg, Nums, PBulletImg, EBulletImg, Enemy1Img, Enemy2Img, P1Img, P2Img: PSDL_Surface;
  39. PlayerX: Integer;
  40. Enemies: TEnemyList;
  41. Projectiles: TProjectileList;
  42. Level, Life, Score, RetryY: Integer;
  43. ToDelete: array of TObject;
  44. PlayerShootTime, ShootTime, HitTime: Cardinal;
  45. ScaleMode: Integer = 1;
  46.  
  47. function SDL_SoftStretch(Src: PSDL_Surface; SrcRect: PSDL_Rect; Dst: PSDL_Surface; DstRect: PSDL_Rect): Integer; cdecl; external 'SDL';
  48.  
  49. function RectOverRect(AX1, AY1, AX2, AY2, BX1, BY1, BX2, BY2: Integer): Boolean; inline;
  50. begin
  51. Result:=not ((BX1 > AX2) or (BX2 < AX1) or (BY1 > AY2) or (BY2 < AY1));
  52. end;
  53.  
  54. function CollisionWithEnemy(CX, CY: Integer; CW: Integer=32; CH: Integer=32; Ignore: Integer=-1; Enemy: PEnemy=nil): Boolean;
  55. var
  56. I: Integer;
  57. begin
  58. for I:=0 to Enemies.Count - 1 do with Enemies[I] do
  59. if (I <> Ignore) and RectOverRect(X, Y, X + 31, Y + 31, CX, CY, CX + CW - 1, CY + CH - 1) then begin
  60. if Assigned(Enemy) then Enemy^:=Enemies[I];
  61. Exit(True);
  62. end;
  63. Result:=False;
  64. end;
  65.  
  66. procedure LaunchProjectile(X, Y, DX, DY: Single; Img: PSDL_Surface; PHarm, EHarm: Boolean; Life: Integer=-1);
  67. var
  68. P: TProjectile;
  69. begin
  70. P:=TProjectile.Create;
  71. Projectiles.Add(P);
  72. P.X:=Round(X);
  73. P.Y:=Round(Y);
  74. P.FX:=X;
  75. P.FY:=Y;
  76. P.DX:=DX;
  77. P.DY:=DY;
  78. P.Img:=Img;
  79. P.PHarm:=PHarm;
  80. P.EHarm:=EHarm;
  81. P.Life:=Life;
  82. end;
  83.  
  84. procedure DeleteLater(AObject: TObject);
  85. var
  86. I: Integer;
  87. begin
  88. for I:=0 to High(ToDelete) do if ToDelete[I]=AObject then Exit;
  89. SetLength(ToDelete, Length(ToDelete) + 1);
  90. ToDelete[High(ToDelete)]:=AObject;
  91. end;
  92.  
  93. procedure DeleteDeferredObjects;
  94. var
  95. I: Integer;
  96. begin
  97. for I:=0 to High(ToDelete) do begin
  98. if ToDelete[I] is TProjectile then Projectiles.Remove(TProjectile(ToDelete[I]))
  99. else if ToDelete[I] is TEnemy then Enemies.Remove(TEnemy(ToDelete[I]))
  100. else ToDelete[I].Free;
  101. end;
  102. SetLength(ToDelete, 0);
  103. end;
  104.  
  105. function Key(K: Integer): Boolean; inline;
  106. begin
  107. if (K >= Low(KeyState)) and (K <= High(KeyState)) then Result:=KeyState[K] else Result:=False;
  108. end;
  109.  
  110. function InitVideo: Boolean;
  111. var
  112. Flags: Cardinal = SDL_DOUBLEBUF or SDL_SWSURFACE;
  113. I: Integer;
  114. Bits: Integer = 16;
  115. begin
  116. for I:=1 to ParamCount do begin
  117. if ParamStr(I)='-fullscreen' then begin
  118. Flags:=Flags + SDL_FULLSCREEN;
  119. SDL_ShowCursor(0);
  120. end;
  121. if ParamStr(I)='-double' then ScaleMode:=2;
  122. if ParamStr(I)='-triple' then ScaleMode:=3;
  123. if ParamStr(I)='-8bit' then Bits:=8;
  124. end;
  125. if ScaleMode > 1 then begin
  126. RealSurface:=SDL_SetVideoMode(320*ScaleMode, 240*ScaleMode, 16, Flags);
  127. with RealSurface^.format^ do
  128. Surface:=SDL_CreateRGBSurface(SDL_SWSURFACE, 320, 240, 16, Rmask, Gmask, Bmask, Amask);
  129. end else begin
  130. Surface:=SDL_SetVideoMode(320, 240, Bits, Flags);
  131. RealSurface:=Surface;
  132. end;
  133. Result:=Assigned(Surface);
  134. end;
  135.  
  136. procedure ShowSurface;
  137. var
  138. S, D: TSDL_Rect;
  139. begin
  140. if ScaleMode > 1 then begin
  141. S.x:=0;
  142. S.y:=0;
  143. S.w:=320;
  144. S.h:=240;
  145. D.x:=0;
  146. D.y:=0;
  147. D.w:=320*ScaleMode;
  148. D.h:=240*ScaleMode;
  149. SDL_SoftStretch(Surface, @S, RealSurface, @D);
  150. end;
  151. SDL_Flip(RealSurface);
  152. end;
  153.  
  154. procedure LoadImages;
  155.  
  156. function Load(Name: AnsiString): PSDL_Surface;
  157. begin
  158. Result:=SDL_LoadBMP(PChar(Name));
  159. SDL_SetColorKey(Result, SDL_SRCCOLORKEY, SDL_MapRGB(Result^.format, 255, 0, 255));
  160. end;
  161.  
  162. begin
  163. Background:=SDL_LoadBMP('bgnd.bmp');
  164. Nums:=Load('nums.bmp');
  165. PlayerImg:=Load('player.bmp');
  166. PlayerHitImg:=Load('plrhit.bmp');
  167. PlayerDeadImg:=Load('plrdead.bmp');
  168. PlayerShootImg:=Load('plrshoot.bmp');
  169. RetryImg:=Load('retry.bmp');
  170. LifeImg:=Load('life.bmp');
  171. PBulletImg:=Load('pbullet.bmp');
  172. EBulletImg:=Load('ebullet.bmp');
  173. Enemy1Img:=Load('enemy1.bmp');
  174. Enemy2Img:=Load('enemy2.bmp');
  175. P1Img:=Load('part1.bmp');
  176. P2Img:=Load('part2.bmp');
  177. end;
  178.  
  179. procedure TitleScreen;
  180. var
  181. Title: PSDL_Surface;
  182. Ev: TSDL_Event;
  183. ShowTitle: Boolean = True;
  184. begin
  185. Title:=SDL_LoadBMP('title.bmp');
  186. while ShowTitle do begin
  187. while SDL_PollEvent(@Ev) <> 0 do begin
  188. case Ev.Type_ of
  189. SDL_QUITEV: begin
  190. Running:=False;
  191. ShowTitle:=False;
  192. end;
  193. SDL_KEYDOWN: case Ev.Key.KeySym.Sym of
  194. SDLK_ESCAPE: begin
  195. Running:=False;
  196. ShowTitle:=False;
  197. end;
  198. SDLK_Space: ShowTitle:=False;
  199. end;
  200. end;
  201. end;
  202. SDL_BlitSurface(Title, nil, Surface, nil);
  203. ShowSurface;
  204. end;
  205. end;
  206.  
  207. procedure DrawScreen;
  208.  
  209. procedure Draw(X, Y: Integer; Surf: PSDL_Surface);
  210. var
  211. R: TSDL_Rect;
  212. begin
  213. R.x:=X;
  214. R.y:=Y;
  215. R.w:=Surf^.w;
  216. R.h:=Surf^.h;
  217. SDL_BlitSurface(Surf, nil, Surface, @R);
  218. end;
  219.  
  220. procedure DrawNum(X, Y, N: Integer);
  221. var
  222. R, S: TSDL_Rect;
  223. begin
  224. R.x:=X;
  225. R.y:=Y;
  226. R.w:=8;
  227. R.h:=10;
  228. S.x:=N*8;
  229. S.y:=0;
  230. S.w:=8;
  231. S.h:=10;
  232. SDL_BlitSurface(Nums, @S, Surface, @R);
  233. end;
  234.  
  235. procedure DrawNumber(X, Y, N: Integer);
  236. var
  237. V: Integer = 10000000;
  238. begin
  239. repeat
  240. if (N div V > 0) or (N=0) then begin
  241. DrawNum(X, Y, (N div V) mod 10);
  242. Inc(X, 8);
  243. end;
  244. V:=V div 10;
  245. until (V=0) or (N=0);
  246. end;
  247.  
  248. procedure DrawThings(ThingList: TThingList);
  249. var
  250. I: Integer;
  251. begin
  252. for I:=0 to ThingList.Count - 1 do with ThingList[I] do
  253. Draw(Round(X + OX), Round(Y + OY), Img);
  254. end;
  255.  
  256. procedure DrawHUD;
  257. var
  258. I: Integer;
  259. begin
  260. for I:=0 to Life - 1 do Draw(I*6 + 1, 14, LifeImg);
  261. DrawNumber(1, 1, Score);
  262. if Life=0 then Draw(40, RetryY, RetryImg);
  263. end;
  264.  
  265. begin
  266. Draw(0, 0, Background);
  267. if Life > 0 then begin
  268. if HitTime=0 then
  269. if ShootTime=0 then
  270. Draw(PlayerX, 206, PlayerImg)
  271. else
  272. Draw(PlayerX, 206, PlayerShootImg)
  273. else
  274. Draw(PlayerX, 206, PlayerHitImg);
  275. end else
  276. Draw(PlayerX, 206, PlayerDeadImg);
  277. DrawThings(TThingList(Enemies));
  278. DrawThings(TThingList(Projectiles));
  279. DrawHUD;
  280.  
  281. ShowSurface;
  282. end;
  283.  
  284. procedure NewGame(Reset: Boolean);
  285.  
  286. procedure InitEnemies;
  287. var
  288. GX, GY: Integer;
  289. begin
  290. for GY:=0 to 3 do
  291. for GX:=0 to 7 do begin
  292. Enemies.Add(TEnemy.Create);
  293. with Enemies[GY*8 + GX] do begin
  294. X:=GX*32 + 32;
  295. Y:=GY*32;
  296. Direction:=1;
  297. if (Level*17 + GX*311 + GY*3787) mod 2=0 then
  298. Img:=Enemy1Img
  299. else
  300. Img:=Enemy2Img;
  301. end;
  302. end;
  303. if Level < 19 then
  304. for GX:=1 to 19-Level do Enemies.Remove(Enemies[Random(Enemies.Count)]);
  305. end;
  306.  
  307. begin
  308. PlayerX:=160 - 16;
  309. if Reset then begin
  310. Life:=4;
  311. Level:=1;
  312. Score:=0;
  313. end;
  314. FreeAndNil(Enemies);
  315. FreeAndNil(Projectiles);
  316. Enemies:=TEnemyList.Create;
  317. Projectiles:=TProjectileList.Create;
  318. InitEnemies;
  319. end;
  320.  
  321. procedure UpdateGame;
  322.  
  323. procedure LaunchPoof(X, Y: Integer; Img: PSDL_Surface; Life: Integer);
  324. begin
  325. LaunchProjectile(X, Y, -1, -0.4, Img, False, False, Life+Random(10));
  326. LaunchProjectile(X, Y, -0.2, -0.7, Img, False, False, Life+Random(10));
  327. LaunchProjectile(X, Y, 0.3, -0.6, Img, False, False, Life+Random(10));
  328. LaunchProjectile(X, Y, 0.96, -0.3, Img, False, False, Life+Random(10));
  329. LaunchProjectile(X, Y, -0.8, 0.5, Img, False, False, Life+Random(10));
  330. LaunchProjectile(X, Y, -0.3, 0.65, Img, False, False, Life+Random(10));
  331. LaunchProjectile(X, Y, 0.34, 0.67, Img, False, False, Life+Random(10));
  332. LaunchProjectile(X, Y, 0.93, 0.31, Img, False, False, Life+Random(10));
  333. end;
  334.  
  335. procedure MovePlayer(D: Integer);
  336. begin
  337. if (PlayerX + D < 0) or (PlayerX + D > 320-32) then Exit;
  338. PlayerX:=PlayerX + D;
  339. end;
  340.  
  341. procedure MoveEnemies;
  342. var
  343. I, J: Integer;
  344. Collisions: Boolean;
  345. Sides: array of Integer;
  346. begin
  347. for I:=0 to Enemies.Count - 1 do with Enemies[I] do begin
  348. Inc(X, Direction);
  349. OX:=OX + (TOX - OX)*0.9;
  350. OY:=OY + (TOY - OY)*0.9;
  351. TOX:=TOX*0.9;
  352. TOY:=TOY*0.9;
  353. if (Game.Life <> 0) and RectOverRect(X, Y, X + 31, Y + 31, PlayerX, 206, PlayerX + 31, 240) then begin
  354. DeleteLater(Enemies[I]);
  355. LaunchPoof(X, Y, P2Img, 10);
  356. LaunchPoof((X + PlayerX) div 2, (Y + 206) div 2, P2Img, 30);
  357. LaunchPoof(PlayerX + 13, 204, P1Img, 70);
  358. LaunchPoof(PlayerX + 17, 207, P1Img, 96);
  359. Game.Life:=0;
  360. RetryY:=-32;
  361. end;
  362. end;
  363. SetLength(Sides, 0);
  364. repeat
  365. Collisions:=False;
  366. for I:=0 to Enemies.Count - 1 do with Enemies[I] do
  367. if (X <= 0) or (X >= 320-32) or CollisionWithEnemy(X, Y, 32, 32, I) then begin
  368. if (X <= 0) or (X >= 320-32) then begin
  369. SetLength(Sides, Length(Sides) + 1);
  370. Sides[High(Sides)]:=Y;
  371. end;
  372. Direction:=-Direction;
  373. Inc(X, Direction);
  374. Collisions:=True;
  375. end;
  376. until not Collisions;
  377. for I:=0 to Enemies.Count - 1 do with Enemies[I] do
  378. for J:=0 to High(Sides) do
  379. if Sides[J] <= Y then begin
  380. Inc(Y, 2);
  381. Break;
  382. end;
  383. end;
  384.  
  385. procedure Splash(CX, CY: Integer);
  386. const
  387. Radius = 100;
  388. var
  389. I: Integer;
  390. Len, TX, TY: Single;
  391. begin
  392. for I:=0 to Enemies.Count - 1 do with Enemies[I] do begin
  393. TX:=X - CX + 16;
  394. TY:=Y - CY + 16;
  395. Len:=Sqrt(Sqr(TX) + Sqr(TY));
  396. if Len=0 then TX:=0 else TX:=TX/Len * 10;
  397. if Len=0 then TY:=0 else TY:=TY/Len * 10;
  398. TOX:=TOX + Max(0, Radius - Len)/Radius * TX;
  399. TOY:=TOY + Max(0, Radius - Len)/Radius * TY;
  400. end;
  401. end;
  402.  
  403. procedure MoveProjectiles;
  404. var
  405. I: Integer;
  406. Enemy: TEnemy;
  407. begin
  408. for I:=0 to Projectiles.Count - 1 do with Projectiles[I] do begin
  409. FX:=FX + DX;
  410. FY:=FY + DY;
  411. X:=Round(FX);
  412. Y:=Round(FY);
  413. if Life <> -1 then Dec(Life);
  414. if (X < -9) or (Y < -9) or (X > 320) or (Y > 230) or (Life=0) then begin
  415. if PHarm and (Y > 230) then begin
  416. LaunchProjectile(X, Y - 4, 0.3, -0.6, P1Img, False, False, 10+Random(10));
  417. LaunchProjectile(X, Y - 4, -0.5, -0.5, P1Img, False, False, 12+Random(10));
  418. end;
  419. DeleteLater(Projectiles[I]);
  420. Continue;
  421. end;
  422. if EHarm and CollisionWithEnemy(X, Y, 9, 9, -1, @Enemy) then begin
  423. DeleteLater(Projectiles[I]);
  424. DeleteLater(Enemy);
  425. LaunchPoof(Enemy.X + 16, Enemy.Y + 16, P1Img, 20);
  426. Splash(Enemy.X + 16, Enemy.Y + 16);
  427. Inc(Score, Y*3+30);
  428. Continue;
  429. end;
  430. if PHarm and (Game.Life > 0) and RectOverRect(X, Y, X + 8, Y + 8, PlayerX + 4, 210, PlayerX + 28, 224) then begin
  431. DeleteLater(Projectiles[I]);
  432. HitTime:=4;
  433. LaunchPoof(X, Y, P2Img, 10);
  434. Dec(Game.Life);
  435. if Game.Life=0 then begin
  436. LaunchPoof((X + PlayerX) div 2, (Y + 206) div 2, P2Img, 30);
  437. LaunchPoof(PlayerX + 13, 204, P1Img, 70);
  438. LaunchPoof(PlayerX + 17, 207, P1Img, 96);
  439. RetryY:=-32;
  440. end;
  441. Continue;
  442. end;
  443. end;
  444. end;
  445.  
  446. procedure ShootPlayerBullet;
  447. begin
  448. if SDL_GetTicks - PlayerShootTime < (200 - Min(100, Max(0, Level*4))) then Exit;
  449. PlayerShootTime:=SDL_GetTicks;
  450. ShootTime:=4;
  451. LaunchProjectile(PlayerX + 11, 204, 0, -4, PBulletImg, False, True);
  452. end;
  453.  
  454. procedure ShootEnemyBullet;
  455. var
  456. TX, TY, Len: Single;
  457. begin
  458. if Random(100) > 4*((Level div 3)+1) then Exit;
  459. if Enemies.Count=0 then Exit;
  460. with Enemies[Random(Enemies.Count)] do begin
  461. TOY:=TOY-2;
  462. TX:=PlayerX - X;
  463. TY:=206 - Y;
  464. Len:=Sqrt(TX*TX + TY*TY);
  465. TX:=TX/Len;
  466. TY:=TY/Len;
  467. LaunchProjectile(X + 12, Y + 30, TX, TY, EBulletImg, True, False);
  468. end;
  469. end;
  470.  
  471. begin
  472. if Life > 0 then begin
  473. if Key(SDLK_LEFT) then MovePlayer(-4)
  474. else if Key(SDLK_RIGHT) then MovePlayer(4);
  475. if Key(SDLK_LCTRL) then ShootPlayerBullet;
  476.  
  477. if Enemies.Count=0 then begin
  478. SDL_Delay(600);
  479. Inc(Life);
  480. Inc(Score, 1000);
  481. Inc(Level);
  482. NewGame(False);
  483. end;
  484. end else begin
  485. if RetryY < 100 then Inc(RetryY, 6);
  486. if Key(SDLK_LCTRL) then begin
  487. NewGame(True);
  488. SDL_Delay(500);
  489. Exit;
  490. end;
  491. end;
  492. MoveEnemies;
  493. MoveProjectiles;
  494. ShootEnemyBullet;
  495. if HitTime > 0 then Dec(HitTime);
  496. if ShootTime > 0 then Dec(ShootTime);
  497. end;
  498.  
  499. procedure MainLoop;
  500. var
  501. LastTime, CurrentTime: Cardinal;
  502.  
  503. procedure HandleEvents;
  504. var
  505. Ev: TSDL_Event;
  506.  
  507. procedure HandleKey(Sym: Integer; Down: Boolean);
  508. begin
  509. if (Sym >= Low(KeyState)) and (Sym <= High(KeyState)) then KeyState[Sym]:=Down;
  510. case Sym of
  511. SDLK_ESCAPE: Running:=False;
  512. end;
  513. end;
  514.  
  515. begin
  516. while SDL_PollEvent(@Ev) <> 0 do begin
  517. case Ev.Type_ of
  518. SDL_QUITEV: Running:=False;
  519. SDL_KEYDOWN: HandleKey(Ev.Key.KeySym.Sym, True);
  520. SDL_KEYUP: HandleKey(Ev.Key.KeySym.Sym, False);
  521. end;
  522. end;
  523. end;
  524.  
  525. begin
  526. LastTime:=SDL_GetTicks();
  527. while Running do begin
  528. CurrentTime:=SDL_GetTicks();
  529. if CurrentTime - LastTime > 1000 then LastTime:=CurrentTime - 60;
  530. while CurrentTime - LastTime > 1000/20 do begin
  531. UpdateGame;
  532. Inc(LastTime, 20);
  533. end;
  534. HandleEvents;
  535. DrawScreen;
  536. DeleteDeferredObjects;
  537. end;
  538. end;
  539.  
  540. begin
  541. Randomize;
  542. SDL_Init(SDL_INIT_VIDEO);
  543. if not InitVideo then Exit;
  544. SDL_WM_SetCaption('Game', 'Game');
  545. LoadImages;
  546. TitleScreen;
  547. NewGame(True);
  548. MainLoop;
  549. SDL_Quit;
  550. end.
Add Comment
Please, Sign In to add comment