iT邦幫忙

2024 iThome 鐵人賽

0
生成式 AI

輕鬆搞笑與陪伴系列 第 15

Day15 - 懶

  • 分享至 

  • xImage
  •  

InteractiveComponent


小遊戲

既然這個頁面一直改不好,那乾脆全部重寫,好麻煩XD。

看完貓咪和梗圖,可以來這邊打遊戲,現在很陽春也沒什麼設計感,之後再參考其他的網頁做一些炫泡一點的。

Game

程式碼如下圖

import React, { useState, useEffect, useRef } from 'react';
import { FaRedo, FaPlay, FaPause } from 'react-icons/fa';

function getRandomPosition(maxWidth, maxHeight) {
  const x = Math.floor(Math.random() * maxWidth);
  const y = Math.floor(Math.random() * maxHeight);
  return { x, y };
}

function getRandomColor() {
  const colors = ['#FF6347', '#4682B4', '#32CD32', '#FFD700', '#8A2BE2'];
  return colors[Math.floor(Math.random() * colors.length)];
}

function getRandomSize() {
  return Math.floor(Math.random() * 30) + 20; // 隨機大小在20到50之間
}

function getRandomScore() {
  return Math.floor(Math.random() * 10) + 1; // 隨機分數在1到10之間
}

function InteractiveComponent() {
  const [score, setScore] = useState(0);
  const [highScore, setHighScore] = useState(0);
  const [targets, setTargets] = useState([]);
  const [timeLeft, setTimeLeft] = useState(30); // 倒計時30秒
  const [isPlaying, setIsPlaying] = useState(false);
  const gameAreaRef = useRef(null);
  const timerRef = useRef(null);
  const moveTargetsRef = useRef(null);

  useEffect(() => {
    const { clientWidth, clientHeight } = gameAreaRef.current;
    const initialTargets = Array.from({ length: 5 }).map(() => ({
      position: getRandomPosition(clientWidth - 50, clientHeight - 50),
      color: getRandomColor(),
      size: getRandomSize(),
      score: getRandomScore(),
    }));
    setTargets(initialTargets);
  }, []);

  useEffect(() => {
    if (isPlaying) {
      timerRef.current = setInterval(() => {
        setTimeLeft((prevTime) => {
          if (prevTime <= 1) {
            clearInterval(timerRef.current);
            clearInterval(moveTargetsRef.current);
            setIsPlaying(false);
            return 0;
          }
          return prevTime - 1;
        });
      }, 1000);

      moveTargetsRef.current = setInterval(() => {
        const { clientWidth, clientHeight } = gameAreaRef.current;
        setTargets((prevTargets) =>
          prevTargets.map((target) => ({
            ...target,
            position: getRandomPosition(clientWidth - target.size, clientHeight - target.size),
          }))
        );
      }, 2000); // 將移動速度變慢
    } else {
      clearInterval(timerRef.current);
      clearInterval(moveTargetsRef.current);
    }

    return () => {
      clearInterval(timerRef.current);
      clearInterval(moveTargetsRef.current);
    };
  }, [isPlaying]);

  const handleTargetClick = (index) => {
    setScore((prevScore) => prevScore + targets[index].score);
    const { clientWidth, clientHeight } = gameAreaRef.current;
    setTargets((prevTargets) =>
      prevTargets.map((target, i) =>
        i === index
          ? {
              position: getRandomPosition(clientWidth - target.size, clientHeight - target.size),
              color: getRandomColor(),
              size: getRandomSize(),
              score: getRandomScore(),
            }
          : target
      )
    );
  };

  const handleRestart = () => {
    setHighScore((prevHighScore) => Math.max(prevHighScore, score));
    setScore(0);
    setTimeLeft(30);
    setIsPlaying(false);
    const { clientWidth, clientHeight } = gameAreaRef.current;
    const initialTargets = Array.from({ length: 5 }).map(() => ({
      position: getRandomPosition(clientWidth - 50, clientHeight - 50),
      color: getRandomColor(),
      size: getRandomSize(),
      score: getRandomScore(),
    }));
    setTargets(initialTargets);
  };

  const handleStartPause = () => {
    setIsPlaying((prevIsPlaying) => !prevIsPlaying);
  };

  return (
    <div className="flex flex-col items-center justify-center w-full h-screen bg-white text-black">
      <div className="flex flex-col md:flex-row items-center justify-between w-full px-4 py-2 bg-gray-200 shadow-md space-y-2 md:space-y-0 md:space-x-4">
        <h1 className="text-xl font-bold">點下去就對了</h1>
        <p className="text-lg">得分: {score}</p>
        <p className="text-lg">最高分數: {highScore}</p>
        <p className="text-lg">剩餘時間: {timeLeft} 秒</p>
      </div>
      <div className="flex items-center justify-center w-full px-4 py-2 bg-gray-200 shadow-md space-x-4 mt-2">
        <button
          onClick={handleStartPause}
          className="flex items-center px-4 py-2 bg-green-500 text-white font-semibold rounded-md shadow-md hover:bg-green-600 transition-all"
        >
          {isPlaying ? <FaPause className="mr-2" /> : <FaPlay className="mr-2" />}
          {isPlaying ? '暫停遊戲' : '開始遊戲'}
        </button>
        <button
          onClick={handleRestart}
          className="flex items-center px-4 py-2 bg-blue-500 text-white font-semibold rounded-md shadow-md hover:bg-blue-600 transition-all"
        >
          <FaRedo className="mr-2" />
          重新開始
        </button>
      </div>
      <div
        ref={gameAreaRef}
        className="relative w-full h-full flex-grow bg-gray-100 rounded-lg shadow-lg overflow-hidden mt-4"
      >
        {timeLeft > 0 ? (
          targets.map((target, index) => (
            <div
              key={index}
              onClick={() => handleTargetClick(index)}
              style={{
                top: target.position.y,
                left: target.position.x,
                width: `${target.size}px`,
                height: `${target.size}px`,
                backgroundColor: target.color,
                position: 'absolute',
                borderRadius: '50%',
                cursor: 'pointer',
                transition: 'all 0.2s ease-in-out',
              }}
              className="transform hover:scale-110"
            ></div>
          ))
        ) : (
          <div className="absolute inset-0 flex flex-col items-center justify-center">
            <p className="text-4xl font-bold mb-4">遊戲結束!</p>
            <button
              onClick={handleRestart}
              className="flex items-center px-4 py-2 bg-blue-500 text-white font-semibold rounded-md shadow-md hover:bg-blue-600 transition-all"
            >
              <FaRedo className="mr-2" />
              重新開始
            </button>
          </div>
        )}
      </div>
    </div>
  );
}

