Skip to content

Commit

Permalink
Tetris data and block model setting
Browse files Browse the repository at this point in the history
  • Loading branch information
dbstpwlsWork32 committed May 25, 2020
1 parent 3131c35 commit 1754f99
Show file tree
Hide file tree
Showing 6 changed files with 384 additions and 3 deletions.
124 changes: 124 additions & 0 deletions src/components/tetris/Stage.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
import React from 'react'
import { ModelStage, ModelBlock, ModelUserBlock } from './typeModels'
import { Cell as StyledCell, Stage as StyledStage, Row as StyledRow } from './styles/stage'

interface StageState {
stage: ModelStage;
userBlock: ModelUserBlock;
predictionBlocks: ModelBlock[];
}
interface StageProps {
level: number;
gameStatus: 'beforePlay' | 'play' | 'pause' | 'gameOver';
// save data
dataPredictionBlocks: ModelBlock[];
dataStage: ModelStage;
dataUserBlock: ModelUserBlock;
keyCode: {
left: number;
right: number;
down: number;
rotate: number;
pastDown: number;
}
}

export default class Stage extends React.Component<StageProps, StageState> {
private get timerSpeed () {
// millisecond at one y line block drop
// 20 level === 200, 1 level === 4000
return 4000 - 200 * (this.props.level - 1)
}
event: { timerId: number | boolean, key: boolean } = {
key: false,
timerId: false
}

shapeBlockPosPareser(block: ModelUserBlock): [number, number][] {
const pos: [number, number][] = []
block.shape.forEach((row, rowIndex) => {
row.forEach((ySettle, yIndex) => {
if (ySettle) {
pos.push([
block.standardPos[0] + rowIndex,
block.standardPos[1] + yIndex
])
}
})
})

return pos
}
getConcatStageByBlock({ pos, background }: { pos: [number, number][]; background: string }, isSettle: boolean, stage?: ModelStage): ModelStage {
const copyStage = stage ? [...stage] : [...this.state.stage]

pos.forEach(posItem => {
copyStage[posItem[0]][posItem[1]] = {
background,
settle: isSettle
}
})

return copyStage
}

eventHandler (key: 'addKey' | 'removeKey' | 'addTimer' | 'removeTimer') {
switch (key) {
case 'addKey':
if (!this.event.key) {
this.event.key = true
}
break;
default:
break;
}
}

keyboardEvent (e: KeyboardEvent) {
switch (e.keyCode) {
case this.props.keyCode.left:
break;
case this.props.keyCode.right:
break;
case this.props.keyCode.down:
break;
case this.props.keyCode.rotate:
break;
case this.props.keyCode.pastDown:
break;
}
}

constructor (props: StageProps) {
super(props)

this.state = {
stage: props.dataStage,
userBlock: props.dataUserBlock,
predictionBlocks: props.dataPredictionBlocks
}
}

shouldComponentUpdate (nextProps: StageProps) {
if (this.props.gameStatus !== nextProps.gameStatus) return true
else return false
}

render () {
return (
<StyledStage cellCount={this.state.stage.length}>
{
this.state.stage.map((rows, xIndex) => (
<StyledRow key={`tetris__x-${xIndex}`}>
{
rows.map((cell, yIndex) => (
<StyledCell {...cell} key={`tetris__x-${xIndex}-${yIndex}`} />
))
}
</StyledRow>
))
}
</StyledStage>
)
}
}
119 changes: 116 additions & 3 deletions src/components/tetris/index.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,124 @@
import React from 'react'
import { ModelScoreBoard, ModelStage, ModelBlock, ModelUserBlock } from './typeModels'
import ScoreBoard from './scoreBoard'
import Stage from './Stage'
import getBlock from './logic/block'

