123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427 |
- // @flow
-
- import * as React from "react";
- import {StackNavigationProp} from "@react-navigation/stack";
- import type {CustomTheme} from "../../../managers/ThemeManager";
- import {Button, Card, Divider, Headline, Paragraph, Text, withTheme} from "react-native-paper";
- import {View} from "react-native";
- import i18n from "i18n-js";
- import Mascot, {MASCOT_STYLE} from "../../../components/Mascot/Mascot";
- import MascotPopup from "../../../components/Mascot/MascotPopup";
- import AsyncStorageManager from "../../../managers/AsyncStorageManager";
- import type {Grid} from "../components/GridComponent";
- import GridComponent from "../components/GridComponent";
- import GridManager from "../logic/GridManager";
- import Piece from "../logic/Piece";
- import * as Animatable from "react-native-animatable";
- import MaterialCommunityIcons from "react-native-vector-icons/MaterialCommunityIcons";
- import LinearGradient from "react-native-linear-gradient";
- import SpeechArrow from "../../../components/Mascot/SpeechArrow";
- import CollapsibleScrollView from "../../../components/Collapsible/CollapsibleScrollView";
-
- type GameStats = {
- score: number,
- level: number,
- time: number,
- }
-
- type Props = {
- navigation: StackNavigationProp,
- route: {
- params: GameStats
- },
- theme: CustomTheme,
- }
-
- class GameStartScreen extends React.Component<Props> {
-
- gridManager: GridManager;
- scores: Array<number>;
-
- gameStats: GameStats | null;
- isHighScore: boolean;
-
- constructor(props: Props) {
- super(props);
- this.gridManager = new GridManager(4, 4, props.theme);
- this.scores = AsyncStorageManager.getObject(AsyncStorageManager.PREFERENCES.gameScores.key);
- this.scores.sort((a, b) => b - a);
- if (this.props.route.params != null)
- this.recoverGameScore();
- }
-
- recoverGameScore() {
- this.gameStats = this.props.route.params;
- this.isHighScore = this.scores.length === 0 || this.gameStats.score > this.scores[0];
- for (let i = 0; i < 3; i++) {
- if (this.scores.length > i && this.gameStats.score > this.scores[i]) {
- this.scores.splice(i, 0, this.gameStats.score);
- break;
- } else if (this.scores.length <= i) {
- this.scores.push(this.gameStats.score);
- break;
- }
- }
- if (this.scores.length > 3)
- this.scores.splice(3, 1);
- AsyncStorageManager.set(AsyncStorageManager.PREFERENCES.gameScores.key, this.scores);
- }
-
- getPiecesBackground() {
- let gridList = [];
- for (let i = 0; i < 18; i++) {
- gridList.push(this.gridManager.getEmptyGrid(4, 4));
- const piece = new Piece(this.props.theme);
- piece.toGrid(gridList[i], true);
- }
- return (
- <View style={{
- position: "absolute",
- width: "100%",
- height: "100%",
- }}>
- {gridList.map((item: Grid, index: number) => {
- const size = 10 + Math.floor(Math.random() * 30);
- const top = Math.floor(Math.random() * 100);
- const rot = Math.floor(Math.random() * 360);
- const left = (index % 6) * 20;
- const animDelay = size * 20;
- const animDuration = 2 * (2000 - (size * 30));
- return (
- <Animatable.View
- animation={"fadeInDownBig"}
- delay={animDelay}
- duration={animDuration}
- key={"piece" + index.toString()}
- style={{
- width: size + "%",
- position: "absolute",
- top: top + "%",
- left: left + "%",
- }}
- >
- <GridComponent
- width={4}
- height={4}
- grid={item}
- style={{
- transform: [{rotateZ: rot + "deg"}],
- }}
- />
- </Animatable.View>
- );
- })}
- </View>
- );
- }
-
- getPostGameContent(stats: GameStats) {
- return (
- <View style={{
- flex: 1
- }}>
- <Mascot
- emotion={this.isHighScore ? MASCOT_STYLE.LOVE : MASCOT_STYLE.NORMAL}
- animated={this.isHighScore}
- style={{
- width: this.isHighScore ? "50%" : "30%",
- marginLeft: this.isHighScore ? "auto" : null,
- marginRight: this.isHighScore ? "auto" : null,
- }}/>
- <SpeechArrow
- style={{marginLeft: this.isHighScore ? "60%" : "20%"}}
- size={20}
- color={this.props.theme.colors.mascotMessageArrow}
- />
- <Card style={{
- borderColor: this.props.theme.colors.mascotMessageArrow,
- borderWidth: 2,
- marginLeft: 20,
- marginRight: 20,
- }}>
- <Card.Content>
- <Headline
- style={{
- textAlign: "center",
- color: this.isHighScore
- ? this.props.theme.colors.gameGold
- : this.props.theme.colors.primary
- }}>
- {this.isHighScore
- ? i18n.t("screens.game.newHighScore")
- : i18n.t("screens.game.gameOver")}
- </Headline>
- <Divider/>
- <View style={{
- flexDirection: "row",
- marginLeft: "auto",
- marginRight: "auto",
- marginTop: 10,
- marginBottom: 10,
- }}>
- <Text style={{
- fontSize: 20,
- }}>
- {i18n.t("screens.game.score", {score: stats.score})}
- </Text>
- <MaterialCommunityIcons
- name={'star'}
- color={this.props.theme.colors.tetrisScore}
- size={30}
- style={{
- marginLeft: 5
- }}/>
- </View>
- <View style={{
- flexDirection: "row",
- marginLeft: "auto",
- marginRight: "auto",
- }}>
- <Text>{i18n.t("screens.game.level")}</Text>
- <MaterialCommunityIcons
- style={{
- marginRight: 5,
- marginLeft: 5,
- }}
- name={"gamepad-square"}
- size={20}
- color={this.props.theme.colors.textDisabled}
- />
- <Text>
- {stats.level}
- </Text>
- </View>
- <View style={{
- flexDirection: "row",
- marginLeft: "auto",
- marginRight: "auto",
- }}>
- <Text>{i18n.t("screens.game.time")}</Text>
- <MaterialCommunityIcons
- style={{
- marginRight: 5,
- marginLeft: 5,
- }}
- name={"timer"}
- size={20}
- color={this.props.theme.colors.textDisabled}
- />
- <Text>
- {stats.time}
- </Text>
- </View>
- </Card.Content>
- </Card>
- </View>
- )
- }
-
- getWelcomeText() {
- return (
- <View>
- <Mascot emotion={MASCOT_STYLE.COOL} style={{
- width: "40%",
- marginLeft: "auto",
- marginRight: "auto",
- }}/>
- <SpeechArrow
- style={{marginLeft: "60%"}}
- size={20}
- color={this.props.theme.colors.mascotMessageArrow}
- />
- <Card style={{
- borderColor: this.props.theme.colors.mascotMessageArrow,
- borderWidth: 2,
- marginLeft: 10,
- marginRight: 10,
- }}>
- <Card.Content>
- <Headline
- style={{
- textAlign: "center",
- color: this.props.theme.colors.primary
- }}>
- {i18n.t("screens.game.welcomeTitle")}
- </Headline>
- <Divider/>
- <Paragraph
- style={{
- textAlign: "center",
- marginTop: 10,
- }}>
- {i18n.t("screens.game.welcomeMessage")}
- </Paragraph>
- </Card.Content>
- </Card>
- </View>
- );
- }
-
- getPodiumRender(place: 1 | 2 | 3, score: string) {
- let icon = "podium-gold";
- let color = this.props.theme.colors.gameGold;
- let fontSize = 20;
- let size = 70;
- if (place === 2) {
- icon = "podium-silver";
- color = this.props.theme.colors.gameSilver;
- fontSize = 18;
- size = 60;
- } else if (place === 3) {
- icon = "podium-bronze";
- color = this.props.theme.colors.gameBronze;
- fontSize = 15;
- size = 50;
- }
- return (
- <View style={{
- marginLeft: place === 2 ? 20 : "auto",
- marginRight: place === 3 ? 20 : "auto",
- flexDirection: "column",
- alignItems: "center",
- justifyContent: "flex-end",
- }}>
- {
- this.isHighScore && place === 1
- ?
- <Animatable.View
- animation={"swing"}
- iterationCount={"infinite"}
- duration={2000}
- delay={1000}
- useNativeDriver={true}
- style={{
- position: "absolute",
- top: -20
- }}
- >
- <Animatable.View
- animation={"pulse"}
- iterationCount={"infinite"}
- useNativeDriver={true}
- >
- <MaterialCommunityIcons
- name={"decagram"}
- color={this.props.theme.colors.gameGold}
- size={150}
- />
- </Animatable.View>
- </Animatable.View>
-
- : null
- }
- <MaterialCommunityIcons
- name={icon}
- color={this.isHighScore && place === 1 ? "#fff" : color}
- size={size}
- />
- <Text style={{
- textAlign: "center",
- fontWeight: place === 1 ? "bold" : null,
- fontSize: fontSize,
- }}>{score}</Text>
- </View>
- );
- }
-
- getTopScoresRender() {
- const gold = this.scores.length > 0
- ? this.scores[0]
- : "-";
- const silver = this.scores.length > 1
- ? this.scores[1]
- : "-";
- const bronze = this.scores.length > 2
- ? this.scores[2]
- : "-";
- return (
- <View style={{
- marginBottom: 20,
- marginTop: 20
- }}>
- {this.getPodiumRender(1, gold.toString())}
- <View style={{
- flexDirection: "row",
- marginLeft: "auto",
- marginRight: "auto",
- }}>
- {this.getPodiumRender(3, bronze.toString())}
- {this.getPodiumRender(2, silver.toString())}
- </View>
- </View>
- );
- }
-
- getMainContent() {
- return (
- <View style={{flex: 1}}>
- {
- this.gameStats != null
- ? this.getPostGameContent(this.gameStats)
- : this.getWelcomeText()
- }
- <Button
- icon={"play"}
- mode={"contained"}
- onPress={() => this.props.navigation.replace(
- "game-main",
- {
- highScore: this.scores.length > 0
- ? this.scores[0]
- : null
- }
- )}
- style={{
- marginLeft: "auto",
- marginRight: "auto",
- marginTop: 10,
- }}
- >
- {i18n.t("screens.game.play")}
- </Button>
- {this.getTopScoresRender()}
- </View>
- )
- }
-
- keyExtractor = (item: number) => item.toString();
-
- render() {
- return (
- <View style={{flex: 1}}>
- {this.getPiecesBackground()}
- <LinearGradient
- style={{flex: 1}}
- colors={[
- this.props.theme.colors.background + "00",
- this.props.theme.colors.background
- ]}
- start={{x: 0, y: 0}}
- end={{x: 0, y: 1}}
- >
- <CollapsibleScrollView>
- {this.getMainContent()}
- <MascotPopup
- prefKey={AsyncStorageManager.PREFERENCES.gameStartShowBanner.key}
- title={i18n.t("screens.game.mascotDialog.title")}
- message={i18n.t("screens.game.mascotDialog.message")}
- icon={"gamepad-variant"}
- buttons={{
- action: null,
- cancel: {
- message: i18n.t("screens.game.mascotDialog.button"),
- icon: "check",
- }
- }}
- emotion={MASCOT_STYLE.COOL}
- />
- </CollapsibleScrollView>
- </LinearGradient>
- </View>
-
- );
- }
- }
-
- export default withTheme(GameStartScreen);
|