使用余弦定理计算角度,给定 2 点并计算 1 点

发布于 2024-12-22 20:54:52 字数 3153 浏览 2 评论 0原文

我正在 AIR (as3) 中开发一款移动游戏。我为这个游戏创建了一些机器人,它们最初只是四处游荡。但当奖金登场时,他们就必须走向奖金。

新奖励的检测和机器人的移动工作正常,但当新奖励进入阶段时,操作会出现问题。

基本上,这就是它的工作原理(或者我尝试让它工作):

我的机器人随着他的旋转作为参数移动。 (工作正常)

private function moveToNextLocation():void
{
    var angle:Number = _rotation * 0.0174532925; // 1 degree = 0.0174532925 radians
    var speedX:Number = Math.sin(angle) * _speed; 
    var speedY:Number = -Math.cos(angle) * _speed;

    if (_turnLeft && !_moveToBonus){
        _rotation -= _rotationStep * (_speed / _maxSpeed);
    }
    else if (_turnRight && !_moveToBonus){
        _rotation += _rotationStep * (_speed / _maxSpeed);
    }

    this.x += speedX; this.y += speedY;
}

所以,为了知道是否出现新的奖金,我首先捕获一个事件:

protected function onNewBonusAppeared(event:BonusEvent):void
{
    trace("new bonus appeared!");
    _moveToBonus = true;
    _rotation = getRotation(new Point(event.bonus.x, event.bonus.y));
    trace("Heading to " + event.bonus.type + " with new rotation: "  + _rotation);
}

我的机器人现在位于 A 点,通常会前往 B 点(正常的下一个位置)。 然后,新的奖励出现在 C 点(下一个位置)。 我想用余弦定理来解决这个问题,因为我需要 A 的角度来知道我的机器人的新旋转。 这就是我尝试计算的方法:

// calculate new rotation 
private function getRotation(nextLocation:Point):Number
{
    //sources:
    //http://www.teacherschoice.com.au/maths_library/trigonometry/triangle_given_3_points.htm
    //http://en.wikipedia.org/wiki/Law_of_cosines
    //http://stackoverflow.com/questions/1211212/how-to-calculate-an-angle-from-three-points

    //Calculate current angle and corners
    var angle:Number = _rotation * 0.0174532925;
    var currentLocation:Point = new Point(this.x, this.y);
    var normalNextLocation:Point = new Point(Math.sin(angle) * _speed, -Math.cos(angle) * _speed);

    //Calculate lengths of the 3 sides of the triangle  
    var lengthA:Number = calculateLength(normalNextLocation, nextLocation);
    var lengthB:Number = calculateLength(currentLocation, nextLocation);
    var lengthC:Number = calculateLength(currentLocation, normalNextLocation);

    //Calculate the difference in rotation  
    //-------------THIS IS WHERE IT GOES WRONG-----------
    var deltaRotation:Number = calculateAndInverseCosineRule(lengthA, lengthB, lengthC);

    //positive or negative rotation difference
    if (normalNextLocation.y < nextLocation.y)
        return _rotation - deltaRotation;
    else
        return _rotation + deltaRotation;
}
private function calculateLength(a:Point, b:Point):Number
{
    //SQRT((x2 - x1)² + (y2 - y1)²)
    return Math.sqrt(Math.pow(b.x - a.x, 2) + Math.pow(b.y - a.y, 2));
}
private function calculateAndInverseCosineRule(lengthA:Number, lengthB:Number, lengthC:Number):Number
{
    //a² = b² + c² - 2*b*c*cos(alpha)
    //cos(alpha) = (b² + c ² - a²) / (2 * b * c)
    //alpha = cos^-1(cos(alpha))
    var cos:Number = (Math.pow(lengthB, 2) + Math.pow(lengthC, 2) - Math.pow(lengthA, 2))
                         / (2 * lengthB * lengthC);
    trace("cos: ", cos); //returns NAN at some point... don't know why
    return Math.acos(cos);
}

我已经在这个问题上搜索了很长一段时间,但找不到答案......有人看到我做错了什么吗? - [固定的]

I am developing a game for mobile in AIR (as3). I have created some bots for this game that initially just wander around. But when a bonus enters the stage, they have to move to the bonus.

The detection of a new bonus and moving of the bots works fine, but there is something wrong with the manipulation when a new bonus enters the stage.

Basically, this is how it works (or I try to make it work):

My bot moves along with his rotation as a parameter. (works fine)

