• Advertisement
Sign in to follow this  

[C++] Where to draw player relative to camera?

This topic is 3438 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

Hey. I have a Level_Camera class that stores information about a camera:
class Level_Camera
{
public:
	Level_Camera(const SDL_Rect& camera, const Point& offset);

	void Centre_On(const Point& on, const SDL_Rect& boundary);

	const SDL_Rect& Camera() const;
	const Point& Offset() const;
private:
	SDL_Rect camera; // in tiles.
	Point offset; // in pixels.
};


Level_Camera::Level_Camera(const SDL_Rect& camera, const Point& offset)
: camera(camera)
, offset(offset)
{
}

void Level_Camera::Centre_On(const Point& on, const SDL_Rect& boundary)
{
	// Centre the camera over point.
	camera.x = on.x - camera.w / 2;
	camera.y = on.y - camera.h / 2;
	// Clamp x, y values if out of bounds.
	camera.x = std::min<int>(boundary.w, std::max<int>(0, camera.x));
	camera.y = std::min<int>(boundary.h, std::max<int>(0, camera.y));
	// Account for the width and height of camera by subtracting difference.
	// (if went over edge of boundary adjust it to fit).
	int x_diff = camera.x + camera.w - boundary.w;
	int y_diff = camera.y + camera.h - boundary.h;
	camera.x -= x_diff > 0 ? x_diff : 0;
	camera.y -= y_diff > 0 ? y_diff : 0;
}

const SDL_Rect& Level_Camera::Camera() const
{
	return camera;
}

const Point& Level_Camera::Offset() const
{
	return offset;
}


I draw the Level according to the position of the camera:
void Level_View::Render_View(const Level& level, Renderer& renderer, const Level_Camera& camera)
{
	const std::vector<Tile>& background_tiles = level.Background_Tiles();
	const std::vector<Tile>& foreground_tiles = level.Foreground_Tiles();
	const std::vector<Object_Tile>& object_tiles = level.Object_Tiles();
	typedef unsigned int uint;

	uint ax = 0, ay = 0, index = 0;
	const SDL_Rect& cam = camera.Camera();
	// c = Camera (position of camera) , r = Render (position tile will be rendered on screen)
	// a = Adjusted (position tile will be rendered on screen after camera_offset and tile size adjustment.
	// All tiles inside camera view are drawn. Saves testing if tile is inside camera.
	const Object_Tile* it = NULL;
	for(int cy = cam.y, ry = 0; cy < cam.y + cam.h; ++cy, ++ry)
	{
		for(int cx = cam.x, rx = 0; cx < cam.x + cam.w; ++cx, ++rx)
		{
			ax = rx * Tile::TILE_WIDTH + camera.Offset().x;
			ay = ry * Tile::TILE_HEIGHT + camera.Offset().y;
			index = cy * level.Width() + cx;

			Render_Tile(renderer, Renderer::D1, ax, ay,
				background_tiles[index].File_Name()); 

			it = &object_tiles[index]; // could be level width instead?
			Render_Tile(renderer, Depth_From_Passability(it->Passability()),
				ax, ay, it->File_Name()); 

			Render_Tile(renderer, Renderer::D4, ax, ay,
				foreground_tiles[index].File_Name()); 
		}
	}
}


That all works fine. My problem is that my character can walk outside the bounds of the camera... and because of this the camera doesn't centre on them properly.
void Player_View::Render_View(Renderer& renderer, const Player& player,
const Point& camera_offset)
{
	const SDL_Surface* surface = renderer.Surface_At(player.Image_Fn());
	SDL_Rect clip = SDL_Tools::calculate_clip(surface->w, surface->h,
		player.Frame(), player.Facing());

	renderer.Render(Renderer::D2, player.Position() + camera_offset,
		player.Image_Fn(), clip);
}


camera_offset holds the value of the offset member in the Level_Camera class. The offset is the distance from the top left corner of the screen to where the camera is drawn. The addition of player.position and camera_offset looks like this:
const Point operator+(const Point& lhs, const Point& rhs)
{
	return Point(lhs.x + rhs.x, lhs.y + rhs.y);
}


So I'm wondering what kinda equation I'd need to get the character properly drawn within the camera. Cheers!

Share this post


Link to post
Share on other sites
Advertisement
Any help with this would be awesome... kinda haven't done anything on the game since this and would like to make some progress.

Cheers.

Share this post


Link to post
Share on other sites
I haven't read all of your code, but I think that the following line is wrong:

renderer.Render(Renderer::D2, player.Position() + camera_offset,
player.Image_Fn(), clip);


If the second parameter of Render is supposed be the position to render to (pixels, screen coordinates), and camera_offset is the top-left corner of the camera view (pixels, world coordinates) and player.Position is the top-left corner of the player (pixels, world-coordinates) then it should be player.Position() - camera_offset.

Share this post


Link to post
Share on other sites
Quote:
Original post by Barius
I haven't read all of your code, but I think that the following line is wrong:

renderer.Render(Renderer::D2, player.Position() + camera_offset,
player.Image_Fn(), clip);


If the second parameter of Render is supposed be the position to render to (pixels, screen coordinates), and camera_offset is the top-left corner of the camera view (pixels, world coordinates) and player.Position is the top-left corner of the player (pixels, world-coordinates) then it should be player.Position() - camera_offset.
Yeah, camera_offset is the top-left corner of the camera on the screen (usually 20,20). What if the player was at (0,0), though? (0,0) - (20,20) = (-20, -20)..

Share this post


Link to post
Share on other sites
No, not "yeah". I thought camera_offset was the offset of the camera in the world, not the offset of the view window on the screen.

The basic way to do this is:

- Calculate a view rectangle "viewrect" (world coordinates, pixels) based on the player position (world coordinates, pixels), and adjust it for special cases like the edges of the map.

- Draw each object or tile that intersects the view rectangle at camera_offset + object.topleft - viewrect.topleft.

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement