我怎样才能在两点之间相对缩放?

时间:2016-06-19 19:49:06

标签: python math pygame 2d-games

这更像是一个数学问题,我似乎无法在网上找到任何答案。

所以这就是我想要实现的目标:

假设我有一个圆圈,从Ay开始。现在,当这个圆圈移向By时,我希望它按比例缩放到一定的大小。

例如,如果圆的直径在Ay处为5,那么在到达By时,如何将其缩放为52.2。

enter image description here

奖金问题:我可以用正方形实现同样的目标吗?

3 个答案:

答案 0 :(得分:2)

如果是

,则进行线性缩放
  • D[Ay]Ay
  • 时圆/方的直径/边
  • D[By]By
  • 时圆/方的直径/边
  • D[Cy]Cy
  • 时圆/方的直径/边
  • Ay <= Cy <= By

然后

D[Cy] = D[Ay] + (Cy - Ay) * (D[By] - D[Ay]) / (By - Ay)

答案 1 :(得分:1)

如果向量v=(By-Ay),则AyBy之间的行可以定义为l(t)=Ay+vt。因此,l(t)上带参数t的任何点的缩放系数都为s=47.5t+5。例如,在t = 0时,线上的点Ay具有缩放因子s=5。如果您放置t=1,则会获得并缩放s= 52.5。对于您的红利问题,缩放因子是相同的,但您不能简单地将缩放因子中的平方坐标相乘。您需要使用l(t)将方块转换为原点并缩放坐标并将其转换回l(t)

答案 2 :(得分:1)

在位置方面补间。

密钥和密钥框

在动画中,我们将已知位置和状态定义为关键帧,通常我们会根据时间对关键帧进行索引。

// an array of keys. The ? represents the applicable number value
var keys = [{ 
         time : 0, // the state of an object at time 0
         pos : {x : ? , y : ? }, // position
         scale : ?,
         rotation : ?,
         colour : [?,?,?],       // rgb colour, just for the hell of it
         // and whatever else you may want to animate
     },{
         time : 100, // the state of the object at time 100
         pos : {x : ? , y : ? },
         scale : ?,
         rotation : ?,
         colour : [?,?,?],
         // and whatever else you may want to animate
     }
]

标准化时间

为了在关键帧之间的任何时间t获得对象的状态,我们在时间之间找到归一化时间(0到1之间的值)并将其乘以其他状态之间的差值然后将其添加到开始状态

所以说时间是50,首先得到标准化时间

var currentTime = 50;
var timeDif = currentTime - keys[0].time; // difference from start time to current
// to get the normalised time divid by the differance
var normTime = timeDif / (keys[1].time - keys[0].time); // divide by the differance in time between keys

现在你有了标准化的时间,你可以轻松地计算任何状态

var scaleDif =  keys[1].scale - keys[0].scale; // get diff in scale
var scaleChange = scaleDif * normTime;  // multiply by the normalised time
var currentScale = keys[0].scale + scaleChange; // add to the starting scale

这有点长啰嗦,但这是为了让你轻松进入正在发生的事情。完整的键控功能看起来像。

function tweenKeys(time,key1,key2){
    var nt = (time - key1.time) / (key2.time - key1.time); // get normalised time
    // because you can not divide by zero we need a little check. Javascript return infinity if we div by zero but we want the value 0 
    nt = nt < Infinity ? nt : 0; // zero if there was a divide by zero
    var ck = {}; // ck for current key. the key represents the state at time
    ck.scale = key1.scale + (key2.scale - key1.scale) * nt;
    ck.rotation = key1.rotation + (key2.rotation - key1.rotation ) * nt;
    ck.pos.x = key1.pos.x + (key2.pos.x- key1.pos.x) * nt;
    ck.pos.y = key1.pos.y + (key2.pos.y- key1.pos.y) * nt;
    ck.colour[0] = key1.colour[0] + (key2.colour[0] - key1.colour[0]) * nt;
    ck.colour[1] = key1.colour[1] + (key2.colour[1] - key1.colour[1]) * nt;
    ck.colour[2] = key1.colour[2] + (key2.colour[2] - key1.colour[2]) * nt;
    return ck; // return the newly create state
}

这是关键帧的基础知识,你可以在这个答案中找到更多关于它的内容How would I animate... ?

在空间而不是时间

一切都很好,但对于你的问题,这没有帮助,你没有使用时间你使用位置来确定对象的当前状态。好吧,我们使用什么来查找当前状态并不重要,关键帧中的任何值都可用于确定所有其他值的状态。我们需要做的就是找到归一化的差异,然后像我们将归一化时间应用于所有其他值一样。

标准化位置

让我们看看位置

考虑两个点p1和p2,定义为

var p1 = {x : ?, y : ?}; // ? represent some number value
var p2 = {x : ?, y : ?}; // ? represent some number value

代表你的职位A,B

如果我们有第3点C

var c = {x : ?, y : ?}; // ? represent some number value

在2D平面上的某个地方。我们想要一个公式,当C在点p1时返回0,当点c在点p2时返回1。这将是我们用于获得当前状态的标准化位置。

由于位置是2d,我们需要在计算中同时涉及x和y。我们得到从p1到c点的距离和由点p1和p2之间的距离得到的距离。这将为我们提供我们想要的价值。为了找到距离,我们使用了pythag溶液。正方形之和的根

