首页 / 应用软件 / 实战教学,为你的网站添加在线迷你游戏以提升用户互动与留存

实战教学,为你的网站添加在线迷你游戏以提升用户互动与留存

实战教学:为你的WordPress网站添加在线迷你游戏以提升用户互动与留存

引言:为什么网站需要迷你游戏?

在当今互联网环境中,用户注意力已成为最稀缺的资源之一。网站运营者面临着一个共同的挑战:如何让访客停留更长时间,提高用户参与度,并最终实现转化率的提升?传统的内容展示方式已难以满足现代用户的需求,而互动元素的加入正成为解决这一问题的有效途径。

在线迷你游戏作为一种轻量级互动形式,具有以下优势:

  • 提升用户停留时间:有趣的游戏体验能有效延长用户在网站的停留时间
  • 增强品牌记忆:通过游戏化体验加深用户对品牌的印象
  • 促进社交分享:用户乐于分享游戏成绩和体验,带来自然流量
  • 收集用户数据:游戏过程中可以收集有价值的用户行为数据
  • 提高转化率:游戏化元素可以作为引导用户完成特定动作的有效手段

本文将详细介绍如何通过WordPress代码二次开发,为你的网站添加实用的在线迷你游戏和小工具功能,从而显著提升用户互动与留存率。

第一部分:准备工作与环境搭建

1.1 选择合适的开发环境

在开始开发之前,确保你拥有以下环境:

  1. 本地开发环境:推荐使用XAMPP、MAMP或Local by Flywheel
  2. WordPress安装:最新版本的WordPress(建议5.8以上)
  3. 代码编辑器:VS Code、Sublime Text或PHPStorm
  4. 浏览器开发者工具:用于调试JavaScript和CSS

1.2 创建子主题保护核心文件

为了避免主题更新导致自定义代码丢失,我们首先创建一个子主题:

/*
Theme Name: 我的游戏化子主题
Template: twentytwentythree
Version: 1.0
Description: 为网站添加迷你游戏功能的子主题
*/

// 引入父主题样式表
add_action('wp_enqueue_scripts', 'my_gamification_theme_enqueue_styles');
function my_gamification_theme_enqueue_styles() {
    wp_enqueue_style('parent-style', get_template_directory_uri() . '/style.css');
    wp_enqueue_style('child-style', get_stylesheet_directory_uri() . '/style.css', array('parent-style'));
}

1.3 创建必要的目录结构

在你的子主题目录中创建以下文件夹结构:

/my-gamification-theme/
├── games/
│   ├── js/
│   ├── css/
│   └── assets/
├── includes/
├── templates/
└── functions.php

第二部分:实现经典记忆配对游戏

2.1 游戏设计与功能规划

记忆配对游戏是一种简单但有效的互动游戏,适合各种类型的网站。我们将实现以下功能:

  • 可配置的卡片数量(4x4、4x5、5x6等)
  • 计时器和步数计数器
  • 得分系统
  • 社交分享功能
  • 保存最高分记录

2.2 创建游戏短代码

在functions.php中添加短代码,使游戏可以轻松插入到任何文章或页面中:

// 注册记忆游戏短代码
add_shortcode('memory_game', 'memory_game_shortcode');
function memory_game_shortcode($atts) {
    // 短代码属性
    $atts = shortcode_atts(
        array(
            'columns' => 4,
            'rows' => 4,
            'theme' => 'default'
        ),
        $atts,
        'memory_game'
    );
    
    // 生成唯一游戏ID
    $game_id = 'memory_game_' . uniqid();
    
    // 输出游戏容器
    ob_start();
    ?>
    <div id="<?php echo esc_attr($game_id); ?>" class="memory-game-container" 
         data-columns="<?php echo esc_attr($atts['columns']); ?>"
         data-rows="<?php echo esc_attr($atts['rows']); ?>"
         data-theme="<?php echo esc_attr($atts['theme']); ?>">
        
        <div class="game-controls">
            <div class="game-stats">
                <span class="timer">时间: <span class="time-value">00:00</span></span>
                <span class="moves">步数: <span class="moves-value">0</span></span>
                <span class="score">得分: <span class="score-value">0</span></span>
            </div>
            <div class="game-buttons">
                <button class="restart-game">重新开始</button>
                <button class="pause-game">暂停</button>
            </div>
        </div>
        
        <div class="game-board"></div>
        
        <div class="game-result" style="display:none;">
            <h3>游戏结束!</h3>
            <p>你的得分: <span class="final-score">0</span></p>
            <p>用时: <span class="final-time">00:00</span></p>
            <p>步数: <span class="final-moves">0</span></p>
            <button class="play-again">再玩一次</button>
            <button class="share-score">分享成绩</button>
        </div>
    </div>
    <?php
    
    return ob_get_clean();
}

