Heim > Artikel > Web-Frontend > JavaScript-Schreiben Lianliankan mini game_javascript skills
Ich sehe jeden Tag andere Leute, die Lianliankan spielen, aber sie sagen, dass sie es nicht ernsthaft gespielt haben. Warum verbinden sie nicht einfach zwei identische Bilder?
Ich habe eines mit Javascript geschrieben und auf Github gehostet. Sehen Sie sich die Online-DEMO-Adresse an: Öffnen
Endgültiges Rendering:
Was sollten Sie beachten, bevor Sie Lianliankan schreiben?
1: Wie kann ich beurteilen, ob zwei Elemente verbunden sein können? Sie können hier nachschlagen:
2: Wie wähle ich eine Template-Engine aus? Ich habe die Vorlage der Bottom-Line-Bibliothek verwendet, weil die Syntax einfach ist. Ursprünglich wollte ich „Lenkers“ verwenden, aber das ist etwas umfangreich und die Endergebnisbibliothek bietet auch viele gängige Tools und Methoden ( •̀ ω •́ )y;
3: Wie gestalte ich das Layout? Es gibt ein Div innerhalb des Rahmens. Die Schnittstelle ist tatsächlich erfrischender und einfacher schreibe direkt in Leinwand. Ich habe Leinwand nicht ernsthaft studiert;4: Wie erreichen wir den Verbindungseffekt, wenn wir DOM zur Implementierung verwenden? Wenn die Elemente verbunden sind, müssen wir die Bilder auf dem Verbindungspfad positionieren . Oder verwenden Sie Canvas, um den Verbindungseffekt direkt zu zeichnen
Da ich keine Low-End-Browser in Betracht ziehe, habe ich die zeptoJS-Bibliothek verwendet und aus Gewohnheit auch auf Bootstrap verwiesenEs werden drei Hauptkonstruktoren verwendet, darunter Daten, Ansicht und Bewertung
Die Struktur von View ist wie folgt, mit relativ wenigen Dingen, einschließlich Ereignisbindung, Schnittstellengenerierung und dem Zeicheneffekt, wenn zwei identische Elemente verschwinden:
Ansicht
Die getImg-Methode im obigen Code ruft die getImg-Methode des globalen Fensters auf. Diese Methode generiert eine Bildzeichenfolge basierend auf den Daten und ist eine Hilfsfunktion:
/** * @desc 根据数据生成map * */ renderHTML : function /** * @desc 界面的主要事件绑定 * @return this; * */ bindEvents : function /** * @desc 工具方法,在canvas上面进行绘图; * @param [{x:0,y:0},{x:1,y:1},{x:2,y:2},{x:3,y:3}]一个数组, 会自动重绘; * */ showSparkLine : function tbody内部元素的模板是这样的: <script type="text/template" id="tr-td-tpl"> <% for(var i=0; i<data.length; i++) {%> <tr> <% for(var j=0; j< data[i].length; j++ ) { %> <td id="<%=i%><%=j%>" class="bg<%=data[i][j]%>" data-x="<%=j%>" data-y="<%=i%>" data-data="<%=data[i][j]%>" data-info='{"x":<%=[j]%>,"y":<%=[i]%>}'> <div> <%=getImg(data[i][j])%> </div> </td> <% } %> </tr> <% } %> </script>
Da es sich bei den Daten von Lianliankan um ein zweidimensionales Array handelt, müssen in der Vorlage zwei for-Schleifen verwendet werden. Die Schleifen generieren HTML-Strings. Wenn die Daten und die Vorlage kombiniert werden, wird die DOM-Struktur in der folgenden Abbildung generiert >
window.getImg = function( num ) { switch(num){ case 1: return "<img src='imgs/ani (1).gif' />"; case 2: return "<img src='imgs/ani (2).gif' />"; case 3: return "<img src='imgs/ani (3).gif' />"; case 4: return "<img src='imgs/ani (4).gif' />"; case 5: return "<img src='imgs/ani (5).gif' />"; case 6: return "<img src='imgs/ani (6).gif' />"; } };
Score-Modulkonstruktorfunktion Score, das ist der gesamte Code, der sich auf die Partitur bezieht (übergeben Sie das Element, rufen Sie direkt die addScore-Methode der generierten Instanz auf, und das DOM wird automatisch gerendert. Der Grund für das Schreiben eines separaten Konstruktors). Die Punktzahl gilt für die Entkopplung:
Konstruktordaten, die Hauptstruktur ist wie folgt. Obwohl es relativ wenige Methoden gibt, belegt der Code von Daten tatsächlich 300 Zeilen.... Um zu bestimmen, ob ein Element verbunden werden kann, verwenden Sie die Methode canConnect und die Methode canConnect ruft die dirConnect-Methode auf. Es ist ziemlich kompliziert. Wenn Sie mehr wissen möchten, schreiben Sie es am besten selbst:
Score = function(el) { this.el = $(el); this.score = 0; }; $.extend( Score.prototype , { /** * @desc 改变元素的HTML,递增分数; * @param * */ addScore : function() { this.el.html(++this.score); } });
Alle Codes lauten als Referenz wie folgt:
//新建初始化 newData : function //工具方法,随机混肴数组; suffer : function /** * @desc set值,把地图中对应的数据清空或者设置,两用接口 * @param x, y * @return chain * */ set : function /** * @desc 判断两个元素之间是否可以连接 * @param [{x:1,y:1},{x:1,y:1}] * @return false || [] * */ canConnect : function /** * @desc 判断元素是否可以直连 * @param [{x:1,y:1},{x:1,y:1}] * @return false || true * */ dirConnect
Online-DEMO-Adressansicht:
Öffnenlink 得分0
<script> var el = document.getElementById("tbody"); var elCan = document.getElementById("canvas"); var tpl = document.getElementById("tr-td-tpl"); var cfg = { width : 8, height : 8 }; window.getImg = function( num ) { switch(num){ case 1: return "<img src='imgs/ani (1).gif' />"; case 2: return "<img src='imgs/ani (2).gif' />"; case 3: return "<img src='imgs/ani (3).gif' />"; case 4: return "<img src='imgs/ani (4).gif' />"; case 5: return "<img src='imgs/ani (5).gif' />"; case 6: return "<img src='imgs/ani (6).gif' />"; } }; var View = function(data, score) { this.data = data; this.score = score; }, Data = function(cfg) { this.cfg = { width : cfg.width+2, height : cfg.height+2 }; this.getRandom = this.getRandom(); }, Score = function(el) { this.el = $(el); this.score = 0; }; $.extend( Data.prototype, { /** * @desc 把两个 * @param HTMLELEMENT * @return true || false * */ clear : function(obj, target) { }, /** * @desc 根据this.cfg新建数据到this.map * @param void * @return void * */ newData : function() { var result = []; for(var i=0; i<=this.cfg.height+1; i++ ) { result[i] = result[i] || []; for(var j = 0; j<= this.cfg.width+1; j++) { if(i === 0 || j===0 || (i===this.cfg.height+1) || j === (this.cfg.width+1) ) { result[i][j] = 0; }else{ //1-4 result[i][j] = this.getRandom(); } }; }; this.map = result; return this; }, //随机混肴数组; suffer : function(obj) { function random(min, max) { if (max == null) { max = min; min = 0; } return min + Math.floor(Math.random() * (max - min + 1)); }; var set = obj; var length = set.length; var shuffled = Array(length); for (var index = 0, rand; index < length; index++) { rand = random(0, index); if (rand !== index) shuffled[index] = shuffled[rand]; shuffled[rand] = set[index]; } return shuffled; }, /** * @return 返回值必须是成双的, 消除到最后尼玛,发现有一堆不匹配的,玩个球; * */ getRandom : function() { //如果消消乐是3*3, 那么你告诉我....最后一个和谁消, 所以要做的就是把所有的元素生成变成一半,然后返回; var arr = new Array( (this.cfg.height) * (this.cfg.width) / 2 ); var result = []; for(var i=0; i<arr.length; i++ ) { arr[i] = (Math.floor( Math.random()*6 ) + 1); }; result = Array.prototype.concat.call( [] , arr, arr); result = this.suffer( result ); return function( ) { return result.pop(); }; }, /** * @desc set值 * @param x, y * @return chain * */ set : function( x, y) { this.map[y][x] = 0; return this; }, /** * @desc 判断元素是否可以连接 * @param [{x:1,y:1},{x:1,y:1}] * @return false || true * */ canConnect : function(obj,target) { var map = this.map; //循环obj的y轴相等 , obj.x旁边所有数据为0的元素;; var getX = function( obj ) { var result = []; //循环找出在X附近为0的元素; for(var i=obj.x+1; i< map[0].length; i++) { if( map[obj.y][i] == 0 ) { result.push( {x:i, y:obj.y} ); }else{ break; }; }; for(var i=obj.x-1; i>=0; i--) { if( map[obj.y][i] == 0 ) { result.push( {x:i,y:obj.y} ); }else{ break; }; }; return result; }; //循环obj的x轴相等, obj.y旁边所有数据为0的元素; var getY = function(obj) { var result = []; for(var i=obj.y+1; i<map.length; i++) { if( map[i][obj.x] == 0) { result.push( { x : obj.x ,y : i} ); }else{ break; }; }; for(var i=obj.y-1; i>=0; i--) { if( map[i][obj.x] == 0 ) { result.push( { x : obj.x ,y : i} ); }else{ break; }; }; return result; }; var arr0 = Array.prototype.concat.call( [], getX(obj), obj, getY(obj)).filter(function(obj) { return !!obj; }); var arr1 = Array.prototype.concat.call( [], getX(target), target, getY(target) ).filter(function(obj) { return !!obj; }); for(i = 0; i<arr0.length; i++) { for(var j = 0; j<arr1.length; j++) { //只要有一个连接就返回true; if( this.dirConnect(arr0[i],arr1[j]) ) { return [obj, arr0[i], arr1[j], target]; }; }; }; return false; }, /** * @desc 判断元素是否可以直接连接 * @param [{x:1,y:1},{x:1,y:1}] * @return false || true * */ dirConnect : function(obj, target) { var map = this.map; //row是x轴 列 //col是y轴 行 var min = 0, max = 0, sum = 0; if(obj.y === target.y) { if(obj.x < target.x) { min = obj.x; max = target.x; }else{ min = target.x; max = obj.x; }; for(var i=min; i<=max; i++) { sum += map[obj.y][i]; }; if(sum === (map[obj.y][obj.x] + map[target.y][target.x])) { return true; }else{ return false; }; }; if(obj.x === target.x) { if(obj.y < target.y) { min = obj.y; max = target.y; }else{ min = target.x; max = obj.y; }; for( i=min; i<=max; i++) { sum += map[i][obj.x]; }; if( sum === (map[obj.y][obj.x] + map[target.y][target.x])) { return true; }else{ return false; }; }; } }); $.extend( View.prototype, { /** * @desc 为view添加视图的主元素 * @return void * */ setEL : function(el) { this.el = el; return this; }, setTpl : function(tpl) { this.tpl = _.template( tpl.innerHTML ); return this; }, /** * @desc 根据数据生成map * */ renderHTML : function() { $(this.el).html( this.tpl( {data : this.data.map} ) ); return this; }, /** * @desc 界面的主要事件绑定 * @return this; * */ bindEvents : function() { $(this.el).delegate("td", "click", this.click.bind(this)); return this; }, /** * @desc click事件, 单独抽出来的; * */ click : function(ev) { //修改样式; $("td.active").removeClass("active"); var target = $(ev.target).closest("td"); target.addClass("active"); //第一次点击我们做的特殊处理; var prev = this.prev; if( !prev || target[0] === prev[0]){ this.prev = target; return; }; if( prev.attr("data-data") === target.attr("data-data")) { var xy = JSON.parse( prev.attr("data-info") ); var xxyy = JSON.parse( target.attr("data-info") ); //保存了连接的数组信息 var connectionInfo = [] || false; if( connectionInfo = this.data.canConnect( xy, xxyy) ) { this.showSparkLine( connectionInfo ); this.prev = undefined; this.data.set(xy.x, xy.y); this.data.set(xxyy.x, xxyy.y); this.score.addScore(); var _this = this; setTimeout(function() { _this.renderHTML(); },2000); }; prev.attr("data-data", ""); target.attr("data-data","") }else{ this.prev = target; }; }, /** * @desc 工具方法,在canvas上面进行绘图; * @param [{x:0,y:0},{x:1,y:1},{x:2,y:2},{x:3,y:3}]一个数组, 会自动重绘; * */ showSparkLine : function( arr ) { arr = arr.map(function(xy) { return { x : (xy.x)*40 + 20, y : (xy.y)*40 + 20 } }); var elCan = document.getElementById("canvas"); function spark(ctx) { function showAndClear(arr, lineWidth) { ctx.clearRect(0,0,elCan.width,elCan.height); ctx.beginPath(); ctx.lineJoin = "round"; ctx.lineWidth = lineWidth; ctx.shadowColor = "rgba(241, 196, 15, 0.41)"; ctx.shadowOffsetX = 1; ctx.shadowOffsetY = 1; ctx.shadowBlur = 1; for(var i=0; i<arr.length-1; i++) { var xy = arr[i]; var nextXY = arr[i+1] ctx.moveTo(xy.x, xy.y); ctx.lineTo(nextXY.x, nextXY.y); }; ctx.stroke(); }; var ctx = elCan.getContext("2d"); ctx.strokeStyle = "#F1C40F"; var lineWidthArr = [1,2,1,2,1,3,1,0]; var len = lineWidthArr.length; var times = 400, addTimes = 200; while(len--) { (function(len){ setTimeout(function() { showAndClear(arr, lineWidthArr[len]); if(len==0) { ctx.clearRect(0,0,elCan.width,elCan.height); } }, times); times += addTimes; })(len) }; }; spark( elCan ); } }); $.extend( Score.prototype , { /** * @desc 改变元素的HTML,递增分数; * @param * */ addScore : function() { this.el.html(++this.score); } }); $(function() { var score = new Score( document.getElementById("score") ); var data = new Data(cfg).newData(); var view = new View(data, score); view.setEL( el ).setTpl( tpl).renderHTML().bindEvents(); (function init() { //如果通过style属性添加width或者height,会根据原来的宽和高度自动伸缩的 elCan.width = el.offsetWidth; elCan.height = el.offsetHeight; })(); }); </script>
Das Obige ist der gesamte Inhalt dieses Artikels. Ich hoffe, er gefällt Ihnen allen.