iT邦幫忙

2021 iThome 鐵人賽

DAY 16
0
Modern Web

Canvas 小錦囊系列 第 16

Day 16 - 用 canvas 做射擊小遊戲

  • 分享至 

  • xImage
  •  
import { useEffect, useState, useRef } from "react";
import "./styles.css";
import { playerImg, enemyImage, boomImg } from "./images";
import { forEach } from "lodash";
import usePlayer from "./usePlayer";
import useBullet from "./useBullet";
import useEnemy from "./useEnemy";
const canvasWidth = 500;
const canvasHeight = 500;

let startTimer = null;
const FPS = 31;

export default function App() {
  const [score, setScore] = useState(0);
  const [playerBullets, setPlayerBullets] = useState([]);
  const [playerEnemys, setPlayerEnemys] = useState([]);
  const playerImgRef = useRef(null);
  const enemyImgRef = useRef(null);
  const enemyBoomImgRef = useRef(null);
  const canvasRef = useRef(null);
  const [ctx, setCtx] = useState(null);

  useEffect(() => {
    console.log("playerEnemys", playerEnemys);
  }, [playerEnemys]);

  const endGame = () => {
    clearInterval(startTimer);
    setScore(0);
    setPlayerBullets([]);
    setPlayerEnemys([]);
    playerImgRef.current.img = playerImg;

    ctx.clearRect(0, 0, canvasWidth, canvasHeight);
  };

  useEffect(() => {
    if (canvasRef.current) setCtx(canvasRef.current.getContext("2d"));
  }, [canvasRef]);

  const { bullet, drawBullet, explodeBullet, setBullet } = useBullet({ ctx });

  const { player, drawPlayer, updatePlayer, explodPlayer } = usePlayer({
    endGame,
    ctx,
    setPlayerBullets,
    setBullet,
    bullet,
    playerImgRef
  });

  const { E, setE, explodeE, drawE, enemyImg, active } = useEnemy({
    ctx,
    enemyImgRef
  });

  const startGame = () => {
    update();
    // draw();
    // if (ctx) {
    //   startTimer = setInterval(function () {
    //     update();
    //     draw();
    //   }, 1000 / FPS);
    // }
  };

  const draw = () => {
    if (ctx) {
      ctx.clearRect(0, 0, canvasWidth, canvasHeight);
      drawPlayer();
      forEach(playerBullets, (bullet) => {
        drawBullet();
      });
      forEach(playerEnemys, (enemy) => {
        drawE();
      });
    }
  };

  const update = () => {
    forEach(playerBullets, (bullet, index, object) => {
      setBullet((prev) => {
        return { ...prev, y: prev.y - prev.speed };
      });
      if (bullet?.y < 0 || bullet?.active) {
        object.splice(index, 1);
      }
    });
    forEach(playerEnemys, (enemy, index, object) => {
      setE((prev) => ({ ...prev, y: prev.y + enemy.speed }));
      if (enemy.y > canvasHeight || enemy.active) {
        setScore((prev) => prev + 1);
        object.splice(index, 1);
      }
    });
    console.log(Math.random(), Math.random() < 0.02);
    if (Math.random() < 0.5) {
      console.log("add");
      setPlayerEnemys((prev) => [...prev, { ...E }]);
    }
    handleCollisions();
  };

  const handleCollisions = () => {
    forEach(playerBullets, (bullet) => {
      forEach(playerEnemys, (enemy) => {
        if (collides(bullet, enemy)) {
          explodeBullet();
          explodeE();
        }
      });
    });

    forEach(playerEnemys, (enemy) => {
      if (collides(enemy, player)) {
        explodeE();
        explodPlayer();
      }
    });
  };

  const collides = (a, b) => {
    return (
      a.x < b.x + b.width &&
      a.x + a.width > b.x &&
      a.y < b.y + b.height &&
      a.y + a.height > b.y
    );
  };

  return (
    <div className="App">
      <button className="startBtn" onClick={startGame}>
        Start
      </button>
      <div> Score:{score}</div>
      <br />
      <canvas
        ref={canvasRef}
        width={canvasWidth}
        height={canvasHeight}
      ></canvas>
      <img alt="" className="playerImg" ref={playerImgRef} src={playerImg} />
      <img alt="" className="enemyImg" ref={enemyImgRef} src={enemyImage} />
      <img
        alt=""
        className="enemyBoomImg"
        ref={enemyBoomImgRef}
        src={boomImg}
      />
    </div>
  );
}

待完成
https://codesandbox.io/s/tie-ren-sai-she-ji-you-xi-g0kob?file=/src/App.js:0-3833


上一篇
Day 15 - 用 canvas 做打彈珠
下一篇
Day 17 - canvas 文字換行
系列文
Canvas 小錦囊30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言