纯JS的打字游戏算是JavaScript入门的一个检验吧,我开始做的时候也是各种蒙圈,确实作为前端小白有点不知道该怎么入手,但是学习了那么久的知识,总得磨刀霍霍向猪羊…啊呸,总得实践出真知啊。所以在网上研究了和分析了别人的程序(我想知道实现的思路却全都是代码,大概别人都觉得这个太简单了吧-,-),花了一段时间把代码写出来了,现在来分享一下我的成果~

一、太长不看我只要代码

Edition 1:(点这里下载版本1代码)

这部分代码是属于完全的功能的堆砌,没有对JavaScript代码进行对象化处理,属于人家一看就觉得low但是作为初学者的我好理解的类型(ps: 为了美观起见,我还是不是纯JS的代码,有部分样式设计)。关门,放代码:

<!--  index.html  -->
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>Typing Game</title><link rel="stylesheet" type="text/css" href="style.css">
</head>
<body>
<div id="container"><!--  显示游戏提示  --><div id="tools"><div class="list"><h2>单词大战</h2><p>到达底线消灭游戏框中出现的字母</p></div><div class="list"><h2>游戏得分</h2><p>首局游戏需得分<span id="need">10</span>分</p></div></div><!--  背景盒  --><div id="box" style="height: 640px; width: 760px;"><div id="panel">得分:<span id="score">0</span></div><button id="start" class="btn">开始游戏</button><button id="stop" class="btn">停止游戏</button><!--  游戏的部分  --><div id="gameBox" style="height: 610px; width: 585px;"></div><div id="danger"><hr/></div></div>
</div>
<script type="text/javascript" src="main.js"></script>
</body>
</html>
/*  style.css  */
* {margin: 0;padding: 0;
}html, body {/*  Box-model  */height: 100%;/*  Typography  */color: #fff;font-family: helvetica, arial, sans-serif;/*  Visual  */background: -webkit-linear-gradient(#3a3a3a, #c3c3c3);background: -o-linear-gradient(#3a3a3a, #c3c3c3);background: -moz-linear-gradient(#3a3a3a, #c3c3c3);background: linear-gradient(#3a3a3a, #c3c3c3);
}#container {/*  Positioning  */position: relative;margin-left: auto;margin-right: auto;/*  Box-model  */display: block;width: 80%;max-width: 1140px;
}#tools {/* Positioning */position: absolute;top: 32%;left: 25%;margin-top: 50px;z-index: 100;/*  Box-model  */display: block;padding: 5px;
}#tools .list {/* Positioning */margin-bottom: 35px;/*  Typography  */font-family: "Microsoft YaHei UI", "微软雅黑";
}#panel {/* Positioning */position: absolute;right: 5%;top: 5%;z-index: 100;/*  Box-model  */display: none;/*  Typography  */font-family: "Microsoft YaHei UI", "微软雅黑";font-weight: 700;/*  Visual  */text-shadow: 2px 2px 3px rgba(255, 255, 255, 0.5);/*  Misc  */
}.btn {/*  Positioning  */z-index: 100;/*  Box-model  */display: inline-block;width: 80px;height: 40px;/*  Typography  */font-family: helvetica, Arial, sans-serif;line-height: 40px;text-align: center;/*  Visual  */color: #fff;background-color: #999;-webkit-border-radius: 15px;-moz-border-radius: 15px;border-radius: 15px;-webkit-box-shadow: 0 0 2px 5px rgba(255, 255, 255, 0.5);-moz-box-shadow: 0 0 2px 5px rgba(255, 255, 255, 0.5);box-shadow: 0 0 2px 5px rgba(255, 255, 255, 0.5);/*  Misc  */opacity: 0.8;cursor: pointer;
}#start {/*  Positioning  */position: absolute;right: 5%;top: 34%;
}#stop {/*  Positioning  */position: absolute;right: 5%;top: 48%;}#box {/*  Positioning  */position: relative;top: 50px;margin-left: auto;margin-right: auto;/*  Box-model  */display: block;height: 640px;width: 760px;/*  Visual  */background-image: url("backdrop.png");border: 1px solid #888;/*  Misc  */opacity: 1;
}#gameBox {/*  Positioning  */position: relative;/* Box-model */margin-top: 20px;margin-left: 20px;
}#danger {/*  Positioning  */position: absolute;left: 0;bottom: 30px;/*  Box-model  */width: 100%;/*  Typography  */text-align: center;/*  Visual */color: #c3c3c3;border-top: 5px dotted #c3c3c3;
}
/*** main.js*/// 1. 字母下降的速度选择
var getSpeed = {1: {speed: 50},2: {speed: 30},3: {speed: 20},4: {speed: 10},5: {speed: 5}
};// 2. 随机生成字母
function getRandom() {// 随机生成一个字母( a-z )的ASCII码var charCode = 97 + Math.floor(Math.random() * 26);// 将该ASCII码转化为字母return String.fromCharCode(charCode);
}// 获取键盘上按键的值并消除
function game(level, score) {var gameBox = document.getElementById("gameBox");var letterArr = [],     // 字母对象列表spanArr = [];       // span对象列表var hit = 0;            // 击中个数var start = function () {// 使用random可以使每次下落的字母数随机if (Math.random() > (0.8 - level * 0.01)) {var letterIn = getRandom();letterArr.push(letterIn);spanArr.push(createSpan(letterIn));window.addEventListener("keyup", keyup);}};// 绑定键盘事件var keyup = function (event) {var e = event || window.event || arguments.callee.caller.arguments[0];var keyCode = String.fromCharCode(e.keyCode);for (var i = 0; i < letterArr.length; i++) {if (keyCode.toLowerCase() === letterArr[i]) {clearInterval(spanArr[i].intervalID); // 这是一句不写就后患无穷的代码,不信你可以试试spanArr[i].parentNode.removeChild(spanArr[i]);letterArr.splice(i, 1);spanArr.splice(i, 1);hit++;document.getElementById("score").innerHTML = hit;if (hit >= Number(score) && getSpeed[level + 1] === undefined) {alert("恭喜你,所有关卡挑战成功!");location.reload();return;} else if (hit >= Number(score)) {clear();alert("恭喜你,进入下一关卡!\n下一关卡需要得分:" + ( score + 10 ));document.getElementById("score").innerHTML = 0;game(level + 1, score + 10);}break;}}};// 3. 根据随机生成的字母生成标签,插入到gameBox中并显示var createSpan = function (letter) {var span = document.createElement("span");var spanCon = document.createTextNode(letter);var loc = document.getElementById("gameBox");var width = parseInt(loc.style.width);span.appendChild(spanCon);span.setAttribute("style","position:absolute;" +"top:" + parseInt(loc.offsetTop) + "px;" +"left:" + Math.random() * width + "px;" +"display:inline-block;" +"height:15px;width:15px;" +"line-height:15px;" +"text-align:center;" +"background-color:#888;" +"border-radius:15px;" +"box-shadow:0 0 2px 5px rgba(255,255,255,0.5);" +"opacity:0.8");loc.appendChild(span);spanMove(span);return span;};// 4. 获取标签位置始末并下落var spanMove = function (span) {// 页面高度var height = parseInt(document.getElementById("gameBox").style.height);var top = parseInt(span.style.top);span.intervalID = window.setInterval(function () {if (span.parentNode) {top = top + 1;if (top <= height - 40) {span.style.top = top + "px";} else {span.style.boxShadow = "0px 0px 2px 5px red";console.log(span.intervalID);clearInterval(span.intervalID);alert("很遗憾,挑战失败,游戏结束!");location.reload();}}}, getSpeed[level].speed);};var clear = function () {clearInterval(game.timer);window.removeEventListener("keyup", keyup);for (var n = spanArr.length - 1; n >= 0; n--) {console.log(spanArr[n] === null);if (spanArr[n] !== null) {spanArr[n].parentNode.removeChild(spanArr[n]);clearInterval(spanArr[n]);spanArr[n] = null;}}letterArr = [];};game.timer = setInterval(start, 200);
}// 游戏开始
document.getElementById("start").addEventListener("click", function () {var start = document.getElementById("start");start.disabled = true;start.style.cursor = "not-allowed";document.getElementById("tools").style.display = "none";document.getElementById("panel").style.display = "inline-block";game(1, 10);
});
// 游戏结束
document.getElementById("stop").addEventListener("click", function () {location.reload();document.getElementById("start").disabled = false;document.getElementById("tools").style.display = "block";document.getElementById("panel").style.display = "none";
});

Edition 2 :

对象化设计该部分,将功能细分并且抽象,使得代码更易于阅读和修改(ps:大概这部分才是前端愿意看的代码…)。这里只放修改后的JS的部分咯,再关门,再放代码:

/*** main.js*/
// 1. letter对象,使用构造函数模式创建对象
/*** @param id:    时间戳作为每个标签的唯一标识* @param value: 存储随机生成的字母值* @param x_pos: 标签的left初始值* @param y_pos: 标签的top初始值*/
function Letters(id, value, x_pos, y_pos) {this.id = id || '';this.value = String.fromCharCode(value) || 'A';this.x_pos = x_pos || 0;this.y_pos = y_pos || 0;this.speed = Math.random() * 3 + 1;this.domObj = null;this.createSpan = function () {var span = document.createElement("span");var alpha = document.createTextNode(this.value);span.appendChild(alpha);span.setAttribute("id", this.id);span.setAttribute("style","position:absolute;" +"top: 0px;" +"left: 0px;" +"display:inline-block;" +"height:15px;width:15px;" +"line-height:15px;" +"text-align:center;" +"background-color:#888;" +"border-radius:15px;" +"box-shadow:0 0 2px 5px rgba(255,255,255,0.5);" +"opacity:0.8");this.domObj = span;};// 将标签创建之后赋值给this.domObj,调用此函数时,将this.domObj添加到相应父元素中去this.attachStage = function (stage) {stage.appendChild(this.domObj);};this.moveTo = function (x_pos, y_pos) {this.domObj.style.left = x_pos + "px";this.domObj.style.top = y_pos + "px";};this.remove = function () {var span = document.getElementById(this.id);if (span.parentNode !== null) {span.parentNode.removeChild(span);} else {console.log("No parent Node! " + span.id);}};this.failed = function () {var span = document.getElementById(this.id);span.style.boxShadow = "0px 0px 2px 5px red";};
}// 2. Monitor对象
function Monitor(level, score) {// 存储当前屏幕上的所有元素var nodes = [];// 存储最终得分var final = new Score();// 逐帧运行this.runFrame = function () {if (Math.random() > 0.8) {this.createAlpha();}for (var i = 0; i < nodes.length; i++) {nodes[i].y_pos = parseInt(nodes[i].y_pos) + nodes[i].speed;nodes[i].y_pos += "px";document.getElementById(nodes[i].id).style.top = nodes[i].y_pos;if (parseInt(nodes[i].y_pos) > 560) {nodes[i].failed();alert("很遗憾,挑战失败,游戏结束!");location.reload();}if (level === 5 && final.getCount() >= score) {alert("恭喜你,完成所有关卡,闯关成功!");location.reload();console.log("getCount = " + final.getCount() + " score = " + score + final.getCount() >= score);} else if (final.getCount() >= score) {alert("恭喜你,进入下一关卡\n下一关卡需要得分:" + (score + 10));final.clearScore();document.getElementById("score").innerHTML = String(0);this.clear();level++;score += 10;this.Monitor(level, score);}}};// 生成字母表标签this.createAlpha = function () {// 随机生成字母(A - Z)var code = 65 + Math.floor(Math.random() * 26);var letter = new Letters(new Date().getTime(), code);// 将定义的节点添加到盒子中letter.createSpan();letter.attachStage(document.getElementById("gameBox"));var x = Math.ceil(Math.random() * parseInt(document.getElementById("gameBox").style.width));var y = 0;letter.moveTo(x, y);nodes.push(letter);return letter;};// 绑定键盘事件this.keydown = function (event) {var e = event || window.event || arguments.callee.caller.arguments[0];var keyCode = String.fromCharCode(e.keyCode);for (var i = 0; i < nodes.length; i++) {if (keyCode === nodes[i].value) {nodes[i].remove();nodes.splice(i, 1);final.incScore();document.getElementById("score").innerHTML = final.getCount();break;}}// 跳出循环后,i = monitor.node.length || i = 当前value在node中的下标// 若i = monitor.node.length, 则表明未找到键盘按下的字母// i !== 0排除数组只有一个元素且被消除的情况if (i === nodes.length && i !== 0) {final.decScore();document.getElementById("score").innerHTML = final.getCount();if (final.getCount() === 0) {alert("很遗憾,您的分数太低了,挑战失败!");location.reload();}}};// 清除游戏界面上的多余标签this.clear = function () {for (var i = 0; i < nodes.length; i++) {nodes[i].remove();}nodes.splice(0, nodes.length);clearInterval(this.Monitor.timer);};this.refreshFrame = {1: {time: 150},2: {time: 100},3: {time: 80},4: {time: 50},5: {time: 30}};window.addEventListener("keydown", this.keydown);this.Monitor.timer = setInterval(this.runFrame, this.refreshFrame[level].time);
}// 3. 计分对象
function Score() {var count = 0;this.incScore = function () {count++;};this.decScore = function () {count --;};this.getCount = function () {return count;};this.clearScore = function () {count = 0;}
}// 游戏开始
document.getElementById("start").addEventListener("click", function () {var start = document.getElementById("start");start.disabled = true;start.style.cursor = "not-allowed";document.getElementById("tools").style.display = "none";document.getElementById("panel").style.display = "inline-block";Monitor(1, 10);
});// 游戏结束
document.getElementById("stop").addEventListener("click", function () {location.reload();document.getElementById("start").disabled = false;document.getElementById("tools").style.display = "block";document.getElementById("panel").style.display = "none";
});

