作者:王圣松

转发链接:https://juejin.im/post/6844903687307919373

前言

今天给大家带来一个小游戏。

要求:熟悉 JavaScript 继承的概念。

游戏预览

玩法:

开局一个球,两块板子,其中最上方是电脑板子,会跟着球跑,球打到板子上会弹回来,打到你的板子上也是回弹出去,如果达到了上下边界,游戏结束。控制你的板子就用方向左右键。接到一个球+10分。

基础布局部分(HTML+CSS)

游戏部分,我们按照以下图示尺寸设定:

HTML:

//游戏本体

//电脑的板子(上板子)
//你的板子(下板子)

开始游戏

点击这里

0

//左上角分数卡

CSS:

.game {  width: 500px;  height: 500px;  position: relative;  border: 5px solid #fff;  background-color: #222;}.board {  background-color: #FF644E;}.ball {  background-color: #fff;}.info {  width: 100%;  height: 100%;  position: absolute;  left: 0;  top: 0;  color: white;  background-color: #222;  display: flex;  justify-content: center;  align-items: center;  flex-direction: column;}

逻辑部分(JavaScript)

我们采用 JavaScript 继承的方式来写这个游戏。

首先先定义一个 GameObject:

let GameObject = function (position,size,selector){  this.$el = $(selector) //选择器  this.position = position //游戏物体位置  this.size = size //游戏物体大小  this.$el.css("position","absolute") //设置其Css为绝对定位  this.updateCss()}

首先,$el为选择器,代表 jQuery 的元素选择器。position 为元素定位的位置。size为元素大小。

设置在原型链上的 updateCss 方法为元素位置、大小更新方法。按照当前对象的属性数值更新。

那我们先创建一个球(Ball)对象,继承 GameObject:

let Ball = function () {  this.size = {width: 15, height: 15}; //球的大小  this.position = {x: 250, y: 250}; //球的位置  this.velocity = {x: 5, y: 5}; //球的速度  GameObject.call(this,this.position,{width: 15, height: 15},".ball") //继承GameObject。并将参数和自身传入};Ball.prototype = Object.create(GameObject.prototype); //将Ball的原型链连接GameObjecr的原型链Ball.prototype.constructor = Ball.constructor //因为连接,所以需要重新指向构造函数。将原型链的构造函数指向自己的构造函数

因为球只有一个,所以参数我们写死在对象里面。

我们实例化一个球对象:

let ball = new Ball();

接着屏幕中央就会有一个球:

接下来开始绘制两个可移动的板子:

let Board = function (position, sel) {  this.size = { //锁定板子大小    width: 100,    height: 15  };  GameObject.call(this, position, this.size, sel); //对接父对象};Board.prototype = Object.create(GameObject.prototype); //对接父对象原型链Board.prototype.constructor = Board.constructor; //更改原型链上的构造为自己的构造

然后 new 两块板子:

let board1 = new Board({x: 0, y: 30}, '.b1');let board2 = new Board({x: 0, y: 455}, '.b2');

然后,我们让球动起来。

我们在 Ball的原型链上定义一个 update 方法来移动小球:

Ball.prototype.update = function () {  this.position.x += this.velocity.x; //x轴按速度移动  this.position.y += this.velocity.y; //Y轴按速度移动  this.updateCss(); //调用父对象的updateCss方法更新界面  if (this.position.x < 0 || this.position.x > 500) { //如果撞到了左右墙壁    this.velocity.x = -this.velocity.x; // 回弹  }  if (this.position.y < 0 || this.position.y > 500) { //如果撞到了上下墙壁    this.velocity.y = -this.velocity.y; // 回弹  }};

如果球的横向边界小于 0 或者大于 500,说明球碰到了左右墙壁。

如果球的纵向边界小于 0 或者大于 500,说明球碰到了上下墙壁。

然后我们每隔 30ms 调用一下小球的 update 函数,使其位置更新:

setInterval(function () {  ball.update();}, 30)

如图 :

这样小球就有了碰到障碍物反弹的能力了。

接着我们删掉这个定时器的代码。

然后,我们定义一个 Game 对象。这个对象不会继承任何父对象,因为它只负责控制其他物体对象。

let Game = function () {  this.timer = null; //唯一timer 负责开始游戏结束游戏的timer  this.grade = 0; //分数  this.initControl(); //键盘监听事件  this.control = {}; //这个放置各个键盘按键情况的对象};

因为我们有键盘要控制板子的移动,所以我们要加监听事件。

Game.prototype.initControl = function () {  let _this = this; //防止this作用域混淆  $(window).keydown(function (evt) { //按键按下    _this.control[evt.key] = true; //设置当前的key value为true  });  $(window).keyup(function (evt) { //按键抬起    _this.control[evt.key] = false; //设置当前的key value为false  })};

根据我们的游戏规则,小球碰到上下墙壁要判别输赢,碰到上下板子要回弹。所以我们在 GameObject 的原型链上定义一个碰撞方法 collide。

GameObject.prototype.collide = function (otherObject) {  let inRangeX = otherObject.position.x > this.position.x &&    otherObject.position.x < this.position.x + this.size.width;  let inRangeY = otherObject.position.y > this.position.y &&    otherObject.position.y < this.position.y + this.size.height;  return inRangeX && inRangeY;};

其参数是另一个物体对象。

inRangeX 的判别式:当另一个物体的 X 值大于你的 X 值,且另一个物体 X 值小于你的 X 值+你宽度的时候,返回 true,否则 false。

inRangeY 的判别式:当另一个物体的 Y 值大于你的 Y 值,且另一个物体 Y 值小于你的 Y 值+你高度的时候,返回 true,否则 false。

然后返回两个判别式的情况。如果都为 true,说明两个物体相撞了。

这样我们在 Game 对象定义一个 startGameMain 方法,代表是我们游戏控制器主体。

Game.prototype.startGameMain = function () {  let _this = this; //作用域!!!  this.timer = setInterval(function () { //唯一定时器    if (board1.collide(ball)) { //如果一号板子撞到了球      console.log("碰到了1号板子");       ball.velocity.y = -ball.velocity.y; //Y反向运动    }    if (board2.collide(ball)) { //如果二号板子撞到了球      console.log("碰到了2号板子");      _this.grade += 10; //自己的分数+10      ball.velocity.y = -ball.velocity.y;    }    ball.update(); //球体更新方法    $(".grade").text(this.grade); //jQuery更新分数  }, 30) //每隔30ms走一次};

然后,

let game = new Game();game.startGameMain();

看一看效果:

接着在 startGameMain 函数内,继续编写。

如果球碰到上板子,说明上板子输了,如果碰到下板子,下板子输了。

if (ball.position.y < 0) {  console.log("第一个板子输了");  _this.endGame("你赢了"); //后面的结束游戏方法}if (ball.position.y > 500) {  console.log("第二个板子输了");  _this.endGame("你输了");}

接着我们让上板子跟着球跑。我们在板子 Board 对象内定义一个 update 方法,更新板子的坐标和 UI。

Board.prototype.update = function () {  this.updateCss();};

然后继续在 startGameMain 函数内写板子跟球跑的逻辑:

board1.position.x += ball.position.x > board1.position.x + board1.size.width / 2 ? 12 : 0;board1.position.x += ball.position.x < board1.position.x + board1.size.width / 2 ? -12 : 0;board1.update();

如果球的 X 坐标 > 板子 X 坐标+板子宽度/2,那么板子 X +12,向右跑。

如果球的 X 坐标 < 板子 X 坐标+板子宽度/2,那么板子 X -12,向左跑。

如图:

但是细心的朋友可能会发现,板子超出边界了。

所以我们就限制板子最小 X 为 0,最大 X 为容器 width-板子 width。

于是我们重写一下 Board 的 update 方法。

Board.prototype.update = function () {  if (this.position.x < 0) {    this.position.x = 0;  }  if (this.position.x + this.size.width > 500) {    this.position.x = 500 - this.size.width;  }  this.updateCss();};

这样再看看:

接着写我方板子键盘控制事件,还是在 startGameMain 函数内。

if (_this.control["ArrowLeft"]) { //如果左键  board2.position.x -= 8; //二号板子左移8}
board2.update();

这样我们的键盘也可以操控了,球也能正常回弹。

我们继续写 endGame 函数:

Game.prototype.endGame = function (res) {  clearInterval(this.timer); //清除定时器  $(".infoText").html(res + '分数:' + this.grade); //展示分数  $(".info").show(); //展示信息};

然后我们再加一个 startGame 的函数:

Game.prototype.startGame = function () {  let time = 3; //倒计时3秒  let _this = this;  this.grade = 0; //初始化分数0  ball.init(); //稍后用到  let timer = setInterval(function () {    $(".infoText").text(time);    time--;    if (time < 0) { //如果时间<0      clearInterval(timer); //清除定时器      $(".info").hide(); //隐藏信息      _this.startGameMain(); //开始主要的游戏函数    }  }, 1000)};

我们在 HTML 里面新增 info 信息的元素:

//新增的地方

开始游戏

点击这里

0

下面我们调用一下 startGame:

let game = new Game();$(".start").click(function () {  game.startGame();})

这样一个比较完整的游戏完成了:

但是这看起来有点傻,因为它每次只向一个方向去发车。

我们可以使用 JavaScript 中的三角函数解决这个问题。

首先我们找到 Ball 对象,把里面的速度参数抽出为一个函数,取名叫 init。

Ball.prototype.init = function () {  this.position = {x: 250, y: 250};  let randomDeg = Math.random() * 2 * Math.PI;  this.velocity = {    x: Math.cos(randomDeg) * 8,    y: Math.sin(randomDeg) * 8  }};

然后 Ball 对象内只剩下:

let Ball = function () {  this.size = {width: 15, height: 15};  this.init();  GameObject.call(this, this.position, this.size, '.ball');};

我们来仔细讲一下这个 init 函数。首先我们先锁定速度为 10,这个是首要条件,所以我们先产生一个随机角度。

  let randomDeg = Math.random() * 2 * Math.PI;

1PI 为 180 度,2PI 为 360 度。然后我们再随机一个小数,可以得到一个 360 度以内的任意角。

接着,我们可以根据三角函数 cos 和 sin。sin 是斜边/对边,cos 是斜边/邻边。我们如果知道了角度和长度,就可以知道 XY 的速度分别是多少。

X 长度 = 斜边长 * Cos(角度) Y 长度 = 斜边长 * Sin(角度)

如图:

这也就是数学中向量的概念。

然后我们再看看游戏:

显然比之前合理多了。

Gitee:https://gitee.com/Janlaywss/juejin-doc/blob/master/JsExtendGame.vue

作者:王圣松

转发链接:https://juejin.im/post/6844903687307919373

jQuery 一次定时器_用 jQuery 手写一个小游戏相关推荐

  1. python能制作游戏吗_如何用python写一个小游戏

    广告关闭 腾讯云11.11云上盛惠 ,精选热门产品助力上云,云服务器首年88元起,买的越多返的越多,最高返5000元! 引言最近python语言大火,除了在科学计算领域python有用武之地之外,在游 ...

  2. dueros模拟测试没有请求后台_实战 | 用手写一个骚气的请求合并,演绎底层的真实...

    来源:公众号[ java进阶架构师] 好文推荐: 字节跳动Java岗4面面经分享:索弓|+rabbitmq+spring+Redis 拼多多面经Java开发3面面经:准备好久没想到面试题超级简单 网易 ...

  3. python游戏小项目简单_[简单学Python] 通过一个小游戏完成Python入门[2]变量和赋值...

    变量和赋值 到这里,你已经成功地打印出了千寻的名字和卖身契.与此同时,千寻也成为了汤婆婆的工人,渐渐地,她忘记了自己是谁,遗失了自己"姓名"的信息. 那么,在信息纷繁的代码世界里, ...

  4. python连连看小游戏_请用PYTHON编一个小游戏,如五子棋,连连看,贪吃蛇,扫雷,计算器等等...

    展开全部 #!/usr/bin/python from Tkinter import * import random class snake(Frame): def __init__(self, ma ...

  5. 使用python制作聊天框解谜游戏_使用Python写一个小游戏alien invasion!

    最近python语言大火,除了在科学计算领域python有用武之地之外,在游戏.后台等方面,python也大放异彩,本篇博文将按照正规的项目开发流程,手把手教大家写个python小游戏,来感受下其中的 ...

  6. 黑白块游戏java代码_用java做的一个小游戏—黑白反斗棋(适合菜鸟)

    用Java做的一个小游戏,黑白反斗棋,我玩过了5*5和10*10的.是学习之后做的,不是自己原始开发的. import java.awt.Color; import java.awt.FlowLayo ...

  7. python如何开发网站_如何用Python写一个小网站?

    一.准备 python基础相关准备:pygame的基础知识,参考目光博客的"用Python和Pygame写游戏-从入门到精通"安python 3.8.0 在python官网下载,不 ...

  8. 手机版python3h如何自制游戏_教你如何用 Python 写一个小游戏

    教你如何用 Python 写一个小游戏 引言 最近 python 语言大火, 除了在科学计算领域 python 有用武之地之外, 在游戏后台等方面, python 也大放异彩, 本篇博文将按照正规的项 ...

  9. 关于python小游戏的毕业论文_使用Python写一个小游戏

    引言 最近python语言大火,除了在科学计算领域python有用武之地之外,在游戏.后台等方面,python也大放异彩,本篇博文将按照正规的项目开发流程,手把手教大家写个python小游戏,来感受下 ...

最新文章

  1. 如何避免Java中的回调“地狱”
  2. Resource通配符路径 ——跟我学spring3
  3. 【Python3_进阶系列_006】Python3-单例模式
  4. android应用程序的组成部分
  5. MySQL_前缀索引_建立
  6. python有比赛吗_python编程比赛到底应不应该让孩子参加?有好处
  7. 11月3日 迅雷白金会员vip账号分享 91freevip 23:00更新
  8. html让图片变灰色,firefox浏览器中css如何把图片变成灰色?
  9. Mac 制作U盘操作系统并清空Mac全部数据后重装系统
  10. 港科百创 | 一清创新完成Pre-A+轮战略融资
  11. onap桂林版部署教程
  12. 基于OpenCV DNN模块给黑白老照片上色(附Python/C++源码)
  13. Codeup墓地-1123
  14. 51SCM_AD模块CS5550学习心得
  15. 关于DecimalFormat的取舍问题,DecimalFormat四舍五入的坑
  16. 海思IPC平台快速拔插SD卡会出现SD卡不识别解决方法
  17. 亚马逊mysql无法远程连接不上_mysql – 无法从EC2实例连接到RDS实例
  18. 各类数据库驱动包列表下载
  19. 动态联编与静态联编的区别
  20. 微信小程序城市列表构建

热门文章

  1. CSS学习之CSS Syntax
  2. [转]终于有人说出来了——Java不适合于作为主要编程教学语言
  3. 之前的一个5g核心网解决方案
  4. Excel中提取英文,数值和编码(LEN函数)
  5. Scrapy框架新手入门教程
  6. 微软IEG(创新工程组)实习面试
  7. python创建文件夹和文件夹_Python快捷创建文件夹和文件详解
  8. 宇视项目新手||集成商超级开局法——详细版
  9. [知识点]Log.wtf()
  10. 图像分辨率,DPI和像素个数的关系