博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
【默默努力】h5-game-blockBreaker
阅读量:5319 次
发布时间:2019-06-14

本文共 18805 字,大约阅读时间需要 62 分钟。

先放下游戏的效果,我不太会玩游戏

1037363-20190902161029665-1474431656.gif
然后放下无私开源的作者大大的地址:
这个游戏的话,我觉得应该是如果如果球跟砖碰到了,那么这个砖就消失,然后得一分,然后这个球就会以竖直的相同的角度返回,
如果球到了发射台,就会以在发射台的角度返回去,如果球没有碰到发射台,那么球就沿着坠落的方向消失,游戏结束。
接下来我们看代码
如果我写的话,应该分数是一个,官卡是一个,砖是一个幕布,下面的发射台是一个,球是一个。应该是5个,然后再加一个功能的js,6个js去实现这个。
我们来看看作者大大怎么实现的吧~
入口的文件html,里面引用了common.js,scene.js 还有game.js,canvas绘制了游戏的背景大小

  
打砖块v1.1
使用左右方向键,进行移动;空格键发射小球并开始游戏,游戏结束时按空格键重置游戏;P 键暂停游戏;通关游戏后,按 N 键可进入下一关卡

common.js中的代码写的真好,都看的懂,而且作者大大有注释,真的非常注重浏览器兼容性。

//common.js/* by:弦云孤赫——David Yang** github - https://github.com/yangyunhe369*/// 封装打印日志方法const log = console.log.bind(console)// 生成图片对象方法const imageFromPath = function (src) {  let img = new Image()  img.src = './images/' + src  return img}// 检测页面不可见时自动暂停游戏方法const isPageHidden = function (game) {  let hiddenProperty = 'hidden' in document ? 'hidden' :          'webkitHidden' in document ? 'webkitHidden' :          'mozHidden' in document ? 'mozHidden' :          null  let visibilityChangeEvent = hiddenProperty.replace(/hidden/i, 'visibilitychange')  // 监听页面是否可见事件  document.addEventListener(visibilityChangeEvent, function () {    if (!document[hiddenProperty]) {  // 可见状态      setTimeout(function () {        game.state = game.state_RUNNING      }, 100)    } else { // 不可见状态      game.state = game.state_STOP    }  })}// 图片素材路径const allImg = {  background: 'background.jpg',  paddle: 'paddle.png',  ball: 'ball.png',  block1: 'block001.png',  block2: 'block002.png',}

main.js中就是游戏的初始化

//main.js/* by:弦云孤赫——David Yang** github - https://github.com/yangyunhe369*/// 游戏主函数let _main = {  LV: 1,                               // 初始关卡  MAXLV: 2,                            // 最终关卡  scene: null,                         // 场景对象  blockList: null,                     // 所有砖块对象集合  ball: null,                          // 小球对象  paddle: null,                        // 挡板对象  score: null,                         // 计分板对象  ball_x: 491,                         // 小球默认x轴坐标  ball_y: 432,                         // 小球默认y轴坐标  paddle_x: 449,                       // 挡板默认x轴坐标  paddle_y: 450,                       // 挡板默认y轴坐标  score_x: 10,                         // 计分板默认x轴坐标  score_y: 30,                         // 计分板默认y轴坐标  fps: 60,                             // 游戏运行帧数  game: null,                          // 游戏主要逻辑对象  start: function () {                 // 游戏启动函数    let self = this    /**     * 生成场景(根据游戏难度级别不同,生成不同关卡)     */    self.scene = new Scene(self.LV)    // 实例化所有砖块对象集合    self.blockList = self.scene.initBlockList()    /**     * 小球     */    self.ball = new Ball(self)    /**     * 挡板     */    self.paddle = new Paddle(self)    /**     * 计分板     */    self.score = new Score(self)    /**     * 游戏主要逻辑     */    self.game = new Game(self)    /**     * 游戏初始化     */    self.game.init(self)  }}_main.start()

scene.js里面定义的是各种对象及方法