2.3 实现游戏JavaScript逻辑

创建 /games/js/memory-game.js 文件:

class MemoryGame {
    constructor(containerId) {
        this.container = document.getElementById(containerId);
        this.columns = parseInt(this.container.dataset.columns) || 4;
        this.rows = parseInt(this.container.dataset.rows) || 4;
        this.theme = this.container.dataset.theme || 'default';
        
        this.totalPairs = (this.columns * this.rows) / 2;
        this.cards = [];
        this.flippedCards = [];
        this.matchedPairs = 0;
        this.moves = 0;
        this.score = 0;
        this.gameStarted = false;
        this.gamePaused = false;
        this.startTime = null;
        this.timerInterval = null;
        this.elapsedTime = 0;
        
        this.init();
    }
    
    init() {
        this.createCards();
        this.renderBoard();
        this.setupEventListeners();
        this.updateStats();
    }
    
    createCards() {
        // 创建卡片对
        const symbols = ['★', '❤', '♦', '♠', '♣', '☀', '☁', '☂', '☃', '♫', '⚓', '✈'];
        const usedSymbols = symbols.slice(0, this.totalPairs);
        
        // 每对卡片重复一次
        let cardValues = [...usedSymbols, ...usedSymbols];
        
        // 随机排序
        cardValues = this.shuffleArray(cardValues);
        
        // 创建卡片对象
        this.cards = cardValues.map((value, index) => ({
            id: index,
            value: value,
            flipped: false,
            matched: false
        }));
    }
    
    shuffleArray(array) {
        for (let i = array.length - 1; i > 0; i--) {
            const j = Math.floor(Math.random() * (i + 1));
            [array[i], array[j]] = [array[j], array[i]];
        }
        return array;
    }
    
    renderBoard() {
        const board = this.container.querySelector('.game-board');
        board.innerHTML = '';
        
        // 设置网格布局
        board.style.gridTemplateColumns = `repeat(${this.columns}, 1fr)`;
        board.style.gridTemplateRows = `repeat(${this.rows}, 1fr)`;
        
        // 创建卡片元素
        this.cards.forEach(card => {
            const cardElement = document.createElement('div');
            cardElement.className = 'memory-card';
            cardElement.dataset.id = card.id;
            
            const frontFace = document.createElement('div');
            frontFace.className = 'card-front';
            frontFace.textContent = card.value;
            
            const backFace = document.createElement('div');
            backFace.className = 'card-back';
            backFace.textContent = '?';
            
            cardElement.appendChild(frontFace);
            cardElement.appendChild(backFace);
            
            board.appendChild(cardElement);
        });
    }
    
    setupEventListeners() {
        // 卡片点击事件
        this.container.addEventListener('click', (e) => {
            const cardElement = e.target.closest('.memory-card');
            if (!cardElement || this.gamePaused) return;
            
            const cardId = parseInt(cardElement.dataset.id);
            this.flipCard(cardId);
        });
        
        // 重新开始按钮
        const restartBtn = this.container.querySelector('.restart-game');
        restartBtn.addEventListener('click', () => this.restartGame());
        
        // 暂停按钮
        const pauseBtn = this.container.querySelector('.pause-game');
        pauseBtn.addEventListener('click', () => this.togglePause());
        
        // 再玩一次按钮
        const playAgainBtn = this.container.querySelector('.play-again');
        if (playAgainBtn) {
            playAgainBtn.addEventListener('click', () => this.restartGame());
        }
        
        // 分享按钮
        const shareBtn = this.container.querySelector('.share-score');
        if (shareBtn) {
            shareBtn.addEventListener('click', () => this.shareScore());
        }
    }
    