interface TetrisState {
gameStatus: 'beforePlay' | 'play' | 'pause' | 'gameOver';
scoreBoard: ModelScoreBoard;
sendToStage: {
stage: ModelStage;
predictionBlocks: ModelBlock[];
userBlock: ModelUserBlock;
keyCode: {
left: number,
right: number,
down: number,
rotate: number,
pastDown: number
}
}
}
interface TetrisData {
stage?: ModelStage;
scoreBoard?: ModelScoreBoard;
predictionBlocks?: ModelBlock[];
userBlock?: ModelUserBlock;
keyCode?: {
left: number,
right: number,
down: number,
rotate: number,
pastDown: number
}
}
export default class Tetris extends React.PureComponent<TetrisData, TetrisState> {

gameBtHandler () {
switch (this.state.gameStatus) {
case 'play':
this.setState({
gameStatus: 'pause'
})
break;
default:
this.setState({
gameStatus: 'play'
})
break;
}
}

constructor (props: TetrisData) {
super(props)

const stageX = 10
const stageY = 20

const newUserBlock = getBlock()
this.state = {
sendToStage: {
stage:
props.stage ||
Array.from(new Array(stageX), () => new Array(stageY).fill({ backgrond: '', settle: false })),
predictionBlocks:
props.predictionBlocks ||
[getBlock(), getBlock(), getBlock()],
userBlock:
props.userBlock ||
{
...newUserBlock,
standardPos: [Math.floor((stageX - newUserBlock.shape.length) / 2), 0]
},
keyCode:
props.keyCode ||
{
// left arrow
left: 37,
// right arrow
right: 39,
// down arrow
down: 40,
// s
rotate: 89,
// d
pastDown: 68
}
},
scoreBoard:
props.scoreBoard ||
{
level: 1,
score: 0,
rows: 0
},
gameStatus: 'beforePlay',
}

this.gameBtHandler = this.gameBtHandler.bind(this)
}

export default class Tetris extends React.Component {
render () {
return (
<div>
Tetris play!
<Stage
dataStage={this.state.sendToStage.stage}
dataPredictionBlocks={this.state.sendToStage.predictionBlocks}
dataUserBlock={this.state.sendToStage.userBlock}
level={this.state.scoreBoard.level}
gameStatus={this.state.gameStatus}
keyCode={this.state.sendToStage.keyCode}
/>
<aside>
<ScoreBoard {...this.state.scoreBoard} />
<button onClick={this.gameBtHandler}>{
this.state.gameStatus === 'play' ?
'Pause' :
'Play'
}</button>
</aside>
</div>
)
}
}
}
71 changes: 71 additions & 0 deletions src/components/tetris/logic/block.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
import { ModelBlock } from '../typeModels'

const blocks: ModelBlock[] = [
// ㄱ
{
shape: [
[true, true, true],
[true, false, false],
[false, false, false]
],
background: '#186BD6'
},
{
shape: [
[true, false, false],
[true, true, true],
[false, false, false]
],
background: '#DE651B'
},
// ㄱ + ㄴ
{
shape: [
[false, true, false],
[true, true, false],
[true, false, false]
],
background: '#ED5056'
},
{
shape: [
[true, false, false],
[true, true, false],
[false, true, false]
],
background: '#4ABA54'
},
// ㅡ
{
shape: [
[true, true, true, true],
[false, false, false, false],
[false, false, false, false],
[false, false, false, false]
],
background: '#68C5DB'
},
// ㅗ
{
shape: [
[true, false, false],
[true, true, false],
[true, false, false]
],
background: '#C57CEA'
},
// ㅁ
{
shape: [
[true, true],
[true, true]
],
background: '#F6C643'
}
]

const getBlock = (): ModelBlock => {
return blocks[Math.floor(Math.random() * blocks.length)]
}

export default getBlock
14 changes: 14 additions & 0 deletions src/components/tetris/scoreBoard.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import React from 'react'
import { ModelScoreBoard } from './typeModels'

const ScoreBoard: React.SFC<ModelScoreBoard> = (props: ModelScoreBoard) => {
return (
<div>
<h3>score: {props.score}</h3>
<h3>level: {props.level}</h3>
<h3>rows: {props.rows}</h3>
</div>
)
}

export default React.memo(ScoreBoard)
39 changes: 39 additions & 0 deletions src/components/tetris/styles/stage.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import styled from 'styled-components'
import { Cell as CellProps } from '../typeModels'

const cellSize = {
width: 30,
height: 30
}

export const Cell = styled.div<CellProps>`
height: ${cellSize.height}px;
box-sizing: border-box;
border-bottom: 1px solid #000;
background: ${props =>
props.background === '' ?
'none' : props.background
};
&:last-child {
border-bottom: none
};
`

export const Row = styled.div`
width: ${cellSize.width}px;
border-right: 1px solid #000;
box-sizing: border-box;
float: left;
&:last-child {
border-right: none
};
`
export const Stage = styled.div<{ cellCount: number }>`
width: ${props => props.cellCount * cellSize.width}px;
border: 1px solid #000;
&:after {
content: '';
display: block;
clear: both;
};
`

0 comments on commit 1754f99

Please sign in to comment.