Application Android et IOS pour l'amicale des élèves
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

GameLogic.js 7.1KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318
  1. // @flow
  2. import Piece from './Piece';
  3. import ScoreManager from './ScoreManager';
  4. import GridManager from './GridManager';
  5. import type {CustomThemeType} from '../../../managers/ThemeManager';
  6. import type {GridType} from '../components/GridComponent';
  7. export type TickCallbackType = (
  8. score: number,
  9. level: number,
  10. grid: GridType,
  11. ) => void;
  12. export type ClockCallbackType = (time: number) => void;
  13. export type EndCallbackType = (
  14. time: number,
  15. score: number,
  16. isRestart: boolean,
  17. ) => void;
  18. export type MovementCallbackType = (grid: GridType, score?: number) => void;
  19. export default class GameLogic {
  20. static levelTicks = [1000, 800, 600, 400, 300, 200, 150, 100];
  21. scoreManager: ScoreManager;
  22. gridManager: GridManager;
  23. height: number;
  24. width: number;
  25. gameRunning: boolean;
  26. gamePaused: boolean;
  27. gameTime: number;
  28. currentObject: Piece;
  29. gameTick: number;
  30. gameTickInterval: IntervalID;
  31. gameTimeInterval: IntervalID;
  32. pressInInterval: TimeoutID;
  33. isPressedIn: boolean;
  34. autoRepeatActivationDelay: number;
  35. autoRepeatDelay: number;
  36. nextPieces: Array<Piece>;
  37. nextPiecesCount: number;
  38. tickCallback: TickCallbackType;
  39. clockCallback: ClockCallbackType;
  40. endCallback: EndCallbackType;
  41. theme: CustomThemeType;
  42. constructor(height: number, width: number, theme: CustomThemeType) {
  43. this.height = height;
  44. this.width = width;
  45. this.gameRunning = false;
  46. this.gamePaused = false;
  47. this.theme = theme;
  48. this.autoRepeatActivationDelay = 300;
  49. this.autoRepeatDelay = 50;
  50. this.nextPieces = [];
  51. this.nextPiecesCount = 3;
  52. this.scoreManager = new ScoreManager();
  53. this.gridManager = new GridManager(
  54. this.getWidth(),
  55. this.getHeight(),
  56. this.theme,
  57. );
  58. }
  59. getHeight(): number {
  60. return this.height;
  61. }
  62. getWidth(): number {
  63. return this.width;
  64. }
  65. getCurrentGrid(): GridType {
  66. return this.gridManager.getCurrentGrid();
  67. }
  68. isGamePaused(): boolean {
  69. return this.gamePaused;
  70. }
  71. onFreeze = () => {
  72. this.gridManager.freezeTetromino(this.currentObject, this.scoreManager);
  73. this.createTetromino();
  74. };
  75. setNewGameTick(level: number) {
  76. if (level >= GameLogic.levelTicks.length) return;
  77. this.gameTick = GameLogic.levelTicks[level];
  78. this.stopTick();
  79. this.startTick();
  80. }
  81. startClock() {
  82. this.gameTimeInterval = setInterval(() => {
  83. this.onClock(this.clockCallback);
  84. }, 1000);
  85. }
  86. startTick() {
  87. this.gameTickInterval = setInterval(() => {
  88. this.onTick(this.tickCallback);
  89. }, this.gameTick);
  90. }
  91. stopClock() {
  92. clearInterval(this.gameTimeInterval);
  93. }
  94. stopTick() {
  95. clearInterval(this.gameTickInterval);
  96. }
  97. stopGameTime() {
  98. this.stopClock();
  99. this.stopTick();
  100. }
  101. startGameTime() {
  102. this.startClock();
  103. this.startTick();
  104. }
  105. onTick(callback: TickCallbackType) {
  106. this.currentObject.tryMove(
  107. 0,
  108. 1,
  109. this.gridManager.getCurrentGrid(),
  110. this.getWidth(),
  111. this.getHeight(),
  112. this.onFreeze,
  113. );
  114. callback(
  115. this.scoreManager.getScore(),
  116. this.scoreManager.getLevel(),
  117. this.gridManager.getCurrentGrid(),
  118. );
  119. if (this.scoreManager.canLevelUp())
  120. this.setNewGameTick(this.scoreManager.getLevel());
  121. }
  122. onClock(callback: ClockCallbackType) {
  123. this.gameTime += 1;
  124. callback(this.gameTime);
  125. }
  126. canUseInput(): boolean {
  127. return this.gameRunning && !this.gamePaused;
  128. }
  129. rightPressed(callback: MovementCallbackType) {
  130. this.isPressedIn = true;
  131. this.movePressedRepeat(true, callback, 1, 0);
  132. }
  133. leftPressedIn(callback: MovementCallbackType) {
  134. this.isPressedIn = true;
  135. this.movePressedRepeat(true, callback, -1, 0);
  136. }
  137. downPressedIn(callback: MovementCallbackType) {
  138. this.isPressedIn = true;
  139. this.movePressedRepeat(true, callback, 0, 1);
  140. }
  141. movePressedRepeat(
  142. isInitial: boolean,
  143. callback: MovementCallbackType,
  144. x: number,
  145. y: number,
  146. ) {
  147. if (!this.canUseInput() || !this.isPressedIn) return;
  148. const moved = this.currentObject.tryMove(
  149. x,
  150. y,
  151. this.gridManager.getCurrentGrid(),
  152. this.getWidth(),
  153. this.getHeight(),
  154. this.onFreeze,
  155. );
  156. if (moved) {
  157. if (y === 1) {
  158. this.scoreManager.incrementScore();
  159. callback(
  160. this.gridManager.getCurrentGrid(),
  161. this.scoreManager.getScore(),
  162. );
  163. } else callback(this.gridManager.getCurrentGrid());
  164. }
  165. this.pressInInterval = setTimeout(
  166. () => {
  167. this.movePressedRepeat(false, callback, x, y);
  168. },
  169. isInitial ? this.autoRepeatActivationDelay : this.autoRepeatDelay,
  170. );
  171. }
  172. pressedOut() {
  173. this.isPressedIn = false;
  174. clearTimeout(this.pressInInterval);
  175. }
  176. rotatePressed(callback: MovementCallbackType) {
  177. if (!this.canUseInput()) return;
  178. if (
  179. this.currentObject.tryRotate(
  180. this.gridManager.getCurrentGrid(),
  181. this.getWidth(),
  182. this.getHeight(),
  183. )
  184. )
  185. callback(this.gridManager.getCurrentGrid());
  186. }
  187. getNextPiecesPreviews(): Array<GridType> {
  188. const finalArray = [];
  189. for (let i = 0; i < this.nextPieces.length; i += 1) {
  190. const gridSize = this.nextPieces[i].getCurrentShape().getCurrentShape()[0]
  191. .length;
  192. finalArray.push(this.gridManager.getEmptyGrid(gridSize, gridSize));
  193. this.nextPieces[i].toGrid(finalArray[i], true);
  194. }
  195. return finalArray;
  196. }
  197. recoverNextPiece() {
  198. this.currentObject = this.nextPieces.shift();
  199. this.generateNextPieces();
  200. }
  201. generateNextPieces() {
  202. while (this.nextPieces.length < this.nextPiecesCount) {
  203. this.nextPieces.push(new Piece(this.theme));
  204. }
  205. }
  206. createTetromino() {
  207. this.pressedOut();
  208. this.recoverNextPiece();
  209. if (
  210. !this.currentObject.isPositionValid(
  211. this.gridManager.getCurrentGrid(),
  212. this.getWidth(),
  213. this.getHeight(),
  214. )
  215. )
  216. this.endGame(false);
  217. }
  218. togglePause() {
  219. if (!this.gameRunning) return;
  220. this.gamePaused = !this.gamePaused;
  221. if (this.gamePaused) this.stopGameTime();
  222. else this.startGameTime();
  223. }
  224. endGame(isRestart: boolean) {
  225. this.gameRunning = false;
  226. this.gamePaused = false;
  227. this.stopGameTime();
  228. this.endCallback(this.gameTime, this.scoreManager.getScore(), isRestart);
  229. }
  230. startGame(
  231. tickCallback: TickCallbackType,
  232. clockCallback: ClockCallbackType,
  233. endCallback: EndCallbackType,
  234. ) {
  235. if (this.gameRunning) this.endGame(true);
  236. this.gameRunning = true;
  237. this.gamePaused = false;
  238. this.gameTime = 0;
  239. this.scoreManager = new ScoreManager();
  240. this.gameTick = GameLogic.levelTicks[this.scoreManager.getLevel()];
  241. this.gridManager = new GridManager(
  242. this.getWidth(),
  243. this.getHeight(),
  244. this.theme,
  245. );
  246. this.nextPieces = [];
  247. this.generateNextPieces();
  248. this.createTetromino();
  249. tickCallback(
  250. this.scoreManager.getScore(),
  251. this.scoreManager.getLevel(),
  252. this.gridManager.getCurrentGrid(),
  253. );
  254. clockCallback(this.gameTime);
  255. this.startTick();
  256. this.startClock();
  257. this.tickCallback = tickCallback;
  258. this.clockCallback = clockCallback;
  259. this.endCallback = endCallback;
  260. }
  261. }