SFML C++ Използвам делта време погрешно кой е правилният начин

Опитвам се да направя клонинг на астероиди и досега успях да накарам кораба си да лети. Скоростта му обаче също зависи от FPS. Така че, за да смекча това, прочетох, че ще трябва да умножа моите контролни променливи с deltaTime (времето между кадрите, ако съм разбрал правилно). Въпреки това, когато се опитах да внедря, корабът отказа да се движи. Мислех, че се дължи на възможно неявно закръгляване до 0 (преобразуване в int?), но няма издадени предупреждения. какво правя грешно

Ето как изглежда кодът:

sf::Vector2f newPosition(0,0);
sf::Vector2f velocity(0,0);
float acceleration = 3.0f;
float angle = 0;
float angularVelocity = 5;
float velDecay = 0.99f;


sf::Clock deltaClock;

window.setFramerateLimit(60);
while (window.isOpen())
{
    sf::Time deltaTime = deltaClock.restart();
    sf::Event event;
    while (window.pollEvent(event))
    {
        if (event.type == sf::Event::Closed || ((event.type == sf::Event::KeyPressed) && (event.key.code == sf::Keyboard::Escape)))
            window.close();
    }
    if(sf::Keyboard::isKeyPressed(sf::Keyboard::Up))
    {
        if(velocity.x < 10)velocity.x += acceleration * deltaTime.asSeconds();
        if(velocity.y < 10)velocity.y += acceleration * deltaTime.asSeconds();
        angle = player.getRotation() - 90;
    }
    if(sf::Keyboard::isKeyPressed(sf::Keyboard::Down))
    {
        if(velocity.x > 0)velocity.x -= acceleration * deltaTime.asSeconds();
        else velocity.x = 0;
        if(velocity.y > 0)velocity.y -= acceleration * deltaTime.asSeconds();
        else velocity.y = 0;
    }
    if(sf::Keyboard::isKeyPressed(sf::Keyboard::Left))
    {
        player.rotate(-angularVelocity);
    }
    if(sf::Keyboard::isKeyPressed(sf::Keyboard::Right))
    {
        player.rotate(angularVelocity);
    }

    newPosition.x = player.getPosition().x + (velocity.x * cos(angle * (M_PI / 180.0))) * deltaTime.asSeconds();
    newPosition.y = player.getPosition().y + (velocity.y * sin(angle * (M_PI / 180.0))) * deltaTime.asSeconds();    
    player.setPosition(newPosition);

    velocity.x *= velDecay;
    velocity.y *= velDecay;

    window.clear();
    window.draw(background);
    window.draw(player);
    window.draw(debugText);
    window.display();
}

person MrPlow    schedule 15.06.2013    source източник
comment
може ли да е, защото задавате позиция на скорост? Вместо от скорост до скорост? Това може да е семантика, но реших, че все пак ще попитам. Гледам кода, опитвайки се да разбера какво може да не е наред. Предполагам, че някъде нещо се настройва на нула, ако изобщо не се движите.   -  person Dean Knight    schedule 15.06.2013
comment
Уверете се, че не сте останали в безкраен цикъл тук: while (window.pollEvent(event))   -  person Dean Knight    schedule 15.06.2013
comment
Да, не трябва ли да задавате позиция на нещо като: newPosition.x = curPosition.x + (VelocityPerSec / dtSeconds)? Същото за Y посока. Също така: вашите нови скорости не трябва да се изчисляват с помощта на позицията... Поне ако разбирам правилно от простата физика. Използвайте това уравнение, за да изчислите новата си скорост на всеки кадър: vf = vi + at Може би поправянето на тази математика ще попречи на вашата симулация да се държи странно. Кажете ми как върви и мога да съставя отговор, така че хората да го намерят и прочетат по-лесно.   -  person Dean Knight    schedule 15.06.2013
comment
@DeanKnight Наистина, семантично имената са грешни и математиката ми вероятно е лоша, тъй като не съм правил много от нищо по физика от доста време. Промених малко кода, преименувах няколко неща. Намаляването на скоростта не работи както си мислех, че трябва и не съм сигурен как да го накарам да работи (както е в момента, то се изпълнява постоянно и незабавно убива скоростта, карайки кораба да остане на място). while (window.pollEvent(event)) не предизвиква безкраен цикъл.   -  person MrPlow    schedule 15.06.2013
comment
@DeanKnight while(window.pollEvent(event)) е начинът за обработка на събития в SFML, не може да бъде безкраен цикъл.   -  person teh internets is made of catz    schedule 15.06.2013
comment
Вие сте напълно прав. Открих това след търсене в него. Никога не може да бъде твърде задълбочен, когато нямате кода пред себе си, за да преминете през дебъгер. :) Изглежда сме решили проблема. Благодаря за коментара   -  person Dean Knight    schedule 15.06.2013


Отговори (1)


Не мога да изпълня вашия код, следователно не мога да бъда 100% сигурен, но следното не изглежда правилно:

Изчисляване на скоростта

velocity.x = (player.getPosition().x + (acceleration * cos(angle * (M_PI / 180.0)) * deltaTime.asSeconds()));
velocity.y = (player.getPosition().y + (acceleration * sin(angle * (M_PI / 180.0)) * deltaTime.asSeconds()));   

Опитайте да го промените на нещо подобно:

velocity.x = (player.getVelocity().x + (acceleration * cos(angle * (M_PI / 180.0)) * deltaTime.asSeconds()));
velocity.y = (player.getVelocity().y + (acceleration * sin(angle * (M_PI / 180.0)) * deltaTime.asSeconds()));   

Това използва простото физично уравнение vf = vi + a*t, но по начин на компонентите x,y. Вярвам, че използването на Position.x и Position.y напълно ще отхвърли това уравнение.

Забележка: по отношение на синтаксиса кодът, който ви дадох, може да не работи. Поставете какъвто и да е код в player.getVelocity().x, който ще ви даде текущата скорост на играча в посока X. Направете същото за посоката Y.

Настройка на новата позиция

Не мога да съм сигурен дали player.setPosition(velocity); е правилно или не. Ако функцията setPosition се грижи за извършването на следното:

newPosition.x = oldPosition.x + (velocity.x/dt)

както в посока x, така и в посока y, тогава това трябва да работи.

Но ако просто прави:

newPosition.x = velocity.x

Тогава смятам, че това ще бъде грешно и ще доведе до неправилна симулация.

Като цяло

Може да има други математически грешки във вашия код. Особено с начина, по който изчислявате ускорението. Не съм проверявал това и в момента нямам време. Ако направите корекциите, които споменах, и все още не работи, пуснете ми коментар и мога да опитам да потърся повече, когато имам време. Имам собствена игра, върху която трябва да работя точно сега.

Редактиране1:

Вашият код изглежда много по-добре. От тук бих добавил код, който променя вашето ускорение. Да кажем, че натискането на клавиша w ще включи "тласкачи", които ви дават ускорение от 2. Ускорението ще се понижи (връща се към нула) за ВРЕМЕ, когато не се натиска бутон. Не на кадър. Преди умножавахте по 0,99 на кадър. Което означава, че ускорението може да бъде нула за половин секунда, ако получавате 120 fps (напълно възможно в проста игра като тази). Трябва да го деградирате въз основа на вашата dt променлива. След като достигне нула обаче, все още ще имате положителна скорост. Обикновено тази скорост се влошава с времето поради гравитацията, но гравитацията в космоса би била много малка в сравнение с това, което намирате на земята (-9,8 m/s или -32 ft/s). Така че може би бихте могли да приложите намаляване на гравитацията върху вашата скорост, което също се изчислява във времето

OR

можете да пренебрегнете гравитацията и да им позволите да натиснат клавиша S и да приложат отрицателно ускорение (-2) и след това да го приложат към вашата скорост, както сте направили. Това би позволило отрицателните стойности да влошат скоростта ви и може да се смята, че вашите кораби включват двигатели в обратна посока.

Разбира се, можете да мамите като разработчик на играта и да предотвратите скоростта ви да падне под нулата (ако искате играчът да се движи само напред). И когато откриете скорост, която е отрицателна, задайте скорост на 0 и ускорение на 0.

Забележка: "деградирането" на ускорението ще се случи както за положително, така и за отрицателно, и то ще "деградира" към нула. Ще трябва да бърникате с тези стойности и да играете тест, за да видите какво е правилно. Трябва ли ускорението да се влошава с 1 в секунда? Трябва ли дори да използвате стойността 2 и -2 като стойностите на ускорението, които споменах по-рано? 2 и -2 може да работят, но може би 3 и -3 са по-добри? Това са все въпроси, на които трябва да си отговорите сами, като го тествате.

Надявам се това да ви даде още идеи и да помогне за пълното разрешаване на въпроса ви! Кажи ми как върви.

person Dean Knight    schedule 15.06.2013
comment
Промених малко кода и сега изглежда малко повече като вашите примери. setPosition просто задава стойностите x и y на това, което съм задал там. Въпреки това открих, че има метод move в SFML, който добавя към текущата позиция. Бих искал да има някакъв вид триене, което да забави кораба, докато се носи в космоса, и това е, което трябва да прави разпадането, но не работи, както възнамерявах. Все още не съм сигурен как да поправя това. - person MrPlow; 15.06.2013
comment
Благодаря за идеите. Вече имах мисъл за намаляване на скоростта с времето, вместо да използвам рамки, както правех досега. Засега това ще е достатъчно, тъй като все още трябва да науча много повече, преди да мога да си играя с гравитацията, силите и други подобни. Благодаря за вашата помощ - person MrPlow; 15.06.2013
comment
Не е проблем. Радвам се, че мога да помогна. - person Dean Knight; 15.06.2013