tBane Temat założony przez niniejszego użytkownika |
Kolizje w grze RPG czyli jak opanować Elipsy » 2024-05-01 21:06:52 Witam. Napisałem system kolizji(w main.cpp), który nie działa i potrzebuję waszej pomocy. Kolizje generowane są jako przecięcia elips dla obiektów. Elipsy zawsze mają stosunek promieni 1 - 1/2 paczka z projektem https://drive.google.com/file/d/1LHXaJ7SS30S1l3_kiPrKL-nP4blfTajD/view?usp=sharinghttps://megawrzuta.pl/download/5f7dc8b4c798ec4a9528ddc32785e21d.htmlTextures.hpp#ifndef Textures_hpp #define Textures_hpp
using namespace std;
class Texture { public: string name; sf::Texture * texture; float cx, cy; Texture( string pathfile, float cx, float cy ) { name = ""; int i = pathfile.size() - 1; while( pathfile[ i ] != '/' ) name = pathfile[ i-- ] + name; this->cx = cx; this->cy = cy; texture = new sf::Texture; texture->loadFromFile( pathfile ); cout << "load texture: " << pathfile << " as: " << name << endl; } };
std::vector < Texture * > textures;
void loadTexture( string pathfile, float cx, float cy ) { textures.push_back( new Texture( pathfile, cx, cy ) ); }
Texture * getTexture( string name ) { for( auto & t: textures ) { if( t->name == name ) { return t; } } return nullptr; } #endif
GameObjects.hpp#ifndef GameObjects_hpp #define GameObjects_hpp
class GameObject { public: float x, y, radius; GameObject( float x, float y, float radius ) { this->x = x; this->y = y; this->radius = radius; } ~GameObject() { } virtual void update() { } virtual void render( sf::RenderWindow * window ) { } };
#endif
NatureObjects.hpp#ifndef NatureObjects_hpp #define NatureObjects_hpp
class NatureObject : public GameObject { public: Texture * texture; sf::Sprite * sprite; sf::CircleShape * collider; NatureObject( float x, float y, float radius, Texture * texture = nullptr ) : GameObject( x, y, radius ) { this->texture = texture; sprite = new sf::Sprite(); if( texture != nullptr ) { sprite->setTexture( * texture->texture ); sprite->setOrigin( texture->cx, texture->cy ); sprite->setPosition( x, y ); } collider = new sf::CircleShape( radius ); collider->setOrigin( radius, radius ); collider->setScale( 1.0f, 0.5f ); collider->setFillColor( sf::Color( 128, 64, 64, 128 ) ); collider->setPosition( x, y ); } ~NatureObject() { } void update() { } void render( sf::RenderWindow * window ) { window->draw( * sprite ); window->draw( * collider ); } };
#endif
Player.hpp#ifndef Player_hpp #define Player_hpp
enum class states { idle, run };
class Player : public GameObject { public: sf::Texture * idleTextures[ 16 ]; sf::Texture * runTextures[ 16 ]; sf::Sprite * bodySprite; sf::CircleShape * collider; int direction; int step; float stepSize = 4.0f; states state; Player() : GameObject( 0, 0, 32 ) { direction = 2; step = 0; state = states::idle; for( int i = 0; i < 16; i++ ) idleTextures[ i ] = new sf::Texture(); idleTextures[ 0 ]->loadFromFile( "hero/idleTop0.png" ); idleTextures[ 1 ]->loadFromFile( "hero/idleTop1.png" ); idleTextures[ 2 ]->loadFromFile( "hero/idleTop2.png" ); idleTextures[ 3 ]->loadFromFile( "hero/idleTop3.png" ); idleTextures[ 4 ]->loadFromFile( "hero/idleRight0.png" ); idleTextures[ 5 ]->loadFromFile( "hero/idleRight1.png" ); idleTextures[ 6 ]->loadFromFile( "hero/idleRight2.png" ); idleTextures[ 7 ]->loadFromFile( "hero/idleRight3.png" ); idleTextures[ 8 ]->loadFromFile( "hero/idleBottom0.png" ); idleTextures[ 9 ]->loadFromFile( "hero/idleBottom1.png" ); idleTextures[ 10 ]->loadFromFile( "hero/idleBottom2.png" ); idleTextures[ 11 ]->loadFromFile( "hero/idleBottom3.png" ); idleTextures[ 12 ]->loadFromFile( "hero/idleLeft0.png" ); idleTextures[ 13 ]->loadFromFile( "hero/idleLeft1.png" ); idleTextures[ 14 ]->loadFromFile( "hero/idleLeft2.png" ); idleTextures[ 15 ]->loadFromFile( "hero/idleLeft3.png" ); for( int i = 0; i < 16; i++ ) runTextures[ i ] = new sf::Texture(); runTextures[ 0 ]->loadFromFile( "hero/runTop0.png" ); runTextures[ 1 ]->loadFromFile( "hero/runTop1.png" ); runTextures[ 2 ]->loadFromFile( "hero/runTop2.png" ); runTextures[ 3 ]->loadFromFile( "hero/runTop3.png" ); runTextures[ 4 ]->loadFromFile( "hero/runRight0.png" ); runTextures[ 5 ]->loadFromFile( "hero/runRight1.png" ); runTextures[ 6 ]->loadFromFile( "hero/runRight2.png" ); runTextures[ 7 ]->loadFromFile( "hero/runRight3.png" ); runTextures[ 8 ]->loadFromFile( "hero/runBottom0.png" ); runTextures[ 9 ]->loadFromFile( "hero/runBottom1.png" ); runTextures[ 10 ]->loadFromFile( "hero/runBottom2.png" ); runTextures[ 11 ]->loadFromFile( "hero/runBottom3.png" ); runTextures[ 12 ]->loadFromFile( "hero/runLeft0.png" ); runTextures[ 13 ]->loadFromFile( "hero/runLeft1.png" ); runTextures[ 14 ]->loadFromFile( "hero/runLeft2.png" ); runTextures[ 15 ]->loadFromFile( "hero/runLeft3.png" ); bodySprite = new sf::Sprite(); bodySprite->setOrigin( 32, 58 ); collider = new sf::CircleShape( 16 ); collider->setFillColor( sf::Color( 128, 64, 64, 128 ) ); collider->setOrigin( 16, 16 ); collider->setScale( 1, 0.5f ); } ~Player() { } void move( int direction ) { state = states::run; if( direction != this->direction ) { this->direction = direction; step = 0; } else { if( direction == 0 ) y -= 4.0f; if( direction == 1 ) x += 4.0f; if( direction == 2 ) y += 4.0f; if( direction == 3 ) x -= 4.0f; } } void setPosition( float x, float y ) { this->x = x; this->y = y; } void update() { step += 1; if( step > 3 ) step = 0; if( state == states::run ) { state = states::idle; bodySprite->setTexture( * runTextures[ direction * 4 + step ] ); } else if( state == states::idle ) { bodySprite->setTexture( * idleTextures[ direction * 4 + step ] ); } bodySprite->setPosition( x, y ); collider->setPosition( x, y ); } void render( sf::RenderWindow * window ) { window->draw( * bodySprite ); window->draw( * collider ); } };
#endif
main.cpp#include <SFML/Graphics.hpp>
#include<iostream>
#include "Textures.hpp" #include "GameObjects.hpp" #include "NatureObjects.hpp" #include "Player.hpp"
std::vector < GameObject * > gameObjects; Player * player;
void loadTextures(); void createGameObjects(); bool collisions( GameObject * object, float dx, float dy ); bool collisionTwoElipses( float x1, float y1, float rx1, float ry1, float x2, float y2, float rx2, float ry2 );
int main() { sf::RenderWindow * window = new sf::RenderWindow( sf::VideoMode( 1280, 720 ), "RPG" ); window->setFramerateLimit( 60 ); loadTextures(); createGameObjects(); player = new Player(); player->setPosition( 70, 100 ); 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::W ) && !collisions( player, 0, - player->stepSize ) ) player->move( 0 ); if( sf::Keyboard::isKeyPressed( sf::Keyboard::D ) && !collisions( player, player->stepSize, 0 ) ) player->move( 1 ); if( sf::Keyboard::isKeyPressed( sf::Keyboard::S ) && !collisions( player, 0, player->stepSize ) ) player->move( 2 ); if( sf::Keyboard::isKeyPressed( sf::Keyboard::A ) && !collisions( player, - player->stepSize, 0 ) ) player->move( 3 ); if( sf::Keyboard::isKeyPressed( sf::Keyboard::Up ) && !collisions( player, 0, - player->stepSize ) ) player->move( 0 ); if( sf::Keyboard::isKeyPressed( sf::Keyboard::Right ) && !collisions( player, player->stepSize, 0 ) ) player->move( 1 ); if( sf::Keyboard::isKeyPressed( sf::Keyboard::Down ) && !collisions( player, 0, player->stepSize ) ) player->move( 2 ); if( sf::Keyboard::isKeyPressed( sf::Keyboard::Left ) && !collisions( player, - player->stepSize, 0 ) ) player->move( 3 ); } } cout << "cursor at: " << sf::Mouse::getPosition( * window ).x << "," << sf::Mouse::getPosition( * window ).y << endl; for( auto & go: gameObjects ) go->update(); player->update(); window->clear( sf::Color( 64, 128, 64 ) ); for( auto & go: gameObjects ) go->render( window ); player->render( window ); window->display(); sf::sleep( sf::milliseconds( 150 ) ); } return 0; }
void loadTextures() { loadTexture( "assets/tree1.png", 58, 106 ); loadTexture( "assets/rocks1.png", 67, 83 ); }
void createGameObjects() { gameObjects.push_back( new NatureObject( 100, 50, 16, getTexture( "tree1.png" ) ) ); gameObjects.push_back( new NatureObject( 150, 200, 16, getTexture( "tree1.png" ) ) ); gameObjects.push_back( new NatureObject( 200, 300, 16, getTexture( "tree1.png" ) ) ); gameObjects.push_back( new NatureObject( 300, 30, 16, getTexture( "tree1.png" ) ) ); gameObjects.push_back( new NatureObject( 400, 70, 16, getTexture( "tree1.png" ) ) ); gameObjects.push_back( new NatureObject( 50, 250, 16, getTexture( "tree1.png" ) ) ); gameObjects.push_back( new NatureObject( 420, 270, 16, getTexture( "tree1.png" ) ) ); gameObjects.push_back( new NatureObject( 650, 100, 16, getTexture( "tree1.png" ) ) ); gameObjects.push_back( new NatureObject( 600, 280, 16, getTexture( "tree1.png" ) ) ); gameObjects.push_back( new NatureObject( 30, 150, 40, getTexture( "rocks1.png" ) ) ); gameObjects.push_back( new NatureObject( 320, 170, 40, getTexture( "rocks1.png" ) ) ); gameObjects.push_back( new NatureObject( 350, 350, 40, getTexture( "rocks1.png" ) ) ); }
bool collisions( GameObject * object, float dx, float dy ) { for( auto & go: gameObjects ) { if( go != object && collisionTwoElipses( object->x + dx, object->y + dy, object->radius, object->radius / 2.f, go->x, go->y, go->radius, go->radius / 2.f ) ) return true; } return false; }
bool collisionTwoElipses( float x1, float y1, float rx1, float ry1, float x2, float y2, float rx2, float ry2 ) { float dx = x2 - x1; float dy = y2 - y1; float d = sqrt( dx * dx + dy * dy ); if( d <= rx1 + rx2 && d <= ry1 + ry2 ) return true; else return false; }
|
|
DejaVu |
» 2024-05-02 16:43:45 |
|
tBane Temat założony przez niniejszego użytkownika |
» 2024-05-03 02:32:27 Rozumiem, jednak w mojej grze potrzebowałem wykrywać kolizję elips. Sam zobacz jak to wygląda na screenie. |
|
DejaVu |
» 2024-05-03 16:00:13 No to albo zrób kolizje pixel perfect, albo dostosuj rozwiązanie do prostokątów i okręgów. |
|
tBane Temat założony przez niniejszego użytkownika |
» 2024-05-03 17:34:05 pixel perfect jest powolne moim zdaniem, poza tym po co skoro można użyć prostych elips. #ifndef Collisions_hpp #define Collisions_hpp
bool collisionTwoElipses( float x1, float y1, float rx1, float ry1, float x2, float y2, float rx2, float ry2 ) { float len = sqrt( pow( x1 - x2, 2 ) + pow( y1 - y2, 2 ) ); float angle = atan2( y2 - y1, x2 - x1 ); float px = x1 + rx1 * cos( angle ); float py = y1 + ry1 * sin( angle ); if( pow(( px - x2 ) / rx2, 2 ) + pow(( py - y2 ) / ry2, 2 ) <= 1 ) return true; return false; }
bool collisions( GameObject * object, float dx, float dy ) { for( auto & go: gameObjects ) { if( go != object && collisionTwoElipses( object->x + dx, object->y + dy, object->radius, object->radius / 2.f, go->x, go->y, go->radius, go->radius / 2.f ) ) return true; } return false; }
#endif |
|
tBane Temat założony przez niniejszego użytkownika |
» 2024-05-07 21:44:00 Mam problem z kodem, a chat GPT nie pomógł. Wydaje mi się, że mam poprawny kod, ale nie działa. Funkcja playerInViewRange(); zawsze zwraca falsebool intersectionsTwoElipses( float x1, float y1, float rx1, float ry1, float x2, float y2, float rx2, float ry2 ) { float len = sqrt( pow( x1 - x2, 2 ) + pow( y1 - y2, 2 ) ); float angle = atan2( y2 - y1, x2 - x1 ); float px = x1 + rx1 * cos( angle ); float py = y1 + ry1 * sin( angle ); if( pow(( px - x2 ) / rx2, 2 ) + pow(( py - y2 ) / ry2, 2 ) <= 1 ) return true; else return false; }
bool Beast::playerInViewRange() { if( intersectionsTwoElipses( x, y, radius + viewRange,( radius + viewRange ) / 2.0f, player->x, player->y, player->radius, player->radius / 2.0f ) ) { cout << "player is in range " << name << "\n"; return true; } cout << "player is not in range " << name << "\n"; return false; }
void Beast::update() { if( playerInViewRange() ) { target_x = player->x; target_y = player->y; state = states::run; cout << name << " follow the player\n"; } if( state == states::idle ) { } else if( state == states::run ) { } |
|
DejaVu |
» 2024-05-07 22:12:03 |
|
tBane Temat założony przez niniejszego użytkownika |
» 2024-05-07 22:15:33 Ale dla innej funkcji to przecięcie się dwóch elips działa. void playerAttack() { float x, y, rx, ry; x = player->x; y = player->y; rx = player->radius + player->attackRange; ry =( player->radius + player->attackRange ) / 2.0f; for( auto & b: beasts ) { if( b->type == gameObjectType::Beast ) { if( intersectionsTwoElipses( x, y, rx, ry, b->x, b->y, b->radius, b->radius / 2.0f ) ) { b->takeDamage( 2 ); } } } }
|
|
« 1 » 2 |