Mostrando postagens com marcador API. Mostrar todas as postagens
Mostrando postagens com marcador API. Mostrar todas as postagens

01 setembro 2014

O que aprendi com a programação hoje: dia 4 - sons em Javascript

Esse post faz parte de uma série: o que aprendi com a programação, e tudo começou no dia 1.

Se você está fazendo um jogo ou pretende fazê-lo, ou simplesmente está com curiosidade em saber do que se trata, considere compreender como adicionar efeitos sonoros no seu aplicativo ou game, pois a experiência do usuário fica bem melhor. Neste pequeno post vou mostrar como usar os sons, pois com a linguagem Javascript, tudo fica super simples.

Para tocar uma música ou som, você precisa ter um código Javascript que rode algo como isso:

var audio = new Audio('audio.mp3');
audio.play();


Considerando o exemplo publicado no post do dia 2, sobre animação, que tal adicionar uns efeitos para entender como se faz na prática? Podemos adicionar um tema musical, no qual ficará sempre tocando, além de alguns efeitos sonoros de acordo com o desejado. Neste caso vou demonstrar o efeito de um click na tela, que junto animação da bola, vai tocar efeito sonoro a cada click.

var Sound = {

 init : function() {
  Sound.audio = new Audio('main_theme.mp3');
  Sound.audio.loop = true;
  Sound.play();
 },

 play : function() {
   Sound.audio.play();
 },

 resetAndPlay : function() {
  Sound.audio.currentTime = 6;
  Sound.play();
 },

 pause : function() {
  Sound.audio.pause();
 },

 playSound : function(sound) {
   var audioFile, audio;
   audioFile = sound;
   audio = new Audio(audioFile);
   audio.play();
 },

 playClick : function() {
  var audio = "smb_kick.wav";
  Sound.playSound(audio);
 },

 gameOver : function() {
  Sound.pause();
  var audio = "smb_gameover.wav";
  Sound.playSound(audio);
 },

};

Sound.init();



O código é relativamente simples. Em Javascript temos o objeto Audio, e neste temos alguns controles padrões, tais como: loop do áudio e currentTime. O loop podemos configurar para tornar a música repetitiva quando ela acabar. Enquanto que em currentTime podemos configurar para a música começar a partir de um determinado intervalo de tempo.

Podemos criar funções para tocar ou pausar os sons específicos. Vários formatos de arquivos são suportados pelo Browser. Eu já testei com MP3, WAV e OGG. Todos funcionaram. É importante destacar que se uma música está em execução, e você desejar tocar outra, basta chamá-la que o novo som vai tocar em paralelo com o atual. Se desejar parar ou pausar a música atual, pode chamar o método pausar. Para estudar melhor sobre sons em Javascript de uma olhada neste link.

Vejamos como o jogo principal foi atualizado para possuir as chamadas do sound.js pelo arquivo bola.js:

var Animacao = {
 // variaveis globais
 CANVAS : null,
 CONTEXT : null,
 bola : null,
 emProcessoAnimacao : false,
 contadorAnimacao : 0,

 // inicializa a Animacao
 init : function() {
  // variaveis de canvas
  Animacao.CANVAS = document.querySelector(".canvas");
  Animacao.CONTEXT = Animacao.CANVAS.getContext("2d");

  // registra eventos
  Animacao.addEventListeners();


  bola = new Bola(0,0);
  bola.init();

  setTimeout(Animacao.pintar,100);


 },

 // limpa a tela
 clearCanvas : function() {
  Animacao.CONTEXT.clearRect(0, 0, Animacao.CANVAS.width, Animacao.CANVAS.height);
 },

 // registra eventos
 addEventListeners : function() {
  Animacao.CANVAS.addEventListener("click", Animacao.clickAnimacaoHandler);
 },

 clickAnimacaoHandler : function(e) {

  Animacao.emProcessoAnimacao = true;

  // SOM de click
  Sound.playClick();

  Animacao.pintar();
 },

 pintar : function() {

  // desenha a Animacao aqui
  Animacao.clearCanvas();

  // atualizar posicao e pintar objeto
  bola.update();
  bola.draw();


  // se objeto saiu da tela
  if (bola.y > Animacao.CANVAS.height) {

   console.log("Animacao saiu da tela -> gameOver");

   bola.y = 0;
   bola.draw();

   // SOM de game over

   Sound.gameOver();
   setTimeout(Sound.resetAndPlay,4000);
  }

  // chamar novamente o metodo (pelo menos 5 vezes)
  if (Animacao.emProcessoAnimacao) {

    Animacao.contadorAnimacao++;

    if (Animacao.contadorAnimacao >= 5) {
     Animacao.contadorAnimacao = 0;
     Animacao.emProcessoAnimacao = false;

    } else {

     // repintar a tela novamente
     requestAnimationFrame(Animacao.pintar);
    }
  }
 },

};


