分享web开发知识

注册/登录|最近发布|今日推荐

主页 IT知识网页技术软件开发前端开发代码编程运营维护技术分享教程案例
当前位置:首页 > 代码编程

Vue+Websocket实现多人在线王者飞机(一)

发布时间:2023-09-06 01:44责任编辑:董明明关键词:Web
看了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实现多人在线王者飞机(一)

原文地址:http://blog.51cto.com/janwool/2074129

知识推荐

我的编程学习网——分享web前端后端开发技术知识。 垃圾信息处理邮箱 tousu563@163.com 网站地图
icp备案号 闽ICP备2023006418号-8 不良信息举报平台 互联网安全管理备案 Copyright 2023 www.wodecom.cn All Rights Reserved