diff --git a/demos/demo3-foodthrowing/src/bullet.cpp b/demos/demo3-foodthrowing/src/bullet.cpp index a3415aa..efbc15a 100644 --- a/demos/demo3-foodthrowing/src/bullet.cpp +++ b/demos/demo3-foodthrowing/src/bullet.cpp @@ -4,44 +4,23 @@ #include #include +#include +#include #include "bullet.h" -#define FIXED_POINT_BASE 1000 -#define SPEED_DELTA 1 void Bullet::setDestination(VECTOR destination) { auto currentPos = sprite->getPos(); this->dest = destination; - diff.x = (destination.x - currentPos.x); - diff.y = (destination.y - currentPos.y); - directionToCover.x = diff.x * FIXED_POINT_BASE; - directionToCover.y = diff.y * FIXED_POINT_BASE; - - TextStream::instance().setText(std::string("covering: ") + std::to_string(directionToCover.x) + std::string(",") + std::to_string(directionToCover.y), 15, 1); + this->coords = Math::bresenhamLineBetween(currentPos, destination); } void Bullet::tick() { - auto x = sprite->getX(), y = sprite->getY(); - - if(directionToCover.x != 0) { - if(directionToCover.x > 0) { - directionToCover.x -= FIXED_POINT_BASE; - x += SPEED_DELTA; - } else { - directionToCover.x += FIXED_POINT_BASE; - x -= SPEED_DELTA; - } - } - if(directionToCover.y != 0) { - if(directionToCover.y > 0) { - directionToCover.y -= FIXED_POINT_BASE; - y += SPEED_DELTA; - } else { - directionToCover.y += FIXED_POINT_BASE; - y -= SPEED_DELTA; - } + if(coords.empty()) { + return; } - sprite->moveTo(x, y); + sprite->moveTo(coords.front()); + coords.pop_front(); } diff --git a/demos/demo3-foodthrowing/src/bullet.h b/demos/demo3-foodthrowing/src/bullet.h index eeadaed..e9b3f17 100644 --- a/demos/demo3-foodthrowing/src/bullet.h +++ b/demos/demo3-foodthrowing/src/bullet.h @@ -8,13 +8,13 @@ #include #include +#include class Bullet { private: std::unique_ptr sprite; + std::deque coords; VECTOR dest; - VECTOR diff; - VECTOR directionToCover; public: Bullet(std::unique_ptr sprite) : sprite(std::move(sprite)), dest(VECTOR()) {} diff --git a/demos/demo3-foodthrowing/src/food_scene.cpp b/demos/demo3-foodthrowing/src/food_scene.cpp index ccbb86b..f37e8dd 100644 --- a/demos/demo3-foodthrowing/src/food_scene.cpp +++ b/demos/demo3-foodthrowing/src/food_scene.cpp @@ -128,5 +128,5 @@ void FoodScene::load() { bulletCooldown = BULLET_COOLDOWN_START; // rotation of a point on a circle within the resolution means our radius should be big enough - defaultBulletTarget = { GBA_SCREEN_WIDTH / 2, GBA_SCREEN_HEIGHT + (GBA_SCREEN_WIDTH / 2) - avatar->getCenter().y}; + defaultBulletTarget = { GBA_SCREEN_WIDTH / 2, GBA_SCREEN_HEIGHT + (GBA_SCREEN_WIDTH / 2) - avatar->getCenter().y + 40}; } \ No newline at end of file diff --git a/engine/CMakeLists.txt b/engine/CMakeLists.txt index b1b1061..597e713 100644 --- a/engine/CMakeLists.txt +++ b/engine/CMakeLists.txt @@ -18,7 +18,7 @@ add_library(${PROJECT_NAME} src/background/text_stream.cpp src/background/background.cpp src/effects/fade_out_scene.cpp - src/sound_control.cpp src/scene.cpp src/timer.cpp) + src/sound_control.cpp src/scene.cpp src/timer.cpp include/libgba-sprite-engine/math.h src/math.cpp) target_include_directories(${PROJECT_NAME} PUBLIC $ diff --git a/engine/include/libgba-sprite-engine/math.h b/engine/include/libgba-sprite-engine/math.h new file mode 100644 index 0000000..288f316 --- /dev/null +++ b/engine/include/libgba-sprite-engine/math.h @@ -0,0 +1,16 @@ +// +// Created by Wouter Groeneveld on 14/12/18. +// + +#ifndef GBA_SPRITE_ENGINE_PROJECT_MATH_H +#define GBA_SPRITE_ENGINE_PROJECT_MATH_H + +#include +#include + +class Math { +public: + static std::deque bresenhamLineBetween(VECTOR src, VECTOR dest); +}; + +#endif //GBA_SPRITE_ENGINE_PROJECT_MATH_H diff --git a/engine/src/math.cpp b/engine/src/math.cpp new file mode 100644 index 0000000..16c99e1 --- /dev/null +++ b/engine/src/math.cpp @@ -0,0 +1,71 @@ +// +// Created by Wouter Groeneveld on 14/12/18. +// + +#include + +std::deque Math::bresenhamLineBetween(VECTOR src, VECTOR dest) { + // https://www.coranac.com/tonc/text/bitmaps.htm - Bresenham's line algorithm with fixed points + VECTOR step, delta; + + std::deque coords; + + if(src.x > dest.x) { + step.x = -1; + delta.x = (src.x - dest.x); + } else { + step.x = +1; + delta.x = (dest.x - src.x); + } + if(src.y > dest.y) { + step.y = -1; + delta.y = (src.y - dest.y); + } else { + step.y = +1; + delta.y = (dest.y - src.y); + } + + int dd, x = src.x, y = src.y, ii; + + if(delta.y == 0) { + // horizontal + for(ii = 0; ii <= delta.x; ii++) { + coords.push_back({x, y}); + x += step.x; + } + } else if(delta.x == 0) { + // vertical + for(ii = 0; ii <= delta.y; ii++) { + coords.push_back({x, y}); + y += step.y; + } + } else if(delta.x >= delta.y) { + // Diagonal, slope <= 1 + dd = 2 * delta.y - delta.x; + + for(ii = 0; ii <= delta.x; ii++) { + coords.push_back({x, y}); + if(dd >= 0) { + dd -= 2 * delta.x; + y += step.y; + } + dd += 2 * delta.y; + x += step.x; + } + } else { + // Diagonal, slope > 1 + dd = 2 * delta.x - delta.y; + + for(ii = 0; ii <= delta.y; ii++) { + coords.push_back({x, y}); + if(dd >= 0) { + dd -= 2 * delta.y; + x += step.x; + } + dd += 2 * delta.x; + y += step.y; + } + } + + return coords; +} \ No newline at end of file diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 3251a35..037109b 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -35,6 +35,7 @@ add_executable(unittest ../engine/src/allocator.cpp ../engine/src/palette/combined_palette.cpp ../engine/src/timer.cpp - timertest.cpp) + ../engine/src/math.cpp + timertest.cpp mathtest.cpp) target_link_libraries(unittest ${GTEST_LIBRARY}/build/libgtest.a ${GTEST_LIBRARY}/build/libgtest_main.a) diff --git a/test/allocatortest.cpp b/test/allocatortest.cpp index c492bcf..9d842f4 100644 --- a/test/allocatortest.cpp +++ b/test/allocatortest.cpp @@ -69,7 +69,7 @@ TEST_F(AllocatorSuite, Allocate_Sprite_Pointers_Reservers_Some_Tile_Space) { auto curr2 = Allocator::getCurrentSpriteIndex(); auto diff2 = curr2 - curr; - cout << "prev: " << prev << " - curr: " << curr << " (diff: " << diff << ")" << " and " << curr2 << endl; + cout << "prev: " << prev << " - curr: " << curr << " (delta: " << diff << ")" << " and " << curr2 << endl; ASSERT_EQ(prev, allocated.currentAddress); ASSERT_EQ(curr, allocated2.currentAddress); diff --git a/test/mathtest.cpp b/test/mathtest.cpp new file mode 100644 index 0000000..bf399dc --- /dev/null +++ b/test/mathtest.cpp @@ -0,0 +1,120 @@ +// +// Created by Wouter Groeneveld on 14/12/18. +// + + + +#include +#include + +class MathSuite : public ::testing::Test { +protected: + + virtual void TearDown() { + } + + virtual void SetUp() { + } +}; + +TEST_F(MathSuite, LineBetween_Diagonal_ToTopRightCorner) { + auto points = Math::bresenhamLineBetween({120, 80}, {240, 0}); + ASSERT_EQ(121, points.size()); + VECTOR pt; + + // some sampling + pt = points.at(1); + ASSERT_EQ(121, pt.x); + ASSERT_EQ(79, pt.y); + pt = points.at(2); + ASSERT_EQ(122, pt.x); + ASSERT_EQ(79, pt.y); + pt = points.at(10); + ASSERT_EQ(130, pt.x); + ASSERT_EQ(73, pt.y); + pt = points.at(100); + ASSERT_EQ(220, pt.x); + ASSERT_EQ(13, pt.y); +} + +TEST_F(MathSuite, LineBetween_Diagonal_ToTopLeftCorner) { + auto points = Math::bresenhamLineBetween({120, 80}, {0, 0}); + ASSERT_EQ(121, points.size()); + VECTOR pt; + + // some sampling + pt = points.at(1); + ASSERT_EQ(119, pt.x); + ASSERT_EQ(79, pt.y); + pt = points.at(2); + ASSERT_EQ(118, pt.x); + ASSERT_EQ(79, pt.y); + pt = points.at(10); + ASSERT_EQ(110, pt.x); + ASSERT_EQ(73, pt.y); + pt = points.at(100); + ASSERT_EQ(20, pt.x); + ASSERT_EQ(13, pt.y); +} + +TEST_F(MathSuite, LineBetween_Diagonal_ToBottomLeftCorner) { + auto points = Math::bresenhamLineBetween({120, 80}, {0, 160}); + ASSERT_EQ(121, points.size()); + VECTOR pt; + + // some sampling + pt = points.at(1); + ASSERT_EQ(119, pt.x); + ASSERT_EQ(81, pt.y); + pt = points.at(2); + ASSERT_EQ(118, pt.x); + ASSERT_EQ(81, pt.y); + pt = points.at(10); + ASSERT_EQ(110, pt.x); + ASSERT_EQ(87, pt.y); + pt = points.at(100); + ASSERT_EQ(20, pt.x); + ASSERT_EQ(147, pt.y); +} + +TEST_F(MathSuite, LineBetween_Diagonal_ToBottomRightCorner) { + auto points = Math::bresenhamLineBetween({120, 80}, {240, 160}); + ASSERT_EQ(121, points.size()); + VECTOR pt; + + // some sampling + pt = points.at(1); + ASSERT_EQ(121, pt.x); + ASSERT_EQ(81, pt.y); + pt = points.at(2); + ASSERT_EQ(122, pt.x); + ASSERT_EQ(81, pt.y); + pt = points.at(10); + ASSERT_EQ(130, pt.x); + ASSERT_EQ(87, pt.y); + pt = points.at(100); + ASSERT_EQ(220, pt.x); + ASSERT_EQ(147, pt.y); +} + +TEST_F(MathSuite, LineBetween_Horizontal_FromCenterToHalfYZeroX) { + auto points = Math::bresenhamLineBetween({120, 80}, {0, 80}); + ASSERT_EQ(121, points.size()); + for(int i = 0; i <= 120; i++) { + auto &vec = points.front(); + ASSERT_EQ(80, vec.y); + ASSERT_EQ(120 - i, vec.x); + points.pop_front(); + } +} + +TEST_F(MathSuite, LineBetween_Vertical_FromCenterToHalfXFullY) { + auto points = Math::bresenhamLineBetween({120, 80}, {120, 160}); + ASSERT_EQ(81, points.size()); + for(int i = 0; i <= (160 - 80); i++) { + auto &vec = points.front(); + ASSERT_EQ(120, vec.x); + ASSERT_EQ(80 + i, vec.y); + points.pop_front(); + } +}