HT for Web 3D游戏设计设计--汉诺塔(Towers of Hanoi)
在這里我們將構(gòu)造一個基于HT for Web的HTML5+JavaScript來實現(xiàn)漢諾塔游戲。
漢諾塔的游戲規(guī)則及遞歸算法分析請參考http://en.wikipedia.org/wiki/Tower_of_Hanoi。
知道了漢諾塔的規(guī)則和算法,現(xiàn)在就開始創(chuàng)建元素。用HT for Web(http://www.hightopo.com)現(xiàn)有的3D模板創(chuàng)建底盤和3根柱子不是問題,問題是要創(chuàng)建若干個中空的圓盤。一開始的想法是:創(chuàng)建一個圓柱體,將圓柱體的上下兩端隱藏,設(shè)置柱面的寬度來實現(xiàn)圓盤的效果,經(jīng)過多次嘗試并查閱相關(guān)api文檔,發(fā)現(xiàn)柱面是沒有厚度的,改方法不可行。
后來在HT for Web自定義3D模型的WebGL應(yīng)用(http://www.hightopo.com/blog/381.html)受到啟發(fā),圓盤的形成就是在xy平面上的一個矩形,根據(jù)y軸旋轉(zhuǎn)一周產(chǎn)生的,通過查閱相關(guān)文檔,最總決定采用ht.Default.createRingModel方法來創(chuàng)建圓盤模型,然后在創(chuàng)建node的時候通過shape3d屬性引用創(chuàng)建好的模型。
?
在邏輯實現(xiàn)上,采用了棧的先進(jìn)后出的原理,對圓柱上的圓盤做順序控制,確保每次移動的圓盤都是最小的圓盤。
在算法上,采用的是遞歸算法,通過遞歸算法,將搬遷過程一步一步記錄下來,再采用堆的原理一步一步地執(zhí)行搬遷過工作。
?
http://v.youku.com/v_show/id_XODcwMTk4MDI4.html
var barNum = 5, // 圓盤個數(shù)cylinderHeight = barNum * 20 + 40, // 圓柱高度barrelMinORadius = 50, // 圓盤最大外半徑barrelIRadius = 10, // 圓盤內(nèi)半徑poorRadius = 20, // 圓盤外半徑差值barrelMaxORadius = barrelMinORadius + barNum * poorRadius,barrelHeight = 20, // 圓盤高barPadding = 20, // 柱體之間的間隙floorX = barrelMaxORadius * 6 + barPadding * 4, // 底盤長floorY = 20, // 底盤高floorZ = 2 * barrelMaxORadius + barPadding * 2, // 底盤寬// 柱體集positions = [{barrels: [],position: [-(2*barrelMaxORadius + barPadding), cylinderHeight / 2 + 1, 0]},{barrels: [],position: [0, cylinderHeight / 2 + 1, 0]},{barrels: [],position: [(2*barrelMaxORadius + barPadding), cylinderHeight / 2 + 1, 0]}],runOrder = [], // 圓盤移動順序集// 動畫參數(shù)params = {delay: 10,duration: 500,easing: Easing['easeBoth']};/*** 初始化程序* */ function init(){dataModel = new ht.DataModel();g3d = new ht.graph3d.Graph3dView(dataModel);view = g3d.getView();view.className = 'main';document.body.appendChild(view);window.addEventListener('resize', function (e) {g3d.invalidate();}, false);g3d.setEye([0, cylinderHeight * 2, floorX * sin(2*PI/360*60)]);// 初始化節(jié)點 initNodes();moveAnimation(); }/*** 構(gòu)造游戲移動隊列* diskQuantity:圓盤個數(shù)* positionA:起點* positionB:中轉(zhuǎn)點* positionC:終點* */ function buildRunOrder(diskQuantity, positionA, positionB, positionC){if (diskQuantity == 1) {runOrder.push([positionA, positionC]);} else {buildRunOrder(diskQuantity - 1, positionA, positionC, positionB);buildRunOrder(1, positionA, positionB, positionC);buildRunOrder(diskQuantity - 1, positionB, positionA, positionC);} }/*** 移動動畫* positionA:起點* positionC:終點* */ function moveAnimation(positionA, positionC){if(!positionA){var poses = runOrder.shift();if(!poses){setTimeout(reset, 500);}else{moveAnimation(positions[poses[0]], positions[poses[1]]);}}else {var barrel = positionA.barrels.pop();var position = positionC.cylinder.p3(),barPos = barrel.getPosition3d();position[1] = position[1] + floorY + barrelHeight * positionC.barrels.length - cylinderHeight / 2;setPolylinePoints(polyline, barPos, position);params.action = function (v, t) {var length = g3d.getLineLength(polyline),offset = g3d.getLineOffset(polyline, length * v),point = offset.point,px = point.x,py = point.y,pz = point.z;barrel.p3(px, py, pz);};params.finishFunc = function () {positionC.barrels.push(barrel);var poses = runOrder.shift();if (!poses) {moveAnimation();} else {moveAnimation(positions[poses[0]], positions[poses[1]]);}};anim = ht.Default.startAnim(params);} }/*** 重置游戲* */ function reset(){if(positions[0].barrels.length == 0){positions[0].barrels = positions[2].barrels;}positions[2].barrels = [];for(var i = 0, len = positions[0].barrels.length; i < len; i++){var pos = positions[0].cylinder.p3();pos[1] = pos[1] + floorY + i * barrelHeight - cylinderHeight / 2;positions[0].barrels[i].p3(pos);}buildRunOrder(barNum, 0, 1, 2);setTimeout(moveAnimation, 500); }/*** 初始化節(jié)點* */ function initNodes(){// 底盤floor = createNode([0, floorY / 2, 0], [floorX, floorY, floorZ]).s({'shape3d': 'box','3d.movable': false});// 創(chuàng)建柱子for(var i = 0, len = 3; i < len; i++){positions[i].cylinder = createNode(positions[i].position, [20, cylinderHeight, 20], floor).s({'shape3d': 'cylinder','shape3d.color': '#E5BB77','3d.movable': false});}// 創(chuàng)建圓盤createBarrels(barNum, positions[0].cylinder);// 創(chuàng)建圓盤運行軌跡polyline = new ht.Polyline();polyline.setSegments([1, 2, 4, 2]);polyline.s({'shape.background': null,'shape.border.color': 'rgba(0,0,0,0)','shape.border.gradient.color': 'rgba(0,0,0,0)','shape.border.pattern': [20, 10],'shape3d.resolution': 50});dataModel.add(polyline); }/*** 設(shè)置路線節(jié)點* */ function setPolylinePoints(polyline, from, to){polyline.setPoints([{x: from[0], y: from[2], e: from[1]},{x: from[0], y: from[2], e: cylinderHeight},{x: from[0], y: from[2], e: cylinderHeight + 60},{x: to[0], y: to[2], e: cylinderHeight + 60},{x: to[0], y: to[2], e: cylinderHeight},{x: to[0], y: to[2], e: to[1]}]);return polyline; }/*** 創(chuàng)建圓盤* barNum:圓盤個數(shù)* host:吸附節(jié)點* */ function createBarrels(barNum, host){// 圓盤初始x位置var pos = host.p3();for(var i = barNum, j = 0; i > 0; i--, j++){pos[1] = barrelHeight * j + floorY;positions[0].barrels.push(createBarrel(pos, [1, barrelHeight, 1], barrelMinORadius + i*poorRadius, barrelIRadius, host).s({'shape3d.color': randomColor(),'3d.movable': false}));} }/*** 創(chuàng)建節(jié)點* p3:節(jié)點位置* s3:節(jié)點大小* host:吸附節(jié)點* */ function createNode(p3, s3, host){var node = new ht.Node();node.p3(p3);node.s3(s3);node.setHost(host);node.s({'wf.visible': 'selected','wf.color': '#FF6B10','wf.width': 2,'wf.short': true});dataModel.add(node);return node; }/*** 創(chuàng)建空心圓柱* p3:圓桶位置* s3:圓桶大小* oRadius:圓桶外徑* iRadius:圓桶內(nèi)徑* host:吸附節(jié)點* */ function createBarrel(p3, s3, oRadius, iRadius, host){return createNode(p3, s3, host).s({'shape3d': ht.Default.createRingModel([oRadius, 1,oRadius, 0,iRadius, 0,iRadius, 1,oRadius, 1], null, 20, false, false, 70)}); }?
轉(zhuǎn)載于:https://www.cnblogs.com/xhload3d/p/4219025.html
總結(jié)
以上是生活随笔為你收集整理的HT for Web 3D游戏设计设计--汉诺塔(Towers of Hanoi)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: js中继承的几种用法总结(apply,c
- 下一篇: PHP几个快速读取大文件例子