原生JS实现Flappy Bird小游戏(本地化存储)

本文详细介绍了使用HTML5、JavaScript和WebStorage开发一款简单的H5小游戏的过程,包括创建随机高度的柱子、实现柱子的移动、碰撞检测、本地存储成绩及成绩展示等功能。


源码地址
展示地址

1.准备

该游戏主要涉及的知识:

  • JavaScript基础
  • ES6基础(模板字符串,箭头函数,模块化)
  • H5 Web Storage知识
2.难点
(1)、创建柱子

由于两根柱子之间的距离是150,柱子的最小长度为50,页面的大小为600,(600-150)/2 = 225, 因此柱子的长度范围为50-275.通过Math.random函数来实现随机生成长度不同的柱子。
createEle()函数用来创建元素,在创建的同时可以给元素添加相应的样式。
创建完元素以后使用appendChild将元素插入页面。并且将柱子的信息保存下来,方便在后面实现柱子的移动的时候使用。

/**
   * 创建柱子
   * @param {*设置柱子的left值} x 
   */
  createPipe: function(x){
   
   
    var upHeight = 50 + Math.floor(Math.random() * 175);
    var downHeight = 600 - 150 -upHeight;
    // 创建上柱子
    var oUpPipe = createEle('div', ['pipe', 'pipe-up'],{
   
   
      height: upHeight + 'px',
      left: x + 'px'
    });
    // 创建下柱子
    var oDownPipe = createEle('div', ['pipe', 'pipe-bottom'],{
   
   
      height: downHeight + 'px',
      left: x + 'px'
    });
    // 将柱子插入页面
    this.el.appendChild(oUpPipe);
    this.el.appendChild(oDownPipe);
    // 保存柱子的信息
    this.pipeArr.push({
   
   
      up: oUpPipe,
      down: oDownPipe,
      y: [upHeight, upHeight+150]
    })
  },
/**
 * 创建元素
 * @param {*} eleName 
 * @param {*} classArr 
 * @param {*} styleObj 
 */
export function createEle(eleName, classArr, styleObj){
   
   
  let dom = document.createElement(eleName);
  for(let i = 0; i < classArr.length; i++){
   
   
    dom.classList.add(classArr[i]);
  }
  for(let key in styleObj){
   
   
    dom.style[key] = styleObj[key];
  }
  return dom;
}
(2)、柱子移动

柱子移动:我们通过在创建柱子的时候保存的柱子的信息,通过对应信息得到柱子的偏移量然后通过改变left值来实现柱子的移动。
由于一开始我们只设置了7对柱子,因此在移动过程中要实现柱子的循环,当X<52的时候,表示柱子已经看不到了,这时候,我们拿到最后一个柱子的偏移值,加上300(两个柱子之间的距离是300)得到当前柱子的新的位置。
每轮循环的时候为了使创建的柱子的高度不是重复的,在这里我们调用getPipeHeight重新设置柱子的高度

 /**
   * 柱子移动,通过在创建柱子的时候保存柱子的信息,然后改变柱子的left值实现柱子的移动
   */
  pipeMove: function(){
   
   
    for(let i = 0; i < this.pipeLength; i++){
   
   
      let oUpPipe = this.pipeArr[i].up;
      let oDownPipe = this.pipeArr[i].down;
      let x = oUpPipe.offsetLeft - this.skyStep;
      // 因为柱子的width是52
      if(x < -52){
   
   
        let lastPipeLeft = this.pipeArr[this.pipeLastIndex].up.offsetLeft;
        oUpPipe.style.left = lastPipeLeft + 300 + 'px';
        oDownPipe.style.left = lastPipeLeft + 300 + 'px';
        // 由于是一个循环,每次拿到最后一个柱子的时候,pipeLastIndex应该改变
        this.pipeLastIndex ++;
        this.pipeLastIndex = this.pipeLastIndex % this.pipeLength;
        // 为了使每一轮循环的柱子的高度是不同的,我们在这里调用getPipeHeight重新设置柱子的高度
        var newPipeHeight = this.getPipeHeight();
        // console.log(result);
        oUpPipe.style.height = newPipeHeight.up + 'px';
        oDownPipe.style.height = newPipeHeight.down + 'px';
        continue;
      }
      oUpPipe.style.left = x + 'px';
      oDownPipe.style.left = x + 'px';
    }
  },
 /**
   * 获取柱子的高度
   */
  getPipeHeight: function(){
   
   
    var upHieght = 50+ Math.floor(Math.random() * 175);
    var downHeight = 600 - 150 - upHieght;
    return {
   
   
      up: upHieght,
      down: downHeight
    }
  },
(3)、碰撞检测

边界碰撞检测
当小鸟的top值大于maxTop或者小于minTop时游戏结束

 /**
   * 边界碰撞检测
   */
  judgeBoundary: function(){
   
   
    if(this.birdTop > this.maxTop || this.birdTop < this.minTop){
   
   
      this.failGame();  //游戏结束
    }
  },

柱子碰撞检测
难点在于如果获取是哪一根柱子
因为柱子是和分数相关联的,因此我们可以通过分数来得到柱子的信息。
由于柱子是由7个循环来的,因此分数需要this.score % this.pipeLength
柱子和小鸟相遇时的图示:
小鸟距离屏幕左边的距离是80px,自身有15px的margin-left,因此在pipeX <= 95px的时候小鸟和柱子相遇
在这里插入图片描述
小鸟离开柱子的图示:
pipeX = 80 - 52 - 15 =13,因此pipe>=13的时候小鸟刚好离开柱子。
判断完小鸟和柱子左右碰撞的情况还需要判断上下碰撞的情况(birdY <pipeY[0] || birdY >= pipeY[1])
在这里插入图片描述

  /**
   * 柱子的碰撞检测
   */
  judgePipe: function(){
   
   
    let index = this.score % this.pipeLength;
    let pipeX = this.pipeArr[index].up.offsetLeft;
    let pipeY = this.pipeArr[index].y;
    let birdY = this.birdTop;
    if((pipeX <= 95 && pipeX >= 13) && (birdY < pipeY[0] || birdY >= pipeY[1])){
   
   
      this.failGame();
    }
  },
(4)、本地存储

util.js
添加数据
当添加的数据不是数组形式的时候,需要通过JSON.stringify(value)将数据转换成数组形式的字符串。

/**
 * 添加数据
 */
export function setLocal (key, value){
   
   
  if(typeof value === 'object' && value !== null){
   
   
    value = JSON.stringify(value);
  }
  localStorage.setItem(key,value);
}

获取数据
由于想获取出来的数据时数组或者字符串形式的因此取数据的时候需要使用JSON.parse(value)将数组字符串或者对象字符串转换成正常的数组或者对象。

/**
 * 取数据
 * @param {*} key 
 */
export function getLocal (key){
   
   
  var value = localStorage.getItem(key);
  if(value === null) {
   
   
    return value;
  }
  if(value[0] === '[' || value[0] === '{'){
   
   
    return JSON.parse(value);
  }
  return value;
}

我们使用scoreArr来保存成绩信息

/**
   * 从本地获取分数
   */
  getScore: function(){
   
   
    var scoreArr = getLocal('score');
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值