二、代码设计详解

这一部分内容我也按照不同的版本来进行不同的解释好了,按照上面摆放的顺序,首先来说一下第一个版本。

Edition 1 代码分析

这里我先要说一下,原则上纯JS的打字游戏是没有这么多元素更没有CSS文件的,我只是看到有的游戏做的很好看,然后就突发奇想把自己做的游戏加上了样式,还顺便捞过来一个背景图→_→,不知道算不算侵权,如果算作者记得提醒我我就换一下。哦,还有我的样式只是我在我自己的电脑上看起来比较顺眼,换了电脑如果样式辣眼睛我是不负责任的。

———— (正事专用分隔线←_←)

HTML文件和CSS样式就不多说了,“开始游戏”按钮控制游戏的开始,游戏中的字母标签均在 <div id="gameBox">中生成并消除,该盒子就是这个游戏最重要的容器。

我们来考虑一个问题,字母游戏的需求是什么:不断生成掉落的字母,然后由用户键盘按下后对应消除游戏界面上的字母,当字母超出界面或者按错按钮时做出对应操作。根据该需求,我们不难得到,字母游戏的主要功能有以下几点:

  1. 随机生成需要的字母
  2. 设置字母下落
  3. 键盘绑定和鼠标点击事件的完成
  4. 设置游戏结束的判断

