vue 一次失败的dom游戏制作

本来打算使用vue做一个简单的飞机游戏

不过实践中发现dom性能貌似有点差,元素过多时卡顿很明显

还是以后看看canvas吧

PS:

貌似是把计算属性和方法搞混了,元素的位置是用的函数进行计算。。。这种方法可能效率比较差吧

项目结构

辅助工具类,子弹,飞机和小球

在主页面分别引入这几个类,然后调用类中 的方法控制元素位置,并刷新视图

类里面包括基本数据,和操作方法

注意设置interval时,this的指向问题,闭包!!!!!!

直接赋值一个成员函数,则该函数在执行时的指向是windows

import {REFRESH_INTERVAL, HEIGHT, Width} from "./config";

class Ball {
  // 位置,大小,类型,速度,方向是度数,向下为0,顺时针增加
  constructor(x = 0, y = 0, size = 20, type = 0, direction = 0, speed = 10,) {
    this.x = x
    this.y = y
    this.size = size
    this.type = type
    this.speed = speed
    this.direction = direction
    // 闭包问题,下面这种写法是有问题的,在执行move时,this的指向已经变化为windows
    // 所以变化不会生效
    // setInterval(
    //   this.move, 100
    // )

    this.start()

  }

  move() {
    this.x -= this.speed * Math.sin(this.direction * Math.PI / 180)
    this.y -= this.speed * Math.cos(this.direction * Math.PI / 180)
  }


  start() {
    this.inv = setInterval(
      () => this.move(), REFRESH_INTERVAL
    )
  }

  stop() {
    clearInterval(this.inv)
  }

  isDestory() {
    return this.x >= Width || this.x <= 0 || this.y <= 0 || this.y >= HEIGHT
  }
}


export default Ball

全局添加按键事件,在div上添加的监听器失效了,只能在body上添加

      document.body.onkeydown = this.keyDown

使用watch深度观察数据,数据变化则刷新视图,检查是否碰撞和越界

注意绑定对象的方法使用的是字符串,也可以使用普通函数或者箭头函数,注意this指向的不是vue的实例对象,在这里踩过坑。。。。

    data() {
      return {
        balls: [],
        bullets: [],
        plane: new Plane(0, 0, 2),
        clientHeight: 0,
        clientWidth: 0,
      }
    },
    watch: {
      plane: {
        handler: 'refresh',
        deep: true,
      },
      balls: {
        handler: 'refresh',
        deep: true,
      },
      bullets: {
        handler: 'refresh',
        deep: true,
      }
    },

通过code获取触发的键名,触发键盘事件

      keyDown(e) {
        console.log(e.code)
        if (e.code == 'ArrowUp') {
          this.move(0)
        } else if (e.code == 'ArrowRight') {
          this.move(1)
        } else if (e.code == 'ArrowDown') {
          this.move(2)
        } else if (e.code == 'ArrowLeft') {
          this.move(3)
        } else if (e.code == 'Space') {
          this.shoot()
        } else if (e.code == 'Enter') {
          this.addBallRandom()
        }
      },

主页面,控制面板也是 也问题。。。

按钮的话有点丑,应该试试王者荣耀的那种移动按钮。。。不知道能不能找到类似的库

<template>
  <div class="main" ref="main">

    <div class="bullet" v-for="b in bullets" :style="getStyle(b)"></div>
    <div class="ball" v-for="b in balls" :style="getBallStyle(b)"></div>
    <!--<div class="ball" :style="getBallStyle(ball)"></div>-->
    <img src="../assets/plane.svg" ref="plane" class="plane" :style="getStyle(plane)">

    <!--<div class="control">-->
    <!--<div class="btn-group">-->
    <!--<button @click="move(0)">U</button>-->
    <!--<button @click="move(1)">R</button>-->
    <!--<button @click="move(2)">D</button>-->
    <!--<button @click="move(3)">L</button>-->
    <!--</div>-->

    <!--<div class="action">-->
    <!--<button @click="shoot">shoot</button>-->
    <!--<button @click="addBallRandom">add</button>-->
    <!--</div>-->
    <!--</div>-->
  </div>
