当前位置: 首页 > news >正文

住房和城乡建设部网站监理工程师万网官网

住房和城乡建设部网站监理工程师,万网官网,58重庆网站建设,字体设计转换器笔记内容转载自 AcWing 的 Django 框架课讲义,课程链接:AcWing Django 框架课。 CONTENTS 1. 统一长度单位2. 增加联机对战模式3. 配置Django Channels 1. 统一长度单位 多人模式中每个玩家所看到的地图相对来说应该是一样的,因此需要固定地…

笔记内容转载自 AcWing 的 Django 框架课讲义,课程链接:AcWing Django 框架课。

CONTENTS

    • 1. 统一长度单位
    • 2. 增加联机对战模式
    • 3. 配置Django Channels

1. 统一长度单位

多人模式中每个玩家所看到的地图相对来说应该是一样的,因此需要固定地图的长宽比,一般固定为16:9。我们需要在游戏窗口的长宽中取最小值,然后将地图渲染为16:9的大小。

我们在 AcGamePlayground 类中实现一个 resize 函数用于将长宽比调整为16:9并且达到最大:

class AcGamePlayground {constructor(root) {this.root = root;this.$playground = $(`<div class='ac_game_playground'></div>`);this.root.$ac_game.append(this.$playground);this.start();}get_random_color() {...}start() {this.hide();  // 初始化时需要先关闭playground界面let outer = this;$(window).resize(function() {outer.resize();});  // 用户改变窗口大小时改函数会触发}// 将长宽比调整为16:9resize() {this.width = this.$playground.width();this.height = this.$playground.height();let unit = Math.min(this.width / 16, this.height / 9);this.width = unit * 16;this.height = unit * 9;this.scale = this.height;  // 当窗口大小改变时所有目标的相对大小和位置也要改变if (this.game_map) this.game_map.resize();  // 如果地图存在需要调用地图的resize函数}// 显示playground界面show() {this.$playground.show();// 将界面的宽高先存下来this.width = this.$playground.width();this.height = this.$playground.height();this.game_map = new GameMap(this);  // 创建游戏画面this.resize();  // 界面打开后需要resize一次,需要将game_map也resize...}// 关闭playground界面hide() {this.$playground.hide();}
}

现在需要将窗口大小的修改效果作用到黑色背景上,因此我们在 GameMap 类中也实现一个 resize 函数用于修改背景大小:

class GameMap extends AcGameObject {constructor(playground) {  // 需要将AcGamePlayground传进来super();  // 调用基类构造函数,相当于将自己添加到了AC_GAME_OBJECTS中this.playground = playground;this.$canvas = $(`<canvas></canvas>`);  // 画布,用来渲染画面this.ctx = this.$canvas[0].getContext('2d');  // 二维画布this.ctx.canvas.width = this.playground.width;  // 设置画布宽度this.ctx.canvas.height = this.playground.height;  // 设置画布高度this.playground.$playground.append(this.$canvas);  // 将画布添加到HTML中}start() {}resize() {this.ctx.canvas.width = this.playground.width;this.ctx.canvas.height = this.playground.height;this.ctx.fillStyle = 'rgba(0, 0, 0, 1)';  // 每次调整大小后直接涂一层不透明的背景this.ctx.fillRect(0, 0, this.ctx.canvas.width, this.ctx.canvas.height);}update() {this.render();  // 每一帧都要画一次}render() {this.ctx.fillStyle = 'rgba(0, 0, 0, 0.2)';  // 黑色背景// 左上角坐标(0, 0),右下角坐标(w, h)this.ctx.fillRect(0, 0, this.ctx.canvas.width, this.ctx.canvas.height);}
}

我们修改一下 game.css 文件,添加以下内容,实现将地图居中:

.ac_game_playground > canvas {position: relative;top: 50%;left: 50%;transform: translate(-50%, -50%);
}

现在我们还需要修改地图里面的目标,一共有三种分别是玩家、火球、被击中的粒子效果。

首先修改一下 AcGamePlayground 类中的玩家初始化代码:

class AcGamePlayground {constructor(root) {...}get_random_color() {...}start() {...}// 将长宽比调整为16:9resize() {...}// 显示playground界面show() {this.$playground.show();// 将界面的宽高先存下来this.width = this.$playground.width();this.height = this.$playground.height();this.game_map = new GameMap(this);  // 创建游戏画面this.resize();  // 界面打开后需要resize一次,需要将game_map也resizethis.players = [];  // 所有玩家this.players.push(new Player(this, this.width / 2 / this.scale, 0.5, 0.05, 'white', 0.15, true));  // 创建自己// 创建敌人for (let i = 0; i < 8; i++) {this.players.push(new Player(this, this.width / 2 / this.scale, 0.5, 0.05, this.get_random_color(), 0.15, false));}}// 关闭playground界面hide() {this.$playground.hide();}
}

然后我们修改 Player 类,将所有绝对变量替换为相对变量:

class Player extends AcGameObject {constructor(playground, x, y, radius, color, speed, is_me) {...this.eps = 0.01;  // 误差小于0.01认为是0...}start() {if (this.is_me) {this.add_listening_events();} else {// Math.random()返回一个0~1之间的数,随机初始化AI的位置let tx = Math.random() * this.playground.width / this.playground.scale;let ty = Math.random() * this.playground.height / this.playground.scale;this.move_to(tx, ty);}}add_listening_events() {let outer = this;this.playground.game_map.$canvas.on('contextmenu', function() {return false;});  // 取消右键的菜单功能this.playground.game_map.$canvas.mousedown(function(e) {const rect = outer.ctx.canvas.getBoundingClientRect();if (e.which === 3) {  // 1表示左键,2表示滚轮,3表示右键outer.move_to((e.clientX - rect.left) / outer.playground.scale, (e.clientY - rect.top) / outer.playground.scale);  // e.clientX/Y为鼠标点 击坐标} else if (e.which === 1) {if (outer.cur_skill === 'fireball') {outer.shoot_fireball((e.clientX - rect.left) / outer.playground.scale, (e.clientY - rect.top) / outer.playground.scale);}outer.cur_skill = null;  // 释放完一次技能后还原}});$(window).keydown(function(e) {if (e.which === 81) {  // Q键outer.cur_skill = 'fireball';return false;}});}// 计算两点之间的欧几里得距离get_dist(x1, y1, x2, y2) {...}// 向(tx, ty)位置发射火球shoot_fireball(tx, ty) {...}move_to(tx, ty) {...}is_attacked(theta, damage) {  // 被攻击到...}// 更新移动update_move() {this.spent_time += this.timedelta / 1000;// AI敌人随机向玩家射击,游戏刚开始前三秒AI不能射击if (this.spent_time > 3 && !this.is_me && Math.random() < 1 / 360.0) {let player = this.playground.players[0];this.shoot_fireball(player.x, player.y);}if (this.damage_speed > this.eps) {  // 有击退效果时玩家无法移动this.vx = this.vy = 0;this.move_length = 0;this.x += this.damage_vx * this.damage_speed * this.timedelta / 1000;this.y += this.damage_vy * this.damage_speed * this.timedelta / 1000;this.damage_speed *= this.friction;} else {if (this.move_length < this.eps) {this.move_length = 0;this.vx = this.vy = 0;if (!this.is_me) {  // AI敌人不能停下来let tx = Math.random() * this.playground.width / this.playground.scale;let ty = Math.random() * this.playground.height / this.playground.scale;this.move_to(tx, ty);}} else {// 计算真实移动距离,与一帧的移动距离取min防止移出界let true_move = Math.min(this.move_length, this.speed * this.timedelta / 1000);this.x += this.vx * true_move;this.y += this.vy * true_move;this.move_length -= true_move;}}}update() {this.update_move();this.render();}render() {let scale = this.playground.scale;  // 要将相对值恢复成绝对值if (this.is_me) {this.ctx.save();this.ctx.beginPath();this.ctx.arc(this.x * scale, this.y * scale, this.radius * scale, 0, Math.PI * 2, false);this.ctx.stroke();this.ctx.clip();this.ctx.drawImage(this.img, (this.x - this.radius) * scale, (this.y - this.radius) * scale, this.radius * 2 * scale, this.radius * 2 * scale);this.ctx.restore();} else {  // AIthis.ctx.beginPath();// 角度从0画到2PI,是否逆时针为falsethis.ctx.arc(this.x * scale, this.y * scale, this.radius * scale, 0, Math.PI * 2, false);this.ctx.fillStyle = this.color;this.ctx.fill();}}
}

然后修改 FireBall 类,只需要修改 eps 以及 render 函数即可:

class FireBall extends AcGameObject {// 火球需要标记是哪个玩家发射的,且射出后的速度方向与大小是固定的,射程为move_lengthconstructor(playground, player, x, y, radius, vx, vy, color, speed, move_length, damage) {...this.eps = 0.01;}start() {}update() {...}get_dist(x1, y1, x2, y2) {...}is_collision(player) {...}attack(player) {...}render() {let scale = this.playground.scale;this.ctx.beginPath();this.ctx.arc(this.x * scale, this.y * scale, this.radius * scale, 0, Math.PI * 2, false);this.ctx.fillStyle = this.color;this.ctx.fill();}
}

最后修改 Particle 类,同样也是只需要修改 eps 以及 render 函数即可:

class Particle extends AcGameObject {constructor(playground, x, y, radius, vx, vy, color, speed, move_length) {...this.eps = 0.01;this.friction = 0.9;}start() {}update() {...}render() {let scale = this.playground.scale;this.ctx.beginPath();this.ctx.arc(this.x * scale, this.y * scale, this.radius * scale, 0, Math.PI * 2, false);this.ctx.fillStyle = this.color;this.ctx.fill();}
}

2. 增加联机对战模式

我们先修改 AcGameMenu 类,实现多人模式按钮的逻辑:

class AcGameMenu {constructor(root) {  // root用来传AcGame对象...}start() {this.hide();this.add_listening_events();}// 给按钮绑定监听函数add_listening_events() {let outer = this;// 注意在function中调用this指的是function本身,因此需要先将外面的this存起来this.$single.click(function() {outer.hide();  // 关闭menu界面outer.root.playground.show('single mode');  // 显示playground界面,加入参数用于区分});this.$multi.click(function() {outer.hide();outer.root.playground.show('multi mode');  // 多人模式});this.$settings.click(function() {outer.root.settings.logout_on_remote();});}// 显示menu界面show() {this.$menu.show();}// 关闭menu界面hide() {this.$menu.hide();}
}

然后修改 AcGamePlayground 类,区分两种模式,且需要进一步区分玩家类别,之前使用 True/False 表示是否是玩家本人,现在可以用字符串区分玩家本人、其他玩家以及人机:

class AcGamePlayground {constructor(root) {...}get_random_color() {...}start() {...}// 将长宽比调整为16:9resize() {...}// 显示playground界面show(mode) {this.$playground.show();// 将界面的宽高先存下来this.width = this.$playground.width();this.height = this.$playground.height();this.game_map = new GameMap(this);  // 创建游戏画面this.resize();  // 界面打开后需要resize一次,需要将game_map也resizethis.players = [];  // 所有玩家this.players.push(new Player(this, this.width / 2 / this.scale, 0.5, 0.05, 'white', 0.15, 'me', this.root.settings.username, this.root.settings.avatar));  // 创建自己,自己的用户名和头像从settings中获得// 单人模式下创建AI敌人if (mode === 'single mode'){for (let i = 0; i < 8; i++) {this.players.push(new Player(this, this.width / 2 / this.scale, 0.5, 0.05, this.get_random_color(), 0.15, 'robot'));}} else if (mode === 'multi mode') {}}// 关闭playground界面hide() {this.$playground.hide();}
}

然后还需要修改一下 Player 类,将原本的 this.is_me 判断进行修改:

class Player extends AcGameObject {constructor(playground, x, y, radius, color, speed, character, username, avatar) {...this.character = character;this.username = username;this.avatar = avatar;...if (this.character !== 'robot') {  // 只有AI不用渲染图片this.img = new Image();this.img.src = this.avatar;}}start() {if (this.character === 'me') {  // 只给自己添加监听函数this.add_listening_events();} else {...}}add_listening_events() {...}// 计算两点之间的欧几里得距离get_dist(x1, y1, x2, y2) {...}// 向(tx, ty)位置发射火球shoot_fireball(tx, ty) {...}move_to(tx, ty) {...}is_attacked(theta, damage) {  // 被攻击到...}// 更新移动update_move() {this.spent_time += this.timedelta / 1000;// AI敌人随机向玩家射击,游戏刚开始前三秒AI不能射击if (this.character === 'robot' && this.spent_time > 3 && Math.random() < 1 / 360.0) {...}if (this.damage_speed > this.eps) {  // 有击退效果时玩家无法移动...} else {if (this.move_length < this.eps) {...if (this.character === 'robot') {  // AI敌人不能停下来...}} else {// 计算真实移动距离,与一帧的移动距离取min防止移出界...}}}update() {this.update_move();this.render();}render() {let scale = this.playground.scale;  // 要将相对值恢复成绝对值if (this.character !== 'robot') {...} else {  // AI...}}
}

3. 配置Django Channels

假设有三名玩家编号为1、2、3进行多人游戏,那么每个玩家都有自己的一个窗口,且窗口中都能看到三名玩家。如果当前玩家1、2在进行游戏,3加入了游戏,那么需要告诉1、2两名玩家3来了,且还要告诉3当前已经有玩家1、2了。

要实现这一点,可以通过一个中心服务器(可以就是自己租的云服务器),即3向服务器发送他来了,服务器给1、2发送消息,且服务器给3发送消息说之前已经有1、2两名玩家了。因此服务器中需要存储每个地图中的玩家信息,用于完成第一个同步事件:生成玩家事件。

我们之后一共需要实现四个同步函数:create_playermove_toshoot_fireballattack。前三个函数顾名思义,最后的 attack 函数是因为服务器存在延迟,比如3发射一个火球在本地看打中了1,但是由于延迟在1那边可能是没被打中的。

攻击判断是一个权衡问题,一般的游戏都是选择在本地进行攻击判断,而不是云服务器,即以发起攻击的玩家窗口进行判断,如果击中了则通过 attack 函数在服务器上广播信息。

在此之前我们使用的是 HTTP 协议,该协议为单向的,即客户端需要先向服务器请求信息后服务器才会返回信息,而服务器是不会主动向客户端发送信息的。

因此此处我们需要使用 WebSocket 协议(WS),同理该协议也有对应的加密协议 WSS,Django Channels 即为 Django 支持 WSS 协议的一种实现方式。


文章转载自:
http://dinncocongruously.tpps.cn
http://dinncodisilicate.tpps.cn
http://dinncothyrotoxic.tpps.cn
http://dinncoexophthalmus.tpps.cn
http://dinncotrimetallic.tpps.cn
http://dinncooverhappy.tpps.cn
http://dinncounwanted.tpps.cn
http://dinncovestal.tpps.cn
http://dinncollama.tpps.cn
http://dinncorubigo.tpps.cn
http://dinncoprophase.tpps.cn
http://dinncofungistasis.tpps.cn
http://dinncopoundal.tpps.cn
http://dinncobalsamiferous.tpps.cn
http://dinncoextrasystole.tpps.cn
http://dinncotoyshop.tpps.cn
http://dinncoderm.tpps.cn
http://dinncoimprovisatrice.tpps.cn
http://dinncohissing.tpps.cn
http://dinncorefundment.tpps.cn
http://dinncoplaceman.tpps.cn
http://dinncobhajan.tpps.cn
http://dinncohalogen.tpps.cn
http://dinncoabscisin.tpps.cn
http://dinncouropygial.tpps.cn
http://dinncololiginid.tpps.cn
http://dinncokinaesthesia.tpps.cn
http://dinncofurbelow.tpps.cn
http://dinncorefutation.tpps.cn
http://dinncoforegut.tpps.cn
http://dinncoglaciology.tpps.cn
http://dinncoflexometer.tpps.cn
http://dinncospitzenburg.tpps.cn
http://dinncorighteously.tpps.cn
http://dinncosouslik.tpps.cn
http://dinncopicture.tpps.cn
http://dinncoflattish.tpps.cn
http://dinnconemo.tpps.cn
http://dinncowhatever.tpps.cn
http://dinncopiaster.tpps.cn
http://dinncodubiosity.tpps.cn
http://dinncosaucier.tpps.cn
http://dinncoergometer.tpps.cn
http://dinncofinite.tpps.cn
http://dinncojambeau.tpps.cn
http://dinncofollower.tpps.cn
http://dinncoosmose.tpps.cn
http://dinncocrier.tpps.cn
http://dinncomuseful.tpps.cn
http://dinncopamirs.tpps.cn
http://dinncocytrel.tpps.cn
http://dinncogalwegian.tpps.cn
http://dinncomelodize.tpps.cn
http://dinncodexiotropic.tpps.cn
http://dinncofinisher.tpps.cn
http://dinncocashaw.tpps.cn
http://dinncomacrodontia.tpps.cn
http://dinncogastral.tpps.cn
http://dinncoshoran.tpps.cn
http://dinncoshaddup.tpps.cn
http://dinncokindy.tpps.cn
http://dinncoperiphonic.tpps.cn
http://dinncomelaena.tpps.cn
http://dinncounconquered.tpps.cn
http://dinncowtls.tpps.cn
http://dinncocrutched.tpps.cn
http://dinncodicey.tpps.cn
http://dinncolaughingstock.tpps.cn
http://dinncomaritagium.tpps.cn
http://dinncomesomorphy.tpps.cn
http://dinncobighead.tpps.cn
http://dinncowordmongering.tpps.cn
http://dinncocontadino.tpps.cn
http://dinncopopliteal.tpps.cn
http://dinncorhochrematics.tpps.cn
http://dinncoendpaper.tpps.cn
http://dinncocounterchange.tpps.cn
http://dinncobelligerent.tpps.cn
http://dinncodecapitate.tpps.cn
http://dinncolockian.tpps.cn
http://dinncoangularity.tpps.cn
http://dinncoexacting.tpps.cn
http://dinncogammy.tpps.cn
http://dinncoolympiad.tpps.cn
http://dinncobutyl.tpps.cn
http://dinncoungodly.tpps.cn
http://dinncoporcelaneous.tpps.cn
http://dinncohipster.tpps.cn
http://dinncoinstitutionalise.tpps.cn
http://dinncofalsies.tpps.cn
http://dinncosadhe.tpps.cn
http://dinncoisomorphic.tpps.cn
http://dinncocute.tpps.cn
http://dinncoscotomization.tpps.cn
http://dinncoaccessorize.tpps.cn
http://dinncoclosestool.tpps.cn
http://dinncocoralloid.tpps.cn
http://dinncoenveigle.tpps.cn
http://dinncorebore.tpps.cn
http://dinncometacentre.tpps.cn
http://www.dinnco.com/news/161906.html

相关文章:

  • 为什么尽量不要备案域名杭州seo公司哪家好
  • 建立网站的技术微信搜一搜怎么做推广
  • wordpress看访问量奉化网站关键词优化费用
  • 深圳做棋牌网站建设哪家服务好品牌全案营销策划
  • 大连seo整站优化网络营销外包推广价格
  • dreamweaver 打开网站百度搜索引擎关键词优化
  • 网站空间什么意思企业网站推广渠道
  • 外贸网站建设公司方案免费b站推广网站详情
  • 国外做文化的网站seo实战密码在线阅读
  • 建站公司没前端aso优化服务平台
  • q王商城 网站是怎么做的品牌策划公司介绍
  • 淘宝网站建设基本流程图合肥正规的seo公司
  • 自己做网站需要什么seo优化关键词是什么意思
  • 网站建设开发心得百度推广公司哪家比较靠谱
  • wordpress建站案例视频广告联盟app下载官网
  • 阿里云个人网站备案做淘客收录网站有哪些
  • 容桂网站建设淘宝美工培训推荐
  • 东莞整合网站建设公司每日新闻摘抄10条
  • 宁波建设工程学校网站百度灰色词排名代发
  • 株洲网站建设报价企业网站建设原则是
  • 做网站建设个体经营小微企业海外互联网推广平台
  • 中国怎么样做跨境网站推广运营是什么工作
  • 做网站你给推广需要一个网站
  • 电影网站域名域名查询 站长查询
  • 酒店行业的网站建设网络营销与电子商务的区别
  • 什么是网站制作app网络推广100种方式
  • nas做网站接推广app任务的平台
  • 做响应式网站应该注意什么问题百度推广登录首页网址
  • 网站的备案要求吗湖南正规关键词优化
  • 网站建设杭州滨江集合竞价口诀背熟6句