Dlaczego open gl odwraca tile mapę i w jaki sposób naprawić kolizję?

0

Witam! próbuje zrobić grę 2D użwająć open gl. Jak na razie zrobiłem parę klas do mapy i gracza.

class Block
{
public:

	Block(const Rect& destRect, const Rect& uvRect, const GLuint& texture)
	{
		this->uvRect = uvRect;
		this->texture = texture;
		this->destRect = destRect;
	}
	~Block();

	void Update(float deltaTime);
	void Draw(Renderer& renderer)
	{
		renderer.Draw(destRect, uvRect, texture);
	}

	Vector2 getCenter() const
	{
		Vector2 result;
		result.x = destRect.x + destRect.w / 2;
		result.y = destRect.y + destRect.h / 2;
		return result;
	}

	float getPosX() const;
	float getPosY() const;
	float getWidth() const;
	float getHeight() const;
private:
	Rect uvRect = Rect(0.0f, 0.0f, 0.0f, 0.0f);
	Rect destRect = Rect(0.0f, 0.0f, 0.0f, 0.0f);

	GLuint texture = 0;
};
class TileMap
{
public:
	TileMap();
	~TileMap();

	void Initialize(const std::string& filePath)
	{
		LoadFromFile(filePath);
		loadTextures();

		for (int y = 0; y < map.size(); ++y) {
			for (int x = 0; x < map[y].size(); ++x) {
				destRect.w = 64.0f;
				destRect.h = 64.0f;
				destRect.x = destRect.w * (float)x;
				destRect.y = destRect.h * (float)y;

				switch(map[y][x]) {
					case 1: 
						block.emplace_back(destRect, uvRect, textureID("Wooden"));
						break;
				}
			}	
		}
	}

	void Draw(Renderer& renderer)
	{
		for (auto& b : block) {
			b.Draw(renderer);
		}
	}

	void Update(float deltaTime)
	{
		for (auto& b : block) {
			b.Update(deltaTime);
		}
	}

	std::vector<std::vector<int>> getMap();
private:
	void LoadFromFile(const std::string& filePath)
	{
		std::ifstream openFile(filePath);

		map.clear();

		int tileCode;
		std::string line;

		if (openFile.is_open()) {
			while (!openFile.eof()) {
				while (std::getline(openFile, line)) {

					std::stringstream str(line);

					std::vector<int> tempV;

					while (str >> tileCode) {
						tempV.push_back(tileCode);
					}

					map.push_back(tempV);
				}
			}
		}

		openFile.clear();
		openFile.close();
	}
	void loadTextures();

	TextureManager texture;

	Rect destRect = { 0.0f, 0.0f, 0.0f, 0.0f };
	Rect uvRect = { 0.0f, 0.0f, 1.0f, 1.0f };

	std::vector<Block> block;
	std::vector<std::vector<int>> map;

	std::map<std::string, GLuint> textureID;
};

Odnosząc się do pierwszego pytania w tytule, mapa musi wyglądać tak:

1 1 1 1 1 1 1 1 1 1
0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0

żeby uzyskać taki efekt

0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0
1 1 1 1 1 1 1 1 1 1

Dlaczego tak się dzieje?

Co do drugiego pytania, tzn. kolizji między mapą a graczem, to mam taki kod:

bool Player::collideWithLevel(const std::vector<std::vector<int>>& levelData)
{
	std::vector<Vector2> collideTilePositions;

	//sprawdzam każdy róg 
	checkTilePosition(levelData, collideTilePositions, position.x, position.y); // position.x  - pozycja gracza
	checkTilePosition(levelData, collideTilePositions, position.x + hitBox.x, position.y);
	checkTilePosition(levelData, collideTilePositions, position.x, position.y + hitBox.y);
	checkTilePosition(levelData, collideTilePositions, position.x + hitBox.x, position.y + hitBox.y);

	if (collideTilePositions.size() == 0) {
		return false;
	}
	for (int i = 0; i < collideTilePositions.size(); i++) {
		collideWithTile(collideTilePositions[i]);
	}
	return true;
}