</template>

<script>

  import Ball from '../util/Ball'
  import Bullet from '../util/Bullet'
  import Plane from '../util/Plane'
  import _ from 'lodash'
  import {BALL_COLORS, REFRESH_INTERVAL, HEIGHT, Width} from "../util/config";

  export default {
    name: "game-card",
    data() {
      return {
        balls: [],
        bullets: [],
        plane: new Plane(0, 0, 2),
        ball: {},
      }
    },
    watch: {
      plane: {
        handler: 'refresh',
        deep: true,
      },
      balls: {
        handler: 'refresh',
        deep: true,
      },
      bullets: {
        handler: 'refresh',
        deep: true,
      }
    },
    computed: {
      planeCss() {
        let css = `left:${this.plane.x}px;bottom:${this.plane.y}px`
        console.log(css)
        return css
      }
    },
    methods: {
      getBallStyle(ball) {
        // 灰色,击中得分,并消失
        // 白色,击中分裂黑灰色和白色
        // 蓝色,击中分裂,随机数目和颜色
        // 绿色,全部白色消失
        // 黄色,所有白色变为蓝色
        // 橙色,暂停2s
        // 青色,全体上升
        // 黑色,gg
        let color = BALL_COLORS[ball.type]
        let css = `left:${ball.x}px;bottom:${ball.y}px;width:${ball.size}px;height:${ball.size}px;background:${color}`
        console.log(css)
        return css
      },
      // 返回对象的位置的css字符串
      getStyle(obj) {
        let css = `left:${obj.x}px;bottom:${obj.y}px`
        console.log(css)
        return css
      },
      refresh(newVal, oldVal) {
        console.log('refresh')
      },

      keyDown(e) {
        console.log(e.code)
        if (e.code == 'ArrowUp') {
          this.move(0)
        } else if (e.code == 'ArrowRight') {
          this.move(1)
        } else if (e.code == 'ArrowDown') {
          this.move(2)
        } else if (e.code == 'ArrowLeft') {
          this.move(3)
        } else if (e.code == 'Space') {
          this.shoot()
        } else if (e.code == 'Enter') {
          this.addBallRandom()
        }
      },
      move(direction) {
        this.plane.move(direction)
        console.log(this.$refs.plane.style.left);
      },
      shoot() {
        let b = new Bullet(this.plane.x + 32, this.plane.y + 64)
        this.bullets.push(b)
      },
      addBallRandom() {
        let x = Math.floor(Width * Math.random())
        let y = Math.floor((HEIGHT - 400) * Math.random() + 200)
        let size = Math.min(Math.random() * 100, 30)
        let type = Math.floor(Math.random() * BALL_COLORS.length)
        let direction = (Math.random() - 0.5) * 180
        let b = new Ball(x, y, size, type, direction)
        this.balls.push(b)
      },

      // 检查越界和碰撞函数
      check() {

      }
    },
    mounted() {
      document.body.onkeydown = this.keyDown
      setInterval(
        () => {
          this.check()
        },
        REFRESH_INTERVAL
      )


    }
  }
</script>

<style scoped>
  .main {
    width: 100vw;
    height: 100vh;
    position: relative;

  }

  .plane {
    position: absolute;
    left: 0;
    bottom: 0;
  }

  .bullet {
    width: 5px;
    height: 5px;
    border-radius: 50%;
    background: black;
    position: absolute;
    left: 0;
    bottom: 0;
  }

  .ball {
    width: 10px;
    height: 10px;
    background: deepskyblue;
    position: absolute;
    border-radius: 50%;
  }

  .control {
    display: flex;
    position: fixed;
    width: 100%;
    bottom: 0;
    justify-content: space-around;
  }
</style>

猜你喜欢

转载自my.oschina.net/ahaoboy/blog/1795114