现在可以开始完成功能了:使用JS自带的Math对象随机生成一个数字,并将该数字转换为字符串中的字符。也就是我们上面的getRandom()函数:

接着我们考虑,游戏需要的内容,有了生成的字母,现在需要一个标签来装这个字母,然后标签装好了字母后还要从顶部向下掉落,所以创建标签函数中需要一个参数,该参数表示传入的字母值,将字母值写入span标签的文本节点并对其设置样式,然后将设置好内容和样式的标签插入到游戏盒子中去,这就是createSpan()函数完成的工作;至于标签下落的工作就不妨交给spanMove()函数,它可以获取页面高度,并对每一个元素设置对应的计时器ID(正式代码千万不要这样写,效率极低!!!另外此处还有一个容易被忽略掉的bug,让我头疼了很久啊,后面仔细说)。

至此,我们完成了1、2两个功能点。接下来我们看第3个功能点,键盘绑定事件(哎呀,我开始以为很难,其实简单到只有几行代码←_←)

我们可以先写一个start函数来运行前面的代码,start函数作为整体游戏的setInterval的功能,对该游戏进行重复的调用,具体代码见start()函数,功能很好理解,随机生成一个字母,将该字母添加到全局变量letterArr[]中,然后调用createSpan()函数生成字母对应的标签元素,再对窗口添加键盘监听事件。那么键盘监听事件做的事情有哪些呢:获取键入信息→判断键入信息是否与自身定义的对象相同→根据判断结果做出不同的响应。具体代码见keyup()函数。

最后,我们来考虑游戏结束的判断。我在设计游戏的时候,设置的一共有5关,每一关过关分数在之前的基础上加10分,一旦元素接触到底线游戏就结束,用户成功闯过5关则挑战成功。此处有三处判断:1. 游戏界面是否有元素触碰到底线(该部分判断在spanMove()函数中);2. 用户在当前关卡是否已经达到过关分数;3. 用户是否全部闯关成功(判断2,3在keyup()函数中)。在这里,我就遇到了由于每个元素都设置了setInterval()而带来的隐患:我在数组中将元素删除了之后,没有清除元素对应的计时器,导致元素从游戏界面上清除了但是过了一段时间会直接弹出“游戏失败”的幽灵事件。解决方案也是只有一行代码,我已经在对应的地方做了标注。

