🔥🔥异形工厂 更新和修复BUG
前言
这次为大家带来的依旧是Github高星游戏Shapez的一些问题BUG的修复,以及工具板块的更新。因为最近还是有很多学校的事情在忙,功能的更新和BUG修复一直都是时断时续的。所以很多人私信我的一些BUG不是不能解决,而是时间上不太充裕所以在这里说一声抱歉。
这次更新了这篇文章也是觉得一个星期的时间里,我也更新和修复不少内容了。接下来我将会列出更新的内容,供大家有一个直观的了解。
在文章里的在线代码不能很好的显示这个游戏,可以点击在线代码上面的这个图标链接进入单独页面进行体验么么哒~~ 也希望亲爱的掘友玩完觉得不错的话记得点赞 收藏呦
优化后的感悟
问题分析
先来谈谈本次修复及优化的内容,我在优化一些冗余代码和BUG的时候会发现自己为什么这么 &*,明明这么简单就能完成的逻辑功能却写了一大堆冗余代码。当然后面沉思了一会就发现原因其实就是出在每次写完一个板块之后,并没有立马去测试他是否符合各种需求就继续往下写了;
再加上每次写完一个板块,隔很长时间才会继续写,也就忘记了以前已经预留过这个功能了,导致重复编写照成冗余
如何避免
虽然知道各位已经在工作的jy们应该不会出现这种问题,但是对于可能会遇到我一样的问题的还在学习阶段的jy 提供一定的参考价值
-
我也知道大多数人应该和我一样写东西的注释不太可能特别全面,但建议在写完一个复杂的功能之后,一定要对这个板块的功能和还存在的一些问题做一个详细的记录,记录方式可以通过注释、md或者有道云笔记之类的;这样你很久之后再回来编写修改的时候能对板块有更加快速的了解。
-
在写完一个功能之后,一定要对功能在是否符合要求上进行严格的测试,这样可以避免以后写到相关功能板块的时候导致要进行一次大改!
-
在修复BUG的时候一定要进行上个版本的保存,这样可以避免因为修复一个大的BUG,结果导致出现的BUG越来越多还很难回到起初修改的时候。当然据我所知很多已经在工作的编程大佬们都会使用git提交自己的项目到github或者码云上做一个版本的保存,不了解的可以去试着了解一下是个很简单的东西。但如果实在觉得没必要也可以直接另起一个文件保存上一次的代码或者仅是哪个板块的代码。
BUG修复及优化
- 修复 操作时超出页面视图导致BUG
- 修复 游戏加载崩溃
- 修复 切割器删除报错
- 修复 使用铺路工具绘画的时候末端不会自动吸附到目标工具上
- 修复 缩放和拖动时工具消失
新增功能
- 增加关卡 3-5 关
- 增加 右键删除板块功能
- 增加工具 旋转器
- 增加工具 垃圾桶
- 增加 缩小地图后用像素表达放置的工具
制作实现
这里就不对上面的BUG修复及优化的方面进行解析啦~ 因为我尝试着写过进行一次解析但发现很难去单独讲述我这个问题是如何出现的,如何修复的。工程量太大,望谅解~ 所以就只对新增加的功能进行一些解析。
新增关卡3-5关
3关和4关基本就是改变了一下关卡的相对参数,所以也没有特别好讲的地方,这里重点讲一下第五关。我先放出每个关卡的关卡数据:
// type: 关卡要提交的采集物类型,num:所需要提交的数量,info:中心点显示可以解锁的东西
// half: 指定需要经过切割后的哪一半采集物
levels: [
{type: 'circular', num: 10, info: '图形切割'},
{type: 'circular', num: 20, info: '下一关', half: 'left'},
{type: 'square', num: 30, info: '下一关'},
{type: 'square', num: 30, info: '旋转机', half: 'right'},
{type: 'circular', num: 75, info: '下一关', half: 'top'},
],
上期提到了我的中心区域在地图上是以一个 Main Class类的方式存储的,每个关卡通关需要提交的采集物和显示的信息也是显示在中心区域上。所以这里我直接在类里添加了一个 init方法 专门用于保存每个关卡中心点需要提交的东西,也方便重置。
// 地图中心点
class Main extends Item{
constructor(i, j, grids) {
super(i, j);
this.grids = grids
this.img = 'main';
this.w = 26;
this.init();
}
init(){
// 关卡需要提交的采集物类型
this.type = app.levels[app.level].type;
// 关卡需要采集的数量s
this.num = app.levels[app.level].num;
// 需要提交的是哪一半
this.half = app.levels[app.level].half || undefined;
// 已经提交的采集物
this.getNum = 0;
// 提交的采集物图形展示切割
if(this.half !== undefined){
// drawImage方法提供的切割区域参数
// sx
this.cx = -30
// sy
this.cy = 0;
// swidth
this.cw = 60;
// sheight
this.ch = 60;
// 切割后图形的偏移位置
this.hx = -3.5;
}
// half朝向来定义rotate图片旋转角度多少
if(this.half === 'top'){
this.rotate = 90;
} else if(this.half === 'right'){
this.rotate = 180;
}else if(this.half === 'bottom'){
this.rotate = 270;
}
}
}
这是第五关卡的,拿这个来举例子,这个关卡需要用到切割器把图形切成两半,然后在用旋转器把图片旋转成朝上的。这里我的逻辑就是利用canvas渲染图片原本就自带的属性来进行切割效果 参考下面第二张图。当然切割完剩下的是左半边。
这个时候再利用canvas的rotate方法来进行旋转,这里我直接封装成了一个 map类里的rotate方法就可以达到下图一的效果啦
旋转函数
rotate(x, y, rotate){
this.ctx.translate(x + 3.25, y + 3.25);
this.ctx.rotate(rotate * Math.PI / 180);
this.ctx.translate(-x - 3.25, -y - 3.25);
}
中心区域渲染图形
// 地图中心点
class Main extends Item{
constructor(i, j, grids) {
super(i, j);
this.grids = grids
this.img = 'main';
this.w = 26;
this.init();
}
info(x, y){
// 提示提交的采集物图形
app.map.begin()
app.map.rotate((x, y , this.rotate);
if(!this.half) app.map.drawImage((x + (6 * 6.5) + 4.5), y + (7 * 6.5) + 1, urlImg[this.type], 7.5);
else app.map.drawImage(x + this.hx, y, urlImg[this.type], 7.5, 7.5, this.cx, this.cy, this.cw, this.ch)
app.map.close()
}
}
右键删除放置工具
基本功能: 点击鼠标右键删除目标工具,完成的效果可以参考下面的动图;
实现及原理: 想要完成这个功能先要禁用鼠标右键的默认事件
document.oncontextmenu = function(){
return false;
}
禁用默认鼠标右键事件之后,可以通过鼠标的mousedown事件的属性event.button来判断是否点击的是鼠标右键。确定是鼠标右键之后,就可以拿到这个点击位置在地图上的相对位置,并删除掉这个格子里的工具就算是完成啦~
mousedown(ev){
// 点击的偏移位
this.dx = ev.offsetX;
this.dy = ev.offsetY;
// 获取点击位置在地图上的坐标
let x = ~~((Math.abs(this.map.translateX) + this.dx) / ((Math.pow(1.125, 20 - Math.abs(this.wheel))) * (this.game.w / 16)))
let y = ~~((Math.abs(this.map.translateY) + this.dy) / ((Math.pow(1.125, 20 - Math.abs(this.wheel))) * (this.game.h / 16)))
// 获取确切的格子
let grid = this.game.getGrid(x, y);
// 确定点击的是鼠标右键 并且 当前格子是有工具的
if(ev.button == 2 && grid.tool) {
grid.tool = null;
}
}
最终效果
旋转器
基本功能: 就和他的名字一样,把经过的采集物图形进行旋转的机器
实现及原理: 上次讲到所有的工具都是继承一个名字是 Tool 的Class类里的一些事件的,不清楚的可以参考我上一篇文章里的工具介绍。那么实现功能的基本原理相信我不用说大家也能想到;和第五关的展示提交采集物的图形一样,只需要切割之后再用之前封装在Map里的rotate事件进行旋转就能做到。
// 旋转器
class Rotate extends Tool{
constructor(i, j, dir) {
super(i, j, dir);
// 图片类型
this.img = 'rotate';
// 工具的输出朝向
this.dir = dir;
// 是否透明
this.pre = false;
// 工具进入方向
this.nextDir = app.reversePos(dir);
}
update(){
super.update(() => {
// 根据输出方向,设置工具旋转多大角度
if(this.dir === 'right'){
this.rotate = 90;
}else if(this.dir === 'bottom'){
this.rotate = 180;
}else if(this.dir === 'left'){
this.rotate = 270;
}else if(this.dir === 'top'){
this.rotate = 0;
}
// 旋转
app.map.rotate(this.x, this.y, this.rotate);
app.map.ctx.globalAlpha = this.pre ? .4 : 1;
if (!app.line) {
app.map.ctx.fillStyle = '#7DC6CD';
app.map.ctx.fillRect(this.x, this.y, this.w, this.w);
}
})
}
}
最终效果
垃圾桶
基本功能: 用于把采集或工具生成的不必要的采集物进行销毁。并且类似于切割工具会处理后生成两种采集物的工具是需要你在工具输出的两个出口都有传送带才能运行的。这时候用垃圾桶作为一个输出口的连接点就能完美解决这个问题
实现及原理: 这个工具一共有4个面都是可以连接工具或者是传送带的。从4个面进入后销毁采集物。因为要从4个方向渲染,所以也就不存在什么工具朝向问题,在Remove工具函数里,dir朝向直接为All。设置为All也是为了之后的Goods采集物进入时做的当前工具点的朝向增加一个 grid.tool.dir === 'All' 直接可通行的判断。
// 垃圾桶工具
class Remove extends Tool{
constructor(i, j, dir) {
super(i, j, dir);
// 图片类型
this.img = 'remove';
// 工具朝向
this.dir = 'all';
// 是否透明
this.pre = false;
}
update(){
// 继承Tool工具类的 update()方法 作为渲染图片用
super.update(() => {
app.map.ctx.globalAlpha = this.pre ? .4 : 1;
// 缩小地图后在工具在地图上的渲染
if (!app.line) {
app.map.ctx.fillStyle = '#E81C5C';
app.map.ctx.fillRect(this.x, this.y, this.w, this.w);
}
})
}
}
最终效果
缩小地图后放置的工具
基本功能: 这个功能就是为了地图被缩小之后,游戏还能对用户已经放置的工具有一个用canvas绘制出来的直观的提现。
实现及原理: 这个原理很简单,我每个工具显示出来都是因为继承了Tool工具类的update方法,那么我就只需要在继续继承的时候增加一个判断如果是缩小状态的时候绘制出来的像素块就行。
// 垃圾桶工具
class ??? extends Tool{
constructor(i, j, dir) {
super(i, j, dir);
}
update(){
// 继承Tool工具类的 update()方法 作为渲染图片用
super.update(() => {
app.map.ctx.globalAlpha = this.pre ? .4 : 1;
// 缩小地图后在工具在地图上的渲染
if (!app.line) {
// 绘制的颜色
app.map.ctx.fillStyle = '';
// 矩形块的绘制
app.map.ctx.fillRect(this.x, this.y, this.w, this.w);
}
})
}
}
后语
接下来有点长的话语可能会涉及到对三体小说的剧透!这个游戏目前能直接游玩的测试版只用10个关卡,目前我已经更新到了第五关,但是事实上很多核心算法看的出来还是有很大差距的。
这种感觉就像是我以前经常喜欢看的叫做《三体》的小说科幻小说,我相信对宇宙感兴趣的科幻迷应该都或多或少看过或者听说过,里面讲的大概的故事就是人类的前沿物理学知识被外星人通过某种手段锁死了。人类只能被还没被锁死的那所剩无几的物理知识来创造出对抗三体人的宇宙舰队。虽然在往后的200年里人类的确创造出了科技发展奇迹,甚至创造出的战舰一度在速度和数量上都远超三体外星人的舰队。 也让新世纪的人类一度认为可以战胜三体人,结果在第一次接触三体外星人的探测器的时候地球舰队就被摧毁的寥寥无几了。
讲这个故事也是想为大家说明我的两点感悟:引用小说里的一句话 “ 弱小和无知从来都不是生存的障碍,傲慢才是”,其实这个到底放在学习或者别的方面都是一样的。基础的扎实和你不断渴求新东西的态度是你能在这个行业生存下来的真谛,一旦停止进取和思考,只满足于现状导致的将是被那些时时进取的人完全碾压,以至于出现像三体小说里被敌人精神和物理意义上的双重 “降维打击”
所以!大家一起不断进取,不断学习新的知识,互相勉励~
那么本期的内容到这里就结束啦!也希望掘友们能为我的文章和在线代码 动动手指 点个赞!爱你们~
转载自:https://juejin.cn/post/7164181085473996813