旋转精灵(sprite)JavaScript

4
我有一个精灵动画,使用3D应用程序渲染的小型火炮。我恰好有360帧,可以完成360度旋转。每个图像的大小为100x100像素。
所以基本上我想做的是,当我在页面的任何地方单击时,火炮的炮管需要旋转以指向鼠标光标,听起来很简单,但我无法使其正常工作,可能是因为我的数学技能不足 :P
目前我拥有的东西类似于这样
/* This is my div with the cannon background image (360 images stitched into one) each  "image area" is 100x100px */

obj.cannon = $('#cannon');

/* Get the X/Y of the cannon loc in the dom */
var cannonX = $(obj.cannon).offset().left;
var cannonY = $(obj.cannon).offset().top;

/* Get radians using atan2 */
var radians = Math.atan2(e.pageY-cannonY, e.pageX-cannonX);

/* Convert to degrees */
var degrees = radians * (180/Math.PI);

现在我所处的情况是这样的,因为图像的宽度为100px,我需要将背景位置向右移动100px以使大炮右转一度,因为360个图像* 100px = 总共36000px。 因此,拼接的精灵图像宽度为36000px。

所以

根据图像精灵的当前背景位置插入奇怪的计算,并根据鼠标光标点击的位置应用新的背景位置,然后使用某种setTimeout(animateIt,speed)来“动画”背景位置到新位置。

function animateIt(){
  if(newpos!=targetpos) { //Use < > here if we need to add or remove
      newpos+=100; //Until we arrive at the new backgroundPosition
      $(obj.cannon).css({backgroundPosition: newpos+'px' });
      setTimeout(animateIt, speed);
  }
}

我现在的想法是对的吗?这应该是一件简单的事情,但我感到很蠢,我的大脑现在好像崩溃了 =P。我的问题是,我不知道如何正确地到达“新的目标背景位置”,然后根据当前的背景位置进行动画 ++ 或 - - 。


使用一张图片和基于HTML5的图像旋转方法怎么样?http://raphaeljs.com/image-rotation.html .. 或者渲染出来的图片真的不同吗? - Fosco
大炮的视角真的在改变吗?你有精灵的链接吗?正如Fosco所说,Raphael可以做到这一点,或者您甚至可以使用CSS转换(不过IE不支持)旋转图像本身。 - Peter Ajtai
很抱歉,这是不可能的,因为这个炮台是透视图,一种等轴测视图,它实际上是一个真正的三维物体。当精灵旋转时,并不能直接从上方看到它...因此简单的CSS旋转是行不通的。 - quiggle
2个回答

4

这里有一个简化的工作示例,包含10张图片。

我现在会发布代码和jsFiddle,稍后可能会回来深入介绍。但基本上你只需要正确排序你的图片,然后使用(Segments - Math.floor(degree / (360 / segments)))选择段落即可。你可能需要调整你的0度数。例如,我把我的0等于正常的90度。

请注意屏幕坐标x和y向右和增加。这使得atan的角度顺时针工作,而不是在x和y向右和增加的坐标系中通常逆时针工作。

我添加了一些文本输出,显示正在显示的角度和图像段。

jQuery很好地处理了x和y位置的归一化。只需注意您的CSS设置跨浏览器即可。

工作的jsFiddle示例


这是我们的图片: alt text


这是我们的HTML:

<div id="main"><div id="img"></div></div>
<div id="info">
    <span></span><br/>
    <span></span>
</div>


CSS:

div#main {
    width:500px;
    height:500px;
    border:2px #000 solid; }
div#img {
    width:94px;
    height:119px;
    overflow:hidden;
    top:50%;
    left:50%;
    margin-left:-45px;
    margin-top:-60px;
    position:relative; 
    background-image:url('http://imgur.com/3UPki.png');
    background-position:0;}
div#info {
    position: absolute;
    bottom:0;
    left:0; }


Javascript / jQuery:

$(function() {
    var position = $("div#img").position(), 
        mouseX, mouseY, imgX, imgY, degree;
    imgX = position.left;
    imgY = position.top;
    $("#main").mousemove(function(e) {
          // degree is arctan y over x (soh,cah,toa)
        degree = Math.atan2((e.pageY - imgY),(e.pageX - imgX))*(180 / Math.PI);
        degree = (degree - 90) % 360;
          // jQuery normalizes pageX and pageY
          // transfrom from -180 to 180 ==> 0 to 360
        if (degree < 0) degree = 180 + (180 - (Math.abs(degree)));        
        rotate(degree);
        $("span:first").html("Segment: " + (9 - Math.floor(degree / 36)));
        $("span:last").html("Degree: " + Math.floor(degree));          
    }); 

    function rotate(degree) {
        var off = 9 - Math.floor(degree / 36);
        $("div#img").css("background-position",-off*94);
    }    
}); ​

工作中的jsFiddle示例


(本段为标题)

我注意到一些奇怪的行为,当你接近每个90/180/270度时它运作得很好,但45度意味着不够精确,炮筒没有直接指向指针,然而当在这些90/180/270值时,炮筒总是准确地指向指针,有什么想法吗?看来我必须对这里的一些神秘行为进行补偿;P - quiggle

0

请记住,从atan获得的角度将从零度开始指向右侧,并从那里顺时针旋转(-90为上方,90为下方)。

您图像的每个位置应对应于特定的角度。一旦您测量了角度(看起来您已经做到了这一点),请使用某种类型的映射将您的角度转换为正确的图像偏移量。我不知道您的图像是什么样子的,所以无法提供帮助。假设您的图像从右侧开始指向,并从那里顺时针旋转,角度将直接对应于正确图像的偏移量。(我建议您为方便起见将帧排列如此...)


好的,制作一个新的渲染/精灵像那样排列,让我们看看结果如何,谢谢;-) - quiggle
当然可以!只是在等待看看这是否有效,我认为你建议的整个映射正是我头脑中难以理解的问题所在,但这肯定会有所帮助 :] - quiggle
@quiggle - 你必须自己处理这个问题,由于它从+180跳到-180,所以有点麻烦。基本上,对于任何小于0度的角度,你可以采用180 + (180 - (Math.abs(degree)))的方法。 - Peter Ajtai
@Peter,你把中午和6点倒过来了。请查看http://en.wikipedia.org/wiki/Atan2。角度逆时针增加。 - JoshD
@quiggle - 谢谢Josh-所以正确的 atan 角度是: 3点钟=0度,正午=90度,9点钟=180度和-180度,6点钟=-90度。 atan 方法返回介于-pi/2到 pi/2 弧度之间的数值,还要记住 Math.atan2()方法。----然而,atan 永远不会返回270度。 - Peter Ajtai
显示剩余4条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接