function Sprite(image) {
 this.image = new Image();
 this.image.src = image + ".jpg";

 this.draw = function(x, y) {
  Animacao.CONTEXT.drawImage(this.image, x, y);
 };
}

function Bola(x, y) {
 this.x = x;
 this.y = y;
 this.clicked = false;
 this.sprite;

 this.init = function() {
  this.sprite = new Sprite("bola");
 };

 this.update = function() {

  this.y += (this.sprite.image.height/10);

 };

 this.draw = function() {
  this.sprite.draw(this.x, this.y);
 };

 this.click = function() {
  this.clicked = true;
  this.draw();
 };

 this.animate = function() {
  this.type.sprite.animate();
 };

}


// o javascript vai carregar esse metodo a cada refresh no browser
window.onload = Animacao.init;



Baixei alguns sons prontos que encontrei em uma busca na internet. No entanto, tenha cuidado para não sair copiando da internet qualquer som que você achar legal, pois há licenças proibitivas (copyrights), e que podem não estarem autorizados pelos detentores da propriedade intelectual. Para fins de testes, eu copiei as músicas do Mário neste site. Se desejar publicar, recomendo utilizar sons de domínio público ou produzir seus próprios.

Um detalhe importante: se deseja fazer diferentes partes do código Javascript chamarem os sons específicos, garanta que o arquivo sound.js seja declarado no HTML antes dos demais Javascripts para que sejam reconhecidos.



 
 Bola



 

início

This browser is not supported

fim


Aprendi com a programação para tratamento de sons usando Javascript que é muito simples de usá-los. Percebi também que o mais difícil não é fazê-los tocarem, mas encontrar um som de nosso agrado. O ideal seria produzir os próprios sons. Mas isso também envolve um custo adicional. 

Para baixar todos os arquivos com seus códigos fontes acesse aqui.

Que tal usar persistência em Javascript/HTML 5. De forma simples poderemos salvar dados do usuário e tornar nosso aplicativo bem mais "inteligente". No próximo post vou tentar explicar como gravar dados.


13 setembro 2012

Mudanças de perspectivas em aplicações Android: evite recriar a Activity

Usuários de aplicativos em geral podem requerer mudar a orientação do aparelho para visualizar melhor os conteúdos sendo exibidos na tela. Dependendo do que está sendo visto é comum girar a orientação da tela para o sentido horizontal (landscape) ou sentido vertical (portrait).

(1) Tela em modo Portrait


Em aplicações Android e iOS (smartphones e tablets) é comum implementar telas que vão funcionar em diferentes perspectivas de orientação de tela. No entanto, programadores de Android precisam estar atentos que quando ocorrem mudanças de orientação no aplicativo, o comportamento padrão do Android recria a Activity em execução, chamando os métodos do ciclo de vida: onPause(), onStop(), onDestroy(), para em seguida chamar o método onCreate() novamente, além dos métodos do ciclo de vida: onStart() e onResume().



Problema / Solução
Se a tela atual da sua aplicação apenas desenha elementos visuais sem obter dados de fontes custosas (para memória em geral ou uso da Internet para baixar os dados), então esse procedimento padrão do Android não será um problema. Contudo, caso sua Activity requeira dados da internet ou algum outro tipo de esquema de processamento “mais pesado” para ser realizado, talvez seja necessário evitar recarregar a instância da Activity, mantendo o estado dos objetos carregados na memória. Desta forma podemos evitar consultar a rede novamente, além de otimizar o uso do processamento do aparelho, melhorando o consumo da bateria. :)

