Решил посмотреть на самые простые способы отображения графических примитивов в Windows и нашел библиотеку memake. В использовании достаточно простая и удобная, но зависит от библиотеки SDL. В примере для Visual Studio (я использую VS 2019 и всем советую использовать эту или новее) сразу идут собранные бинари SDL, так что все работает "из коробки", но настроено там все только для дебажной x86 версии, так что я пытался настроить для остальных (Release x86, Debug x64, Release x64), но не преуспел (слишком много всяких параметров менять руками) и решил сделать все через cmake, попутно разбираясь, а что же там не работает. Получил вот такой CMakeLists.txt:
- #
- cmake_minimum_required (VERSION 3.8)
- project ("MemakePrj")
- # Add source to this project's executable.
- add_executable (MemakePrj "main.cpp" "Memake/Memake.cpp" "Memake/Vector2d.cpp")
- # SDL2 headers
- target_include_directories(MemakePrj PRIVATE "SDL2-2.0.14/include")
- # add SDL_MAIN_HANDLED definition to avoid
- # "LNK2019 unresolved external symbol SDL_main referenced in function main_getcmdline"
- add_definitions( -DSDL_MAIN_HANDLED )
- # SDL library folder
- set(SDL2_lib_folder "${PROJECT_SOURCE_DIR}/SDL2-2.0.14/lib")
- message(${CMAKE_BUILD_TYPE})
- # check 32 or 64 bits
- if(CMAKE_SIZEOF_VOID_P EQUAL 8)
- # 64 bits
- set(SDL2_lib_folder "${SDL2_lib_folder}/x64")
- elseif(CMAKE_SIZEOF_VOID_P EQUAL 4)
- # 32 bits
- set(SDL2_lib_folder "${SDL2_lib_folder}/x86")
- endif()
- # link SDL2 static lib
- target_link_libraries(MemakePrj ${SDL2_lib_folder}/SDL2.lib)
- target_link_libraries(MemakePrj ${SDL2_lib_folder}/SDL2main.lib)
- # copy dynamic lib to folder with executable file
- file(COPY ${SDL2_lib_folder}/SDL2.dll DESTINATION ${PROJECT_BINARY_DIR})
То ли дело посмотреть как работает "коллижн менеджер" в оригинальном примере - а он работает очень просто и можно даже сказать примитивно, но справляется со своей задачей (демонстрация работы библиотеки):
- void checkCollision(Ball& b)
- {
- float distX = x - b.x;
- float distY = y - b.y;
- float distance = sqrt((distX * distX) + (distY * distY));
- if (distance < r + b.r)
- {
- dx *= -1;
- dy *= -1;
- }
- }
Если расстояниеот одного до другого шарика меньше, чем сумма радиусов обоих, то шарик отлетает в противоположную сторону (направления движения по обоим осям умножаются на -1). Простенько и со вкусом. В результате все шарики летают под углом, кратным 45 градусов:
Я решил заморочиться и все же учесть правило "угол падения равен углу отражения", для чего даже написал "библиотеку" операций для двумерного пространства. В результате вот такой получился код:
- void checkCollision(Ball& b)
- {
- float dist = pos.distanceTo(b.pos);
- if (dist < r + b.r)
- {
- // direction to other ball
- Point2f toB = b.pos - pos;
- // calculate dot product
- float dotProd = f.dotProduct(toB);
- // if dot product is negative then force directed away from B ball
- // and we do nothing
- if (dotProd > 0)
- {
- // angle between normal and force (moving) vectors
- float angle = f.angleTo(toB);
- // the angle of incidence is equal to the angle of reflection
- f = Mat2x2f().rot(angle * 2) * f;
- f = f * (-1.f);
- }
- }
- }
Вот тут вертикальная ось - это как раз вектор toB на центр другого шарика, а горизонтальная линия - это касательная к точке, где произошел контакт. Получилось вот так:
Весь код здесь.
Комментариев нет:
Отправить комментарий