Edition 2 代码分析

恕我直言,自己写了第二个版本之后,真心觉得第一个版本没眼看…这都是什么鬼,功能各种交缠,说都说不清楚,就是纯粹的功能的堆叠没有一点逻辑!请注意:JavaScript是面向对象的语言!JavaScript是面向对象的语言!!JavaScript是面向对象的语言!!!所以,在设计代码的时候,注意要从面向对象的方式来思考问题。把之前的所有思路打破,来分析一下在打字游戏中有哪些对象:

  1. 游戏盒子——用于展现字母和下落的效果,在代码中就是id="gameBox"的div元素,它像舞台一样圈定了游戏的范围;
  2. 字母对象——用于创建和执行所有与字母相关的操作:例如创建字母标签,将字母标签移动至指定坐标,移除字母标签等
  3. 指挥者对象——用于指挥游戏盒子中所有元素的行为:例如生成一个字母表,每一帧中各字母对象的移动,键盘监听事件,清空所有元素等。

首先,我们来看第一个对象:我们在HTML文件中已经设置了一个div标签用于确定游戏盒子的大小和方位,之后的操作只需要把生成的字母标签添加到游戏盒子中即可,对象1的功能就到此结束。

其次,我们解释一下字母对象,和字母有关的操作:创建字母,删除字母,改变字母的状态。此处可能会有疑问,字母下落难道不是和字母相关的操作吗?准确的说,字母下落是指挥者控制的行为,字母本身只需要确定它需要下落的初始位置,下落的行为不由字母本身控制,而是应该由指挥者指导,并且下落是所有字母的共同行为,所以如果每个字母逐个下落,反而不如由指挥者控制每一帧中字母的下落来得方便和效率。另外,字母作为对象,它需要接收一系列参数,每个字母应该有一个id,还应该有字母的值,同时,为了确认下落初始位置,还可以设置两个参数x_pos和y_pos来确认方位。对应所需要的方法就有创建字母标签createSpan(),将字母标签添加至盒子attachStage(),将字母移动到指定的初始位置moveTo(),移除当前字母标签remove(),代码中的failed()方法用于改变字母标签的状态,当字母标签下落至危险区域时,将标签设置为该状态提示用户。

最后是指挥者对象,指挥者对象首先需要有创建字母数组的功能,能够在屏幕上显示多个字母,对应createAlpha()方法;然后指挥者需要能够监控键盘,获取并判断用户键入的值是否与当前屏幕上显示的值相同,对应keydown()方法;最后还需要一个清除屏幕上所有字母的方法,对应clear()方法。这里再讨论一下上一个对象中移动的问题,指挥者作为所有字母行为的监控人,它是用来指挥所有字母下落的,这里需要用到计时器的setInterval()函数来对每一帧的内容进行修改,当执行的频率较快时,用户就不会看到明显的卡顿了。所以setFrame()函数就用来控制字母表的行为,并对闯关的结果进行判断。

不知道读者大大有没有觉得Edition 2整体功能很清晰,从上往下逐个解读也没有任何困难,反正我是觉得写了两个版本之后,深刻的意识到面向对象的好处,就是逻辑清晰,包装良好同时各部分适当耦合,符合最小最大和开放封闭原则,是一个很好的编码方式。在之后的学习中,我也会尽量去按照这种方式去进行编码。

参考网址

http://www.cnblogs.com/diligenceday/p/5857103.html
http://www.mycodes.net/166/7302.htm
(背景图就是上面的代码里“盗”的),这个游戏真的炫,我这个小菜鸡是做不出来

