Django_3

news/2024/9/22 1:05:25

文章目录

  • 游戏界面实现
    • 修改js模块化
    • 增加界面样式
    • 实现简易游戏引擎
    • 创建人物
    • 创建火球类
    • 实现碰撞
    • 实现动态效果

游戏界面实现

修改js模块化

game/templates/multiends/web.html
在这里插入图片描述
并且删除<head></head>里面的AcGame
game/static/js/src/zbase.js
class前加上export即可完成,再重新打包

增加界面样式

game/static/css/game.css

.ac-game-playground{                                              width:100%;                                                   height:100%;                                                  user-select:none;                                             }                       

在game/static/js/src/playground中先存下界面的长和宽

this.width=this.$playground.width();                       this.weight=this.$playground.height();  

实现简易游戏引擎

在game/static/js/src/playground创建ac_game_object文件夹,并在文件夹内创建zbase.js

let AC_GAME_OBJECTS=[];                                                                                                class AcGameObject{                                              
constructor(){                                                   AC_GAME_OBJECTS.push(this);                                                                                            this.has_called_start=false;  //是否执行过start函数       this.timedelta=0;  //当前帧距离上一帧的时间间隔           }                                                                                                                               start(){  //只会在第一帧执行  }                                                                                                                                 update(){  //每一帧会执行一次        }                                                                                                                              on_destory(){  //被删除之前执行一次            }                                                                                                                               destory(){  //删掉该物体                         this.on_destory();             for(let i=0;i<AC_GAME_OBJECTS.length;i++){             if(AC_GAME_OBJECTS[i] === this){                       AC_GAME_OBJECTS.splice(i,1);           break;                               }              }                                }                     }                                                                                                                                                                                                 let AC_GAME_ANIMATION=function(timestamp){                                                                                    for(let i = 0;i<AC_GAME_OBJECTS.length;i++){                    let obj=AC_GAME_OBJECTS[i];         if(!obj.has_called_start){                                 obj.start();                                               obj.has_called_start=true;                              }else{                                                         obj.timedelta=timestamp-last_timestamp;                obj.update();                                                }                                                          }                                                              last_timestamp=timestamp;                                                                                                  requestAnimationFrame(AC_GAME_ANIMATION);                  }                                                                                                                                                                                     requestAnimationFrame(AC_GAME_ANIMATION);    

在game/static/js/src/playground/创建game_map文件夹,并在文件夹内创建zbase.js

       class GameMap extends AcGameObject{2     constructor(playground){3         super();4         this.playground =playground;5         this.$canvas=$(`<canvas></canvas>`);6         this.ctx=this.$canvas[0].getContext('2d');7         this.ctx.canvas.width=this.playground.width;8         this.ctx.canvas.height=this.playground.height;9         this.playground.$playground.append(this.$canvas);10     }11 12     start(){13     }14 15     update(){16         this.render();17     }18 19     render(){20         this.ctx.fillStyle="rgba(0,0,0,0.2)";21         this.ctx.fillRect(0,0,this.ctx.canvas.width,this.ctx.canvas.height);22     }23 }                                               

创建人物

class Player extends AcGameObject{                                                                                               2     constructor(playground,x,y,radius,color,speed,is_me){                                                                       3         super();                                                                                                                     4         this.playground=playground;                                                                                            5         this.ctx=this.playground.game_map.ctx;                                                                                   6         this.x=x;                                                                                                               7         this.y=y;     this.vx=0;this.vy=0;this.move_length=0;                                                                                                              8         this.radius=radius;                                                                                                   9         this.color=color;                                                                                              10         this.speed=speed;                                                                            11         this.is_me=is_me;                                                                                         12         this.eps=0.1;                                                                                                13     }                                                                                                         16                                                                                                                       17     start(){                                                                                                            18     if(this.is_me){                                                                                                   19         this.add_listening_events();                                                                              20         }                                                                                                      21     }                                                                                                      22     add_listening_events(){                                                                                 23         let outer=this;                                                                                         24   this.playground.game_map.$canvas.on("contextmenu",function(){                                                                                                                              25             return false;                                                                                                    26      });                                                                                                                          27        this.playground.game_map.$canvas.mousedown(function(e){                                                             28             if(e.which === 3){   29                 outer.move_to(e.clientX,e.clientY);                                                                            30             }                                                                                                                  31         });                                                                                                                    32     }                                                                                                                          33                                                                                                                                  34     get_dist(x1,y1,x2,y2){                                                                                                       35         let dx=x1-x2;                                                                                                                 36         let dy=y1-y2;                                                                                                              anvas37         return Math.sqrt(dx*dx+dy*dy);                                                                                             38                                                                                                                                    39     }                                                                                                                               40                                                                                                                                        41        42     move_to(tx,ty){                                                                                                                 43         console.log("move to",this.x,this.y,tx,t                                                                                      y);                                                                                                                                  44         this.move_length=this.get_dist(this.x,th                                                                                    is.y,tx,ty);                                                                                                                     45         let angle=Math.atan2(ty-this.y,tx-this.x);         46         this.vx=Math.cos(angle);                                                                                                    47         this.vy=Math.sin(angle);                                                                                                    48         console.log("angle",this.move_length,this.vx,this.vy);                                                                                                                         49     }  50                                                                                                                             51     update(){                                                                                                                52         if(this.move_length<this.eps){                                             53             this.move_length=0;                                                54             this.vx=this.vy=0;                                                55         }else{                                                       56             let moved=Math.min(this.move_length,this.speed*this.timedelta/1000);                                         57             //console.log(this.angle,this.move_length,this.speed,this.timedelta/1000);                                                                                       58             this.x+=this.vx*moved;                                                                                          59             this.y+=this.vy*moved;                                                                                              60             this.move_length-=moved;      61                                                                                                                            62         }                                                                                                                   63     this.render();                                                      64     }                                                                                                                                              22     render(){                                                                                                                         23     this.ctx.beginPath();                                                                                                             24     this.ctx.arc(this.x,this.y,this.radius,0,Math.PI*2,false);                                                                       25     this.ctx.fillStyle=this.color;                                                                                                   26     this.ctx.fill();  

在AcGamePlayground中加入:
在这里插入图片描述

创建火球类

 1 class FireBall extends AcGameObject{2     constructor(playground,player,x,y,radius,vx,vy,color,speed,move_length){3         super();4         this.playground=playground;5         this.player=player;6         this.ctx=this.playground.game_map.ctx;7         this.x=x;8         this.y=y; 9         this.vx=vx;
10         this.vy=vy;
11         this.color=color;
12         this.speed=speed;
13         this.move_length=move_length;
14         this.eps=0.1;
15     }
16     start(){
17     }   
18     update(){
19         if(this.move_length<this.eps){                                                           
20             this.destroy();
21             return false;
22         }
23         let moved=Math.min(this.move_length,this.speed*this.timedelta/1000);
24         this.x+=this.vx*moved;
25         this.y+=this.vy*moved;
26         this.move_length-=moved;
27 
28         this.render();
29 
30     }
31 
32     render(){         
33         this.ctx.beginPath();
34         this.ctx.arc(this.x,this.y,this.radius,0,Math.PI*2,false);
35         this.ctx.fillStyle=this.color;
36         this.ctx.fill();
37     }
38 }      

在player中实现发射火球

constructor(...)
{...this.cur_skill = null; // 当前选中的技能...
}add_listening_events()
{...this.playground.game_map.$canvas.mousedown(function(e){...else if (ee === 1){if (outer.cur_skill === "fireball") // 当前技能是火球就发射{outer.shoot_fireball(e.clientX, e.clientY);return false;}outer.cur_skill = null; // 点击之后就得清空}});...$(window).keydown(function(e){if (!outer.is_alive) return false;let ee = e.which;if (ee === 81) // Q的keycode是81,其他keycode可以自行查阅{outer.cur_skill = "fireball"; // 技能选为fireballreturn false;}    });...
}shoot_fireball(tx, ty)
{console.log(tx, ty); // 测试用// 以下部分在测试成功之后再写入let x = this.x, y = this.y;let radius = this.playground.height * 0.01; // 半径let color = "orange"; // 颜色let damage = this.playground.height * 0.01; // 伤害值let angle = Math.atan2(ty - this.y, tx - this.x); // 角度let vx = Math.cos(angle), vy = Math.sin(angle); // 方向let speed = this.playground.height * 0.5; // 速度let move_dist = this.playground.height * 1; // 射程new FireBall(this.playground, this, x, y, radius, color, damage, vx, vy, speed, move_dist);

随机生成其他敌人

constructor()
{...for (let i = 0; i < 5; ++ i)//随机生成5个敌人{this.players.push(new Player(this, this.width / 2, this.height / 2, this.height * 0.05, GET_RANDOM_COLOR(), false, this.height * 0.15));    }
}

修改player:

update()
{this.update_AI();...
}update_AI()
{if (this.is_me) return false; // 如果这不是一个机器人就直接退出this.update_AI_move();
}update_AI_move()
{if (this.move_length < EPS) // 如果停下来就随机选个地方走向那边{let tx = Math.random() * this.playground.width;let ty = Math.random() * this.playground.height;this.move_to(tx, ty);}
}

实现碰撞

let is_collision = function(obj1, obj2) // 这是一个全局函数,代表两个物体之间是否碰撞
{return GET_DIST(obj1.x, obj1.y, obj2.x, obj2.y) < obj1.radius + obj2.radius; // 很简单的两圆相交条件
}is_satisfy_collision(obj) // 真的碰撞的条件
{if (this === obj) return false; // 自身不会被攻击if (this.player === obj) return false; // 发射源不会被攻击return IS_COLLISION(this, obj); // 距离是否满足
}hit(obj) // 碰撞
{obj.is_attacked(this); // obj被this攻击了this.is_attacked(obj); // this被obj攻击了
}is_attacked(obj) // 被伤害
{this.is_attacked_concrete(0, 0); // 具体被伤害多少,火球不需要关注伤害值和血量,因为碰到后就直接消失
}is_attacked_concrete(angle, damage) // 具体被伤害
{this.destroy(); // 直接消失
}update()
{this.update_attack();...
}update_attack()
{for (let i = 0; i < AC_GAME_OBJECTS.length; ++ i){let obj = AC_GAME_OBJECTS[i];if (this.is_satisfy_collision(obj)) // 如果真的碰撞了(这样可以保证碰撞条件可以自行定义,以后会很好维护){this.hit(this, obj); // 两个物体碰撞了break; // 火球,只能碰到一个物体}}
}is_attacked(obj)
{let angle = Math.atan2(this.y - obj.y, this.x - obj.x); // 角度let damage = obj.damage; // 伤害// 注意,这里被伤害之后的表现,就是什么方向碰撞就是什么伤害,简单的向量方向计算this.is_attacked_concrete(angle, damage);
}is_attacked_concrete(angle, damage) // 被具体伤害
{this.radius -= damage; // 这里半径就是血量this.friction_damage = 0.8; // 击退移动摩擦力if (this.is_died()) return false; // 已经去世了吗this.x_damage = Math.cos(angle);this.y_damage = Math.sin(angle); // (x_damage, y_damage)是伤害向量的方向向量this.speed_damage = damage * 100; // 击退速度
}is_died()
{if (this.radius < EPS * 10) // 少于这个数表示已经去世{this.destroy(); // 去世return true;}return false;
}update_move()
{if (this.speed_damage && this.speed_damage > EPS) // 如果此时在被击退的状态,就不能自己动{this.vx = this.vy = 0; // 不能自己动this.move_length = 0; // 不能自己动this.x += this.x_damage * this.speed_damage * this.timedelta / 1000; // 被击退的移动this.y += this.y_damage * this.speed_damage * this.timedelta / 1000; // 被击退的移动this.speed_damage *= this.friction_damage; // 摩擦力,表现出一个被击退越来越慢的效果}...
}

实现动态效果

// 这里面很多过程都是前面写过的,借这个机会努力回想一下。

class Particle extends AcGameObject
{constructor(playground, x, y, radius, color, vx, vy, speed){super();this.playground = playground;this.ctx = this.playground.game_map.ctx;this.x = x;this.y = y;this.radius = radius;this.color = color;this.vx = vx;this.vy = vy;this.speed = speed;}render(){this.ctx.beginPath();this.ctx.arc(this.x, this.y, this.radius, 0, Math.PI * 2, false);this.fillStyle = this.color;this.fill();}start(){this.friction_speed = 0.8;this.friction_radius = 0.8;}update(){this.update_move();this.render();}update_move(){if (this.speed < EPS * 10 || this.radius < EPS * 10){this.destroy();return false;}this.x += this.vx * this.speed * this.timedelta / 1000;this.y += this.vy * this.speed * this.timedelta / 1000;this.speed *= this.friction_speed;this.radius *= this.friction_radius;}}

修改后的Player:

class Player extends AcGameObject
{constructor(playground, x, y, radius, color, is_me, speed){super(true);this.playground = playground; // 所属playgroundthis.ctx = this.playground.game_map.ctx; // 操作的画笔this.x = x;  // 坐标this.y = y; // 坐标this.radius = radius; // 半径this.color = color; // 颜色this.is_me = is_me; // 玩家类型this.speed = speed; // 速度this.is_alive = true; // 是否存活this.eps = 0.1; // 精度,这里建议定义为全局变量,EPS = 0.1,在这个教程里以后都这么用。this.cur_skill = null; // 当前选中的技能}add_listening_events(){let outer = this; // 设置正确的this指针,因为接下来的后面的function内的this不是对象本身的thisthis.playground.game_map.$canvas.on("contextmenu", function(){ // 关闭画布上的鼠标监听右键return false;});this.playground.game_map.$canvas.mousedown(function(e){ // 鼠标监听if (!this.is_alive) return false;let ee = e.which; // e.which就是点击的键对应的值if (ee === 3) // 右键{outer.move_to(e.clientX, e.clientY); // e.clientX是鼠标的x坐标,e.clientY同理}else if (ee === 1){if (outer.cur_skill === "fireball"){outer.shoot_fireball(e.clientX, e.clientY);return false;}outer.cur_skill = null; // 点击之后就得清空}});$(window).keydown(function(e){if (!this.is_alive) return false;let ee = e.which;if (ee === 81) // Q的keycode是81,其他keycode可以自行查阅{outer.cur_skill = "fireball"; // 技能选为fireballreturn false;}    });}render(){// 画圆的方法,请照抄,深入了解同样自行查阅菜鸟教程this.ctx.beginPath();this.ctx.arc(this.x, this.y, this.radius, 0, Math.PI * 2, false);this.ctx.fillStyle = this.color;this.ctx.fill();}move_to(tx, ty){this.move_length = GET_DIST(this.x, this.y, tx, ty); // 跟目的地的距离let dx = tx - this.x, dy = ty - this.y; let angle = Math.atan2(dy, dx); // 计算角度,这里Math.atan2(y, x)相当于求arctan(y / x);this.vx = Math.cos(angle); // vx是这个速度(单位向量)的x上的速度(学过向量的都明白)this.vy = Math.sin(angle); // vy是这个速度的y上的速度}shoot_fireball(tx, ty){console.log(tx, ty); // 测试用// 以下部分在测试成功之后再写入let x = this.x, y = this.y;let radius = this.playground.height * 0.01; // 半径let color = "orange"; // 颜色let damage = this.playground.height * 0.01; // 伤害值let angle = Math.atan2(ty - this.y, tx - this.x); // 角度let vx = Math.cos(angle), vy = Math.sin(angle); // 方向let speed = this.playground.height * 0.5; // 速度let move_dist = this.playground.height * 1; // 射程new FireBall(this.playground, this, x, y, radius, color, damage, vx, vy, speed, move_dist);}is_attacked(obj){let angle = Math.atan2(this.y - obj.y, this.x - obj.x); // 角度let damage = obj.damage; // 伤害// 注意,这里被伤害之后的表现,就是什么方向碰撞就是什么伤害,简单的向量方向计算   this.is_attacked_concrete(angle, damage);}is_attacked_concrete(angle, damage) // 被具体伤害{this.explode_particle();this.radius -= damage; // 这里半径就是血量this.friction_damage = 0.8; // 击退移动摩擦力if (this.is_died()) return false; // 已经去世了吗this.x_damage = Math.cos(angle);this.y_damage = Math.sin(angle); // (x_damage, y_damage)是伤害向量的方向向量this.speed_damage = damage * 100; // 击退速度}explode_particle(){for (let i = 0; i < 10 + Math.random() * 5; ++ i) // 粒子数{let x = this.x, y = this.y;let radius = this.radius / 3;let angle = Math.PI * 2 * Math.random(); // 随机方向let vx = Math.cos(angle), vy = Math.sin(angle);let color = this.color;let speed = this.speed * 10;new Particle(this.playground, x, y, radius, color, vx, vy, speed); // 创建粒子对象}}is_died(){if (this.radius < EPS * 10) // 少于这个数表示已经去世{this.destroy(); //消失return true;}return false;}start(){this.start_add_listening_events();this.cold_time = 5;}start_add_listening_evnet(){if (this.is_me){this.add_listening_evnets();}}update(){this.update_AI();this.update_move(); // 更新移动this.render(); // 同样要一直画一直画(yxc:“人不吃饭会死,物体不一直画会消失。”)}update_AI(){if (this.is_me) return false; // 如果这不是一个机器人就直接退出this.update_AI_move();if (!this.update_AI_cold_time()) return false; // 还没走完冷静期,就不能放技能this.update_AI_shoot_fireball(); // 发射火球}update_AI_move(){if (this.move_length < EPS) // 如果停下来就随机选个地方走向那边{let tx = Math.random() * this.playground.width;let ty = Math.random() * this.playground.height;this.move_to(tx, ty);}}update_AI_cold_time() // 冷静期{if (this.cold_time > 0) // 如果处于冷静期,就不能放技能,返回false{this.cold_time -= this.timedelta / 1000; // 冷静期流逝return false;}return true; // 过了冷静期,可以放技能了,返回true}update_AI_shoot_fireball(){if (Math.random() < 1 / 300.0) // 每隔一定时间发射一次{let player = this.playground.players[0]; // 这个可以设置为随机,自行实现this.shoot_fireball(player.x, player.y); // 发射火球}}update_move() // 将移动单独写为一个过程{if (this.speed_damage && this.speed_damage > EPS) // 如果此时在被击退的状态,就不能自己动{this.vx = this.vy = 0; // 不能自己动this.move_length = 0; // 不能自己动this.x += this.x_damage * this.speed_damage * this.timedelta / 1000; // 被击退的移动this.y += this.y_damage * this.speed_damage * this.timedelta / 1000; // 被击退的移动this.speed_damage *= this.friction_damage; // 摩擦力,表现出一个被击退越来越慢的效果}if (this.move_length < EPS) // 移动距离没了(小于精度){this.move_length = 0; // 全都停下了this.vx = this.vy = 0;}else // 否则继续移动{let moved = Math.min(this.move_length, this.speed * this.timedelta / 1000); // 每个时间微分里该走的距离// 注意:this.timedelta 的单位是毫秒,所以要 / 1000 转换单位为秒this.x += this.vx * moved; // 移动this.y += this.vy * moved; // 移动}}on_destroy() // 死之前在this.players数组里面删掉这个player{this.is_alive = false;for (let i = 0; i < this.playground.players.length; ++ i){let player = this.playground.players[i];if (this === player){this.playground.players.splice(i, 1);}}}
}

在这里插入图片描述
大致碰撞效果如上。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.pgtn.cn/news/17564.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈,一经查实,立即删除!

相关文章

十一运夺金基础数据采集工具

点击下载 转载于:https://www.cnblogs.com/JiangHuakey/archive/2010/11/17/1880139.html

卷积神经网络(CNN)使用自己的数据集进行天气识别

记录|深度学习100例-卷积神经网络&#xff08;CNN&#xff09;天气识别 | 第5天 这篇博客将从构建自己的天气数据集开始&#xff0c;到定义模型&#xff0c;编译模型&#xff0c;训练模型及验证模型。并进行一些升级&#xff0c;以使得模型更好。 如ImageDateGenerator进行数据…

使用Tensorflow2.0执行视觉显著性检测(Visual Saliency Detection)

使用Tensorflow2.0执行视觉显著性检测&#xff08;Visual Saliency Detection) 上一篇博客介绍了如何使用Python&#xff0c;OpenCV执行视觉显著性检测&#xff08;Visual Saliency Detection)。这篇博客将介绍如何使用Tensorflow2.0执行显著性检测&#xff0c;这是一个应用图…

epub 电子书软件代码销售

epub 电子书软件代码销售本套代码用来读取epub 格式电子书。主要面向&#xff1a;有一定开发能力的人员&#xff0c;和有一定制作水平的朋友们。用途&#xff1a;自己开发学习&#xff0c;钻研&#xff0c;出appstore 应用&#xff0c;卖钱&#xff0c;加广告赚钱等。&#xff…

程序媛过中秋的正确打开方式——使用Python绘制月饼消消乐,素描图,词云图,字符画图及提取轮廓

程序媛过中秋的正确打开方式——使用Python绘制月饼消消乐&#xff0c;素描图&#xff0c;词云图&#xff0c;字符画图及提取轮廓 这篇博客将介绍如何使用Python绘制月饼消消乐&#xff0c;素描图&#xff0c;词云图&#xff0c;字符画图及提取轮廓。 使用Python绘制端午drag…

moviepy第一天|模糊视频中卓别林的头,并添加一个文本生成的结尾clip,同时保留音频

MoviePy(完整文档)是一个用于视频编辑的Python库:剪切,串联,标题插入,视频合成(又名非线性编辑),视频处理和创建自定义效果。有关一些使用示例,请参阅库。 MoviePy可以读取和写入所有最常见的音频和视频格式,包括GIF,并在Windows / Mac / Linux上运行,使用Python …

moviepy第2天|对视频添加圆圈渐变大小的结尾及文字

MoviePy(完整文档)是一个用于视频编辑的Python库:剪切,串联,标题插入,视频合成(又名非线性编辑),视频处理和创建自定义效果。有关一些使用示例,请参阅库。 MoviePy可以读取和写入所有最常见的音频和视频格式,包括GIF,并在Windows / Mac / Linux上运行,使用Python …

Java POST请求MutliPartFile上传时最大文件限制报错及解决

Java POST请求既有文件&#xff08;图片&#xff0c;excel&#xff0c;可以为多个&#xff09;&#xff0c;又有表单项&#xff0c;可以通过form-data方式提交&#xff1b; apifox提交请求 后台Controller接收&#xff1a; 报错详情如下&#xff1a; 主要原因是&#xff1a;M…