    flipCard(cardId) {
        // 如果游戏未开始,开始计时
        if (!this.gameStarted) {
            this.startGame();
        }
        
        const card = this.cards.find(c => c.id === cardId);
        
        // 如果卡片已匹配或已翻转,忽略点击
        if (card.matched || card.flipped || this.flippedCards.length >= 2) {
            return;
        }
        
        // 翻转卡片
        card.flipped = true;
        this.flippedCards.push(card);
        
        // 更新UI
        this.updateCardUI(cardId);
        
        // 如果翻转了两张卡片,检查是否匹配
        if (this.flippedCards.length === 2) {
            this.moves++;
            this.updateStats();
            
            const [card1, card2] = this.flippedCards;
            
            if (card1.value === card2.value) {
                // 匹配成功
                card1.matched = true;
                card2.matched = true;
                this.matchedPairs++;
                this.score += 100;
                
                // 更新分数
                this.updateStats();
                
                // 清空翻转卡片数组
                this.flippedCards = [];
                
                // 检查游戏是否结束
                if (this.matchedPairs === this.totalPairs) {
                    this.endGame();
                }
            } else {
                // 不匹配,稍后翻转回来
                setTimeout(() => {
                    card1.flipped = false;
                    card2.flipped = false;
                    this.flippedCards = [];
                    
                    this.updateCardUI(card1.id);
                    this.updateCardUI(card2.id);
                }, 1000);
            }
        }
    }
    
    updateCardUI(cardId) {
        const cardElement = this.container.querySelector(`[data-id="${cardId}"]`);
        const card = this.cards.find(c => c.id === cardId);
        
        if (card.flipped || card.matched) {
            cardElement.classList.add('flipped');
        } else {
            cardElement.classList.remove('flipped');
        }
    }
    
    startGame() {
        this.gameStarted = true;
        this.startTime = Date.now();
        
        // 开始计时器
        this.timerInterval = setInterval(() => {
            if (!this.gamePaused) {
                this.elapsedTime = Date.now() - this.startTime;
                this.updateStats();
            }
        }, 1000);
    }
    
    togglePause() {
        this.gamePaused = !this.gamePaused;
        const pauseBtn = this.container.querySelector('.pause-game');
        
        if (this.gamePaused) {
            pauseBtn.textContent = '继续';
        } else {
            pauseBtn.textContent = '暂停';
            
            // 如果游戏暂停后继续,调整开始时间
            if (this.gameStarted) {
                this.startTime = Date.now() - this.elapsedTime;
            }
        }
    }
    
    updateStats() {
        // 更新时间显示
        const timeElement = this.container.querySelector('.time-value');
        const minutes = Math.floor(this.elapsedTime / 60000);
        const seconds = Math.floor((this.elapsedTime % 60000) / 1000);
        timeElement.textContent = `${minutes.toString().padStart(2, '0')}:${seconds.toString().padStart(2, '0')}`;
        
        // 更新步数
        const movesElement = this.container.querySelector('.moves-value');
        movesElement.textContent = this.moves;
        
        // 更新分数
        const scoreElement = this.container.querySelector('.score-value');
        scoreElement.textContent = this.score;
    }
    
    endGame() {
        clearInterval(this.timerInterval);
        
        // 计算最终得分(考虑时间和步数)
        const timeBonus = Math.max(0, 300 - Math.floor(this.elapsedTime / 1000)) * 10;
        const movesBonus = Math.max(0, 50 - this.moves) * 5;
        this.score += timeBonus + movesBonus;
        
        // 显示结果
        const resultElement = this.container.querySelector('.game-result');
        resultElement.querySelector('.final-score').textContent = this.score;
        resultElement.querySelector('.final-time').textContent = 
            this.container.querySelector('.time-value').textContent;
        resultElement.querySelector('.final-moves').textContent = this.moves;
        
        resultElement.style.display = 'block';
        
        // 保存最高分到本地存储
        this.saveHighScore();
    }
    
