Vue實現(xiàn)飛機大戰(zhàn)小游戲
使用 Vue 開發(fā)一個簡略版的飛機大戰(zhàn)小游戲
如題,假設你為了向更多訪問你博客的人展示你的技術,你決定小試身手開發(fā)一個飛機大戰(zhàn)小游戲。
功能: 開始游戲前用戶名必填,玩家可以發(fā)射子彈,敵軍與行星隨機出現(xiàn),鼠標可操控玩家移動,敵軍可發(fā)射子彈
一、實現(xiàn)思路
如題所述:
玩家可操控玩家飛機可發(fā)射子彈,敵軍與行星隨機生成;
這意味著我們需要一個單獨的玩家飛機dom,以及敵軍、行星與子彈 用 vue 循環(huán)生成的3個dom。
敵軍與行星生成后的dom的位置由數(shù)據(jù)里的 x 與 y 值決定。
按下空格時產(chǎn)生的子彈由當時按下空格鍵的時候的飛機的位置來決定。
敵軍隨機發(fā)射的子彈由當時發(fā)射子彈的敵軍的位置來決定。
游戲開始時用戶名必填,那么我們只需要在 Vue 實例里為該 input 綁定一個數(shù)據(jù),再為開始游戲按鈕綁定點擊事件。隨后計算用戶名的長度只要大于3,就調用游戲開始函數(shù)或初始化函數(shù)。
玩家鼠標操控移動飛機移動只需要為其父節(jié)點綁定鼠標移動事件,然后更改 player 里的 x 與 y 的數(shù)據(jù) (x與y的值不能小于0,x與y的值不能大于父節(jié)點的寬高) 并且賦予 玩家飛機即可。
擊毀敵軍只需要拿 子彈與敵軍 的 x,y 計算對比即可。
二、所需知識點
1. Vue 事件綁定
2. Vue 監(jiān)聽事件
3. Vue 計算屬性
4. Vue Style操作
三、實現(xiàn)步驟
第一步:創(chuàng)建 HTML 與 CSS 文件
HTML
<!DOCTYPE html> <html> ?? ?<head> ?? ??? ?<meta charset="utf-8"> ?? ??? ?<title>Vue 飛機大戰(zhàn)</title> ?? ??? ?<link rel="stylesheet" href="css/style.css" > ?? ?</head> ?? ?<body> ?? ??? ?<main> ?? ??? ??? ?- ?? ??? ??? ?<div class="game-plane"? ?? ??? ??? ??? ?@mousemove="touchmove" ?? ??? ??? ??? ?:style="{backgroundPosition:'0px '+ positionY +'px'}" ref='plane'> ?? ??? ??? ??? ? ?? ??? ??? ??? ?<div id="hit"> ?? ??? ??? ??? ??? ?<h2>擊毀:{{ hitCount }}</h2> ?? ??? ??? ??? ??? ?<h2>與敵機相撞:{{ boom }}</h2> ?? ??? ??? ??? ??? ?<h2>被擊中次數(shù):{{ HitTimes }}</h2> ?? ??? ??? ??? ??? ?<h2>用戶名:{{ username }}</h2> ?? ??? ??? ??? ?</div> ?? ??? ??? ??? ? ?? ??? ??? ??? ?<!-- 玩家 --> ?? ??? ??? ??? ?<img src="image/player.png" alt="player" id="p" :style="{top:p.y + 'px',left:p.x+'px'}"> ?? ??? ??? ??? ? ?? ??? ??? ??? ?<!-- 星球 --> ?? ??? ??? ??? ?<img v-for="(item,index) of plane.arr" :style="{top:item.y + 'px',left:item.x+'px'}" src="image/plane.png" alt="plane"> ?? ??? ??? ??? ? ?? ??? ??? ??? ?<!-- 敵軍 --> ?? ??? ??? ??? ?<img v-for="(item,index) of e.arr" :style="{top:item.y + 'px',left:item.x+'px'}" src="image/e.png" class="e" alt="e"> ?? ??? ??? ??? ? ?? ??? ??? ??? ?<!-- 子彈 --> ?? ??? ??? ??? ?<img v-for="(item,index) of bullets.arr" class="b" ?? ??? ??? ??? ? :style="{top:item.y + 'px',left:item.x+'px'}"? ?? ??? ??? ??? ? :src="item.tag == 'p' ? 'image/p_b.png' : 'image/e_b.png' "? ?? ??? ??? ??? ? alt="p_b"> ?? ??? ??? ??? ? ?? ??? ??? ?</div> ?? ??? ? ?? ??? ??? ?<!-- 開始面板 --> ?? ??? ??? ?<div class="alert" ref="alert"> ?? ??? ??? ??? ?<div class="content"> ?? ??? ??? ??? ??? ?<div class="left"> ?? ??? ??? ??? ??? ??? ?<h1>Vue 飛機大戰(zhàn)</h1> ?? ??? ??? ??? ??? ??? ?<p>作者:柴不是柴</p> ?? ??? ??? ??? ??? ??? ?<img :src="faceChange" class="face"> ?? ??? ??? ??? ??? ?</div> ?? ??? ??? ??? ??? ?<div class="right"> ?? ??? ??? ??? ??? ??? ?<input type="text" v-model="username" placeholder="請輸入你的名字"> ?? ??? ??? ??? ??? ??? ?<input type="submit" @click="startBtnClick" ?value="開始游戲"> ?? ??? ??? ??? ??? ?</div> ?? ??? ??? ??? ?</div> ?? ??? ??? ?</div> ?? ??? ?</main> ?? ??? ? ?? ??? ?<script src="js/vue.js"></script> ?? ??? ?<script src="js/data.js"></script> ?? ??? ?<script src="js/app.js"></script> ?? ?</body> </html>
CSS
* { ?? ?padding: 0; ?? ?margin: 0; } main { ?? ?display: flex; ?? ?justify-content: center; ?? ?align-items: center; ?? ?width: 100%; ?? ?height: 100vh; ?? ?background-color: #282828; } main .game-plane { ?? ?position: relative; ?? ?width: 1200px; ?? ?max-width: 1200px; ?? ?height: 900px; ?? ?background-image: url(../image/background.png); ?? ?background-size: 100% auto; ?? ?box-shadow: 0 2px 30px rgba(255,255,255,0.5); ?? ?overflow: hidden; } main .game-plane img { position: absolute; } .alert { ?? ?position: absolute; ?? ?top: calc(50% - 100px); ?? ?left: 0; ?? ?width: 100%; ?? ?height: 200px; ?? ?background: #FFF; ? ? box-shadow: 0 0 0 999em rgba(0, 0, 0, 0.5); } .alert .content { ?? ?display: grid; ?? ?grid-template-columns: 4fr 6fr; ?? ?grid-template-rows: 100%; ?? ?gap: 20px; ?? ?margin: 0 auto; ?? ?max-width: 1200px; ?? ?width: 100%; ?? ?height: 100%; } .alert .content .left { ?? ?display: flex; ?? ?flex-direction: column; ?? ?align-items: center; ?? ?justify-content: center; } .alert .content .left * { margin: 5px 0; } .alert .content .right { ?? ?display: flex; ?? ?flex-direction: column; ?? ?align-items: center; ?? ?justify-content: center; } .alert .content .right input { ?? ?width: 100%; ?? ?display: block; ?? ?box-sizing: border-box; ?? ?padding: 10px; } .e { transform: rotate(180deg); } .b { width: 30px; }#hit { ?? ?position: absolute; ?? ?top: 20px; ?? ?left: 20px; ?? ?color: #FFF; }
第二步:創(chuàng)建一個全局 data 文件
window.el = document.querySelector(".game-plane"); window.data = { ?? ?p : {// 玩家 Player ?? ??? ?w : document.querySelector("#p").offsetWidth, ?? ??? ?h : document.querySelector("#p").offsetHeight, ?? ??? ?x : el.offsetWidth / 2 - document.querySelector("#p").offsetWidth / 2, ?? ??? ?y : el.offsetHeight - document.querySelector("#p").offsetHeight ?? ?}, ?? ? ?? ?e : {// 敵機 enemy plane ?? ??? ?arr : [], ?? ??? ?speed : 6, ?? ?}, ?? ? ?? ?plane : { arr : [] },// 星球?? ? ?? ?bullets : { arr : [] },// 子彈 ?? ?hitCount : 0,// 擊中總數(shù) ?? ?boom : 0,// 碰撞次數(shù) ?? ?HitTimes : 0,// 被擊中次數(shù) ?? ?start : false,// 游戲是否開始 ?? ?positionY : 0,// 背景 Y 值 ?? ?timers : [],// 定時器 ?? ?face : "ordinary",// 表情 ?? ?username : "" // 玩家名 }
第三步:創(chuàng)建Vue 實例
var Game = new Vue({ ?? ?el : "main", ?? ?data, ?? ? ?? ?methods:{ ?? ??? ?startBtnClick() { ?? ??? ??? ?if ( this.username.length <= 2 ) return alert("用戶名不可少于3位字符哦!"); ?? ??? ??? ?this.init(); ?? ??? ?}, ?? ??? ? ?? ??? ?init() {// 初始化 ?? ??? ??? ?let _this = this; ?? ??? ??? ?this.start = true; ?? ??? ??? ?this.$refs.alert.style.display = "none"; ?? ??? ??? ? ?? ??? ??? ?this.createE(); ?? ??? ??? ?this.createPlane(); ?? ??? ??? ?this.timers.push( setInterval( this.bgMove,20 ) ) ?? ??? ??? ?this.timers.push( setInterval(function() { _this.move('bullets') }, 20 ) ) ?? ??? ?}, ?? ??? ? ?? ??? ?bgMove () { // 背景移動 順帶判斷玩家是否裝上敵軍 ?? ??? ??? ?this.positionY += 5;? ?? ??? ??? ?if ( this.hit_check(this.p) ) this.boom++; ?? ??? ?}, ?? ??? ? ?? ??? ?touchmove(){// 飛機移動 ?? ??? ??? ?let touch,x,y; ?? ??? ??? ?if ( !this.start ) return; ?? ??? ??? ? ?? ??? ??? ?if(event.touches) touch = event.touches[0]; ?? ??? ??? ?else touch = event; ?? ??? ??? ? ?? ??? ??? ?x = touch.clientX - this.$refs.plane.offsetLeft - this.p.w / 2; ?? ??? ??? ?y = touch.clientY - this.$refs.plane.offsetTop - this.p.h / 2; ?? ??? ??? ? ?? ??? ??? ?y = y < 0 ? 0 : y > (this.$refs.plane.offsetHeight - this.p.h) ? this.$refs.plane.offsetHeight - this.p.h : y; ?? ??? ??? ?x = x < 0 ? 0 : x > (this.$refs.plane.offsetWidth - this.p.w) ? this.$refs.plane.offsetWidth - this.p.w : x; ?? ??? ??? ? ?? ??? ??? ?this.p.x = x; ?? ??? ??? ?this.p.y = y; ?? ??? ?}, ?? ??? ? ?? ??? ?createE() { // 創(chuàng)建敵軍 ?? ??? ??? ?let _this = this,x; ?? ??? ??? ? ?? ??? ??? ?this.timers.push( setInterval( function() { ?? ??? ??? ??? ?x = Math.ceil( Math.random() * ( _this.$refs.plane.offsetWidth - 80 ) ); ?? ??? ??? ??? ?_this.build('e',{ x: x, y: 5 }) ?? ? ?? ??? ??? ?}, 1000 )); ?? ??? ??? ? ?? ??? ??? ?this.timers.push( setInterval( function() { _this.move('e') }, 20 )); ?? ??? ?}, ?? ??? ? ?? ??? ?createPlane() {// 創(chuàng)建行星 ?? ??? ??? ?let _this = this,x; ?? ??? ??? ? ?? ??? ??? ?this.timers.push( setInterval( function() { ?? ??? ??? ??? ?x = Math.ceil( Math.random() * ( _this.$refs.plane.offsetWidth - 80 ) ); ?? ??? ??? ??? ?_this.build('plane',{ x: x, y: 5 })? ?? ??? ??? ?}, 2000 )); ?? ??? ??? ? ?? ??? ??? ?this.timers.push( setInterval( function() { _this.move('plane') }, 20 )); ?? ??? ?}, ?? ??? ? ?? ??? ?createButter(table,e) {// 創(chuàng)建子彈 ?? ??? ??? ?if ( !this.start ) return; ?? ??? ??? ? ?? ??? ??? ?let bullter = { ?? ??? ??? ??? ?x:(e.x + (e.w ? e.w : 30) / 2), ?? ??? ??? ??? ?y:e.y - (e.h ? e.h : -30), ?? ??? ??? ??? ?speed : table == "p" ? -6 : 10, ?? ??? ??? ??? ?tag : table ?? ??? ??? ?}; ?? ??? ??? ? ?? ??? ??? ?this.build('bullets',bullter); ?? ??? ?}, ?? ??? ? ?? ??? ?build(table,data) {// 公共創(chuàng)建 ?? ??? ??? ?let _this = this; ?? ??? ??? ?this[table].arr.push( data ); ?? ??? ?}, ?? ??? ? ?? ??? ?move(table) {// 公共移動 ?? ??? ??? ?for( let i = 0; i < this[table].arr.length; i ++ ){ ?? ??? ??? ??? ?let e = this[table].arr[i], ?? ??? ??? ??? ??? ?math = Math.random() * 100, ?? ??? ??? ??? ??? ?speed = this[table].speed ? this[table].speed : 5; ?? ??? ??? ??? ? ?? ??? ??? ??? ?if ( table == 'bullets' ) speed = e.speed; ?? ??? ??? ??? ? ?? ??? ??? ??? ?e.y += speed; ?? ??? ??? ? ? ?? ??? ??? ??? ?if ( table !== 'bullets' ) {// 如果不是子彈dom的移動 ?? ??? ??? ??? ??? ?if( e.y > this.$refs.plane.offsetHeight - 55 ) this[table].arr.splice(i,1); ?? ??? ??? ??? ??? ? ?? ??? ??? ??? ??? ?if ( table == 'e' && math < 1 ) { this.createButter('e',e); } ?? ??? ??? ??? ?} else { ?? ??? ??? ??? ??? ?if ( e.tag == 'p' ) { ?? ??? ??? ??? ??? ??? ?if ( this.hit_check(e) ) this[table].arr.splice(i,1); ?? ??? ??? ??? ??? ??? ?else if ( e.y < 0 ) this[table].arr.splice(i,1); ?? ??? ??? ??? ??? ?} else { ?? ??? ??? ??? ??? ??? ?if ( this.hit(e,this.p) ) { ?? ??? ??? ??? ??? ??? ??? ?this[table].arr.splice(i,1); ?? ??? ??? ??? ??? ??? ??? ?this.HitTimes++; ?? ??? ??? ??? ??? ??? ?} ?? ??? ??? ??? ??? ??? ?else if ( e.y > this.$refs.plane.offsetHeight - 30 ) this[table].arr.splice(i,1); ?? ??? ??? ??? ??? ?} ?? ??? ??? ??? ?} ?? ??? ??? ?} ?? ??? ?}, ?? ??? ? ?? ??? ?hit_check(b) {// 是否擊毀敵軍 ?? ??? ??? ?for( let i = 0; i < this.e.arr.length; i ++ ){ ?? ??? ??? ??? ?if( this.hit(b,this.e.arr[i]) ){? ?? ??? ??? ??? ??? ?this.e.arr.splice(i,1); ?? ??? ??? ??? ??? ?this.hitCount++; ?? ??? ??? ??? ??? ?return true; ?? ??? ??? ??? ?} ?? ??? ??? ?} ?? ??? ?}, ?? ??? ? ?? ??? ?hit(b,e) {// 碰撞 ?? ??? ??? ?let d = this.judgeHit( b.x, b.y, e.x, e.y ); ?? ??? ??? ?if( d < 35 ) return true; ?? ??? ?}, ?? ??? ? ?? ??? ?judgeHit(x1, y1, x2, y2) {// 計算兩個點的距離差 ?? ??? ??? ?let a = x1 - x2, ?? ??? ??? ??? ?b = y1 - y2, ?? ??? ??? ??? ?result = Math.sqrt( Math.pow( a, 2) + Math.pow( b, 2 ) ); ?? ??? ??? ?return Math.round( result ); ?? ??? ?}, ?? ??? ? ?? ??? ?pause() {// 暫停 ?? ??? ??? ?this.start = false; ?? ??? ??? ?this.timers.forEach(element => { clearInterval(element); }) ?? ??? ?} ?? ?}, ?? ? ?? ?watch: { ?? ??? ?username () {// 監(jiān)聽玩家輸入事件 ?? ??? ??? ?if ( this.username.length > 2 ) this.face = "shy"; ?? ??? ??? ?else this.face = "ordinary"; ?? ??? ?} ?? ?}, ?? ?mounted(){ ?? ??? ?let _this = this; ?? ??? ?document.onkeyup = function(e) { ?? ??? ??? ?( e.keyCode == 32 ) && _this.createButter("p",_this.p); ?? ??? ??? ?// ( e.keyCode == 80 ) && _this.pause(); ?? ??? ?} ?? ?}, ?? ? ?? ?computed:{ faceChange() { return "image/"+this.face + ".png"; } } });
以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持腳本之家。

vue 本地環(huán)境跨域請求proxyTable的方法

vue 使用axios 數(shù)據(jù)請求第三方插件的使用教程詳解

vue按住shift鍵多選方式(以element框架的table為例)