【问题标题】:Find a new angle of the ball when it bounces (using coordinates)找到球反弹时的新角度(使用坐标)
【发布时间】:2017-09-18 12:09:18
【问题描述】:

我有一个游戏,球从墙上反弹。它在一个坐标平面上。我希望在弹跳时有一些随机性,以使游戏更有趣。在保持球始终保持恒定速度的同时,我将如何做到这一点?现在我的代码意味着它只能以直角反弹。

窗口的左上角是 0,0,右下角是 winW,winH(现在设置为 800,800)。

ball.cpp sn-p

pos.x = start.x;
pos.y = start.y;

speed.x = .4f; // the f indicates that it's per frame. 
speed.y = .4f;

void Ball::hitLeftRight() {
    speed.x = -speed.x;
}

void Ball::hitTopBottom() {
    speed.y = -speed.y;
}

void Ball::reset() {
   // for a new level in game
   pos.x = start.x;
   pos.y = start.y;
}    

void Ball::update() {
    // called every frame
    pos.y += speed.y;
    pos.x += speed.x;

    ballShape.setPosition(pos);
}

【问题讨论】:

  • ...通过添加一个被钳位的随机生成数?
  • 速度和反射角度是独立的,那又如何呢?

标签: c++ math sfml trigonometry


【解决方案1】:

除了翻转速度之外,您还可以为球添加一个随机角度。通过使用 <random> 标头并生成 0 到 2 * pi 之间的值,您可以在任何方向添加随机速度。或者如下例所示,将其限制为 -22.5 到 22.5 度。或pi / 8.0 弧度。

随机角度

您当然可以根据冲击角度调整这些值,但这是特定于实现的。下面是一个关于如何生成此类数字的示例:

#include <random>
#include <cmath>
#include <iostream>


int main() {
    constexpr double pi = 3.14159;
    constexpr double bounceSpeed = 5.0;

    std::random_device seed;
    std::mt19937 generator(seed());

    // Numbers between - pi / 2 and pi / 8 gives angles between -22.5 and 22.5
    std::uniform_real_distribution<double> random(-pi / 8.0, pi / 8.0);

    double deltaX = cos(random(generator)) * bounceSpeed;
    double deltaY = sin(random(generator)) * bounceSpeed;

    std::cout << deltaX << "\n" << deltaY << "\n";

    return 0;
}

之后,您可以将 deltaX 和 deltaY 添加到各自的 x 和 y 速度中。

普通随机

或者,如果您对任何纯粹的随机速度感到满意:

// Generate random double in range [min, max]
double uniform(double min, double max) {
    static std::random_device seed;
    static std::mt19937 generator(seed());
    std::uniform_real_distribution<double> random(min, max);
    return random(generator);
}

以您想要的速度范围调用该函数两次,并将其添加到您的球的x 和y。

保持速度

为了保持球的速度,您可以将速度向量归一化,然后在添加随机速度后将其乘以球的所需速度。

要标准化,除以长度:

#include <cmath>
#include <iostream>
int main() {
    
    constexpr double speed = 4.0;

    double x = 3.0;
    double y = 4.0;

    double length = sqrt(x * x + y * y);

    x /= length;
    y /= length;

    x *= speed;
    y *= speed;

    std::cout << x << "\n" << y << "\n";

    return 0;
}

然后乘以速度以保持一致。

【讨论】:

  • 你想生成一个数字,而不是 2
  • “保持速度”部分如何适应“随机角度”部分。 x 和 y 应该是 deltaX 和 deltaY 吗?
【解决方案2】:

首先,将球设置为浮动速度。然后有一个速度,你在每次更新时都会移动 x 和 y 成员,就像你现在所拥有的一样。使用你的速度、你的移动角度和一些三角函数计算你移动 x 和 y 的距离。 (记得把度数换成弧度)

float Speed = 10;
float Angle = 45;
Velocity.x = cos(Angle * 3.14159 / 180) * Speed;
Velocity.y = sin(Angle * 3.14159 / 180) * Speed;

当你遇到碰撞时,你可以重新计算你的角度添加你的新随机角度并重新计算你的速度。 (再次将度数转换为弧度)。

//if (collision)
Angle = atan2(Velocity.y * 3.14159 / 180, Velocity.x * 3.14159 / 180);
Angle += rand() % 90 + 1; // Could also be subtracting here
Velocity.x = cos(Angle * 3.14159 / 180) * Speed;
Velocity.y = sin(Angle * 3.14159 / 180) * Speed;

根据您击打的一侧和角度来增加或减少角度。

void HitTop()
{
    if (Velocity.x > 0)
        //Subtract random angle
    else
        //Add random angle
}

对所有方面都这样做。

【讨论】:

    【解决方案3】:

    让你的边框具有任意形式(不仅仅是矩形)。如果弹跳点中的边界法线(单位)向量是

    n = (n.x, n.y)
    

    然后是弹跳变化后的速度向量:

        dot = speed.x * n.x + speed.y * n.y
    
        //after reflection
        newspeed.x = speed.x - 2 * dot * n.x
        newspeed.y = speed.y - 2 * dot * n.y
    

    要添加一些随机性,只需正常旋转一个小的随机角度:

    df = GaussianRandom(Mean = 0, Sigma = Pi / 30)  //arbitrary parameter
                //seems in c++ it is std::normal_distribution
    n'.x = n.x * Cos(df) - n.y * Sin(df)
    n'.y = n.x * Sin(df) + n.y * Cos(df)
    

    并使用n' 计算反射。请注意,这种方法保留了速度幅度。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2011-07-28
      • 2021-02-23
      • 2015-11-12
      • 2021-11-27
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多