Esse comportamento pode ser realizado de 2 formas: (que eu conheço)
  1. Salvar os dados atuais (o estado atual) utilizando o mecanismo do ciclo de vida da Activity do Android, através dos métodos onSaveInstanceState(bundle) para salvar, e o onRetainNonConfigurationInstance() para recuperar os dados do estado atual;
  2. Alterar o comportamento default do Android, descrito acima, evitando que a Activity seja automaticamente recriada. Desta forma o Android apenas irá notificar Activity que ocorreu uma mudança de orientação, através do método onConfigurationChanged(Configuration c).
Neste post vou mostrar como podemos implementar abordagem (2), ou seja, como evitar que o Android recrie Activity do ciclo de vida do aplicativo.

Essa dica eu encontrei no site oficial do desenvolvedor Android. Está neste link: Handling Runtime Changes: http://developer.android.com/guide/topics/resources/runtime-changes.html

Vou descrever passo a passo:

Passo 1: altere o arquivo AndroidManifest.xml conforme o exemplo abaixo adicionando a propriedade chamada (android:configChanges="orientation|screenSize") da sua Activity:



    

    
        
            
                

                
            
        
    



Passo 2: implementar no código Java da sua Activity o método conforme exemplo:
package br.com.blogspot.profdouglas.dicas3.orientationchange;

import android.app.Activity;
import android.content.res.Configuration;
import android.os.Bundle;
import android.util.Log;
import android.view.Menu;
import android.widget.TextView;

public class OrientationChange extends Activity {

 @Override
 public void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  setContentView(R.layout.activity_orientation_change);

  Log.d("DOUGLAS", "OrientationChange.onCreate");

  TextView orientationTextView = (TextView) findViewById(R.id.orientationTextView);

  // detect the current orientation
  int currentOrientation = getResources().getConfiguration().orientation;

  if (currentOrientation == Configuration.ORIENTATION_LANDSCAPE) {
   // setting orientation landscape
   orientationTextView.setText(R.string.orientation_landscape);

  } else if (currentOrientation == Configuration.ORIENTATION_PORTRAIT) {
   // setting orientation portrait
   orientationTextView.setText(R.string.orientation_portrait);
  }

 }

 @Override
 public boolean onCreateOptionsMenu(Menu menu) {
  getMenuInflater().inflate(R.menu.activity_orientation_change, menu);
  return true;
 }

 @Override
 protected void onStart() {
  super.onStart();
  Log.i("DOUGLAS", "OrientationChange.onStart");
 }

 @Override
 protected void onResume() {
  super.onResume();
  Log.i("DOUGLAS", "OrientationChange.onResume");
 }

 @Override
 protected void onStop() {
  super.onStop();
  Log.i("DOUGLAS", "OrientationChange.onStop");
 }

 @Override
 protected void onPause() {
  super.onPause();
  Log.i("DOUGLAS", "OrientationChange.onPause");
 }

 @Override
 protected void onDestroy() {
  super.onDestroy();
  Log.i("DOUGLAS", "OrientationChange.onDestroy");
 }

 /**
  * Caution: Beginning with Android 3.2 (API level 13), the "screen size"
  * also changes when the device switches between portrait and landscape
  * orientation. Thus, if you want to prevent runtime restarts due to
  * orientation change when developing for API level 13 or higher (as
  * declared by the minSdkVersion and targetSdkVersion attributes), you must
  * include the "screenSize" value in addition to the "orientation" value.
  * That is, you must decalare
  * android:configChanges="orientation|screenSize". However, if your
  * application targets API level 12 or lower, then your activity always
  * handles this configuration change itself (this configuration change does
  * not restart your activity, even when running on an Android 3.2 or higher
  * device).
  */
 @Override
 public void onConfigurationChanged(Configuration newConfig) {
  super.onConfigurationChanged(newConfig);
  Log.d("DOUGLAS", "MainActivity.onConfigurationChanged");

  TextView orientationTextView = (TextView) findViewById(R.id.orientationTextView);

  if (newConfig.orientation == Configuration.ORIENTATION_PORTRAIT) {
   Log.i("DOUGLAS",
     "MainActivity.onConfigurationChanged (ORIENTATION_PORTRAIT)");
   // setting orientation portrait
   orientationTextView.setText(R.string.orientation_portrait);

  } else if (newConfig.orientation == Configuration.ORIENTATION_LANDSCAPE) {
   Log.i("DOUGLAS",
     "MainActivity.onConfigurationChanged (ORIENTATION_LANDSCAPE)");
   orientationTextView.setText(R.string.orientation_landscape);
  }
 }

}


