Improve control panel, add zoom and fps controls
This commit is contained in:
@@ -4,6 +4,18 @@
|
|||||||
<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" />
|
<link href="https://fonts.googleapis.com/css?family=Lato:100,400|Raleway:100,400,700|Rubik:500" rel="stylesheet" />
|
||||||
|
<link
|
||||||
|
rel="stylesheet"
|
||||||
|
href="https://use.fontawesome.com/releases/v5.9.0/css/solid.css"
|
||||||
|
integrity="sha384-ypqxM+6jj5ropInEPawU1UEhbuOuBkkz59KyIbbsTu4Sw62PfV3KUnQadMbIoAzq"
|
||||||
|
crossorigin="anonymous"
|
||||||
|
/>
|
||||||
|
<link
|
||||||
|
rel="stylesheet"
|
||||||
|
href="https://use.fontawesome.com/releases/v5.9.0/css/fontawesome.css"
|
||||||
|
integrity="sha384-NnhYAEceBbm5rQuNvCv6o4iIoPZlkaWfvuXVh4XkRNvHWKgu/Mk2nEjFZpPQdwiz"
|
||||||
|
crossorigin="anonymous"
|
||||||
|
/>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<div id="root"></div>
|
<div id="root"></div>
|
||||||
|
|||||||
@@ -1,15 +1,21 @@
|
|||||||
import styled from "styled-components";
|
import styled from "styled-components";
|
||||||
|
|
||||||
export const Apple = styled.div.attrs({ role: "img", "aria-label": "apple" })`
|
const Apple = styled.div.attrs(({ theme, zoom }) => ({
|
||||||
width: ${({ theme }) => theme.snake.cell.size};
|
style: {
|
||||||
height: ${({ theme }) => theme.snake.cell.size};
|
height: theme.snake.cell.size * (zoom || 1) + "rem",
|
||||||
|
width: theme.snake.cell.size * (zoom || 1) + "rem",
|
||||||
|
border: theme.snake.cell.border,
|
||||||
|
fontSize: (zoom || 1) * 1.3 + "rem",
|
||||||
|
lineHeight: (zoom || 1) * 1.7 + "rem",
|
||||||
|
paddingLeft: (zoom || 1) * 0.0625 + "rem"
|
||||||
|
}
|
||||||
|
}))`
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
font-size: 1.3rem;
|
|
||||||
vertical-align: top;
|
vertical-align: top;
|
||||||
line-height: 1.8rem;
|
|
||||||
padding-left: 0.0625rem;
|
|
||||||
&:after {
|
&:after {
|
||||||
content: "${props => (!props.died ? "🍎" : "🐛")}";
|
// content: "${props => (!props.died ? "🍎" : "🐛")}";
|
||||||
|
content: "🍎";
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
|||||||
@@ -54,6 +54,16 @@ export const Button = (props, refs) => {
|
|||||||
return StyledNavLink.render(updatedProps);
|
return StyledNavLink.render(updatedProps);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (props.icon) {
|
||||||
|
return (
|
||||||
|
<i
|
||||||
|
onClick={updatedProps.onClick}
|
||||||
|
className={`fas fa-${props.icon} ${props.className}`}
|
||||||
|
style={{ display: "inline-block", fontSize: `${props.size || 1}rem` }}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
return StyledButton.render(updatedProps);
|
return StyledButton.render(updatedProps);
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -61,4 +71,21 @@ export const ToggleButton = styled(Button)`
|
|||||||
background-color: ${props => (props.toggle ? "silver" : null)};
|
background-color: ${props => (props.toggle ? "silver" : null)};
|
||||||
`;
|
`;
|
||||||
|
|
||||||
|
export const IconButton = styled(Button)`
|
||||||
|
margin: 0 0.2rem;
|
||||||
|
display: inline-block;
|
||||||
|
cursor: pointer;
|
||||||
|
|
||||||
|
&:before {
|
||||||
|
text-shadow: 0 0 1px black, 1px 1px 3px #d0bfa3;
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
||||||
|
export const ToggleIconButton = styled(IconButton)`
|
||||||
|
color: ${props => (props.toggle ? "#e6b4c4" : null)};
|
||||||
|
&:before {
|
||||||
|
text-shadow: 0 0 1px gray, 0 0 1px #d0bfa3;
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
||||||
export default Button;
|
export default Button;
|
||||||
|
|||||||
@@ -1,21 +1,76 @@
|
|||||||
import React from "react";
|
import React from "react";
|
||||||
import styled from "styled-components";
|
import styled from "styled-components";
|
||||||
import Button, { ToggleButton } from "../components/Button.js";
|
import Button, { IconButton, ToggleIconButton } from "../components/Button.js";
|
||||||
|
|
||||||
|
const buttonSize = 2.5;
|
||||||
|
|
||||||
const Layout = styled.div`
|
const Layout = styled.div`
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
`;
|
`;
|
||||||
|
|
||||||
export const ControlPanel = ({ updateFrameSnake, paused, pauseSnake, stopSnake, startSnake, fps }) => (
|
const ButtonRow = styled.div`
|
||||||
|
display: flex;
|
||||||
|
place-content: center;
|
||||||
|
align-content: space-around;
|
||||||
|
`;
|
||||||
|
|
||||||
|
const HorizontalStack = styled.div`
|
||||||
|
display: flex;
|
||||||
|
width: 100%;
|
||||||
|
// place-content: center;
|
||||||
|
align-content: center;
|
||||||
|
place-content: space-between;
|
||||||
|
`;
|
||||||
|
|
||||||
|
const VerticalStack = styled.div`
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
place-content: center;
|
||||||
|
align-content: space-around;
|
||||||
|
`;
|
||||||
|
|
||||||
|
export const ControlPanel = ({
|
||||||
|
updateFrameSnake,
|
||||||
|
paused,
|
||||||
|
started,
|
||||||
|
pauseSnake,
|
||||||
|
stopSnake,
|
||||||
|
startSnake,
|
||||||
|
fps,
|
||||||
|
zoom,
|
||||||
|
setFps,
|
||||||
|
zoomIn,
|
||||||
|
zoomOut
|
||||||
|
}) => (
|
||||||
<Layout>
|
<Layout>
|
||||||
<h1>Control Panel</h1>
|
{
|
||||||
<ToggleButton toggle={paused} onClick={pauseSnake}>
|
// <h1>Control Panel</h1>
|
||||||
{paused ? "Resume" : "Pause"}
|
// <ToggleButton toggle={paused} onClick={pauseSnake}>
|
||||||
</ToggleButton>
|
// {paused ? "Resume" : "Pause"}
|
||||||
<Button onClick={stopSnake}>Stop</Button>
|
// </ToggleButton>
|
||||||
<Button onClick={startSnake}>Reset</Button>
|
}
|
||||||
<span>FPS: {fps}</span>
|
|
||||||
|
<HorizontalStack style={{ minHeight: "2rem" }}>
|
||||||
|
<span>Zoom: {zoom}</span>
|
||||||
|
<div style={{ display: "inline-block" }}>
|
||||||
|
<IconButton icon="minus-circle" size={1} onClick={zoomOut} />
|
||||||
|
<IconButton icon="plus-circle" size={1} onClick={zoomIn} />
|
||||||
|
</div>
|
||||||
|
</HorizontalStack>
|
||||||
|
<HorizontalStack style={{ minHeight: "2rem" }}>
|
||||||
|
<span>FPS: {fps}</span>
|
||||||
|
<div style={{ display: "inline-block" }}>
|
||||||
|
<IconButton icon="minus-circle" size={1} onClick={() => setFps(fps - 1)} />
|
||||||
|
<IconButton icon="plus-circle" size={1} onClick={() => setFps(fps + 1)} />
|
||||||
|
</div>
|
||||||
|
</HorizontalStack>
|
||||||
|
<ButtonRow>
|
||||||
|
<ToggleIconButton toggle={!started} icon="stop-circle" size={buttonSize} onClick={stopSnake} />
|
||||||
|
<ToggleIconButton toggle={started && !paused} icon="play-circle" size={buttonSize} onClick={startSnake} />
|
||||||
|
<ToggleIconButton toggle={paused || !started} icon="pause-circle" size={buttonSize} onClick={pauseSnake} />
|
||||||
|
<ToggleIconButton toggle={!started} icon="dot-circle" size={buttonSize} onClick={startSnake} />
|
||||||
|
</ButtonRow>
|
||||||
</Layout>
|
</Layout>
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|||||||
@@ -76,7 +76,7 @@ const CardCSSTransition = styled(CSSTransition)`
|
|||||||
|
|
||||||
&.card-appear-active {
|
&.card-appear-active {
|
||||||
${Card} {
|
${Card} {
|
||||||
transition: transform ease-out 250ms, opacity ease-out 100ms;
|
transition: transform ease-in 250ms, opacity ease-in 100ms;
|
||||||
transform: rotateX(0deg);
|
transform: rotateX(0deg);
|
||||||
opacity: 1;
|
opacity: 1;
|
||||||
}
|
}
|
||||||
@@ -84,7 +84,7 @@ const CardCSSTransition = styled(CSSTransition)`
|
|||||||
|
|
||||||
&.card-enter-active {
|
&.card-enter-active {
|
||||||
${Card} {
|
${Card} {
|
||||||
transition: transform ease-out 250ms 250ms, opacity ease-out 100ms;
|
transition: transform ease-in 250ms 250ms, opacity ease-in 100ms;
|
||||||
transform: rotateX(0deg);
|
transform: rotateX(0deg);
|
||||||
opacity: 1;
|
opacity: 1;
|
||||||
}
|
}
|
||||||
@@ -94,13 +94,13 @@ const CardCSSTransition = styled(CSSTransition)`
|
|||||||
&.card-exit {
|
&.card-exit {
|
||||||
${Card} {
|
${Card} {
|
||||||
transform: rotateX(0deg);
|
transform: rotateX(0deg);
|
||||||
transition: transform ease-out 250ms, opacity ease-out 100ms 150ms;
|
transition: transform ease-in 250ms, opacity ease-in 100ms 150ms;
|
||||||
opacity: 1;
|
opacity: 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
&.card-exit-active {
|
&.card-exit-active {
|
||||||
${Card} {
|
${Card} {
|
||||||
transition: transform ease-out 250ms, opacity ease-out 100ms 150ms;
|
transition: transform ease-in 250ms, opacity ease-in 100ms 150ms;
|
||||||
transform: rotateX(90deg);
|
transform: rotateX(90deg);
|
||||||
opacity: 0;
|
opacity: 0;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,13 +1,13 @@
|
|||||||
import styled, { css } from "styled-components";
|
import styled, { css } from "styled-components";
|
||||||
|
|
||||||
export const SnakePart = styled.div`
|
export const SnakePart = styled.div`
|
||||||
width: ${({ theme }) => theme.snake.cell.size};
|
width: ${({ theme, zoom }) => theme.snake.cell.size * (zoom || 1)}rem;
|
||||||
height: ${({ theme }) => theme.snake.cell.size};
|
height: ${({ theme, zoom }) => theme.snake.cell.size * (zoom || 1)}rem;
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
font-size: 1.3rem;
|
font-size: ${props => (props.zoom || 1) * 1.3}rem;
|
||||||
vertical-align: top;
|
vertical-align: top;
|
||||||
line-height: 1.8rem;
|
line-height: ${props => (props.zoom || 1) * 1.7}rem;
|
||||||
padding-left: 0.0625rem;
|
padding-left: ${props => (props.zoom || 1) * 0.0625}rem;
|
||||||
|
|
||||||
${props =>
|
${props =>
|
||||||
!props.died
|
!props.died
|
||||||
|
|||||||
@@ -1,26 +1,35 @@
|
|||||||
import React from "react";
|
import React from "react";
|
||||||
import styled from "styled-components";
|
import styled from "styled-components";
|
||||||
|
|
||||||
const Row = styled.div`
|
const Row = styled.div.attrs(({ theme, zoom }) => ({
|
||||||
|
style: {
|
||||||
|
height: theme.snake.cell.size * (zoom || 1) + "rem"
|
||||||
|
}
|
||||||
|
}))`
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
`;
|
`;
|
||||||
|
|
||||||
const Cell = styled.div`
|
const Cell = styled.div.attrs(({ theme, zoom }) => ({
|
||||||
width: ${({ theme }) => theme.snake.cell.size};
|
style: {
|
||||||
height: ${({ theme }) => theme.snake.cell.size};
|
height: theme.snake.cell.size * (zoom || 1) + "rem",
|
||||||
border: ${({ theme }) => theme.snake.cell.border};
|
width: theme.snake.cell.size * (zoom || 1) + "rem",
|
||||||
|
border: theme.snake.cell.border
|
||||||
|
}
|
||||||
|
}))`
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
vertical-align: top;
|
vertical-align: top;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
box-shadow: 1px 1px 4px gray inset, -1px -1px 4px #fff inset;
|
box-shadow: 1px 1px 4px gray inset, -1px -1px 4px #fff inset;
|
||||||
`;
|
`;
|
||||||
|
|
||||||
export const Stage = ({ data, children }) => (
|
export const Stage = ({ data, children, zoom = 1 }) => (
|
||||||
<div>
|
<div>
|
||||||
{data.map((r, y) => (
|
{data.map((r, y) => (
|
||||||
<Row key={`y${y}`}>
|
<Row key={`y${y}`} zoom={zoom}>
|
||||||
{r.map((c, x) => (
|
{r.map((c, x) => (
|
||||||
<Cell key={`x${x}y${y}`}>{children(c)}</Cell>
|
<Cell key={`x${x}y${y}`} zoom={zoom}>
|
||||||
|
{children(c, zoom)}
|
||||||
|
</Cell>
|
||||||
))}
|
))}
|
||||||
</Row>
|
</Row>
|
||||||
))}
|
))}
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ import { connect } from "react-redux";
|
|||||||
import styled from "styled-components";
|
import styled from "styled-components";
|
||||||
|
|
||||||
/* Redux Modules */
|
/* Redux Modules */
|
||||||
import { module as gameModule, keyPress } from "../redux/game.js";
|
import { module as gameModule, keyPress, setFps } from "../redux/game.js";
|
||||||
import {
|
import {
|
||||||
module as snakeModule,
|
module as snakeModule,
|
||||||
startSnake,
|
startSnake,
|
||||||
@@ -11,7 +11,9 @@ import {
|
|||||||
pauseSnake,
|
pauseSnake,
|
||||||
updateFrameSnake,
|
updateFrameSnake,
|
||||||
keyPressedSnake,
|
keyPressedSnake,
|
||||||
keys
|
keys,
|
||||||
|
zoomIn,
|
||||||
|
zoomOut
|
||||||
} from "../redux/snake.js";
|
} from "../redux/snake.js";
|
||||||
|
|
||||||
/* Components */
|
/* Components */
|
||||||
@@ -24,12 +26,15 @@ import Apple from "../components/Apple.js";
|
|||||||
const Layout = styled.div`
|
const Layout = styled.div`
|
||||||
display: flex;
|
display: flex;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
place-content: space-between;
|
place-content: center;
|
||||||
|
margin-top: 2rem;
|
||||||
`;
|
`;
|
||||||
|
|
||||||
const SidePanel = styled.div`
|
const SidePanel = styled.div`
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
|
margin-left: 2rem;
|
||||||
|
place-content: space-between;
|
||||||
`;
|
`;
|
||||||
|
|
||||||
class Snake extends React.Component {
|
class Snake extends React.Component {
|
||||||
@@ -61,27 +66,36 @@ class Snake extends React.Component {
|
|||||||
snake,
|
snake,
|
||||||
died,
|
died,
|
||||||
fps,
|
fps,
|
||||||
score
|
setFps,
|
||||||
|
score,
|
||||||
|
zoom,
|
||||||
|
zoomIn,
|
||||||
|
zoomOut
|
||||||
} = this.props;
|
} = this.props;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<React.Fragment>
|
<React.Fragment>
|
||||||
<Layout>
|
<Layout>
|
||||||
<Stage data={grid}>
|
<Stage data={grid} zoom={zoom}>
|
||||||
{cell =>
|
{cell =>
|
||||||
(cell.type === "apple" && <Apple died={died} />) ||
|
(cell.type === "apple" && <Apple zoom={zoom} died={died} />) ||
|
||||||
(cell.type === "snake" && <SnakePart value={cell} died={died} />)
|
(cell.type === "snake" && <SnakePart zoom={zoom} value={cell} died={died} />)
|
||||||
}
|
}
|
||||||
</Stage>
|
</Stage>
|
||||||
<SidePanel>
|
<SidePanel>
|
||||||
<Scoreboard score={score} zoom={2} />
|
<Scoreboard score={score} zoom={2} />
|
||||||
<ControlPanel
|
<ControlPanel
|
||||||
updateFrameSnake={updateFrameSnake}
|
updateFrameSnake={updateFrameSnake}
|
||||||
|
started={started}
|
||||||
paused={paused}
|
paused={paused}
|
||||||
pauseSnake={pauseSnake}
|
pauseSnake={pauseSnake}
|
||||||
stopSnake={stopSnake}
|
stopSnake={stopSnake}
|
||||||
startSnake={startSnake}
|
startSnake={startSnake}
|
||||||
fps={fps}
|
fps={fps}
|
||||||
|
setFps={setFps}
|
||||||
|
zoom={zoom}
|
||||||
|
zoomIn={zoomIn}
|
||||||
|
zoomOut={zoomOut}
|
||||||
/>
|
/>
|
||||||
</SidePanel>
|
</SidePanel>
|
||||||
</Layout>
|
</Layout>
|
||||||
@@ -105,7 +119,10 @@ const mapActionsToProps = {
|
|||||||
pauseSnake,
|
pauseSnake,
|
||||||
updateFrameSnake,
|
updateFrameSnake,
|
||||||
keyPressedSnake,
|
keyPressedSnake,
|
||||||
keyPress
|
keyPress,
|
||||||
|
setFps,
|
||||||
|
zoomIn,
|
||||||
|
zoomOut
|
||||||
};
|
};
|
||||||
|
|
||||||
export default connect(
|
export default connect(
|
||||||
|
|||||||
@@ -10,9 +10,11 @@ import {
|
|||||||
|
|
||||||
const MODULE_NAME = "SNAKE";
|
const MODULE_NAME = "SNAKE";
|
||||||
const DEFAULT_GRID_SIZE = 16;
|
const DEFAULT_GRID_SIZE = 16;
|
||||||
|
const DEFAUL_ZOOM_STEP = 0.1;
|
||||||
|
|
||||||
const initialState = {
|
const initialState = {
|
||||||
grid: createGrid(DEFAULT_GRID_SIZE),
|
grid: createGrid(DEFAULT_GRID_SIZE),
|
||||||
|
zoom: 1.5,
|
||||||
size: DEFAULT_GRID_SIZE,
|
size: DEFAULT_GRID_SIZE,
|
||||||
paused: false,
|
paused: false,
|
||||||
vX: 1,
|
vX: 1,
|
||||||
@@ -46,7 +48,18 @@ export const keys = {
|
|||||||
|
|
||||||
snakePart: "snakePart",
|
snakePart: "snakePart",
|
||||||
s: "s",
|
s: "s",
|
||||||
r: "r"
|
r: "r",
|
||||||
|
|
||||||
|
1: "1",
|
||||||
|
2: "2",
|
||||||
|
3: "3",
|
||||||
|
4: "4",
|
||||||
|
5: "5",
|
||||||
|
6: "6",
|
||||||
|
7: "7",
|
||||||
|
8: "8",
|
||||||
|
9: "9",
|
||||||
|
0: "0"
|
||||||
};
|
};
|
||||||
|
|
||||||
function randomPosition(size) {
|
function randomPosition(size) {
|
||||||
@@ -106,6 +119,9 @@ export const [START_SNAKE, startSnake] = module.action("START_SNAKE");
|
|||||||
export const [RESET_SNAKE, resetSnake] = module.action("RESET_SNAKE", options => ({ ...options }));
|
export const [RESET_SNAKE, resetSnake] = module.action("RESET_SNAKE", options => ({ ...options }));
|
||||||
export const [STOP_SNAKE, stopSnake] = module.action("STOP_SNAKE");
|
export const [STOP_SNAKE, stopSnake] = module.action("STOP_SNAKE");
|
||||||
export const [PAUSE_SNAKE, pauseSnake] = module.action("PAUSE_SNAKE");
|
export const [PAUSE_SNAKE, pauseSnake] = module.action("PAUSE_SNAKE");
|
||||||
|
export const [ZOOM_IN, zoomIn] = module.action("ZOOM_IN", step => ({ step }));
|
||||||
|
export const [SET_ZOOM_LEVEL, setZoomLevel] = module.action("SET_ZOOM_LEVEL", level => ({ level }));
|
||||||
|
export const [ZOOM_OUT, zoomOut] = module.action("ZOOM_OUT", step => ({ step }));
|
||||||
export const [UPDATE_FRAME_SNAKE, updateFrameSnake] = module.action("UPDATE_FRAME_SNAKE");
|
export const [UPDATE_FRAME_SNAKE, updateFrameSnake] = module.action("UPDATE_FRAME_SNAKE");
|
||||||
export const [CHANGE_DIRECTION, changeDirection] = module.action("CHANGE_DIRECTION", direction => ({ direction }));
|
export const [CHANGE_DIRECTION, changeDirection] = module.action("CHANGE_DIRECTION", direction => ({ direction }));
|
||||||
export const [KEY_PRESSED_SNAKE, keyPressedSnake] = module.action("KEY_PRESSED_SNAKE", key => ({ key }));
|
export const [KEY_PRESSED_SNAKE, keyPressedSnake] = module.action("KEY_PRESSED_SNAKE", key => ({ key }));
|
||||||
@@ -117,8 +133,18 @@ export const [UPDATE_STATE, updateState] = module.action("UPDATE_STATE", (newSta
|
|||||||
/* === Reducers ================================================================================= */
|
/* === Reducers ================================================================================= */
|
||||||
|
|
||||||
module.reducer(UPDATE_STATE, (state, { newState, fullUpdate }) => (fullUpdate ? newState : { ...state, ...newState }));
|
module.reducer(UPDATE_STATE, (state, { newState, fullUpdate }) => (fullUpdate ? newState : { ...state, ...newState }));
|
||||||
|
|
||||||
|
module.reducer(ZOOM_IN, (state, { step = DEFAUL_ZOOM_STEP }) => ({
|
||||||
|
...state,
|
||||||
|
zoom: Math.round((state.zoom + step) * 10) / 10
|
||||||
|
}));
|
||||||
|
module.reducer(SET_ZOOM_LEVEL, (state, { level }) => ({ ...state, zoom: level }));
|
||||||
|
module.reducer(ZOOM_OUT, (state, { step = DEFAUL_ZOOM_STEP }) =>
|
||||||
|
state.zoom - step >= 0.5 ? { ...state, zoom: Math.round((state.zoom - step) * 10) / 10 } : { ...state, zoom: 1 }
|
||||||
|
);
|
||||||
module.reducer(RESET_SNAKE, (state, options) => {
|
module.reducer(RESET_SNAKE, (state, options) => {
|
||||||
const grid = createGrid(state.size);
|
const grid = createGrid(state.size);
|
||||||
|
const zoom = state.zoom;
|
||||||
const apple = options.started ? randomPosition(state.size) : initialState.apple;
|
const apple = options.started ? randomPosition(state.size) : initialState.apple;
|
||||||
const snake = options.started ? [[0, 0]] : initialState.snake;
|
const snake = options.started ? [[0, 0]] : initialState.snake;
|
||||||
|
|
||||||
@@ -126,7 +152,7 @@ module.reducer(RESET_SNAKE, (state, options) => {
|
|||||||
snake.forEach((snakePart, i) =>
|
snake.forEach((snakePart, i) =>
|
||||||
markCell(grid, snakePart, { type: "snake", index: snake.length - 1 - i, brightness: brightness(snake.length, i) })
|
markCell(grid, snakePart, { type: "snake", index: snake.length - 1 - i, brightness: brightness(snake.length, i) })
|
||||||
);
|
);
|
||||||
return { ...state, ...initialState, grid, snake, apple, ...options };
|
return { ...state, ...initialState, grid, zoom, snake, apple, ...options };
|
||||||
});
|
});
|
||||||
|
|
||||||
module.reducer(CHANGE_DIRECTION, (state, { direction }) => {
|
module.reducer(CHANGE_DIRECTION, (state, { direction }) => {
|
||||||
@@ -223,7 +249,7 @@ module.middleware(START_SNAKE, (dispatch, { started }) => {
|
|||||||
|
|
||||||
module.middleware(STOP_SNAKE, (dispatch, { started }) => {
|
module.middleware(STOP_SNAKE, (dispatch, { started }) => {
|
||||||
dispatch(unregisterCaller(UPDATE_FRAME_SNAKE));
|
dispatch(unregisterCaller(UPDATE_FRAME_SNAKE));
|
||||||
dispatch(unsubscribeKeyPressed(KEY_PRESSED_SNAKE));
|
// dispatch(unsubscribeKeyPressed(KEY_PRESSED_SNAKE));
|
||||||
dispatch(stopLoop());
|
dispatch(stopLoop());
|
||||||
dispatch(resetSnake({ started: false }));
|
dispatch(resetSnake({ started: false }));
|
||||||
});
|
});
|
||||||
@@ -237,6 +263,7 @@ module.middleware(PAUSE_SNAKE, (dispatch, { paused }) => {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// eslint-disable-next-line complexity
|
||||||
module.middleware(KEY_PRESSED_SNAKE, (dispatch, _, { key }) => {
|
module.middleware(KEY_PRESSED_SNAKE, (dispatch, _, { key }) => {
|
||||||
if (key === keys.UP || key === keys.k) {
|
if (key === keys.UP || key === keys.k) {
|
||||||
dispatch(changeDirection(directions.UP));
|
dispatch(changeDirection(directions.UP));
|
||||||
@@ -259,4 +286,31 @@ module.middleware(KEY_PRESSED_SNAKE, (dispatch, _, { key }) => {
|
|||||||
if (key === keys.r) {
|
if (key === keys.r) {
|
||||||
dispatch(startSnake());
|
dispatch(startSnake());
|
||||||
}
|
}
|
||||||
|
if (key === keys[1]) {
|
||||||
|
dispatch(setZoomLevel(0.6));
|
||||||
|
}
|
||||||
|
if (key === keys[2]) {
|
||||||
|
dispatch(setZoomLevel(0.8));
|
||||||
|
}
|
||||||
|
if (key === keys[3]) {
|
||||||
|
dispatch(setZoomLevel(1));
|
||||||
|
}
|
||||||
|
if (key === keys[4]) {
|
||||||
|
dispatch(setZoomLevel(1.2));
|
||||||
|
}
|
||||||
|
if (key === keys[5]) {
|
||||||
|
dispatch(setZoomLevel(1.4));
|
||||||
|
}
|
||||||
|
if (key === keys[6]) {
|
||||||
|
dispatch(setZoomLevel(1.6));
|
||||||
|
}
|
||||||
|
if (key === keys[7]) {
|
||||||
|
dispatch(setZoomLevel(1.8));
|
||||||
|
}
|
||||||
|
if (key === keys[8]) {
|
||||||
|
dispatch(setZoomLevel(2));
|
||||||
|
}
|
||||||
|
if (key === keys[9]) {
|
||||||
|
dispatch(setZoomLevel(2.2));
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ const themes = {
|
|||||||
snake: {
|
snake: {
|
||||||
cell: {
|
cell: {
|
||||||
border: "0.0625rem solid papayawhip",
|
border: "0.0625rem solid papayawhip",
|
||||||
size: "1.5rem"
|
size: 1.5
|
||||||
},
|
},
|
||||||
cellColors: {
|
cellColors: {
|
||||||
" ": "",
|
" ": "",
|
||||||
|
|||||||
Reference in New Issue
Block a user