Compare commits
20 commits
42731d26a1
...
3bc45704f6
| Author | SHA1 | Date | |
|---|---|---|---|
| 3bc45704f6 | |||
| 7da30e0af6 | |||
| 7a00452cc0 | |||
| 879ae46abe | |||
| dbe03a2a2d | |||
| 7d718141e7 | |||
| 79e72784d1 | |||
| b29973189f | |||
| 07d8fb8d15 | |||
| e5bde81964 | |||
| 7980b8b422 | |||
| 3affbfcb40 | |||
| c9237cc824 | |||
| 7f33c8376d | |||
| 8fc5cfb25e | |||
| 3fe1d85eec | |||
| a32294e394 | |||
| 7b45841c30 | |||
| bb54186d9e | |||
| 3aaf56a660 |
9 changed files with 1125 additions and 1 deletions
|
|
@ -6,6 +6,7 @@ import i18n from "i18n-js";
|
||||||
import * as WebBrowser from 'expo-web-browser';
|
import * as WebBrowser from 'expo-web-browser';
|
||||||
import SidebarDivider from "./SidebarDivider";
|
import SidebarDivider from "./SidebarDivider";
|
||||||
import SidebarItem from "./SidebarItem";
|
import SidebarItem from "./SidebarItem";
|
||||||
|
import {TouchableRipple} from "react-native-paper";
|
||||||
|
|
||||||
const deviceWidth = Dimensions.get("window").width;
|
const deviceWidth = Dimensions.get("window").width;
|
||||||
|
|
||||||
|
|
@ -154,9 +155,17 @@ export default class SideBar extends React.PureComponent<Props, State> {
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
|
const onPress = this.onListItemPress.bind(this, {route: 'TetrisScreen'});
|
||||||
return (
|
return (
|
||||||
<View style={{height: '100%'}}>
|
<View style={{height: '100%'}}>
|
||||||
<Image source={require("../assets/drawer-cover.png")} style={styles.drawerCover}/>
|
<TouchableRipple
|
||||||
|
onPress={onPress}
|
||||||
|
>
|
||||||
|
<Image
|
||||||
|
source={require("../assets/drawer-cover.png")}
|
||||||
|
style={styles.drawerCover}
|
||||||
|
/>
|
||||||
|
</TouchableRipple>
|
||||||
<FlatList
|
<FlatList
|
||||||
data={this.dataSet}
|
data={this.dataSet}
|
||||||
extraData={this.state}
|
extraData={this.state}
|
||||||
|
|
|
||||||
|
|
@ -9,6 +9,7 @@ import AboutDependenciesScreen from '../screens/About/AboutDependenciesScreen';
|
||||||
import SelfMenuScreen from '../screens/SelfMenuScreen';
|
import SelfMenuScreen from '../screens/SelfMenuScreen';
|
||||||
import AvailableRoomScreen from "../screens/Websites/AvailableRoomScreen";
|
import AvailableRoomScreen from "../screens/Websites/AvailableRoomScreen";
|
||||||
import BibScreen from "../screens/Websites/BibScreen";
|
import BibScreen from "../screens/Websites/BibScreen";
|
||||||
|
import TetrisScreen from "../screens/Tetris/TetrisScreen";
|
||||||
import DebugScreen from '../screens/About/DebugScreen';
|
import DebugScreen from '../screens/About/DebugScreen';
|
||||||
import Sidebar from "../components/Sidebar";
|
import Sidebar from "../components/Sidebar";
|
||||||
import {createStackNavigator, TransitionPresets} from "@react-navigation/stack";
|
import {createStackNavigator, TransitionPresets} from "@react-navigation/stack";
|
||||||
|
|
@ -161,6 +162,30 @@ function BibStackComponent() {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const TetrisStack = createStackNavigator();
|
||||||
|
|
||||||
|
function TetrisStackComponent() {
|
||||||
|
return (
|
||||||
|
<TetrisStack.Navigator
|
||||||
|
initialRouteName="TetrisScreen"
|
||||||
|
headerMode="float"
|
||||||
|
screenOptions={defaultScreenOptions}
|
||||||
|
>
|
||||||
|
<TetrisStack.Screen
|
||||||
|
name="TetrisScreen"
|
||||||
|
component={TetrisScreen}
|
||||||
|
options={({navigation}) => {
|
||||||
|
const openDrawer = getDrawerButton.bind(this, navigation);
|
||||||
|
return {
|
||||||
|
title: 'Tetris',
|
||||||
|
headerLeft: openDrawer
|
||||||
|
};
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</TetrisStack.Navigator>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
const Drawer = createDrawerNavigator();
|
const Drawer = createDrawerNavigator();
|
||||||
|
|
||||||
function getDrawerContent(props) {
|
function getDrawerContent(props) {
|
||||||
|
|
@ -202,6 +227,10 @@ export default function DrawerNavigator() {
|
||||||
name="BibScreen"
|
name="BibScreen"
|
||||||
component={BibStackComponent}
|
component={BibStackComponent}
|
||||||
/>
|
/>
|
||||||
|
<Drawer.Screen
|
||||||
|
name="TetrisScreen"
|
||||||
|
component={TetrisStackComponent}
|
||||||
|
/>
|
||||||
</Drawer.Navigator>
|
</Drawer.Navigator>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
370
screens/Tetris/GameLogic.js
Normal file
370
screens/Tetris/GameLogic.js
Normal file
|
|
@ -0,0 +1,370 @@
|
||||||
|
// @flow
|
||||||
|
|
||||||
|
import Tetromino from "./Tetromino";
|
||||||
|
|
||||||
|
export default class GameLogic {
|
||||||
|
|
||||||
|
static levelTicks = [
|
||||||
|
1000,
|
||||||
|
800,
|
||||||
|
600,
|
||||||
|
400,
|
||||||
|
300,
|
||||||
|
200,
|
||||||
|
150,
|
||||||
|
100,
|
||||||
|
];
|
||||||
|
|
||||||
|
static scoreLinesModifier = [40, 100, 300, 1200];
|
||||||
|
|
||||||
|
currentGrid: Array<Array<Object>>;
|
||||||
|
|
||||||
|
height: number;
|
||||||
|
width: number;
|
||||||
|
|
||||||
|
gameRunning: boolean;
|
||||||
|
gamePaused: boolean;
|
||||||
|
gameTime: number;
|
||||||
|
score: number;
|
||||||
|
level: number;
|
||||||
|
|
||||||
|
currentObject: Tetromino;
|
||||||
|
|
||||||
|
gameTick: number;
|
||||||
|
gameTickInterval: IntervalID;
|
||||||
|
gameTimeInterval: IntervalID;
|
||||||
|
|
||||||
|
pressInInterval: TimeoutID;
|
||||||
|
isPressedIn: boolean;
|
||||||
|
autoRepeatActivationDelay: number;
|
||||||
|
autoRepeatDelay: number;
|
||||||
|
|
||||||
|
nextPieces: Array<Tetromino>;
|
||||||
|
nextPiecesCount: number;
|
||||||
|
|
||||||
|
onTick: Function;
|
||||||
|
onClock: Function;
|
||||||
|
endCallback: Function;
|
||||||
|
|
||||||
|
colors: Object;
|
||||||
|
|
||||||
|
levelProgression: number;
|
||||||
|
|
||||||
|
constructor(height: number, width: number, colors: Object) {
|
||||||
|
this.height = height;
|
||||||
|
this.width = width;
|
||||||
|
this.gameRunning = false;
|
||||||
|
this.gamePaused = false;
|
||||||
|
this.colors = colors;
|
||||||
|
this.autoRepeatActivationDelay = 300;
|
||||||
|
this.autoRepeatDelay = 50;
|
||||||
|
this.nextPieces = [];
|
||||||
|
this.nextPiecesCount = 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
getNextPieces() {
|
||||||
|
let finalArray = [];
|
||||||
|
for (let i = 0; i < this.nextPieces.length; i++) {
|
||||||
|
finalArray.push(this.getEmptyGrid(4, 4));
|
||||||
|
let coord = this.nextPieces[i].getCellsCoordinates(false);
|
||||||
|
this.tetrominoToGrid(this.nextPieces[i], coord, finalArray[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return finalArray;
|
||||||
|
}
|
||||||
|
|
||||||
|
getHeight(): number {
|
||||||
|
return this.height;
|
||||||
|
}
|
||||||
|
|
||||||
|
getWidth(): number {
|
||||||
|
return this.width;
|
||||||
|
}
|
||||||
|
|
||||||
|
isGameRunning(): boolean {
|
||||||
|
return this.gameRunning;
|
||||||
|
}
|
||||||
|
|
||||||
|
isGamePaused(): boolean {
|
||||||
|
return this.gamePaused;
|
||||||
|
}
|
||||||
|
|
||||||
|
getEmptyLine(width: number) {
|
||||||
|
let line = [];
|
||||||
|
for (let col = 0; col < width; col++) {
|
||||||
|
line.push({
|
||||||
|
color: this.colors.tetrisBackground,
|
||||||
|
isEmpty: true,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return line;
|
||||||
|
}
|
||||||
|
|
||||||
|
getEmptyGrid(height: number, width: number) {
|
||||||
|
let grid = [];
|
||||||
|
for (let row = 0; row < height; row++) {
|
||||||
|
grid.push(this.getEmptyLine(width));
|
||||||
|
}
|
||||||
|
return grid;
|
||||||
|
}
|
||||||
|
|
||||||
|
getGridCopy() {
|
||||||
|
return JSON.parse(JSON.stringify(this.currentGrid));
|
||||||
|
}
|
||||||
|
|
||||||
|
getFinalGrid() {
|
||||||
|
let coord = this.currentObject.getCellsCoordinates(true);
|
||||||
|
let finalGrid = this.getGridCopy();
|
||||||
|
for (let i = 0; i < coord.length; i++) {
|
||||||
|
finalGrid[coord[i].y][coord[i].x] = {
|
||||||
|
color: this.currentObject.getColor(),
|
||||||
|
isEmpty: false,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
return finalGrid;
|
||||||
|
}
|
||||||
|
|
||||||
|
getLinesRemovedPoints(numberRemoved: number) {
|
||||||
|
if (numberRemoved < 1 || numberRemoved > 4)
|
||||||
|
return 0;
|
||||||
|
return GameLogic.scoreLinesModifier[numberRemoved-1] * (this.level + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
canLevelUp() {
|
||||||
|
let canLevel = this.levelProgression > this.level * 5;
|
||||||
|
if (canLevel)
|
||||||
|
this.levelProgression -= this.level * 5;
|
||||||
|
return canLevel;
|
||||||
|
}
|
||||||
|
|
||||||
|
tetrominoToGrid(object: Object, coord : Array<Object>, grid: Array<Array<Object>>) {
|
||||||
|
for (let i = 0; i < coord.length; i++) {
|
||||||
|
grid[coord[i].y][coord[i].x] = {
|
||||||
|
color: object.getColor(),
|
||||||
|
isEmpty: false,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
freezeTetromino() {
|
||||||
|
let coord = this.currentObject.getCellsCoordinates(true);
|
||||||
|
this.tetrominoToGrid(this.currentObject, coord, this.currentGrid);
|
||||||
|
this.clearLines(this.getLinesToClear(coord));
|
||||||
|
}
|
||||||
|
|
||||||
|
clearLines(lines: Array<number>) {
|
||||||
|
lines.sort();
|
||||||
|
for (let i = 0; i < lines.length; i++) {
|
||||||
|
this.currentGrid.splice(lines[i], 1);
|
||||||
|
this.currentGrid.unshift(this.getEmptyLine(this.getWidth()));
|
||||||
|
}
|
||||||
|
switch (lines.length) {
|
||||||
|
case 1:
|
||||||
|
this.levelProgression += 1;
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
this.levelProgression += 3;
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
this.levelProgression += 5;
|
||||||
|
break;
|
||||||
|
case 4: // Did a tetris !
|
||||||
|
this.levelProgression += 8;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
this.score += this.getLinesRemovedPoints(lines.length);
|
||||||
|
}
|
||||||
|
|
||||||
|
getLinesToClear(coord: Object) {
|
||||||
|
let rows = [];
|
||||||
|
for (let i = 0; i < coord.length; i++) {
|
||||||
|
let isLineFull = true;
|
||||||
|
for (let col = 0; col < this.getWidth(); col++) {
|
||||||
|
if (this.currentGrid[coord[i].y][col].isEmpty) {
|
||||||
|
isLineFull = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (isLineFull && rows.indexOf(coord[i].y) === -1)
|
||||||
|
rows.push(coord[i].y);
|
||||||
|
}
|
||||||
|
return rows;
|
||||||
|
}
|
||||||
|
|
||||||
|
isTetrominoPositionValid() {
|
||||||
|
let isValid = true;
|
||||||
|
let coord = this.currentObject.getCellsCoordinates(true);
|
||||||
|
for (let i = 0; i < coord.length; i++) {
|
||||||
|
if (coord[i].x >= this.getWidth()
|
||||||
|
|| coord[i].x < 0
|
||||||
|
|| coord[i].y >= this.getHeight()
|
||||||
|
|| coord[i].y < 0
|
||||||
|
|| !this.currentGrid[coord[i].y][coord[i].x].isEmpty) {
|
||||||
|
isValid = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return isValid;
|
||||||
|
}
|
||||||
|
|
||||||
|
tryMoveTetromino(x: number, y: number) {
|
||||||
|
if (x > 1) x = 1; // Prevent moving from more than one tile
|
||||||
|
if (x < -1) x = -1;
|
||||||
|
if (y > 1) y = 1;
|
||||||
|
if (y < -1) y = -1;
|
||||||
|
if (x !== 0 && y !== 0) y = 0; // Prevent diagonal movement
|
||||||
|
|
||||||
|
this.currentObject.move(x, y);
|
||||||
|
let isValid = this.isTetrominoPositionValid();
|
||||||
|
|
||||||
|
if (!isValid && x !== 0)
|
||||||
|
this.currentObject.move(-x, 0);
|
||||||
|
else if (!isValid && y !== 0) {
|
||||||
|
this.currentObject.move(0, -y);
|
||||||
|
this.freezeTetromino();
|
||||||
|
this.createTetromino();
|
||||||
|
} else
|
||||||
|
return true;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
tryRotateTetromino() {
|
||||||
|
this.currentObject.rotate(true);
|
||||||
|
if (!this.isTetrominoPositionValid()) {
|
||||||
|
this.currentObject.rotate(false);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
setNewGameTick(level: number) {
|
||||||
|
if (level >= GameLogic.levelTicks.length)
|
||||||
|
return;
|
||||||
|
this.gameTick = GameLogic.levelTicks[level];
|
||||||
|
clearInterval(this.gameTickInterval);
|
||||||
|
this.gameTickInterval = setInterval(this.onTick, this.gameTick);
|
||||||
|
}
|
||||||
|
|
||||||
|
onTick(callback: Function) {
|
||||||
|
this.tryMoveTetromino(0, 1);
|
||||||
|
callback(this.score, this.level, this.getFinalGrid());
|
||||||
|
if (this.canLevelUp()) {
|
||||||
|
this.level++;
|
||||||
|
this.setNewGameTick(this.level);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
onClock(callback: Function) {
|
||||||
|
this.gameTime++;
|
||||||
|
callback(this.gameTime);
|
||||||
|
}
|
||||||
|
|
||||||
|
canUseInput() {
|
||||||
|
return this.gameRunning && !this.gamePaused
|
||||||
|
}
|
||||||
|
|
||||||
|
rightPressed(callback: Function) {
|
||||||
|
this.isPressedIn = true;
|
||||||
|
this.movePressedRepeat(true, callback, 1, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
leftPressedIn(callback: Function) {
|
||||||
|
this.isPressedIn = true;
|
||||||
|
this.movePressedRepeat(true, callback, -1, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
downPressedIn(callback: Function) {
|
||||||
|
this.isPressedIn = true;
|
||||||
|
this.movePressedRepeat(true, callback, 0, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
movePressedRepeat(isInitial: boolean, callback: Function, x: number, y: number) {
|
||||||
|
if (!this.canUseInput() || !this.isPressedIn)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (this.tryMoveTetromino(x, y)) {
|
||||||
|
if (y === 1) {
|
||||||
|
this.score++;
|
||||||
|
callback(this.getFinalGrid(), this.score);
|
||||||
|
} else
|
||||||
|
callback(this.getFinalGrid());
|
||||||
|
}
|
||||||
|
this.pressInInterval = setTimeout(() => this.movePressedRepeat(false, callback, x, y), isInitial ? this.autoRepeatActivationDelay : this.autoRepeatDelay);
|
||||||
|
}
|
||||||
|
|
||||||
|
pressedOut() {
|
||||||
|
this.isPressedIn = false;
|
||||||
|
clearTimeout(this.pressInInterval);
|
||||||
|
}
|
||||||
|
|
||||||
|
rotatePressed(callback: Function) {
|
||||||
|
if (!this.canUseInput())
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (this.tryRotateTetromino())
|
||||||
|
callback(this.getFinalGrid());
|
||||||
|
}
|
||||||
|
|
||||||
|
recoverNextPiece() {
|
||||||
|
this.currentObject = this.nextPieces.shift();
|
||||||
|
this.generateNextPieces();
|
||||||
|
}
|
||||||
|
|
||||||
|
generateNextPieces() {
|
||||||
|
while (this.nextPieces.length < this.nextPiecesCount) {
|
||||||
|
let shape = Math.floor(Math.random() * 7);
|
||||||
|
this.nextPieces.push(new Tetromino(shape, this.colors));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
createTetromino() {
|
||||||
|
this.pressedOut();
|
||||||
|
this.recoverNextPiece();
|
||||||
|
if (!this.isTetrominoPositionValid())
|
||||||
|
this.endGame(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
togglePause() {
|
||||||
|
if (!this.gameRunning)
|
||||||
|
return;
|
||||||
|
this.gamePaused = !this.gamePaused;
|
||||||
|
if (this.gamePaused) {
|
||||||
|
clearInterval(this.gameTickInterval);
|
||||||
|
clearInterval(this.gameTimeInterval);
|
||||||
|
} else {
|
||||||
|
this.gameTickInterval = setInterval(this.onTick, this.gameTick);
|
||||||
|
this.gameTimeInterval = setInterval(this.onClock, 1000);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
endGame(isRestart: boolean) {
|
||||||
|
this.gameRunning = false;
|
||||||
|
this.gamePaused = false;
|
||||||
|
clearInterval(this.gameTickInterval);
|
||||||
|
clearInterval(this.gameTimeInterval);
|
||||||
|
this.endCallback(this.gameTime, this.score, isRestart);
|
||||||
|
}
|
||||||
|
|
||||||
|
startGame(tickCallback: Function, clockCallback: Function, endCallback: Function) {
|
||||||
|
if (this.gameRunning)
|
||||||
|
this.endGame(true);
|
||||||
|
this.gameRunning = true;
|
||||||
|
this.gamePaused = false;
|
||||||
|
this.gameTime = 0;
|
||||||
|
this.score = 0;
|
||||||
|
this.level = 0;
|
||||||
|
this.levelProgression = 0;
|
||||||
|
this.gameTick = GameLogic.levelTicks[this.level];
|
||||||
|
this.currentGrid = this.getEmptyGrid(this.getHeight(), this.getWidth());
|
||||||
|
this.nextPieces = [];
|
||||||
|
this.generateNextPieces();
|
||||||
|
this.createTetromino();
|
||||||
|
tickCallback(this.score, this.level, this.getFinalGrid());
|
||||||
|
clockCallback(this.gameTime);
|
||||||
|
this.onTick = this.onTick.bind(this, tickCallback);
|
||||||
|
this.onClock = this.onClock.bind(this, clockCallback);
|
||||||
|
this.gameTickInterval = setInterval(this.onTick, this.gameTick);
|
||||||
|
this.gameTimeInterval = setInterval(this.onClock, 1000);
|
||||||
|
this.endCallback = endCallback;
|
||||||
|
}
|
||||||
|
}
|
||||||
303
screens/Tetris/TetrisScreen.js
Normal file
303
screens/Tetris/TetrisScreen.js
Normal file
|
|
@ -0,0 +1,303 @@
|
||||||
|
// @flow
|
||||||
|
|
||||||
|
import * as React from 'react';
|
||||||
|
import {Alert, View} from 'react-native';
|
||||||
|
import {IconButton, Text, withTheme} from 'react-native-paper';
|
||||||
|
import {MaterialCommunityIcons} from "@expo/vector-icons";
|
||||||
|
import GameLogic from "./GameLogic";
|
||||||
|
import Grid from "./components/Grid";
|
||||||
|
import HeaderButton from "../../components/HeaderButton";
|
||||||
|
import Preview from "./components/Preview";
|
||||||
|
|
||||||
|
type Props = {
|
||||||
|
navigation: Object,
|
||||||
|
}
|
||||||
|
|
||||||
|
type State = {
|
||||||
|
grid: Array<Array<Object>>,
|
||||||
|
gameRunning: boolean,
|
||||||
|
gameTime: number,
|
||||||
|
gameScore: number,
|
||||||
|
gameLevel: number,
|
||||||
|
}
|
||||||
|
|
||||||
|
class TetrisScreen extends React.Component<Props, State> {
|
||||||
|
|
||||||
|
colors: Object;
|
||||||
|
|
||||||
|
logic: GameLogic;
|
||||||
|
onTick: Function;
|
||||||
|
onClock: Function;
|
||||||
|
onGameEnd: Function;
|
||||||
|
updateGrid: Function;
|
||||||
|
updateGridScore: Function;
|
||||||
|
|
||||||
|
constructor(props) {
|
||||||
|
super(props);
|
||||||
|
this.colors = props.theme.colors;
|
||||||
|
this.logic = new GameLogic(20, 10, this.colors);
|
||||||
|
this.state = {
|
||||||
|
grid: this.logic.getEmptyGrid(this.logic.getHeight(), this.logic.getWidth()),
|
||||||
|
gameRunning: false,
|
||||||
|
gameTime: 0,
|
||||||
|
gameScore: 0,
|
||||||
|
gameLevel: 0,
|
||||||
|
};
|
||||||
|
this.onTick = this.onTick.bind(this);
|
||||||
|
this.onClock = this.onClock.bind(this);
|
||||||
|
this.onGameEnd = this.onGameEnd.bind(this);
|
||||||
|
this.updateGrid = this.updateGrid.bind(this);
|
||||||
|
this.updateGridScore = this.updateGridScore.bind(this);
|
||||||
|
this.props.navigation.addListener('blur', this.onScreenBlur.bind(this));
|
||||||
|
this.props.navigation.addListener('focus', this.onScreenFocus.bind(this));
|
||||||
|
}
|
||||||
|
|
||||||
|
componentDidMount() {
|
||||||
|
const rightButton = this.getRightButton.bind(this);
|
||||||
|
this.props.navigation.setOptions({
|
||||||
|
headerRight: rightButton,
|
||||||
|
});
|
||||||
|
this.startGame();
|
||||||
|
}
|
||||||
|
|
||||||
|
getRightButton() {
|
||||||
|
return (
|
||||||
|
<View
|
||||||
|
style={{
|
||||||
|
flexDirection: 'row',
|
||||||
|
}}>
|
||||||
|
<HeaderButton icon={'pause'} onPress={() => this.togglePause()}/>
|
||||||
|
</View>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove any interval on un-focus
|
||||||
|
*/
|
||||||
|
onScreenBlur() {
|
||||||
|
if (!this.logic.isGamePaused())
|
||||||
|
this.logic.togglePause();
|
||||||
|
}
|
||||||
|
|
||||||
|
onScreenFocus() {
|
||||||
|
if (!this.logic.isGameRunning())
|
||||||
|
this.startGame();
|
||||||
|
else if (this.logic.isGamePaused())
|
||||||
|
this.showPausePopup();
|
||||||
|
}
|
||||||
|
|
||||||
|
getFormattedTime(seconds: number) {
|
||||||
|
let date = new Date();
|
||||||
|
date.setHours(0);
|
||||||
|
date.setMinutes(0);
|
||||||
|
date.setSeconds(seconds);
|
||||||
|
let format;
|
||||||
|
if (date.getHours())
|
||||||
|
format = date.getHours() + ':' + date.getMinutes() + ':' + date.getSeconds();
|
||||||
|
else if (date.getMinutes())
|
||||||
|
format = date.getMinutes() + ':' + date.getSeconds();
|
||||||
|
else
|
||||||
|
format = date.getSeconds();
|
||||||
|
return format;
|
||||||
|
}
|
||||||
|
|
||||||
|
onTick(score: number, level: number, newGrid: Array<Array<Object>>) {
|
||||||
|
this.setState({
|
||||||
|
gameScore: score,
|
||||||
|
gameLevel: level,
|
||||||
|
grid: newGrid,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
onClock(time: number) {
|
||||||
|
this.setState({
|
||||||
|
gameTime: time,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
updateGrid(newGrid: Array<Array<Object>>) {
|
||||||
|
this.setState({
|
||||||
|
grid: newGrid,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
updateGridScore(newGrid: Array<Array<Object>>, score: number) {
|
||||||
|
this.setState({
|
||||||
|
grid: newGrid,
|
||||||
|
gameScore: score,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
togglePause() {
|
||||||
|
this.logic.togglePause();
|
||||||
|
if (this.logic.isGamePaused())
|
||||||
|
this.showPausePopup();
|
||||||
|
}
|
||||||
|
|
||||||
|
showPausePopup() {
|
||||||
|
Alert.alert(
|
||||||
|
'PAUSE',
|
||||||
|
'GAME PAUSED',
|
||||||
|
[
|
||||||
|
{text: 'RESTART', onPress: () => this.showRestartConfirm()},
|
||||||
|
{text: 'RESUME', onPress: () => this.togglePause()},
|
||||||
|
],
|
||||||
|
{cancelable: false},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
showRestartConfirm() {
|
||||||
|
Alert.alert(
|
||||||
|
'RESTART?',
|
||||||
|
'WHOA THERE',
|
||||||
|
[
|
||||||
|
{text: 'NO', onPress: () => this.showPausePopup()},
|
||||||
|
{text: 'YES', onPress: () => this.startGame()},
|
||||||
|
],
|
||||||
|
{cancelable: false},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
showGameOverConfirm() {
|
||||||
|
let message = 'SCORE: ' + this.state.gameScore + '\n';
|
||||||
|
message += 'LEVEL: ' + this.state.gameLevel + '\n';
|
||||||
|
message += 'TIME: ' + this.getFormattedTime(this.state.gameTime) + '\n';
|
||||||
|
Alert.alert(
|
||||||
|
'GAME OVER',
|
||||||
|
message,
|
||||||
|
[
|
||||||
|
{text: 'LEAVE', onPress: () => this.props.navigation.goBack()},
|
||||||
|
{text: 'RESTART', onPress: () => this.startGame()},
|
||||||
|
],
|
||||||
|
{cancelable: false},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
startGame() {
|
||||||
|
this.logic.startGame(this.onTick, this.onClock, this.onGameEnd);
|
||||||
|
this.setState({
|
||||||
|
gameRunning: true,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
onGameEnd(time: number, score: number, isRestart: boolean) {
|
||||||
|
this.setState({
|
||||||
|
gameTime: time,
|
||||||
|
gameScore: score,
|
||||||
|
gameRunning: false,
|
||||||
|
});
|
||||||
|
if (!isRestart)
|
||||||
|
this.showGameOverConfirm();
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
return (
|
||||||
|
<View style={{
|
||||||
|
width: '100%',
|
||||||
|
height: '100%',
|
||||||
|
}}>
|
||||||
|
<View style={{
|
||||||
|
flexDirection: 'row',
|
||||||
|
position: 'absolute',
|
||||||
|
top: 5,
|
||||||
|
left: 10,
|
||||||
|
}}>
|
||||||
|
<MaterialCommunityIcons
|
||||||
|
name={'timer'}
|
||||||
|
color={this.colors.subtitle}
|
||||||
|
size={20}/>
|
||||||
|
<Text style={{
|
||||||
|
marginLeft: 5,
|
||||||
|
color: this.colors.subtitle
|
||||||
|
}}>{this.getFormattedTime(this.state.gameTime)}</Text>
|
||||||
|
</View>
|
||||||
|
<View style={{
|
||||||
|
flexDirection: 'row',
|
||||||
|
position: 'absolute',
|
||||||
|
top: 50,
|
||||||
|
left: 10,
|
||||||
|
}}>
|
||||||
|
<MaterialCommunityIcons
|
||||||
|
name={'gamepad'}
|
||||||
|
color={this.colors.text}
|
||||||
|
size={20}/>
|
||||||
|
<Text style={{
|
||||||
|
marginLeft: 5
|
||||||
|
}}>{this.state.gameLevel}</Text>
|
||||||
|
</View>
|
||||||
|
<View style={{
|
||||||
|
flexDirection: 'row',
|
||||||
|
marginRight: 'auto',
|
||||||
|
marginLeft: 'auto',
|
||||||
|
}}>
|
||||||
|
<MaterialCommunityIcons
|
||||||
|
name={'star'}
|
||||||
|
color={this.colors.tetrisScore}
|
||||||
|
size={30}/>
|
||||||
|
<Text style={{
|
||||||
|
marginLeft: 5,
|
||||||
|
fontSize: 22,
|
||||||
|
}}>{this.state.gameScore}</Text>
|
||||||
|
</View>
|
||||||
|
<Grid
|
||||||
|
width={this.logic.getWidth()}
|
||||||
|
height={this.logic.getHeight()}
|
||||||
|
containerMaxHeight={'80%'}
|
||||||
|
containerMaxWidth={'60%'}
|
||||||
|
grid={this.state.grid}
|
||||||
|
backgroundColor={this.colors.tetrisBackground}
|
||||||
|
/>
|
||||||
|
<View style={{
|
||||||
|
position: 'absolute',
|
||||||
|
top: 50,
|
||||||
|
right: 5,
|
||||||
|
}}>
|
||||||
|
<Preview
|
||||||
|
next={this.logic.getNextPieces()}
|
||||||
|
/>
|
||||||
|
</View>
|
||||||
|
<View style={{
|
||||||
|
position: 'absolute',
|
||||||
|
bottom: 0,
|
||||||
|
flexDirection: 'row',
|
||||||
|
width: '100%',
|
||||||
|
}}>
|
||||||
|
<IconButton
|
||||||
|
icon="format-rotate-90"
|
||||||
|
size={40}
|
||||||
|
onPress={() => this.logic.rotatePressed(this.updateGrid)}
|
||||||
|
style={{marginRight: 'auto'}}
|
||||||
|
/>
|
||||||
|
<View style={{
|
||||||
|
flexDirection: 'row',
|
||||||
|
}}>
|
||||||
|
<IconButton
|
||||||
|
icon="arrow-left"
|
||||||
|
size={40}
|
||||||
|
onPress={() => this.logic.pressedOut()}
|
||||||
|
onPressIn={() => this.logic.leftPressedIn(this.updateGrid)}
|
||||||
|
|
||||||
|
/>
|
||||||
|
<IconButton
|
||||||
|
icon="arrow-right"
|
||||||
|
size={40}
|
||||||
|
onPress={() => this.logic.pressedOut()}
|
||||||
|
onPressIn={() => this.logic.rightPressed(this.updateGrid)}
|
||||||
|
/>
|
||||||
|
</View>
|
||||||
|
<IconButton
|
||||||
|
icon="arrow-down"
|
||||||
|
size={40}
|
||||||
|
onPressIn={() => this.logic.downPressedIn(this.updateGridScore)}
|
||||||
|
onPress={() => this.logic.pressedOut()}
|
||||||
|
style={{marginLeft: 'auto'}}
|
||||||
|
color={this.colors.tetrisScore}
|
||||||
|
/>
|
||||||
|
</View>
|
||||||
|
</View>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
export default withTheme(TetrisScreen);
|
||||||
228
screens/Tetris/Tetromino.js
Normal file
228
screens/Tetris/Tetromino.js
Normal file
|
|
@ -0,0 +1,228 @@
|
||||||
|
export default class Tetromino {
|
||||||
|
|
||||||
|
static types = {
|
||||||
|
'I': 0,
|
||||||
|
'O': 1,
|
||||||
|
'T': 2,
|
||||||
|
'S': 3,
|
||||||
|
'Z': 4,
|
||||||
|
'J': 5,
|
||||||
|
'L': 6,
|
||||||
|
};
|
||||||
|
|
||||||
|
static shapes = [
|
||||||
|
[
|
||||||
|
[
|
||||||
|
[0, 0, 0, 0],
|
||||||
|
[1, 1, 1, 1],
|
||||||
|
[0, 0, 0, 0],
|
||||||
|
[0, 0, 0, 0],
|
||||||
|
],
|
||||||
|
[
|
||||||
|
[1, 1],
|
||||||
|
[1, 1],
|
||||||
|
],
|
||||||
|
[
|
||||||
|
[0, 1, 0],
|
||||||
|
[1, 1, 1],
|
||||||
|
[0, 0, 0],
|
||||||
|
],
|
||||||
|
[
|
||||||
|
[0, 1, 1],
|
||||||
|
[1, 1, 0],
|
||||||
|
[0, 0, 0],
|
||||||
|
],
|
||||||
|
[
|
||||||
|
[1, 1, 0],
|
||||||
|
[0, 1, 1],
|
||||||
|
[0, 0, 0],
|
||||||
|
],
|
||||||
|
[
|
||||||
|
[1, 0, 0],
|
||||||
|
[1, 1, 1],
|
||||||
|
[0, 0, 0],
|
||||||
|
],
|
||||||
|
[
|
||||||
|
[0, 0, 1],
|
||||||
|
[1, 1, 1],
|
||||||
|
[0, 0, 0],
|
||||||
|
],
|
||||||
|
],
|
||||||
|
[
|
||||||
|
[
|
||||||
|
[0, 0, 1, 0],
|
||||||
|
[0, 0, 1, 0],
|
||||||
|
[0, 0, 1, 0],
|
||||||
|
[0, 0, 1, 0],
|
||||||
|
],
|
||||||
|
[
|
||||||
|
[1, 1],
|
||||||
|
[1, 1],
|
||||||
|
],
|
||||||
|
[
|
||||||
|
[0, 1, 0],
|
||||||
|
[0, 1, 1],
|
||||||
|
[0, 1, 0],
|
||||||
|
],
|
||||||
|
[
|
||||||
|
[0, 1, 0],
|
||||||
|
[0, 1, 1],
|
||||||
|
[0, 0, 1],
|
||||||
|
],
|
||||||
|
[
|
||||||
|
[0, 0, 1],
|
||||||
|
[0, 1, 1],
|
||||||
|
[0, 1, 0],
|
||||||
|
],
|
||||||
|
[
|
||||||
|
[0, 1, 1],
|
||||||
|
[0, 1, 0],
|
||||||
|
[0, 1, 0],
|
||||||
|
],
|
||||||
|
[
|
||||||
|
[0, 1, 0],
|
||||||
|
[0, 1, 0],
|
||||||
|
[0, 1, 1],
|
||||||
|
],
|
||||||
|
],
|
||||||
|
[
|
||||||
|
[
|
||||||
|
[0, 0, 0, 0],
|
||||||
|
[0, 0, 0, 0],
|
||||||
|
[1, 1, 1, 1],
|
||||||
|
[0, 0, 0, 0],
|
||||||
|
],
|
||||||
|
[
|
||||||
|
[1, 1],
|
||||||
|
[1, 1],
|
||||||
|
],
|
||||||
|
[
|
||||||
|
[0, 0, 0],
|
||||||
|
[1, 1, 1],
|
||||||
|
[0, 1, 0],
|
||||||
|
],
|
||||||
|
[
|
||||||
|
[0, 0, 0],
|
||||||
|
[0, 1, 1],
|
||||||
|
[1, 1, 0],
|
||||||
|
],
|
||||||
|
[
|
||||||
|
[0, 0, 0],
|
||||||
|
[1, 1, 0],
|
||||||
|
[0, 1, 1],
|
||||||
|
],
|
||||||
|
[
|
||||||
|
[0, 0, 0],
|
||||||
|
[1, 1, 1],
|
||||||
|
[0, 0, 1],
|
||||||
|
],
|
||||||
|
[
|
||||||
|
[0, 0, 0],
|
||||||
|
[1, 1, 1],
|
||||||
|
[1, 0, 0],
|
||||||
|
],
|
||||||
|
],
|
||||||
|
[
|
||||||
|
[
|
||||||
|
[0, 1, 0, 0],
|
||||||
|
[0, 1, 0, 0],
|
||||||
|
[0, 1, 0, 0],
|
||||||
|
[0, 1, 0, 0],
|
||||||
|
],
|
||||||
|
[
|
||||||
|
[1, 1],
|
||||||
|
[1, 1],
|
||||||
|
],
|
||||||
|
[
|
||||||
|
[0, 1, 0],
|
||||||
|
[1, 1, 0],
|
||||||
|
[0, 1, 0],
|
||||||
|
],
|
||||||
|
[
|
||||||
|
[1, 0, 0],
|
||||||
|
[1, 1, 0],
|
||||||
|
[0, 1, 0],
|
||||||
|
],
|
||||||
|
[
|
||||||
|
[0, 1, 0],
|
||||||
|
[1, 1, 0],
|
||||||
|
[1, 0, 0],
|
||||||
|
],
|
||||||
|
[
|
||||||
|
[0, 1, 0],
|
||||||
|
[0, 1, 0],
|
||||||
|
[1, 1, 0],
|
||||||
|
],
|
||||||
|
[
|
||||||
|
[1, 1, 0],
|
||||||
|
[0, 1, 0],
|
||||||
|
[0, 1, 0],
|
||||||
|
],
|
||||||
|
],
|
||||||
|
];
|
||||||
|
|
||||||
|
static colors: Object;
|
||||||
|
|
||||||
|
currentType: Object;
|
||||||
|
currentShape: Object;
|
||||||
|
currentRotation: number;
|
||||||
|
position: Object;
|
||||||
|
colors: Object;
|
||||||
|
|
||||||
|
constructor(type: Tetromino.types, colors: Object) {
|
||||||
|
this.currentType = type;
|
||||||
|
this.currentRotation = 0;
|
||||||
|
this.currentShape = Tetromino.shapes[this.currentRotation][type];
|
||||||
|
this.position = {x: 0, y: 0};
|
||||||
|
if (this.currentType === Tetromino.types.O)
|
||||||
|
this.position.x = 4;
|
||||||
|
else
|
||||||
|
this.position.x = 3;
|
||||||
|
this.colors = colors;
|
||||||
|
Tetromino.colors = {
|
||||||
|
0: colors.tetrisI,
|
||||||
|
1: colors.tetrisO,
|
||||||
|
2: colors.tetrisT,
|
||||||
|
3: colors.tetrisS,
|
||||||
|
4: colors.tetrisZ,
|
||||||
|
5: colors.tetrisJ,
|
||||||
|
6: colors.tetrisL,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
getColor() {
|
||||||
|
return Tetromino.colors[this.currentType];
|
||||||
|
}
|
||||||
|
|
||||||
|
getCellsCoordinates(isAbsolute: boolean) {
|
||||||
|
let coordinates = [];
|
||||||
|
for (let row = 0; row < this.currentShape.length; row++) {
|
||||||
|
for (let col = 0; col < this.currentShape[row].length; col++) {
|
||||||
|
if (this.currentShape[row][col] === 1)
|
||||||
|
if (isAbsolute)
|
||||||
|
coordinates.push({x: this.position.x + col, y: this.position.y + row});
|
||||||
|
else
|
||||||
|
coordinates.push({x: col, y: row});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return coordinates;
|
||||||
|
}
|
||||||
|
|
||||||
|
rotate(isForward) {
|
||||||
|
if (isForward)
|
||||||
|
this.currentRotation++;
|
||||||
|
else
|
||||||
|
this.currentRotation--;
|
||||||
|
if (this.currentRotation > 3)
|
||||||
|
this.currentRotation = 0;
|
||||||
|
else if (this.currentRotation < 0)
|
||||||
|
this.currentRotation = 3;
|
||||||
|
this.currentShape = Tetromino.shapes[this.currentRotation][this.currentType];
|
||||||
|
}
|
||||||
|
|
||||||
|
move(x: number, y: number) {
|
||||||
|
this.position.x += x;
|
||||||
|
this.position.y += y;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
41
screens/Tetris/components/Cell.js
Normal file
41
screens/Tetris/components/Cell.js
Normal file
|
|
@ -0,0 +1,41 @@
|
||||||
|
// @flow
|
||||||
|
|
||||||
|
import * as React from 'react';
|
||||||
|
import {View} from 'react-native';
|
||||||
|
import {withTheme} from 'react-native-paper';
|
||||||
|
|
||||||
|
type Props = {
|
||||||
|
color: string,
|
||||||
|
isEmpty: boolean,
|
||||||
|
id: string,
|
||||||
|
}
|
||||||
|
|
||||||
|
class Cell extends React.PureComponent<Props> {
|
||||||
|
|
||||||
|
colors: Object;
|
||||||
|
|
||||||
|
constructor(props) {
|
||||||
|
super(props);
|
||||||
|
this.colors = props.theme.colors;
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
return (
|
||||||
|
<View
|
||||||
|
style={{
|
||||||
|
flex: 1,
|
||||||
|
backgroundColor: this.props.isEmpty ? 'transparent' : this.props.color,
|
||||||
|
borderColor: this.props.isEmpty ? 'transparent' : this.colors.tetrisBorder,
|
||||||
|
borderStyle: 'solid',
|
||||||
|
borderRadius: 2,
|
||||||
|
borderWidth: 1,
|
||||||
|
aspectRatio: 1,
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
export default withTheme(Cell);
|
||||||
68
screens/Tetris/components/Grid.js
Normal file
68
screens/Tetris/components/Grid.js
Normal file
|
|
@ -0,0 +1,68 @@
|
||||||
|
// @flow
|
||||||
|
|
||||||
|
import * as React from 'react';
|
||||||
|
import {View} from 'react-native';
|
||||||
|
import {withTheme} from 'react-native-paper';
|
||||||
|
import Cell from "./Cell";
|
||||||
|
|
||||||
|
type Props = {
|
||||||
|
navigation: Object,
|
||||||
|
grid: Array<Array<Object>>,
|
||||||
|
backgroundColor: string,
|
||||||
|
height: number,
|
||||||
|
width: number,
|
||||||
|
containerMaxHeight: number|string,
|
||||||
|
containerMaxWidth: number|string,
|
||||||
|
}
|
||||||
|
|
||||||
|
class Grid extends React.Component<Props>{
|
||||||
|
|
||||||
|
colors: Object;
|
||||||
|
|
||||||
|
constructor(props) {
|
||||||
|
super(props);
|
||||||
|
this.colors = props.theme.colors;
|
||||||
|
}
|
||||||
|
|
||||||
|
getRow(rowNumber: number) {
|
||||||
|
let cells = [];
|
||||||
|
for (let i = 0; i < this.props.width; i++) {
|
||||||
|
let cell = this.props.grid[rowNumber][i];
|
||||||
|
let key = rowNumber + ':' + i;
|
||||||
|
cells.push(<Cell color={cell.color} isEmpty={cell.isEmpty} id={key}/>);
|
||||||
|
}
|
||||||
|
return(
|
||||||
|
<View style={{
|
||||||
|
flexDirection: 'row',
|
||||||
|
backgroundColor: this.props.backgroundColor,
|
||||||
|
}}>
|
||||||
|
{cells}
|
||||||
|
</View>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
getGrid() {
|
||||||
|
let rows = [];
|
||||||
|
for (let i = 0; i < this.props.height; i++) {
|
||||||
|
rows.push(this.getRow(i));
|
||||||
|
}
|
||||||
|
return rows;
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
return (
|
||||||
|
<View style={{
|
||||||
|
flexDirection: 'column',
|
||||||
|
maxWidth: this.props.containerMaxWidth,
|
||||||
|
maxHeight: this.props.containerMaxHeight,
|
||||||
|
aspectRatio: this.props.width/this.props.height,
|
||||||
|
marginLeft: 'auto',
|
||||||
|
marginRight: 'auto',
|
||||||
|
}}>
|
||||||
|
{this.getGrid()}
|
||||||
|
</View>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default withTheme(Grid);
|
||||||
52
screens/Tetris/components/Preview.js
Normal file
52
screens/Tetris/components/Preview.js
Normal file
|
|
@ -0,0 +1,52 @@
|
||||||
|
// @flow
|
||||||
|
|
||||||
|
import * as React from 'react';
|
||||||
|
import {View} from 'react-native';
|
||||||
|
import {withTheme} from 'react-native-paper';
|
||||||
|
import Grid from "./Grid";
|
||||||
|
|
||||||
|
type Props = {
|
||||||
|
next: Object,
|
||||||
|
}
|
||||||
|
|
||||||
|
class Preview extends React.PureComponent<Props> {
|
||||||
|
|
||||||
|
colors: Object;
|
||||||
|
|
||||||
|
constructor(props) {
|
||||||
|
super(props);
|
||||||
|
this.colors = props.theme.colors;
|
||||||
|
}
|
||||||
|
|
||||||
|
getGrids() {
|
||||||
|
let grids = [];
|
||||||
|
for (let i = 0; i < this.props.next.length; i++) {
|
||||||
|
grids.push(
|
||||||
|
<Grid
|
||||||
|
width={this.props.next[i][0].length}
|
||||||
|
height={this.props.next[i].length}
|
||||||
|
grid={this.props.next[i]}
|
||||||
|
containerMaxHeight={50}
|
||||||
|
containerMaxWidth={50}
|
||||||
|
backgroundColor={'transparent'}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return grids;
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
if (this.props.next.length > 0) {
|
||||||
|
return (
|
||||||
|
<View>
|
||||||
|
{this.getGrids()}
|
||||||
|
</View>
|
||||||
|
);
|
||||||
|
} else
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
export default withTheme(Preview);
|
||||||
|
|
@ -54,6 +54,18 @@ export default class ThemeManager {
|
||||||
proxiwashColor: '#1fa5ee',
|
proxiwashColor: '#1fa5ee',
|
||||||
menuColor: '#e91314',
|
menuColor: '#e91314',
|
||||||
tutorinsaColor: '#f93943',
|
tutorinsaColor: '#f93943',
|
||||||
|
|
||||||
|
// Tetris
|
||||||
|
tetrisBackground:'#e6e6e6',
|
||||||
|
tetrisBorder:'#2f2f2f',
|
||||||
|
tetrisScore:'#e2bd33',
|
||||||
|
tetrisI : '#3cd9e6',
|
||||||
|
tetrisO : '#ffdd00',
|
||||||
|
tetrisT : '#a716e5',
|
||||||
|
tetrisS : '#09c528',
|
||||||
|
tetrisZ : '#ff0009',
|
||||||
|
tetrisJ : '#2a67e3',
|
||||||
|
tetrisL : '#da742d',
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
@ -94,6 +106,18 @@ export default class ThemeManager {
|
||||||
proxiwashColor: '#1fa5ee',
|
proxiwashColor: '#1fa5ee',
|
||||||
menuColor: '#b81213',
|
menuColor: '#b81213',
|
||||||
tutorinsaColor: '#f93943',
|
tutorinsaColor: '#f93943',
|
||||||
|
|
||||||
|
// Tetris
|
||||||
|
tetrisBackground:'#2c2c2c',
|
||||||
|
tetrisBorder:'#1b1b1b',
|
||||||
|
tetrisScore:'#e2d707',
|
||||||
|
tetrisI : '#30b3be',
|
||||||
|
tetrisO : '#c1a700',
|
||||||
|
tetrisT : '#9114c7',
|
||||||
|
tetrisS : '#08a121',
|
||||||
|
tetrisZ : '#b50008',
|
||||||
|
tetrisJ : '#0f37b9',
|
||||||
|
tetrisL : '#b96226',
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue