企画概要
今アツいReactを使って、みんなでアプリを作ってみよう!という思いから始まった神経衰弱アプリ作成企画…
全6回でお送りしてきましたが、今回が最終回!!!
リファクタリング編です
関連記事は以下です
興味のある方は是非シリーズで読んでみてください
- 決起編
- フロント環境構築編
- フロントエンド編
- バックエンド編
- コンポーネント作成編
- リファクタリング編 ★本記事
リファクタリング
ついに神経衰弱ができるようになりました!
Reactの経験が浅いチームでしたが、ここまでこれました!感動です
しかし、あんまりゲームっぽくはないような???
さらに内部のコードも読みにくい…
ということで、ここからはブラッシュアップの時間です
コードが長い
例えば…
import {
Button,
Typography,
Stack,
} from "@mui/material";
import { Link } from "react-router-dom";
const Top = () => {
return (
<div>
<div
style={{
display: "flex",
justifyContent: "center",
marginTop: "200px",
}}
>
<Typography sx={{ fontSize: "4rem", color: "#65BBE9" }}>M</Typography>
<Typography sx={{ fontSize: "4rem" }}>emory</Typography>
<Typography sx={{ fontSize: "4rem", color: "#65BBE9" }}>T</Typography>
<Typography sx={{ fontSize: "4rem" }}>racer</Typography>
</div>
<div
style={{
display: "flex",
justifyContent: "center",
}}
>
<Typography sx={{ fontSize: "2rem", fontWeight: "bold" }}>
神経衰弱
</Typography>
</div>
<div
style={{
display: "flex",
justifyContent: "center",
marginTop: "150px",
}}
>
<Stack>
<Link to="/game">
<Button
variant="outlined"
sx={{ width: "200px", fontSize: "19px" }}
>
Game Start
</Button>
</Link>
</Stack>
</div>
</div>
);
};
うん 長い
この規模の実装なら「めちゃくちゃ読みにくい!」とはなりませんがもっと大きくなると確実に目に優しくなくなるのは目に見えてます
せっかくReactを使っているということもあるので全てコンポーネント化していきましょう
import styled from "@emotion/styled";
import {
Button,
Typography,
} from "@mui/material";
export const TopStyle = styled("div")({
display: "flex",
justifyContent: "center",
marginTop: "200px",
})
export const SubStyle = styled("div")({
display: "flex",
justifyContent: "center",
})
export const ChoiceStyle = styled("div")({
display: "flex",
justifyContent: "center",
marginTop: "150px",
})
export const SelectButton = styled(Button)({
variant: "outlined",
width: "200px",
fontSize: "19px" ,
})
export const LightBlueText = styled(Typography)({
fontSize: "4rem",
color: "#65BBE9"
})
export const BlackText = styled(Typography)({
fontSize: "4rem"
})
export const SubTitleText = styled(Typography)({
fontSize: "2rem",
fontWeight: "bold"
})
今回はtop.tsxの文字数をいかに減らすか焦点を置いているのでpropsは使用していません
このようにcss部分のみ別ファイルに切り出して置くと…
import {
Stack,
} from "@mui/material";
import { Link } from "react-router-dom";
import { TopStyle, SubStyle, ChoiceStyle, SelectButton, LightBlueText, BlackText, SubTitleText } from "../components/element";
const Top = () => {
return (
<>
<TopStyle>
<LightBlueText>M</LightBlueText>
<BlackText>emory</BlackText>
<LightBlueText>T</LightBlueText>
<BlackText>racer</BlackText>
</TopStyle>
<SubStyle>
<SubTitleText>
神経衰弱
</SubTitleText>
</SubStyle>
<ChoiceStyle>
<Stack>
<Link to="/game">
<SelectButton variant="outlined">
Game Start
</SelectButton>
</Link>
</Stack>
</ChoiceStyle>
</>
);
};
とてもすっきりしました
コンポーネント名の先頭は大文字じゃないとReactは認識しないところが注意点です
文字の装飾をまとめて変えたいときも元のコンポーネントを変えるだけなので楽ですね
プレイヤーを焦らせたい
残り時間が少なくなると表示の色が変わると焦りも出やすくなりタイムアタックゲームぽくなるのではないでしょうか?SASUKEのあれっぽいやつです
音こそ出ませんがせっかくなのでプレイヤーを焦らせていきましょう
useEffect(() => {
const area=document.getElementById("time");
if(area !== null)
// countTime = 制限時間
if(countTime <= 10){
area.style.color="red";
}else{
area.style.color="black"
}
})
return(
ゲーム残り時間:
<span id = "time" >{countTime % 90}秒</span>
)
getElementByIdで"time"というidが付与されているhtml要素を取得しています
SASUKEリスペクトなので制限時間が10秒切ったときに赤くなるよう実装しています
いろんな難易度で遊びたい
12組24枚を60秒以内に揃えきってクリアモーダルを拝むのはちょっと厳しい…(少なくとも私は)
もうちょっと簡単なモードも欲しい!ということで作りました
// (変更部分のみ抜粋)
// カードの枚数
const NUMBEROFCARDS = 16;
// カード生成関数
const generateCards = (): CardData[] => {
const values = ["A", "B", "C", "D", "E", "F", "G", "H"];
const cards = values.flatMap((value) => [
{ id: Math.random(), value },
{ id: Math.random(), value },
]);
return shuffle(cards)
};
// カードを並べるためのレイアウトを設定
const rows = [];
for (let i = 0; i < 4; i++) {
rows.push(
<div key={i} style={{ display: "flex", justifyContent: "center" }}>
{cards.slice(i * 4, (i + 1) * 4).map((card) => (
<Card
key={card.id}
id={card.id}
value={card.value}
// 以下評価結果がtrueだと裏になる。
isFlipped={
flippedCards.includes(card.id) || matchedCards.includes(card.id)
}
onClick={handleCardClick}
/>
))}
</div>
);
}
作るといってもカードの総枚数を8種16枚に変えて、カードの枚数に合わせてレイアウトを4×4に変更しただけで他のロジックは使いまわしです
一応、神経衰弱神のために13種52枚のトランプを踏襲したモードも作っておきますか…
// (変更部分のみ抜粋)
// カードの枚数
const NUMBEROFCARDS = 52;
// カード生成関数
const generateCards = (): CardData[] => {
const values = ["A", "2", "3", "4", "5", "6", "7", "8", "9", "10", "J", "Q", "K"];
const cards = values.flatMap((value) => [
{ id: Math.random(), value },
{ id: Math.random(), value },
{ id: Math.random(), value },
{ id: Math.random(), value },
]);
return shuffle(cards)
};
// カードを並べるためのレイアウトを設定
const rows = [];
for (let i = 0; i < 4; i++) {
rows.push(
<div key={i} style={{ display: "flex", justifyContent: "center" }}>
{cards.slice(i * 13, (i + 1) * 13).map((card) => (
<Card
key={card.id}
id={card.id}
value={card.value}
isFlipped={
flippedCards.includes(card.id) || matchedCards.includes(card.id)
}
onClick={handleCardClick}
/>
))}
</div>
);
}
......
ゲーム残り時間:
<span id = "time" >{countTime % 90}秒</span>
先ほどと同じように基本的なロジックは使いまわしです
カードの枚数に加えて制限時間の表示部分とレイアウトを変更しています
{ id: Math.random(), value }
を4つに増やすことで1つの値に対してカードを4枚ずつ("A"が4枚、"2"が4枚、"3"が4枚......)生成しています
それに合わせてレイアウトを4×13に設定しています
ゲーム残り時間:
<span id = "time" >{countTime % 90}秒</span>
カードの総枚数が大幅に増えているので制限時間を90秒に伸ばしています
この難易度ではたして誰がクリアできるんでしょうか!?!?!?
難易度選択したい
現在は12種24枚のモード(以下ノーマルモード)しか遊べないので、今回の8種16枚のモード(以下イージーモード)と13種52枚のモード(以下ハードモード)も遊べるように難易度選択画面を実装します。
(難易度という概念が生まれたのでLink toの向き先を/gameから/normalGameにこっそり変えています)
import { Link } from "react-router-dom";
import {
Stack,
} from "@mui/material";
import { TopStyle, SubStyle, ChoiceStyle, SelectButton, LightBlueText, BlackText, SubTitleText } from "../components/element";
const SelectDifficultyOfGame = () => {
return(
<>
<TopStyle>
<LightBlueText>S</LightBlueText>
<BlackText>elect</BlackText>
<LightBlueText>D</LightBlueText>
<BlackText>ifficulty</BlackText>
</TopStyle>
<SubStyle>
<SubTitleText>難易度選択</SubTitleText>
</SubStyle>
<ChoiceStyle>
<Stack>
<Link to="/easyGame">
<SelectButton
variant="outlined">
Easy
</SelectButton>
</Link>
</Stack>
<Stack>
<Link to="/normalGame">
<SelectButton
variant="outlined">
Normal
</SelectButton>
</Link>
</Stack>
<Stack>
<Link to="/hardGame">
<SelectButton
variant="outlined">
Hard
</SelectButton>
</Link>
</Stack>
</ChoiceStyle>
</>
)
}
なんと先ほどコンポーネント化したおかげでここでもcssを使いまわせています
コンポーネント化っていいですね、時短にもなりますし便利です
完成画面
イージーモードゲーム画面↓↓↓
ハードモードゲーム画面↓↓↓
ハードモードの無理ゲー感が…笑
難易度選択までできるとちゃんとゲームっぽくなりましたね!!!!!