Continuando nossa série de artigo traduzido do site lazyfoo, agora que sabemos como renderizar, lidar com entrada de dados e gerenciar o tempo, agora sabemos tudo que é necessário para mover coisas pela tela.
//The dot that will move around on the screen class Dot { public: //The dimensions of the dot static const int DOT_WIDTH = 20; static const int DOT_HEIGHT = 20; //Maximum axis velocity of the dot static const int DOT_VEL = 10; //Initializes the variables Dot(); //Takes key presses and adjusts the dot's velocity void handleEvent( SDL_Event& e ); //Moves the dot void move(); //Shows the dot on the screen void render(); private: //The X and Y offsets of the dot int mPosX, mPosY; //The velocity of the dot int mVelX, mVelY; };
Aqui temos a classe para o ponto que iremos mover pela tela. Ela possui constantes que definem suas dimensões e velocidade. Possui um construtor, um manipulador de eventos, uma função para mover cada frame, e uma função de renderização. Como dados, possui variáveis para a posição x e y e velocidade em x e y.
Dot::Dot() { //Initialize the offsets mPosX = 0; mPosY = 0; //Initialize the velocity mVelX = 0; mVelY = 0; }
O construtor simplesmente inicializa variáveis.
void Dot::handleEvent( SDL_Event& e ) { //If a key was pressed if( e.type == SDL_KEYDOWN && e.key.repeat == 0 ) { //Adjust the velocity switch( e.key.keysym.sym ) { case SDLK_UP: mVelY -= DOT_VEL; break; case SDLK_DOWN: mVelY += DOT_VEL; break; case SDLK_LEFT: mVelX -= DOT_VEL; break; case SDLK_RIGHT: mVelX += DOT_VEL; break; } }
Em nosso manipulador de eventos, iremos ajustar a velocidade baseado no pressionamento de algumas teclas.
Você pode estar se perguntando por quê nós não simplesmente aumentamos a posição quando pressionamos uma tecla. Se estivéssemos dizendo para adicionar um valor à posição x a cada vez que pressionarmos a tecla seta para direita, teríamos que repetidamente pressionar essa tecla para continuar movendo o ponto. Ajustando a velocidade, temos que pressiona a tecla uma única vez.
Se você está se perguntando por quê estamos checando se a repetição da tecla é 0, é porque repetição de tecla é ativa por padrão e se você pressionar e segurar um tecla, será reportado múltiplos pressionamentos de tecla. Isso significa que temos que checar se o pressionamento da tecla é o primeiro pois nós nos importamos apenas com essa primeira vez.
Para aqueles que ainda não estudaram física, velocidade é a rapidez/direção de um objeto. Se um objeto está se movendo para a direita a 10 pixels por frame, ele possui uma velocidade de 10. Se está se movendo para a esquerda a 10 pixels por frame, ele possui uma velocidade de -10. Se a velocidade do ponto é 10, isso significa que após 10 frames ele terá se movido 100 pixels nessa direção.
//If a key was released else if( e.type == SDL_KEYUP && e.key.repeat == 0 ) { //Adjust the velocity switch( e.key.keysym.sym ) { case SDLK_UP: mVelY += DOT_VEL; break; case SDLK_DOWN: mVelY -= DOT_VEL; break; case SDLK_LEFT: mVelX += DOT_VEL; break; case SDLK_RIGHT: mVelX -= DOT_VEL; break; } } }
Quando soltamos uma tecla, temos que desfazer a mudança de velocidade para o valor anterior a quando ela foi pressionada pela primeira vez. Quando pressionamos a tecla seta para direita, adicionamos o valor de x à velocidade. Quando soltamos essa tecla, subtraímos x à velocidade para retornar para 0.
void Dot::move() { //Move the dot left or right mPosX += mVelX; //If the dot went too far to the left or right if( ( mPosX < 0 ) || ( mPosX + DOT_WIDTH > SCREEN_WIDTH ) ) { //Move back mPosX -= mVelX; }
Aqui temos a função que chamamos a cada frame para mover o ponto.
Primeiro movemos o ponto pelo eixo x baseado em sua velocidade x. Depois checamos se o ponto se moveu para fora da tela. Caso afirmativo, desfazemos o movimento realizado através do eixo x.
//Move the dot up or down mPosY += mVelY; //If the dot went too far up or down if( ( mPosY < 0 ) || ( mPosY + DOT_HEIGHT > SCREEN_HEIGHT ) ) { //Move back mPosY -= mVelY; } }
Em seguida fazemos o mesmo para o eixo y.
void Dot::render() { //Show the dot gDotTexture.render( mPosX, mPosY ); }
Na função de renderização, renderizamos a textura do ponto na posição dele.
//Main loop flag bool quit = false; //Event handler SDL_Event e; //The dot that will be moving around on the screen Dot dot;
Antes de entrarmos no loop principal declaramos um objeto da classe do ponto.
//While application is running while( !quit ) { //Handle events on queue while( SDL_PollEvent( &e ) != 0 ) { //User requests quit if( e.type == SDL_QUIT ) { quit = true; } //Handle input for the dot dot.handleEvent( e ); } //Move the dot dot.move(); //Clear screen SDL_SetRenderDrawColor( gRenderer, 0xFF, 0xFF, 0xFF, 0xFF ); SDL_RenderClear( gRenderer ); //Render objects dot.render(); //Update screen SDL_RenderPresent( gRenderer ); }
Nesse artigo, nós baseamos a velocidade como a quantidade de pixels movidos por frame. Na maioria dos jogos, a velocidade é calculada por segundos. A razão pela qual fizemos aqui por frame é por ser mais fácil, mas se você souber física não deve ser difícil atualizar a posição do ponto baseado no tempo. Se você não tiver conhecimento de física, então fique com a velocidade calculada por frame por enquanto.