/* by:弦云孤赫——David Yang** github - https://github.com/yangyunhe369*/// 定义挡板对象class Paddle {  constructor (_main) {    let p = {      x: _main.paddle_x,                                   // x轴坐标      y: _main.paddle_y,                                   // y轴坐标      w: 102,                                              // 图片宽度      h: 22,                                               // 图片高度      speed: 10,                                           // x轴移动速度      ballSpeedMax: 8,                                     // 小球反弹速度最大值      image: imageFromPath(allImg.paddle),                 // 引入图片对象      isLeftMove: true,                                    // 能否左移      isRightMove: true,                                   // 能否右移    }    Object.assign(this, p)  }  moveLeft () {    this.x -= this.speed  }  moveRight () {    this.x += this.speed  }  // 小球、挡板碰撞检测  collide (ball) {    let b = ball    let p = this    if (Math.abs((b.x + b.w/2) - (p.x + p.w/2)) < (b.w + p.w)/2 &&        Math.abs((b.y + b.h/2) - (p.y + p.h/2)) < (b.h + p.h)/2) {      return true    }    return false  }  // 计算小球、挡板碰撞后x轴速度值  collideRange (ball) {    let b = ball    let p = this    let rangeX = 0    rangeX = (p.x + p.w/2) - (b.x + b.w/2)    if (rangeX < 0) { // 小球撞击挡板左侧      return rangeX / (b.w/2 + p.w/2) * p.ballSpeedMax    } else if (rangeX > 0) { // 小球撞击挡板右侧      return rangeX / (b.w/2 + p.w/2) * p.ballSpeedMax    }  }}// 小球对象class Ball {  constructor (_main) {    let b = {      x: _main.ball_x,                      // x轴坐标      y: _main.ball_y,                      // y轴坐标      w: 18,                                // 图片宽度      h: 18,                                // 图片高度      speedX: 1,                            // x轴速度      speedY: 5,                            // y轴速度      image: imageFromPath(allImg.ball),    // 图片对象      fired: false,                         // 是否运动,默认静止不动    }    Object.assign(this, b)  }  move (game) {    if (this.fired) {      // 碰撞边界检测      if (this.x < 0 || this.x > 1000 - this.w) {        this.speedX *= -1      }      if (this.y < 0) {        this.speedY *= -1      }      if (this.y > 500 - this.h) {        // 游戏结束        game.state = game.state_GAMEOVER        // game.isGameOver = true      }      // 移动      this.x -= this.speedX      this.y -= this.speedY    }  }}// 砖块class Block {  constructor (x, y, life = 1) {    let bk = {      x: x,                                                                               // x轴坐标      y: y,                                                                               // y轴坐标      w: 50,                                                                              // 图片宽度      h: 20,                                                                              // 图片高度      image: life == 1 ? imageFromPath(allImg.block1) : imageFromPath(allImg.block2),     // 图片对象      life: life,                                                                         // 生命值      alive: true,                                                                        // 是否存活    }    Object.assign(this, bk)  }  // 消除砖块  kill () {    this.life--    if (this.life == 0) {      this.alive = false    } else if (this.life == 1) {      this.image = imageFromPath(allImg.block1)    }  }  // 小球、砖块碰撞检测  collide (ball) {    let b = ball    if (Math.abs((b.x + b.w/2) - (this.x + this.w/2)) < (b.w + this.w)/2 &&        Math.abs((b.y + b.h/2) - (this.y + this.h/2)) < (b.h + this.h)/2) {      this.kill()      return true    } else {      return false    }  }  // 计算小球、砖块碰撞后x轴速度方向  collideBlockHorn (ball) {    let b = ball    // 小球    let bk = this   // 砖块    let rangeX = 0    let rangeY = 0    rangeX = Math.abs((b.x + b.w/2) - (bk.x + bk.w/2))    rangeY = Math.abs((b.y + b.h/2) - (bk.y + bk.h/2))    if (rangeX > bk.w/2 && rangeX < (bk.w/2 + b.w/2) && rangeY < (bk.h/2 + b.h/2)) { // X轴方向与砖块四角相交      if (b.x < bk.x && b.speedX > 0 || b.x > bk.x && b.speedX < 0) { // 小球在砖块左侧时        return false      } else { // 小球在砖块右侧        return true      }    }    return false  }}// 计分板class Score {  constructor (_main) {    let s = {      x: _main.score_x,                               // x轴坐标      y: _main.score_y,                               // y轴坐标      text: '分数:',                                 // 文本分数      textLv: '关卡:',                               // 关卡文本      score: 200,                                     // 每个砖块对应分数      allScore: 0,                                    // 总分      blockList: _main.blockList,                     // 砖块对象集合      blockListLen: _main.blockList.length,           // 砖块总数量      lv: _main.LV,                                   // 当前关卡    }    Object.assign(this, s)  }  // 计算总分  computeScore () {    let num = 0    let allNum = this.blockListLen    num = this.blockListLen - this.blockList.length    this.allScore = this.score * num  }}// 定义场景class Scene {  constructor (lv) {    let s = {      lv: lv,                                         // 游戏难度级别      canvas: document.getElementById("canvas"),      // canvas对象      blockList: [],                                  // 砖块坐标集合    }    Object.assign(this, s)  }  // 实例化所有砖块对象  initBlockList () {    this.creatBlockList()    let arr = []    for (let item of this.blockList) {      for (let list of item) {        if (list.type === 1) {          let obj = new Block(list.x, list.y)          arr.push(obj)        } else if (list.type === 2) {          let obj = new Block(list.x, list.y, 2)          arr.push(obj)        }      }    }    return arr  }  // 创建砖块坐标二维数组,并生成不同关卡  creatBlockList () {    let lv = this.lv,                         // 游戏难度级别        c_w = this.canvas.width,              // canvas宽度        c_h = this.canvas.height,             // canvas高度        xNum_max = c_w/50,                    // x轴砖块最大数量        yNum_max = 12,                        // y轴砖块最大数量        x_start = 0,                          // x轴起始坐标,根据砖块数量浮动        y_start = 60                          // y轴起始坐标,默认从60起    switch (lv) {      case 1 : // 正三角形        var xNum = 16,                               // x轴砖块第一层数量            yNum = 9                                 // y轴砖块层数        // 循环y轴        for(let i = 0;i < yNum;i++){          let arr = []          // 修改每层x轴砖块数量          if (i === 0) {            xNum = 1          } else if (i === 1) {            xNum = 2          } else {            xNum += 2          }          x_start = (xNum_max - xNum)/2 * 50             // 修改每层x轴砖块起始坐标          // 循环x轴          for(let k = 0;k < xNum;k++){            if (i < 3) { // 前三排为特殊砖块              arr.push({                x: x_start + k*50,                y: y_start + i*20,                type: 2,              })            } else {              arr.push({                x: x_start + k*50,                y: y_start + i*20,                type: 1,              })            }          }          this.blockList.push(arr)        }        break      case 2 :  // 倒三角形        var xNum = 16,                              // x轴砖块第一层数量            yNum = 9                                // y轴砖块层数        // 循环y轴        for(let i = 0;i < yNum;i++){          let arr = []          // 修改每层x轴砖块数量          if (i === yNum - 1) {            xNum = 1          } else if (i === 0) {            xNum = xNum          } else {            xNum -= 2          }          x_start = (xNum_max - xNum)/2 * 50             // 修改每层x轴砖块起始坐标          // 循环x轴          for(let k = 0;k < xNum;k++){            if (i < 3) { // 前三排为特殊砖块              arr.push({                x: x_start + k*50,                y: y_start + i*20,                type: 2,              })            } else {              arr.push({                x: x_start + k*50,                y: y_start + i*20,                type: 1,              })            }          }          this.blockList.push(arr)        }        break      case 3 : // 工字形        var xNum = 16,                              // x轴砖块第一层数量            yNum = 9                                // y轴砖块层数        // 循环y轴        for(let i = 0;i < yNum;i++){          let arr = []          // 修改每层x轴砖块数量          if (i === 0) {            xNum = xNum          } else if (i > 4) {            xNum += 2          } else {            xNum -= 2          }          x_start = (xNum_max - xNum)/2 * 50             // 修改每层x轴砖块起始坐标          // 循环x轴          for(let k = 0;k < xNum;k++){            if (i < 3) { // 前三排为特殊砖块              arr.push({                x: x_start + k*50,                y: y_start + i*20,                type: 2,              })            } else {              arr.push({                x: x_start + k*50,                y: y_start + i*20,                type: 1,              })            }          }          this.blockList.push(arr)        }        break    }  }}

