检测鼠标悬停在重叠的+透明图像上

戈迪

我正在构建一个小游戏,用户可以在其中购买物品来装饰自己的房屋。

  • 我有很多物品/图片;因此,我决定为每个图像使用一个“遮罩”(图像)来定义可悬停区域,而不是为每个图像绘制一个地图区域。
    例如:这里显示的沙发上,和它的磨砂
    我将遮罩“转换”为canvas元素,稍后将检查悬停的像素是否透明以检测项目是否悬停。

  • 第二件事是很多项目重叠,因此我还需要检查哪一层在最上面。

在house元素上mousemove事件(jQuery);与函数getObjectsUnderMouse()绑定

基本上,这就是getObjectsUnderMouse()的工作方式:

  1. 获取鼠标坐标
  2. 获取房屋中的活动(显示)物品
  3. 过滤这些项目以仅保留那些鼠标点击画布边界的项目,知道项目的位置和宽度/高度)
  4. 过滤这些项目以仅保留那些鼠标不在透明像素(画布)上的项目
  5. 过滤这些项目以仅其保留在顶部(z索引)
  6. 给该项目一个mouseon

我对自己的代码感到非常满意,这是一个很大的挑战,但可以在Chrome上完美运行。

我的问题是其他地方的速度较慢(没什么大不了的),但是;最重要的是,似乎在ipad上崩溃了;我需要我的游戏才能在ipad上运行...:/

有谁知道为什么或对此有更好的解决方案?

下面是游戏的演示,这里的JavaScript文件,你可以看看getObjectsUnderMouse()。

欢迎任何建议!

品牌

尽管无光泽的画布包含您需要进行命中测试的信息,但是就内存而言,为每个无光泽保留完整尺寸的画布是昂贵的。为每个遮罩保留一块画布可能使用的资源超出了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>

本文收集自互联网,转载请注明来源。

如有侵权,请联系[email protected] 删除。

编辑于
0

我来说两句

0条评论
登录后参与评论

相关文章

来自分类Dev

透明图像上的相交检测

来自分类Dev

鼠标悬停在图像上

来自分类Dev

鼠标悬停在图像上

来自分类Dev

如果悬停在另一个重叠元素上,请保持鼠标悬停

来自分类Dev

d3.js鼠标悬停在重叠的圆圈上

来自分类Dev

将鼠标悬停在jQuery上

来自分类Dev

将鼠标悬停在SVG上

来自分类Dev

将鼠标悬停在div上

来自分类Dev

鼠标悬停在 SVG 文本上

来自分类Dev

将鼠标悬停在元素上?

来自分类Dev

检测将鼠标悬停在PyQt4中的特定小部件上

来自分类Dev

检测鼠标悬停在哪个元素上并传递给函数

来自分类Dev

将鼠标悬停在图像上时显示图像

来自分类Dev

将鼠标悬停在背景图像上的半透明菜单项

来自分类Dev

将鼠标悬停在图像上时,显示带有半透明颜色覆盖的标题

来自分类Dev

取消将鼠标悬停在图像上的部分模糊

来自分类Dev

JavaScript对将鼠标悬停在图像上的影响

来自分类Dev

鼠标悬停在图像上添加文字

来自分类Dev

将鼠标悬停在导航栏上显示图像

来自分类Dev

鼠标悬停在图像上之前的常量文本

来自分类Dev

jQuery鼠标悬停在文本和图像上

来自分类Dev

将鼠标悬停在图像上时按钮显示

来自分类Dev

WordPress将鼠标悬停在图像上

来自分类Dev

将鼠标悬停在导航栏上显示图像

来自分类Dev

鼠标悬停在JButton上更改图像

来自分类Dev

鼠标悬停在图像上之前的常量文本

来自分类Dev

将鼠标悬停在 <a> 上加载图像

来自分类Dev

将鼠标悬停在div上,同时将鼠标悬停在整个标签上

来自分类Dev

当鼠标悬停在两个重叠的画布上时,CSS下拉菜单不起作用