Improved game UI

This commit is contained in:
Arnaud Vergnet 2020-07-18 22:38:17 +02:00
parent fdf0fffabc
commit 4bff6e15a8
7 changed files with 179 additions and 123 deletions

View file

@ -363,6 +363,9 @@
}, },
"game": { "game": {
"title": "Game", "title": "Game",
"score": "Score : %{score}",
"time": "Time :",
"level": "Level :",
"pause": "Game Paused", "pause": "Game Paused",
"pauseMessage": "The game is paused", "pauseMessage": "The game is paused",
"resume": "Resume", "resume": "Resume",

View file

@ -361,16 +361,19 @@
"homeButtonSubtitle": "Contacte le développeur de l'appli" "homeButtonSubtitle": "Contacte le développeur de l'appli"
}, },
"game": { "game": {
"title": "Le jeu trop ouf", "title": "Le Jeu trop ouf",
"score": "Score : %{score}",
"time": "Temps :",
"level": "Niveau :",
"pause": "Pause", "pause": "Pause",
"pauseMessage": "Le jeu est en pause", "pauseMessage": "T'as fait pause, t'es nul",
"resume": "Continuer", "resume": "Continuer",
"restart": { "restart": {
"text": "Redémarrer", "text": "Redémarrer",
"confirm": "Est-tu sûr de vouloir redémarrer ?", "confirm": "T'es sûr de vouloir redémarrer ?",
"confirmMessage": "Tout ton progrès sera perdu, continuer ?", "confirmMessage": "Tout ton progrès sera perdu, continuer ?",
"confirmYes": "Oui", "confirmYes": "Oui",
"confirmNo": "Non" "confirmNo": "Oula non"
}, },
"gameOver": { "gameOver": {
"text": "Game Over", "text": "Game Over",

View file

@ -119,8 +119,7 @@ export default class ThemeManager {
tutorinsaColor: '#f93943', tutorinsaColor: '#f93943',
// Tetris // Tetris
tetrisBackground: '#e6e6e6', tetrisBackground: '#f0f0f0',
tetrisBorder: '#2f2f2f',
tetrisScore: '#e2bd33', tetrisScore: '#e2bd33',
tetrisI: '#3cd9e6', tetrisI: '#3cd9e6',
tetrisO: '#ffdd00', tetrisO: '#ffdd00',
@ -182,8 +181,7 @@ export default class ThemeManager {
tutorinsaColor: '#f93943', tutorinsaColor: '#f93943',
// Tetris // Tetris
tetrisBackground: '#2c2c2c', tetrisBackground: '#181818',
tetrisBorder: '#1b1b1b',
tetrisScore: '#e2d707', tetrisScore: '#e2d707',
tetrisI: '#30b3be', tetrisI: '#30b3be',
tetrisO: '#c1a700', tetrisO: '#c1a700',

View file

@ -21,9 +21,8 @@ class CellComponent extends React.PureComponent<Props> {
style={{ style={{
flex: 1, flex: 1,
backgroundColor: item.isEmpty ? 'transparent' : item.color, backgroundColor: item.isEmpty ? 'transparent' : item.color,
borderColor: item.isEmpty ? 'transparent' : this.props.theme.colors.tetrisBorder, borderColor: 'transparent',
borderStyle: 'solid', borderRadius: 4,
borderRadius: 2,
borderWidth: 1, borderWidth: 1,
aspectRatio: 1, aspectRatio: 1,
}} }}

View file

@ -5,16 +5,15 @@ import {View} from 'react-native';
import {withTheme} from 'react-native-paper'; import {withTheme} from 'react-native-paper';
import type {Cell} from "./CellComponent"; import type {Cell} from "./CellComponent";
import CellComponent from "./CellComponent"; import CellComponent from "./CellComponent";
import type {ViewStyle} from "react-native/Libraries/StyleSheet/StyleSheet";
export type Grid = Array<Array<CellComponent>>; export type Grid = Array<Array<CellComponent>>;
type Props = { type Props = {
grid: Array<Array<Object>>, grid: Array<Array<Object>>,
backgroundColor: string,
height: number, height: number,
width: number, width: number,
containerMaxHeight: number | string, style: ViewStyle,
containerMaxWidth: number | string,
} }
class GridComponent extends React.Component<Props> { class GridComponent extends React.Component<Props> {
@ -23,10 +22,7 @@ class GridComponent extends React.Component<Props> {
let cells = this.props.grid[rowNumber].map(this.getCellRender); let cells = this.props.grid[rowNumber].map(this.getCellRender);
return ( return (
<View <View
style={{ style={{flexDirection: 'row',}}
flexDirection: 'row',
backgroundColor: this.props.backgroundColor,
}}
key={rowNumber.toString()} key={rowNumber.toString()}
> >
{cells} {cells}
@ -49,12 +45,8 @@ class GridComponent extends React.Component<Props> {
render() { render() {
return ( return (
<View style={{ <View style={{
flexDirection: 'column',
maxWidth: this.props.containerMaxWidth,
maxHeight: this.props.containerMaxHeight,
aspectRatio: this.props.width / this.props.height, aspectRatio: this.props.width / this.props.height,
marginLeft: 'auto', ...this.props.style
marginRight: 'auto',
}}> }}>
{this.getGrid()} {this.getGrid()}
</View> </View>

View file

@ -5,9 +5,11 @@ import {View} from 'react-native';
import {withTheme} from 'react-native-paper'; import {withTheme} from 'react-native-paper';
import type {Grid} from "./GridComponent"; import type {Grid} from "./GridComponent";
import GridComponent from "./GridComponent"; import GridComponent from "./GridComponent";
import type {ViewStyle} from "react-native/Libraries/StyleSheet/StyleSheet";
type Props = { type Props = {
items: Array<Grid>, items: Array<Grid>,
style: ViewStyle
} }
class Preview extends React.PureComponent<Props> { class Preview extends React.PureComponent<Props> {
@ -25,9 +27,10 @@ class Preview extends React.PureComponent<Props> {
width={item[0].length} width={item[0].length}
height={item.length} height={item.length}
grid={item} grid={item}
containerMaxHeight={50} style={{
containerMaxWidth={50} marginRight: 5,
backgroundColor={'transparent'} marginLeft: 5,
}}
key={index.toString()} key={index.toString()}
/>; />;
}; };
@ -35,7 +38,7 @@ class Preview extends React.PureComponent<Props> {
render() { render() {
if (this.props.items.length > 0) { if (this.props.items.length > 0) {
return ( return (
<View> <View style={this.props.style}>
{this.getGrids()} {this.getGrids()}
</View> </View>
); );

View file

@ -2,7 +2,7 @@
import * as React from 'react'; import * as React from 'react';
import {View} from 'react-native'; import {View} from 'react-native';
import {IconButton, Text, withTheme} from 'react-native-paper'; import {Caption, IconButton, Text, withTheme} from 'react-native-paper';
import MaterialCommunityIcons from "react-native-vector-icons/MaterialCommunityIcons"; import MaterialCommunityIcons from "react-native-vector-icons/MaterialCommunityIcons";
import GameLogic from "../logic/GameLogic"; import GameLogic from "../logic/GameLogic";
import type {Grid} from "../components/GridComponent"; import type {Grid} from "../components/GridComponent";
@ -51,7 +51,8 @@ class GameMainScreen extends React.Component<Props, State> {
dialogTitle: "", dialogTitle: "",
dialogMessage: "", dialogMessage: "",
dialogButtons: [], dialogButtons: [],
onDialogDismiss: () => {}, onDialogDismiss: () => {
},
}; };
this.props.navigation.addListener('blur', this.onScreenBlur); this.props.navigation.addListener('blur', this.onScreenBlur);
this.props.navigation.addListener('focus', this.onScreenFocus); this.props.navigation.addListener('focus', this.onScreenFocus);
@ -146,11 +147,11 @@ class GameMainScreen extends React.Component<Props, State> {
dialogMessage: i18n.t("screens.game.pauseMessage"), dialogMessage: i18n.t("screens.game.pauseMessage"),
dialogButtons: [ dialogButtons: [
{ {
title: i18n.t("screens.game.restart.text"), title: i18n.t("screens.game.restart.text"),
onPress: this.showRestartConfirm onPress: this.showRestartConfirm
}, },
{ {
title: i18n.t("screens.game.resume"), title: i18n.t("screens.game.resume"),
onPress: onDismiss onPress: onDismiss
} }
], ],
@ -165,14 +166,14 @@ class GameMainScreen extends React.Component<Props, State> {
dialogMessage: i18n.t("screens.game.restart.confirmMessage"), dialogMessage: i18n.t("screens.game.restart.confirmMessage"),
dialogButtons: [ dialogButtons: [
{ {
title: i18n.t("screens.game.restart.confirmYes"), title: i18n.t("screens.game.restart.confirmYes"),
onPress: () => { onPress: () => {
this.onDialogDismiss(); this.onDialogDismiss();
this.startGame(); this.startGame();
} }
}, },
{ {
title: i18n.t("screens.game.restart.confirmNo"), title: i18n.t("screens.game.restart.confirmNo"),
onPress: this.showPausePopup onPress: this.showPausePopup
} }
], ],
@ -194,11 +195,11 @@ class GameMainScreen extends React.Component<Props, State> {
dialogMessage: message, dialogMessage: message,
dialogButtons: [ dialogButtons: [
{ {
title: i18n.t("screens.game.gameOver.exit"), title: i18n.t("screens.game.gameOver.exit"),
onPress: () => this.props.navigation.goBack() onPress: () => this.props.navigation.goBack()
}, },
{ {
title: i18n.t("screens.game.resume"), title: i18n.t("screens.game.resume"),
onPress: onDismiss onPress: onDismiss
} }
], ],
@ -223,111 +224,168 @@ class GameMainScreen extends React.Component<Props, State> {
this.showGameOverConfirm(); this.showGameOverConfirm();
} }
render() { getStatusIcons() {
const colors = this.props.theme.colors;
return ( return (
<View style={{ <View style={{
width: '100%', flex: 1,
height: '100%', marginTop: "auto",
marginBottom: "auto"
}}> }}>
<View style={{ <View style={{
flexDirection: 'row',
position: 'absolute',
top: 5,
left: 10,
}}>
<MaterialCommunityIcons
name={'timer'}
color={colors.subtitle}
size={20}/>
<Text style={{
marginLeft: 5,
color: colors.subtitle
}}>{this.getFormattedTime(this.state.gameTime)}</Text>
</View>
<View style={{
flexDirection: 'row',
position: 'absolute',
top: 50,
left: 10,
}}>
<MaterialCommunityIcons
name={'gamepad'}
color={colors.text}
size={20}/>
<Text style={{
marginLeft: 5
}}>{this.state.gameLevel}</Text>
</View>
<View style={{
flexDirection: 'row',
marginRight: 'auto',
marginLeft: 'auto', marginLeft: 'auto',
marginRight: 'auto',
}}> }}>
<MaterialCommunityIcons <Caption style={{
name={'star'} marginLeft: "auto",
color={colors.tetrisScore} marginRight: "auto",
size={30}/> marginBottom: 5,
<Text style={{ }}>{i18n.t("screens.game.time")}</Caption>
marginLeft: 5, <View style={{
fontSize: 22, flexDirection: "row"
}}>{this.state.gameScore}</Text> }}>
<MaterialCommunityIcons
name={'timer'}
color={this.props.theme.colors.subtitle}
size={20}/>
<Text style={{
marginLeft: 5,
color: this.props.theme.colors.subtitle
}}>{this.getFormattedTime(this.state.gameTime)}</Text>
</View>
</View> </View>
<GridComponent <View style={{
width={this.logic.getWidth()} marginLeft: 'auto',
height={this.logic.getHeight()} marginRight: 'auto',
containerMaxHeight={'80%'} marginTop: 20,
containerMaxWidth={'60%'} }}>
grid={this.state.grid} <Caption style={{
backgroundColor={colors.tetrisBackground} marginLeft: "auto",
marginRight: "auto",
marginBottom: 5,
}}>{i18n.t("screens.game.level")}</Caption>
<View style={{
flexDirection: "row"
}}>
<MaterialCommunityIcons
name={'gamepad-square'}
color={this.props.theme.colors.text}
size={20}/>
<Text style={{
marginLeft: 5
}}>{this.state.gameLevel}</Text>
</View>
</View>
</View>
);
}
getScoreIcon() {
return (
<View style={{
flexDirection: "row",
marginLeft: "auto",
marginRight: "auto",
marginTop: 10,
marginBottom: 10,
}}>
<Text style={{
marginLeft: 5,
fontSize: 22,
}}>{i18n.t("screens.game.score", {score: this.state.gameScore})}</Text>
<MaterialCommunityIcons
name={'star'}
color={this.props.theme.colors.tetrisScore}
size={20}
style={{
marginTop: "auto",
marginBottom: "auto",
marginLeft: 5
}}/>
</View>
);
}
getControlButtons() {
return (
<View style={{
height: 80,
flexDirection: "row"
}}>
<IconButton
icon="rotate-right-variant"
size={40}
onPress={() => this.logic.rotatePressed(this.updateGrid)}
style={{flex: 1}}
/> />
<View style={{ <View style={{
position: 'absolute',
top: 50,
right: 5,
}}>
<Preview
items={this.logic.getNextPiecesPreviews()}
/>
</View>
<View style={{
position: 'absolute',
bottom: 0,
flexDirection: 'row', flexDirection: 'row',
width: '100%', flex: 4
}}> }}>
<IconButton <IconButton
icon="rotate-right-variant" icon="chevron-left"
size={40} size={40}
onPress={() => this.logic.rotatePressed(this.updateGrid)} style={{flex: 1}}
style={{marginRight: 'auto'}} onPress={() => this.logic.pressedOut()}
/> onPressIn={() => this.logic.leftPressedIn(this.updateGrid)}
<View style={{
flexDirection: 'row',
}}>
<IconButton
icon="arrow-left"
size={40}
onPress={() => this.logic.pressedOut()}
onPressIn={() => this.logic.leftPressedIn(this.updateGrid)}
/> />
<IconButton <IconButton
icon="arrow-right" icon="chevron-right"
size={40} size={40}
onPress={() => this.logic.pressedOut()} style={{flex: 1}}
onPressIn={() => this.logic.rightPressed(this.updateGrid)} onPress={() => this.logic.pressedOut()}
onPressIn={() => this.logic.rightPressed(this.updateGrid)}
/>
</View>
<IconButton
icon="arrow-down-bold"
size={40}
onPressIn={() => this.logic.downPressedIn(this.updateGridScore)}
onPress={() => this.logic.pressedOut()}
style={{flex: 1}}
color={this.props.theme.colors.tetrisScore}
/>
</View>
);
}
render() {
return (
<View style={{flex: 1}}>
<View style={{
flex: 1,
flexDirection: "row",
}}>
{this.getStatusIcons()}
<View style={{flex: 4}}>
{this.getScoreIcon()}
<GridComponent
width={this.logic.getWidth()}
height={this.logic.getHeight()}
grid={this.state.grid}
style={{
backgroundColor: this.props.theme.colors.tetrisBackground,
flex: 1,
marginLeft: "auto",
marginRight: "auto",
}}
/>
</View>
<View style={{flex: 1}}>
<Preview
items={this.logic.getNextPiecesPreviews()}
style={{
marginLeft: 'auto',
marginRight: 'auto',
marginTop: 10,
}}
/> />
</View> </View>
<IconButton
icon="arrow-down"
size={40}
onPressIn={() => this.logic.downPressedIn(this.updateGridScore)}
onPress={() => this.logic.pressedOut()}
style={{marginLeft: 'auto'}}
color={colors.tetrisScore}
/>
</View> </View>
{this.getControlButtons()}
<OptionsDialog <OptionsDialog
visible={this.state.dialogVisible} visible={this.state.dialogVisible}
title={this.state.dialogTitle} title={this.state.dialogTitle}