SamL
(usa XUbuntu)
Enviado em 02/10/2016 - 09:42h
Voltando. Segue o código comentado onde for possível:
#include <iostream>
#include <SDL2/SDL.h>
struct Vect
{
//tem de ser float e não int
float x;//posição x
float y;//posição y
Vect(float _x=0, float _y=0)
{
x = _x;
y = _y;
}
};
class Camera
{
public:
Vect position; // posição dentro do jogo, ou na área de limite
Vect focus;//focus é o ponto onde a camera foca, não fica só no centro
SDL_Rect dimension;//dimension são altura e largura da camera
SDL_Rect limit;// limite é toda a área onde a camera pode passar, o que pode ser visto
public:
// recebe o tamanho e o limite como parametro
Camera ( int w, int h, SDL_Rect lim )
{
limit = lim;
dimension.w = w;//aqui é da largura da janela
dimension.h = h;//aqui é da altura da janela
//coloca o foco no centro da camera
focus.x = dimension.w/2;
focus.y = dimension.h/2;
// por simplicidade não usarei o dimension.x e .y, serão apenas 0
dimension.x = 0;
dimension.y = 0;
}
// esse método é chamado dentro do loop para focalizar a
// posição 'p' dentro da camera na posição focus
void lookat ( Vect p )
{
// calcula a nova posição da camera
// po segredo está em entender estas duas linhas
position.x = p.x - focus.x;
position.y = p.y - focus.y;
// limita a posição da camera com os limites da fase
// lembrando que limit aqui é toda a área da fase por onde se pode caminhar
// se saiu pela esquerda da fase
if (position.x < limit.x)
position.x = limit.x;
//senão se saiu pel direita da fase
else if (position.x + dimension.w > limit.x + limit.w)
position.x = (limit.x + limit.w) - dimension.w;
//se saiu por cima da fase
if (position.y < limit.y)
position.y = limit.y;
//senão se saiu por baixo da fase
else if (position.y + dimension.h > limit.x + limit.h)
position.y = (limit.y + limit.h) - dimension.h;
}
};
//exemplo de sprite
class Sprite
{
public:
Vect pos;//posição x e y
SDL_Texture * texture;//imagem para usar
public:
Sprite ( SDL_Renderer * renderer, const char * filename )
{
SDL_Surface * surf = SDL_LoadBMP(filename);
if (!surf)
throw SDL_GetError();
texture = SDL_CreateTextureFromSurface(renderer, surf);
if (!texture)
throw SDL_GetError();
}
void draw ( SDL_Renderer * renderer, const Camera & camera )
{
SDL_Rect dest;
int w = 0, h = 0;
SDL_QueryTexture(texture,0,0,&w,&h);
/*
Aqui define a posição destino da textura usando como base a posição
da camera, por isso é posição atual do sprite menos posição atual da camera
É tudo que precisa fazer para nao mover de verdade cada objeto, mas move-se apenas
sua imagem. Funciona também para quadrados desenhados na tela
*/
dest.x = pos.x - camera.position.x;
dest.y = pos.y - camera.position.y;
dest.w = w;
dest.h = h;
SDL_RenderCopy(renderer,texture,NULL,&dest);
}
};
/*
Para desenhar retangulos na tela, veja que é o mesmo conceito do outro draw de sprite
*/
void drawRect ( SDL_Renderer * renderer, const Camera & camera, SDL_Rect dest, SDL_Color color )
{
dest.x = dest.x - camera.position.x;
dest.y = dest.y - camera.position.y;
SDL_SetRenderDrawColor(renderer,color.r,color.b,color.g,color.a);
SDL_RenderFillRect(renderer, &dest);
}
//exemplo de uso
int main (void)
{
SDL_Init(SDL_INIT_VIDEO);
SDL_Event event;
SDL_Window * window = SDL_CreateWindow("Teste Camera", 0,0,640,480,SDL_WINDOW_SHOWN);
SDL_Renderer * renderer = SDL_CreateRenderer(window,-1,SDL_RENDERER_ACCELERATED);
// verifique por erros
SDL_Rect player = {0,0,64,64};
//limite posicionado em 0,0 tendo o dobro do tamanho da janela
SDL_Rect limit = {0,0,640*2,480*2};
//só lembrando que o foco da camera está localizado no centro dela por padrão
//mude o valor de focus a vontade e veja como fica
Camera camera(640,480,limit);
// retangulos que marcam o chão, os 4 cantos do limite
SDL_Rect rects[4];
/*
Observe que estes retangulos estão posicionados sem considerar a posição da camera
porque a camera só é considerada para desenhar na tela e não para mover ou posicionar
os objetos.
*/
rects[0] = (SDL_Rect){0,0,640,480};//canto esquerdo superior do limite
rects[1] = (SDL_Rect){640,0,640,480};//canto direito superior do limite
rects[2] = (SDL_Rect){0,480,640,480};//canto esuqerdo inferior do limite
rects[3] = (SDL_Rect){640,480,640,480};//canto direito inferior do limite
int done = 0;
// controles do jogador, são as setas
bool right = false, left = false, down = false, up = false;
while (!done)
{
while (SDL_PollEvent(&event))
{
if (event.type == SDL_QUIT)
done = 1;
if (event.type == SDL_KEYDOWN)
{
switch (event.key.keysym.sym)
{
case SDLK_RIGHT:
right = true;
break;
case SDLK_LEFT:
left = true;
break;
case SDLK_UP:
up = true;
break;
case SDLK_DOWN:
down = true;
break;
default:
break;
}
}
if (event.type == SDL_KEYUP)
{
switch (event.key.keysym.sym)
{
case SDLK_RIGHT:
right = false;
break;
case SDLK_LEFT:
left = false;
break;
case SDLK_UP:
up = false;
break;
case SDLK_DOWN:
down = false;
break;
default:
break;
}
}
}
if (right)
player.x += 10;
else if (left)
player.x += -10;
if (up)
player.y += -10;
else if (down)
player.y += 10;
// faz a camera olhar para a posição do jogador
// o jogador pode sair pelas bordas do limite, isso é normal
camera.lookat(Vect(player.x,player.y));
SDL_SetRenderDrawColor(renderer,0,0,0,0);
SDL_RenderClear(renderer);
drawRect(renderer,camera,rects[0],(SDL_Color){255,255,0,255});//rosa
drawRect(renderer,camera,rects[1],(SDL_Color){255,0,255,255});//amarelo
drawRect(renderer,camera,rects[2],(SDL_Color){0,0,255,255});//verde
drawRect(renderer,camera,rects[3],(SDL_Color){0,255,0,255});//azul
drawRect(renderer,camera,player,(SDL_Color){255,0,0,255});//retagulo vermelho
SDL_RenderPresent(renderer);
SDL_Delay(60);
}
SDL_DestroyWindow(window);
SDL_DestroyRenderer(renderer);
SDL_Quit();
}
Uma coisa que você deve saber é que os objetos do jogo não devem ser posicionado em função da camera, e sim posicionados livremente no espaço. Por exemplo, nos jogos do mario os objetos tem uma posição X, Y e eles são dispostos no mapa de acordo com as coordenadas, mas não pensando na camera. A camera é outro elemento mas que não controla os outros, serve apenas para mostrar coisas na tela, como uma camera real, ela tem posição e dimensão da visão. Por isso, quando for posicionar seus objetos pensem somente neles como objetos livres da camera, e a camera livre dos objetos.
Eu coloquei uma classe sprite de exemplo, pra você ver como é o mesmo processo para desenhar retangulos e imagens em relação à camera.