game.js中进行的是一些游戏初始化,以及必备说明

/* by:弦云孤赫——David Yang** github - https://github.com/yangyunhe369*/// 游戏主要运行逻辑class Game {  constructor (main) {    let g = {      main: main,                                                   // 游戏主函数      actions: {},                                                  // 记录按键动作      keydowns: {},                                                 // 记录按键keycode      state: 1,                                                     // 游戏状态值,初始默认为1      state_START: 1,                                               // 开始游戏      state_RUNNING: 2,                                             // 游戏开始运行      state_STOP: 3,                                                // 暂停游戏      state_GAMEOVER: 4,                                            // 游戏结束      state_UPDATE: 5,                                              // 游戏通关      canvas: document.getElementById("canvas"),                    // canvas元素      context: document.getElementById("canvas").getContext("2d"),  // canvas画布      timer: null,                                                  // 轮询定时器      fps: main.fps,                                                // 动画帧数,默认60    }    Object.assign(this, g)  }  // 绘制页面所有素材  draw (paddle, ball, blockList, score) {    let g = this    // 清除画布    g.context.clearRect(0, 0, g.canvas.width, g.canvas.height)    // 绘制背景图    g.drawBg()    // 绘制挡板    g.drawImage(paddle)    // 绘制小球    g.drawImage(ball)    // 绘制砖块    g.drawBlocks(blockList)    // 绘制分数    g.drawText(score)  }  // 绘制图片  drawImage (obj) {    this.context.drawImage(obj.image, obj.x, obj.y)  }  // 绘制背景图  drawBg () {    let bg = imageFromPath(allImg.background)    this.context.drawImage(bg, 0, 0)  }  // 绘制所有砖块  drawBlocks (list) {    for (let item of list) {      this.drawImage(item)    }  }  // 绘制计数板  drawText (obj) {    this.context.font = '24px Microsoft YaHei'    this.context.fillStyle = '#fff'    // 绘制分数    this.context.fillText(obj.text + obj.allScore, obj.x, obj.y)    // 绘制关卡    this.context.fillText(obj.textLv + obj.lv, this.canvas.width - 100, obj.y)  }  // 游戏结束  gameOver () {    // 清除定时器    clearInterval(this.timer)    // 清除画布    this.context.clearRect(0, 0, this.canvas.width, this.canvas.height)    // 绘制背景图    this.drawBg()    // 绘制提示文字    this.context.font = '48px Microsoft YaHei'    this.context.fillStyle = '#fff'    this.context.fillText('游戏结束', 404, 226)  }  // 游戏晋级  goodGame () {    // 清除定时器    clearInterval(this.timer)    // 清除画布    this.context.clearRect(0, 0, this.canvas.width, this.canvas.height)    // 绘制背景图    this.drawBg()    // 绘制提示文字    this.context.font = '48px Microsoft YaHei'    this.context.fillStyle = '#fff'    this.context.fillText('恭喜晋级下一关卡', 308, 226)  }  // 游戏通关  finalGame () {    // 清除定时器    clearInterval(this.timer)    // 清除画布    this.context.clearRect(0, 0, this.canvas.width, this.canvas.height)    // 绘制背景图    this.drawBg()    // 绘制提示文字    this.context.font = '48px Microsoft YaHei'    this.context.fillStyle = '#fff'    this.context.fillText('恭喜通关全部关卡', 308, 226)  }  // 注册事件  registerAction (key, callback) {    this.actions[key] = callback  }  // 小球碰撞砖块检测  checkBallBlock (g, paddle, ball, blockList, score) {    let p = paddle, b = ball    // 小球碰撞挡板检测    if (p.collide(b)) {      // 当小球运动方向趋向挡板中心时,Y轴速度取反,反之则不变      if (Math.abs(b.y + b.h/2 - p.y + p.h/2) > Math.abs(b.y + b.h/2 + b.speedY - p.y + p.h/2)) {        b.speedY *= -1      } else {        b.speedY *= 1      }      // 设置X轴速度      b.speedX = p.collideRange(b)    }    // 小球碰撞砖块检测    blockList.forEach(function (item, i, arr) {      if (item.collide(b)) { // 小球、砖块已碰撞        if (!item.alive) { // 砖块血量为0时,进行移除          arr.splice(i, 1)        }        // 当小球运动方向趋向砖块中心时,速度取反,反之则不变        if ((b.y < item.y && b.speedY < 0) || (b.y > item.y && b.speedY > 0)) {          if (!item.collideBlockHorn(b)) {            b.speedY *= -1          } else { // 当小球撞击砖块四角时,Y轴速度不变            b.speedY *= 1          }        } else {          b.speedY *= 1        }        // 当小球撞击砖块四角时,X轴速度取反        if (item.collideBlockHorn(b)) {          b.speedX *= -1        }        // 计算分数        score.computeScore()      }    })    // 挡板移动时边界检测    if (p.x <= 0) { // 到左边界时      p.isLeftMove = false    } else {      p.isLeftMove = true    }    if (p.x >= 1000 - p.w) { // 到右边界时      p.isRightMove = false    } else {      p.isRightMove = true    }    // 移动小球    b.move(g)  }  // 设置逐帧动画  setTimer (paddle, ball, blockList, score) {    let g = this    let main = g.main    g.timer = setInterval(function () {      // actions集合      let actions = Object.keys(g.actions)      for (let i = 0; i < actions.length; i++) {        let key = actions[i]        if(g.keydowns[key]) {          // 如果按键被按下,调用注册的action          g.actions[key]()        }      }      // 当砖块数量为0时,挑战成功      if (blockList.length == 0) {        if (main.LV === main.MAXLV) { // 最后一关通关          // 升级通关          g.state = g.state_UPDATE          // 挑战成功,渲染通关场景          g.finalGame()        } else { // 其余关卡通关          // 升级通关          g.state = g.state_UPDATE          // 挑战成功,渲染下一关卡场景          g.goodGame()        }      }      // 判断游戏是否结束      if (g.state === g.state_GAMEOVER) {        g.gameOver()      }      // 判断游戏开始时执行事件      if (g.state === g.state_RUNNING) {        g.checkBallBlock(g, paddle, ball, blockList, score)        // 绘制游戏所有素材        g.draw(paddle, ball, blockList, score)      } else if (g.state === g.state_START){        // 绘制游戏所有素材        g.draw(paddle, ball, blockList, score)      }    }, 1000/g.fps)  }  /**   * 初始化函数   */  init () {    let g = this,        paddle = g.main.paddle,        ball = g.main.ball,        blockList = g.main.blockList,        score = g.main.score    // 设置键盘按下及松开相关注册函数    window.addEventListener('keydown', function (event) {     g.keydowns[event.keyCode] = true    })    window.addEventListener('keyup', function (event) {      g.keydowns[event.keyCode] = false    })    g.registerAction = function (key, callback) {      g.actions[key] = callback    }    // 注册左方向键移动事件    g.registerAction('37', function(){      // 判断游戏是否处于运行阶段      if (g.state === g.state_RUNNING && paddle.isLeftMove) {        paddle.moveLeft()      }    })    // 注册右方向键移动事件    g.registerAction('39', function(){      // 判断游戏是否处于运行阶段      if (g.state === g.state_RUNNING && paddle.isRightMove) {        paddle.moveRight()      }    })    window.addEventListener('keydown', function (event) {      switch (event.keyCode) {        // 注册空格键发射事件        case 32 :          if (g.state === g.state_GAMEOVER) { // 游戏结束时            // 开始游戏            g.state = g.state_START            // 初始化            g.main.start()          } else {             // 开始游戏            ball.fired = true            g.state = g.state_RUNNING          }          break        // N 键进入下一关卡        case 78 :          // 游戏状态为通关,且不为最终关卡时          if (g.state === g.state_UPDATE && g.main.LV !== g.main.MAXLV) { // 进入下一关            // 开始游戏            g.state = g.state_START            // 初始化下一关卡            g.main.start(++g.main.LV)          }          break        // P 键暂停游戏事件        case 80 :          g.state = g.state_STOP          break      }    })    // 设置轮询定时器    g.setTimer(paddle, ball, blockList, score)  }}

后记:很多代码没有看懂,珍惜时间,好好学习哇~

转载于:https://www.cnblogs.com/smart-girl/p/11447382.html

你可能感兴趣的文章
Java多线程基础(一)
查看>>
TCP粘包拆包问题
查看>>
SQL Server中利用正则表达式替换字符串
查看>>
POJ 1015 Jury Compromise(双塔dp)
查看>>
论三星输入法的好坏
查看>>
Linux 终端连接工具 XShell v6.0.01 企业便携版
查看>>
JS写一个简单日历
查看>>
Python 发 邮件
查看>>
mysql忘记密码的解决办法
查看>>
全面分析Java的垃圾回收机制2
查看>>
[Code Festival 2017 qual A] C: Palindromic Matrix
查看>>
修改博客园css样式
查看>>
Python3 高阶函数
查看>>
初始面向对象
查看>>
leetcode Letter Combinations of a Phone Number
查看>>
Unity 5.4 测试版本新特性---因吹丝停
查看>>
7.5 文件操作
查看>>
MyEclipse中将普通Java项目convert(转化)为Maven项目
查看>>
node js 安装.node-gyp/8.9.4 权限 无法访问
查看>>
windows基本命令
查看>>