fPongD.pas 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171
  1. unit fPongD;
  2. interface
  3. uses
  4. System.Classes,
  5. System.UITypes,
  6. System.SysUtils,
  7. System.Math,
  8. Vcl.Forms,
  9. Vcl.ExtCtrls,
  10. Vcl.Controls,
  11. Vcl.Dialogs,
  12. GLS.Scene,
  13. GLScene.VectorTypes,
  14. GLS.Objects,
  15. GLS.Texture,
  16. GLScene.VectorGeometry,
  17. GLS.Cadencer,
  18. GLS.SceneViewer,
  19. GLS.SpaceText,
  20. GLS.ShadowPlane,
  21. GLS.ShadowVolume,
  22. GLS.Material,
  23. GLS.Coordinates,
  24. GLS.BaseClasses;
  25. type
  26. TFormPong = class(TForm)
  27. GLScene1: TGLScene;
  28. GLSceneViewer1: TGLSceneViewer;
  29. GLCamera1: TGLCamera;
  30. PlaneTable: TGLPlane;
  31. BackBoard: TGLCube;
  32. LeftBoard: TGLCube;
  33. RightBoard: TGLCube;
  34. Ball: TGLSphere;
  35. DummyCube1: TGLDummyCube;
  36. GLLightSource1: TGLLightSource;
  37. GLMaterialLibrary1: TGLMaterialLibrary;
  38. Pad: TGLCube;
  39. SpaceText1: TGLSpaceText;
  40. Timer1: TTimer;
  41. GLCadencer1: TGLCadencer;
  42. GLShadowVolume: TGLShadowVolume;
  43. procedure GLSceneViewer1MouseMove(Sender: TObject; Shift: TShiftState; X, Y: Integer);
  44. procedure FormCreate(Sender: TObject);
  45. procedure Timer1Timer(Sender: TObject);
  46. procedure GLCadencer1Progress(Sender: TObject; const deltaTime, newTime: Double);
  47. private
  48. ballVector: TAffineVector;
  49. score: Integer;
  50. gameOver: Boolean;
  51. procedure ResetGame;
  52. end;
  53. var
  54. FormPong: TFormPong;
  55. implementation
  56. {$R *.DFM}
  57. procedure TFormPong.FormCreate(Sender: TObject);
  58. begin
  59. Randomize;
  60. GLSceneViewer1.Cursor := crNone;
  61. ResetGame;
  62. end;
  63. procedure TFormPong.ResetGame;
  64. var
  65. angle: Single;
  66. begin
  67. // places the ball in the mat center, resets score and ball speed
  68. angle := DegToRad(45 + Random(90));
  69. MakeVector(ballVector, 4 * cos(angle), 4 * sin(angle), 0);
  70. score := 0;
  71. gameOver := False;
  72. Ball.Position.AsVector := NullHmgPoint;
  73. end;
  74. procedure TFormPong.GLSceneViewer1MouseMove(Sender: TObject; Shift: TShiftState; X, Y: Integer);
  75. const
  76. cPadMinMax = 6.25;
  77. var
  78. px: Single;
  79. begin
  80. // the pad's position is directly calculated from the mouse position
  81. px := (X - (GLSceneViewer1.Width / 2)) * 0.035;
  82. if px < -cPadMinMax then
  83. px := -cPadMinMax
  84. else if px > cPadMinMax then
  85. px := cPadMinMax;
  86. Pad.Position.X := px;
  87. // GLCadencer1.Reset;
  88. // update the whole stuff now!
  89. GLCadencer1.Progress;
  90. end;
  91. procedure TFormPong.GLCadencer1Progress(Sender: TObject; const deltaTime, newTime: Double);
  92. var
  93. newBallPos: TGLVector;
  94. begin
  95. // gameOver is True as soon as the ball is behind the pad, but we don't end
  96. // the game immediately so the user can realize he has lost
  97. if (not gameOver) and (deltaTime > 0) then
  98. begin
  99. // calc expected new ball pos (if no bump occurs)
  100. // ( note : VectorCombine(v1, v2, f1, f2)=v1*f1+v2*f2 )
  101. newBallPos := VectorCombine(Ball.Position.AsVector, ballVector, 1, deltaTime);
  102. // check collision with edges
  103. if newBallPos.X < -7.05 then
  104. ballVector.X := -ballVector.X
  105. else if newBallPos.X > 7.05 then
  106. ballVector.X := -ballVector.X
  107. else if newBallPos.Y > 4.55 then
  108. ballVector.Y := -ballVector.Y;
  109. // check collision with pad
  110. if newBallPos.Y < -4 then
  111. begin
  112. if (newBallPos.X > Pad.Position.X - 1.25) and (newBallPos.X < Pad.Position.X + 1.25) then
  113. begin
  114. // when ball bumps the pad, it is accelerated and the vector
  115. // is slightly randomized
  116. ballVector.Y := -ballVector.Y;
  117. ballVector.X := ballVector.X + (Random(100) - 50) / 50;
  118. ballVector.Y := ballVector.Y + 0.1;
  119. // ...and of course a point is scored !
  120. Inc(score);
  121. SpaceText1.Text := Format('%.3d', [score]);
  122. end
  123. else
  124. begin
  125. // ball missed !
  126. gameOver := True;
  127. Exit;
  128. end
  129. end;
  130. end;
  131. // move the ball
  132. with Ball.Position do
  133. AsVector := VectorCombine(AsVector, ballVector, 1, deltaTime);
  134. end;
  135. procedure TFormPong.Timer1Timer(Sender: TObject);
  136. begin
  137. // update performance monitor
  138. // %s : Name,
  139. Caption := Format('%.2f FPS', [GLSceneViewer1.FramesPerSecond]);
  140. GLSceneViewer1.ResetPerformanceMonitor;
  141. // display score window when game is over and the ball is well out of the board
  142. if gameOver and (Ball.Position.Y < -6) then
  143. begin
  144. // stop the timer to avoid stacking up Timer events
  145. // while the user makes up his mind...
  146. Timer1.Enabled := False;
  147. if MessageDlg('Score : ' + IntToStr(score) + #13#10#13#10 + 'Play again ?', mtInformation,
  148. [mbYes, mbNo], 0) = mrYes then
  149. begin
  150. ResetGame;
  151. Timer1.Enabled := True;
  152. end
  153. else
  154. Close;
  155. end;
  156. end;
  157. end.