---
# System prepended metadata

title: 物件導向JS繼承 - 遊戲實作
tags: [jquery, SASS, HTML & CSS, JavaScript]

---


# 物件導向JS繼承 - 遊戲實作

### **撰寫程式：HTML ｜ CSS（SASS） ｜ JS（jQuery ∕ 原生JS）**
###### codepen：https://codepen.io/liu_0821/pen/XWYZgRV

![](https://i.imgur.com/AuK70wH.jpg)

## HTML
> ###### 原生HTML撰寫

```
<div class="game"> <!--遊戲主體-->
  <div class="board b1"></div>
  <div class="board b2"></div>
  <div class="ball"></div>
  <div class="info">
    <h2 class="infoText">Start Game</h2>
    <button class="start" onclick = "newGame.startGame()">開始</button>
  </div>
  <div class="grade"></div>
</div>
```
****
## CSS（SASS）
> ###### 與原生CSS不同之處，原生CSS使用大括弧{}套用CSS特性，SASS則利用縮排區分HTML之間的層級關係。
```
*
 font-family: "微軟正黑體"
 font-weight: 900

html,body
  background-color: #222
  color: white
  display: flex
  justify-content: center
  align-items: center
  height: 100%
  margin: 0

.game
  width: 500px
  height: 500px
  position: relative 
  border: 5px solid white
  overflow: hidden
  
  .board
    background-color: #ffab2d
  .ball
    background-color: white
  .info
    width: 100%
    height: 100%
    position: absolute
    left: 0
    top: 0
    background-color: #222
    color: white
    display: flex
    justify-content: center
    align-items: center
    //垂直排列
    flex-direction: column 
    
    .start
      width: 80px 
      height: 50px
      border-radius: 25px
      border: 1px solid white
      font-size: 18px
      background-color: #222
      color: white
      cursor: pointer
      
  .grade
    padding: 10px
  
```
****
## JS（jQuery ∕ 原生JS）
> ###### 使用原生JS與jQuery撰寫，利用JS物件導向的繼承來作為整體程式開發的主軸。
###### 遊戲物件與繼承範圍
```
let gameObject = function(position,size,selector){
  this.$el = $(selector); 
  this.position = position;
  this.size = size ;
  this.$el.css("position","absolute");
  
  this.updateCss(); // 把初始化的條件更新到螢幕上
  
};

// 更新遊戲物件
gameObject.prototype.updateCss = function(){
  this.$el.css('left',this.position.x);
  this.$el.css('top',this.position.y);
  this.$el.css('width',this.size.width);
  this.$el.css('height',this.size.height);
};

// 計算遊戲碰撞
gameObject.prototype.collide = function(otherObject){
  // this => 與其他物件
  var inRangeX = otherObject.position.x > this.position.x && otherObject.position.x < this.position.x + this.size.width; 
  var inRangeY = otherObject.position.y > this.position.y && otherObject.position.y < this.position.y + this.size.height; 
  
  // 回傳 是否有同時滿足在他的範圍內
  return inRangeX && inRangeY
};

```
###### 球體物件與更新
```
// 球球物件
let Ball = function(){
  this.size = {width:15,height:15}
  this.position = {x:250 ,y:250}
  this.velocity = {x:-3,y:5} // 球體速度
  
  // 繼承三步驟
  //1.呼叫初始化函數
  gameObject.call(this,this.position,this.size,".ball") 
}
//2.讓ball可以使用gameObject的函數
Ball.prototype = Object.create(gameObject.prototype);
//3.將建構函數返回到自己原本建立的函數
Ball.prototype.constructor = Ball.constructor;

// 球球速度更新
Ball.prototype.update = function(){
  this.position.x += this.velocity.x;
  this.position.y += this.velocity.y;
  this.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
  }
};
// 球球初始化
Ball.prototype.init = function(){
  this.position = {x:250 ,y:250}
  
  // 球體速度 改成隨機速度 Math.random()原本是0~1的之間亂數
  var speed = 8;
  var angle = Math.random()*Math.PI*2
  this.velocity = {
    x: speed*Math.cos(angle),
    y: speed*Math.sin(angle)
  } 
  
  this.update();
};

// 建立球球
let newBall = new Ball()
// setInterval(function(){
//   newBall.update() //呼叫球球移動
// },30)

```
###### 設立板子物件
```
let Board = function (position,selector){
  this.size = {width:100,height:15}
  
  // 1.呼叫初始化函數
  gameObject.call(this,position,this.size,selector) 
};
// 2.讓Board可以使用gameObject的函數
Board.prototype = Object.create(gameObject.prototype);
// 3.將建構函數返回到自己原本建立的函數
Board.prototype.constructor = Board.constructor;
// 檢查board1的板子不超出邊界
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();
};

// 建立板子
let board1 = new Board(
  { x : 0 , y : 30},".b1"
);

let board2 = new Board(
  { x : 0 , y : 455},".b2"
);

```
###### 遊戲開始物件與綁定鍵盤事件
```
let Game = function(){
  this.timer = null;
  this.grade = 0 ;
  
  // 執行鍵盤事件
  this.initControl();
  this.control = {};  // 新增物件管理鍵盤按的變數
}

// 使用者控制 綁定鍵盤事件
Game.prototype.initControl = function(){
  let _this = this;
  $(window).keydown(function(evt){
    _this.control[evt.key] = true ;
    console.log(_this.control)
  });
  $(window).keyup(function(evt){
    _this.control[evt.key] = false ;
    console.log(_this.control)
  });
}

//設定遊戲開始之前的倒數
Game.prototype.startGame = function(){
  var _this = this ;
  var time = 3;
  this.grade = 0; // 初始分數為0
  newBall.init(); //球球初始化
  $("button").hide();
  var timer = setInterval(function(){
    $(".infoText").text(time);
    time--;
    if(time<0){
      clearInterval(timer)
      $(".info").hide();
      _this.startGameMain()
    }
  },1000);
};
// 建立遊戲函數
Game.prototype.startGameMain = function(){
  let _this = this; //代表game的this
  
  // 偵測球體碰撞、輸贏狀態
  this.timer = setInterval(function(){
    // 判斷板子有無碰撞到球
    if(board1.collide(newBall)){
      console.log("hit 1")
      // 打到後回彈
      newBall.velocity.y = -newBall.velocity.y;
      
      //打到板子後球體速度會變化
      newBall.velocity.x *= 1.1;
      newBall.velocity.y *= 1.1;
      newBall.velocity.x += 0.5-Math.random();
      newBall.velocity.y += 0.5-Math.random();
    }
    if(board2.collide(newBall)){
      console.log("hit 2")
      newBall.velocity.y = -newBall.velocity.y;
      _this.grade += 10;
    }
    
    // 判斷有無撞到邊界
    if(newBall.position.y < 0){
      console.log("Board 1 lose")
      _this.endGame("computer lose")
    }
    if(newBall.position.y > 500){
      console.log("Board 2 lose")
      _this.endGame("you lose")
    }
    
    // 判斷鍵盤按鍵
    if(_this.control["ArrowLeft"]){
      board2.position.x -= 12;
    }
    if(_this.control["ArrowRight"]){
      board2.position.x += 12;
    }
    
    // 上方板子移動(以中心點來判斷，如果球在右邊向右跑，反之)
    // 如果滿足條件就+8，反之+0
    board1.position.x += newBall.position.x > board1.position.x + board1.size.width/2 ? 12:0 ;
    board1.position.x += newBall.position.x < board1.position.x + board1.size.width/2 ? -12:0 ;
    
    // 呼叫板子更新css
    board1.update() ;
    board2.update() ;
    
    newBall.update();
    
    //遊戲內更新自己的成績
    $(".grade").text(_this.grade)
  },30)
};

// 遊戲結束計算
Game.prototype.endGame = function(res){
  clearInterval(this.timer)
  $(".info").show();
   $("button").show();
  $(".infoText").html(res + "<br>分數:" + this.grade);
};

let newGame = new Game();
//newGame.startGame(); // 呼叫遊戲開始
```
##### ヽ(∀ﾟ )人(ﾟ∀ﾟ)人( ﾟ∀)人(∀ﾟ )人(ﾟ∀ﾟ)人( ﾟ∀)ﾉヽ(∀ﾟ )人(ﾟ∀ﾟ)人( ﾟ∀)人(∀ﾟ )人(ﾟ∀ﾟ)人( ﾟ∀)人(∀ﾟ )人( ﾟ∀)人

##### 以上 如果註解哪裡有錯誤或有問題，歡迎提出來一起討論~~~~


---
