Написание небольшой игры с помощью jQuery

внешний интерфейс JavaScript игра jQuery

Сегодня я предлагаю вам небольшую игру

Ссылка на CodePen

Ссылка на источник облака кода Gitee

Требования: Знание концепций наследования 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; //更改原型链上的构造为自己的构造


Затем новые две доски

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



Затем мы заставляем мяч двигаться

Мы определяем метод обновления в цепочке прототипов Ball. двигать мяч

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, это означает, что мяч ударяется о верхнюю и нижнюю стенки


Затем мы вызываем функцию обновления шара каждые 30 мс. сделать свое местоположение обновленным

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
  })
};


Согласно нашим правилам игры, мяч касается верхней и нижней стенок, чтобы определить победителя или проигравшего. Когда он ударяется о верхнюю и нижнюю доски, он отскакивает назад.

Итак, мы определяем метод столкновения collide в цепочке прототипов GameObject.

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. в противном случае ложь

Дискриминант inRangeY: когда значение Y другого объекта больше вашегоYзначение и другой объектYзначение меньше вашегоYКогда значение + ваш рост, верните true. в противном случае ложь

Затем верните случай двух дискриминантов

Если оба верны, два объекта столкнулись


Таким образом мы определяем метод startGameMain для объекта Game. Представитель является основным корпусом нашего игрового контроллера.

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. Обновить координаты доски и пользовательский интерфейс

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 доски равным 0, а максимальный x равен ширине контейнера-ширине доски.

Итак, давайте перепишем метод обновления платы

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

<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');
};



Давайте подробнее рассмотрим эту функцию инициализации.

Прежде всего зафиксируем скорость на 10, это первое условие. Итак, мы сначала генерируем случайный угол:

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

1PI — 180 градусов, 2PI — 360 градусов.

Затем мы случайным образом десятичной дроби. Вы можете быть под любым углом в пределах 360 градусов


Далее мы можем по тригонометрическим функциям, cos и sin

sin - гипотенуза/противоположная сторона, а cos - гипотенуза/прилежащая сторона. Если мы знаем угол и длину, мы можем узнать, какова скорость XY.

Длина X = длина гипотенузы * Cos (угол)
Длина Y = длина гипотенузы * Sin (угол)

Как показано



Это понятие вектора в математике


Затем снова смотрим на нашу игру:



Явно разумнее, чем раньше.


Сейчас 3 часа ночи, когда я заканчиваю писать эту статью. спать~~~


Спасибо