    saveHighScore() {
        const highScores = JSON.parse(localStorage.getItem('memoryGameHighScores') || '[]');
        
        highScores.push({
            score: this.score,
            time: this.elapsedTime,
            moves: this.moves,
            date: new Date().toISOString(),
            grid: `${this.columns}x${this.rows}`
        });
        
        // 按分数排序,只保留前10名
        highScores.sort((a, b) => b.score - a.score);
        const topScores = highScores.slice(0, 10);
        
        localStorage.setItem('memoryGameHighScores', JSON.stringify(topScores));
    }
    
    shareScore() {
        const text = `我在记忆配对游戏中获得了${this.score}分!用时${this.container.querySelector('.time-value').textContent},用了${this.moves}步。`;
        
        if (navigator.share) {
            navigator.share({
                title: '我的游戏成绩',
                text: text,
                url: window.location.href
            });
        } else {
            // 备用方案:复制到剪贴板
            navigator.clipboard.writeText(text).then(() => {
                alert('成绩已复制到剪贴板,快去分享吧!');
            });
        }
    }
    
    restartGame() {
        // 重置游戏状态
        this.matchedPairs = 0;
        this.moves = 0;
        this.score = 0;
        this.gameStarted = false;
        this.gamePaused = false;
        this.flippedCards = [];
        this.elapsedTime = 0;
        
        clearInterval(this.timerInterval);
        
        // 重新创建卡片
        this.createCards();
        this.renderBoard();
        
        // 隐藏结果
        const resultElement = this.container.querySelector('.game-result');
        resultElement.style.display = 'none';
        
        // 更新统计
        this.updateStats();
    }
}

// 初始化所有记忆游戏实例
document.addEventListener('DOMContentLoaded', () => {
    document.querySelectorAll('.memory-game-container').forEach(container => {
        new MemoryGame(container.id);
    });
});

2.4 添加游戏样式

创建 /games/css/memory-game.css 文件:

