diff --git a/public/index.html b/public/index.html
index 85ddfc3..9776439 100644
--- a/public/index.html
+++ b/public/index.html
@@ -4,6 +4,18 @@
Redux Demo
+
+
diff --git a/src/components/Apple.js b/src/components/Apple.js
index 104b15a..049b331 100644
--- a/src/components/Apple.js
+++ b/src/components/Apple.js
@@ -1,15 +1,21 @@
import styled from "styled-components";
-export const Apple = styled.div.attrs({ role: "img", "aria-label": "apple" })`
- width: ${({ theme }) => theme.snake.cell.size};
- height: ${({ theme }) => theme.snake.cell.size};
+const Apple = styled.div.attrs(({ theme, zoom }) => ({
+ style: {
+ 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;
- font-size: 1.3rem;
vertical-align: top;
- line-height: 1.8rem;
- padding-left: 0.0625rem;
+
&:after {
- content: "${props => (!props.died ? "🍎" : "🐛")}";
+ // content: "${props => (!props.died ? "🍎" : "🐛")}";
+ content: "🍎";
display: inline-block;
}
`;
diff --git a/src/components/Button.js b/src/components/Button.js
index d6a98ea..9fc2c46 100644
--- a/src/components/Button.js
+++ b/src/components/Button.js
@@ -54,6 +54,16 @@ export const Button = (props, refs) => {
return StyledNavLink.render(updatedProps);
}
+ if (props.icon) {
+ return (
+
+ );
+ }
+
return StyledButton.render(updatedProps);
};
@@ -61,4 +71,21 @@ export const ToggleButton = styled(Button)`
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;
diff --git a/src/components/ControlPanel.js b/src/components/ControlPanel.js
index 180201f..2ee6a39 100644
--- a/src/components/ControlPanel.js
+++ b/src/components/ControlPanel.js
@@ -1,21 +1,76 @@
import React from "react";
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`
display: flex;
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
+}) => (
- Control Panel
-
- {paused ? "Resume" : "Pause"}
-
-
-
- FPS: {fps}
+ {
+ // Control Panel
+ //
+ // {paused ? "Resume" : "Pause"}
+ //
+ }
+
+
+ Zoom: {zoom}
+
+
+
+
+
+
+ FPS: {fps}
+
+ setFps(fps - 1)} />
+ setFps(fps + 1)} />
+
+
+
+
+
+
+
+
);
diff --git a/src/components/Scoreboard.js b/src/components/Scoreboard.js
index 96bcf0c..7487561 100644
--- a/src/components/Scoreboard.js
+++ b/src/components/Scoreboard.js
@@ -76,7 +76,7 @@ const CardCSSTransition = styled(CSSTransition)`
&.card-appear-active {
${Card} {
- transition: transform ease-out 250ms, opacity ease-out 100ms;
+ transition: transform ease-in 250ms, opacity ease-in 100ms;
transform: rotateX(0deg);
opacity: 1;
}
@@ -84,7 +84,7 @@ const CardCSSTransition = styled(CSSTransition)`
&.card-enter-active {
${Card} {
- transition: transform ease-out 250ms 250ms, opacity ease-out 100ms;
+ transition: transform ease-in 250ms 250ms, opacity ease-in 100ms;
transform: rotateX(0deg);
opacity: 1;
}
@@ -94,13 +94,13 @@ const CardCSSTransition = styled(CSSTransition)`
&.card-exit {
${Card} {
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;
}
&.card-exit-active {
${Card} {
- transition: transform ease-out 250ms, opacity ease-out 100ms 150ms;
+ transition: transform ease-in 250ms, opacity ease-in 100ms 150ms;
transform: rotateX(90deg);
opacity: 0;
}
diff --git a/src/components/SnakePart.js b/src/components/SnakePart.js
index a8763db..17d7154 100644
--- a/src/components/SnakePart.js
+++ b/src/components/SnakePart.js
@@ -1,13 +1,13 @@
import styled, { css } from "styled-components";
export const SnakePart = styled.div`
- width: ${({ theme }) => theme.snake.cell.size};
- height: ${({ theme }) => theme.snake.cell.size};
+ width: ${({ theme, zoom }) => theme.snake.cell.size * (zoom || 1)}rem;
+ height: ${({ theme, zoom }) => theme.snake.cell.size * (zoom || 1)}rem;
display: inline-block;
- font-size: 1.3rem;
+ font-size: ${props => (props.zoom || 1) * 1.3}rem;
vertical-align: top;
- line-height: 1.8rem;
- padding-left: 0.0625rem;
+ line-height: ${props => (props.zoom || 1) * 1.7}rem;
+ padding-left: ${props => (props.zoom || 1) * 0.0625}rem;
${props =>
!props.died
diff --git a/src/components/Stage.js b/src/components/Stage.js
index 4330ab9..85b80c0 100644
--- a/src/components/Stage.js
+++ b/src/components/Stage.js
@@ -1,26 +1,35 @@
import React from "react";
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;
`;
-const Cell = styled.div`
- width: ${({ theme }) => theme.snake.cell.size};
- height: ${({ theme }) => theme.snake.cell.size};
- border: ${({ theme }) => theme.snake.cell.border};
+const Cell = styled.div.attrs(({ theme, zoom }) => ({
+ style: {
+ height: theme.snake.cell.size * (zoom || 1) + "rem",
+ width: theme.snake.cell.size * (zoom || 1) + "rem",
+ border: theme.snake.cell.border
+ }
+}))`
display: inline-block;
vertical-align: top;
text-align: center;
box-shadow: 1px 1px 4px gray inset, -1px -1px 4px #fff inset;
`;
-export const Stage = ({ data, children }) => (
+export const Stage = ({ data, children, zoom = 1 }) => (
{data.map((r, y) => (
-
+
{r.map((c, x) => (
- | {children(c)} |
+
+ {children(c, zoom)}
+ |
))}
))}
diff --git a/src/containers/Snake.js b/src/containers/Snake.js
index 3c3c1f6..0df77a1 100644
--- a/src/containers/Snake.js
+++ b/src/containers/Snake.js
@@ -3,7 +3,7 @@ import { connect } from "react-redux";
import styled from "styled-components";
/* Redux Modules */
-import { module as gameModule, keyPress } from "../redux/game.js";
+import { module as gameModule, keyPress, setFps } from "../redux/game.js";
import {
module as snakeModule,
startSnake,
@@ -11,7 +11,9 @@ import {
pauseSnake,
updateFrameSnake,
keyPressedSnake,
- keys
+ keys,
+ zoomIn,
+ zoomOut
} from "../redux/snake.js";
/* Components */
@@ -24,12 +26,15 @@ import Apple from "../components/Apple.js";
const Layout = styled.div`
display: flex;
width: 100%;
- place-content: space-between;
+ place-content: center;
+ margin-top: 2rem;
`;
const SidePanel = styled.div`
display: flex;
flex-direction: column;
+ margin-left: 2rem;
+ place-content: space-between;
`;
class Snake extends React.Component {
@@ -61,27 +66,36 @@ class Snake extends React.Component {
snake,
died,
fps,
- score
+ setFps,
+ score,
+ zoom,
+ zoomIn,
+ zoomOut
} = this.props;
return (
-
+
{cell =>
- (cell.type === "apple" && ) ||
- (cell.type === "snake" && )
+ (cell.type === "apple" && ) ||
+ (cell.type === "snake" && )
}
@@ -105,7 +119,10 @@ const mapActionsToProps = {
pauseSnake,
updateFrameSnake,
keyPressedSnake,
- keyPress
+ keyPress,
+ setFps,
+ zoomIn,
+ zoomOut
};
export default connect(
diff --git a/src/redux/snake.js b/src/redux/snake.js
index 5e4bb06..a82d4a2 100644
--- a/src/redux/snake.js
+++ b/src/redux/snake.js
@@ -10,9 +10,11 @@ import {
const MODULE_NAME = "SNAKE";
const DEFAULT_GRID_SIZE = 16;
+const DEFAUL_ZOOM_STEP = 0.1;
const initialState = {
grid: createGrid(DEFAULT_GRID_SIZE),
+ zoom: 1.5,
size: DEFAULT_GRID_SIZE,
paused: false,
vX: 1,
@@ -46,7 +48,18 @@ export const keys = {
snakePart: "snakePart",
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) {
@@ -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 [STOP_SNAKE, stopSnake] = module.action("STOP_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 [CHANGE_DIRECTION, changeDirection] = module.action("CHANGE_DIRECTION", direction => ({ direction }));
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 ================================================================================= */
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) => {
const grid = createGrid(state.size);
+ const zoom = state.zoom;
const apple = options.started ? randomPosition(state.size) : initialState.apple;
const snake = options.started ? [[0, 0]] : initialState.snake;
@@ -126,7 +152,7 @@ module.reducer(RESET_SNAKE, (state, options) => {
snake.forEach((snakePart, 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 }) => {
@@ -223,7 +249,7 @@ module.middleware(START_SNAKE, (dispatch, { started }) => {
module.middleware(STOP_SNAKE, (dispatch, { started }) => {
dispatch(unregisterCaller(UPDATE_FRAME_SNAKE));
- dispatch(unsubscribeKeyPressed(KEY_PRESSED_SNAKE));
+ // dispatch(unsubscribeKeyPressed(KEY_PRESSED_SNAKE));
dispatch(stopLoop());
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 }) => {
if (key === keys.UP || key === keys.k) {
dispatch(changeDirection(directions.UP));
@@ -259,4 +286,31 @@ module.middleware(KEY_PRESSED_SNAKE, (dispatch, _, { key }) => {
if (key === keys.r) {
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));
+ }
});
diff --git a/src/theming/theme.js b/src/theming/theme.js
index 6524f81..fcc2c00 100644
--- a/src/theming/theme.js
+++ b/src/theming/theme.js
@@ -24,7 +24,7 @@ const themes = {
snake: {
cell: {
border: "0.0625rem solid papayawhip",
- size: "1.5rem"
+ size: 1.5
},
cellColors: {
" ": "",