From d40917eda1fe3ac4483a991dcd45636ecce8a948 Mon Sep 17 00:00:00 2001 From: dzevako Date: Wed, 24 Feb 2021 14:48:27 +0500 Subject: [PATCH 1/8] feat: base logic of game and base components --- .gitignore | 2 + package.json | 37 ++++++++ src/main/js/app.js | 21 +++++ src/main/js/components/game/GamePanel.css | 0 src/main/js/components/game/GamePanel.jsx | 0 src/main/js/components/page/Page.css | 23 +++++ src/main/js/components/page/Page.jsx | 28 ++++++ src/main/js/components/snake/SnakeElement.css | 8 ++ src/main/js/components/snake/SnakeElement.jsx | 24 +++++ src/main/js/components/square/Square.css | 10 ++ src/main/js/components/square/Square.jsx | 94 +++++++++++++++++++ src/main/js/components/target/Target.css | 23 +++++ src/main/js/components/target/Target.jsx | 34 +++++++ src/main/resources/templates/index.html | 19 ++++ webpack/config.js | 52 ++++++++++ webpack/define.js | 23 +++++ webpack/loaders.js | 65 +++++++++++++ webpack/optimization.js | 17 ++++ webpack/plugins.js | 22 +++++ webpack/resolve.js | 21 +++++ 20 files changed, 523 insertions(+) create mode 100644 .gitignore create mode 100644 package.json create mode 100644 src/main/js/app.js create mode 100644 src/main/js/components/game/GamePanel.css create mode 100644 src/main/js/components/game/GamePanel.jsx create mode 100644 src/main/js/components/page/Page.css create mode 100644 src/main/js/components/page/Page.jsx create mode 100644 src/main/js/components/snake/SnakeElement.css create mode 100644 src/main/js/components/snake/SnakeElement.jsx create mode 100644 src/main/js/components/square/Square.css create mode 100644 src/main/js/components/square/Square.jsx create mode 100644 src/main/js/components/target/Target.css create mode 100644 src/main/js/components/target/Target.jsx create mode 100644 src/main/resources/templates/index.html create mode 100644 webpack/config.js create mode 100644 webpack/define.js create mode 100644 webpack/loaders.js create mode 100644 webpack/optimization.js create mode 100644 webpack/plugins.js create mode 100644 webpack/resolve.js diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..d5f19d8 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +node_modules +package-lock.json diff --git a/package.json b/package.json new file mode 100644 index 0000000..467778c --- /dev/null +++ b/package.json @@ -0,0 +1,37 @@ +{ + "name": "vkapp", + "version": "0.1.0", + "description": "VK APP", + "author": "Zevako Dmitry", + "license": "Apache-2.0", + "dependencies": { + "react": "^16.5.2", + "react-dom": "^16.5.2", + "react-keyboard-event-handler": "^1.5.4", + "rest": "^1.3.1" + }, + "scripts": { + "dev": "webpack-dev-server --hot --inline --config './webpack/config.js'", + "flow": "flow" + }, + "devDependencies": { + "@babel/core": "^7.1.0", + "@babel/plugin-proposal-class-properties": "^7.2.1", + "@babel/preset-env": "^7.1.0", + "@babel/preset-flow": "^7.0.0", + "@babel/preset-react": "^7.0.0", + "babel-loader": "^8.0.2", + "classnames": "^2.2.6", + "css-loader": "^0.28.11", + "html-webpack-plugin": "^3.2.0", + "less": "^3.8.1", + "less-loader": "^4.1.0", + "mini-css-extract-plugin": "^0.4.0", + "my-local-ip": "^1.0.0", + "postcss-loader": "^2.1.5", + "style-loader": "^0.21.0", + "webpack": "^4.19.1", + "webpack-cli": "^3.1.0", + "webpack-dev-server": "^3.1.14" + } +} diff --git a/src/main/js/app.js b/src/main/js/app.js new file mode 100644 index 0000000..3de0dbd --- /dev/null +++ b/src/main/js/app.js @@ -0,0 +1,21 @@ +import Page from './components/page/Page.jsx'; + +const React = require('react'); +const ReactDOM = require('react-dom'); + +/** + * Client Entry Point + */ +class App extends React.Component { + + render() { + return + } +} + +ReactDOM.render ( + , + document.getElementById('root') + ) + +export default App; \ No newline at end of file diff --git a/src/main/js/components/game/GamePanel.css b/src/main/js/components/game/GamePanel.css new file mode 100644 index 0000000..e69de29 diff --git a/src/main/js/components/game/GamePanel.jsx b/src/main/js/components/game/GamePanel.jsx new file mode 100644 index 0000000..e69de29 diff --git a/src/main/js/components/page/Page.css b/src/main/js/components/page/Page.css new file mode 100644 index 0000000..5b1af3f --- /dev/null +++ b/src/main/js/components/page/Page.css @@ -0,0 +1,23 @@ +:local { + .header { + height: 60px; + background: #2a3347; + } + + .topMenu { + height: 20px; + } + + .container {} + + .leftMenu { + display: inline-block; + width: 16%; + min-width: 300px; + height: 100%; + } + + .content { + /*display: inline-block;*/ + } + } diff --git a/src/main/js/components/page/Page.jsx b/src/main/js/components/page/Page.jsx new file mode 100644 index 0000000..f902c6f --- /dev/null +++ b/src/main/js/components/page/Page.jsx @@ -0,0 +1,28 @@ +//import Block from '../block/Block.jsx'; +import Square from '../square/Square.jsx'; +import styles from './Page.css'; + +const React = require('react'); + +/** + * Разметка страницы (сетка с блоками) + */ +class Page extends React.Component { + + render() { + return ( + [ +
, +
, +
+
+
+ +
+
+ ] + ) + } +} + +export default Page; \ No newline at end of file diff --git a/src/main/js/components/snake/SnakeElement.css b/src/main/js/components/snake/SnakeElement.css new file mode 100644 index 0000000..9741cc0 --- /dev/null +++ b/src/main/js/components/snake/SnakeElement.css @@ -0,0 +1,8 @@ +:local { + .snakeElement { + border-radius: 8px; + background: #9a4900; + box-sizing: border-box; + position: absolute; + } + } \ No newline at end of file diff --git a/src/main/js/components/snake/SnakeElement.jsx b/src/main/js/components/snake/SnakeElement.jsx new file mode 100644 index 0000000..3564b00 --- /dev/null +++ b/src/main/js/components/snake/SnakeElement.jsx @@ -0,0 +1,24 @@ +import styles from './SnakeElement.css'; + +const React = require('react'); + +/** + * Элемент тела змейки + */ +class SnakeElement extends React.Component { + + render() { + const {x, y, size} = this.props; + const style = { + width: size + "px", + height: size + "px", + left: x * size, + top: y * size + }; + return ( +
+ ) + } +} + +export default SnakeElement; \ No newline at end of file diff --git a/src/main/js/components/square/Square.css b/src/main/js/components/square/Square.css new file mode 100644 index 0000000..367260d --- /dev/null +++ b/src/main/js/components/square/Square.css @@ -0,0 +1,10 @@ +:local { + .square { + height: 600px; + width: 1000px; + margin: auto; + background: #9fc5d4; + border: 5px solid #797979; + position: relative; + } + } \ No newline at end of file diff --git a/src/main/js/components/square/Square.jsx b/src/main/js/components/square/Square.jsx new file mode 100644 index 0000000..dcd4753 --- /dev/null +++ b/src/main/js/components/square/Square.jsx @@ -0,0 +1,94 @@ +import Target from '../target/Target.jsx'; +import SnakeElement from '../snake/SnakeElement.jsx'; +import styles from './Square.css'; + +const React = require('react'); +const KeyboardEventHandler = require('react-keyboard-event-handler'); + +/** + * Главное поле игры +*/ +class Square extends React.Component { + + constructor(props) { + super(props); + //this.state = {target: {x : 5, y : 7}}; + this.state = {target: this.getNewTarget(), + snake: [{x: 5, y: 7}, {x: 4, y: 7}, {x: 3, y: 7}], + direction: 'right'}; + + setInterval(() => { + let {target, snake, direction} = this.state; + + const frontElement = this.step(snake[0], direction); + if (target.x === frontElement.x && target.y === frontElement.y){ + target = this.getNewTarget(); + } else { + snake.pop(); + } + snake.unshift(frontElement); + this.setState({target, snake}) + }, 100); + } + + step(frontElement, direction) { + let x = frontElement.x; + let y = frontElement.y; + if (direction === 'left') { + x = x - 1; + } + if (direction === 'right') { + x = x + 1; + } + if (direction === 'up') { + y = y - 1; + } + if (direction === 'down') { + y = y + 1; + } + return {x, y}; + } + + render() { + const {target, snake} = this.state; + return ( +
+ + {snake.map((el) => { + return ( + + ); + })} + this.processChangeDirection(key)} + /> +
+ ) + } + + getNewTarget() { + return {x : this.getRandomInt(50), y : this.getRandomInt(30)}; + } + + getKey(el) { + return (el.x + el.y) * (el.x - el.y); + } + + processChangeDirection(key) { + let {direction} = this.state; + if ((direction === 'left' || direction === 'right') && + (key === 'left' || key === 'right') || + (direction === 'up' || direction === 'down') && + (key === 'up' || key === 'down')) { + return; + } + this.setState({direction : key}); + } + + getRandomInt(max) { + return Math.floor(Math.random() * Math.floor(max)); + } +} + +export default Square; \ No newline at end of file diff --git a/src/main/js/components/target/Target.css b/src/main/js/components/target/Target.css new file mode 100644 index 0000000..ec085c8 --- /dev/null +++ b/src/main/js/components/target/Target.css @@ -0,0 +1,23 @@ +:local { + .target { + border-radius: 3px; + background: #dcdc45; + border: 1px solid #797979; + box-sizing: border-box; + position: absolute; + } + + .blink { + animation-name: blinker; + animation-iteration-count: infinite; + animation-timing-function: cubic-bezier(1.0,0,0,1.0); + animation-duration: 2s; + } + + @keyframes blinker { + from { opacity: 1.0; } + to { opacity: 0.0; } + } + } + + \ No newline at end of file diff --git a/src/main/js/components/target/Target.jsx b/src/main/js/components/target/Target.jsx new file mode 100644 index 0000000..81f8e03 --- /dev/null +++ b/src/main/js/components/target/Target.jsx @@ -0,0 +1,34 @@ +import styles from './Target.css'; + +const React = require('react'); + +/** + * Цель для змейки + */ +class Target extends React.Component { + + constructor(props) { + super(props); + //this.state = {target: {x : 5, y : 7}}; + //this.state = {target: {x : this.getRandomInt(50), y : this.getRandomInt(30)}}; + } + + render() { + const {x, y, size} = this.props; + const style = { + width: size + "px", + height: size + "px", + left: x * size, + top: y * size + }; + return ( +
+ ) + } + + getRandomInt(max) { + return Math.floor(Math.random() * Math.floor(max)); + } +} + +export default Target; \ No newline at end of file diff --git a/src/main/resources/templates/index.html b/src/main/resources/templates/index.html new file mode 100644 index 0000000..2ac51cb --- /dev/null +++ b/src/main/resources/templates/index.html @@ -0,0 +1,19 @@ + + + + + + ReactGame + + + + + + + +
+ + + + + diff --git a/webpack/config.js b/webpack/config.js new file mode 100644 index 0000000..7cb666b --- /dev/null +++ b/webpack/config.js @@ -0,0 +1,52 @@ +'use strict'; + +const path = require('path'); +const express = require('express'); +const localIp = require('my-local-ip'); + +const define = require('./define'); +const loaders = require('./loaders'); +const optimization = require('./optimization'); +const plugins = require('./plugins'); +const resolve = require('./resolve'); + +console.log('Reading webpack config...'); + +//console.log('entry.index = ' + path.join(define.src, 'app.js')); +//console.log('output.path = ' + path.resolve(__dirname, "../src/main/resources/static/built")); + +module.exports = { + + target: "web", + + entry: { + index: path.join(define.src, 'app.js') + }, + + output: { + path: define.staticPath, + //path: path.resolve(__dirname, "../src/main/resources/static"), + filename: './built/bundle.js', + //publicPath : path.resolve(__dirname, "../target/classes/static") + }, + + devtool: define.development ? 'inline-source-map' : false, + + cache: true, + + mode: define.mode, + + module: loaders, + + optimization, + + plugins, + + resolve, + + devServer: { + host: localIp(), + port: define.port.dev, + contentBase: define.staticPath + }, +}; diff --git a/webpack/define.js b/webpack/define.js new file mode 100644 index 0000000..0383378 --- /dev/null +++ b/webpack/define.js @@ -0,0 +1,23 @@ +// @flow +'use strict'; + +const {resolve} = require('path'); + +const environment = 'development'; // process.env.NODE_ENV; +const development = environment === 'development'; +const staticPath = resolve(__dirname, '../src/main/resources/static'); +const production = environment === 'production'; +const src = resolve(__dirname, '../src/main/js'); +const port = { + dev: 9000, + prod: 8080 + } + +module.exports = { + development, + staticPath, + mode: environment, + production, + src, + port +}; diff --git a/webpack/loaders.js b/webpack/loaders.js new file mode 100644 index 0000000..667c2da --- /dev/null +++ b/webpack/loaders.js @@ -0,0 +1,65 @@ +// @flow +'use strict'; + +const Autoprefixer = require('autoprefixer'); +const define = require('./define'); +const MiniCssExtractPlugin = require('mini-css-extract-plugin'); + +module.exports = { + rules: [ + { + exclude: /(node_modules|bower_components)/, + test: /\.jsx?$/, + use: { + loader: 'babel-loader', + options: { + presets: ["@babel/preset-env", "@babel/preset-react"], + plugins: ["@babel/plugin-proposal-class-properties"] + } + } + }, + { + test: /\.(css|less)$/, + use: [ + { + loader: MiniCssExtractPlugin.loader + }, + { + loader: 'css-loader', + options: { + localIdentName: define.development ? '[path][name]__[local]' : '[hash:base64]', + sourceMap: define.development + } + }, + { + loader: 'postcss-loader', + options: { + plugins: [ + new Autoprefixer({ + browsers: [ + '>1%', + 'last 3 versions', + 'ie > 8' + ] + }) + ], + sourceMap: define.development + } + }, + { + loader: 'less-loader', + options: { + relativeUrls: true, + sourceMap: define.development + } + } + ] + }, + { + test: /\.(gif|png|jpg|jpeg|woff|woff2|ttf|eot|svg)$/, + use: { + loader: 'file-loader' + } + } + ] +}; diff --git a/webpack/optimization.js b/webpack/optimization.js new file mode 100644 index 0000000..8e9eac0 --- /dev/null +++ b/webpack/optimization.js @@ -0,0 +1,17 @@ +// @flow +'use strict'; + +const define = require('./define'); +const UglifyJsPlugin = require('uglifyjs-webpack-plugin'); + +const optimization = define.production + ? { + minimizer: [ + new UglifyJsPlugin({ + cache: false + }) + ] + } + : {}; + +module.exports = optimization; diff --git a/webpack/plugins.js b/webpack/plugins.js new file mode 100644 index 0000000..ce99de9 --- /dev/null +++ b/webpack/plugins.js @@ -0,0 +1,22 @@ +// @flow +'use strict'; + +const {join} = require('path'); + +const HtmlWebpackPlugin = require('html-webpack-plugin'); +// MiniCssExtractPlugin заменяет ExtractTextWebpackPlugin и выполняет ту же задачу (сборку css в один файл) +const MiniCssExtractPlugin = require('mini-css-extract-plugin'); + +const plugins = [ + new MiniCssExtractPlugin({ + chunkFilename: '[id].css', + filename: '[name].css' + }), + new HtmlWebpackPlugin({ + filename: 'index.html', + template: join(__dirname, '../src/main/resources/templates/index.html'), + title: 'Scheduler' + }) +]; + +module.exports = plugins; diff --git a/webpack/resolve.js b/webpack/resolve.js new file mode 100644 index 0000000..cc55206 --- /dev/null +++ b/webpack/resolve.js @@ -0,0 +1,21 @@ +// @flow +'use strict'; + +const define = require('./define'); +const {resolve} = require('path'); + +module.exports = { + alias: { + 'actions': resolve(define.src, 'actions'), + 'component': resolve(define.src, 'component'), + 'constants': resolve(define.src, 'constants'), + 'helpers': resolve(define.src, 'helpers'), + 'images': resolve(define.src, 'images'), + 'init': resolve(define.src, 'init'), + 'reducers': resolve(define.src, 'reducers'), + 'store': resolve(define.src, 'store'), + 'styles': resolve(define.src, 'styles'), + 'types': resolve(define.src, 'types') + }, + extensions: ['.js', '.jsx'] +}; From dfa33bcd5230155a352bfb685558b52d2c865e3c Mon Sep 17 00:00:00 2001 From: dzevako Date: Wed, 24 Feb 2021 18:00:30 +0500 Subject: [PATCH 2/8] feat: add crash with walls and self --- src/main/js/components/page/Page.jsx | 2 +- src/main/js/components/square/Square.css | 8 +- src/main/js/components/square/Square.jsx | 123 ++++++++++++++++------- 3 files changed, 93 insertions(+), 40 deletions(-) diff --git a/src/main/js/components/page/Page.jsx b/src/main/js/components/page/Page.jsx index f902c6f..08b3b08 100644 --- a/src/main/js/components/page/Page.jsx +++ b/src/main/js/components/page/Page.jsx @@ -17,7 +17,7 @@ class Page extends React.Component {
- +
] diff --git a/src/main/js/components/square/Square.css b/src/main/js/components/square/Square.css index 367260d..c948851 100644 --- a/src/main/js/components/square/Square.css +++ b/src/main/js/components/square/Square.css @@ -1,10 +1,14 @@ :local { .square { - height: 600px; - width: 1000px; margin: auto; background: #9fc5d4; border: 5px solid #797979; position: relative; } + + .crash { + background: #f1a5af; + border-color: #b76570; + transition: background .5s, border-color .5s; + } } \ No newline at end of file diff --git a/src/main/js/components/square/Square.jsx b/src/main/js/components/square/Square.jsx index dcd4753..0b5f582 100644 --- a/src/main/js/components/square/Square.jsx +++ b/src/main/js/components/square/Square.jsx @@ -10,57 +10,109 @@ const KeyboardEventHandler = require('react-keyboard-event-handler'); */ class Square extends React.Component { + roundId = null; + left = 'left'; + right = 'right'; + up = 'up'; + down = 'down'; + leftRight = [this.left, this.right]; + upDown = [this.up, this.down]; + constructor(props) { super(props); - //this.state = {target: {x : 5, y : 7}}; + this.state = {target: this.getNewTarget(), - snake: [{x: 5, y: 7}, {x: 4, y: 7}, {x: 3, y: 7}], - direction: 'right'}; + snake: [{x: 39, y: 7}, {x: 38, y: 7}, {x: 37, y: 7}], + direction: this.right, + crash: false}; + } + + componentDidMount() { + this.startRound() + } + + startRound() { + this.roundId = setInterval(() => this.roundStep(), this.props.speed); + } - setInterval(() => { - let {target, snake, direction} = this.state; + stopRound() { + clearInterval(this.roundId); + } + + roundStep() { + let {target, snake, direction, crash} = this.state; - const frontElement = this.step(snake[0], direction); - if (target.x === frontElement.x && target.y === frontElement.y){ - target = this.getNewTarget(); - } else { + const frontElement = this.snakeStep(snake[0], direction); + console.log(frontElement.x + " " + frontElement.y) + if (target.x === frontElement.x && target.y === frontElement.y){ + target = this.getNewTarget(); + } else { + if (this.moveIsValid(snake, frontElement)) { snake.pop(); + snake.unshift(frontElement); + } else { + crash = true; + this.stopRound(); } - snake.unshift(frontElement); - this.setState({target, snake}) - }, 100); + } + + this.setState({target, snake, crash}) } - step(frontElement, direction) { + snakeStep(frontElement, direction) { let x = frontElement.x; let y = frontElement.y; - if (direction === 'left') { - x = x - 1; - } - if (direction === 'right') { - x = x + 1; + switch (direction) { + case this.left: x = x - 1; break; + case this.right: x = x + 1; break; + case this.up: y = y - 1; break; + case this.down: y = y + 1; break; } - if (direction === 'up') { - y = y - 1; + + return {x, y}; + } + + moveIsValid(snake, frontElement) { + const {width, height} = this.props; + const x = frontElement.x; + const y = frontElement.y; + if (x < 0 || y < 0 || x >= width || y >= height) { + return false; } - if (direction === 'down') { - y = y + 1; + + const lastIndex = snake.length - 1; + const hitch = snake.filter((item, index) => { + return index != lastIndex && item.x == x && item.y == y + }); + + console.log(hitch.length) + + if (hitch.length > 0) { + return false; } - return {x, y}; + + return true; } render() { - const {target, snake} = this.state; - return ( -
+ const {target, snake, crash} = this.state; + const {width, height, step} = this.props; + const style = { + width: width * step + "px", + height: height * step + "px", + }; + + const cm = styles.square + (crash ? " " + styles.crash : ""); + return ( +
- {snake.map((el) => { + {snake.map((el, index) => { return ( - + ); })} this.processChangeDirection(key)} />
@@ -71,18 +123,15 @@ class Square extends React.Component { return {x : this.getRandomInt(50), y : this.getRandomInt(30)}; } - getKey(el) { - return (el.x + el.y) * (el.x - el.y); - } - processChangeDirection(key) { let {direction} = this.state; - if ((direction === 'left' || direction === 'right') && - (key === 'left' || key === 'right') || - (direction === 'up' || direction === 'down') && - (key === 'up' || key === 'down')) { + + // Forbid turn for 180 degrees + if (this.upDown.indexOf(key) > -1 && this.upDown.indexOf(direction) > -1 + || this.leftRight.indexOf(key) > -1 && this.leftRight.indexOf(direction) > -1) { return; } + this.setState({direction : key}); } From f1095c81aca90cb250bd2ade5b00fc21e4cda6b9 Mon Sep 17 00:00:00 2001 From: dzevako Date: Fri, 26 Feb 2021 16:51:41 +0500 Subject: [PATCH 3/8] feat: controls + refactor: dom --- package.json | 1 + src/main/js/app.js | 4 +-- src/main/js/components/game/Game.css | 25 +++++++++++++++ src/main/js/components/game/Game.jsx | 31 +++++++++++++++++++ src/main/js/components/game/GamePanel.css | 0 src/main/js/components/game/GamePanel.jsx | 0 .../components/game/controls/ControlPanel.css | 15 +++++++++ .../components/game/controls/ControlPanel.jsx | 26 ++++++++++++++++ .../Square.css => game/main/GamePanel.css} | 2 +- .../Square.jsx => game/main/GamePanel.jsx} | 19 ++++++------ src/main/js/components/page/Page.css | 23 -------------- src/main/js/components/page/Page.jsx | 28 ----------------- src/main/resources/templates/index.html | 3 -- webpack/config.js | 8 ++--- webpack/define.js | 2 ++ 15 files changed, 117 insertions(+), 70 deletions(-) create mode 100644 src/main/js/components/game/Game.css create mode 100644 src/main/js/components/game/Game.jsx delete mode 100644 src/main/js/components/game/GamePanel.css delete mode 100644 src/main/js/components/game/GamePanel.jsx create mode 100644 src/main/js/components/game/controls/ControlPanel.css create mode 100644 src/main/js/components/game/controls/ControlPanel.jsx rename src/main/js/components/{square/Square.css => game/main/GamePanel.css} (94%) rename src/main/js/components/{square/Square.jsx => game/main/GamePanel.jsx} (89%) delete mode 100644 src/main/js/components/page/Page.css delete mode 100644 src/main/js/components/page/Page.jsx diff --git a/package.json b/package.json index 467778c..17ae5fc 100644 --- a/package.json +++ b/package.json @@ -11,6 +11,7 @@ "rest": "^1.3.1" }, "scripts": { + "build": "--mode 'production' --config './webpack/config.js'", "dev": "webpack-dev-server --hot --inline --config './webpack/config.js'", "flow": "flow" }, diff --git a/src/main/js/app.js b/src/main/js/app.js index 3de0dbd..6d0b3b8 100644 --- a/src/main/js/app.js +++ b/src/main/js/app.js @@ -1,4 +1,4 @@ -import Page from './components/page/Page.jsx'; +import Game from './components/game/Game'; const React = require('react'); const ReactDOM = require('react-dom'); @@ -9,7 +9,7 @@ const ReactDOM = require('react-dom'); class App extends React.Component { render() { - return + return } } diff --git a/src/main/js/components/game/Game.css b/src/main/js/components/game/Game.css new file mode 100644 index 0000000..666770a --- /dev/null +++ b/src/main/js/components/game/Game.css @@ -0,0 +1,25 @@ +:local { + .header { + height: 60px; + background: #2a3347; + color: azure; + font-size: 32px; + letter-spacing: 48px; + text-align: center; + line-height: 60px; + } + + .topMenu { + height: 20px; + } + + .flexContainer { + display: table; + margin: auto; + } + + .flexContent { + display: inline-flex; + background: rgb(213, 229, 235); + } + } diff --git a/src/main/js/components/game/Game.jsx b/src/main/js/components/game/Game.jsx new file mode 100644 index 0000000..d0904f9 --- /dev/null +++ b/src/main/js/components/game/Game.jsx @@ -0,0 +1,31 @@ +//import Block from '../block/Block.jsx'; +import ControlPanel from './controls/ControlPanel.jsx'; +import GamePanel from './main/GamePanel.jsx'; +import styles from './Game.css'; + +const React = require('react'); + +/** + * Игра + */ +class Game extends React.Component { + + + + render() { + return ( + [ +
SNAKE
, +
, +
+
+ + +
+
+ ] + ) + } +} + +export default Game; \ No newline at end of file diff --git a/src/main/js/components/game/GamePanel.css b/src/main/js/components/game/GamePanel.css deleted file mode 100644 index e69de29..0000000 diff --git a/src/main/js/components/game/GamePanel.jsx b/src/main/js/components/game/GamePanel.jsx deleted file mode 100644 index e69de29..0000000 diff --git a/src/main/js/components/game/controls/ControlPanel.css b/src/main/js/components/game/controls/ControlPanel.css new file mode 100644 index 0000000..0568122 --- /dev/null +++ b/src/main/js/components/game/controls/ControlPanel.css @@ -0,0 +1,15 @@ +:local { + .controlPanel { + padding: 16px; + background: #e2e2e2; + } + .startButton { + height: 32px; + width: 120px; + /*background: #eb992e;*/ + } + .score { + font-size: 32; + color: greenyellow + } + } \ No newline at end of file diff --git a/src/main/js/components/game/controls/ControlPanel.jsx b/src/main/js/components/game/controls/ControlPanel.jsx new file mode 100644 index 0000000..432887d --- /dev/null +++ b/src/main/js/components/game/controls/ControlPanel.jsx @@ -0,0 +1,26 @@ +import styles from './ControlPanel.css'; + +const React = require('react'); + +/** + * Панель управления + */ +class ControlPanel extends React.Component { + + constructor(props) { + super(props); + + this.state = {score: 0}; + } + + render() { + return ( +
+
{this.state.score}
+ +
+ ); + } +} + +export default ControlPanel; \ No newline at end of file diff --git a/src/main/js/components/square/Square.css b/src/main/js/components/game/main/GamePanel.css similarity index 94% rename from src/main/js/components/square/Square.css rename to src/main/js/components/game/main/GamePanel.css index c948851..f014f57 100644 --- a/src/main/js/components/square/Square.css +++ b/src/main/js/components/game/main/GamePanel.css @@ -1,5 +1,5 @@ :local { - .square { + .gameField { margin: auto; background: #9fc5d4; border: 5px solid #797979; diff --git a/src/main/js/components/square/Square.jsx b/src/main/js/components/game/main/GamePanel.jsx similarity index 89% rename from src/main/js/components/square/Square.jsx rename to src/main/js/components/game/main/GamePanel.jsx index 0b5f582..7dbd5e3 100644 --- a/src/main/js/components/square/Square.jsx +++ b/src/main/js/components/game/main/GamePanel.jsx @@ -1,6 +1,6 @@ -import Target from '../target/Target.jsx'; -import SnakeElement from '../snake/SnakeElement.jsx'; -import styles from './Square.css'; +import Target from '../../target/Target.jsx'; +import SnakeElement from '../../snake/SnakeElement.jsx'; +import styles from './GamePanel.css'; const React = require('react'); const KeyboardEventHandler = require('react-keyboard-event-handler'); @@ -8,7 +8,7 @@ const KeyboardEventHandler = require('react-keyboard-event-handler'); /** * Главное поле игры */ -class Square extends React.Component { +class GamePanel extends React.Component { roundId = null; left = 'left'; @@ -42,10 +42,11 @@ class Square extends React.Component { roundStep() { let {target, snake, direction, crash} = this.state; - const frontElement = this.snakeStep(snake[0], direction); + const frontElement = this.getNextStep(snake[0], direction); console.log(frontElement.x + " " + frontElement.y) - if (target.x === frontElement.x && target.y === frontElement.y){ + if (target.x === frontElement.x && target.y === frontElement.y) { target = this.getNewTarget(); + snake.unshift(frontElement); } else { if (this.moveIsValid(snake, frontElement)) { snake.pop(); @@ -59,7 +60,7 @@ class Square extends React.Component { this.setState({target, snake, crash}) } - snakeStep(frontElement, direction) { + getNextStep(frontElement, direction) { let x = frontElement.x; let y = frontElement.y; switch (direction) { @@ -102,7 +103,7 @@ class Square extends React.Component { height: height * step + "px", }; - const cm = styles.square + (crash ? " " + styles.crash : ""); + const cm = styles.gameField + (crash ? " " + styles.crash : ""); return (
@@ -140,4 +141,4 @@ class Square extends React.Component { } } -export default Square; \ No newline at end of file +export default GamePanel; \ No newline at end of file diff --git a/src/main/js/components/page/Page.css b/src/main/js/components/page/Page.css deleted file mode 100644 index 5b1af3f..0000000 --- a/src/main/js/components/page/Page.css +++ /dev/null @@ -1,23 +0,0 @@ -:local { - .header { - height: 60px; - background: #2a3347; - } - - .topMenu { - height: 20px; - } - - .container {} - - .leftMenu { - display: inline-block; - width: 16%; - min-width: 300px; - height: 100%; - } - - .content { - /*display: inline-block;*/ - } - } diff --git a/src/main/js/components/page/Page.jsx b/src/main/js/components/page/Page.jsx deleted file mode 100644 index 08b3b08..0000000 --- a/src/main/js/components/page/Page.jsx +++ /dev/null @@ -1,28 +0,0 @@ -//import Block from '../block/Block.jsx'; -import Square from '../square/Square.jsx'; -import styles from './Page.css'; - -const React = require('react'); - -/** - * Разметка страницы (сетка с блоками) - */ -class Page extends React.Component { - - render() { - return ( - [ -
, -
, -
-
-
- -
-
- ] - ) - } -} - -export default Page; \ No newline at end of file diff --git a/src/main/resources/templates/index.html b/src/main/resources/templates/index.html index 2ac51cb..0920ac0 100644 --- a/src/main/resources/templates/index.html +++ b/src/main/resources/templates/index.html @@ -10,10 +10,7 @@ -
- - diff --git a/webpack/config.js b/webpack/config.js index 7cb666b..4ff6363 100644 --- a/webpack/config.js +++ b/webpack/config.js @@ -12,8 +12,8 @@ const resolve = require('./resolve'); console.log('Reading webpack config...'); -//console.log('entry.index = ' + path.join(define.src, 'app.js')); -//console.log('output.path = ' + path.resolve(__dirname, "../src/main/resources/static/built")); +console.log('entry.index = ' + path.join(define.src, 'app.js')); +console.log('output.path = ' + path.resolve(__dirname, "../src/main/resources/static/built")); module.exports = { @@ -24,9 +24,9 @@ module.exports = { }, output: { - path: define.staticPath, + path: define.buildPath, //path: path.resolve(__dirname, "../src/main/resources/static"), - filename: './built/bundle.js', + filename: 'index.js', //publicPath : path.resolve(__dirname, "../target/classes/static") }, diff --git a/webpack/define.js b/webpack/define.js index 0383378..856ff37 100644 --- a/webpack/define.js +++ b/webpack/define.js @@ -6,6 +6,7 @@ const {resolve} = require('path'); const environment = 'development'; // process.env.NODE_ENV; const development = environment === 'development'; const staticPath = resolve(__dirname, '../src/main/resources/static'); +const buildPath = resolve(__dirname, '../build'); const production = environment === 'production'; const src = resolve(__dirname, '../src/main/js'); const port = { @@ -16,6 +17,7 @@ const port = { module.exports = { development, staticPath, + buildPath, mode: environment, production, src, From e2450d3dfc64981bcc65aa7d751fbe168d9d7284 Mon Sep 17 00:00:00 2001 From: dzevako Date: Sun, 28 Feb 2021 14:17:54 +0500 Subject: [PATCH 4/8] refactor: state level up from GameField --- src/main/js/app.js | 4 +- src/main/js/components/game/Game.css | 25 --- src/main/js/components/game/Game.jsx | 149 ++++++++++++++++-- .../{main/GamePanel.css => GameField.css} | 0 src/main/js/components/game/GameField.jsx | 38 +++++ .../components/game/controls/ControlPanel.css | 10 +- .../components/game/controls/ControlPanel.jsx | 7 +- .../js/components/game/main/GamePanel.jsx | 144 ----------------- src/main/js/components/page/Page.css | 30 ++++ src/main/js/components/page/Page.jsx | 24 +++ src/main/js/components/snake/SnakeElement.jsx | 14 +- src/main/js/components/target/Target.jsx | 10 +- 12 files changed, 250 insertions(+), 205 deletions(-) rename src/main/js/components/game/{main/GamePanel.css => GameField.css} (100%) create mode 100644 src/main/js/components/game/GameField.jsx delete mode 100644 src/main/js/components/game/main/GamePanel.jsx create mode 100644 src/main/js/components/page/Page.css create mode 100644 src/main/js/components/page/Page.jsx diff --git a/src/main/js/app.js b/src/main/js/app.js index 6d0b3b8..4943365 100644 --- a/src/main/js/app.js +++ b/src/main/js/app.js @@ -1,4 +1,4 @@ -import Game from './components/game/Game'; +import Page from './components/page/Page'; const React = require('react'); const ReactDOM = require('react-dom'); @@ -9,7 +9,7 @@ const ReactDOM = require('react-dom'); class App extends React.Component { render() { - return + return } } diff --git a/src/main/js/components/game/Game.css b/src/main/js/components/game/Game.css index 666770a..e69de29 100644 --- a/src/main/js/components/game/Game.css +++ b/src/main/js/components/game/Game.css @@ -1,25 +0,0 @@ -:local { - .header { - height: 60px; - background: #2a3347; - color: azure; - font-size: 32px; - letter-spacing: 48px; - text-align: center; - line-height: 60px; - } - - .topMenu { - height: 20px; - } - - .flexContainer { - display: table; - margin: auto; - } - - .flexContent { - display: inline-flex; - background: rgb(213, 229, 235); - } - } diff --git a/src/main/js/components/game/Game.jsx b/src/main/js/components/game/Game.jsx index d0904f9..d9b100c 100644 --- a/src/main/js/components/game/Game.jsx +++ b/src/main/js/components/game/Game.jsx @@ -1,31 +1,148 @@ -//import Block from '../block/Block.jsx'; +import GameField from './GameField.jsx'; import ControlPanel from './controls/ControlPanel.jsx'; -import GamePanel from './main/GamePanel.jsx'; -import styles from './Game.css'; const React = require('react'); +const KeyboardEventHandler = require('react-keyboard-event-handler'); /** - * Игра - */ + * Главное поле игры +*/ class Game extends React.Component { + roundId = null; + left = 'left'; + right = 'right'; + up = 'up'; + down = 'down'; + leftRight = [this.left, this.right]; + upDown = [this.up, this.down]; + constructor(props) { + super(props); + + this.state = {target: this.getNewTarget(), + snake: [{x: 39, y: 7}, {x: 38, y: 7}, {x: 37, y: 7}], + direction: this.right, + crash: false}; + } + + /*UNSAFE_componentWillReceiveProps(nextProps) { + console.log(nextProps); + if (nextProps.onComplete) { + this.startRound(); + nextProps.onComplete(); + } + }*/ + + startRound() { + this.roundId = setInterval(() => this.roundStep(), this.props.speed); + } + + stopRound() { + clearInterval(this.roundId); + } + + roundStep() { + let {target, snake, direction, crash} = this.state; + + const frontElement = this.getNextStep(snake[0], direction); + console.log(frontElement.x + " " + frontElement.y) + if (target.x === frontElement.x && target.y === frontElement.y) { + target = this.getNewTarget(); + snake.unshift(frontElement); + } else { + if (this.moveIsValid(snake, frontElement)) { + snake.pop(); + snake.unshift(frontElement); + } else { + crash = true; + this.stopRound(); + } + } + + this.setState({target, snake, crash}) + } + + getNextStep(frontElement, direction) { + let x = frontElement.x; + let y = frontElement.y; + switch (direction) { + case this.left: x = x - 1; break; + case this.right: x = x + 1; break; + case this.up: y = y - 1; break; + case this.down: y = y + 1; break; + } + + return {x, y}; + } + + moveIsValid(snake, frontElement) { + const {width, height} = this.props; + const x = frontElement.x; + const y = frontElement.y; + if (x < 0 || y < 0 || x >= width || y >= height) { + return false; + } + + const lastIndex = snake.length - 1; + const hitch = snake.filter((item, index) => { + return index != lastIndex && item.x == x && item.y == y + }); + + console.log(hitch.length) + + if (hitch.length > 0) { + return false; + } + + return true; + } render() { - return ( - [ -
SNAKE
, -
, -
-
- - -
-
- ] + const {target, snake, crash} = this.state; + const {width, height, step} = this.props; + const {left, right, up, down} = this; + console.log("Game:" + width) + return ( +
+ + this.startRound()} + /> + this.processChangeDirection(key)} + /> +
) } + + getNewTarget() { + return {x : this.getRandomInt(50), y : this.getRandomInt(30)}; + } + + processChangeDirection(key) { + let {direction} = this.state; + + // Forbid turn for 180 degrees + if (this.upDown.indexOf(key) > -1 && this.upDown.indexOf(direction) > -1 + || this.leftRight.indexOf(key) > -1 && this.leftRight.indexOf(direction) > -1) { + return; + } + + this.setState({direction : key}); + } + + getRandomInt(max) { + return Math.floor(Math.random() * Math.floor(max)); + } } export default Game; \ No newline at end of file diff --git a/src/main/js/components/game/main/GamePanel.css b/src/main/js/components/game/GameField.css similarity index 100% rename from src/main/js/components/game/main/GamePanel.css rename to src/main/js/components/game/GameField.css diff --git a/src/main/js/components/game/GameField.jsx b/src/main/js/components/game/GameField.jsx new file mode 100644 index 0000000..eff48fb --- /dev/null +++ b/src/main/js/components/game/GameField.jsx @@ -0,0 +1,38 @@ +import Target from '../target/Target.jsx'; +import SnakeElement from '../snake/SnakeElement.jsx'; +import styles from './GameField.css'; + +const React = require('react'); + +/** + * Главное поле игры +*/ +class GameField extends React.Component { + + render() { + + const {width, height, step, target, snake, crash} = this.props; + console.log(width) + const style = { + width: width * step + "px", + height: height * step + "px", + }; + + const cm = styles.gameField + (crash ? " " + styles.crash : ""); + return ( +
+ + + + {snake.map((el, index) => { + return ( + + ); + })} + +
+ ) + } +} + +export default GameField; \ No newline at end of file diff --git a/src/main/js/components/game/controls/ControlPanel.css b/src/main/js/components/game/controls/ControlPanel.css index 0568122..7f5b6c8 100644 --- a/src/main/js/components/game/controls/ControlPanel.css +++ b/src/main/js/components/game/controls/ControlPanel.css @@ -3,13 +3,19 @@ padding: 16px; background: #e2e2e2; } + .controlPanel > * { + display: inline-block; + margin-right: 32px; + } + .startButton { height: 32px; width: 120px; /*background: #eb992e;*/ } .score { - font-size: 32; - color: greenyellow + font-size: 32px; + color: rgb(255, 106, 47); + vertical-align: middle; } } \ No newline at end of file diff --git a/src/main/js/components/game/controls/ControlPanel.jsx b/src/main/js/components/game/controls/ControlPanel.jsx index 432887d..fadbf30 100644 --- a/src/main/js/components/game/controls/ControlPanel.jsx +++ b/src/main/js/components/game/controls/ControlPanel.jsx @@ -13,11 +13,16 @@ class ControlPanel extends React.Component { this.state = {score: 0}; } + handleClick = () => { + const {onClick} = this.props; + onClick && onClick(); + } + render() { return (
+
{this.state.score}
-
); } diff --git a/src/main/js/components/game/main/GamePanel.jsx b/src/main/js/components/game/main/GamePanel.jsx deleted file mode 100644 index 7dbd5e3..0000000 --- a/src/main/js/components/game/main/GamePanel.jsx +++ /dev/null @@ -1,144 +0,0 @@ -import Target from '../../target/Target.jsx'; -import SnakeElement from '../../snake/SnakeElement.jsx'; -import styles from './GamePanel.css'; - -const React = require('react'); -const KeyboardEventHandler = require('react-keyboard-event-handler'); - -/** - * Главное поле игры -*/ -class GamePanel extends React.Component { - - roundId = null; - left = 'left'; - right = 'right'; - up = 'up'; - down = 'down'; - leftRight = [this.left, this.right]; - upDown = [this.up, this.down]; - - constructor(props) { - super(props); - - this.state = {target: this.getNewTarget(), - snake: [{x: 39, y: 7}, {x: 38, y: 7}, {x: 37, y: 7}], - direction: this.right, - crash: false}; - } - - componentDidMount() { - this.startRound() - } - - startRound() { - this.roundId = setInterval(() => this.roundStep(), this.props.speed); - } - - stopRound() { - clearInterval(this.roundId); - } - - roundStep() { - let {target, snake, direction, crash} = this.state; - - const frontElement = this.getNextStep(snake[0], direction); - console.log(frontElement.x + " " + frontElement.y) - if (target.x === frontElement.x && target.y === frontElement.y) { - target = this.getNewTarget(); - snake.unshift(frontElement); - } else { - if (this.moveIsValid(snake, frontElement)) { - snake.pop(); - snake.unshift(frontElement); - } else { - crash = true; - this.stopRound(); - } - } - - this.setState({target, snake, crash}) - } - - getNextStep(frontElement, direction) { - let x = frontElement.x; - let y = frontElement.y; - switch (direction) { - case this.left: x = x - 1; break; - case this.right: x = x + 1; break; - case this.up: y = y - 1; break; - case this.down: y = y + 1; break; - } - - return {x, y}; - } - - moveIsValid(snake, frontElement) { - const {width, height} = this.props; - const x = frontElement.x; - const y = frontElement.y; - if (x < 0 || y < 0 || x >= width || y >= height) { - return false; - } - - const lastIndex = snake.length - 1; - const hitch = snake.filter((item, index) => { - return index != lastIndex && item.x == x && item.y == y - }); - - console.log(hitch.length) - - if (hitch.length > 0) { - return false; - } - - return true; - } - - render() { - const {target, snake, crash} = this.state; - const {width, height, step} = this.props; - const style = { - width: width * step + "px", - height: height * step + "px", - }; - - const cm = styles.gameField + (crash ? " " + styles.crash : ""); - return ( -
- - {snake.map((el, index) => { - return ( - - ); - })} - this.processChangeDirection(key)} - /> -
- ) - } - - getNewTarget() { - return {x : this.getRandomInt(50), y : this.getRandomInt(30)}; - } - - processChangeDirection(key) { - let {direction} = this.state; - - // Forbid turn for 180 degrees - if (this.upDown.indexOf(key) > -1 && this.upDown.indexOf(direction) > -1 - || this.leftRight.indexOf(key) > -1 && this.leftRight.indexOf(direction) > -1) { - return; - } - - this.setState({direction : key}); - } - - getRandomInt(max) { - return Math.floor(Math.random() * Math.floor(max)); - } -} - -export default GamePanel; \ No newline at end of file diff --git a/src/main/js/components/page/Page.css b/src/main/js/components/page/Page.css new file mode 100644 index 0000000..39a2e50 --- /dev/null +++ b/src/main/js/components/page/Page.css @@ -0,0 +1,30 @@ +:local { + .header { + height: 60px; + background: #2a3347; + color: azure; + font-size: 32px; + letter-spacing: 48px; + text-align: center; + line-height: 60px; + } + + .topMenu { + height: 20px; + } + + .flexContainer { + display: table; + margin: auto; + } + + .flexContent { + display: inline-flex; + background: rgb(213, 229, 235); + } + } + + body { + margin: 0; + background: #b7b681; + } \ No newline at end of file diff --git a/src/main/js/components/page/Page.jsx b/src/main/js/components/page/Page.jsx new file mode 100644 index 0000000..c2991ba --- /dev/null +++ b/src/main/js/components/page/Page.jsx @@ -0,0 +1,24 @@ + +import Game from '../game/Game.jsx'; +import styles from './Page.css'; + +const React = require('react'); + +/** + * Страница с игрой + */ +class Page extends React.Component { + + render() { + return ( + [ +
SNAKE
, +
+ +
+ ] + ) + } +} + +export default Page; \ No newline at end of file diff --git a/src/main/js/components/snake/SnakeElement.jsx b/src/main/js/components/snake/SnakeElement.jsx index 3564b00..7367d74 100644 --- a/src/main/js/components/snake/SnakeElement.jsx +++ b/src/main/js/components/snake/SnakeElement.jsx @@ -8,13 +8,13 @@ const React = require('react'); class SnakeElement extends React.Component { render() { - const {x, y, size} = this.props; - const style = { - width: size + "px", - height: size + "px", - left: x * size, - top: y * size - }; + const {x, y, size} = this.props; + const style = { + width: size + "px", + height: size + "px", + left: x * size + "px", + top: y * size + "px" + }; return (
) diff --git a/src/main/js/components/target/Target.jsx b/src/main/js/components/target/Target.jsx index 81f8e03..86fd9d9 100644 --- a/src/main/js/components/target/Target.jsx +++ b/src/main/js/components/target/Target.jsx @@ -7,19 +7,13 @@ const React = require('react'); */ class Target extends React.Component { - constructor(props) { - super(props); - //this.state = {target: {x : 5, y : 7}}; - //this.state = {target: {x : this.getRandomInt(50), y : this.getRandomInt(30)}}; - } - render() { const {x, y, size} = this.props; const style = { width: size + "px", height: size + "px", - left: x * size, - top: y * size + left: x * size + "px", + top: y * size + "px" }; return (
From 17460a8e89b769bb6c0aeb7bf50e7d857ed90b3e Mon Sep 17 00:00:00 2001 From: dzevako Date: Sun, 28 Feb 2021 14:28:59 +0500 Subject: [PATCH 5/8] feat: game score --- src/main/js/components/game/Game.jsx | 11 +++++++---- src/main/js/components/game/controls/ControlPanel.jsx | 8 +------- 2 files changed, 8 insertions(+), 11 deletions(-) diff --git a/src/main/js/components/game/Game.jsx b/src/main/js/components/game/Game.jsx index d9b100c..eeee60c 100644 --- a/src/main/js/components/game/Game.jsx +++ b/src/main/js/components/game/Game.jsx @@ -23,7 +23,8 @@ class Game extends React.Component { this.state = {target: this.getNewTarget(), snake: [{x: 39, y: 7}, {x: 38, y: 7}, {x: 37, y: 7}], direction: this.right, - crash: false}; + crash: false, + score: 0}; } /*UNSAFE_componentWillReceiveProps(nextProps) { @@ -43,12 +44,13 @@ class Game extends React.Component { } roundStep() { - let {target, snake, direction, crash} = this.state; + let {target, snake, direction, crash, score} = this.state; const frontElement = this.getNextStep(snake[0], direction); console.log(frontElement.x + " " + frontElement.y) if (target.x === frontElement.x && target.y === frontElement.y) { target = this.getNewTarget(); + score = score + 1; snake.unshift(frontElement); } else { if (this.moveIsValid(snake, frontElement)) { @@ -60,7 +62,7 @@ class Game extends React.Component { } } - this.setState({target, snake, crash}) + this.setState({target, snake, crash, score}) } getNextStep(frontElement, direction) { @@ -99,7 +101,7 @@ class Game extends React.Component { } render() { - const {target, snake, crash} = this.state; + const {target, snake, crash, score} = this.state; const {width, height, step} = this.props; const {left, right, up, down} = this; console.log("Game:" + width) @@ -115,6 +117,7 @@ class Game extends React.Component { /> this.startRound()} + score = {score} /> { const {onClick} = this.props; @@ -22,7 +16,7 @@ class ControlPanel extends React.Component { return (
-
{this.state.score}
+
Score: {this.props.score}
); } From c20a45101634c287eede8d359e02d21ebe0266be Mon Sep 17 00:00:00 2001 From: dzevako Date: Sun, 28 Feb 2021 15:18:27 +0500 Subject: [PATCH 6/8] feat: restart game --- src/main/js/components/game/Game.jsx | 18 ++++++------------ src/main/js/components/game/GameField.jsx | 6 ++++-- 2 files changed, 10 insertions(+), 14 deletions(-) diff --git a/src/main/js/components/game/Game.jsx b/src/main/js/components/game/Game.jsx index eeee60c..a695062 100644 --- a/src/main/js/components/game/Game.jsx +++ b/src/main/js/components/game/Game.jsx @@ -20,22 +20,16 @@ class Game extends React.Component { constructor(props) { super(props); - this.state = {target: this.getNewTarget(), - snake: [{x: 39, y: 7}, {x: 38, y: 7}, {x: 37, y: 7}], - direction: this.right, - crash: false, + this.state = {crash: false, score: 0}; } - /*UNSAFE_componentWillReceiveProps(nextProps) { - console.log(nextProps); - if (nextProps.onComplete) { - this.startRound(); - nextProps.onComplete(); - } - }*/ - startRound() { + this.setState({target: this.getNewTarget(), + snake: [{x: 39, y: 7}, {x: 38, y: 7}, {x: 37, y: 7}], + direction: this.right, + crash: false, + score: 0}) this.roundId = setInterval(() => this.roundStep(), this.props.speed); } diff --git a/src/main/js/components/game/GameField.jsx b/src/main/js/components/game/GameField.jsx index eff48fb..4a44c72 100644 --- a/src/main/js/components/game/GameField.jsx +++ b/src/main/js/components/game/GameField.jsx @@ -22,9 +22,11 @@ class GameField extends React.Component { return (
- + {target && ( + + )} - {snake.map((el, index) => { + {snake && snake.map((el, index) => { return ( ); From b0474e1d590abaafc690c99bb08a3e0c164eeded Mon Sep 17 00:00:00 2001 From: dzevako Date: Sun, 28 Feb 2021 16:01:51 +0500 Subject: [PATCH 7/8] feat: start button disable after start --- src/main/js/components/game/Game.css | 0 src/main/js/components/game/Game.jsx | 13 ++++++------- src/main/js/components/game/GameField.jsx | 5 +++-- .../components/game/controls/ControlPanel.css | 18 ++++++++++++++++-- .../components/game/controls/ControlPanel.jsx | 6 ++++-- src/main/js/components/page/Page.css | 15 +++++---------- src/main/js/components/page/Page.jsx | 4 ++-- 7 files changed, 36 insertions(+), 25 deletions(-) delete mode 100644 src/main/js/components/game/Game.css diff --git a/src/main/js/components/game/Game.css b/src/main/js/components/game/Game.css deleted file mode 100644 index e69de29..0000000 diff --git a/src/main/js/components/game/Game.jsx b/src/main/js/components/game/Game.jsx index a695062..e485d6e 100644 --- a/src/main/js/components/game/Game.jsx +++ b/src/main/js/components/game/Game.jsx @@ -20,8 +20,10 @@ class Game extends React.Component { constructor(props) { super(props); - this.state = {crash: false, + this.state = {crash: true, score: 0}; + + this.startRound = this.startRound.bind(this); } startRound() { @@ -39,9 +41,8 @@ class Game extends React.Component { roundStep() { let {target, snake, direction, crash, score} = this.state; - const frontElement = this.getNextStep(snake[0], direction); - console.log(frontElement.x + " " + frontElement.y) + if (target.x === frontElement.x && target.y === frontElement.y) { target = this.getNewTarget(); score = score + 1; @@ -85,8 +86,6 @@ class Game extends React.Component { return index != lastIndex && item.x == x && item.y == y }); - console.log(hitch.length) - if (hitch.length > 0) { return false; } @@ -98,7 +97,7 @@ class Game extends React.Component { const {target, snake, crash, score} = this.state; const {width, height, step} = this.props; const {left, right, up, down} = this; - console.log("Game:" + width) + return (
this.startRound()} + onClick={crash && this.startRound} score = {score} /> diff --git a/src/main/js/components/game/controls/ControlPanel.css b/src/main/js/components/game/controls/ControlPanel.css index 7f5b6c8..0bad866 100644 --- a/src/main/js/components/game/controls/ControlPanel.css +++ b/src/main/js/components/game/controls/ControlPanel.css @@ -11,11 +11,25 @@ .startButton { height: 32px; width: 120px; - /*background: #eb992e;*/ + background: #eb992e; + border: none; + color: white; + letter-spacing: 4px; } + .startButton:hover { + background: #d38c2e; + } + .startButton:active { + background: #b8761f; + } + + .disabled { + background-color: #ccc !important; + } + .score { font-size: 32px; - color: rgb(255, 106, 47); + color: #eb992e; vertical-align: middle; } } \ No newline at end of file diff --git a/src/main/js/components/game/controls/ControlPanel.jsx b/src/main/js/components/game/controls/ControlPanel.jsx index a1a2c3a..f465a6e 100644 --- a/src/main/js/components/game/controls/ControlPanel.jsx +++ b/src/main/js/components/game/controls/ControlPanel.jsx @@ -13,10 +13,12 @@ class ControlPanel extends React.Component { } render() { + const {onClick, score} = this.props; + const cm = styles.startButton + (!onClick ? " " + styles.disabled : ""); return (
- -
Score: {this.props.score}
+ +
Score: {score}
); } diff --git a/src/main/js/components/page/Page.css b/src/main/js/components/page/Page.css index 39a2e50..4ad605b 100644 --- a/src/main/js/components/page/Page.css +++ b/src/main/js/components/page/Page.css @@ -13,18 +13,13 @@ height: 20px; } - .flexContainer { + .container { display: table; margin: auto; } - - .flexContent { - display: inline-flex; - background: rgb(213, 229, 235); - } } - body { - margin: 0; - background: #b7b681; - } \ No newline at end of file +body { + margin: 0; + background: #b7b681; +} \ No newline at end of file diff --git a/src/main/js/components/page/Page.jsx b/src/main/js/components/page/Page.jsx index c2991ba..604f894 100644 --- a/src/main/js/components/page/Page.jsx +++ b/src/main/js/components/page/Page.jsx @@ -13,8 +13,8 @@ class Page extends React.Component { return ( [
SNAKE
, -
- +
+
] ) From 1623ce39c09490b61c9c924df81d523d92a87f28 Mon Sep 17 00:00:00 2001 From: dzevako Date: Sun, 28 Feb 2021 17:18:35 +0500 Subject: [PATCH 8/8] feat: create boost --- src/main/js/components/game/Game.jsx | 38 +++++++++++++++---- .../components/game/controls/ControlPanel.css | 13 +++++++ .../components/game/controls/ControlPanel.jsx | 25 +++++++++++- 3 files changed, 67 insertions(+), 9 deletions(-) diff --git a/src/main/js/components/game/Game.jsx b/src/main/js/components/game/Game.jsx index e485d6e..8253383 100644 --- a/src/main/js/components/game/Game.jsx +++ b/src/main/js/components/game/Game.jsx @@ -16,23 +16,40 @@ class Game extends React.Component { down = 'down'; leftRight = [this.left, this.right]; upDown = [this.up, this.down]; + speed = 1000; + boost = 0; constructor(props) { super(props); this.state = {crash: true, score: 0}; - - this.startRound = this.startRound.bind(this); } - startRound() { + startRound = () => { + + this.speed = this.props.speed; + this.setState({target: this.getNewTarget(), snake: [{x: 39, y: 7}, {x: 38, y: 7}, {x: 37, y: 7}], direction: this.right, crash: false, score: 0}) - this.roundId = setInterval(() => this.roundStep(), this.props.speed); + + this.start(); + } + + start() { + this.roundId = setInterval(() => this.roundStep(), this.speed); + } + + restartWithBoost() { + if (this.boost == 0) { + return; + } + clearInterval(this.roundId); + this.speed = this.speed - this.speed * this.boost / 100; + this.start(); } stopRound() { @@ -47,6 +64,7 @@ class Game extends React.Component { target = this.getNewTarget(); score = score + 1; snake.unshift(frontElement); + this.restartWithBoost(); } else { if (this.moveIsValid(snake, frontElement)) { snake.pop(); @@ -92,6 +110,11 @@ class Game extends React.Component { return true; } + + onBoostChange = (value) => { + this.boost = (!value || value < 1 || value > 50) ? 0 : value; + console.log("setBoost: " + this.boost) + } render() { const {target, snake, crash, score} = this.state; @@ -110,11 +133,12 @@ class Game extends React.Component { /> this.processChangeDirection(key)} + onKeyEvent={(key, e) => this.handleChangeDirection(key)} />
) @@ -124,7 +148,7 @@ class Game extends React.Component { return {x : this.getRandomInt(50), y : this.getRandomInt(30)}; } - processChangeDirection(key) { + handleChangeDirection(key) { let {direction} = this.state; // Forbid turn for 180 degrees diff --git a/src/main/js/components/game/controls/ControlPanel.css b/src/main/js/components/game/controls/ControlPanel.css index 0bad866..70c3851 100644 --- a/src/main/js/components/game/controls/ControlPanel.css +++ b/src/main/js/components/game/controls/ControlPanel.css @@ -25,11 +25,24 @@ .disabled { background-color: #ccc !important; + color: grey !important; } .score { font-size: 32px; color: #eb992e; vertical-align: middle; + float: right; } + .boost { + color: #24c524; + font-size: 24px; + vertical-align: middle; + } + .boost input { + height: 32px; + width: 40px; + margin: 0 8px; + padding: 0 4px; + } } \ No newline at end of file diff --git a/src/main/js/components/game/controls/ControlPanel.jsx b/src/main/js/components/game/controls/ControlPanel.jsx index f465a6e..982df44 100644 --- a/src/main/js/components/game/controls/ControlPanel.jsx +++ b/src/main/js/components/game/controls/ControlPanel.jsx @@ -12,12 +12,33 @@ class ControlPanel extends React.Component { onClick && onClick(); } + handleBoostChange= (value) => { + const {onBoostChange} = this.props; + onBoostChange && onBoostChange(value); + } + + mayBeDisabled = (style, disabled) => { + return style + (disabled ? " " + styles.disabled : ""); + } + render() { const {onClick, score} = this.props; - const cm = styles.startButton + (!onClick ? " " + styles.disabled : ""); + return (
- + +
+ Boost: + this.handleBoostChange(e.target.value)} + /> + % +
Score: {score}
);