tBane Temat założony przez niniejszego użytkownika |
[SFML] Zaznaczanie jednostek w grze » 2024-02-09 17:05:13 Witam. Napisałem prosty system zaznaczania i sterowania jednostek. Left Click - Zaznacz nową jednostkę Shift + Left Click - Dodaj jednostkę do zaznaczonych Right Click - Wyznacz cel jednostkom Potrzebuję zrozumieć jak wyznaczyć "obszar zaznaczenia", który zaznaczy kilka jednostek jednocześnie. kod poniżej ... Villager.hpp#ifndef Villager_hpp #define Villager_hpp
#include <iostream> #include <SFML/Graphics.hpp> using namespace std;
class Villager { public: string name; float x, y, radius; sf::CircleShape * shape; bool isSelected; float speed; bool goToTarget; float target_x, target_y; Villager( string, float, float, float ); ~Villager(); bool collisionWithPoint( float, float ); void update(); void render( sf::RenderWindow * ); };
#endif
Villager.cpp#include "Villager.hpp"
Villager::Villager( string name, float x, float y, float radius ) { this->name = name; this->x = x; this->y = y; this->radius = radius; shape = new sf::CircleShape( radius ); shape->setOrigin( radius, radius ); shape->setPosition( x, y ); shape->setFillColor( sf::Color( 128.0f, 128.0f, 128.0f ) ); shape->setOutlineThickness( 4.0f ); shape->setOutlineColor( sf::Color( 16.0f, 16.0f, 16.0f ) ); speed = 1.0f; isSelected = false; goToTarget = false; target_x = target_y = 0; }
Villager::~Villager() { }
bool Villager::collisionWithPoint( float px, float py ) { if( pow( px - x, 2 ) + pow( py - y, 2 ) < radius * radius ) return true; else return false; }
void Villager::update() { if( goToTarget == true ) { if( target_x == x && target_y == y ) { goToTarget = false; } else if( pow( target_x - x, 2 ) + pow( target_y - y, 2 ) < speed * speed ) { x = target_x; y = target_y; } else { float radians = atan2( target_y - y, target_x - x ); x += speed * cos( radians ); y += speed * sin( radians ); } } shape->setPosition( x, y ); if( isSelected == true ) shape->setFillColor( sf::Color( 128.0f, 48.0f, 48.0f ) ); else shape->setFillColor( sf::Color( 128.0f, 128.0f, 128.0f ) ); }
void Villager::render( sf::RenderWindow * window ) { window->draw( * shape ); }
main#include <iostream> #include <vector>
#include <SFML/Graphics.hpp> using namespace std;
#include "villager.hpp"
sf::RenderWindow * window;
std::vector < Villager * > villagers; std::vector < Villager * > selectedVillagers;
void deselectVillagers() { for( auto & sv: selectedVillagers ) { sv->isSelected = false; } selectedVillagers.clear(); }
void selectVillagers( float x, float y ) { selectedVillagers.clear(); for( auto & v: villagers ) { if( v->collisionWithPoint( x, y ) ) if( v->isSelected ) { v->isSelected = false; } else { v->isSelected = true; } if( v->isSelected ) selectedVillagers.push_back( v ); } cout << "click [" << x << ", " << y << "]\n"; }
void setTargetForVillagers( float x, float y ) { for( auto & sv: selectedVillagers ) { sv->goToTarget = true; sv->target_x = x; sv->target_y = y; } }
void updateVillagers() { for( auto & v: villagers ) v->update(); }
void renderVillagers( sf::RenderWindow * window ) { for( auto & v: villagers ) v->render( window ); }
int main() { window = new sf::RenderWindow( sf::VideoMode( 720, 480 ), "village" ); window->setFramerateLimit( 60 ); villagers.clear(); villagers.push_back( new Villager( "Odyn", 100, 100, 16 ) ); villagers.push_back( new Villager( "Uruk", 200, 100, 16 ) ); villagers.push_back( new Villager( "Har", 200, 300, 16 ) ); villagers.push_back( new Villager( "Zahn", 150, 250, 16 ) ); selectedVillagers.clear(); while( window->isOpen() ) { sf::Event ev; while( window->pollEvent( ev ) ) { sf::Vector2i mousePosition = sf::Mouse::getPosition( * window ); if( ev.type == sf::Event::Closed ) window->close(); if( sf::Keyboard::isKeyPressed( sf::Keyboard::LShift ) && ev.type == sf::Event::MouseButtonPressed && sf::Mouse::isButtonPressed( sf::Mouse::Left ) ) { selectVillagers( mousePosition.x, mousePosition.y ); } else if( ev.type == sf::Event::MouseButtonPressed && sf::Mouse::isButtonPressed( sf::Mouse::Left ) ) { deselectVillagers(); selectVillagers( mousePosition.x, mousePosition.y ); } else if( ev.type == sf::Event::MouseButtonPressed && sf::Mouse::isButtonPressed( sf::Mouse::Right ) ) { setTargetForVillagers( mousePosition.x, mousePosition.y ); } } updateVillagers(); window->clear( sf::Color( 48.0f, 128.0f, 48.0f ) ); renderVillagers( window ); window->display(); } return 0; }
|
|
tBane Temat założony przez niniejszego użytkownika |
» 2024-02-09 19:44:55 Postanowiłem zrobić inaczej. Zrezygnowałem z pojedynczego zaznaczenia na rzecz obszarowego, gdyż zaznaczenie pojedyncze to zaznaczenie obszarowe 1x1. (Jeśli się mylę naprostujcie mnie). Prawie działa, nie rozumiem tylko dlaczego obszar jest nieporawnie generowany :-/ main.cpp#include <iostream> #include <vector>
#include <SFML/Graphics.hpp> using namespace std;
#include "villager.hpp"
sf::RenderWindow * window;
std::vector < Villager * > villagers; std::vector < Villager * > selectedVillagers;
bool cursor_press; float cursor_start_x, cursor_start_y; float cursor_end_x, cursor_end_y; sf::RectangleShape * dragArea;
void deselectVillagers() { for( auto & sv: selectedVillagers ) { sv->isSelected = false; } selectedVillagers.clear(); }
void selectVillagers( float x, float y ) { selectedVillagers.clear(); for( auto & v: villagers ) { if( v->collisionWithPoint( x, y ) ) if( v->isSelected ) { v->isSelected = false; } else { v->isSelected = true; } if( v->isSelected ) selectedVillagers.push_back( v ); } cout << "click [" << x << ", " << y << "]\n"; }
void selectVillagers( float x, float y, float width, float height ) { for( auto & v: villagers ) { if( v->collisionWithRectangle( x, y, width, height ) ) v->isSelected = true; if( v->isSelected ) selectedVillagers.push_back( v ); } }
void setTargetForVillagers( float x, float y ) { for( auto & sv: selectedVillagers ) { sv->goToTarget = true; sv->target_x = x; sv->target_y = y; } }
void updateVillagers() { for( auto & v: villagers ) v->update(); }
void renderVillagers( sf::RenderWindow * window ) { for( auto & v: villagers ) v->render( window ); }
int main() { window = new sf::RenderWindow( sf::VideoMode( 720, 480 ), "village" ); window->setFramerateLimit( 60 ); villagers.clear(); villagers.push_back( new Villager( "Odyn", 100, 100, 16 ) ); villagers.push_back( new Villager( "Uruk", 200, 100, 16 ) ); villagers.push_back( new Villager( "Har", 200, 300, 16 ) ); villagers.push_back( new Villager( "Zahn", 150, 250, 16 ) ); selectedVillagers.clear(); cursor_press = false; cursor_end_x = cursor_start_x = sf::Mouse::getPosition( * window ).x; cursor_end_y = cursor_start_y = sf::Mouse::getPosition( * window ).y; dragArea = new sf::RectangleShape(); dragArea->setFillColor( sf::Color( 48.0f, 48.0f, 128.0f, 128.0f ) ); while( window->isOpen() ) { sf::Event ev; while( window->pollEvent( ev ) ) { if( ev.type == sf::Event::Closed ) window->close(); if( sf::Mouse::isButtonPressed( sf::Mouse::Left ) ) { if( cursor_press == false ) { cout << "click"; cursor_end_x = cursor_start_x = sf::Mouse::getPosition( * window ).x; cursor_end_y = cursor_start_y = sf::Mouse::getPosition( * window ).y; cursor_press = true; deselectVillagers(); selectVillagers( cursor_start_x, cursor_start_y ); } else { cout << "press"; cursor_end_x = sf::Mouse::getPosition( * window ).x; cursor_end_y = sf::Mouse::getPosition( * window ).y; float x =( cursor_end_x + cursor_start_x ) / 2.0f; float y =( cursor_end_y + cursor_start_y ) / 2.0f; float w = cursor_end_x - cursor_start_x; float h = cursor_end_y - cursor_start_y; deselectVillagers(); selectVillagers( x, y, w, h ); } } if( cursor_press == true && !sf::Mouse::isButtonPressed( sf::Mouse::Left ) ) { cursor_end_x = cursor_start_x = sf::Mouse::getPosition( * window ).x; cursor_end_y = cursor_start_y = sf::Mouse::getPosition( * window ).y; cursor_press = false; } if( sf::Mouse::isButtonPressed( sf::Mouse::Right ) ) { setTargetForVillagers( sf::Mouse::getPosition( * window ).x, sf::Mouse::getPosition( * window ).y ); } } updateVillagers(); dragArea->setPosition( cursor_start_x, cursor_start_y ); dragArea->setSize( sf::Vector2f( cursor_end_x - cursor_start_x, cursor_end_y - cursor_start_y ) ); window->clear( sf::Color( 48.0f, 128.0f, 48.0f ) ); renderVillagers( window ); window->draw( * dragArea ); window->display(); } return 0; }
Villager.hpp#ifndef Villager_hpp #define Villager_hpp
#include <iostream> #include <SFML/Graphics.hpp> using namespace std;
class Villager { public: string name; float x, y, radius; sf::CircleShape * shape; bool isSelected; float speed; bool goToTarget; float target_x, target_y; sf::CircleShape * collisioner; float xx, yy; Villager( string, float, float, float ); ~Villager(); bool collisionWithPoint( float, float ); bool collisionWithRectangle( float, float, float, float ); void update(); void render( sf::RenderWindow * ); };
#endif
Villager.cpp#include "Villager.hpp"
Villager::Villager( string name, float x, float y, float radius ) { this->name = name; this->x = x; this->y = y; this->radius = radius; shape = new sf::CircleShape( radius ); shape->setOrigin( radius, radius ); shape->setPosition( x, y ); shape->setFillColor( sf::Color( 128.0f, 128.0f, 128.0f ) ); shape->setOutlineThickness( 4.0f ); shape->setOutlineColor( sf::Color( 16.0f, 16.0f, 16.0f ) ); speed = 1.0f; collisioner = new sf::CircleShape( 4.0f ); collisioner->setOrigin( 4.0f, 4.0f ); isSelected = false; goToTarget = false; target_x = target_y = 0; }
Villager::~Villager() { }
bool Villager::collisionWithPoint( float px, float py ) { float radians = atan2( py - y, px - x ); xx = x + radius * cos( radians ); yy = y + radius * sin( radians ); if( pow( px - x, 2 ) + pow( py - y, 2 ) < radius * radius ) return true; else return false; }
bool Villager::collisionWithRectangle( float rx, float ry, float rwidth, float rheight ) { float radians = atan2( ry - y, rx - x ); xx = x + radius * cos( radians ); yy = y + radius * sin( radians ); if( xx > rx - rwidth / 2.0f && xx < rx + rwidth / 2.0f && yy > ry - rheight / 2.0f && yy < ry + rheight / 2.0f ) return true; else return false; }
void Villager::update() { if( goToTarget == true ) { if( target_x == x && target_y == y ) { goToTarget = false; } else if( pow( target_x - x, 2 ) + pow( target_y - y, 2 ) < speed * speed ) { x = target_x; y = target_y; } else { float radians = atan2( target_y - y, target_x - x ); x += speed * cos( radians ); y += speed * sin( radians ); } } shape->setPosition( x, y ); collisioner->setPosition( xx, yy ); if( isSelected == true ) shape->setFillColor( sf::Color( 128.0f, 48.0f, 48.0f ) ); else shape->setFillColor( sf::Color( 128.0f, 128.0f, 128.0f ) ); }
void Villager::render( sf::RenderWindow * window ) { window->draw( * shape ); window->draw( * collisioner ); }
|
|
pekfos |
» 2024-02-09 20:32:08 |
|
tBane Temat założony przez niniejszego użytkownika |
» 2024-02-09 20:34:26 Potrzebuje w grze zaimplementować system sterowania jednostkami. Taki jak w typowej grze RTS.
Prawie działa, nie rozumiem tylko dlaczego obszar jest niepoprawnie generowany :-/ Gdy zaznaczamy obszar z prawego dolnego punktu w lewo do góryy to obszar zaznaczenia się "minimalizuje" |
|
pekfos |
» 2024-02-10 13:40:32 W sensie ma ujemny rozmiar? Jak chcesz mieć lewy górny róg jako start, powinieneś brać mniejsze współrzędne jako początek. |
|
tBane Temat założony przez niniejszego użytkownika |
» 2024-02-10 13:55:03 udało mi się rozwiązać problem. Dodałem dodatkowe zmienne do przechowywania pozycji. Nadal nie rozumiem gdzie miałem błąd ale teraz przynajmniej działa. Wrzucam kod może kiedyś się to komuś przyda. sterowanieLeft Click - Zaznacz nową jednostkę LShift + Left Click - Dodaj/Usuń jednostkę z wybranych Right Click - Wyznacz cel jednostkom Zaznacz Obszar - Wybierz jednostki main.cpp#include <iostream> #include <vector>
#include <SFML/Graphics.hpp> using namespace std;
#include "villager.hpp"
sf::RenderWindow * window;
std::vector < Tree * > trees; std::vector < Villager * > villagers; std::vector < Villager * > selectedVillagers;
bool cursor_press; float cursor_start_x, cursor_start_y, cursor_end_x, cursor_end_y; float select_x1, select_x2, select_y1, select_y2; sf::RectangleShape * dragArea;
void deselectVillagers() { for( auto & sv: selectedVillagers ) { sv->isSelected = false; } selectedVillagers.clear(); }
void selectVillagers( float x, float y ) { selectedVillagers.clear(); for( auto & v: villagers ) { if( v->collisionWithPoint( x, y ) ) if( v->isSelected ) { v->isSelected = false; } else { v->isSelected = true; } if( v->isSelected ) selectedVillagers.push_back( v ); } }
void selectVillagers( float x, float y, float width, float height ) { for( auto & v: villagers ) { if( v->collisionWithRectangle( x, y, width, height ) ) v->isSelected = true; if( v->isSelected ) selectedVillagers.push_back( v ); } }
void setTargetForVillagers( float x, float y ) { for( auto & sv: selectedVillagers ) { sv->goToTarget = true; sv->target_x = x; sv->target_y = y; } }
void updateVillagers() { for( auto & v1: villagers ) for( auto & v2 : villagers ) { float d = sqrt( pow( v1->x - v2->x, 2.0f ) + pow( v1->y - v2->y, 2.0f ) ); if( d < v1->radius + v2->radius && d > 0.0f ) { v1->x +=( v1->x - v2->x ) *( v1->radius + v2->radius - d ) /( d * 2 ); v1->y +=( v1->y - v2->y ) *( v1->radius + v2->radius - d ) /( d * 2 ); v2->x -=( v1->x - v2->x ) *( v1->radius + v2->radius - d ) /( d * 2 ); v2->y -=( v1->y - v2->y ) *( v1->radius + v2->radius - d ) /( d * 2 ); } } for( auto & v: villagers ) v->update(); }
void renderVillagers( sf::RenderWindow * window ) { for( auto & v: villagers ) v->render( window ); }
void renderTrees( sf::RenderWindow * window ) { for( auto & t: trees ) t->render( window ); }
int main() { window = new sf::RenderWindow( sf::VideoMode( 720, 480 ), "village" ); window->setFramerateLimit( 60 ); trees.clear(); villagers.clear(); selectedVillagers.clear(); villagers.push_back( new Villager( "Odyn", 100, 100, 16 ) ); villagers.push_back( new Villager( "Uruk", 200, 100, 16 ) ); villagers.push_back( new Villager( "Har", 200, 300, 16 ) ); villagers.push_back( new Villager( "Zahn", 150, 250, 16 ) ); cursor_press = false; cursor_end_x = cursor_start_x = sf::Mouse::getPosition( * window ).x; cursor_end_y = cursor_start_y = sf::Mouse::getPosition( * window ).y; select_x2 = select_x1 = cursor_end_x; select_y2 = select_y1 = cursor_end_y; dragArea = new sf::RectangleShape(); dragArea->setFillColor( sf::Color( 48.0f, 48.0f, 128.0f, 128.0f ) ); while( window->isOpen() ) { sf::Event ev; while( window->pollEvent( ev ) ) { cursor_press = false; if( ev.type == sf::Event::Closed ) window->close(); if( ev.type == sf::Event::MouseButtonPressed && sf::Mouse::isButtonPressed( sf::Mouse::Left ) && sf::Keyboard::isKeyPressed( sf::Keyboard::LShift ) ) { cursor_end_x = cursor_start_x = sf::Mouse::getPosition( * window ).x; cursor_end_y = cursor_start_y = sf::Mouse::getPosition( * window ).y; selectVillagers( cursor_end_x, cursor_end_y ); } else if( ev.type == sf::Event::MouseButtonPressed && sf::Mouse::isButtonPressed( sf::Mouse::Left ) ) { cursor_end_x = cursor_start_x = sf::Mouse::getPosition( * window ).x; cursor_end_y = cursor_start_y = sf::Mouse::getPosition( * window ).y; deselectVillagers(); selectVillagers( cursor_end_x, cursor_end_y ); } else if( ev.type == sf::Event::MouseButtonPressed && sf::Mouse::isButtonPressed( sf::Mouse::Right ) ) { setTargetForVillagers( sf::Mouse::getPosition( * window ).x, sf::Mouse::getPosition( * window ).y ); } else if( ev.type == sf::Event::MouseMoved && sf::Mouse::isButtonPressed( sf::Mouse::Left ) ) { cursor_press = true; cursor_end_x = sf::Mouse::getPosition( * window ).x; cursor_end_y = sf::Mouse::getPosition( * window ).y; select_x1 = cursor_start_x; select_x2 = cursor_end_x; select_y1 = cursor_start_y; select_y2 = cursor_end_y; if( cursor_start_x > cursor_end_x ) swap( select_x1, select_x2 ); if( cursor_start_y > cursor_end_y ) swap( select_y1, select_y2 ); float x =( select_x1 + select_x2 ) / 2.0f; float y =( select_y1 + select_y2 ) / 2.0f; float w = select_x2 - select_x1; float h = select_y2 - select_y1; deselectVillagers(); selectVillagers( cursor_end_x, cursor_end_y ); selectVillagers( x, y, w, h ); } dragArea->setPosition( select_x1, select_y1 ); dragArea->setSize( sf::Vector2f( select_x2 - select_x1, select_y2 - select_y1 ) ); } updateVillagers(); window->clear( sf::Color( 48.0f, 128.0f, 48.0f ) ); renderVillagers( window ); renderTrees( window ); if( cursor_press ) window->draw( * dragArea ); window->display(); } return 0; }
Villager.hpp#ifndef Villager_hpp #define Villager_hpp
#include <iostream> #include <SFML/Graphics.hpp> using namespace std;
class Villager { public: string name; float x, y, radius; float angle; float speed; bool isSelected; sf::CircleShape * shape; bool goToTarget; float target_x, target_y; Villager( string, float, float, float ); ~Villager(); bool collisionWithPoint( float, float ); bool collisionWithRectangle( float, float, float, float ); void update(); void render( sf::RenderWindow * ); };
#endif
Villager.cpp#include "Villager.hpp" #define PI 3.14159265358979323846
Villager::Villager( string name, float x, float y, float radius ) { this->name = name; this->x = x; this->y = y; this->radius = radius; this->angle = 0.0f; this->speed = 1.0f; isSelected = false; shape = new sf::CircleShape( radius ); shape->setOrigin( radius, radius ); shape->setPosition( x, y ); shape->setFillColor( sf::Color( 128.0f, 128.0f, 128.0f ) ); shape->setOutlineThickness( 4.0f ); shape->setOutlineColor( sf::Color( 16.0f, 16.0f, 16.0f ) ); goToTarget = false; target_x = target_y = 0; }
Villager::~Villager() { }
bool Villager::collisionWithPoint( float px, float py ) { float radians = atan2( py - y, px - x ); float xx = x + radius * cos( radians ); float yy = y + radius * sin( radians ); if( pow( px - x, 2 ) + pow( py - y, 2 ) < radius * radius ) return true; else return false; }
bool Villager::collisionWithRectangle( float rx, float ry, float rwidth, float rheight ) { float radians = atan2( ry - y, rx - x ); float xx = x + radius * cos( radians ); float yy = y + radius * sin( radians ); if( xx > rx - rwidth / 2.0f && xx < rx + rwidth / 2.0f && yy > ry - rheight / 2.0f && yy < ry + rheight / 2.0f ) return true; else return false; }
void Villager::update() { if( goToTarget == true ) { if( target_x == x && target_y == y ) { goToTarget = false; } else if( pow( target_x - x, 2 ) + pow( target_y - y, 2 ) < speed * speed ) { float radians = atan2( target_y - y, target_x - x ); x = target_x; y = target_y; angle = radians * 180.0f / PI; } else { float radians = atan2( target_y - y, target_x - x ); x += speed * cos( radians ); y += speed * sin( radians ); angle = radians * 180.0f / PI; } } shape->setPosition( x, y ); if( isSelected == true ) shape->setFillColor( sf::Color( 128.0f, 48.0f, 48.0f ) ); else shape->setFillColor( sf::Color( 128.0f, 128.0f, 128.0f ) ); }
void Villager::render( sf::RenderWindow * window ) { window->draw( * shape ); }
|
|
tBane Temat założony przez niniejszego użytkownika |
» 2024-02-12 14:23:02 logika trochę kuleje, ale program się kompiluje. |
|
« 1 » |