var dist = Math.sqrt( Math.pow( p2.x - p1.x, 2) + Math.pow( p2.y - p1.y, 2)); // for the twisted world of IE users and
var dist = Math.hypot(p2.x - p1.x, p2.y - p1.y); // for all good browsers

因此标准化距离为

var normDist = Math.hypot(c.x - p1.x, c.y - p1.y) / Math.hypot(p2.x - p1.x, p2.y - p1.y); 
// because you can not divide by zero we need a little check. Javascript returns infinity if we div by zero but we want the value 0 
normDist = normDist < Infinity ? normDist : 0; // zero if there was a divide by zero

然后将(normDist)应用于所有关键状态。

var currentScale = (keys[1].scale - keys[0].scale) * normDist + keys[0].scale;

定位问题

好的,你说谢谢,对不起,但这不是解决方案,如果你知道点c总是在p1,p2之间的线上,但情况并非总是如此,并且在严格的检查下它是几乎没有因为计算机存储数字信息所以在任何需要非常精细细节的计算中会有一点误差。此外,对于距离p1远离p2的任何点,上述方法将返回1的归一化距离,其描述了点p1周围的圆。我们需要更多地约束这个值。此外,如果c是点p1或点p2之后,那么知道它将是很方便的。因此,我们可以使用以下方法。

// get the unit distance on the line p1,p2 of point c representing 
// the distance along the line that is closest to c
function unitDistOfPoint(p1,p2,c){
    var v1 = {}; // working vectors
    var v2 = {}; 
    v1.x = p2.x - p1.x; // vector between p1,p2
    v1.y = p2.y - p1.y;
    v2.x = c.x - p1.x;  // vector to c from p1
    v2.y = c.y - p1.y;
    // a little math magic. Divide the dot product of the vectors v2, v1
    // by the square of line length
    return (v2.x * v1.x + v2.y * v1.y) / (v1.y * v1.y + v1.x * v1.x);
}

现在我们可以进行补间并获得你的比例

// return the state for a object at point c in terms of key1, to key2
function tweenKeysViaPos(c,key1,key2){
    // get the normalised distance of the point c between keys 1 and 2
    var nd = unitDistOfPoint(c, key1.pos, key2.pos); // nd for normalised distance
    // you may want to constrain the position to only between the points 
    // do that by clamping the value nd between 0 and 1 inclusive
    nd = Math.max(0, Math.min(1, nd)); // clamp the normalise distance
    var ck = {}; // ck for current key. the key represents the state at time
    ck.scale = key1.scale + (key2.scale - key1.scale) * nt;
    ck.rotation = key1.rotation + (key2.rotation - key1.rotation ) * nt;
    ck.pos.x = key1.pos.x + (key2.pos.x- key1.pos.x) * nt;
    ck.pos.y = key1.pos.y + (key2.pos.y- key1.pos.y) * nt;
    ck.colour[0] = key1.colour[0] + (key2.colour[0] - key1.colour[0]) * nt;
    ck.colour[1] = key1.colour[1] + (key2.colour[1] - key1.colour[1]) * nt;
    ck.colour[2] = key1.colour[2] + (key2.colour[2] - key1.colour[2]) * nt;
    return ck; // return the newly create state
}

这就是答案。如果点c偏离键之间的线,那么上面的函数也会返回它应该的位置。

如有需要,可提供更多信息

您可能希望对其进行扩展以适应许多关键帧。通常,对于两个以上的关键帧和使用时间,通过查找时间大于第一个键且小于下一个键的位置,很容易找到我们想要的键。但是,如果您使用该职位来解决您所处的关键问题,那么这并不是那么简单。因此,为了帮助更复杂的解决方案,您会发现这个功能很方便

// returns the distance point c is from the line p1,p2. If on the line
// the the return value is 0. If befor point p1 or after p2 then the distance
// is the distance to p1, or p2 respectively
function distFromLine(p1,p2,c){
    var v1 = {}; // working vectors
    var v2 = {}; 
    v1.x = p2.x - p1.x; // vector between p1,p2
    v1.y = p2.y - p1.y;
    v2.x = c.x - p1.x;  // vector to c from p1
    v2.y = c.y - p1.y;
    // a little math magic. Divide the dot product of the vectors v2, v1
    // by the square of line length
    var u = (v2.x * v1.x + v2.y * v1.y) / (v1.y * v1.y + v1.x * v1.x);
    var v3 = {};
    if(u < 0){ // befor the start
        return Math.hypot(v2.x,v2.y); // distance to p1
    }
    if(u > 1){ // after end
        return Math.hypot(c.x - p2.x,c.y p2.y); // distance to p2
    }
    // get the point on the line that is closest
    v3.x = p1.x + v1.x * u;
    v3.y = p1.y + v1.y * u;
    // return the distance from that point to c
    return Math.hypot(c.x - v3.x,c.y - v3.y); // distance from line of c
}

然后,您可以通过找到返回距离它们之间的线最小距离的键来找到所需的两个键。您然后通过定义许多关键帧来定义一条复杂的线条,无论您放置一个对象,您都可以计算它应该在哪里以及处于什么状态。

希望这有所帮助,并没有超越顶部。如果任何读者都不清楚,请在评论中说明,我会澄清。