tBane Temat założony przez niniejszego użytkownika |
[SFML] Ruch gracza w grze » 2024-05-09 09:41:45 Witam. Pracuję obecnie nad ruchem gracza w grze. Postarałem się jak najlepiej to zrobić i proszę Was o pomoc czy aby na pewno wszystko dobrze napisałem. Oto mój kod: while( window->isOpen() ) { sf::Event event; while( window->pollEvent( event ) ) { if( event.type == sf::Event::Closed ) window->close(); if( event.type == sf::Event::KeyPressed ) { if( sf::Keyboard::isKeyPressed( sf::Keyboard::Escape ) ) { window->close(); exit( 0 ); } } } cout << "cursor at: " << sf::Mouse::getPosition( * window ).x << "," << sf::Mouse::getPosition( * window ).y << endl; if(( sf::Keyboard::isKeyPressed( sf::Keyboard::Space ) || sf::Keyboard::isKeyPressed( sf::Keyboard::Enter ) ) && player->state != states::fight ) { player->attack(); } if( sf::Keyboard::isKeyPressed( sf::Keyboard::W ) || sf::Keyboard::isKeyPressed( sf::Keyboard::Up ) ) { if( player->direction != 0 ) player->setDirection( 0 ); else if( !collisions( player, 0, - player->stepSize ) ) player->move(); } if( sf::Keyboard::isKeyPressed( sf::Keyboard::D ) || sf::Keyboard::isKeyPressed( sf::Keyboard::Right ) ) { if( player->direction != 1 ) player->setDirection( 1 ); else if( !collisions( player, player->stepSize, 0 ) ) player->move(); } if( sf::Keyboard::isKeyPressed( sf::Keyboard::S ) || sf::Keyboard::isKeyPressed( sf::Keyboard::Down ) ) { if( player->direction != 2 ) player->setDirection( 2 ); else if( !collisions( player, 0, player->stepSize ) ) player->move(); } if( sf::Keyboard::isKeyPressed( sf::Keyboard::A ) || sf::Keyboard::isKeyPressed( sf::Keyboard::Left ) ) { if( player->direction != 3 ) player->setDirection( 3 ); else if( !collisions( player, - player->stepSize, 0 ) ) player->move(); } if( player->state == states::fight && player->step == 3 ) { playerAttack(); } deleteDeadBeasts(); for( auto & go: gameObjects ) go->update(); std::sort( gameObjects.begin(), gameObjects.end(),[ ]( const auto & a, const auto & b ) { return a->y < b->y; } ); view.setCenter( player->x, player->y ); window->clear( sf::Color( 64, 128, 64 ) ); window->setView( view ); for( auto & go: gameObjects ) go->render( window ); window->display(); sf::sleep( sf::milliseconds( 70 ) ); } |
|
pekfos |
» 2024-05-09 21:38:31 Podstawowe pytanie brzmi: jakie będzie zachowanie w przypadku naciśnięcia kombinacji klawiszy. 1) ruch na skos, 2) dwa przeciwne kierunki naraz. Wygląda trochę tak jakby ruch nie był wtedy w ogóle możliwy przez warunki na player->direction. sf::sleep( sf::milliseconds( 70 ) );
Tego zdecydowanie nie powinno tu być. |
|
tBane Temat założony przez niniejszego użytkownika |
» 2024-05-09 22:56:30 usunąłem sleep i wstawiłem setFramerateLimit(30). Teraz gra działa bardzo szybko. Jak spowolnić update tzn. ruch gracza i potworków ? Mam taką funkcję aktualizującą gracza void update() { if( state == states::fight ) { if( state == states::fight && step > 3 ) { state = states::idle; step = 0; bodySprite->setTexture( * idleTextures[ direction * 4 ] ); } else { bodySprite->setTexture( * fightTextures[ direction * 4 + step ] ); step += 1; } } else if( state == states::run ) { if( step > 3 ) step = 0; state = states::idle; bodySprite->setTexture( * runTextures[ direction * 4 + step ] ); step += 1; } else if( state == states::idle ) { if( step > 3 ) step = 0; bodySprite->setTexture( * idleTextures[ direction * 4 + step ] ); step += 1; } mouseOvering(); bodySprite->setPosition( x, y ); collider->setPosition( x, y ); attackRangeArea->setPosition( x, y ); textname->setPosition( x, y - height - 30 ); }
|
|
pekfos |
» 2024-05-09 23:27:08 Najlepiej nie polegać na ilości klatek na sekundę i uzależnić aktualizacje od upływu czasu rzeczywistego, ten możesz dokładnie mierzyć z użyciem sf::Clock. Mając różnicę czasu od ostatniej aktualizacji w sekundach (oznaczane często deltaT, albo dt), używasz tej wartości do aktualizowania wszystkiego. Dalej lecisz z klasycznymi wzorami z fizyki na ruch jednostajny. Gdy jako stałą w kodzie określasz prędkość, to wtedy nie ma co działać za szybko czy za wolno, o ile tylko się obliczenia zgadzają. W przypadkach gdzie robisz inkrementację zmiennej step, też trzeba to jakoś wyrazić w oparciu o czas, na przykład z użyciem dodatkowej zmiennej float w której trzymasz czas do następnej inkrementacji. float countdown = 0;
void update( float dt ) { countdown -= dt; while( countdown <= 0 ) { countdown += StepTimeInSeconds; step++; } } |
|
tBane Temat założony przez niniejszego użytkownika |
» 2024-05-10 18:53:45 no dobra, zacząłem od dodania zmiennej upływu czasu w funkcji main.cpp. Teraz potrzebuję aktualizować gracza i nie mam pojęcia jak to zrobić. main.cpp... sf::Clock clock; sf::Time elapsedTime = clock.getElapsedTime(); float prevTime = elapsedTime.asSeconds(); float currentTime = prevTime; float dt;
int main() { while( window->isOpen() ) { elapsedTime = clock.getElapsedTime(); prevTime = currentTime; currentTime = elapsedTime.asSeconds(); dt = currentTime - prevTime; for( auto & go: gameObjects ) go->update( dt ); } player.hppvoid update( float dt ) { float distance = 10.0f * stepSize * dt; if( state == states::fight ) { if( state == states::fight && step > 3 ) { state = states::idle; step = 0; bodySprite->setTexture( * idleTextures[ direction * 4 ] ); } else { bodySprite->setTexture( * fightTextures[ direction * 4 + step ] ); step += 1; } } else if( state == states::run ) { if( direction == 0 ) y -= distance; if( direction == 1 ) x += distance; if( direction == 2 ) y += distance; if( direction == 3 ) x -= distance; state = states::idle; bodySprite->setTexture( * runTextures[ direction * 4 + step ] ); step += 1; if( step > 3 ) step = 0; } else if( state == states::idle ) { bodySprite->setTexture( * idleTextures[ direction * 4 + step ] ); step += 1; if( step > 3 ) step = 0; } mouseOvering(); bodySprite->setPosition( x, y ); collider->setPosition( x, y ); attackRangeArea->setPosition( x, y ); textname->setPosition( x, y - height - 30 ); }
|
|
tBane Temat założony przez niniejszego użytkownika |
» 2024-05-10 19:14:03 dobra, jakoś działa. Ale czy to dobrze jest napisane ? |
|
pekfos |
» 2024-05-10 22:27:09 Ale co jest dobrze napisane? Ostatni kod był w wiadomości w której "nie miałeś pojęcia jak to zrobić". Tam aktualizacja animacji wygląda jakby polegała na częstotliwości aktualizacji a nie czasie. dt = currentTime - prevTime;
Odejmujesz od siebie 2 czasy liczone od startu programu jako float, więc z czasem precyzja będzie maleć i gra może przestać działać w ogóle bo dt będzie zerowe, chociaż nikt pewnie nie będzie grać tak długo by tego doświadczyć. Te odejmowanie powinno działać na sf::Time, które ma stałą precyzję. A najprościej nie pisać tego odejmowania samemu tylko użyć metody restart() zamiast getElapsedTime(). float dt = clock.restart().asSeconds();
|
|
tBane Temat założony przez niniejszego użytkownika |
» 2024-05-10 22:31:20 o to chodziło ? sf::Clock clock; sf::Time prevTime = clock.getElapsedTime(); sf::Time currentTime = prevTime; float dt;
while( window->isOpen() ) { prevTime = currentTime; currentTime = clock.getElapsedTime(); dt = currentTime.asSeconds() - prevTime.asSeconds(); for( auto & go: gameObjects ) go->update( dt ); |
|
« 1 » 2 |