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.

GameMainScreen.js 14KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424
  1. // @flow
  2. import * as React from 'react';
  3. import {View} from 'react-native';
  4. import {Caption, IconButton, Text, withTheme} from 'react-native-paper';
  5. import MaterialCommunityIcons from "react-native-vector-icons/MaterialCommunityIcons";
  6. import GameLogic from "../logic/GameLogic";
  7. import type {Grid} from "../components/GridComponent";
  8. import GridComponent from "../components/GridComponent";
  9. import Preview from "../components/Preview";
  10. import i18n from "i18n-js";
  11. import MaterialHeaderButtons, {Item} from "../../../components/Overrides/CustomHeaderButton";
  12. import {StackNavigationProp} from "@react-navigation/stack";
  13. import type {CustomTheme} from "../../../managers/ThemeManager";
  14. import type {OptionsDialogButton} from "../../../components/Dialogs/OptionsDialog";
  15. import OptionsDialog from "../../../components/Dialogs/OptionsDialog";
  16. type Props = {
  17. navigation: StackNavigationProp,
  18. route: { params: { highScore: number }, ... },
  19. theme: CustomTheme,
  20. }
  21. type State = {
  22. grid: Grid,
  23. gameRunning: boolean,
  24. gameTime: number,
  25. gameScore: number,
  26. gameLevel: number,
  27. dialogVisible: boolean,
  28. dialogTitle: string,
  29. dialogMessage: string,
  30. dialogButtons: Array<OptionsDialogButton>,
  31. onDialogDismiss: () => void,
  32. }
  33. class GameMainScreen extends React.Component<Props, State> {
  34. logic: GameLogic;
  35. highScore: number | null;
  36. constructor(props) {
  37. super(props);
  38. this.logic = new GameLogic(20, 10, this.props.theme);
  39. this.state = {
  40. grid: this.logic.getCurrentGrid(),
  41. gameRunning: false,
  42. gameTime: 0,
  43. gameScore: 0,
  44. gameLevel: 0,
  45. dialogVisible: false,
  46. dialogTitle: "",
  47. dialogMessage: "",
  48. dialogButtons: [],
  49. onDialogDismiss: () => {
  50. },
  51. };
  52. if (this.props.route.params != null)
  53. this.highScore = this.props.route.params.highScore;
  54. }
  55. componentDidMount() {
  56. this.props.navigation.setOptions({
  57. headerRight: this.getRightButton,
  58. });
  59. this.startGame();
  60. }
  61. getRightButton = () => {
  62. return <MaterialHeaderButtons>
  63. <Item title="pause" iconName="pause" onPress={this.togglePause}/>
  64. </MaterialHeaderButtons>;
  65. }
  66. getFormattedTime(seconds: number) {
  67. let date = new Date();
  68. date.setHours(0);
  69. date.setMinutes(0);
  70. date.setSeconds(seconds);
  71. let format;
  72. if (date.getHours())
  73. format = date.getHours() + ':' + date.getMinutes() + ':' + date.getSeconds();
  74. else if (date.getMinutes())
  75. format = date.getMinutes() + ':' + date.getSeconds();
  76. else
  77. format = date.getSeconds();
  78. return format;
  79. }
  80. onTick = (score: number, level: number, newGrid: Grid) => {
  81. this.setState({
  82. gameScore: score,
  83. gameLevel: level,
  84. grid: newGrid,
  85. });
  86. }
  87. onClock = (time: number) => {
  88. this.setState({
  89. gameTime: time,
  90. });
  91. }
  92. updateGrid = (newGrid: Grid) => {
  93. this.setState({
  94. grid: newGrid,
  95. });
  96. }
  97. updateGridScore = (newGrid: Grid, score: number) => {
  98. this.setState({
  99. grid: newGrid,
  100. gameScore: score,
  101. });
  102. }
  103. togglePause = () => {
  104. this.logic.togglePause();
  105. if (this.logic.isGamePaused())
  106. this.showPausePopup();
  107. }
  108. onDialogDismiss = () => this.setState({dialogVisible: false});
  109. showPausePopup = () => {
  110. const onDismiss = () => {
  111. this.togglePause();
  112. this.onDialogDismiss();
  113. };
  114. this.setState({
  115. dialogVisible: true,
  116. dialogTitle: i18n.t("screens.game.pause"),
  117. dialogMessage: i18n.t("screens.game.pauseMessage"),
  118. dialogButtons: [
  119. {
  120. title: i18n.t("screens.game.restart.text"),
  121. onPress: this.showRestartConfirm
  122. },
  123. {
  124. title: i18n.t("screens.game.resume"),
  125. onPress: onDismiss
  126. }
  127. ],
  128. onDialogDismiss: onDismiss,
  129. });
  130. }
  131. showRestartConfirm = () => {
  132. this.setState({
  133. dialogVisible: true,
  134. dialogTitle: i18n.t("screens.game.restart.confirm"),
  135. dialogMessage: i18n.t("screens.game.restart.confirmMessage"),
  136. dialogButtons: [
  137. {
  138. title: i18n.t("screens.game.restart.confirmYes"),
  139. onPress: () => {
  140. this.onDialogDismiss();
  141. this.startGame();
  142. }
  143. },
  144. {
  145. title: i18n.t("screens.game.restart.confirmNo"),
  146. onPress: this.showPausePopup
  147. }
  148. ],
  149. onDialogDismiss: this.showPausePopup,
  150. });
  151. }
  152. showGameOverConfirm() {
  153. let message = i18n.t("screens.game.gameOver.score") + this.state.gameScore + '\n';
  154. message += i18n.t("screens.game.gameOver.level") + this.state.gameLevel + '\n';
  155. message += i18n.t("screens.game.gameOver.time") + this.getFormattedTime(this.state.gameTime) + '\n';
  156. const onDismiss = () => {
  157. this.onDialogDismiss();
  158. this.startGame();
  159. };
  160. this.setState({
  161. dialogVisible: true,
  162. dialogTitle: i18n.t("screens.game.gameOver.text"),
  163. dialogMessage: message,
  164. dialogButtons: [
  165. {
  166. title: i18n.t("screens.game.gameOver.exit"),
  167. onPress: () => this.props.navigation.goBack()
  168. },
  169. {
  170. title: i18n.t("screens.game.resume"),
  171. onPress: onDismiss
  172. }
  173. ],
  174. onDialogDismiss: onDismiss,
  175. });
  176. }
  177. startGame = () => {
  178. this.logic.startGame(this.onTick, this.onClock, this.onGameEnd);
  179. this.setState({
  180. gameRunning: true,
  181. });
  182. }
  183. onGameEnd = (time: number, score: number, isRestart: boolean) => {
  184. this.setState({
  185. gameTime: time,
  186. gameScore: score,
  187. gameRunning: false,
  188. });
  189. if (!isRestart)
  190. this.props.navigation.replace(
  191. "game-start",
  192. {
  193. score: this.state.gameScore,
  194. level: this.state.gameLevel,
  195. time: this.state.gameTime,
  196. }
  197. );
  198. }
  199. getStatusIcons() {
  200. return (
  201. <View style={{
  202. flex: 1,
  203. marginTop: "auto",
  204. marginBottom: "auto"
  205. }}>
  206. <View style={{
  207. marginLeft: 'auto',
  208. marginRight: 'auto',
  209. }}>
  210. <Caption style={{
  211. marginLeft: "auto",
  212. marginRight: "auto",
  213. marginBottom: 5,
  214. }}>{i18n.t("screens.game.time")}</Caption>
  215. <View style={{
  216. flexDirection: "row"
  217. }}>
  218. <MaterialCommunityIcons
  219. name={'timer'}
  220. color={this.props.theme.colors.subtitle}
  221. size={20}/>
  222. <Text style={{
  223. marginLeft: 5,
  224. color: this.props.theme.colors.subtitle
  225. }}>{this.getFormattedTime(this.state.gameTime)}</Text>
  226. </View>
  227. </View>
  228. <View style={{
  229. marginLeft: 'auto',
  230. marginRight: 'auto',
  231. marginTop: 20,
  232. }}>
  233. <Caption style={{
  234. marginLeft: "auto",
  235. marginRight: "auto",
  236. marginBottom: 5,
  237. }}>{i18n.t("screens.game.level")}</Caption>
  238. <View style={{
  239. flexDirection: "row"
  240. }}>
  241. <MaterialCommunityIcons
  242. name={'gamepad-square'}
  243. color={this.props.theme.colors.text}
  244. size={20}/>
  245. <Text style={{
  246. marginLeft: 5
  247. }}>{this.state.gameLevel}</Text>
  248. </View>
  249. </View>
  250. </View>
  251. );
  252. }
  253. getScoreIcon() {
  254. let highScore = this.highScore == null || this.state.gameScore > this.highScore
  255. ? this.state.gameScore
  256. : this.highScore;
  257. return (
  258. <View style={{
  259. marginTop: 10,
  260. marginBottom: 10,
  261. }}>
  262. <View style={{
  263. flexDirection: "row",
  264. marginLeft: "auto",
  265. marginRight: "auto",
  266. }}>
  267. <Text style={{
  268. marginLeft: 5,
  269. fontSize: 20,
  270. }}>{i18n.t("screens.game.score", {score: this.state.gameScore})}</Text>
  271. <MaterialCommunityIcons
  272. name={'star'}
  273. color={this.props.theme.colors.tetrisScore}
  274. size={20}
  275. style={{
  276. marginTop: "auto",
  277. marginBottom: "auto",
  278. marginLeft: 5
  279. }}/>
  280. </View>
  281. <View style={{
  282. flexDirection: "row",
  283. marginLeft: "auto",
  284. marginRight: "auto",
  285. marginTop: 5,
  286. }}>
  287. <Text style={{
  288. marginLeft: 5,
  289. fontSize: 10,
  290. color: this.props.theme.colors.textDisabled
  291. }}>{i18n.t("screens.game.highScore", {score: highScore})}</Text>
  292. <MaterialCommunityIcons
  293. name={'star'}
  294. color={this.props.theme.colors.tetrisScore}
  295. size={10}
  296. style={{
  297. marginTop: "auto",
  298. marginBottom: "auto",
  299. marginLeft: 5
  300. }}/>
  301. </View>
  302. </View>
  303. );
  304. }
  305. getControlButtons() {
  306. return (
  307. <View style={{
  308. height: 80,
  309. flexDirection: "row"
  310. }}>
  311. <IconButton
  312. icon="rotate-right-variant"
  313. size={40}
  314. onPress={() => this.logic.rotatePressed(this.updateGrid)}
  315. style={{flex: 1}}
  316. />
  317. <View style={{
  318. flexDirection: 'row',
  319. flex: 4
  320. }}>
  321. <IconButton
  322. icon="chevron-left"
  323. size={40}
  324. style={{flex: 1}}
  325. onPress={() => this.logic.pressedOut()}
  326. onPressIn={() => this.logic.leftPressedIn(this.updateGrid)}
  327. />
  328. <IconButton
  329. icon="chevron-right"
  330. size={40}
  331. style={{flex: 1}}
  332. onPress={() => this.logic.pressedOut()}
  333. onPressIn={() => this.logic.rightPressed(this.updateGrid)}
  334. />
  335. </View>
  336. <IconButton
  337. icon="arrow-down-bold"
  338. size={40}
  339. onPressIn={() => this.logic.downPressedIn(this.updateGridScore)}
  340. onPress={() => this.logic.pressedOut()}
  341. style={{flex: 1}}
  342. color={this.props.theme.colors.tetrisScore}
  343. />
  344. </View>
  345. );
  346. }
  347. render() {
  348. return (
  349. <View style={{flex: 1}}>
  350. <View style={{
  351. flex: 1,
  352. flexDirection: "row",
  353. }}>
  354. {this.getStatusIcons()}
  355. <View style={{flex: 4}}>
  356. {this.getScoreIcon()}
  357. <GridComponent
  358. width={this.logic.getWidth()}
  359. height={this.logic.getHeight()}
  360. grid={this.state.grid}
  361. style={{
  362. backgroundColor: this.props.theme.colors.tetrisBackground,
  363. flex: 1,
  364. marginLeft: "auto",
  365. marginRight: "auto",
  366. }}
  367. />
  368. </View>
  369. <View style={{flex: 1}}>
  370. <Preview
  371. items={this.logic.getNextPiecesPreviews()}
  372. style={{
  373. marginLeft: 'auto',
  374. marginRight: 'auto',
  375. marginTop: 10,
  376. }}
  377. />
  378. </View>
  379. </View>
  380. {this.getControlButtons()}
  381. <OptionsDialog
  382. visible={this.state.dialogVisible}
  383. title={this.state.dialogTitle}
  384. message={this.state.dialogMessage}
  385. buttons={this.state.dialogButtons}
  386. onDismiss={this.state.onDialogDismiss}
  387. />
  388. </View>
  389. );
  390. }
  391. }
  392. export default withTheme(GameMainScreen);