前端小白系列——打字游戏相关推荐

  1. 前端小白系列之——导言

    博主前端小白一枚,接触前端有小半年了,此次希望能专心从零开始做一个有自己特色本地页面,鞭挞下自己以严谨的规范代码写页面,顺便写成个系列,仅此而已. 这个页面一开始只是想着要实现前端常用的一些组件,像是 ...

  2. 前端小白系列——Bootstrap重现捕鱼猎人页面

    之前写了一个纯CSS的捕鱼猎人仿写页面,还是很容易发现没有媒体查询和完整的响应式页面体系,HTML和CSS能够完成的事情还是有限的.现在来看看对应的Bootstrap版本应该如何入手.首先,先下载最新 ...

  3. html+css+js适合前端小白的实战全解(超详细)——2048小游戏(三)

    续上一小节,我们回到newgame()这个函数,我们之前只做了init()内函数,相当于一个初始化操作 现在,我们需要再随机两个两个生成数字. 随机生成数字在这个游戏里会经常出现,用户移动一步,也会产 ...

  4. html+css+js适合前端小白的实战全解(超详细)——2048小游戏(二)

    续上一小节,我们可以发现每一个grid-cell上的数字初始时并不在格子里. 这些数字可以随着玩家的操作而移动 ​ 我们可以想象:初始时每一个格子上的数为0,他们并不显示 ↓ 只有当grid-cell ...

  5. 使用c#制作打字游戏_使用打字稿iii绘制网格构建游戏4 5

    使用c#制作打字游戏 Chapter III in the series of tutorials on how to build a game from scratch with TypeScrip ...

  6. Web前端小白入门指迷

    大前端之旅 大前端有很多种,Shell 前端,客户端前端,App 前端,Web 前端和可能接下来很会火起来的 VR 前端等.当然在这篇文章,集中讨论一下身为小白,我们怎样去了解 Web 前端,以至达到 ...

  7. c语言 倒计时不清屏_打字游戏超细讲解(C语言基础小游戏)

    首先我们会发现我们网上看到的打字游戏都是上来就敲代码,小白看的一脸懵,所以鑫哥在这给大家送上一份超级详细的打字游戏编写流程及对应的结果展示,希望可以帮到小白进行入门学习. 话不多说,我们先看一下什么叫 ...

  8. 前端小白也能快速学会的博客园博客美化全攻略

    前端小白也能快速学会的博客园博客美化全攻略 A呦V,博客园er的自我修养是什么?第一条,别只顾收藏和偷师呀,记得点"推荐"或关注本人喔~ 美化方法论简介 一般而言,需要选一个默认的 ...

  9. Linux打字游戏程序代码,c语言shell打字游戏.pdf

    一.实验说明 1. 环境登录 无需密码自动登录 ,系统用户名shiyanlou ,密码shiyanlou 2. 环境介绍 本实验环境采用带桌面的Ubuntu Linux环境 ,实验中 用到桌面上的程序 ...

  10. 2021年最新版Web前端学习路线图-前端小白入门必读-推荐

    2021年最新版Web前端学习路线图-前端小白入门必读-推荐 Hello,大家好,相信很多学习前端的小伙伴,会有很多的疑惑: 我要学习那些技术? 我要到哪里去学习这些技术呢? 学习这些技术的目的对就业 ...

最新文章

  1. Java基类共同属性设置_java – 你有一个Hibernate实体的基类吗?
  2. 双边滤波器在灰度和彩色图像处理中的应用
  3. 敏捷到底有没有带来新的东西?
  4. 【git】git基本操作命令
  5. java 蓝桥杯算法训练 水仙花(题解)
  6. 用于构建高级媒体应用程序的工具
  7. oracle取本月最后一天是星期几_在oracle里,如何取得本周、本月、本季度、本年度的第一天和最后一天的时间...
  8. WinForm模拟单击按钮两种方法
  9. C语言如何调用REFPROP软件,如何用C++6.0调用refprop物性查询软件
  10. 【MySql】Navicat Premium 15 无限试用脚本
  11. 联想笔记本声音太小怎么办_图文详解笔记本电脑声音太小解决方法
  12. 好用的飞书版固定资产管理系统
  13. MyBatis-Plus配置全局sql注入器后,BaseMapper中方法失效
  14. Activiti6.0 用户任务分配方式总结(单人任务、多人任务)
  15. ps如何做出动态火焰燃烧效果
  16. FCPX插件:视频去闪烁插件DEFlicker安装教程
  17. 在线预览文档 Office Online
  18. 2021-11-01第一节课总结
  19. 云悦智联企业级物联网官网源码
  20. 用matlab绘制翼型,机翼翼型的Matlab编程

热门文章

  1. 二维凸包算法(Andrew算法)
  2. Dism++ 一款传说中的系统工具,使用简介
  3. 汉诺塔c 语言程序代码,汉诺塔 (C语言代码)
  4. 【推荐算法】推荐系统必读论文整理
  5. 遗传算法Python代码实现
  6. win10正常上网但是网络图标显示无连接,无法开启热点
  7. 快速上手Perl语言
  8. ubuntu 常用命令锦集
  9. java常见反编译工具
  10. 炮灰模型——女生选择追求者模型