HTML5版的String Avoider小遊戲

HTML5版的String Avoider小遊戲 http://www.newgrounds.com/portal/view/300760 蠻簡單也蠻考驗耐心,從遊戲起始點移動鼠標到終點位置,鼠標移動過程繪製出移動軌跡的String平滑曲線,整個過程不能碰撞到邊界,從技術角度來講其核心就是根據鼠標移動位置生成String線的算法,該遊戲是ActionScript寫的Flash版,這裏將其改形成HTML5版的JavaScript實現,並增長可自定義關卡功能的一種設計思路。html

Screen Shot 2014-12-28 at 3.39.34 PM

String連線我是緩存了300個點信息的數組,鼠標移動時不斷調整300個點的新位置信息,每次更新時先將新鼠標點設置給第一個元素,後續更新x點時,計算其與x-1點的角度,在此方向長度爲1的位置更新座標,這樣就達到了平滑曲線的效果。node

除了繪製String線外還有個技術點就是監測碰撞,該Flash遊戲的邊界都是線段,所以第一想到的監測方式就是線線相交的思路,算法可參考 http://en.wikipedia.org/wiki/Line%E2%80%93line_intersection ,若是以LineLine的相交思路只須要遍歷全部point間的線段,判斷是否與遊戲關卡定義的邊界線相交,但這種方式對不規則邊界就比較麻煩,監測性能也不高。算法

考慮到咱們還須要提供用戶可DIY自定義遊戲關卡的功能,咱們將採用監測顏色透明度信息的方式,因爲正常遊戲時場景無需用戶動態修改,所以邊界的信息可提早緩存到ImageData內存中,而且咱們300個點的距離都是1,監測只需根據點進行就能夠。數組

Screen Shot 2014-12-28 at 3.38.33 PM

整個程序採用HT for WebGraphView拓撲圖組件,再其上經過addTopPainter添加頂層畫筆繪製曲線,當曲線碰到Node圖元時繪製成紅色,不然繪製成黃色,監聽GraphView拓撲圖的interaction事件,在該事件中設置dirty的髒標誌,在繪製時根據dirty的標誌進行更新,採用這樣的方式可將屢次變換最終聚合成一次更新,這也是圖形刷新繪製經常使用的基本技巧。同時經過GraphView.setEditable(true)開啓了拓撲圖的可視化編輯功能,用戶可隨時改變界面圖元位置和旋轉等形狀信息,至關於自定義關卡的效果。
緩存

全部代碼和運行效果以下:http://v.youku.com/v_show/id_XODU4NzY5MzQ0.htmlapp

function init(){                    
	dataModel = new ht.DataModel();                   
	graphView = new ht.graph.GraphView(dataModel); 
	graphView.handleScroll = function(){};
	graphView.setEditable(true);
	graphView.setPannable(false)

	view = graphView.getView();
	view.style.left = '10px';
	view.style.top = '10px';
	view.style.width = '600px';
	view.style.height = '400px';
	view.style.background = 'black';
	document.body.appendChild(view);

	createNode(20, 20, 80, 40, 'rect');                
	createNode(200, 300, 80, 40, 'star');
	createNode(400, 100, 80, 40, 'oval');
	createShape();

	length = 1;
	count = 300;
	points = [];
	for(var i=0; i<count; i++){
		points.push({x: 0, y: 0});
	}
	view.addEventListener('mousemove', function(e){
		var point = graphView.lp(e);
		points[0].x = point.x;
		points[0].y = point.y;
		for (var i = 1; i < count - 1; i++) {
			var angle = Math.atan2(points[i].y - points[i - 1].y, points[i].x - points[i - 1].x);
			points[i].x = points[i - 1].x + length * Math.cos(angle);
			points[i].y = points[i - 1].y + length * Math.sin(angle);
		}
		if(imageData){
			hit = false;
			for (var i = 0; i < count; i++) {
				var x = Math.floor(points[i].x);
				var y = Math.floor(points[i].y);
				var index = (y * graphView.getWidth() + x) * 4;
				if(imageData.data[index+3] !== 0){
					hit = true;
					break;
				}
			}                        
		}                    
		graphView.redraw();
	});

	dirty = true;                
	imageData = null;
	graphView.mi(function(e){
		dirty = true;
	});                
	graphView.addTopPainter(function(g){
		if(dirty){
			dirty = false;    
			hit = false;
			imageData = g.getImageData(0, 0, graphView.getWidth(), graphView.getHeight());                                                                                                                                              
			ht.Default.callLater(graphView.redraw, graphView);  
		}else{
			g.beginPath();
			g.lineWidth = 3;
			g.strokeStyle = hit ? 'red' : 'yellow';                   
			g.moveTo(points[0].x, points[0].y);
			for (var i = 1; i < count - 1; i++) {
				g.lineTo(points[i].x, points[i].y);
			}
			g.stroke();                        
		}
	});
}    
function createNode(x, y, w, h, shape){
	var node = new ht.Node();
	node.setRect(x, y, w, h);
	node.s({
		'shape': shape,
		'select.width': 0
	});
	dataModel.add(node);
	return node;
}
相關文章
相關標籤/搜索