Vue+Websocket实现多人在线王者飞机
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Vue+Websocket实现多人在线王者飞机相关的知识,希望对你有一定的参考价值。
看了Vue官方教程(貌似和自己写的框架差别不大,听前前端同事一直吹Vue,于是学习了一下,和自己写的框架好像也没强哪里去嘛,就是要傲娇哈哈),等有空也整理自己的框架,开源好了),想找个项目练练手(没找到好的),就写个飞机大战吧。
飞机大战总共三个页面:登录、匹配、游戏页面,三个页面的功能:
1、 登录:玩家填写用户名,socket连接
2、匹配:等待其他玩家准备
3、游戏:战斗页面
上述流程仿照了王者荣耀,所以就叫王者飞机(当然和王者荣耀相差十万八千里)最终效果:
git地址:https://gitee.com/djxfire/PlaneWar.git
根据上面的设计,Vue套餐基本就都用上了。
首先,先编写游戏页面(让飞机动起来):
我们定义一下玩家类player.js:
export default class Player {
constructor (name, x, y, enermy = false) {
this.name = name // 玩家名称
this.position = {} // 位置
this.position.x = x
this.position.y = y
this.speed = 1
this.direct = 0 // 方向0:朝上,1朝左,2朝下,3朝右
this.attack = 1 // 攻击力
this.flood = 5 // 血量
this.sock = null // socket连接
this.state = 0 // 0:停止,1:移动
this.bullets = [] // 发射的子弹
this.enermys = [] // 敌人
if (!enermy) {
this.init()
}
}
init () {
// TODO: WebSocket连接
}
move (direct) {
this.direct = direct
switch (direct) {
case 0:
if (this.position.y > 0) {
this.position.y -= this.speed
}
break
case 1:
if (this.position.x > 0) {
this.position.x -= this.speed
}
break
case 2:
if (this.position.y < window.innerHeight - 55) {
this.position.y += this.speed
}
break
case 3:
if (this.position.x < window.innerWidth - 55) {
this.position.x += this.speed
}
break
}
}
}
玩家类的具体信息参照注释。
接下来编写Game.vue组件
<template>
<div class = "scene">
<div v-for="(monster,index) of monsters" :key="index" class="monster" :style="{left:monster.position.x + ‘px‘,top:monster.position.y + ‘px‘}">
<img src="../assets/monster.png"
:class="{‘turn-left‘:monster.direct == 1,‘turn-right‘:monster.direct == 3,‘turn-up‘:monster.direct == 0,‘turn-down‘:monster.direct == 2}"/>
<p>{{ monster.name }}</p>
</div>
<span v-for="(monster,index) of monsters" :key="index">
<div class="bullet" v-for="(bullet,index2) of monster.bullets"
:key = "index2"
:style="{left:bullet.position.x + ‘px‘,top:bullet.position.y + ‘px‘}">
</div>
</span>
<div class = "monster"
:style="{left:own.position.x + ‘px‘,top:own.position.y + ‘px‘}">
<img src="../assets/monster.png"
:class="{‘turn-left‘:own.direct == 1,‘turn-right‘:own.direct == 3,‘turn-up‘:own.direct == 0,‘turn-down‘:own.direct == 2}"/>
<p>{{ own.name }}</p>
</div>
<div class="bullet" v-for="(bullet,index) of own.bullets"
:key = "index"
:style="{left:bullet.position.x + ‘px‘,top:bullet.position.y + ‘px‘}">
</div>
<div class = "play-control">
<div>
<div @touchstart="turn(0)" @touchend="turnEnd()" class="up"></div>
</div>
<div style="text-align: initial;">
<div @touchstart="turn(1)" @touchend="turnEnd()" class="left"></div>
<div @touchstart="turn(3)" @touchend="turnEnd()" class="right"></div>
<div class="clear"></div>
</div>
<div>
<div @touchstart="turn(2)" @touchend="turnEnd()" class = "down"></div>
</div>
</div>
<div class = "shoot-control" @touchstart="shoot()">
</div>
</div>
</template>
<script>
import Player from ‘../player‘
export default {
name: ‘game‘,
data () {
return {
own: new Player(‘test‘, Math.round(Math.random() * window.innerWidth), Math.round(Math.random() * window.innerHeight)),
monsters: []
}
},
methods: {
turn (direct) {
this.own.move(direct)
},
turnEnd () {
},
shoot () {
}
}
}
</script>
<style scoped>
.scene{
position: relative;
overflow: hidden;
width:100%;
height:calc(100vh);
}
.bomb{
animation:bombframe 3s;
-webkit-animation: bombframe 3s;
}
.turn-right{
-webkit-transform: rotate(270deg);
-moz-transform: rotate(270deg);
-ms-transform: rotate(270deg);
-o-transform:rotate(270deg) ;
transform: rotate(270deg);
}
.turn-left{
-webkit-transform: rotate(90deg);
-moz-transform: rotate(90deg);
-ms-transform: rotate(90deg);
-o-transform: rotate(90deg);
transform: rotate(90deg);
}
.turn-up{
-webkit-transform: rotate(180deg);
-moz-transform: rotate(180deg);
-ms-transform: rotate(180deg);
-o-transform: rotate(180deg);
transform: rotate(180deg);
}
.turn-down{
-webkit-transform: rotate(0deg);
-moz-transform: rotate(0deg);
-ms-transform: rotate(0deg);
-o-transform: rotate(0deg);
transform: rotate(0deg);
}
.monster{
position: absolute;
display: inline-block;
text-align: center;
}
.bullet{
position: absolute;
display: inline-block;
width: 4px;
height:4px;
background: #000;
-webkit-border-radius: 4px;
-moz-border-radius: 4px;
border-radius: 4px;
}
.play-control{
position: fixed;
text-align:center;
bottom:0;
left:0;
background: #E9E9E9;
width:100px;
height:100px;
opacity: 0.5;
z-index: 999;
-webkit-border-radius: 100px;
-moz-border-radius: 100px;
border-radius: 200px;
}
.clear{
clear: both;
}
.play-control .left{
display: inline-block;
width:0;
height:0;
float: left;
border-top: 25px solid transparent;
border-right: 25px solid #A8A8A8;
border-bottom: 25px solid transparent;
vertical-align: middle;
}
.play-control .right{
display: inline-block;
width:0;
height:0;
float: right;
vertical-align: middle;
border-top: 25px solid transparent;
border-left: 25px solid #A8A8A8;
border-bottom: 25px solid transparent;
}
.play-control .up{
display: inline-block;
vertical-align: top;
width:0;
height:0;
border-right: 25px solid transparent;
border-bottom: 25px solid #A8A8A8;
border-left: 25px solid transparent;
}
.play-control .down{
display: inline-block;
vertical-align: bottom;
width:0;
height:0;
border-right: 25px solid transparent;
border-top: 25px solid #A8A8A8;
border-left: 25px solid transparent;
}
.play-control .left:active{
border-right: 25px solid #A88888;
}
.play-control .right:active{
border-left: 25px solid #A88888;
}
.play-control .up:active{
border-bottom: 25px solid #A88888;
}
.play-control .down:active{
border-top: 25px solid #A88888;
}
.shoot-control{
position: fixed;
text-align:center;
bottom:0;
right:0;
background: #E9E9E9;
width:100px;
height:100px;
opacity: 0.5;
z-index: 999;
-webkit-border-radius: 100px;
-moz-border-radius: 100px;
border-radius: 200px;
background-size: 100%;
background: url(../assets/BButton.png) no-repeat;
}
</style>
现在点击方向盘飞机就动起来了,然而需要不停的点击按键,显然不合理,所以我们使用requestAnimationFrame()方法实现动画,在Game组件中添加代码:
mounted () {
let that = this
function _callback () {
for (let monster of that.own.enermys) {
monster.onframe()
for (let bullet of monster.bullets) {
bullet.onframe()
}
}
that.own.onframe()
for (let bullet of that.own.bullets) {
bullet.onframe()
}
requestAnimationFrame(_callback)
}
_callback()
}
添加player的onframe代码:
onframe () {
if (this.state === 1) {
this.move(this.direct)
this.send({ opt: ‘upposition‘, name: this.name, x: this.position.x, y: this.position.y, direct: this.direct })
}
}
当方向盘touchstart时own.state置为1,当touchend时置为0,修改方法:
turn (direct) {
this.$store.dispatch(‘move‘, direct)
},
turnEnd () {
this.$store.dispatch(‘turnEnd‘)
},
至此,当按下方向键时,飞机开始运动,当放开方向键时,飞机停止运动。
下一篇将实现NodeJs实现WebSocket游戏服务端的逻辑
以上是关于Vue+Websocket实现多人在线王者飞机的主要内容,如果未能解决你的问题,请参考以下文章
SpringBoot+Vue+WebSocket 实现在线聊天
SpringBoot+Netty+Vue+Websocket实现在线推送/聊天系统