Observe o javadoc que deixei para que você entenda porque a propriedade do manifest precisou utilizar dois valores. A figura (2) demonstra o log (da view LogCat) demonstrando que a Activity não foi recriada, mas o método onConfigurationChanged foi notificado.

(2) Tela em modo Landscape sem recriar a Activity após mudar orientação


Conclusão
Ao executar seu aplicativo agora, quando ocorrer mudanças de orientação de tela sua Activity não será recriada e o método onConfigurationChanged será automaticamente notificada a cada mudança de orientação. 

Como sugestão, caso queira fazer algo específico para cada modo de orientação, pode-se usar a lógica da condição implementada no método, que atualmente possui instruções com logs. Dependendo do cenário no qual seu aplicativo está sendo usado, essa dica pode ser útil para você.

Assim que possível vou fazer uma vídeo aula sobre isso também e colocar aqui. O código fonte do exemplo do projeto pode ser baixado aqui.



25 maio 2012

Série sobre Programação Orientada a Objetos com Java (POO) (+ códigos fonte)

AULA 02 - Programação Orientada a Objetos - (POO)


Antes de mais nada, se deseja acompanhar meu twitter é só me seguir. Se preferir, sugiro acompanhar o canal no YouTube.


  • Você sabe codificar sem uma IDE?
  • Você sabe compilar sem o Eclipse? 
  • Sabe rodar sem o NetBeans?
  • Sabe definir uma classe?
  • Compreende as diferenças de usar uma classe pronta da linguagem Java e definir a sua própria? 
  • O que os objetos tem haver com isso?

Assista, pratique e descubra! :)


Objetivos vistos na aula 2:


1 - Entender o conceito de classe;
- discutido na aula 1;

2 - Criar uma classe para fazer algo;
2.1) mostrar na prática classe chamada Teste
2.2 - escrever na saída de dados um texto qualquer;
2.3 - Entender o processo Codificar/Compilar/Executar sem IDE :)















import java.util.Date;

public class Teste {

 public static void main(String[] argumentos) {

  // o programa ira comecar por essa classe

  System.out.println("Oi JAVA!! ");

  Date dataAtual = new Date();
  System.out.println("Data Atual é: " + dataAtual.toString());

  // criar um cliente
  // criar um objeto do tipo Cliente
  Cliente cliente1;
  cliente1 = new Cliente();
  cliente1.nome = "Douglas Frari";
  cliente1.CPF = "721.XXX.XXX.XX";
  cliente1.efetuarPedidoCompra();
  cliente1.efetuarPedidoCompra();
  cliente1.efetuarPedidoCompra();
  cliente1.efetuarPedidoCompra();
  
  // definicao do objeto
  Cliente cliente2;
  // instanciando objeto cliente
  cliente2 = new Cliente();
  
  // escrita no objeto (write)
  cliente2.nome = "Maria Eduarda";
  cliente2.CPF = "543.323.321.12";

  System.out.println("Nome do cliente 1: " + cliente1.toString());

  System.out.println("Nome do cliente 2: " + cliente2.toString());

 }

}




public class Cliente {


 // atributos para representar 
 // um cliente no sistema ATUAL
 String nome;
 String CPF;
 int quantidadePedidos;
 

 // operacoes que o cliente poderá
 // fazer neste sistema
 void efetuarPedidoCompra() {
  System.out.println("efetuando pedido de compra");
  quantidadePedidos++;
 }
 
 // imprimir os seus valores
 @Override
 public String toString() {
  String atributosClasse = "Nome: " + nome + ", CPF: " + CPF+
    " , quantidade pedidos: "+quantidadePedidos;
  return atributosClasse;
 }
 
 

}
Conclusão parcial Programar sem uma IDE é essencial. É claro que utilizar IDE torna o trabalho mais produtivo e a ideia é exatamente essa. Porém, como pretende ser um bom programador se não compreender o que essas ferramentas fazem sem que você perceba? Outro aspecto destacado foi o uso de classes em duas abordagens distintas. Veremos mais sobre isso nos próximas aulas. O código fonte refere-se as aulas 2, 3, 4 e 5. Porém, somente publiquei até o momento de hoje a aula 2. Em breve mais!