原生JS面向对象如何实现打字小游戏

发布时间:2021-09-13 10:56:53 作者:柒染
来源:亿速云 阅读:163
# 原生JS面向对象如何实现打字小游戏

## 一、前言

在Web开发中,JavaScript作为核心语言,其面向对象编程(OOP)能力常被忽视。本文将使用原生JS面向对象技术,从零开始构建一个完整的打字小游戏。通过这个项目,您将掌握:

1. ES6类(class)的运用
2. 游戏状态管理
3. DOM操作优化
4. 动画与定时器控制
5. 键盘事件处理

## 二、项目结构与设计

### 2.1 游戏核心模块

```javascript
class TypingGame {
  constructor(config) {
    // 初始化游戏配置
    this.difficulty = config.difficulty || 'normal';
    this.timeLimit = config.timeLimit || 60;
    this.currentScore = 0;
    this.isPlaying = false;
    this.timer = null;
    this.wordsPool = [];
  }
  
  // 其他方法...
}

2.2 UML类图设计

┌───────────────────┐       ┌───────────────────┐
│    TypingGame     │       │     WordItem      │
├───────────────────┤       ├───────────────────┤
│ - difficulty      │       │ - word            │
│ - timeLimit       │       │ - speed           │
│ - currentScore    │       │ - position        │
│ - isPlaying       │       │ - element         │
│ - timer           │       ├───────────────────┤
│ - wordsPool       │       │ + move()          │
├───────────────────┤       │ + createElement() │
│ + startGame()     │       └───────────────────┘
│ + endGame()       │
│ + updateScore()   │
│ + generateWord()  │
└───────────────────┘

三、核心代码实现

3.1 单词生成模块

class WordItem {
  constructor(word, options) {
    this.word = word;
    this.speed = options.speed || 2;
    this.position = { x: 0, y: 0 };
    this.element = null;
    this.init();
  }

  init() {
    this.createElement();
    this.setInitialPosition();
  }

  createElement() {
    const wordEl = document.createElement('div');
    wordEl.className = 'word-item';
    wordEl.textContent = this.word;
    document.getElementById('game-area').appendChild(wordEl);
    this.element = wordEl;
  }

  setInitialPosition() {
    const gameArea = document.getElementById('game-area');
    this.position = {
      x: Math.random() * (gameArea.offsetWidth - 200),
      y: 0
    };
    this.updatePosition();
  }

  move() {
    this.position.y += this.speed;
    this.updatePosition();
    return this.position.y > document.getElementById('game-area').offsetHeight;
  }

  updatePosition() {
    this.element.style.transform = `translate(${this.position.x}px, ${this.position.y}px)`;
  }
}

3.2 游戏主逻辑

class TypingGame {
  // ...constructor...

  startGame() {
    if (this.isPlaying) return;
    
    this.isPlaying = true;
    this.currentScore = 0;
    this.updateScoreDisplay();
    
    // 初始化单词池
    this.initWordsPool();
    
    // 启动游戏循环
    this.gameLoop();
    
    // 设置倒计时
    this.startTimer();
    
    // 绑定键盘事件
    this.bindEvents();
  }

  gameLoop() {
    if (!this.isPlaying) return;
    
    // 随机生成新单词
    if (Math.random() < 0.03) {
      this.generateWord();
    }
    
    // 移动所有单词
    this.wordsPool.forEach((word, index) => {
      if (word.move()) {
        // 单词超出底部边界
        word.element.remove();
        this.wordsPool.splice(index, 1);
        this.updateScore(-10); // 扣分
      }
    });
    
    requestAnimationFrame(() => this.gameLoop());
  }

  generateWord() {
    const words = ['JavaScript', 'TypeScript', 'React', 'Vue', 'Angular', 
                  'Node.js', 'Webpack', 'ES6', 'Promise', 'Async'];
    const word = words[Math.floor(Math.random() * words.length)];
    const speed = this.difficulty === 'hard' ? 3 : 
                 this.difficulty === 'normal' ? 2 : 1;
    
    const newWord = new WordItem(word, { speed });
    this.wordsPool.push(newWord);
  }

  handleInput(inputWord) {
    let found = false;
    
    this.wordsPool.forEach((word, index) => {
      if (word.word === inputWord) {
        word.element.remove();
        this.wordsPool.splice(index, 1);
        this.updateScore(inputWord.length * 2); // 按长度计分
        found = true;
      }
    });
    
    return found;
  }
}

四、完整实现代码

4.1 HTML结构

<!DOCTYPE html>
<html lang="zh-CN">
<head>
  <meta charset="UTF-8">
  <title>JS打字游戏</title>
  <style>
    #game-container {
      width: 800px;
      height: 500px;
      margin: 0 auto;
      position: relative;
      border: 2px solid #333;
      overflow: hidden;
    }
    
    #game-area {
      width: 100%;
      height: 100%;
      background-color: #f0f0f0;
    }
    
    #game-ui {
      position: absolute;
      top: 10px;
      left: 10px;
      z-index: 100;
    }
    
    .word-item {
      position: absolute;
      font-size: 24px;
      color: #333;
      white-space: nowrap;
      transition: transform 0.1s linear;
    }
    
    #input-area {
      margin-top: 20px;
      text-align: center;
    }
    
    #word-input {
      padding: 8px;
      font-size: 16px;
    }
  </style>
</head>
<body>
  <div id="game-container">
    <div id="game-ui">
      <div>分数: <span id="score">0</span></div>
      <div>时间: <span id="time">60</span>秒</div>
    </div>
    <div id="game-area"></div>
  </div>
  
  <div id="input-area">
    <input type="text" id="word-input" placeholder="输入看到的单词...">
  </div>
  
  <script src="typing-game.js"></script>
</body>
</html>

4.2 JavaScript完整实现

// typing-game.js
class WordItem {
  constructor(word, options = {}) {
    this.word = word;
    this.speed = options.speed || 2;
    this.position = { x: 0, y: 0 };
    this.element = null;
    this.init();
  }

  init() {
    this.createElement();
    this.setInitialPosition();
  }

  createElement() {
    const wordEl = document.createElement('div');
    wordEl.className = 'word-item';
    wordEl.textContent = this.word;
    document.getElementById('game-area').appendChild(wordEl);
    this.element = wordEl;
  }

  setInitialPosition() {
    const gameArea = document.getElementById('game-area');
    this.position = {
      x: Math.random() * (gameArea.offsetWidth - 200),
      y: 0
    };
    this.updatePosition();
  }

  move() {
    this.position.y += this.speed;
    this.updatePosition();
    return this.position.y > document.getElementById('game-area').offsetHeight;
  }

  updatePosition() {
    this.element.style.transform = `translate(${this.position.x}px, ${this.position.y}px)`;
  }
}

class TypingGame {
  constructor(config) {
    this.config = {
      difficulty: 'normal',
      timeLimit: 60,
      ...config
    };
    
    this.currentScore = 0;
    this.isPlaying = false;
    this.timer = null;
    this.wordsPool = [];
    this.inputWord = '';
    
    this.init();
  }

  init() {
    this.bindEvents();
  }

  startGame() {
    if (this.isPlaying) return;
    
    this.isPlaying = true;
    this.currentScore = 0;
    this.updateScoreDisplay();
    
    // 清空现有单词
    this.clearWords();
    
    // 启动游戏循环
    this.gameLoop();
    
    // 设置倒计时
    this.startTimer();
  }

  endGame() {
    this.isPlaying = false;
    clearInterval(this.timer);
    this.timer = null;
    this.clearWords();
    
    alert(`游戏结束! 最终得分: ${this.currentScore}`);
  }

  clearWords() {
    this.wordsPool.forEach(word => word.element.remove());
    this.wordsPool = [];
  }

  gameLoop() {
    if (!this.isPlaying) return;
    
    // 随机生成新单词
    if (Math.random() < this.getSpawnRate()) {
      this.generateWord();
    }
    
    // 移动所有单词
    this.wordsPool.forEach((word, index) => {
      if (word.move()) {
        // 单词超出底部边界
        word.element.remove();
        this.wordsPool.splice(index, 1);
        this.updateScore(-10); // 扣分
      }
    });
    
    requestAnimationFrame(() => this.gameLoop());
  }

  getSpawnRate() {
    switch (this.config.difficulty) {
      case 'easy': return 0.02;
      case 'normal': return 0.03;
      case 'hard': return 0.05;
      default: return 0.03;
    }
  }

  generateWord() {
    const words = this.getWordList();
    const word = words[Math.floor(Math.random() * words.length)];
    const speed = this.getWordSpeed();
    
    const newWord = new WordItem(word, { speed });
    this.wordsPool.push(newWord);
  }

  getWordList() {
    return [
      'function', 'variable', 'constant', 'object', 'array',
      'string', 'number', 'boolean', 'null', 'undefined',
      'class', 'constructor', 'method', 'property', 'inheritance',
      'encapsulation', 'polymorphism', 'abstraction', 'interface',
      'prototype', 'closure', 'callback', 'promise', 'async',
      'await', 'module', 'import', 'export', 'spread',
      'destructuring', 'arrow', 'template', 'literal', 'generator',
      'iterator', 'symbol', 'proxy', 'reflect', 'set', 'map'
    ];
  }

  getWordSpeed() {
    switch (this.config.difficulty) {
      case 'easy': return 1;
      case 'normal': return 2;
      case 'hard': return 3;
      default: return 2;
    }
  }

  startTimer() {
    let timeLeft = this.config.timeLimit;
    document.getElementById('time').textContent = timeLeft;
    
    this.timer = setInterval(() => {
      timeLeft--;
      document.getElementById('time').textContent = timeLeft;
      
      if (timeLeft <= 0) {
        this.endGame();
      }
    }, 1000);
  }

  updateScore(points) {
    this.currentScore += points;
    if (this.currentScore < 0) this.currentScore = 0;
    this.updateScoreDisplay();
  }

  updateScoreDisplay() {
    document.getElementById('score').textContent = this.currentScore;
  }

  bindEvents() {
    const inputEl = document.getElementById('word-input');
    
    inputEl.addEventListener('keydown', (e) => {
      if (e.key === 'Enter') {
        this.handleInput(inputEl.value.trim());
        inputEl.value = '';
      }
    });
    
    // 开始游戏按钮
    document.getElementById('start-btn')?.addEventListener('click', () => {
      this.startGame();
      inputEl.focus();
    });
  }

  handleInput(inputWord) {
    if (!this.isPlaying || !inputWord) return;
    
    let found = false;
    
    // 从后往前查找,避免splice影响索引
    for (let i = this.wordsPool.length - 1; i >= 0; i--) {
      const word = this.wordsPool[i];
      if (word.word === inputWord) {
        word.element.remove();
        this.wordsPool.splice(i, 1);
        this.updateScore(inputWord.length * 2); // 按长度计分
        found = true;
        break; // 只匹配第一个找到的单词
      }
    }
    
    if (!found) {
      this.updateScore(-5); // 输入错误扣分
    }
  }
}

// 初始化游戏
const game = new TypingGame({
  difficulty: 'normal',
  timeLimit: 60
});

// 暴露全局变量便于测试
window.game = game;

五、功能扩展建议

  1. 多语言支持:增加不同语言的单词库
  2. 用户系统:保存最高分记录
  3. 音效系统:添加打字音效和背景音乐
  4. 动画效果:单词击中的爆炸效果
  5. 难度曲线:随游戏时间增加难度
  6. 多人模式:WebSocket实现对战功能

六、性能优化方案

  1. 对象池技术:复用DOM元素减少创建/销毁开销
  2. 节流处理:控制单词生成频率
  3. 离线DOM:使用DocumentFragment批量操作
  4. CSS硬件加速:使用transform代替top/left
  5. 事件委托:减少事件监听器数量

七、总结

通过这个打字游戏项目,我们实践了以下面向对象编程原则:

  1. 封装:将游戏逻辑封装在类中
  2. 单一职责:每个类只处理特定功能
  3. 开放封闭:易于扩展新功能而不修改现有代码

原生JS面向对象开发不仅能构建复杂应用,还能帮助开发者深入理解JavaScript语言特性。这种开发模式在大型项目中尤其重要,能显著提高代码的可维护性和可扩展性。 “`

推荐阅读:
  1. 原生js实现的金山打字小游戏(实例代码详解)
  2. 怎么使用原生JS实现贪吃蛇小游戏

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

js面向对象

上一篇:如何解决mysql客户端显示乱码的问题

下一篇:Kotlin中Android的Activity使用方法

相关阅读

您好,登录后才能下订单哦!

密码登录
登录注册
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》