private function moveToNextLocation():void
{
    var angle:Number = _rotation * 0.0174532925; // 1 degree = 0.0174532925 radians
    var speedX:Number = Math.sin(angle) * _speed; 
    var speedY:Number = -Math.cos(angle) * _speed;

    if (_turnLeft && !_moveToBonus){
        _rotation -= _rotationStep * (_speed / _maxSpeed);
    }
    else if (_turnRight && !_moveToBonus){
        _rotation += _rotationStep * (_speed / _maxSpeed);
    }

    this.x += speedX; this.y += speedY;
}

So, to do know if a new bonus appears I catch an event first:

protected function onNewBonusAppeared(event:BonusEvent):void
{
    trace("new bonus appeared!");
    _moveToBonus = true;
    _rotation = getRotation(new Point(event.bonus.x, event.bonus.y));
    trace("Heading to " + event.bonus.type + " with new rotation: "  + _rotation);
}

My bot is now on point A and would normally go to point B (normalNextLocation).
Then, the new bonus appears on point C (nextLocation).
I wanted to solve this whit the Law of Cosines, since I needed A's angle to know the new rotation of my bot.
This is how I tried to calculate this:

// calculate new rotation 
private function getRotation(nextLocation:Point):Number
{
    //sources:
    //http://www.teacherschoice.com.au/maths_library/trigonometry/triangle_given_3_points.htm
    //http://en.wikipedia.org/wiki/Law_of_cosines
    //http://stackoverflow.com/questions/1211212/how-to-calculate-an-angle-from-three-points

    //Calculate current angle and corners
    var angle:Number = _rotation * 0.0174532925;
    var currentLocation:Point = new Point(this.x, this.y);
    var normalNextLocation:Point = new Point(Math.sin(angle) * _speed, -Math.cos(angle) * _speed);

    //Calculate lengths of the 3 sides of the triangle  
    var lengthA:Number = calculateLength(normalNextLocation, nextLocation);
    var lengthB:Number = calculateLength(currentLocation, nextLocation);
    var lengthC:Number = calculateLength(currentLocation, normalNextLocation);

    //Calculate the difference in rotation  
    //-------------THIS IS WHERE IT GOES WRONG-----------
    var deltaRotation:Number = calculateAndInverseCosineRule(lengthA, lengthB, lengthC);

    //positive or negative rotation difference
    if (normalNextLocation.y < nextLocation.y)
        return _rotation - deltaRotation;
    else
        return _rotation + deltaRotation;
}
private function calculateLength(a:Point, b:Point):Number
{
    //SQRT((x2 - x1)² + (y2 - y1)²)
    return Math.sqrt(Math.pow(b.x - a.x, 2) + Math.pow(b.y - a.y, 2));
}
private function calculateAndInverseCosineRule(lengthA:Number, lengthB:Number, lengthC:Number):Number
{
    //a² = b² + c² - 2*b*c*cos(alpha)
    //cos(alpha) = (b² + c ² - a²) / (2 * b * c)
    //alpha = cos^-1(cos(alpha))
    var cos:Number = (Math.pow(lengthB, 2) + Math.pow(lengthC, 2) - Math.pow(lengthA, 2))
                         / (2 * lengthB * lengthC);
    trace("cos: ", cos); //returns NAN at some point... don't know why
    return Math.acos(cos);
}

I've searched on this matter for quite some time now, but can't find the answer... Does anybody see what I'm doing wrong? - [Fixed]

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

笔落惊风雨 2024-12-29 20:54:52

这里有一个拼写错误:

var cos:Number = (Math.pow(lengthB, 2) + Math.pow(lengthC, 2) - Math.pow(lengthC, 2))

要减去的数量应该是 Math.pow(lengthA, 2)。按照原样,您可以计算(模浮点误差)lengthB^2/(2*lengthB*lengthC)。如果 lengthB == 0,这会产生一个 NaN,我怀疑这就是发生的情况。这意味着 nextLocationcurrentLocation 相同或至少非常接近。

另一方面,normalNextLocation 不应该是 currentLocation + timeStep*velocity 吗?据我所知,您将其设置为velocity

You have a typo here:

var cos:Number = (Math.pow(lengthB, 2) + Math.pow(lengthC, 2) - Math.pow(lengthC, 2))

The quantity to subtract should be Math.pow(lengthA, 2). As is, you calculate (modulo floating point inaccuracies) lengthB^2/(2*lengthB*lengthC). That would produce a NaN if lengthB == 0, which I suspect is what happens. This means nextLocation is identical or at least very close to currentLocation.

On another note, shouldn't normalNextLocation be currentLocation + timeStep*velocity? You set it to velocity, as far as I can see.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文