Skip to content

Commit

Permalink
Merge pull request #25 from shibisuriya/feat/step-controls
Browse files Browse the repository at this point in the history
Feat/step controls
  • Loading branch information
shibisuriya authored Nov 9, 2023
2 parents 5f51ef1 + 750de8e commit 8f86f5d
Show file tree
Hide file tree
Showing 4 changed files with 95 additions and 22 deletions.
58 changes: 53 additions & 5 deletions packages/game-client/src/App.jsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import React, { Fragment, useState } from 'react';
import React, { Fragment, useState, useRef, useEffect } from 'react';
import Game from './Game';
import { Button } from 'antd';
import { Divider, Space, Checkbox, Switch } from 'antd';
import { Divider, Space, Checkbox, Flex, Select, Button } from 'antd';
import { stringToBoolean } from './utils';
import { allSnakesSelectOption } from './constants';

function App() {
const [recordInLocalStorage, setRecordInLocalStorage] = useState(
Expand All @@ -11,6 +11,25 @@ function App() {

const [isGamePaused, setIsGamePaused] = useState(stringToBoolean(localStorage.getItem('isGamePaused') ?? true));
const [showCellId, setShowCellId] = useState(stringToBoolean(localStorage.getItem('showCellId')) ?? false);
const gameRef = useRef();

const [snakeIdList, setSnakeIdList] = useState([allSnakesSelectOption]);
const [selectedSnake, setSelectedSnake] = useState(allSnakesSelectOption);

function updateSnakeIdList(ids) {
if (ids.length > 0) {
if (!ids.includes(selectedSnake) && selectedSnake !== allSnakesSelectOption) {
const [firstId] = ids;
setSelectedSnake(firstId);
}

setSnakeIdList([allSnakesSelectOption].concat(ids));
} else {
setSelectedSnake(null);
setSnakeIdList([]);
}
}

return (
<Fragment>
<Space>
Expand Down Expand Up @@ -44,10 +63,39 @@ function App() {
>
Show cell ID?
</Checkbox>
</Space>
<Button type="primary" onClick={() => gameRef.current.spawnFood()}>
Spawn food
</Button>

<Select
style={{ width: 60 }}
value={selectedSnake}
disabled={snakeIdList.length === 0}
onChange={(val) => {
setSelectedSnake(val);
}}
options={snakeIdList.map((id) => {
return { value: id, label: id };
})}
/>
</Space>
<Flex>
<Space>
<Button type="primary" onClick={() => gameRef.current.prevMove(selectedSnake)}>
{'<'}
</Button>
<Button type="primary" onClick={() => gameRef.current.nextMove(selectedSnake)}>
{'>'}
</Button>
</Space>
</Flex>
<Divider dashed />
<Game showCellId={showCellId} isGamePaused={isGamePaused} />
<Game
ref={gameRef}
showCellId={showCellId}
isGamePaused={isGamePaused}
updateSnakeIdList={updateSnakeIdList}
/>
</Fragment>
);
}
Expand Down
51 changes: 36 additions & 15 deletions packages/game-client/src/Game.jsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import React, { Fragment, useState } from 'react';
import { defaultDirections } from './constants';
import React, { Fragment, useState, useImperativeHandle, forwardRef, useEffect } from 'react';
import { allSnakesSelectOption, defaultDirections } from './constants';
import { initialSnakesState, initialFoodState } from './computed';
import { useDirection, useFood, useTicks, useSnakes, useInput, useSocket } from './hooks';
import Grid from './Grid';
Expand All @@ -17,8 +17,8 @@ import styles from './app.module.css';
// );
// }

function Game(props) {
const { showCellId, isGamePaused } = props;
const Game = forwardRef((props, ref) => {
const { showCellId, isGamePaused, updateSnakeIdList } = props;
const [snakeId, setSnakeId] = useState(1);

// Keep the direction of the snakes inside useRef since we don't
Expand Down Expand Up @@ -53,25 +53,46 @@ function Game(props) {
getTracks,
});

useEffect(() => {
updateSnakeIdList(Object.keys(snakes));
}, [snakes]);

const { addSnakeToTrack, removeSnakeFromTracks, resetSnakeTrack } = useTicks({
moveForward,
spawnFood,
getAllSnakeIds,
isGamePaused,
});

function nextMove(snakeId = allSnakesSelectOption) {
if (snakeId) {
moveForward(snakeId === allSnakesSelectOption ? Object.keys(snakes) : [snakeId]); // Move all the snakes available one step forward.
}
}

function prevMove() {
console.log('Prev move!');
}

useImperativeHandle(
ref,
() => {
return {
nextMove,
prevMove,
spawnFood,
};
},
[],
);

return (
<div className={styles.game}>
{/* <select value={snakeId} onChange={(e) => setSnakeId(e.target.value)}>
{Object.keys(snakes).map((snakeId, index) => (
<option value={snakeId} key={index}>
{snakeId}
</option>
))}
</select> */}
<Grid snakes={snakes} food={food} showCellId={showCellId} />
</div>
<Fragment>
<div className={styles.game}>
<Grid snakes={snakes} food={food} showCellId={showCellId} />
</div>
</Fragment>
);
}
});

export default Game;
4 changes: 3 additions & 1 deletion packages/game-client/src/constants.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ const GRID_WIDTH = 30 * 13;
const GRID_HEIGHT = 30 * 13;
const CELL_DIMENSION = 30;

export const allSnakesSelectOption = 'All';

if (GRID_HEIGHT % CELL_DIMENSION !== 0) {
throw new Error('GRID_HEIGHT is not divislbe by CELL_DIMENSION');
}
Expand Down Expand Up @@ -90,7 +92,7 @@ const FOOD_TYPES = {

const defaultDirections = {
1: DIRECTIONS.RIGHT,
2: DIRECTIONS.DOWN,
2: DIRECTIONS.LEFT,
3: DIRECTIONS.RIGHT,
4: DIRECTIONS.RIGHT,
};
Expand Down
4 changes: 3 additions & 1 deletion packages/game-client/src/hooks/useSnakes.js
Original file line number Diff line number Diff line change
Expand Up @@ -154,7 +154,9 @@ const useSnakes = ({
if (h1 == h2) {
// Head to head collision remove both snakes.
snakesToRemove.push(s1, s2);
removeFood(hash2[h1].x, hash2[h1].y);
if (isFood(hash2[h1].x, hash2[h1].y)) {
removeFood(hash2[h1].x, hash2[h1].y);
}
bothSnakesRemoved = true;
} else {
// remove snake 1
Expand Down

0 comments on commit 8f86f5d

Please sign in to comment.