V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
Liulang007
V2EX  ›  Vue.js

尝试用 Vue.js 开发网页小游戏的过程

  •  
  •   Liulang007 · 2020-04-24 13:00:14 +08:00 · 490 次点击
    这是一个创建于 1673 天前的主题,其中的信息可能已经有所发展或是发生改变。

    准备

    首先去官方下载并安装 VSCODE,下载地址 https://code.visualstudio.com/。安装后打开会发现是英文版的,需要去安装插件来汉化。具体是在扩展插件搜索chinese,选择第一个安装然后重启软件,这样打开就是中文界面了。

    网页

    去这个网站 https://getbootstrap.com/docs/4.4/examples/album/ 将源代码 Copy 下来,然后打开 VSCODE 选择项目文件夹

    1587690221.png 在你的项目目录新建个src文件夹用来存放源代码,并在src下新建个index.html文件,将复制的代码拷贝进去

    1587690519.png 如果想要实时看到页面可以在扩展插件中安装个live server作为本地服务器

    1587690813.png 安装后在回到项目文件夹里的index.html文件,右键选择Open with live server就可以查看了,但是你会发现样式乱了这时候需要去修改一下代码,将代码第15行修改成下面的样子

    <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/css/bootstrap.min.css" integrity="sha384-Vkoo8x4CGsO3+Hhxv8T/Q5PaXtkKtu6ug5TOeNV6gBiFeWPGFN9MuhOf23Q9Ifjh" crossorigin="anonymous">
    

    保存后再次打开网页就好了

    1587691137.png 但是你会发现导航按钮好像不能使用这是因为没用正确的引用 js,还需要修改一下代码。替换</body>前面的三个<script>标签,替换代码如下:

    <script src="https://code.jquery.com/jquery-3.4.1.slim.min.js" integrity="sha384-J6qa4849blE2+poT4WnyKhv5vZF5SrPo0iEjwBvKU7imGFAV0wwj1yYfoRSJoZ+n" crossorigin="anonymous"></script>
    <script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/umd/popper.min.js" integrity="sha384-Q6E9RHvbIyZFJoft+2mJbHaEWldlvI9IOYy5n3zV9zzTtmI3UksdQRVvoxMfooAo" crossorigin="anonymous"></script>
    <script src="https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/js/bootstrap.min.js" integrity="sha384-wfSDF2E50Y2D1uUdj0O3uMBJnjuUD4Ih7YwaYd1iqfktj0Uod8GCExl3Og8ifwB6" crossorigin="anonymous"></script>
    

    这样保存之后导航菜单就可以使用了。接下来新建一个img文件夹在src目录,并放入这张图片

    forest 再新建一个style.css样式文件在src目录,填入如下内容

    #dog, #fox{
        position: absolute;
        font-size: xx-large;
    }
    
    #forest{
        background-image: url("./img/forest.jpg");
        height: 160px;
    }
    
    span.arrow-key {
        font-size: xx-large;
        cursor: pointer
    }
    

    开始

    现在正式开始进入 Vue 开发,这是 Vue 的开发文档 https://cn.vuejs.org/v2/guide/。在index.html</body>前面添加

    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
    <script src="custom.js"></script>
    

    代码中 custom.js 文件需要在项目中自己建一个,接下来替换<div class="album py-5 bg-light">

    <div class="album py-5 bg-light" id="app"> 
    

    <div id="forest">...</div>添加如下内容

    <span id="dog" :style="{left: dog.x + 'px', top: dog.y + 'px'}">🐶</span>
    

    顺便把这里修改下

    <small class="text-muted">抓捕时间:{{ dog.抓捕时间 }}</small>
    

    文件custom.js内容如下

    var app = new Vue({
        el: '#app',
        data: {
            forest: {
                width: $('#forest')[0].offsetWidth,
                height: $('#forest')[0].offsetHeight
            },
            dog: {
                width: $('#dog')[0].offsetWidth,
                height: $('#dog')[0].offsetHeight,
                x: 0,
                y: 0,
                step: {
                    x: 10,
                    y: 2
                },
                抓捕时间: 0
            }
        },
        methods: {
            move_dog(){
                this.dog.x += this.dog.step.x
                this.dog.y += this.dog.step.y
                this.dog.抓捕时间 = Math.round((this.dog.抓捕时间 + 0.1) * 10) / 10
            }
        },
        mounted: function(){
            this.timer1 = setInterval(this.move_dog, 100)
        },
        watch: {
            'dog.x': function(){
                let x = this.dog.x
                let w = this.forest.width
                if(x <= 0 || x >= (w - this.dog.width)){
                    this.dog.step.x = - this.dog.step.x
                }
            },
            'dog.y': function(){
                let y = this.dog.y
                let h = this.forest.height
                if(y <= 0 || y >= (h - this.dog.height)){
                    this.dog.step.y = - this.dog.step.y
                }
            }
        }
    })
    

    保存后预览就会发现狗狗动起来了。接下来实现按键的功能,将操作说明的内容改为

    <p class="card-text"> 操作说明: 点击
    <span class="arrow-key" @click="change_dog_direct(37)">⬅</span>
    <span class="arrow-key" @click="change_dog_direct(39)">➡</span>
    <span class="arrow-key" @click="change_dog_direct(38)">⬆</span>
    <span class="arrow-key" @click="change_dog_direct(40)">⬇</span> 控制狗狗方向 </p> 
    

    然后将js的内容改成

    var app = new Vue({
        ...
        methods: {
            ...
            change_dog_direct(k) {
                if (k === 37 && this.dog.step.x > 0 || k === 39 && this.dog.step.x < 0) {
                    this.dog.step.x = -this.dog.step.x
                }
                if (k === 38 && this.dog.step.y > 0 || k === 40 && this.dog.step.y < 0) {
                    this.dog.step.y = -this.dog.step.y
                }
            },
            change_dog_direct_keyboard(event) {
                this.change_dog_direct(event.keyCode)
            }
        },
        mounted: function(){
            ...
            window.addEventListener('keyup', this.change_dog_direct_keyboard)
        },
        ...
    })
    

    保存后就会发现可以通过键盘或者点击图标来控制狗狗移动了。接下来要在森林中添加狐狸,在狗狗图标下添加

    <span id="fox" :class="fox.class" :style="{ left: fox.x + 'px', top: fox.y + 'px'}">🦊</span>
    

    并且添加动画样式文件

    <link href="https://cdn.bootcss.com/animate.css/3.7.2/animate.css" rel="stylesheet">
    

    js文件定义狐狸对象,并且让狐狸随机移动且“得瑟起来”

    var app = new Vue({
        ...
        data: {
            ...
            fox: {
                width: $('#fox')[0].offsetWidth,
                height: $('#fox')[0].offsetHeight,
                x: 0,
                y: 100,
                class: ''
            },
        },
        methods: {
            ...
            random_fox() {
                this.fox.x = Math.ceil(Math.random() * this.forest.width / 2)
                this.fox.y = Math.ceil(Math.random() * (this.forest.height - this.fox.height))
                this.fox.class = this.fox.class ? '': 'animated jello'
            },
        },
        mounted: function(){
            this.timer1 = setInterval(this.move_dog, 100)
            this.timer2 = setInterval(this.random_fox, 1000)
            window.addEventListener('keyup', this.change_dog_direct_keyboard)
        },
        ...
    })
    

    可以看到动画其效果了。那么继续接下来就是如何抓捕狐狸,我们需要在js文件中添加功能

    var app = new Vue({
        ...
        data: {
            ...
            dog: {
                ...
                与狐狸的距离: 999,
                抓捕成功: false,
                class: ''
            },
            ...
        },
        methods: {
            move_dog(){
                if (this.dog.抓捕成功) return
                ...
                this.dog.与狐狸的距离 = getDistanceBetweenTwoPoints(
                    this.dog.x, 
                    this.dog.y,
                    this.fox.x,
                    this.fox.y
                )
            },
            ...
            bounce_dog() {
                if (this.dog.抓捕成功) {
                    this.dog.class = this.dog.class ? '' : 'animated bounce'
                }
            },
            ...
            random_fox() {
                if (this.dog.抓捕成功) return
                ...
            },
        },
        mounted: function(){
            this.timer1 = setInterval(this.move_dog, 100)
            this.timer2 = setInterval(this.random_fox, 1000)
            this.timer3 = setInterval(this.bounce_dog, 2000);
            window.addEventListener('keyup', this.change_dog_direct_keyboard)
        },
        watch: {
            ...
            'dog.与狐狸的距离': function(val) {
                let min_d = this.dog.width / 2 + this.fox.width / 2
                if(val < min_d){
                    this.dog.抓捕成功 = true
                }
            },
            'dog.抓捕成功': function(val) {
                if (val) {
                    this.fox.class = 'animated rotateOut delay-2s'
                } else {
                    this.fox.class = ''
                    this.dog.class = ''
                }
            }
        }
    })
    
    //计算平面中两点距离
    function getDistanceBetweenTwoPoints(x1, y1, x2, y2) {
        var a = x1 - x2;
        var b = y1 - y2;
    
        // c^2 = a^2 + b^2
        // a^2 = Math.pow(a, 2)
        // b^2 = Math.pow(b, 2)
        var result = Math.sqrt(Math.pow(a, 2) + Math.pow(b, 2));
    
        return Math.round(result);
    }
    

    保存刷新一下界面,可以看到当狗狗碰到狐狸的时候会被捕获成功监听器捕获到。接下来开发再来一次功能,把html代码中的再来一次按钮修改成

    <button type="button" :class="btn_play_again.class" @click="play_again" class="btn btn-sm btn-outline-secondary">
    	<span v-if=" !dog.抓捕成功 ">正在抓捕 。。。</span>
    	<span v-if=" dog.抓捕成功 "> 抓捕成功!再来一次</span>
    </button> 
    

    然后是js文件需要为再来一次添加功能

    var app = new Vue({
       ...
        data: {
            ...
            btn_play_again: {
                class: ''
            }
        },
        methods: {
            ...
            bounce_dog() {
                if (this.dog.抓捕成功) {
                    this.dog.class = this.dog.class ? '' : 'animated bounce'
                    this.btn_play_again.class = this.btn_play_again.class ? '' : 'animated swing delay-1s'
                }
            },
    		...
            play_again() {
                if (!this.dog.抓捕成功) return
    
                this.dog.抓捕成功 = false
                this.dog.抓捕时间 = 0
                this.fox.x = 0
                this.fox.y = 100
            }
        },
        ...
    })
    
    ...
    

    然后开发记录抓捕时间功能,下面我直接贴出完整的js代码和html代码

    index.html

    <!DOCTYPE html>
    <html lang="en">
     <head> 
      <meta charset="utf-8" /> 
      <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no" /> 
      <meta name="description" content="" /> 
      <meta name="author" content="Mark Otto, Jacob Thornton, and Bootstrap contributors" /> 
      <meta name="generator" content="Jekyll v3.8.6" /> 
      <title>🐶 Dog & 🦊 Fox - 美图博客</title>
      <link rel="canonical" href="https://getbootstrap.com/docs/4.4/examples/album/" /> 
      <link href="https://cdn.bootcss.com/animate.css/3.7.2/animate.css" rel="stylesheet" /> 
      <!-- Bootstrap core CSS --> 
      <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/css/bootstrap.min.css" integrity="sha384-Vkoo8x4CGsO3+Hhxv8T/Q5PaXtkKtu6ug5TOeNV6gBiFeWPGFN9MuhOf23Q9Ifjh" crossorigin="anonymous" /> 
      <!-- Favicons --> 
      <meta name="theme-color" content="#563d7c" /> 
      <style>
          .bd-placeholder-img {
            font-size: 1.125rem;
            text-anchor: middle;
            -webkit-user-select: none;
            -moz-user-select: none;
            -ms-user-select: none;
            user-select: none;
          }
    
          @media (min-width: 768px) {
            .bd-placeholder-img-lg {
              font-size: 3.5rem;
            }
          }
        </style> 
      <!-- Custom styles for this template --> 
      <link href="style.css" rel="stylesheet" /> 
     </head> 
     <body> 
      <header> 
       <div class="collapse bg-dark" id="navbarHeader"> 
        <div class="container"> 
         <div class="row"> 
          <div class="col-sm-8 col-md-7 py-4"> 
           <h4 class="text-white">故事</h4> 
           <p class="text-muted">通常,人们认为,狗狗是我们人类的朋友,而狐狸则相反,它代表着奸诈,狡猾,人们都想除掉它,让美丽的森林恢复宁静 ... 于是人们派出了狗狗,开始了一场铲除邪恶的战斗 ...</p> 
          </div> 
         </div> 
        </div> 
       </div> 
       <div class="navbar navbar-dark bg-dark shadow-sm"> 
        <div class="container d-flex justify-content-between"> 
         <a href="#" class="navbar-brand d-flex align-items-center"> 
          <svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" aria-hidden="true" class="mr-2" viewbox="0 0 24 24" focusable="false"> 
           <path d="M23 19a2 2 0 0 1-2 2H3a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h4l2-3h6l2 3h4a2 2 0 0 1 2 2z" /> 
           <circle cx="12" cy="13" r="4" /> 
          </svg> <strong>🐶 Dog & 🦊 Fox</strong> </a> 
         <button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarHeader" aria-controls="navbarHeader" aria-expanded="false" aria-label="Toggle navigation"> <span class="navbar-toggler-icon"></span> </button> 
        </div> 
       </div> 
      </header> 
      <main role="main"> 
       <section class="jumbotron text-center"> 
        <div class="container"> 
         <h1>通过游戏学编程</h1> 
         <p class="lead text-muted">这是一个由 Vue.js 开发的游戏小案例。课程链接 https://www.bilibili.com/video/BV1V7411R7dP?p=5</p> 
         <p> <a href="https://www.meitubk.com/" class="btn btn-primary my-2">访问我的博客</a></p> 
        </div> 
       </section> 
       <div class="album py-5 bg-light" id="app"> 
        <div class="container"> 
         <div class="row"> 
          <div class="col-md-12"> 
           <div class="card mb-4 shadow-sm"> 
            <div id="forest"> 
             <span id="dog" :class="dog.class" :style="{left: dog.x + 'px', top: dog.y + 'px'}">🐶</span> 
             <span id="fox" :class="fox.class" :style="{left: fox.x + 'px', top: fox.y + 'px'}">🦊</span> 
            </div> 
            <div class="card-body"> 
             <p class="card-text"> 操作说明: 点击 <span class="arrow-key" @click="change_dog_direct(37)">⬅</span> <span class="arrow-key" @click="change_dog_direct(39)">➡</span> <span class="arrow-key" @click="change_dog_direct(38)">⬆</span> <span class="arrow-key" @click="change_dog_direct(40)">⬇</span> 控制狗狗方向 </p> 
             <div class="d-flex justify-content-between align-items-center"> 
              <div class="btn-group"> 
               <button type="button" :class="btn_play_again.class" @click="play_again" class="btn btn-sm btn-outline-secondary"> <span v-if=" !dog.抓捕成功 ">正在抓捕 。。。</span> <span v-if=" dog.抓捕成功 "> 抓捕成功!再来一次</span> </button> 
              </div> 
              <small class="text-muted">抓捕时间:{{ dog.抓捕时间 }}</small> 
             </div> 
            </div> 
           </div> 
          </div> 
         </div> 
         <div class="row"> 
          <div class="col-md-12"> 
           <table class="table table-striped"> 
            <thead> 
             <tr> 
              <th>No.</th> 
              <th>抓捕时间(秒)</th> 
             </tr> 
            </thead> 
            <tbody> 
             <tr v-for="(seconds, index) of dog.logs"> 
              <td>{{index+1}}</td> 
              <td>{{seconds}}</td> 
             </tr> 
            </tbody> 
            <tfoot> 
             <tr> 
              <td>平均时间:</td> 
              <td>{{dog.平均抓捕时间}}</td> 
             </tr> 
            </tfoot> 
           </table> 
          </div> 
         </div> 
        </div> 
       </div> 
      </main> 
      <footer class="text-muted"> 
       <div class="container py-4"> 
        <p class="float-right"> <a href="#">⬆</a> </p> 
        <p>祝您玩得愉快。</p> 
        <p>www.meitubk.com</p> 
       </div> 
      </footer> 
      <script src="https://code.jquery.com/jquery-3.4.1.slim.min.js" integrity="sha384-J6qa4849blE2+poT4WnyKhv5vZF5SrPo0iEjwBvKU7imGFAV0wwj1yYfoRSJoZ+n" crossorigin="anonymous"></script> 
      <script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/umd/popper.min.js" integrity="sha384-Q6E9RHvbIyZFJoft+2mJbHaEWldlvI9IOYy5n3zV9zzTtmI3UksdQRVvoxMfooAo" crossorigin="anonymous"></script> 
      <script src="https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/js/bootstrap.min.js" integrity="sha384-wfSDF2E50Y2D1uUdj0O3uMBJnjuUD4Ih7YwaYd1iqfktj0Uod8GCExl3Og8ifwB6" crossorigin="anonymous"></script> 
      <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script> 
      <script src="custom.js"></script>  
     </body>
    </html>
    

    custom.js

    var app = new Vue({
        el: '#app',
        data: {
            forest: {
                width: $('#forest')[0].offsetWidth,
                height: $('#forest')[0].offsetHeight
            },
            dog: {
                width: $('#dog')[0].offsetWidth,
                height: $('#dog')[0].offsetHeight,
                x: 0,
                y: 0,
                step: {
                    x: 10,
                    y: 2
                },
                抓捕时间: 0,
                与狐狸的距离: 999,
                抓捕成功: false,
                class: '',
                平均抓捕时间: 0,
                logs: []
            },
            fox: {
                width: $('#fox')[0].offsetWidth,
                height: $('#fox')[0].offsetHeight,
                x: 0,
                y: 100,
                class: ''
            },
            btn_play_again: {
                class: ''
            }
        },
        methods: {
            move_dog(){
                if (this.dog.抓捕成功) return
    
                this.dog.x += this.dog.step.x
                this.dog.y += this.dog.step.y
                this.dog.抓捕时间 = Math.round((this.dog.抓捕时间 + 0.1) * 10) / 10
                this.dog.与狐狸的距离 = getDistanceBetweenTwoPoints(
                    this.dog.x, 
                    this.dog.y,
                    this.fox.x,
                    this.fox.y
                )
            },
            change_dog_direct(k) {
                if (k === 37 && this.dog.step.x > 0 || k === 39 && this.dog.step.x < 0) {
                    this.dog.step.x = -this.dog.step.x
                }
                if (k === 38 && this.dog.step.y > 0 || k === 40 && this.dog.step.y < 0) {
                    this.dog.step.y = -this.dog.step.y
                }
            },
            change_dog_direct_keyboard(event) {
                this.change_dog_direct(event.keyCode)
            },
    
            bounce_dog() {
                if (this.dog.抓捕成功) {
                    this.dog.class = this.dog.class ? '' : 'animated bounce'
                    this.btn_play_again.class = this.btn_play_again.class ? '' : 'animated swing delay-1s'
                }
            },
    
            random_fox() {
                if (this.dog.抓捕成功) return
    
                this.fox.x = Math.ceil(Math.random() * this.forest.width / 2)
                this.fox.y = Math.ceil(Math.random() * (this.forest.height - this.fox.height))
                this.fox.class = this.fox.class ? '': 'animated jello'
            },
    
            play_again() {
                if (!this.dog.抓捕成功) return
    
                this.dog.抓捕成功 = false
                this.dog.抓捕时间 = 0
                this.fox.x = 0
                this.fox.y = 100
            }
        },
        mounted: function(){
            this.timer1 = setInterval(this.move_dog, 100)
            this.timer2 = setInterval(this.random_fox, 1000)
            this.timer3 = setInterval(this.bounce_dog, 2000);
            window.addEventListener('keyup', this.change_dog_direct_keyboard)
        },
        watch: {
            'dog.x': function(){
                let x = this.dog.x
                let w = this.forest.width
                if(x <= 0 || x >= (w - this.dog.width)){
                    this.dog.step.x = - this.dog.step.x
                }
            },
            'dog.y': function(){
                let y = this.dog.y
                let h = this.forest.height
                if(y <= 0 || y >= (h - this.dog.height)){
                    this.dog.step.y = - this.dog.step.y
                }
            },
            'dog.与狐狸的距离': function(val) {
                let min_d = this.dog.width / 2 + this.fox.width / 2
                if(val < min_d){
                    this.dog.抓捕成功 = true
                    this.dog.logs.push(this.dog.抓捕时间)
                }
            },
            'dog.抓捕成功': function(val) {
                if (val) {
                    this.fox.class = 'animated rotateOut delay-2s'
                } else {
                    this.fox.class = ''
                    this.dog.class = ''
                }
            },
            'dog.logs': function(val) {
                let sum = 0
                for (s of val) sum += s
                this.dog.平均抓捕时间 = Math.round(sum / val.length * 100) / 100
            }
        }
    })
    
    //计算平面中两点距离
    function getDistanceBetweenTwoPoints(x1, y1, x2, y2) {
        var a = x1 - x2;
        var b = y1 - y2;
    
        // c^2 = a^2 + b^2
        // a^2 = Math.pow(a, 2)
        // b^2 = Math.pow(b, 2)
        var result = Math.sqrt(Math.pow(a, 2) + Math.pow(b, 2));
    
        return Math.round(result);
    }
    

    这样一来这个小游戏就开发完成了!

    预览

    如果想要预览该项目可以在 https://www.meitubk.com/my/demo1/ 此链接访问。

    本文章是根据 https://www.bilibili.com/video/BV1V7411R7dP?p=10 教程所记录的笔记。

    目前尚无回复
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   1081 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 26ms · UTC 18:55 · PVG 02:55 · LAX 10:55 · JFK 13:55
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.