Aquí ambos jugadores tomarán su turno uno por uno. Comenzando con el jugador uno seguido por el jugador dos. Hay tres armas para elegir, a saber, piedra, papel, tijeras. Una vez que el jugador dos juega, el resultado de su turno se calcula actualizando el estado de ganar/perder de ambos jugadores.
Tecnologías Utilizadas / Prerrequisitos:
- ReaccionarJS
- Biblioteca Antd para la interfaz de usuario
Enfoque: los contenedores son componentes de Stateful React (basados en clases). Los componentes son componentes React sin estado (basados en funciones). En este proyecto, tengo un contenedor que es Controller, que es responsable de la gestión del estado y de toda la lógica del juego. Además, hay tres componentes, a saber:
Player ->Representing a Player entity in-game; GameControls -> For Choosing stone, paper, or scissor; DecisionBox -> Displays win/loose status for players;
Al hacer clic en los botones de armas, el estado del controlador se actualiza para el jugador respectivo. Cuando se actualiza el arma del segundo jugador, el resultado se calcula mediante la función del controlador de resultados que cubre las nueve combinaciones de piedra, papel y tijeras tomadas de dos en dos.
Estructura del proyecto:
Pasos :
- Configure el proyecto React usando el comando create-react-app: create-react-app <<name of project>> –scripts-version 1.1.5. Usando este comando, se generará una estructura de proyecto como la anterior, excepto los componentes y las carpetas de contenedores que se crearán dentro de la carpeta src manualmente.
- Instale la biblioteca antd usando el comando: npm install antd
- Elimina el código dentro de App.css .
- Edite el código dentro de App.js : el componente de la aplicación representa el controlador y muestra el título.
Aplicación.jsJavaScript
import React, { Component } from
"react"
;
import Controller from
"./containers/controller/controller"
;
import { Typography } from
"antd"
;
import
"antd/dist/antd.css"
;
import
"./App.css"
;
const { Title } = Typography;
class App extends Component {
render() {
return
(
<div className=
"App"
>
<Title level={3} style={{ textAlign:
"center"
}}>
Stone Paper Scissor
</Title>
<Controller />
</div>
);
}
}
export
default
App;
-
Controller.js: el controlador tiene un estado que incluye el último arma utilizada por cada jugador, el estado actual de victoria/pérdida y el estado activo que indica el turno de qué jugador es.
JavaScript
import React, { Component } from
"react"
;
import { Row, Col, Divider } from
"antd"
;
import { Typography } from
"antd"
;
import axios from
"axios"
;
import
"antd/dist/antd.css"
;
import Player from
"../../components/Player/Player"
;
const { Title } = Typography;
class Controller extends Component {
state = {
playerOne: {
active:
true
,
weapon:
""
,
status:
""
},
playerTwo: {
active:
false
,
weapon:
""
,
status:
""
}
};
La idea central aquí es que al hacer clic en los botones de arma, el arma del jugador correspondiente en el estado debería actualizarse y debería llegar el turno del siguiente jugador, lo cual se hace aquí a través de la función de alternancia activa. Además, si se actualiza el arma del segundo jugador, también se debe actualizar ganar/perder, lo que se hace aquí a través de la función resultHandler. Para la lógica del juego, tiene un montón de funciones:
- Actualización de armas: para actualizar el arma de un jugador en el estado. Se necesitan dos argumentos: el primero es playerId, es decir, playerOne o playerTwo, ya que es un juego de dos jugadores y el segundo es un arma que elige el jugador.
JavaScript
weaponUpdate = (player, weapon) => {
this
.setState({
[player]: {
...
this
.state[player],
weapon: weapon
}
});
if
(player ==
"playerTwo"
) {
this
.resultHandler();
}
else
{
this
.toggleActive();
}
};
- ToggleActive: para revertir el estado activo de los jugadores una vez que cualquiera de los jugadores selecciona un arma. La propiedad activa en el estado es una variable booleana, por lo que solo tenemos que usar el operador NOT para invertir el estado actual de cada jugador.
JavaScript
toggleActive =() => {
this
.setState(prevState => {
return
{
...prevState,
playerOne: {
...prevState.playerOne,
active: !prevState.playerOne.active
},
playerTwo: {
...prevState.playerTwo,
active: !prevState.playerTwo.active
}
};
});
};
- ResultHandler: contiene la lógica principal del juego que decide qué jugador ha ganado. Utiliza una función de ayuda llamada ayudante de decisión que toma dos argumentos que son el arma de cada jugador y devuelve una array que contiene dos elementos en los que el primer elemento corresponde al estado de ganar/perder del primer jugador y, de manera similar, el segundo elemento al estado del segundo jugador. Luego, el manejador de resultados actualiza el estado con los valores devueltos por la función decicerhelper.
JavaScript
resultHandler =() => {
this
.setState(prevState => {
let [s1, s2] =
this
.deciderHelper(
prevState.playerOne.weapon,
prevState.playerTwo.weapon);
return
{
...prevState,
playerOne: {
...prevState.playerOne,
status: s1
},
playerTwo: {
...prevState.playerTwo,
status: s2
}
};
});
this
.toggleActive();
};
- DeciderHelper : es una función auxiliar que toma dos entradas que son armas para cada jugador y devuelve una array que consta de dos elementos, cada uno de los cuales indica el estado de victoria/pérdida del jugador 1 y el jugador 2, respectivamente. Aquí, ‘r’ significa piedra, ‘s’ significa tijera, ‘p’ significa papel, ‘w’ significa victoria y ‘l’ significa suelta. Todas las combinaciones posibles de roca, piedra, tijera se consideran en caso de empate, se devuelven ambos jugadores con estado ganador.
JavaScript
deciderHelper = (p1, p2) => {
if
(p1 ==
"r"
&& p2 ==
"s"
) {
return
[
"w"
,
"l"
];
}
if
(p1 ==
"r"
&& p2 ==
"p"
) {
return
[
"l"
,
"w"
];
}
if
(p1 ==
"r"
&& p2 ==
"r"
) {
return
[
"w"
,
"w"
];
}
if
(p1 ==
"p"
&& p2 ==
"r"
) {
return
[
"w"
,
"l"
];
}
if
(p1 ==
"p"
&& p2 ==
"s"
) {
return
[
"l"
,
"w"
];
}
if
(p1 ==
"p"
&& p2 ==
"p"
) {
return
[
"w"
,
"w"
];
}
if
(p1 ==
"s"
&& p2 ==
"r"
) {
return
[
"l"
,
"w"
];
}
if
(p1 ==
"s"
&& p2 ==
"p"
) {
return
[
"w"
,
"l"
];
}
if
(p1 ==
"s"
&& p2 ==
"s"
) {
return
[
"w"
,
"w"
];
}
};
- Método de procesamiento:
JavaScript
render() {
return
(
<Row justify=
"space-around"
align=
"middle"
>
<Col className=
"gutter-row"
xs={15} sm={15} md={5} lg={5}>
<Title level={3}>Player One</Title>
<Player
active={
this
.state.playerOne.active}
weaponUpdate={weapon =>
this
.weaponUpdate(
"playerOne"
, weapon)}
weapon={
this
.state.playerOne.weapon}
status={
this
.state.playerOne.status}
/>
</Col>
<Col className=
"gutter-row"
xs={15} sm={15} md={5} lg={5}>
<Title level={3}>Player Two</Title>
<Player
active={
this
.state.playerTwo.active}
weaponUpdate={weapon =>
this
.weaponUpdate(
"playerTwo"
, weapon)}
weapon={
this
.state.playerTwo.weapon}
status={
this
.state.playerTwo.status}
/>
</Col>
</Row>
);
}
}
export
default
Controller;
- Actualización de armas: para actualizar el arma de un jugador en el estado. Se necesitan dos argumentos: el primero es playerId, es decir, playerOne o playerTwo, ya que es un juego de dos jugadores y el segundo es un arma que elige el jugador.
-
Codificación de los componentes: el código es muy simple en estos. Solo la lógica representacional reside aquí.
- Player.js : como se mencionó anteriormente, es un componente sin estado que representa una entidad de jugador. Recibe cuatro accesorios que son el estado activo del jugador, el arma actual, el estado de ganar/perder y el controlador de funciones para actualizar el arma. Además, utiliza dos componentes, GameControls y decision box, que se analizan a continuación. Además, si las propiedades activas recibidas son verdaderas, se aplica un objeto CSS llamado glowEffect al div.
JavaScript
import React from
"react"
;
import GameControls from
"../GameControls/GameControls"
;
import DecisionBox from
"../DecisionBox/DecisionBox"
;
const Player = props => {
let glowEffect = {};
if
(props.active) {
glowEffect = {
"-webkit-box-shadow"
:
"0 0 20px blue"
,
"-moz-box-shadow"
:
"0 0 20px blue"
,
"box-shadow"
:
"0 0 20px blue"
};
}
return
(
<div style={glowEffect}>
<GameControls wUpdate={props.weaponUpdate} isActive={props.active} />
<DecisionBox weapon={props.weapon} status={props.status} />
</div>
);
};
export
default
Player;
- GameControls.js: Contiene tres botones roca, piedra, tijera. Si el reproductor no está activo, los botones están desactivados. Al hacer clic en el botón, se llama a la función de actualización de armas, que toma un argumento ‘p’ para papel, ‘r’ para roca, ‘s’ para tijeras y se actualiza el estado correspondiente.
JavaScript
import React from
"react"
;
import { Card } from
"antd"
;
import { Button } from
"antd"
;
import
"antd/dist/antd.css"
;
const GameControls = props => {
return
(
<Card
title=
"Controls"
style={{ width:
"300px"
, height:
"250px"
, alignItems:
"center"
}}
>
<p style={{ alignItems:
"center"
}}>
<Button
type=
"dashed"
size=
"large"
shape=
"round"
block
onClick={() => props.wUpdate(
"r"
)}
disabled={!props.isActive}
>
Rock
</Button>
</p>
<p style={{ alignItems:
"center"
}}>
{
" "
}
<Button
type=
"dashed"
size=
"large"
shape=
"round"
block
onClick={() => props.wUpdate(
"p"
)}
disabled={!props.isActive}
>
Paper
</Button>
</p>
<p style={{ alignItems:
"center"
}}>
<Button
type=
"dashed"
size=
"large"
shape=
"round"
block
onClick={() => props.wUpdate(
"s"
)}
disabled={!props.isActive}
>
Scissors
</Button>
</p>
</Card>
);
};
export
default
GameControls;
- DecisionBox.js : muestra dos cosas: el arma del jugador y el estado de victoria/pérdida del jugador. Recibe dos accesorios arma (‘r’ o ‘p’ o ‘s’) y estado (‘w’ o ‘l’). Se utilizan dos objetos, el mapa de armas y el mapa de estado, para asignar formas abreviadas a palabras adecuadas que se pueden mostrar en la pantalla.
JavaScript
import React from
"react"
;
import { Card } from
"antd"
;
import { Typography } from
"antd"
;
const { Title } = Typography;
const weaponMap = {
s:
"Scissors"
,
p:
"Paper"
,
r:
"Rock"
};
const statusMap = {
w:
"Win"
,
l:
"Loose"
};
const DecisionBox = props => {
return
(
<Card
title=
"Decision Box"
style={{
width:
"300px"
,
height:
"250px"
,
alignItems:
"center"
,
marginTop:
"15px"
}}
bodyStyle={{ textAlign:
"center"
}}
>
<Title level={1} type=
"warning"
>
{weaponMap[props.weapon]}
</Title>
<Title level={2} mark type=
"secondary"
>
{statusMap[props.status]}
</Title>
</Card>
);
};
export
default
DecisionBox;
- Player.js : como se mencionó anteriormente, es un componente sin estado que representa una entidad de jugador. Recibe cuatro accesorios que son el estado activo del jugador, el arma actual, el estado de ganar/perder y el controlador de funciones para actualizar el arma. Además, utiliza dos componentes, GameControls y decision box, que se analizan a continuación. Además, si las propiedades activas recibidas son verdaderas, se aplica un objeto CSS llamado glowEffect al div.
Producción:
Publicación traducida automáticamente
Artículo escrito por manshalamba y traducido por Barcelona Geeks. The original can be accessed here. Licence: CCBY-SA