Javascript 如何计算精灵所能容纳的最小圆形的半径?

Javascript 如何计算精灵所能容纳的最小圆形的半径?,javascript,html,canvas,sprite,collision,Javascript,Html,Canvas,Sprite,Collision,我正在用HTML5,JS制作一个游戏 在游戏中,由于我的精灵正在旋转,我通过圆形形状执行碰撞 玩家有不同的形状,因为当他持有不同的武器时有不同的精灵 玩家的半径是精灵宽度/高度的一半 精灵的大小从16x16调整到50x50像素(50/16=3.125,因此是3.125倍大) 我的问题是:如何计算精灵所适合的最小圆形的半径?像这样: var dx=right-left; var dy=bottom-top; var radius=Math.sqrt(dx*dx+dy*dy)/2; 普通精灵: 红

我正在用HTML5,JS制作一个游戏

在游戏中,由于我的精灵正在旋转,我通过圆形形状执行碰撞

玩家有不同的形状,因为当他持有不同的武器时有不同的精灵

玩家的半径是精灵宽度/高度的一半

精灵的大小从16x16调整到50x50像素(50/16=3.125,因此是3.125倍大)

我的问题是:如何计算精灵所适合的最小圆形的半径?像这样:

var dx=right-left;
var dy=bottom-top;
var radius=Math.sqrt(dx*dx+dy*dy)/2;
普通精灵:

红色=计算半径(如何?),蓝色=我使用的半径(精灵宽度或高度/2):


(为了更好地查看图像,请在图像程序或放大的东西中打开它们。)

您的精灵是统一的圆形还是旋转的矩形/正方形?对于正方形和矩形,你需要找到斜边(使用毕达哥拉斯定理),然后取其中的一半作为半径。这样,当你旋转它时,最长的对角线将始终适合盒子。圆是给定的。

您的精灵是均匀圆还是可以旋转矩形/正方形?对于正方形和矩形,你需要找到斜边(使用毕达哥拉斯定理),然后取其中的一半作为半径。这样,当你旋转它时,最长的对角线将始终适合盒子。圆是给定的。

假设您有一个宽度为w和高度为h的矩形精灵。有两种选择:

  • 外圆:只需计算矩形的斜边
    r=sqrt(w^2+h^2)

  • 内圆:在这种情况下,直径将是矩形的最短边。例如:
    r=w/2

至于透明像素。透明边界是固定大小的吗?如果是这样,只需从半径计算中减去该值即可。如果没有,则可以尝试以下方法:

  • 加载图像
  • 从最外层的像素开始,检查是否有透明像素
  • 如果是,则移动到中的下一层
  • 等等
  • 找到没有透明像素的图层后,请停止
你现在知道有多少像素的透明度。只需从半径计算中减去

如果您不知道如何获得像素颜色,这可能会有所帮助:

当然,每次这样做都会很慢。我建议你在Photoshop或其他任何东西中打开你的精灵,并测量合适的大小



听起来您正试图为非圆形形状实现像素完美碰撞。也许你应该研究一下,例如:

假设你有一个宽度为w和高度为h的矩形精灵。有两种选择:

  • 外圆:只需计算矩形的斜边
    r=sqrt(w^2+h^2)

  • 内圆:在这种情况下,直径将是矩形的最短边。例如:
    r=w/2

至于透明像素。透明边界是固定大小的吗?如果是这样,只需从半径计算中减去该值即可。如果没有,则可以尝试以下方法:

  • 加载图像
  • 从最外层的像素开始,检查是否有透明像素
  • 如果是,则移动到中的下一层
  • 等等
  • 找到没有透明像素的图层后,请停止
你现在知道有多少像素的透明度。只需从半径计算中减去

如果您不知道如何获得像素颜色,这可能会有所帮助:

当然,每次这样做都会很慢。我建议你在Photoshop或其他任何东西中打开你的精灵,并测量合适的大小



听起来您正试图为非圆形形状实现像素完美碰撞。也许你应该研究一下,例如:

获得答案的几个步骤

演示:

确定播放器像素的边界框(不包括透明像素)。

  • 使用.getImageData获取图像的单个像素数据

  • 从左侧检查每个垂直列,并确定第一个播放器像素出现的位置

  • 从右侧检查每个垂直列,并确定第一个播放器像素出现的位置

  • 从顶部检查每个水平行,并确定第一个播放器像素出现的位置

  • 从底部检查每个水平行,并确定第一个播放器像素出现的位置

现在有了顶部、左侧、底部和右侧边界值

确定边界框的半径(=其对角线的一半):

var dx=right-left;
var dy=bottom-top;
var radius=Math.sqrt(dx*dx+dy*dy)/2;
因此包含的圆具有该计算半径。

下面是示例代码:

<!doctype html>
<html>
<head>
<link rel="stylesheet" type="text/css" media="all" href="css/reset.css" /> <!-- reset css -->
<script type="text/javascript" src="http://code.jquery.com/jquery.min.js"></script>

<style>
    body{ background-color: ivory; padding:20px; }
    #canvas{border:1px solid red;}
</style>

<script>
$(function(){

    var canvas=document.getElementById("canvas");
    var ctx=canvas.getContext("2d");

    ctx.translate(.5,.5);

    var img=new Image();
    img.crossOrigin="anonymous";
    img.onload=start;
    img.src="https://dl.dropboxusercontent.com/u/139992952/stackoverflow/sprite.png";

    function start(){

        var cw=canvas.width;
        var ch=canvas.height;

        ctx.drawImage(img,cw/2-img.width/2,ch/2-img.height/2);

        var data=ctx.getImageData(0,0,cw,ch).data;
        var leftX=getLeft(data,cw,ch);
        var rightX=getRight(data,cw,ch);
        var topY=getTop(data,cw,ch);
        var bottomY=getBottom(data,cw,ch);
        var w=rightX-leftX;
        var h=bottomY-topY;
        var cx=leftX+w/2;
        var cy=topY+h/2;
        var radius=Math.sqrt(w*w+h*h)/2;

        ctx.beginPath();
        ctx.arc(leftX+w/2,topY+h/2,radius,0,Math.PI*2);
        ctx.closePath();
        ctx.stroke();

        ctx.strokeRect(leftX,topY,w,h);

    }

    function getLeft(data,width,height){
        for(var x=0;x<width;x++)
        for(var y=0;y<height;y++)
        {
            if(data[(width*y+x)*4+3]>0){ return(x); }
        }
    }

    function getRight(data,width,height){
        for(var x=width-1;x>=0;x--)
        for(var y=height-1;y>=0;y--)
        {
            if(data[(width*y+x)*4+3]>0){ return(x); }
        }
    }

    function getTop(data,width,height){
        for(var y=0;y<height;y++)
        for(var x=0;x<width;x++)
        {
            if(data[(width*y+x)*4+3]>0){ return(y); }
        }
    }

    function getBottom(data,width,height){
        for(var y=height-1;y>=0;y--)
        for(var x=width-1;x>=0;x--)
        {
            if(data[(width*y+x)*4+3]>0){ return(y); }
        }
    }


}); // end $(function(){});
</script>

</head>

<body>
    <h4>1. Calc boundingbox of non-transparent pixels<br>2. Calc radius that contains that boundingbox</h4>
    <canvas id="canvas" width=300 height=300></canvas>
</body>
</html>

正文{背景色:象牙色;填充:20px;}
#画布{边框:1px纯红;}
$(函数(){
var canvas=document.getElementById(“canvas”);
var ctx=canvas.getContext(“2d”);
ctx.translate(.5,5);
var img=新图像();
img.crossOrigin=“匿名”;
img.onload=启动;
img.src=”https://dl.dropboxusercontent.com/u/139992952/stackoverflow/sprite.png";
函数start(){
var cw=画布宽度;
var ch=画布高度;
ctx.图纸图像(img,cw/2-img.宽度/2,ch/2-img.高度/2);
var data=ctx.getImageData(0,0,cw,ch).data;
var leftX=getLeft(数据、连续波、连续波);
var rightX=getRight(数据、连续波、连续波);
var topY=getTop(数据,cw,ch);
var bottomY=getBottom(数据、连续波、连续波);
变量