void Player::checkTilePosition(const std::vector<std::vector<int>>& levelData, std::vector<Vector2>& collideTilePositions, float x, float y)
{
	float TILE_WIDTH = 64; // HEIGHT jest takie samo

	Vector2 gridPos = Vector2(x / TILE_WIDTH, y / TILE_WIDTH);

	if (gridPos.x < 0 || gridPos.x >= levelData[0].size() ||
	    gridPos.y < 0 || gridPos.y >= levelData.size()) {
		return;
	}

	if (levelData[gridPos.y][gridPos.x] != 0) {
		collideTilePositions.push_back(gridPos * TILE_WIDTH + Vector2(TILE_WIDTH / 2.0f, TILE_WIDTH / 2.0f));
	}
}

void Player::collideWithTile(Vector2 tilePos)
{
	float TILE_WIDTH = 64;
	const float TILE_RADIUS = TILE_WIDTH / 2.0f;

	const float MIN_DISTANCE_X = hitBox.x / 2 + TILE_RADIUS; // hitboxX i hitBoxY - wysokość i szerokość gracza
	const float MIN_DISTANCE_Y = hitBox.y / 2 + TILE_RADIUS;

	Vector2 distVec = getCenter() - tilePos; // getCenter - pobiera środek gracza

	float DepthX = MIN_DISTANCE_X - abs(distVec.x);
	float DepthY = MIN_DISTANCE_Y - abs(distVec.y);

	if (DepthX > 0 && DepthY > 0) {
		if (std::max(DepthX, 0.0f) < std::max(DepthY, 0.0f)) {
			if (distVec.x < 0) {
				position.x -= DepthX;
			} else {
				position.x += DepthX;
			}
		} else {
			if (distVec.y < 0) {
				position.y -= DepthY;
			} else {
				position.y += DepthY;
			}
		}
	}
}

void Player::Update(const std::vector<std::vector<int>>& map, flaot deltaTime)
{
	//... input etc.
	collideWithLevel(map)
}

I problem polega na tym, że gdy kolizja w ogóle nie czyta osi X, a dla osi Y w opaczny sposób, tzn. gdy dolna ścianka gracza uderza w górną ściankę bloku mapy zamiast wrócić do góry (tzn. na pozycję górnej ścianki bloku), teleportuje się do ścianki dolnej bloku.
Można by powiedzieć, że skoro tak się dzieje to kiedy jest sprawdzana kolizja na Y po prostu zmienić znaki.
Próbowałem, co się stało, to w momencie w którym dolna ścianka gracza uderza w górną bloku, to gracz odsuwa się o za duży dystans. Dodatkowo jest też błąd przy kolizji ścianka górna gracza - dolna bloku.

Wydaje mi się, że najlepiej pokaże to filmik:
Tutaj pierwszy przypadek:

Tutaj z odwróconym depthY tzn,

	} else {
			if (distVec.y < 0) {
				position.y += DepthY;
			} else {
				position.y -= DepthY;
			}
		}

Co robię w tym źle?

0

Nie wczytywałem się w temat, ale kiedyś robiłem program na zaliczenie w OpenGLu i miałem problem z przekształceniami. Poczytaj o układach współrzędnych:
https://www.khronos.org/opengl/wiki/Coordinate_Transformations
https://softwareengineering.stackexchange.com/questions/17519/why-does-directx-use-a-left-handed-coordinate-system

0

Dlaczego tak się dzieje?

Bo tak ktoś napisał w specyfikacji w 1992 i już tak zostało ;-)

OpenGL oczekuje, że tekstura podana do glTexImage2D itp. jest zapisana w pamięci wierszami w kolejności od dolnego do górnego.
Jeśli podajesz dane wejściowe w złym formacie (w wierszach od górnego do dolnego) dostajesz efekt odwrócenia.

Cytat z dokumentacji:

The first element corresponds to the lower left corner of the texture image. Subsequent elements progress left-to-right through the remaining texels in the lowest row of the texture image, and then in successively higher rows of the texture image. The final element corresponds to the upper right corner of the texture image.

https://www.khronos.org/registry/OpenGL-Refpages/gl4/html/glTexImage2D.xhtml

0

Rozumiem. A w jaki sposob powinienem poprawić tą kolizję?

1 użytkowników online, w tym zalogowanych: 0, gości: 1