Collision isn't precise

newww

as you can see, the player stops midair and not exactly on top of the tile. I approached this in two ways with SDL_HasIntersection() and also with lazy foo’s collision method but in both cases it stops about 100px above and to the side of the tile. How can I fix this ?

Here’s Game.cpp file:

#include "Game.h"

SDL_Window* gWindow = nullptr;
SDL_Renderer* gRenderer = nullptr;

SDL_Rect dest{};

// HORIZONTAL
float speedX = 2.0f;
float rt_runStr = 8.5f;
float lt_runStr = 8.5f;
float maxX = 15.5f;

// VERTICAL
float speedY = 0.0f;
float gravity = 2.2f;
float jumpStr = 12.2f;

// flags
int rightK = 0;
int leftK = 0;
int up = 0;
int collision = 1;

Entity* player = nullptr;

Tile* newT = nullptr;

//Entity* tile = nullptr;

void Game::init(const char* title ,int x, int y, int w, int h, int flags) {
	if (SDL_Init(SDL_INIT_EVERYTHING) == 0) {

		// create window
		gWindow = SDL_CreateWindow(title, x, y, w, h, flags);

		if (gWindow != NULL) {

			// create renderer
			gRenderer = SDL_CreateRenderer(gWindow, -1, 0);

			isRunning = true;
		}
		else {
			isRunning = false;
		}
	}
	else {
		isRunning = false;
	}
	player = new Entity;
	player->loadTexture("assets/doux_00.png");
	newT = new Tile;
	newT->loadImg("assets/grass_tile.png");
	//tile = new Entity;
}

void Game::handleEvent() {

	SDL_Event event;

	while (SDL_PollEvent(&event)) {

		switch (event.type) {

		case SDL_QUIT:
			isRunning = false;
			break;
		}
	}
}

void Game::update() {
	if (SDL_GetKeyboardState(0)[SDL_GetScancodeFromKey(SDLK_d)]) {
		rightK = 1;
	}
	else {
		rightK = 0;
	}

	if (SDL_GetKeyboardState(0)[SDL_GetScancodeFromKey(SDLK_a)]) {
		leftK = 1;
	}
	else {
		leftK = 0;
	}

	if (SDL_GetKeyboardState(0)[SDL_GetScancodeFromKey(SDLK_SPACE)]) {
		up = 1;
	}
	else {
		up = 0;
	}

	if (up == 1) {
		gravity = 0;
	}

	if (rightK == 1) {
		lt_runStr = 0.0f;
		rt_runStr += 0.6f;
	}

	if (leftK == 1) {
		rt_runStr = 0.0f;
		lt_runStr += 0.6f;
	}

	if (rt_runStr >= maxX) {
		rt_runStr = maxX;
		lt_runStr = 0.0f;
	}

	if (lt_runStr >= maxX) {
		lt_runStr = maxX;
		rt_runStr = 0.0f;
	}

	/*if (SDL_HasIntersection(player->getRect(), tile->getTile())) {
		collision = 0;
	}
	else {
		collision = 1;
	}

	if (collision == 0) {
		gravity = 0;
	}*/

	if (newT->isColliding(dest)) {
		collision = 0;
	}
	else {
		collision = 1;
	}

	if (collision == 0) {
		gravity = 0;
	}

	speedX += (rightK * rt_runStr) - (leftK * lt_runStr);
	gravity += 0.6f;
	speedY += (collision * gravity) - (up * jumpStr);
}

void Game::render() {
	SDL_RenderClear(gRenderer);
	// ------------------------------------------
	
	player->drawTexture(250, 200);
	newT->drawTile(250, 350);
	//tile->drawTile(250, 300, 150, 30);

	// ------------------------------------------
	SDL_SetRenderDrawColor(gRenderer, 67, 70, 75, 1);
	SDL_RenderPresent(gRenderer);
}

void Game::clean() {
	delete player;
	//delete tile;
	SDL_DestroyWindow(gWindow);
	SDL_DestroyRenderer(gRenderer);
	SDL_Quit();
}

Here’s Tile.cpp:

#include "Tile.h"

void Tile::loadImg(const char* path) {
	texture = IMG_LoadTexture(gRenderer, path);
}

void Tile::drawTile(int x, int y) {
	src.x = 0;
	src.y = 0;
	src.w = 32;
	src.h = 32;

	dest.x = x;
	dest.y = y;
	dest.w = src.w;
	dest.h = src.h;

	SDL_RenderCopy(gRenderer, texture, &src, &dest);
}

bool Tile::isColliding(SDL_Rect player) {
	int right, right2;
	int left, left2;
	int top, top2;
	int bottom, bottom2;

	right = dest.x + dest.w;
	left = dest.x;
	top = dest.y;
	bottom = dest.y + dest.h;

	right2 = player.x + player.w;
	left2 = player.x;
	top2 = player.y;
	bottom2 = player.y + player.h;

	if (bottom2 == top) {
		return true;
	}
	else {
		return false;
	}
}
  1. It’s unclear to me what this line does: speedY += (collision * gravity) - (up * jumpStr);

  2. The isColliding function in the Tile class looks a bit weird in the end of the function and it looks like it’s missing some checks.
    Compare your function with the checkCollision function in this tutorial:
    Lazy Foo' Productions - Collision Detection

  3. I can’t see that you’re setting the player’s position anywhere, except in the render function, where you’re hardcoding the player texture to be positioned at (250, 200).

You mean this chunk of code right?

I have tried to achieve collision with those if conditionals lazy foo has mentioned but that too doesn’t work.

it’s just an equation for vertical I came up with thru trial and error

I don’t quite understand what you mean…

I think you mean I’m not updating my player’s position to make it move, code for that’s in this Entity.cpp:

#include "Entity.h"

void Entity::loadTexture(const char* path){
	texture = IMG_LoadTexture(gRenderer, path);
}

void Entity::drawTexture(int x, int y) {
	src.x = 0;
	src.y = 0;
	src.w = 24;
	src.h = 24;

	dest.x = x;
	dest.x += speedX;

	dest.y = y;
	dest.y += speedY;

	dest.w = src.w * 3;
	dest.h = src.h * 3;

	SDL_RenderCopy(gRenderer, texture, &src, &dest);
}

I recommend you to check out this tutorial on tiling:

If you follow that tutorial, you should be able to get tile collision working and can then adapt the code to work with gravity, so that the player can fall down and land/stand on the tiles etc.

I did check it out but it doesn’t help me with my current problem. Before populating an entire tile map I want to test my mechanism against a single tile. This tutorial too uses checkCollision() func, like lazy foo’s previous collision tutorial, which didn’t help me fix my problem.