2015-01-14 122 views
0

我正在構建一個小遊戲,用戶已購買物品來裝飾他的房子。檢測鼠標懸停在重疊+透明圖像上

  • 我有很多物品/圖片;所以我決定爲它們中的每一個使用一個「無光澤」(圖像),它將定義可放置區域,而不是爲每個圖像繪製地圖區域。
    示例:這裏是the displayed couchits matte
    我將遮罩「轉換」爲畫布元素,稍後將檢查懸停像素是否透明以檢測項目是否懸停。

  • 第二件事是很多項目重疊,所以我還需要檢查哪一層在頂部。

我有鼠標移動的房子元件上事件(jQuery的);與函數綁定getObjectsUnderMouse()

基本上,這是getObjectsUnderMouse()是如何工作的:

  1. 獲取鼠標座標
  2. 獲取在家裏活動(顯示)項目
  3. 篩選這些項目只保留那些哪裏鼠標碰到畫布邊界,知道項目的位置和寬度/高度)
  4. 過濾這些項目,以保持只有鼠標不在透明像素(畫布)
  5. 篩選這些項目,以保持在頂部(Z-指數)僅一個
  6. 給該項目一mouseon

我與我的代碼很高興,這是一個相當大的挑戰,但在Chrome上完美運行。

我遇到的問題是其他地方比較慢(不是很大),但是;最重要的是,似乎在iPad上崩潰;我需要我的遊戲在ipad上運行...:/

有沒有人知道爲什麼或有更好的解決方案呢?

這裏的a demo of the game,這裏的the javascript file你可以看看getObjectsUnderMouse()。

歡迎任何建議!

+0

使用cocoon.js/PhoneGap的/科爾多瓦包裝作爲原生iOS應用的任何機會呢? –

+0

感謝您的回覆,似乎這將是太多的工作。我需要找到一個解決方案,使其在網站上運行... – gordie

+0

http://stackoverflow.com/questions/1517924/javascript-mapping-touch-events-to-mouse-events – chiliNUT

回答

1

雖然磨砂畫布包含您需要進行點擊測試的信息,但爲每個磨砂保留一個完整尺寸的畫布在內存方面會很昂貴。爲每個遮罩保留一個畫布可能會使用比iPad更多的資源。

這裏有一個方法,大大降低您的內存使用:

首先,作物任何額外的透明空間了每個對象的。例如,您的沙發是600x400 = 240000像素,但裁剪空白空間會將圖像縮小爲612x163 = 99756像素。這比原始圖像尺寸節省了58%。較少的像素意味着較少的無光澤內存。

不是爲每個對象保留一個完整大小的畫布,而是爲每個只包含該圖像中每個像素的不透明度的對象保留一個數組。數組值爲1表示該像素是不透明的(並且是對象的一部分)。數組值爲0表示該像素是透明的(對象的任何部分都不在該像素處)。

然後針對像素數組進行命中測試,而不是針對磨砂畫布進行命中測試。

如果以z-index順序測試數組,您甚至可以知道哪個對象位於另一個對象之上。

這裏的示例代碼和演示:

var canvas=document.getElementById("canvas"); 
 
var ctx=canvas.getContext("2d"); 
 
var cw=canvas.width; 
 
var ch=canvas.height; 
 
var $canvas=$("#canvas"); 
 
var canvasOffset=$canvas.offset(); 
 
var offsetX=canvasOffset.left; 
 
var offsetY=canvasOffset.top; 
 

 
// display which object the mouse is over 
 
var $result=$('#result'); 
 

 
// create an array of target objects 
 
var targets=[]; 
 
targets.push({ name:'couch', x:25, y:50, hitArray:[], url:'https://dl.dropboxusercontent.com/u/139992952/multple/couch.png' }); 
 
targets.push({ name:'lamp', x:50, y:30, hitArray:[], url:'https://dl.dropboxusercontent.com/u/139992952/multple/lamp.png' }); 
 
var imgCount=targets.length; 
 

 
// load the image associated with each target object 
 
for(var i=0;i<targets.length;i++){ 
 
    var t=targets[i]; 
 
    t.image=new Image(); 
 
    t.image.crossOrigin='anonymous'; 
 
    t.image.index=i; 
 
    t.image.onload=start; 
 
    t.image.src=t.url; 
 
} 
 

 
// this is called when each image is fully loaded 
 
function start(){ 
 

 
    // return if all target images are not loaded 
 
    if(--imgCount>0){return;} 
 

 
    // make hit arrays for all targets 
 
    for(var i=0;i<targets.length;i++){ 
 
    var t=targets[i]; 
 
    t.hitArray=makeHitArray(t.image); 
 
    } 
 

 
    // resize the canvas back to its original size 
 
    canvas.width=cw; 
 
    canvas.height=ch; 
 

 
    // draw all targets on the canvas 
 
    for(var i=0;i<targets.length;i++){ 
 
    var t=targets[i]; 
 
    t.width=t.image.width; 
 
    t.height=t.image.height; 
 
    ctx.drawImage(t.image,t.x,t.y); 
 
    } 
 

 
    // listen for events 
 
    $("#canvas").mousemove(function(e){handleMouseMove(e);}); 
 

 
} 
 

 
// Draw a target image on a canvas 
 
// Get the imageData of that canvas 
 
// Make an array containing the opacity of each pixel on the canvas 
 
// (0==pixel is not part of the object, 1==pixel is part of the object) 
 
function makeHitArray(img){ 
 
    var a=[]; 
 
    canvas.width=img.width; 
 
    canvas.height=img.height; 
 
    ctx.drawImage(img,0,0); 
 
    var data=ctx.getImageData(0,0,canvas.width,canvas.height).data; 
 
    for(var i=0;i<data.length;i+=4){ 
 
    // if this pixel is mostly opaque push 1 else push 0 
 
    a.push(data[i+3]>250?1:0); 
 
    } 
 
    return(a); 
 
} 
 

 

 
function handleMouseMove(e){ 
 

 
    // tell the browser we're handling this event 
 
    e.preventDefault(); 
 
    e.stopPropagation(); 
 

 
    // get the mouse position 
 
    mouseX=parseInt(e.clientX-offsetX); 
 
    mouseY=parseInt(e.clientY-offsetY); 
 

 
    // Test the mouse position against each object's pixel array 
 
    // Report hitting the topmost object if 2+ objects overlap 
 
    var hit='Not hovering'; 
 
    for(var i=0;i<targets.length;i++){ 
 
    var t=targets[i]; 
 
    var imgX=mouseX-t.x; 
 
    var imgY=mouseY-t.y; 
 
    if(imgX<=t.width && imgY<=t.height){ 
 
     var hitArrayIndex=imgY*t.width+imgX; 
 
     if(hitArrayIndex<t.hitArray.length-1){ 
 
     if(t.hitArray[hitArrayIndex]>0){ 
 
      hit='Hovering over '+t.name; 
 
     } 
 
     }  
 
    } 
 
    } 
 

 
    $result.text(hit); 
 

 
}
body{ background-color: ivory; padding:10px; } 
 
#canvas{border:1px solid red;}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script> 
 
<h4 id='result'>Move mouse over objects.</h4> 
 
<canvas id="canvas" width=450 height=250></canvas>

+0

真棒回覆,非常感謝!它仍然在iPad上崩潰,我試圖找出原因;但無論如何,現在到處都比較快。 謝謝! – gordie

+0

不客氣!你有沒有機會使用跨域圖像?如果是的話,那麼你可能會遇到CORS安全問題。 – markE