.memory-game-container {
    max-width: 800px;
    margin: 20px auto;
    padding: 20px;
    background: linear-gradient(135deg, #6a11cb 0%, #2575fc 100%);
    border-radius: 15px;
    box-shadow: 0 10px 30px rgba(0, 0, 0, 0.3);
    color: white;
    font-family: 'Arial', sans-serif;
}

.game-controls {
    display: flex;
    justify-content: space-between;
    align-items: center;
    margin-bottom: 20px;
    padding: 15px;
    background: rgba(255, 255, 255, 0.1);
    border-radius: 10px;
    flex-wrap: wrap;
}

.game-stats {
    display: flex;
    gap: 20px;
    font-size: 18px;
    font-weight: bold;
}

.game-stats span {
    background: rgba(0, 0, 0, 0.2);
    padding: 8px 15px;
    border-radius: 5px;
}

.game-buttons {
    display: flex;
    gap: 10px;
}

.game-buttons button {
    padding: 10px 20px;
    border: none;
    border-radius: 5px;
    background: #4CAF50;
    color: white;
    font-weight: bold;
    cursor: pointer;
    transition: all 0.3s ease;
}

.game-buttons button:hover {
    background: #45a049;
    transform: translateY(-2px);
}

.game-buttons .pause-game {
    background: #ff9800;
}

.game-buttons .pause-game:hover {
    background: #e68900;
}

.game-board {
    display: grid;
    gap: 10px;
    margin: 20px 0;
    perspective: 1000px;
}

.memory-card {
    height: 100px;
    position: relative;
    transform-style: preserve-3d;
    transition: transform 0.6s;
    cursor: pointer;
    border-radius: 10px;
    box-shadow: 0 4px 8px rgba(0, 0, 0, 0.2);
}

.memory-card.flipped {
    transform: rotateY(180deg);
}

.memory-card .card-front,
.memory-card .card-back {
    position: absolute;
    width: 100%;
    height: 100%;
    border-radius: 10px;
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: 2em;
    font-weight: bold;
}

.memory-card .card-back {
    background: linear-gradient(45deg, #2196F3, #21CBF3);
    color: white;
    transform: rotateY(0deg);
}

.memory-card .card-front {
    background: linear-gradient(45deg, #FF9800, #FFC107);
    color: white;
    transform: rotateY(180deg);
}

.memory-card.matched .card-front {
    background: linear-gradient(45deg, #4CAF50, #8BC34A);
}

.game-result {
    text-align: center;
    padding: 30px;
    background: rgba(255, 255, 255, 0.1);
    border-radius: 10px;
    margin-top: 20px;
    animation: fadeIn 0.5s ease;
}

.game-result h3 {
    font-size: 28px;
    margin-bottom: 20px;
    color: #FFEB3B;
}

.game-result p {
    font-size: 18px;
    margin: 10px 0;
}

.game-result button {
    margin: 10px;
    padding: 12px 25px;
    border: none;
    border-radius: 5px;
    font-size: 16px;
    font-weight: bold;
    cursor: pointer;
    transition: all 0.3s ease;
}

.game-result .play-again {
    background: #4CAF50;
    color: white;
}

.game-result .share-score {
    background: #2196F3;
    color: white;
}

.game-result button:hover {
    transform: translateY(-3px);
    box-shadow: 0 5px 15px rgba(0, 0, 0, 0.3);
}

@keyframes fadeIn {
    from { opacity: 0; transform: translateY(20px); }
    to { opacity: 1; transform: translateY(0); }
}

/* 响应式设计 */
@media (max-width: 768px) {
    .game-controls {
        flex-direction: column;
        gap: 15px;
    }
    
    .game-stats {
        flex-wrap: wrap;
        justify-content: center;
    }
    
    .memory-card {
        height: 80px;
    }
}

@media (max-width: 480px) {
    .memory-card {
        height: 60px;
    }
    
    .memory-card .card-front,
    .memory-card .card-back {
        font-size: 1.5em;
    }
}

2.5 在WordPress中注册游戏资源

在functions.php中添加以下代码,确保游戏脚本和样式正确加载:

// 注册并加载记忆游戏资源
add_action('wp_enqueue_scripts', 'register_memory_game_assets');
function register_memory_game_assets() {
    // 只在需要时加载游戏资源
    global $post;
    if (is_a($post, 'WP_Post') && has_shortcode($post->post_content, 'memory_game')) {
        // 游戏样式
        wp_enqueue_style(
            'memory-game-css',
            get_stylesheet_directory_uri() . '/games/css/memory-game.css',
            array(),
            '1.0.0'
        );
        
        // 游戏脚本
        wp_enqueue_script(
            'memory-game-js',
            get_stylesheet_directory_uri() . '/games/js/memory-game.js',
            array(),
            '1.0.0',
            true
        );
    }
}

第三部分:创建简易抽奖转盘游戏

3.1 转盘游戏设计与实现

抽奖转盘是另一种受欢迎的互动形式,特别适合电商网站和营销活动。我们将创建一个可配置的转盘游戏:

// 注册转盘游戏短代码
add_shortcode('wheel_of_fortune', 'wheel_of_fortune_shortcode');
function wheel_of_fortune_shortcode($atts) {
    $atts = shortcode_atts(
        array(
            'segments' => '优惠券10%,谢谢参与,优惠券20%,再来一次,折扣30%,幸运奖,优惠券15%,大奖',
            'colors' => '#FF6384,#36A2EB,#FFCE56,#4BC0C0,#9966FF,#FF9F40,#FF6384,#36A2EB',
            'prize_text' => '恭喜您获得:',
            'button_text' => '开始抽奖'
        ),
        $atts,
        'wheel_of_fortune'
    );
    
    $game_id = 'wheel_game_' . uniqid();
    $segments = explode(',', $atts['segments']);
    $colors = explode(',', $atts['colors']);
    
    ob_start();
    ?>
    <div id="<?php echo esc_attr($game_id); ?>" class="wheel-game-container">
        <div class="wheel-header">
            <h3>幸运大转盘</h3>
            <p>试试你的运气,赢取惊喜奖励!</p>
        </div>
        
        <div class="wheel-content">
            <div class="wheel-wrapper">
                <canvas id="<?php echo esc_attr($game_id); ?>_canvas" class="wheel-canvas" 
                        width="400" height="400"></canvas>
                <div class="wheel-pointer"></div>
            </div>
            
            <div class="wheel-controls">
                <div class="wheel-stats">
                    <p>剩余抽奖次数: <span class="spins-left">3</span></p>
                    <p class="prize-result"></p>
                </div>
                
                <button class="spin-button"><?php echo esc_html($atts['button_text']); ?></button>
                <button class="reset-spins">重置次数</button>
                
                <div class="wheel-segments">
                    <h4>奖项设置:</h4>
                    <ul>
                        <?php foreach ($segments as $index => $segment): ?>
                        <li>
                            <span class="segment-color" style="background-color: <?php echo esc_attr($colors[$index % count($colors)]); ?>"></span>
                            <?php echo esc_html($segment); ?>
                        </li>
                        <?php endforeach; ?>
                    </ul>
                </div>
            </div>
        </div>
        
        <div class="wheel-history">
            <h4>中奖记录</h4>
            <ul class="history-list"></ul>
        </div>
    </div>
    
    <script type="text/javascript">
    document.addEventListener('DOMContentLoaded', function() {
        new WheelOfFortune(
            '<?php echo esc_js($game_id); ?>',
            <?php echo json_encode($segments); ?>,
            <?php echo json_encode($colors); ?>,
            '<?php echo esc_js($atts['prize_text']); ?>'
        );
    });
    </script>
    <?php
    
    return ob_get_clean();
}

3.2 转盘游戏JavaScript实现

创建 /games/js/wheel-game.js 文件:

class WheelOfFortune {
    constructor(containerId, segments, colors, prizeText) {
        this.container = document.getElementById(containerId);
        this.canvas = this.container.querySelector('.wheel-canvas');
        this.ctx = this.canvas.getContext('2d');
        this.spinButton = this.container.querySelector('.spin-button');
        this.resetButton = this.container.querySelector('.reset-spins');
        this.prizeResult = this.container.querySelector('.prize-result');
        this.spinsLeftElement = this.container.querySelector('.spins-left');
        this.historyList = this.container.querySelector('.history-list');
        
        this.segments = segments;
        this.colors = colors;
        this.prizeText = prizeText;
        
        // 游戏状态
        this.spinsLeft = 3;
        this.isSpinning = false;
        this.currentRotation = 0;
        this.segmentAngle = (2 * Math.PI) / this.segments.length;
        
        this.init();
    }
    
    init() {
        this.drawWheel();
        this.setupEventListeners();
        this.updateSpinsDisplay();
        this.loadHistory();
    }
    
    drawWheel() {
        const centerX = this.canvas.width / 2;
        const centerY = this.canvas.height / 2;
        const radius = Math.min(centerX, centerY) - 10;
        
        // 清除画布
        this.ctx.clearRect(0, 0, this.canvas.width, this.canvas.height);
        
        // 绘制每个扇形
        for (let i = 0; i < this.segments.length; i++) {
            const startAngle = this.currentRotation + (i * this.segmentAngle);
            const endAngle = startAngle + this.segmentAngle;
            
            // 绘制扇形
            this.ctx.beginPath();
            this.ctx.moveTo(centerX, centerY);
            this.ctx.arc(centerX, centerY, radius, startAngle, endAngle);
            this.ctx.closePath();
            
            // 填充颜色
            this.ctx.fillStyle = this.colors[i % this.colors.length];
            this.ctx.fill();
            
            // 绘制边框
            this.ctx.strokeStyle = '#FFFFFF';
            this.ctx.lineWidth = 2;
            this.ctx.stroke();
            
            // 绘制文本
            this.ctx.save();
            this.ctx.translate(centerX, centerY);
            this.ctx.rotate(startAngle + this.segmentAngle / 2);
            this.ctx.textAlign = 'right';
            this.ctx.fillStyle = '#FFFFFF';
            this.ctx.font = 'bold 14px Arial';
            this.ctx.fillText(this.segments[i], radius - 20, 5);
            this.ctx.restore();
        }
        
        // 绘制中心圆
        this.ctx.beginPath();
        this.ctx.arc(centerX, centerY, 20, 0, 2 * Math.PI);
        this.ctx.fillStyle = '#333333';
        this.ctx.fill();
        this.ctx.strokeStyle = '#FFFFFF';
        this.ctx.lineWidth = 3;
        this.ctx.stroke();
    }
    
    setupEventListeners() {
        this.spinButton.addEventListener('click', () => this.spinWheel());
        this.resetButton.addEventListener('click', () => this.resetSpins());
    }
    
    spinWheel() {
        if (this.isSpinning || this.spinsLeft <= 0) return;
        
        this.isSpinning = true;
        this.spinsLeft--;
        this.updateSpinsDisplay();
        
        // 随机决定停止位置
        const spinDuration = 3000 + Math.random() * 2000; // 3-5秒
        const extraRotation = 5 + Math.random() * 5; // 额外旋转5-10圈
        const totalRotation = (extraRotation * 2 * Math.PI) + (Math.random() * this.segmentAngle);
        
        // 动画开始时间
        const startTime = Date.now();
        
        const animate = () => {
            const elapsed = Date.now() - startTime;
            const progress = Math.min(elapsed / spinDuration, 1);
            
            // 缓动函数:先快后慢
            const easeOut = 1 - Math.pow(1 - progress, 3);
            
            // 更新旋转角度
            this.currentRotation = easeOut * totalRotation;
            this.drawWheel();
            
            if (progress < 1) {
                requestAnimationFrame(animate);
            } else {
                // 动画结束
                this.isSpinning = false;
                this.determinePrize();
            }
        };
        
        animate();
    }
    
    determinePrize() {
        // 计算指针指向的扇形
        const normalizedRotation = this.currentRotation % (2 * Math.PI);
        const segmentIndex = Math.floor(
            ((2 * Math.PI - normalizedRotation) % (2 * Math.PI)) / this.segmentAngle
        );
        
        const prize = this.segments[segmentIndex];
        
        // 显示结果
        this.prizeResult.textContent = `${this.prizeText} ${prize}`;
        this.prizeResult.style.color = this.colors[segmentIndex % this.colors.length];
        
        // 添加到历史记录
        this.addToHistory(prize);
        
        // 保存到本地存储
        this.saveHistory(prize);
        
        // 如果是"再来一次",增加一次抽奖机会
        if (prize === '再来一次') {
            this.spinsLeft++;
            this.updateSpinsDisplay();
        }
    }
    
    addToHistory(prize) {
        const now = new Date();
        const timeString = now.toLocaleTimeString([], {hour: '2-digit', minute:'2-digit'});
        
        const historyItem = document.createElement('li');
        historyItem.innerHTML = `
            <span class="history-time">${timeString}</span>
            <span class="history-prize">${prize}</span>
        `;
        
        this.historyList.insertBefore(historyItem, this.historyList.firstChild);
        
        // 限制历史记录数量
        if (this.historyList.children.length > 10) {
            this.historyList.removeChild(this.historyList.lastChild);
        }
    }
    
    saveHistory(prize) {
        const history = JSON.parse(localStorage.getItem('wheelGameHistory') || '[]');
        history.unshift({
            prize: prize,
            timestamp: new Date().toISOString()
        });
        
        // 只保留最近20条记录
        const recentHistory = history.slice(0, 20);
        localStorage.setItem('wheelGameHistory', JSON.stringify(recentHistory));
    }
    
    loadHistory() {
        const history = JSON.parse(localStorage.getItem('wheelGameHistory') || '[]');
        
        history.forEach(item => {
            const date = new Date(item.timestamp);
            const timeString = date.toLocaleTimeString([], {hour: '2-digit', minute:'2-digit'});
            
            const historyItem = document.createElement('li');
            historyItem.innerHTML = `
                <span class="history-time">${timeString}</span>
                <span class="history-prize">${item.prize}</span>
            `;
            
            this.historyList.appendChild(historyItem);
        });
    }
    
    updateSpinsDisplay() {
        this.spinsLeftElement.textContent = this.spinsLeft;
        
        if (this.spinsLeft <= 0) {
            this.spinButton.disabled = true;
            this.spinButton.textContent = '次数已用完';
        } else {
            this.spinButton.disabled = false;
            this.spinButton.textContent = '开始抽奖';
        }
    }
    
    resetSpins() {
        this.spinsLeft = 3;
        this.updateSpinsDisplay();
        this.prizeResult.textContent = '';
    }
}

3.3 转盘游戏样式设计

创建 /games/css/wheel-game.css 文件:

.wheel-game-container {
    max-width: 900px;
    margin: 30px auto;
    padding: 25px;
    background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
    border-radius: 20px;
    box-shadow: 0 15px 35px rgba(0, 0, 0, 0.2);
    color: white;
    font-family: 'Arial', sans-serif;
}

.wheel-header {
    text-align: center;
    margin-bottom: 30px;
}

.wheel-header h3 {
    font-size: 32px;
    margin-bottom: 10px;
    color: #FFD700;
    text-shadow: 2px 2px 4px rgba(0, 0, 0, 0.3);
}

.wheel-header p {
    font-size: 18px;
    opacity: 0.9;
}

.wheel-content {
    display: flex;
    flex-wrap: wrap;
    gap: 40px;
    align-items: center;
    justify-content: center;
}

.wheel-wrapper {
    position: relative;
    flex: 0 0 auto;
}

.wheel-canvas {
    background: white;
    border-radius: 50%;
    box-shadow: 0 10px 30px rgba(0, 0, 0, 0.3);
    border: 8px solid #FFD700;
}

.wheel-pointer {
    position: absolute;
    top: -20px;
    left: 50%;
    transform: translateX(-50%);
    width: 0;
    height: 0;
    border-left: 20px solid transparent;
    border-right: 20px solid transparent;
    border-top: 40px solid #FF0000;
    filter: drop-shadow(0 5px 5px rgba(0, 0, 0, 0.3));
    z-index: 10;
}

.wheel-controls {
    flex: 1;
    min-width: 300px;
    background: rgba(255, 255, 255, 0.1);
    padding: 25px;
    border-radius: 15px;
    backdrop-filter: blur(10px);
}

.wheel-stats {
    margin-bottom: 25px;
    padding: 15px;
    background: rgba(0, 0, 0, 0.2);
    border-radius: 10px;
}

.wheel-stats p {
    font-size: 18px;
    margin: 10px 0;
}

.prize-result {
    font-size: 22px !important;
    font-weight: bold;
    color: #FFD700 !important;
    min-height: 30px;
    margin-top: 15px !important;
}

.wheel-controls button {
    display: block;
    width: 100%;
    padding: 15px;
    margin: 10px 0;
    border: none;
    border-radius: 8px;
    font-size: 18px;
    font-weight: bold;
    cursor: pointer;
    transition: all 0.3s ease;
}

.spin-button {
    background: linear-gradient(45deg, #FF416C, #FF4B2B);
    color: white;
}

.spin-button:hover:not(:disabled) {
    transform: translateY(-3px);
本文来自网络,不代表柔性供应链服务中心立场,转载请注明出处:https://mall.org.cn/5228.html

EXCHANGES®作者

上一篇
下一篇

为您推荐

发表回复

联系我们

联系我们

18559313275

在线咨询: QQ交谈

邮箱: vip@exchanges.center

工作时间:周一至周五,9:00-17:30,节假日休息
返回顶部