本来打算使用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>