export default InteractiveComponent;

GitHub Copilot對之後的建議

以下是一些可以進一步提升這個遊戲體驗的點子和優化流程的建議:

1. 增加遊戲難度

隨著時間的推移,目標的移動速度逐漸加快,讓遊戲變得更具挑戰性。

2. 增加不同類型的目標

引入不同類型的目標,每種目標有不同的分數和效果。例如:

  • 普通目標:點擊後獲得基本分數。
  • 加分目標:點擊後獲得額外分數。
  • 減分目標:點擊後扣除分數。
  • 時間目標:點擊後增加或減少剩餘時間。

3. 增加遊戲提示

在遊戲開始時顯示簡短的遊戲說明,讓玩家了解遊戲規則和目標。

4. 增加動畫效果

為目標增加一些動畫效果,例如淡入淡出、縮放等,讓遊戲更具視覺吸引力。

5. 增加排行榜

增加一個排行榜,顯示玩家的最高分數和全球最高分數,增加競爭性。

6. 增加音效和背景音樂

雖然你之前提到不需要音效,但適當的音效和背景音樂可以大大提升遊戲體驗。

7. 優化流程

  • 自動重新開始:在遊戲結束後自動重新開始,減少玩家的操作步驟。
  • 簡化按鈕操作:將「開始遊戲」和「暫停遊戲」按鈕合併為一個按鈕,根據遊戲狀態動態顯示。

8. 增加遊戲模式

引入不同的遊戲模式,例如:

  • 計時模式:在限定時間內獲得最高分數。
  • 無限模式:無時間限制,直到玩家失敗為止。

9. 增加成就系統

引入成就系統,玩家完成特定目標後可以獲得成就,增加遊戲的持久性和吸引力。

10. 增加社交分享

增加社交分享功能,讓玩家可以將自己的分數分享到社交媒體,吸引更多人參與遊戲。

這些點子可以幫助提升遊戲的體驗感和趣味性。你可以根據自己的需求和時間,選擇其中的一些進行實現。希望這些建議對你有幫助!

About me


之後應該會增加一個炫泡一點的About me頁面,現在先做個紀錄,讚讚。

假日


這個假日沒什麼規劃,洗洗睡囉。


上一篇
Day14 - 迷失
下一篇
Day16 - 狗
系列文
輕鬆搞笑與陪伴18
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言