yaze 0.3.2
Link to the Past ROM Editor
 
Loading...
Searching...
No Matches
sprite_position_test.cc
Go to the documentation of this file.
1#include <gtest/gtest.h>
2#include <memory>
3#include <iostream>
4#include <iomanip>
5#include <fstream>
6
7#include "app/rom.h"
10
11namespace yaze {
12namespace zelda3 {
13
14class SpritePositionTest : public ::testing::Test {
15protected:
16 void SetUp() override {
17 // Try to load a vanilla ROM for testing
18 rom_ = std::make_unique<Rom>();
19 std::string rom_path = "bin/zelda3.sfc";
20
21 // Check if ROM exists in build directory
22 std::ifstream rom_file(rom_path);
23 if (rom_file.good()) {
24 ASSERT_TRUE(rom_->LoadFromFile(rom_path).ok()) << "Failed to load ROM from " << rom_path;
25 } else {
26 // Skip test if ROM not found
27 GTEST_SKIP() << "ROM file not found at " << rom_path;
28 }
29
30 overworld_ = std::make_unique<Overworld>(rom_.get());
31 ASSERT_TRUE(overworld_->Load(rom_.get()).ok()) << "Failed to load overworld";
32 }
33
34 void TearDown() override {
35 overworld_.reset();
36 rom_.reset();
37 }
38
39 std::unique_ptr<Rom> rom_;
40 std::unique_ptr<Overworld> overworld_;
41};
42
43// Test sprite coordinate system understanding
44TEST_F(SpritePositionTest, SpriteCoordinateSystem) {
45 // Test sprites from different worlds
46 for (int game_state = 0; game_state < 3; game_state++) {
47 const auto& sprites = overworld_->sprites(game_state);
48 std::cout << "\n=== Game State " << game_state << " ===" << std::endl;
49 std::cout << "Total sprites: " << sprites.size() << std::endl;
50
51 int sprite_count = 0;
52 for (const auto& sprite : sprites) {
53 if (!sprite.deleted() && sprite_count < 10) { // Show first 10 sprites
54 std::cout << "Sprite " << std::hex << std::setw(2) << std::setfill('0')
55 << static_cast<int>(sprite.id()) << " (" << const_cast<Sprite&>(sprite).name() << ")" << std::endl;
56 std::cout << " Map ID: 0x" << std::hex << std::setw(2) << std::setfill('0')
57 << sprite.map_id() << std::endl;
58 std::cout << " X: " << std::dec << sprite.x() << " (0x" << std::hex << sprite.x() << ")" << std::endl;
59 std::cout << " Y: " << std::dec << sprite.y() << " (0x" << std::hex << sprite.y() << ")" << std::endl;
60 std::cout << " map_x: " << std::dec << sprite.map_x() << std::endl;
61 std::cout << " map_y: " << std::dec << sprite.map_y() << std::endl;
62
63 // Calculate expected world ranges
64 int world_start = game_state * 0x40;
65 int world_end = world_start + 0x40;
66 std::cout << " World range: 0x" << std::hex << world_start << " - 0x" << world_end << std::endl;
67
68 sprite_count++;
69 }
70 }
71 }
72}
73
74// Test sprite filtering logic
75TEST_F(SpritePositionTest, SpriteFilteringLogic) {
76 // Test the filtering logic used in DrawOverworldSprites
77 for (int current_world = 0; current_world < 3; current_world++) {
78 const auto& sprites = overworld_->sprites(current_world);
79
80 std::cout << "\n=== Testing World " << current_world << " Filtering ===" << std::endl;
81
82 int visible_sprites = 0;
83 int total_sprites = 0;
84
85 for (const auto& sprite : sprites) {
86 if (!sprite.deleted()) {
87 total_sprites++;
88
89 // This is the filtering logic from DrawOverworldSprites
90 bool should_show = (sprite.map_id() < 0x40 + (current_world * 0x40) &&
91 sprite.map_id() >= (current_world * 0x40));
92
93 if (should_show) {
94 visible_sprites++;
95 std::cout << " Visible: Sprite 0x" << std::hex << static_cast<int>(sprite.id())
96 << " on map 0x" << sprite.map_id() << " at ("
97 << std::dec << sprite.x() << ", " << sprite.y() << ")" << std::endl;
98 }
99 }
100 }
101
102 std::cout << "World " << current_world << ": " << visible_sprites << "/"
103 << total_sprites << " sprites visible" << std::endl;
104 }
105}
106
107// Test map coordinate calculations
108TEST_F(SpritePositionTest, MapCoordinateCalculations) {
109 // Test how map coordinates should be calculated
110 for (int current_world = 0; current_world < 3; current_world++) {
111 const auto& sprites = overworld_->sprites(current_world);
112
113 std::cout << "\n=== World " << current_world << " Coordinate Analysis ===" << std::endl;
114
115 for (const auto& sprite : sprites) {
116 if (!sprite.deleted() &&
117 sprite.map_id() < 0x40 + (current_world * 0x40) &&
118 sprite.map_id() >= (current_world * 0x40)) {
119
120 // Calculate map position
121 int sprite_map_id = sprite.map_id();
122 int local_map_index = sprite_map_id - (current_world * 0x40);
123 int map_col = local_map_index % 8;
124 int map_row = local_map_index / 8;
125
126 int map_canvas_x = map_col * 512; // kOverworldMapSize
127 int map_canvas_y = map_row * 512;
128
129 std::cout << "Sprite 0x" << std::hex << static_cast<int>(sprite.id())
130 << " on map 0x" << sprite_map_id << std::endl;
131 std::cout << " Local map index: " << std::dec << local_map_index << std::endl;
132 std::cout << " Map position: (" << map_col << ", " << map_row << ")" << std::endl;
133 std::cout << " Map canvas pos: (" << map_canvas_x << ", " << map_canvas_y << ")" << std::endl;
134 std::cout << " Sprite global pos: (" << sprite.x() << ", " << sprite.y() << ")" << std::endl;
135 std::cout << " Sprite local pos: (" << sprite.map_x() << ", " << sprite.map_y() << ")" << std::endl;
136
137 // Verify the calculation
138 int expected_global_x = map_canvas_x + sprite.map_x();
139 int expected_global_y = map_canvas_y + sprite.map_y();
140
141 std::cout << " Expected global: (" << expected_global_x << ", " << expected_global_y << ")" << std::endl;
142 std::cout << " Actual global: (" << sprite.x() << ", " << sprite.y() << ")" << std::endl;
143
144 if (expected_global_x == sprite.x() && expected_global_y == sprite.y()) {
145 std::cout << " ✓ Coordinates match!" << std::endl;
146 } else {
147 std::cout << " ✗ Coordinate mismatch!" << std::endl;
148 }
149
150 break; // Only test first sprite for brevity
151 }
152 }
153 }
154}
155
156} // namespace zelda3
157} // namespace yaze
std::unique_ptr< Overworld > overworld_
A class for managing sprites in the overworld and underworld.
Definition sprite.h:279
TEST_F(DungeonEditorSystemIntegrationTest, BasicInitialization)
Main namespace for the application.