Implemented snake scoreboard and working towards a dedicated snake app
This commit is contained in:
@@ -33,6 +33,7 @@
|
|||||||
"react-redux": "^7.1.0",
|
"react-redux": "^7.1.0",
|
||||||
"react-router": "^5.0.1",
|
"react-router": "^5.0.1",
|
||||||
"react-router-dom": "^5.0.1",
|
"react-router-dom": "^5.0.1",
|
||||||
|
"react-transition-group": "^4.2.2",
|
||||||
"redux": "^4.0.4",
|
"redux": "^4.0.4",
|
||||||
"styled-components": "^4.3.2"
|
"styled-components": "^4.3.2"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
<head>
|
<head>
|
||||||
<meta charset="UTF-8" />
|
<meta charset="UTF-8" />
|
||||||
<title>Redux Demo</title>
|
<title>Redux Demo</title>
|
||||||
|
<link href="https://fonts.googleapis.com/css?family=Lato:100,400|Raleway:100,400,700|Rubik:500" rel="stylesheet" />
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<div id="root"></div>
|
<div id="root"></div>
|
||||||
|
|||||||
@@ -39,7 +39,7 @@ const StyledNavLink = styled(NavLink)`
|
|||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
const Button = (props, refs) => {
|
export const Button = (props, refs) => {
|
||||||
const updatedProps = { ...props };
|
const updatedProps = { ...props };
|
||||||
|
|
||||||
if (props.onClick) {
|
if (props.onClick) {
|
||||||
@@ -57,4 +57,8 @@ const Button = (props, refs) => {
|
|||||||
return StyledButton.render(updatedProps);
|
return StyledButton.render(updatedProps);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const ToggleButton = styled(Button)`
|
||||||
|
background-color: ${props => (props.toggle ? "silver" : null)};
|
||||||
|
`;
|
||||||
|
|
||||||
export default Button;
|
export default Button;
|
||||||
|
|||||||
@@ -12,7 +12,8 @@ const LogoPanel = styled.div`
|
|||||||
}
|
}
|
||||||
|
|
||||||
h1 {
|
h1 {
|
||||||
line-height: 2rem;
|
line-height: 2.5rem;
|
||||||
|
font-size: 2.3rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
h2 {
|
h2 {
|
||||||
@@ -22,8 +23,8 @@ const LogoPanel = styled.div`
|
|||||||
|
|
||||||
const Logo = () => (
|
const Logo = () => (
|
||||||
<LogoPanel>
|
<LogoPanel>
|
||||||
<h1>Hello Redux</h1>
|
<h1>Crafity Snake</h1>
|
||||||
<h2>Redux demo application</h2>
|
<h2>React Redux Demo Application</h2>
|
||||||
</LogoPanel>
|
</LogoPanel>
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,158 @@
|
|||||||
|
import React from "react";
|
||||||
|
import styled from "styled-components";
|
||||||
|
import { CSSTransition, TransitionGroup } from "react-transition-group";
|
||||||
|
|
||||||
|
const DEFAULT_WIDTH = 1;
|
||||||
|
const DEFAULT_HEIGHT = 1.5;
|
||||||
|
|
||||||
|
const Card = styled.div`
|
||||||
|
display: inline-block;
|
||||||
|
position: relative;
|
||||||
|
margin-right: 0.2em;
|
||||||
|
width: ${props => (props.zoom || 1) * DEFAULT_WIDTH}rem;
|
||||||
|
height: ${props => (props.zoom || 1) * DEFAULT_HEIGHT}rem;
|
||||||
|
content: "${props => props.value}";
|
||||||
|
border: 1px solid gray;
|
||||||
|
border-radius: 1px;
|
||||||
|
text-align: center;
|
||||||
|
line-height: ${props => (props.zoom || 1) * (DEFAULT_HEIGHT + 0)}rem;
|
||||||
|
vertical-align: middle;
|
||||||
|
background-color: ${props => props.theme.body.color};
|
||||||
|
color: ${props => props.theme.body.background};
|
||||||
|
font-size: ${props => (props.zoom || 1) * 1.5}rem;
|
||||||
|
font-family: Rubik,monospace;
|
||||||
|
font-weight: 500;
|
||||||
|
box-shadow: 1px 1px 3px #d0bfa3;
|
||||||
|
text-shadow: 0 0 1px black;
|
||||||
|
overflow: hidden;
|
||||||
|
|
||||||
|
&::before {
|
||||||
|
content: "";
|
||||||
|
display: block;
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
height: 50%;
|
||||||
|
width: 100%;
|
||||||
|
left: 0;
|
||||||
|
border-bottom: solid 2px #bdb19a;
|
||||||
|
}
|
||||||
|
|
||||||
|
&::after {
|
||||||
|
content: "";
|
||||||
|
display: block;
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
height: 50%;
|
||||||
|
width: 100%;
|
||||||
|
border-bottom: dotted 2px #ad5a75;
|
||||||
|
z-index:1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// &::after {
|
||||||
|
// content: "${props => props.children}";
|
||||||
|
// display: block;
|
||||||
|
// position: absolute;
|
||||||
|
// font-size: 3em;
|
||||||
|
// }
|
||||||
|
`;
|
||||||
|
|
||||||
|
const StyledScoreboard = styled.div`
|
||||||
|
height: ${props => (props.zoom || 1) * DEFAULT_HEIGHT}rem;
|
||||||
|
margin-bottom: 1rem;
|
||||||
|
|
||||||
|
& > div {
|
||||||
|
position: relative;
|
||||||
|
display: inline-block;
|
||||||
|
width: ${props => (props.zoom || 1) * DEFAULT_WIDTH}rem;
|
||||||
|
height: ${props => (props.zoom || 1) * DEFAULT_HEIGHT}rem;
|
||||||
|
margin-right: ${props => (props.zoom || 1) * 0.3}rem;
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
||||||
|
const CardCSSTransition = styled(CSSTransition)`
|
||||||
|
position: absolute;
|
||||||
|
|
||||||
|
&.card-enter,
|
||||||
|
&.card-appear {
|
||||||
|
${Card} {
|
||||||
|
transform: rotateX(90deg);
|
||||||
|
z-index: 1;
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.card-appear-active {
|
||||||
|
${Card} {
|
||||||
|
transition: transform ease-out 250ms, opacity ease-out 100ms;
|
||||||
|
transform: rotateX(0deg);
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&.card-enter-active {
|
||||||
|
${Card} {
|
||||||
|
transition: transform ease-out 250ms 250ms, opacity ease-out 100ms;
|
||||||
|
transform: rotateX(0deg);
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&.card-exit {
|
||||||
|
${Card} {
|
||||||
|
transform: rotateX(0deg);
|
||||||
|
transition: transform ease-out 250ms, opacity ease-out 100ms 150ms;
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.card-exit-active {
|
||||||
|
${Card} {
|
||||||
|
transition: transform ease-out 250ms, opacity ease-out 100ms 150ms;
|
||||||
|
transform: rotateX(90deg);
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
&.card-exit-done {
|
||||||
|
${Card} {
|
||||||
|
transform: rotateX(90deg);
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
||||||
|
export const Scoreboard = ({ score, zoom = 1 } = {}) => {
|
||||||
|
const scoreCards = Array.from(`${score}`.padStart(3, "0"));
|
||||||
|
return (
|
||||||
|
<StyledScoreboard zoom={zoom}>
|
||||||
|
<TransitionGroup>
|
||||||
|
<CardCSSTransition key={`card0-${scoreCards[0] || "x"}`} timeout={1000} classNames="card">
|
||||||
|
<div>
|
||||||
|
<Card value={scoreCards[0]} zoom={zoom}>
|
||||||
|
{scoreCards[0] || "0"}
|
||||||
|
</Card>
|
||||||
|
</div>
|
||||||
|
</CardCSSTransition>
|
||||||
|
</TransitionGroup>
|
||||||
|
<TransitionGroup>
|
||||||
|
<CardCSSTransition key={`card1-${scoreCards[1] || "x"}`} timeout={1000} classNames="card">
|
||||||
|
<div>
|
||||||
|
<Card value={scoreCards[1]} zoom={zoom}>
|
||||||
|
{scoreCards[1] || "0"}
|
||||||
|
</Card>
|
||||||
|
</div>
|
||||||
|
</CardCSSTransition>
|
||||||
|
</TransitionGroup>
|
||||||
|
<TransitionGroup>
|
||||||
|
<CardCSSTransition key={`card2-${scoreCards[2] || "x"}`} timeout={1000} classNames="card">
|
||||||
|
<div>
|
||||||
|
<Card value={scoreCards[2]} zoom={zoom}>
|
||||||
|
{scoreCards[2]}
|
||||||
|
</Card>
|
||||||
|
</div>
|
||||||
|
</CardCSSTransition>
|
||||||
|
</TransitionGroup>
|
||||||
|
</StyledScoreboard>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default Scoreboard;
|
||||||
+9
-186
@@ -1,6 +1,8 @@
|
|||||||
import React from "react";
|
import React from "react";
|
||||||
import { connect } from "react-redux";
|
import { connect } from "react-redux";
|
||||||
import styled, { keyframes, css } from "styled-components";
|
import styled from "styled-components";
|
||||||
|
|
||||||
|
/* Redux Modules */
|
||||||
import { module as gameModule, keyPress } from "../redux/game.js";
|
import { module as gameModule, keyPress } from "../redux/game.js";
|
||||||
import {
|
import {
|
||||||
module as snakeModule,
|
module as snakeModule,
|
||||||
@@ -11,12 +13,11 @@ import {
|
|||||||
keyPressedSnake,
|
keyPressedSnake,
|
||||||
keys
|
keys
|
||||||
} from "../redux/snake.js";
|
} from "../redux/snake.js";
|
||||||
import Title from "../components/Title.js";
|
|
||||||
import Button from "../components/Button.js";
|
|
||||||
|
|
||||||
const ToggleButton = styled(Button)`
|
/* Components */
|
||||||
background-color: ${props => (props.toggle ? "silver" : null)};
|
import Title from "../components/Title.js";
|
||||||
`;
|
import Button, { ToggleButton } from "../components/Button.js";
|
||||||
|
import Scoreboard from "../components/Scoreboard.js";
|
||||||
|
|
||||||
const Row = styled.div``;
|
const Row = styled.div``;
|
||||||
|
|
||||||
@@ -68,82 +69,6 @@ const Skull = styled.div.attrs({ role: "img", "aria-label": "skull" })`
|
|||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
const flipIn = keyframes`
|
|
||||||
50% {
|
|
||||||
transform: rotateX(90deg);
|
|
||||||
}
|
|
||||||
100% {
|
|
||||||
transform: rotateX(0deg);
|
|
||||||
}
|
|
||||||
`;
|
|
||||||
|
|
||||||
const flipOut = keyframes`
|
|
||||||
0 {
|
|
||||||
transform: rotateX(0deg);
|
|
||||||
}
|
|
||||||
50% {
|
|
||||||
transform: rotateX(90deg);
|
|
||||||
}
|
|
||||||
`;
|
|
||||||
|
|
||||||
const Card = styled.div`
|
|
||||||
display: inline-block;
|
|
||||||
position: relative;
|
|
||||||
margin-right: 0.2em;
|
|
||||||
width: 1rem;
|
|
||||||
height: 2rem;
|
|
||||||
// perspective: -1rem;
|
|
||||||
|
|
||||||
&:before {
|
|
||||||
content: "${props => props.oldValue}";
|
|
||||||
position: absolute;
|
|
||||||
display: inline-block;
|
|
||||||
// display: none;
|
|
||||||
border: 1px solid gray;
|
|
||||||
width: 1rem;
|
|
||||||
height: 2rem;
|
|
||||||
left: 0;
|
|
||||||
top: 0;
|
|
||||||
text-align: center;
|
|
||||||
line-height: 2rem;
|
|
||||||
vertical-align: middle;
|
|
||||||
background-color: brown;
|
|
||||||
color: white;
|
|
||||||
transition: transform ease-out 100ms;
|
|
||||||
// animation: ${flipIn} 1s infinite;
|
|
||||||
${props =>
|
|
||||||
props.value !== props.oldValue &&
|
|
||||||
css`
|
|
||||||
animation: ${flipIn} 1s forward;
|
|
||||||
`};
|
|
||||||
}
|
|
||||||
|
|
||||||
&:after {
|
|
||||||
content: "${props => props.value}";
|
|
||||||
position: absolute;
|
|
||||||
display: inline-block;
|
|
||||||
border: 1px solid gray;
|
|
||||||
width: 1rem;
|
|
||||||
height: 2rem;
|
|
||||||
left: 0;
|
|
||||||
top: 0;
|
|
||||||
text-align: center;
|
|
||||||
line-height: 2rem;
|
|
||||||
vertical-align: middle;
|
|
||||||
background-color: brown;
|
|
||||||
color: white;
|
|
||||||
transition: transform ease-out 100ms;
|
|
||||||
// animation: ${flipOut} 1s infinite;
|
|
||||||
${props =>
|
|
||||||
props.value !== props.oldValue &&
|
|
||||||
css`
|
|
||||||
animation: ${flipOut} 1s forward;
|
|
||||||
`};
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
`;
|
|
||||||
|
|
||||||
const Grid = ({ data, died }) =>
|
const Grid = ({ data, died }) =>
|
||||||
data.map((r, y) => (
|
data.map((r, y) => (
|
||||||
<Row key={`y${y}`}>
|
<Row key={`y${y}`}>
|
||||||
@@ -157,79 +82,6 @@ const Grid = ({ data, died }) =>
|
|||||||
</Row>
|
</Row>
|
||||||
));
|
));
|
||||||
|
|
||||||
const Score = ({ score, previousScore }) => {
|
|
||||||
const now = Date.now();
|
|
||||||
const [lastChange, changeLastChange] = React.useState({ timestamp: Date.now(), score, previousScore });
|
|
||||||
|
|
||||||
if (score === lastChange.score) {
|
|
||||||
const scoreCards = Array.from(`${score}`.padStart(3, " "));
|
|
||||||
return (
|
|
||||||
<div className="scoreboard">
|
|
||||||
{scoreCards.map((score, index) => (
|
|
||||||
<Card key={`${index}-${score}`} value={score} oldValue={score} />
|
|
||||||
))}
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (score !== lastChange.score && now - lastChange.timestamp > 1200) {
|
|
||||||
const scoreCards = Array.from(`${score}`.padStart(3, " "));
|
|
||||||
const previousScoreCards = Array.from(`${lastChange.score}`.padStart(3, " "));
|
|
||||||
console.log("scoreCards, previousScoreCards", scoreCards, previousScoreCards);
|
|
||||||
return (
|
|
||||||
<div className="scoreboard">
|
|
||||||
{scoreCards.map((score, index) => (
|
|
||||||
<Card key={`${index}-${score}`} value={score} oldValue={previousScoreCards[index]} />
|
|
||||||
))}
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (score !== lastChange.score && now - lastChange.timestamp > 1200) {
|
|
||||||
changeLastChange({ timestamp: now, score, previousScore: lastChange.score });
|
|
||||||
}
|
|
||||||
|
|
||||||
const scoreCards = Array.from(`${lastChange.previousScore}`.padStart(3, " "));
|
|
||||||
|
|
||||||
// console.log("now - lastChange.timestamp", now - lastChange.timestamp);
|
|
||||||
if (score !== lastChange.previousScore) {
|
|
||||||
const newScoreCards = Array.from(`${score}`.padStart(3, " "));
|
|
||||||
console.log("updating");
|
|
||||||
return (
|
|
||||||
<div className="scoreboard">
|
|
||||||
{newScoreCards.map(
|
|
||||||
(score, index) =>
|
|
||||||
console.log(score, scoreCards[index]) || (
|
|
||||||
<Card key={`${index}-${score}`} value={score} oldValue={scoreCards[index]} />
|
|
||||||
)
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
return (
|
|
||||||
<div className="scoreboard">
|
|
||||||
{scoreCards.map((score, index) => (
|
|
||||||
<Card key={`${index}-${score}`} value={score} oldValue={score} />
|
|
||||||
))}
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
|
|
||||||
// const scoreCards = Array.from(`${score}`.padStart(3, " "));
|
|
||||||
// const previousScoreCards = Array.from(`${lastScore}`.padStart(3, " "));
|
|
||||||
|
|
||||||
// if (lastScore < score - 1) {
|
|
||||||
// updateScore(score);
|
|
||||||
// }
|
|
||||||
// console.log("score, lastScore", score, lastScore);
|
|
||||||
// return (
|
|
||||||
// <div className="scoreboard">
|
|
||||||
// {scoreCards.map((score, index) => (
|
|
||||||
// <Card key={`${index}-${score}`} value={score} oldValue={previousScoreCards[index]} />
|
|
||||||
// ))}
|
|
||||||
// </div>
|
|
||||||
// );
|
|
||||||
};
|
|
||||||
|
|
||||||
// const ArrowButton = styled(Button)`
|
// const ArrowButton = styled(Button)`
|
||||||
// min-width: 5rem;
|
// min-width: 5rem;
|
||||||
// `;
|
// `;
|
||||||
@@ -253,7 +105,6 @@ class Snake extends React.Component {
|
|||||||
this.handleKeyDown = this.handleKeyDown.bind(this);
|
this.handleKeyDown = this.handleKeyDown.bind(this);
|
||||||
this.supportedKeys = Object.values(keys);
|
this.supportedKeys = Object.values(keys);
|
||||||
window.me = this;
|
window.me = this;
|
||||||
this.state = { previousPoints: 0 };
|
|
||||||
}
|
}
|
||||||
|
|
||||||
handleKeyDown(e) {
|
handleKeyDown(e) {
|
||||||
@@ -277,40 +128,12 @@ class Snake extends React.Component {
|
|||||||
snake,
|
snake,
|
||||||
died,
|
died,
|
||||||
fps,
|
fps,
|
||||||
score,
|
score
|
||||||
previousScore
|
|
||||||
} = this.props;
|
} = this.props;
|
||||||
|
|
||||||
if (false && died) {
|
|
||||||
return (
|
|
||||||
<React.Fragment>
|
|
||||||
<Title large>Snake</Title>
|
|
||||||
<Title>
|
|
||||||
You died{" "}
|
|
||||||
<span role="img" aria-label="skull">
|
|
||||||
☠️
|
|
||||||
</span>{" "}
|
|
||||||
with {snake.length} points.
|
|
||||||
</Title>
|
|
||||||
<Button onClick={startSnake}>Restart</Button>
|
|
||||||
</React.Fragment>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!started && !died) {
|
|
||||||
return (
|
|
||||||
<React.Fragment>
|
|
||||||
<Title large>Snake</Title>
|
|
||||||
<Grid data={grid} />
|
|
||||||
<Button onClick={startSnake}>Start</Button>
|
|
||||||
</React.Fragment>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<React.Fragment>
|
<React.Fragment>
|
||||||
<Title large>Snake</Title>
|
<Scoreboard score={score} zoom={2} />
|
||||||
<Score score={score} previousScore={previousScore} />
|
|
||||||
<Grid data={grid} died={died} />
|
<Grid data={grid} died={died} />
|
||||||
<Button onClick={updateFrameSnake}>Next</Button>
|
<Button onClick={updateFrameSnake}>Next</Button>
|
||||||
<ToggleButton toggle={paused} onClick={pauseSnake}>
|
<ToggleButton toggle={paused} onClick={pauseSnake}>
|
||||||
|
|||||||
@@ -1,54 +0,0 @@
|
|||||||
import React from "react";
|
|
||||||
import { connect } from "react-redux";
|
|
||||||
import Title from "../components/Title.js";
|
|
||||||
import List from "../components/List.js";
|
|
||||||
import Button from "../components/Button.js";
|
|
||||||
import Link from "../components/Link.js";
|
|
||||||
import Spinner from "../components/Spinner.js";
|
|
||||||
import { getKeyboards, showKeyboard } from "../redux/keyboards.js";
|
|
||||||
|
|
||||||
const KeyboardListItem = ({ item, showKeyboard }) => (
|
|
||||||
<List.Item key={item.id}>
|
|
||||||
<Link to={`/keyboards/${item.id}`}>
|
|
||||||
{item.maker} - {item.model}
|
|
||||||
</Link>
|
|
||||||
</List.Item>
|
|
||||||
);
|
|
||||||
|
|
||||||
const NoKeyboardsFound = ({ spinner }) => {
|
|
||||||
if (spinner) {
|
|
||||||
return <p>Loading...</p>;
|
|
||||||
}
|
|
||||||
return <p>There are no keyboards</p>;
|
|
||||||
};
|
|
||||||
|
|
||||||
class Keyboards extends React.Component {
|
|
||||||
componentDidMount() {
|
|
||||||
this.props.getKeyboards();
|
|
||||||
}
|
|
||||||
render() {
|
|
||||||
const { keyboards, spinner, getKeyboards } = this.props;
|
|
||||||
return (
|
|
||||||
<React.Fragment>
|
|
||||||
<Title large>Keyboard List</Title>
|
|
||||||
<List items={keyboards} Item={KeyboardListItem} Empty={NoKeyboardsFound} itemProps={this.props} />
|
|
||||||
<Button onClick={() => getKeyboards({ force: true })}>Refresh</Button>
|
|
||||||
{spinner && <Spinner />}
|
|
||||||
</React.Fragment>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
const mapState = ({ keyboards, ui }) => ({
|
|
||||||
keyboards: keyboards.list,
|
|
||||||
spinner: ui.spinner
|
|
||||||
});
|
|
||||||
|
|
||||||
const mapActions = {
|
|
||||||
getKeyboards,
|
|
||||||
showKeyboard
|
|
||||||
};
|
|
||||||
|
|
||||||
export default connect(
|
|
||||||
mapState,
|
|
||||||
mapActions
|
|
||||||
)(Keyboards);
|
|
||||||
+2
-1
@@ -14,6 +14,7 @@ export const keys = {
|
|||||||
RIGHT: "ArrowRight",
|
RIGHT: "ArrowRight",
|
||||||
DOWN: "ArrowDown",
|
DOWN: "ArrowDown",
|
||||||
LEFT: "ArrowLeft",
|
LEFT: "ArrowLeft",
|
||||||
|
EQUAL: "=",
|
||||||
PLUS: "+",
|
PLUS: "+",
|
||||||
MINUS: "-"
|
MINUS: "-"
|
||||||
};
|
};
|
||||||
@@ -94,7 +95,7 @@ module.reducer(UNSUBSCRIBE_KEY_PRESSED, (state, { name }) => {
|
|||||||
|
|
||||||
module.middleware(KEY_PRESS, (dispatch, { keyPressSubscribers = [], fps }, { key }) => {
|
module.middleware(KEY_PRESS, (dispatch, { keyPressSubscribers = [], fps }, { key }) => {
|
||||||
keyPressSubscribers.forEach(subscriber => dispatch({ type: subscriber, key }));
|
keyPressSubscribers.forEach(subscriber => dispatch({ type: subscriber, key }));
|
||||||
if (key === keys.PLUS) {
|
if (key === keys.PLUS || key === keys.EQUAL) {
|
||||||
dispatch(setFps(fps + 1));
|
dispatch(setFps(fps + 1));
|
||||||
}
|
}
|
||||||
if (key === keys.MINUS) {
|
if (key === keys.MINUS) {
|
||||||
|
|||||||
+10
-9
@@ -19,8 +19,7 @@ const initialState = {
|
|||||||
vY: 0,
|
vY: 0,
|
||||||
snake: [],
|
snake: [],
|
||||||
score: 0,
|
score: 0,
|
||||||
previousScore: 0,
|
apple: []
|
||||||
apple: randomPosition(DEFAULT_GRID_SIZE)
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/* === Snake Helper Functions ================================================================== */
|
/* === Snake Helper Functions ================================================================== */
|
||||||
@@ -69,7 +68,10 @@ function createGrid(size) {
|
|||||||
return rows;
|
return rows;
|
||||||
}
|
}
|
||||||
|
|
||||||
const markCell = (grid, [x, y], mark) => {
|
const markCell = (grid, [x, y] = [], mark) => {
|
||||||
|
if (x === undefined || y === undefined) {
|
||||||
|
return grid;
|
||||||
|
}
|
||||||
grid[y][x] = mark;
|
grid[y][x] = mark;
|
||||||
return grid;
|
return grid;
|
||||||
};
|
};
|
||||||
@@ -113,12 +115,12 @@ export const [UPDATE_STATE, updateState] = module.action("UPDATE_STATE", (newSta
|
|||||||
module.reducer(UPDATE_STATE, (state, { newState, fullUpdate }) => (fullUpdate ? newState : { ...state, ...newState }));
|
module.reducer(UPDATE_STATE, (state, { newState, fullUpdate }) => (fullUpdate ? newState : { ...state, ...newState }));
|
||||||
module.reducer(RESET_SNAKE, (state, options) => {
|
module.reducer(RESET_SNAKE, (state, options) => {
|
||||||
const grid = createGrid(state.size);
|
const grid = createGrid(state.size);
|
||||||
const { apple } = initialState;
|
const apple = options.started ? randomPosition(state.size) : initialState.apple;
|
||||||
const snake = options.started ? [[0, 0]] : [];
|
const snake = options.started ? [[0, 0]] : initialState.snake;
|
||||||
|
|
||||||
markCell(grid, apple, "a");
|
markCell(grid, apple, "a");
|
||||||
snake.forEach(p => markCell(grid, p, "s"));
|
snake.forEach(p => markCell(grid, p, "s"));
|
||||||
return { ...state, ...initialState, grid, snake, ...options };
|
return { ...state, ...initialState, grid, snake, apple, ...options };
|
||||||
});
|
});
|
||||||
|
|
||||||
module.reducer(CHANGE_DIRECTION, (state, { direction }) => {
|
module.reducer(CHANGE_DIRECTION, (state, { direction }) => {
|
||||||
@@ -142,11 +144,10 @@ module.reducer(CHANGE_DIRECTION, (state, { direction }) => {
|
|||||||
|
|
||||||
module.reducer(UPDATE_FRAME_SNAKE, state => {
|
module.reducer(UPDATE_FRAME_SNAKE, state => {
|
||||||
const { snake, vX, vY, size } = state;
|
const { snake, vX, vY, size } = state;
|
||||||
let { apple, started, died, previousScore, score } = state;
|
let { apple, started, died, score } = state;
|
||||||
const grid = createGrid(size);
|
const grid = createGrid(size);
|
||||||
const newSnake = [...snake];
|
const newSnake = [...snake];
|
||||||
const nextPosition = moveSnakePart(newSnake[newSnake.length - 1], vX, vY, size);
|
const nextPosition = moveSnakePart(newSnake[newSnake.length - 1], vX, vY, size);
|
||||||
previousScore = score;
|
|
||||||
if (comparePositions(nextPosition, apple)) {
|
if (comparePositions(nextPosition, apple)) {
|
||||||
apple = randomPosition(size);
|
apple = randomPosition(size);
|
||||||
// eslint-disable-next-line no-loop-func
|
// eslint-disable-next-line no-loop-func
|
||||||
@@ -165,7 +166,7 @@ module.reducer(UPDATE_FRAME_SNAKE, state => {
|
|||||||
const brightness = (l, i) => 20 + Math.round(0.8 * ((i + 1) / l) * 100);
|
const brightness = (l, i) => 20 + Math.round(0.8 * ((i + 1) / l) * 100);
|
||||||
newSnake.forEach((p, i) => markCell(grid, p, "s" + brightness(newSnake.length, i)));
|
newSnake.forEach((p, i) => markCell(grid, p, "s" + brightness(newSnake.length, i)));
|
||||||
score = newSnake.length;
|
score = newSnake.length;
|
||||||
return { ...state, grid, vX, vY, snake: newSnake, apple, started, died, previousScore, score };
|
return { ...state, grid, vX, vY, snake: newSnake, apple, started, died, score };
|
||||||
});
|
});
|
||||||
|
|
||||||
/* === Middleware =============================================================================== */
|
/* === Middleware =============================================================================== */
|
||||||
|
|||||||
@@ -2,16 +2,20 @@ import { createGlobalStyle } from "styled-components";
|
|||||||
|
|
||||||
const GlobalStyle = createGlobalStyle`
|
const GlobalStyle = createGlobalStyle`
|
||||||
body {
|
body {
|
||||||
position: relative;
|
position: relative;
|
||||||
padding: 0 0 4.25rem;
|
padding: 0 0 4.25rem;
|
||||||
box-sizing:border-box;
|
box-sizing:border-box;
|
||||||
margin: 0;
|
margin: 0;
|
||||||
background: ${props => props.theme.body.background};
|
background: ${props => props.theme.body.background};
|
||||||
color: ${props => props.theme.body.color};
|
color: ${props => props.theme.body.color};
|
||||||
font-family: sans-serif;
|
font-family: Raleway;
|
||||||
font-size: 1rem;
|
font-size: 1rem;
|
||||||
min-height: 100vh;
|
min-height: 100vh;
|
||||||
}
|
}
|
||||||
|
h1, h2 {
|
||||||
|
font-family: Lato;
|
||||||
|
}
|
||||||
|
|
||||||
`;
|
`;
|
||||||
|
|
||||||
export default GlobalStyle;
|
export default GlobalStyle;
|
||||||
|
|||||||
Reference in New Issue
Block a user