内容简介:今天给大家带来一个小游戏
今天给大家带来一个小游戏
要求:熟悉JavaScript继承的概念
游戏预览
玩法:开局一个球 两块板子。其中最上方是电脑板子,会跟着球跑。球达到板子上回弹回来。打到你的板子上也是回弹出去。如果达到了上下边界。游戏结束
控制你的板子就用方向左右键
接到一个球+10分
基础布局部分(HTML+CSS)
游戏部分,我们按照以下图示尺寸设定
html:
<div class="game"> //游戏本体 <div class="board b1"> //电脑的板子(上板子) </div> <div class="board b2"> //你的板子(下板子) </div> <div class="ball"></div> //球体 <div class="info"> <h2 class="infoText">开始游戏</h2> <button class="start">点击这里</button> </div> <div class="grade">0</div> //左上角分数卡 </div>复制代码
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; } .grade { padding: 10px; }复制代码
逻辑部分(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() } GameObject.prototype.updateCss = function(){ this.$el.css("left",this.position.x+"px") this.$el.css("top",this.position.y+"px") this.$el.css("width",this.size.width+"px") this.$el.css("height",this.size.height+"px") }复制代码
首先
$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 } if (_this.control["ArrowRight"]) { //如果右键 board2.position.x += 8; //二号板子右移8 } 复制代码
board2.update(); 复制代码
这样我们的键盘也可以操控了。球也能正常回弹
我们继续写endGame函数
Game.prototype.endGame = function (res) { clearInterval(this.timer); //清除定时器 $(".infoText").html(res + '<br>分数:' + 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信息的元素
<div class="game"> <div class="board b1"> </div> <div class="board b2"> </div> <div class="ball"></div> <div class="info"> //新增的地方 <h2 class="infoText">开始游戏</h2> <button class="start">点击这里</button> </div> <div class="grade">0</div> </div>复制代码
最下面我们调用一下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(角度)如图
这也就是数学中 向量 的概念
然后我们再看看我们的游戏:
显然比之前合理多了。
写完这篇文章已经 凌晨3点钟了。睡觉~~~~
谢谢各位
以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网
猜你喜欢:本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。