[SDL2] Como funciona o Scrolling/Câmera em um game em SDL2 [RESOLVIDO]

1. [SDL2] Como funciona o Scrolling/Câmera em um game em SDL2 [RESOLVIDO]

Perfil removido
removido

(usa Nenhuma)

Enviado em 01/10/2016 - 21:20h

Olá pessoal do VOL. Estava, eu, no Lazyfoo estudando quando encontrei esse assunto.

http://lazyfoo.net/tutorials/SDL/30_scrolling/index.php

Ele trata mais ou menos de um controle de câmera. A lógica eu consegui capturar, mas não entendi como funciona para mover a "Câmera" sem mudar a posição dos outros objetos.
Como para quase tudo que é desconhecido o oráculo sabe a resposta. Acabei encontrando alguns gringos com o mesmo problema, sendo assim, minha pesquisa foi inconclusiva ( linda essa palavra, né ? )

Acabou que essa pesquisa me deixou mais confuso sobre o funcionamento da câmera.

Voltando a pergunta. Eu quero saber com implementar essa câmera em um projeto que usa SDL2.
Mais ou menos assim, um personagem - um quadrado verde - em um cenário - um quadrado amarelo maior que o personagem - para fazer com que quando o personagem se mover para qualquer posição a câmera se mova com ele ô centralizando; não movendo nenhum outro objeto na tela de posição.

Já fiz um gambiarra deixando o personagem parado na tela e movendo o cenário em volta dele, mas não deu muito certo. Quando eu quis colocar mais objetos, eu tinha que mudar a posição de todos eles. Mesmo não tendo muito experiência em desenvolvimento de games, eu achei isso muito complicado.

Eu gostaria que alguém com muita paciência enviasse um pequeno código implementando essa câmera, lembrando que o código em SDL2 ajudaria bastante !

Obrigado pela atenção.

Transportai um punhado de terra todos os dias e fareis uma montanha.
~Confúcio



  


2. MELHOR RESPOSTA

Samuel Leonardo
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.

3. RE: [SDL2] Como funciona o Scrolling/Câmera em um game em SDL2

Perfil removido
removido

(usa Nenhuma)

Enviado em 01/10/2016 - 22:27h

SamL escreveu:

Já passei por isso ai e tive que inventar como fazer isso, pois na época não achei nenhum tutorial ensinando, e quem sabia não ensinava pra ninguém, o que não foi ruim pra mim, assim pude compreender vários princípios. Mas no tempo que eu estava aprendendo era ainda o SDL1.2 e não tinha como criar um simples viewport, mas hoje em dia foi superado pela nova versão.

Vou simplificar aqui a minha classe camera e explicar como desenhar na tela usando ela, só espero que tenha alguma noção de C++ pois não vou fazer em C, por questão de praticidade.

Aguarde uns minutos...


C/C++ são meus amores , pode manda :D




4. Re: [SDL2] Como funciona o Scrolling/Câmera em um game em SDL2 [RESOLVIDO]

Perfil removido
removido

(usa Nenhuma)

Enviado em 02/10/2016 - 01:12h

SamL escreveu:

Ruanhenry escreveu:

C/C++ são meus amores , pode manda :D

Cara posso deixar pra amanhã? É que já vou dormir. Ou você quer sem exemplo de uso? falta só o exemplo no resto você poderia fazer sozinho, mas eu queria demonstrar bem o conceito, mas é algo simples de explicar.



OK






Patrocínio

Site hospedado pelo provedor RedeHost.
Linux banner
Linux banner
Linux banner

Destaques

Artigos

Dicas

Tópicos

Top 10 do mês

Scripts