Marcos Vasconcelos
Pong game - Exemplo completoImprimir
Escrito por Marcos Vasconcelos

Este artigo, não ensina como programar para Android, para isso siga esse roadmap. O intuito desse artigo é mostrar as diferenças entre o Java2D e Android, e também mostrar um jogo como exemplo. Este artigo também mostra alguns conceitos de como programar jogos, e como fazer isso no Android e de quebra um pouquinho de matematica e fisica.

Se você já sabe como programar jogos com Java2D, mudar para o Android vai ser fácil.
O sistema de desenho do Android é parecido com o do Java SE, mas no lugar de denharmos no Graphics, desenhamos no Canvas.

As principais diferenças são:

Para termos acesso a uma surface para desenho, estendemos a classe View e sobrescrevemos o método onDraw(Canvas) e desenhamos nesse parâmetro.

Assim como em Graphics, precisamos salvar o estado do nosso objeto de desenho antes de alterar suas propriedades, para isso usamos o método save() e depois da rotina de desenho usamos o método restore() para retornar o estado original no Canvas, permitindo qualquer outro método de desenho trabalhe corretamente com ele( desenhos da UI por exemplo).

Então vamos lá, crie um projeto com os seguintes parâmetros.

Target: 2.1
Application Name: JPong
Package Name: br.com.pontov
Create Activity: AndPongActivity
Min SDK Version: 7

Crie uma nova classe no pacote br.com.pontov.jpong chamada GameView que extenda android.view.View.

Precisamos sobrescrever os três construtores de View pois o Android os usa quando está inflando o Layout do XML, e um ultimo para criar Layouts programaticamente, como queremos que a classe se comporte igual não importa como esteja sendo construída então vamos chamar um método init() que faça nossa rotina de construção dentro de cada construtor, com isso nosso código ficará assim.

package br.com.pontov.jpong;

import android.graphics.Canvas;
import android.util.AttributeSet;
import android.view.View;

public class GameView extends View implements Runnable {
   public GameView(Context context) {
      super(context);
      init();
   }
   public GameView(Context context, AttributeSet attrs) {
      super(context, attrs);
      init();
   }
   public GameView(Context context, AttributeSet attrs, int defStyle) {
      super(context, attrs, defStyle);
      init();
   }
   private void init() {
      //Metodos para inicializar os componentes da nossa tela
   }
   public void onDraw(Canvas canvas){
      //Desenhar na tela
   }
}

Os métodos de desenho do canvas fora as coordenadas do objeto que vamos desenhar também precisam de um objeto Paint que indica como o objeto deve ser pintado, e como recomendações do Android, não se deve ficar criando esses objetos dentro do método onDraw que será chamado várias vezes na nossa aplicação, então vamos criá-la no nosso método init() e guardar a referencia dela em uma variável na tela.

Crie os atributos na classe.

private Paint backgroundPaint;
private Paint ballPaint;

No método init vamos criar esses objetos e no método onDraw desenhar objetos na tela.

private void init() {
   backgroundPaint = new Paint();
   backgroundPaint.setColor(Color.BLACK);
   ballPaint = new Paint();
   ballPaint.setColor(Color.RED);
}
public void onDraw(Canvas canvas){
   //Guardar o estado do Canvas
   canvas.save();
   //Pintando o fundo
   canvas.drawRect(0, 0, getWidth(), getHeight(), backgroundPaint);
   //Pintando a bola (x, y, radius, Paint)
   canvas.drawCircle(80,80,10,ballPaint);
   //Retornando o estado do Canvas
   canvas.restore();
}

Agora abra o arquivo res/layout/main.xml, ele por enquanto contém o básico de uma aplicação HelloWorld. Para usar nosso componente customizado nas tags do XML só precisamos passar seu nome junto com a declaração do pacote, o XML então vai ficar assim:



    

Para transformar nossa atividade em FullScreen é simples, basta editar o arquivo AndroidManifest.XML e adicionar o seguinte atributo na tag activity da nossa aplicação:

android:theme="@android:style/Theme.NoTitleBar.Fullscreen"

Rodando nosso exemplo já temos algo como isso.

first-result


Vamos transformar nosso exemplo em um jogo de Pong, com isso será possível já apresentar vários conceitos sobre desenvolvimento de jogos e ainda vai ser um resultado legal.

Agora entra a parte interessante, vamos dar algum movimento para nossa bolinha, isso é fácil se você entende de vetores, se ainda não sabe como usá-los voce pode ver aqui.

A principio, a bolinha precisa de uma posição, direção e velocidade e vamos atualizar essa posição através das iterações e redesenhar nossa bolinha.

Vamos criar uma classe chamada Ball no pacote br.com.pontov.pieces para representar nossa bolinha.

Posição e Direção são vetores, e velocidade é um float que é o tanto que nossa bolinha ira andar por iteração.
Nossa classe também é responsável por atualizar a posição da bolinha e oferecer um método para que ela se desenhe em um Canvas.

package br.com.pontov.pieces;

import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import br.com.pontov.Vector2D;

public class Ball {
    private Paint paint;

    private Vector2D pos;
    private Vector2D dir;
    private float speed;

    public Ball(Vector2D pos, Vector2D dir, float speed) {
        this.pos = pos;
        this.dir = dir;
        this.speed = speed;

        paint = new Paint();
        paint.setColor(Color.RED);
    }

    public void draw(Canvas canvas) {
        canvas.save();
        canvas.drawCircle(pos.getX(), pos.getY(), 10, paint);
        canvas.restore();
    }

    private void move() {
        pos.plusMe(dir.multiply(speed));
    }

    public void processAI() {
        move();
    }
}

No Android, assim como no Java2D é necessário chamar os métodos de redesenho na Thread principal da aplicação, mas no lugar de repaint() usamos apenas invalidate(), podemos informar nossa Thread através de um Handler para fazer o refresh da tela.

Voltamos ao AndPongActivity e vamos criar um Handler que vai atualizar o GameView.

Primeiro temos que guardar a referencia do GameView na nossa classe, então criamos uma variável pra ela.

private GameView gameView;

No método onCreate podemos obter essa referencia através do id que demos no XML. E depois criar um Handler para ouvir mensagens da nossa thread para atualizar a tela.

gameView = (GameView) findViewById(R.id.gameView);

guiRefresher = new Handler(){
    public void handleMessage(Message msg){
        if(msg.what == 10001)//Numero arbitrario
            gameView.invalidate();
        super.handleMessage(msg);
    }
};

Vamos deixar nossa GameView responsavel por iterar nosso jogo e avisar o Handler para fazer o refresh, para isso temos que guardar a referencia do Handler nela e também implementar o método run() para que ele processe o jogo.

Também vamos deixar que ele crie um objeto Ball e deixe ele percorrer a tela.

package br.com.pontov.jpong;

import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.os.Handler;
import android.os.Message;
import android.util.AttributeSet;
import android.view.View;
import br.com.pontov.math.Vector2D;
import br.com.pontov.pieces.Ball;

public class GameView extends View implements Runnable {
    private int width = 600, height = 1024;
    private Paint background;
    private Handler handler;
    private Ball ball;

    public GameView(Context context) {
        super(context);
        init();
    }

    public GameView(Context context, AttributeSet attrs) {
        super(context, attrs);
        init();
    }

    public GameView(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        init();
    }

    private void init() {
        background = new Paint();
        background.setColor(Color.BLACK);

        ball = new Ball(new Vector2D(20, 20), new Vector(1,1), 1.2);
    }

    public void onDraw(Canvas canvas) {
        canvas.save();
        //Pintando background
        canvas.drawRect(0, 0, getWidth(), getHeight(), background);
        //Deixando a bolinha se pintar na posição correta
        ball.draw(canvas);
        canvas.restore();
    }

    @Override
    public void run() {
        while (true) {
            try {
                ball.processAI();

                Message msg = new Message();
                msg.what = 10001;//Mesmo id que o Handler espera para atualizar
                handler.sendMessage(msg);

                Thread.sleep(10);
            } catch (Exception e) {
            }
        }
    }

    public void setCallbackHandler(Handler guiRefresher) {
        this.handler = guiRefresher;
    }
}

Voltamos ao AndPongActivity e colocamos nosso Handler na GameView e iniciamos uma Thread para atualizar.

O método onCreate agora ficara o seguinte:

public void onCreate(Bundle savedInstanceState) {
   super.onCreate(savedInstanceState);
   setContentView(R.layout.main);

   gameView = (GameView) findViewById(R.id.gameView);

   guiRefresher = new Handler(){
      public void handleMessage(Message msg){
         if(msg.what == 10001){
            gameView.invalidate();
         }
         super.handleMessage(msg);
      }
   };

   gameView.setCallbackHandler(guiRefresher);

   Thread t = new Thread(gameView);
   t.setDaemon(true);
   t.start();
}

Rodando nossa aplicação já podemos ver a animação da bolinha indo continuamente na direção south-east (1,1).


O problema é que nossa bolinha vai alcançar o final da tela e continuar, precisamos criar paredes e fazer com que a bolinha colida nela.

A parede também é uma entidade do jogo, e precisa passar pelos mesmos passos que a bolinha passa, "draw" e "processAI" tudo bem que ela não precisa realmente pensar, mas esse é um comportamente comum dos objetos de jogo então vamos criar uma classe que represente uma entidade.

package br.com.pontov.pieces;

import android.graphics.Canvas;
import android.graphics.Rect;

public abstract class Entity {
    private Rect bounds;

    public Entity(Rect bounds) {
        this.bounds = bounds;
    }

    public Rect getBounds() {
        return bounds;
    }

    public void setBounds(Rect rect) {
        this.bounds = rect;
    }

    public abstract void draw(Canvas canvas);

    public abstract void processAI();
}

Mudamos a classe Ball simplesmente para estende-la e como já implementamos esses dois métodos anteriormente ela vai continuar funcionando.

Seguindo a mesma ideia das entidades de jogo, logo imaginamos que os Pads e as Walls serão entidades que bloqueiam a passagem de algo. Então podemos criar uma classe que as represente.
É aqui que entra uma pequena mágica da matemática, para fazer que a nossa bolinha colida para o lado certo, precisamos aplicar uma formula na sua direção com um outro vetor chamado normal, que é um vetor que faz ângulo de 90º com o objeto, vamos simplesmente criar uma entidade que tenha um Vector2D normal que será usado depois nas colisões.

package br.com.pontov.pieces;

import android.graphics.Rect;
import br.com.pontov.math.Vector2D;

public abstract class BlockableEntity extends Entity {
    private Vector2D normal;
    public BlockableEntity(Rect bounds, Vector2D vec) {
        super(bounds);
        this.normal = vec;
    }
    public BlockableEntity(Vector2D vec) {
        this.normal = vec;
    }
    public void setNormal(Vector2D normal) {
        this.normal = normal;
    }
    public Vector2D getNormal() {
        return normal;
    }
}

Agora podemos criar uma classe que representa uma parede, e ela seria simplesmente o seguinte:

package br.com.pontov.pieces;

import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Rect;
import br.com.pontov.math.Vector2D;

public class Wall extends BlockableEntity {
    private Paint wallPaint;

    public Wall(Rect bounds, Vector2D normal) {
        super(bounds, normal);
        wallPaint = new Paint();
        wallPaint.setColor(Color.GRAY);
    }

    public void draw(Canvas canvas) {
        canvas.save();
        canvas.drawRect(getBounds(), wallPaint);
        canvas.restore();
    }

    public void processAI() {
        // Do nothing, walls don't think
    }
}

Um problema agora é que para cada vez que precisarmos adicionar uma nova entidade na nossa tela teriamos que guardar uma referencia para ela e verificar suas iterações, também seria necessário chamar o método processAI e draw para todos as entidades, para facilitar isso, vamos criar uma classe que vai cuidar disso para nós, chamada PiecesManager, ela simplesmente guarda uma lista das nossas entidades e invocar os métodos corretos nela:

package br.com.pontov;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;

import android.graphics.Canvas;
import br.com.pontov.Entity;

public class PiecesManager {
    private List pieces;

    public PiecesManager() {
        pieces = new ArrayList();
    }

    public void addPiece(Entity ent) {
        pieces.add(ent);
    }

    public void draw(Canvas canvas) {
        for (Entity ent : pieces)
            ent.draw(canvas);
    }

    public List getPieces() {
        return pieces;
    }

    public void processAI() {
        for (Entity ent : pieces)
            ent.processAI();
    }
}

Com tudo isso pronto, podemos voltar ao GameView e adicionar algumas paredes ao nosso jogo.

Primeiro criamos a variável que guarda nossa instancia de objetos do jogo.
Aproveitamos aqui também e vamos criar uma variável width e height para guardar o tamanho da nossa tela.

private PiecesManager pieces;
private int width = 600, height = 1024;//Tamanho do Galaxy Tab

Agora podemos modificar nosso init e criar os objetos e adicionar ao nosso manager.

O construtor da Wall espera um Vector2D que é um vetor que faz 90º na parede, no sentido oposto ao qual a bola vem, mas não se desespere, esses vetores já tem valores pré-definidos, e seguem como a relação abaixo:

Se for a parede esquerda, esse vetor é (1, 0);
Se for a direita (-1, 0);
Se for a de cima (0, -1);
E se for a de baixo (0, 1);

Então nosso init fica assim:

private void init() {
   background = new Paint();
   background.setColor(Color.BLACK);

   manager = new PiecesManager();

   manager.addPiece(new Ball(new Vector2D(300, 600), new Vector2D(1, 1), 8));

   manager.addPiece(new Wall(new Rect(0, 0, 10, height), new Vector2D(1,0)));//Left
   manager.addPiece(new Wall(new Rect(width - 10, 0, width, height), new Vector2D(-1,0)));//Right
   manager.addPiece(new Wall(new Rect(0, 0, width, 10), new Vector2D(0,-1)));// Top
   manager.addPiece(new Wall(new Rect(0, height - 10, width, height),new Vector2D(0,1)));//Bottom
}

Note que defini variáveis para valores do width e height. Essas variáveis com o tamanho são para facilitar essas contas e deixar um pouco mais escalável, para criar para outro tamanho de tela basta mudar os valores em width e height.

Como nosso manager agora é responsável por invocar todos processAI e draw podemos delegar a ele esses métodos pelo GameView, nosso método draw e run ficam assim.

public void onDraw(Canvas canvas) {
    canvas.save();
    canvas.drawRect(0, 0, getWidth(), getHeight(), background);
    pieces.draw(canvas);
    canvas.restore();
}

@Override
public void run() {
    while (true) {
        try {
            pieces.processAI();

            Message msg = new Message();
            msg.what = 10001;
            handler.sendMessage(msg);

            Thread.sleep(10);
        } catch (Exception e) {
        }
    }
}

Rodando nosso exemplo já podemos ver as paredes, mas isso não fará que a bolinha automaticamente colida e mude sua direção, precisamos implementar o processAI na classe Ball para verificar se existe alguma BlockableEntity no seu caminho e mudar sua direção se isso acontecer.

Primeiro temos que ter as referencias das peças para que a Ball verifique, podemos simplesmente guardar a referencia de PiecesManager nela e iterar sobre sua lista e verificar se alguma BlockableEntity está colidindo com ela.

A função que representa a mudança do angulo da direção é dada por:

r = v-2 * v.dot( n ) * n;

Onde:

Se tivessemos sobrecargas de operadores em Java, aplicar essa formula para nossa bolinha seria simplesmente

dir = dir - 2 * dir.dot(wall.getNormal()) * wall.getNormal()

Como não existe, a fórmula é a seguinte:

dir = dir.minus(n.multiply(2).multiply(dir.dot(n)))

Nosso código ficará o seguinte:

package br.com.pontov.pieces;

import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Rect;
import br.com.pontov.PiecesManager;
import br.com.pontov.math.Vector2D;

public class Ball extends Entity {
    private Paint paint;

    private Vector2D pos;
    private Vector2D dir;
    private float speed;

    private PiecesManager pieces;

    public Ball(Vector2D pos, Vector2D dir, float speed, PiecesManager manager) {
        super();

        this.pos = pos;
        this.dir = dir;
        this.speed = speed;

        paint = new Paint();
        paint.setColor(Color.RED);

        pieces = manager;
    }

    @Override
    public void draw(Canvas canvas) {
        canvas.save();
        canvas.drawCircle(pos.getX(), pos.getY(), 10, paint);
        canvas.restore();
    }

    private void move() {
        pos.plusMe(dir.multiply(speed));
    }

    @Override
    public void processAI() {
        Rect bounds = new Rect((int) pos.getX() - 5, (int) pos.getY() - 5,
                (int) pos.getX() + 5, (int) pos.getY() + 5);

        for (Entity ent : pieces.getPieces()) {
            if (ent == this)
                continue;
            if (ent instanceof BlockableEntity)
                if (bounds.intersect(ent.getBounds())) {
                    Vector2D n = ((BlockableEntity) ent).getNormal();
                    // r = v-2 * v.dot(n) * n
                    dir = dir.minus(n.multiply(2).multiply(dir.dot(n)));
                }
        }
        move();
    }
}

Na classe GameView só precisamos passar o manager como parametro para Ball e finalmente a bolinha pode ficar rebatendo nas paredes.

O resultado até agora será algo como isso:

second-result


Agora precisamos oferecer alguma iteração com o usuário, vamos criar os pads que nada mais são que BlockableEntities que mudam sua posição de acordo com o toque.
package br.com.pontov.pieces;

import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Rect;
import br.com.pontov.math.Vector2D;

public class Pad extends BlockableEntity {
    private Paint wallPaint;

    private int defaultDistanceFromAxis;

    public Pad(Vector2D normal, int defaultDistance) {
        super(new Rect(), normal);
        wallPaint = new Paint();
        wallPaint.setColor(Color.GRAY);

        this.defaultDistanceFromAxis = defaultDistance;
    }

    public void notifyMotionEvent(float x, float y) {
                setBounds(new Rect((int) x - 150,
                        defaultDistanceFromAxis, (int) x + 150,
                        defaultDistanceFromAxis + 10))
    }

    @Override
    public void draw(Canvas canvas) {
        canvas.save();
        canvas.drawRect(getBounds(), wallPaint);
        canvas.restore();
    }

    @Override
    public void processAI() {
        // Do nothing, position is handled by events
    }
}

Essa classe muda sua posição através do setBounds, precisamos notificá-la dos eventos que o usuário tocou na tela, nós podemos adicionar ela no PiecesManager, mas ainda temos que ter a referencia dela para delegar os eventos, como implementar uma AI está fora do escopo desse artigo, podemos usar o suporte multi-touch dos devices para moverem os Pads separadamente.

Primeiro, criamos as variáveis para guardar as referencias dos nossos pads.

private Pad northPad;
private Pad southPad;

Agora inicializamos ele no método init e adicionamos ao PiecesManager para aproveitar o desenho automatizado dos objetos do nosso jogo.

northPad = new Pad(new Vector2D(0, -1), 80); //80 é a distancia default do eixo, no caso desenhar no 80 de y
manager.addPiece(northPad);
southPad = new Pad(new Vector2D(0, 1), 944);//944 do y
manager.addPiece(southPad);

A maneira mais simples de ouvir os eventos de toque é sobrescrevendo o método onTouchEvent(MotionEvent evt) na nossa GameView, podemos sobrescreve-lo e delegar o x e o y para os nossos pads.

public boolean onTouchEvent(MotionEvent evt) {
    southPad.notifyMotionEvent(evt.getX(), evt.getY());
    northPad.notifyMotionEvent(evt.getX(), evt.getY());
    return true;
}

Desse modo o evento vai mover os dois pads na mesma direção.

Como Pad já é uma BlockableEntity a nossa bolinha irá bater nele do mesmo modo que nas paredes sem mais nenhuma alteração necessaria.

A maioria dos devices com Android agora tem suporte a multi-touch, e utiliza-lo também é simples. Mas precisamos de uma permissão especial para isso, basta adicionar a seguinte linha no AndroidManifest.XML

Agora voltamos ao nosso onTouchEvent e vamos verificar os toques de múltiplos usuários, isso é feito através dos métodos getX(int pointer) getY(int pointer). Como nossa aplicação não precisa exatamente se importar com qual dedo está se movendo para tal lugar, vamos apenas adicionar suporte para que qualquer toque em uma área da metade do campo mova o pad daquele lado.

public boolean onTouchEvent(MotionEvent evt) {
    for (int i = 0; i < evt.getPointerCount(); i++) {
        float y = evt.getY(i);
        if (y > 612)
            southPad.notifyMotionEvent(evt.getX(i), evt.getY(i));
        else
            northPad.notifyMotionEvent(evt.getX(i), evt.getY(i));
    }

    return true;
}

Desse modo dois usuarios podem jogar tocando em uma area da tela.

O resultado até aqui:

third-result


Agora que cansamos de ver essa bolinha vermelha kikando pela tela, vamos colocar uma imagem como essa:

Para utiliza-la é facil, primeiro salve esse arquivo dentro da pasta res/drawable-hdpi e voltamos a nossa classe Ball.

A maneira mais fácil de carregar uma imagem é através dos Resources.

Como nossa classe Ball não tem acesso a ela vamos modificar o construtor para aceitar apenas um Bitmap e carregar a imagem na nossa GameView, também modificar o método draw para desenhar a imagem com drawBitmap no lugar de drawCircle com uma cor sólida.

Precisamos guardar a referencia da imagem em um objeto Bitmap.

//Variável para guardar a referência
private Bitmap image;

No construtor apenas um novo argumento para receber esse novo parametro e colocar na variavel, e modificar o método draw para desenhar a imagem.

public void draw(Canvas canvas) {
    canvas.save();
    canvas.drawBitmap(image, pos.getX(),pos.getY(), paint);
    canvas.restore();
}

Agora na GameView podemos carregar a imagem e passar como referencia.

A única coisa necessária é utilizar a classe BitmapFactory para fazer o decode da imagem dos resources que nos referimos pelo id.

Bitmap image = BitmapFactory.decodeResource(getResources(), R.drawable.ball);

Agora passamos como referencia para Ball e terminamos o basico de um jogo de Pong.

E o resultado final da nossa aplicação é o seguinte:

final-result


Isso conclui nosso game de Pong, claramente é possível melhora-lo em vários aspectos e funcionalidades, mas até aqui já foi o suficiente para mostrar como fazer um jogo de Pong, a matematica envolvida e ainda como fazer isso no Android, espero que tenham aprendido mais sobre todas essas áreas.

Ainda é possivel utilizar aceleração nativa com OpenGL ES 2.0 no Android, mas isso é assunto para outro artigo.

Todo código da aplicação está disponível no repositório do AndroidTechsGames no github, com mais algumas alterações que fui implementando quando me sobrou tempo.


Comentários (86)
  • Developer
    avatar

    Java 2D? Usa Unity3D que é bem melhor.

  • Bruno Crivelari Sanches
    avatar

    Comparar uma linguagem de programação com um ferramenta de autoria não tem sentido algum.

    É o mesmo que comparar uma caixa de ferramentas com um robo e dizer que o robo é muito melhor. De fato, o robo faz mais coisas, mas você sempre vai estar restrito ao que o fabricante dele acha bom ou impõe a você, isso resolve o problema de boa parte das pessoas, mas existe um mundo além do unity e pessoas que não podem ficar preso as suas limitações.

    Eu mesmo tenho um projeto de uma empresa que já estamos analisando a melhor estratégia, pois chegamos no limite do unity e ele simplesmente não satisfaz nossos requisitos e é provavel que troquemos por outra tecnologia, talvez ogre, que a principio não faz tudo que o Unity faz, mas assim como o Java, não nos limita.

    T+

  • Júlio Brito
    avatar

    Que artigo legal Marcos. Esclarece muitas coisas que são úteis em diversos tipos de aplicações.

    Sobre o java 2D e Unity3D lá em cima. É bom saber que ambas usam opengl e apenas tem conceitos de uso diferentes.

  • Marcos Vasconcelos  - Ty!
    avatar

    Obrigado, essa foi minha intenção, fora explicar sobre jogos em geral mostrar como fazer isso no Android.

  • Marcos Koga  - Awesome!
    avatar

    Cara, muito bom o seu artigo. foi bem didático(até para quem não tem muito conhecimento em GameDev) e a escolha de fazer um pong é muito boa, pois além de ver as funcionalidades triviais em um jogo, tem um pouco de matemática ;3

    Veja se não tem como anexar uma parte a respeito do áudio =)

  • Marcos Vasconcelos  - Ty!
    avatar

    Valeu. Escolhi Pong pois usa um pouco de cada area essencial para um jogo.

    E é uma boa idéia sobre audio, mas isso vai ser assunto pra outro artigo.

  • Eduardo Bregaida  - Muito Bom
    avatar

    Parabéns Marky, ficou muito bom, vou ler os tutoriais de Android que colocou no seu blog, só preciso de tempo rsss B)

  • Marcos Vasconcelos  - Valeu!
    avatar

    Obrigado. Eu gastei um bom tempo escrevendo estes artigos. Espero que as pessoas também gastem para ler e aprender com eles.

  • Lucas Daltro  - Muito Bom!
    avatar

    Pow cara,muito bom o artigo:D
    Mas o android emulator tá travando que só aqui:(

  • Marcos Vasconcelos  - Valeu
    avatar

    Valeu. E realmente, o emulador é lento. Eu normalmente apenas vejo se funciona corretamente no emulador depois testo em um device.

  • Lucas Daltro
    avatar

    Queria pode instalar o android no meu BlocK Berry...A cada dia que passa eu me arrependo mais de ter comprado um celular chinês :angry:

  • Marcos Vasconcelos  - True
    avatar

    Para quem quer desenvolver mobile não compensa comprar um desses.

  • Marcelo  - Dúvida
    avatar

    Marcos, estou com uma dúvida, no arquivo ComplexGameView.java, método init(), lá dentro tem um laço for que itera só uma vez. Qual era sua intenção nesse laço?

  • Marcos Vasconcelos
    avatar

    Na verdade, é que eu havia adicionado muitas bolinhas na tela para rebater todas. Mas para tirar as pics pro artigo eu só coloquei 1 para tirar uma foto com apenas uma bolinha.

  • Cristiano Marçal Toniolo  - Como executar o JPong no AndroidStudio?
    avatar

    Boa noite Marcos,

    Tudo bem? Sou novo na programação para Jogos e seu tutorial é muito interessante e esclarecedor, mas quando tentei rodar o projeto no AndroidStudio, não me dá a permissão para acessar as Virtual Devices da minha máquina. Como posso resolver isso?

    Atenciosamente,

    Cristiano

  • João Pagotto  - Rotação de Imagens PNG
    avatar

    Olá parabéns pelo artigo.

    Gostaria de fazer uma bussula customizada para o Android, aí vem o problema hehehe. Como fazer uma rotação de uma imagem PNG no Draw do Android ?

    [']s

  • Marcos Vasconcelos
    avatar

    voce faz isso girando o Canvas com o método rotate(float graus)

  • Marcelo Barros  - Rotação
    avatar

    Seu artigo esta muito bom mesmo, mts parabens.
    Sera que me pode ajudar, imagina que pintamos uma roda, e giramos o dedo a volta dela, que detecte se estamos girando na direcção dos ponteiros do relogio ou ao contrario.

    Abraço.

  • Vinícius Godoy de Mendonça
    avatar

    Isso você resolve facilmente através da classe de vetores. Tendo dois pontos (o do início e o do fim do movimento), use o método angleSign para obter o angulo entre eles, com sinal.

    O sinal indica se o sentido é horário ou anti-horário.

  • Marcelo Barros  - Rotação
    avatar

    Não entendi muito bem, imagina que eu começo num ponto, e dou uma volta de 180 graus na direcao do relogio, e não dei uma volta 180 graus ao contrario do ponteiro do relogio.

    Desculpa a ignorancia.

    Cumprimentos.

  • Vinícius Godoy de Mendonça
    avatar

    Você leu chegou a ler o link sobre vetores? http://bit.ly/usovetores

  • Marcelo Barros
    avatar

    Deu jeito, vou usar Produtos Escalares.

    Voces tem alguma comunidade, onde me possa juntar?

    Abraço.

  • Vinícius Godoy de Mendonça
    avatar

    Nós somos participantes ativos do fórum programadores de jogos:
    http://www.programadoresdejogos.com.br

  • Marcelo Barros  - OnFling
    avatar

    Ando a dias com isto.

    Tenho a minha classe principal "main" (Activity), criei uma class que estende de uma imageview "ImageViewI" e logo adiciona a minha classe principal (activity).

    Eu quero detectar um onfling mas quando este é sobre a minha classe "ImageViewI", sera que posso nessa class implementar OnGestureListener, ou se for nesta mesma class como nao é activity nao vai fazer nada.
    Posso de alguma maneira fazer isto na minha class main, para que so de bola quando o onfling é sobre a minha "ImageViewI".

    Desculpem ser chato.

    Abraço.

  • Marcelo Barros  - Resolvido
    avatar

    Penso que o tenho resolvido, na verdade não precisso usar um onfling.
    Com isto ja me resolve, e uma boa opcão?

    "meucomponente".setOnTouchListener(new OnTouchListener() {

    @Override
    public boolean onTouch(View v, MotionEvent event) {

    //meus metodos
    return false
    }

    });

  • Marcos Vasconcelos
    avatar

    Assim como no Swing, voce pode implementar um Listener para cada componente, então voce pode implementar no seu ImageView e ainda ter listeners em outros lugares.

  • Junior  - Não consegui
    avatar

    Grande Marcos, não consegui rodar este exemplo.

    No console do eclipse não aparece nenhum erro, as mensagens finais são:

    [2011-04-30 11:21:29 - GameView] Success!
    [2011-04-30 11:21:29 - GameView] Starting activity br.com.pontov.AndPongActivity on device emulator-5554
    [2011-04-30 11:21:31 - GameView] ActivityManager: Starting: Intent { act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] cmp=br.com.pontov/.AndPongActivity }

    E na Tela do Emulador aparece "Sorry - The Application jPong (process br.com.pontov) has stopped unexpectedly. Please try again."

    Fiquei na dúvida se fiz algo correto. QUando criei o novo projeto uma nova classe chamada AndPongActivity é criada e criei uma nova chamada GameView. Percebi que AndPongActivity fica em br.com.pontov e GameView em br.com.pontov.jpong. Sera que isso ?

  • Marcos Vasconcelos
    avatar

    Entao, o erros do Android, são mostrados na View LogCat do Eclipse.
    Para abri-lo vá em:
    Window > Show View> Other... > +Android > LogCat

    Esse é como o Console, mas mostra as informações do que acontece no emulador.

    Seu StackTrace estará lá.

    Da uma olhada e poste novamente.

  • Junior  - Stack Trace
    avatar

    Valeu pela resposta Marcos, fui na perspectiva DDMS e la encontrei o LogCat. Segue o filtro considerando somente os erros do PID de meu aplicativo:

    Uncaught handler: thread main exiting due to uncaught exception
    java.lang.RuntimeException: Unable to start activity ComponentInfo{br.com.pontov/br.com.pontov.AndPongActivity}: android.view.InflateException: Binary XML file line #1: Error inflating class linearlayout
    at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2 496)
    at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:25 12)
    at android.app.ActivityThread.access$2200(ActivityThread.java:119)
    at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1863) at android.os.Handler.dispatchMessage(Handler.java:99)
    at android.os.Looper.loop(Looper.java:123)
    at android.app.ActivityThread.main(ActivityThread.java:4363)
    at java.lang.reflect.Method.invokeNative(Native Method)
    at java.lang.reflect.Method.invoke(Method.java:521)
    at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit. java:860)
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:618)
    at dalvik.system.NativeStart.main(Native Method)
    Caused by: android.view.InflateException: Binary XML file line #1: Error inflating class linearlayout
    at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:576)
    at android.view.LayoutInflater.inflate(LayoutInflater.java:385)
    at android.view.LayoutInflater.inflate(LayoutInflater.java:320)
    at android.view.LayoutInflater.inflate(LayoutInflater.java:276)
    at com.android.internal.policy.impl.PhoneWindow.setContentView(PhoneWindo w.java:198)
    at android.app.Activity.setContentView(Activity.java:1622)
    at br.com.pontov.AndPongActivity.onCreate(AndPongActivity.java:11)
    at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java: 1047)
    at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2 459)
    ... 11 more
    Caused by: java.lang.ClassNotFoundException: android.view.linearlayout in loader dalvik.system.PathClassLoader@44e8c790
    at dalvik.system.PathClassLoader.findClass(PathClassLoader.java:243)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:573)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:532)
    at android.view.LayoutInflater.createView(LayoutInflater.java:466)
    at android.view.LayoutInflater.onCreateView(LayoutInflater.java:544)
    at com.android.internal.policy.impl.PhoneLayoutInflater.onCreateView(Phon eLayoutInflater.java:66)
    at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:563)
    ... 19 more
    Unable to open stack trace file '/data/anr/traces.txt': Permission denied

  • Marcos Vasconcelos
    avatar

    Hmm...

    "android.view.linearlayout"

    O correto é LinearLayout (letras maiusculas)

  • Marcelo Barros  - Selection
    avatar

    Ola,

    Desculpa postar isto aqui, mas não sei como entrar em contacto com voce e a verdade é que tenho certeza que voce pode resolver isto.

    Tenho uma listview e quero fazer um setSelection(pos) e que a linha que foi selecionada mude de cor, isto sem ter de recorrer necessariamente a codigo.

    Visto que eu ja tenho um estilos, um bocado do que esta defenido


    Quando ponho o dedo em cima da linha ela muda para a cor azul, mas quando tiro volta ao normal, não fica com a cor de seleccionado.
    Mas a parte de isto eu queria com o método setSelection(pos) escolher uma linha e que ela ficasse igualmente selecccionada e mudasse de cor.

    Cumprimentos.

  • Marcos Vasconcelos
    avatar

    O melhor lugar para voce postar isso seria no forum de Android no www.guj.com.br


    Mas respondendo a sua duvida, voce vai precisar guardar o indice de onde voce está selecionando e modificar o seu Adapter para retornar a linha desse indice com a cor de fundo diferente.

  • Marcelo Barros
    avatar

    Desculpa estar a chatear, mas "modificar o seu Adapter para retornar a linha desse indice com a cor de fundo diferente", dizes fazer via codigo, o genero de um metod que altera o background?
    Nativamente e com os estilos xml nao e possivel?

  • Marcos Vasconcelos
    avatar

    Talvez até seja, mas eu digo programaticamente mesmo.

  • derUbar  - MapView
    avatar

    Olà,

    Vc saberia se e possivel criar um poligono delimitando uma area no mapview no emulador do android?

    Eu gostaria de trabalhar com poligonos igual a funçao do google maps.

  • Marcos Vasconcelos
    avatar

    Eu não entendi sua pergunta.

    Se o que voce quer é criar aqueles desenhos que aparecem como popup no Google Maps por poligonos, é possivel sim.

    Voce tem o seu objeto Path e tem que dar um translate nele antes de desenha-lo

  • derUbar  - Mapa
    avatar

    Eu tenho o mapa em meu emulador, no google maps existem a opçao criar mapa, nessa opçao eu posso criar linhas, poligonos, marcar locais com objetos e marcar trajetos via estradas.

    Eu precisaria ter essas funçoes em meu mapa no android. Ou pelo menos a funçao de criar poligonos.

  • Java Player
    avatar

    Onde encontro o código da classe:

    br.com.pontov.Vector2D ?

    Está numa biblioteca disponível para download?

    Obrigado

  • Vinícius Godoy de Mendonça
    avatar

    Está nesse artigo: http://bit.ly/usovetores

  • Jeferson
    avatar

    Ola Marky, estou tendo o mesmo problema do junior tambem.. a stack trace esta identica.. mas, mudando de linearlayout para LinearLayout. obtive o mesmo erro, a configuração do projeto, e as classes estao exatamente como voce demostrou no tutorial.. o que pode ser ?

  • Marcos Vasconcelos
    avatar

    Cara, da uma olhada melhor nos XMLs, por que a pouco tempo descobri que é o CSS do PontoV que deixa tudo minusculo.

  • Marcos Almeida  - Problemas com GoogleMaps
    avatar

    Marcos Vasconcelos boa noite,

    Estou tentando plotar um simples mapa no android, mais esta muito complicado. Não sei o que faço de errado.


    Recebo a mensagem de erro abaixo:

    Sorry! The application HelloMap ( process org.android.maps ) has stopped unexpectedly. Please try again

    View image
    E esse é o erro:


    ERROR/Zygote(33): setreuid() failed. errno: 2
    10-11 02:54:33.144:
    ERROR/Zygote(33): setreuid() failed. errno: 17
    10-11 02:54:34.634:
    ERROR/BatteryService(59): usbOnlinePath not found
    10-11 02:54:34.634:
    ERROR/BatteryService(59): batteryVoltagePath not found
    10-11 02:54:34.634:
    ERROR/BatteryService(59): batteryTemperaturePath not found
    10-11 02:54:34.654:
    ERROR/SurfaceFlinger(59): Couldn't open /sys/power/wait_for_fb_sleep or /sys/power/wait_for_fb_wake
    10-11 02:54:42.234:
    ERROR/PackageManager(59): Package com.android.gesture.builder signatures do not match the previously installed version; ignoring!
    10-11 02:54:43.636:
    ERROR/EventHub(59): could not get driver version for /dev/input/mouse0, Not a typewriter
    10-11 02:54:43.636:
    ERROR/EventHub(59): could not get driver version for /dev/input/mice, Not a typewriter
    10-11 02:54:43.843:
    ERROR/System(59): Failure starting core service
    10-11 02:54:43.843:
    ERROR/System(59): java.lang.SecurityException
    10-11 02:54:43.843:
    ERROR/System(59): at android.os.BinderProxy.transact(Native Method)
    10-11 02:54:43.843:
    ERROR/System(59): at android.os.ServiceManagerProxy.addService(ServiceManagerNative.java:14 6)
    10-11 02:54:43.843:
    ERROR/System(59): at android.os.ServiceManager.addService(ServiceManager.java:72)
    10-11 02:54:43.843:
    ERROR/System(59): at com.android.server.ServerThread.run(SystemServer.java:184)
    10-11 02:54:45.074:
    ERROR/SoundPool(59): error loading /system/media/audio/ui/Effect_Tick.ogg
    10-11 02:54:45.093:
    ERROR/SoundPool(59): error loading /system/media/audio/ui/KeypressStandard.ogg
    10-11 02:54:45.093:
    ERROR/SoundPool(59): error loading /system/media/audio/ui/KeypressSpacebar.ogg
    10-11 02:54:45.104:
    ERROR/SoundPool(59): error loading /system/media/audio/ui/KeypressDelete.ogg
    10-11 02:54:45.104:
    ERROR/SoundPool(59): error loading /system/media/audio/ui/KeypressReturn.ogg
    10-11 02:54:48.543:
    ERROR/ThrottleService(59): Could not open GPS configuration file /etc/gps.conf
    10-11 02:54:50.474:
    ERROR/logwrapper(142): executing /system/bin/tc failed: No such file or directory
    10-11 02:54:50.554:
    ERROR/logwrapper(143): executing /system/bin/tc failed: No such file or directory
    10-11 02:54:50.723:
    ERROR/logwrapper(144): executing /system/bin/tc failed: No such file or directory
    10-11 02:55:04.493:
    ERROR/HierarchicalStateMachine(59): TetherMaster - unhandledMessage: msg.what=3
    10-11 02:55:27.363:
    ERROR/AndroidRuntime(300): FATAL EXCEPTION: main
    10-11 02:55:27.363:
    ERROR/AndroidRuntime(300): java.lang.RuntimeException: Unable to instantiate activity ComponentInfo{org.android.maps/org.android.maps.HelloMaps}: java.lang.ClassNotFoundException: org.android.maps.HelloMaps in loader dalvik.system.PathClassLoader[/system/framework/com.google.android.map s.jar:/data/app/org.android.maps-1.apk]
    10-11 02:55:27.363:
    ERROR/AndroidRuntime(300): at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2 585)
    10-11 02:55:27.363:
    ERROR/AndroidRuntime(300): at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:26 79)
    10-11 02:55:27.363:
    ERROR/AndroidRuntime(300): at android.app.ActivityThread.access$2300(ActivityThread.java:125)
    10-11 02:55:27.363:
    ERROR/AndroidRuntime(300): at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2033) 10-11 02:55:27.363:
    ERROR/AndroidRuntime(300): at android.os.Handler.dispatchMessage(Handler.java:99)
    10-11 02:55:27.363:
    ERROR/AndroidRuntime(300): at android.os.Looper.loop(Looper.java:123)
    10-11 02:55:27.363:
    ERROR/AndroidRuntime(300): at android.app.ActivityThread.main(ActivityThread.java:4627)
    10-11 02:55:27.363:
    ERROR/AndroidRuntime(300): at java.lang.reflect.Method.invokeNative(Native Method)
    10-11 02:55:27.363:
    ERROR/AndroidRuntime(300): at java.lang.reflect.Method.invoke(Method.java:521)
    10-11 02:55:27.363:
    ERROR/AndroidRuntime(300): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit. java:868)
    10-11 02:55:27.363:
    ERROR/AndroidRuntime(300): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:626)
    10-11 02:55:27.363:
    ERROR/AndroidRuntime(300): at dalvik.system.NativeStart.main(Native Method)
    10-11 02:55:27.363:
    ERROR/AndroidRuntime(300): Caused by: java.lang.ClassNotFoundException: org.android.maps.HelloMaps in loader dalvik.system.PathClassLoader[/system/framework/com.google.android.map s.jar:/data/app/org.android.maps-1.apk]
    10-11 02:55:27.363:
    ERROR/AndroidRuntime(300): at dalvik.system.PathClassLoader.findClass(PathClassLoader.ja...

  • Marcos Vasconcelos
    avatar

    Olá,

    Primeiro, voce nao precisa de toda essa StackTrace, a parte importante é:

    java.lang.RuntimeException: Unable to instantiate activity ComponentInfo{org.android.maps/org.android.maps.HelloMaps}: java.lang.ClassNotFoundException: org.android.maps.HelloMaps in loader dalvik.system.PathClassLoader[/system/framework/com.google.android.map s.jar:/data/app/org.android.maps-1.apk]

    Voce tem certeza que essa classe existe nesse lugar? Voce declarou ela no AndroidManifest.xml?

  • irineu  - nada
    avatar

    Irineu :evil:

  • Lucas  - Jogo
    avatar

    Olá você poderia me mandar as pastas já com o jogo só pra min testar aqui.. pois esta dando muito erro quando tento criar através dos códigos q você fez...
    obrigado

    meu email
    martins_lucas1@yahoo.com.br

  • Marcos Vasconcelos
    avatar

    Baixou do repositorio no github?

    https://github.com/MarkyVasconcelos/AndroidTechsGames

  • ViniciusFreitas  - Point2D
    avatar

    Baixei o fonte do Vector2D mais não funciona da erro dizendo que esta faltando o pacote java.awt.geom.Point2D, como resolvo isso?

  • ViniciusFreitas
    avatar

    Baixei o fonte do Vector2D mais da erro dizendo que falta o java.awt.geom.Point2d

  • Diogo Barbosa
    avatar

    Marcos, da uma força ai.

    "super(new Rect())";
    Essa linha referente ao construtor da classe ball está dando erro aqui...
    Essa chamada a super está realmente válida?

  • Marcos Vasconcelos
    avatar

    Arrumado, isso só é valido depois que Ball extends Entity.

    Obrigado por avisar.

  • Anônimo
    avatar

    :woohoo: Adorei, você pretende ensinar tudo o que der sobre fazer jogos no Android? Gostaria muito de aprender a fazer aqueles efeitos de magia.

  • sergio
    avatar

    Marcos gostaria de saber o que vc me indica, para uma aplicação do tipo controle de temperatura no android com animação do tipo, terei um termometro e a medida que a temperatura aumenta ele muda tb a escala nele, tipo como se o nivel de mercurio sobe ou desce. pegarei os dados dessa temperatura via web usando sockets, o que preciso mesmo é a parte da animação


    Parabéns pelo artigo

  • Marcos Vasconcelos
    avatar

    Eu faria na mão mesmo (interpolar os valores através do tempo), com o termometro sendo uma View sua que tem todas as logicas de animação.

  • Anônimo  - Muito BOm o Post
    avatar

    mas gostaria de saber se nao tem um material sobre a programação andoroid voltada a jogos

  • Fernando França  - Dúvida sobre handler...
    avatar

    Olá primeiramente parabéns pelo artigo, pois é graças a pessoas como vc que eu venho aprendendo e muito nessa minha longa jornada android!
    Com base no seu artigo eu estou desenvolvendo um marcador de tempo ultilisando o handler.
    Funciona da seguinte forma: O cara escolhe a quantidade de batidas por minuto e o sistema fica marcando esse tempo com "clicks".
    Está acontecendo que está havendo um atraso em milisegundos segundo meu logcat.
    Como essa seria uma ferramenta de precisão, não poderia atrasar nem um mísero milisegundo...
    Usar o handler é uma boa opção ou existe uma melhor para esse caso?
    Obs: trava tanto no emulador quanto no celular pois acompanhei com um cronometro.
    Se você puder me ajudar mais ainda eu ficarei agradecido!
    vlw!!!

  • Marcos Vasconcelos
    avatar

    Fico feliz de poder ajudar na sua jornada.

    Sobre sua questão, voce não tem controle de que as mensagens do handler vão ser processadas assim que enviadas, então voce não pode garantir a precisão que precisa.

    No seu caso, voce deveria implementar o loop do jogo para guardar o tempo, roda-lo na main-thread e ir atualizando a tela pela diferença do tempo desde o ultimo loop, mas nessa abordagem os eventos de toque devem ser enviados para uma fila de mensagens para serem processados na fase proccessLogics(long uptime).

    Acredito que o ViniGodoy seria a pessoa ideal para falar sobre essa tecnica.

  • Fernando França  - Valew!
    avatar

    Valeu Marcos, vou estudar seguindo esse direcionamento seu. Assim que estiver pronto eu te mando o link para vc dar uma olhada!

  • Anonimo  - Vcs
    avatar

    Valeu cara espero q post mais
    comandos mas esse ai ja da pra desenvolver pelo menos um jogo que nem bounce?

  • Gabriel  - Dúvidas
    avatar

    Olá, Marcos..parabéns pelo post, gostei muito..
    estava seguindo seu tutorial e logo no começo (na primeira página) travei em uma coisa...

    toda vez q adiciono no arquivo XML e coloco isso


    da erro e o emulador desliga a aplicação..
    sabe oque pode ser??...
    parece q ele nao aceita o

    abraços e valeu =]

  • Gabriel
    avatar

    acho q nao foi a linha do erro "^^
    mas eh na ultima parte da primeira pagina, no arquivo XML
    acho q o problema eh no br.com.pontov.gameview

    mas nao sei como resolver
    =[

  • Marcos Vinicius
    avatar

    Eu estou no 2º ano de ciência da computação e eu e meu grupo (3 karas) estamos usando muito o Java2D para programarmos uma cópia do jogo pokemon, é muito bacana kara, experiencia muito boa, principalmente pra mim que sou o mais iniciante do grupo, estou aprendendo muito e estou apaixonado pelo desenvolvimento de jogos!!! Estudando C++ aqui no site de vcs (que por sinal é ótimo)!!! Comprando livros e tal. Muito bom ter um local pra debater sobre.

  • Arthur Alves  - MUito obrigado!
    avatar

    Esse artigo me ajudou muito, consegui recriar um "pong" m android do meu jeito e fiz várias alterações.

  • dougllas  -  pool piscina
    avatar

    ola muito bom o tutotrial saber eu gostaria de um tutotial explicando o uso de pool piscina de objetos usando a reciclagen sou iniciante :pinch:
    estou lendo um livro mais os esemplo esta muito complexo pelo meno para min agradeço desde ja

  • Rodrigo  - Não achei o metodo plusMe ...
    avatar

    Não encontrei o metodo plusMe ???

  • Rodrigo  - re: Não achei o metodo plusMe ...
    avatar

    Não encontrei o metodo plusMe ??? não está no arquvio Vector2D

  • Tyandrer  - Problemas com a Vectod2D
    avatar

    Muito bom seu tutorial amigo...estou tentando conclui-lo, porém na classe Vector2D, ele usa uma classe "Point2D" do java.awt.geom e essa classe não consegui importar para meu projeto...Pesquisei artigos relacionados na internet e pelo que vi a Point2D não pode ser usada no android, alternativas seriam a Point ou PointF, mas elas não aceitam parâmetros "Double". Sou iniciante no assunto, desculpe se estiver falando besteira, mas não consegui resolver.

  • Vinicius Godoy
    avatar

    Simplesmente remova esse método se estiver no Android. Ela se aplica só ao JavaSE.

  • Tyandrer  - Método faltante
    avatar

    Obrigado amigo...havia conseguido resolver, estou com um problema agora no método "dir.minus" do código que controla a colisão...na classe Vector2D que baixei aqui no site não tem esse método, houve outro que não tinha também, mas substitui por um que creio que faça a mesma coisa, porém o nome era diferente. Eraa esse "pos.plusMe" e usei o "pos.addMe".

  • Vinicius Godoy
    avatar

    Provavelmente o minusMe deve ter sido substituído por subtract me.

  • Igor Baad
    avatar

    Olá Amigo boa noite,

    O método "plusMe" não está na classe Vector2D..
    Gostaria de saber como proceder?

  • Vinícius G. de Mendonça
    avatar

    O método plusMe seria implementado assim:

    Código:
    public Vector2D plusMe(Vector2D other) {
    x += other.x;
    y += other.y;
    return this;
    }

    O mesmo vale para qualquer método com "Me" no final, significando "em mim", ou seja, usando += ao invés de +.

  • Igor Baad
    avatar

    Obrigado Vinicius!

  • Francisco  - Classe Vector2D
    avatar

    Eu gostaria muito de saber como foi que você usou essa classe Vector2D no Android.

  • Paulo Márcio  - ViewGroup dúvida
    avatar

    Olá, acompanhar o artigo me ajudou bastante a entender um pouco mais do android, mas algumas aplicações preciso fazer os desenhos e processar botões ao mesmo tempo, prequisando na web encontrei o ViewGroup, no entanto quando eu o incluo como contentView na activity ele só fica com a tela branca e nada acontece, nem mesmo os botões que adcionei nele são desenhados.

    O código é igual ao que você apresentou aqui, a única diferença que ao invés de uma View eu extendi uma ViewGroup e também tem o processamento de dados que é diferente, mas na View tudo funciona como esperado, se puderem ajudar eu agradeço.

  • Anônimo
    avatar

    Bem fui baixar o eclipse e a jdk. E me deparei com Android Studio, e agora ...Como estou iniciando agora, não faço ideia que vantagem tenho em programar com ou outro. Bem o unico conhecimento que estou começando orintação de objetos java. Uso netbeans .

  • Luca  - Duvida
    avatar

    Bom dia, cara quando vc cita no texto "Voltamos ao AndPongActivity" essa AndPongActivity é uma classe? se não, onde fica

  • Fernanda
    avatar

    Você não teria o pacote com o codigo pronto, pq aqui não esta funcionando. Obg =)

  • Fernanda
    avatar

    Bom dia vc não teria o pacote com os codigos, pq aqui não esta funcionado

  • Anônimo  - Erro ao tentar excutar
    avatar

    Compila nomalmente, mas quando vai abrir no emulador dá erro. No LogCat apresenta o log abaixo:
    Por favor me ajude... :(
    ---------------------------------------------------------------------- -------------------
    11-28 15:44:49.132: D/AndroidRuntime(705): Shutting down VM
    11-28 15:44:49.132: W/dalvikvm(705): threadid=1: thread exiting with uncaught exception (group=0x4001d800)
    11-28 15:44:49.142: E/AndroidRuntime(705): FATAL EXCEPTION: main
    11-28 15:44:49.142: E/AndroidRuntime(705): java.lang.RuntimeException: Unable to start activity ComponentInfo{br.com.pontov/br.com.pontov.AndPongActivity}: java.lang.IllegalStateException: You need to use a Theme.AppCompat theme (or descendant) with this activity.
    11-28 15:44:49.142: E/AndroidRuntime(705): at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2 663)
    11-28 15:44:49.142: E/AndroidRuntime(705): at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:26 79)
    11-28 15:44:49.142: E/AndroidRuntime(705): at android.app.ActivityThread.access$2300(ActivityThread.java:125)
    11-28 15:44:49.142: E/AndroidRuntime(705): at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2033) 11-28 15:44:49.142: E/AndroidRuntime(705): at android.os.Handler.dispatchMessage(Handler.java:99)
    11-28 15:44:49.142: E/AndroidRuntime(705): at android.os.Looper.loop(Looper.java:123)
    11-28 15:44:49.142: E/AndroidRuntime(705): at android.app.ActivityThread.main(ActivityThread.java:4627)
    11-28 15:44:49.142: E/AndroidRuntime(705): at java.lang.reflect.Method.invokeNative(Native Method)
    11-28 15:44:49.142: E/AndroidRuntime(705): at java.lang.reflect.Method.invoke(Method.java:521)
    11-28 15:44:49.142: E/AndroidRuntime(705): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit. java:868)
    11-28 15:44:49.142: E/AndroidRuntime(705): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:626)
    11-28 15:44:49.142: E/AndroidRuntime(705): at dalvik.system.NativeStart.main(Native Method)
    11-28 15:44:49.142: E/AndroidRuntime(705): Caused by: java.lang.IllegalStateException: You need to use a Theme.AppCompat theme (or descendant) with this activity.
    11-28 15:44:49.142: E/AndroidRuntime(705): at android.support.v7.app.ActionBarActivityDelegate.onCreate(ActionBarAct ivityDelegate.java:110)
    11-28 15:44:49.142: E/AndroidRuntime(705): at android.support.v7.app.ActionBarActivity.onCreate(ActionBarActivity.ja va:99)
    11-28 15:44:49.142: E/AndroidRuntime(705): at br.com.pontov.AndPongActivity.onCreate(AndPongActivity.java:12)
    11-28 15:44:49.142: E/AndroidRuntime(705): at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java: 1047)
    11-28 15:44:49.142: E/AndroidRuntime(705): at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2 627)
    11-28 15:44:49.142: E/AndroidRuntime(705): ... 11 more
    11-28 15:44:52.702: I/Process(705): Sending signal. PID: 705 SIG: 9

  • Luis  - Solução
    avatar

    Olá!
    Eu estava com o mesmo problema, resolvi com os seguintes passos:

    1 - Verifique se a classe AndPongActivity está estendendo ActionBarActivity ou Activity. Ela deve estender a classe Activity.
    2 - No AndroidManifest remova o atributo android:theme="@style/AppTheme" da tag application se existir.

    Bons estudos!

  • Keyton Klaus  - Ótimo tutorial
    avatar

    Parabéns, estou estudando para Computação Gráfico, e este artigo está me ajudando muito. :woohoo:

  • Silvano Malfatti
    avatar

    Desenvolvi uma pequena engine para Android com OpenGL ES. É muito fácil de usar e pode ajudar. Abraços

    http://www.sourceforge.com/projects/andgraphics

  • Silvano Malfatti  - Android OpenGL ES Engine
    avatar

    O código é aberto, então podem alterar à vontade.

    Silvano Malfatti Escreveu:
    Desenvolvi uma pequena engine para Android com OpenGL ES. É muito fácil de usar e pode ajudar. Abraços

    http://www.sourceforge.com/projects/andgraphics
  • Mauricio Marques  - Dúvida
    avatar

    Como vc fez esses métodos getX() e getY() na Vector2D???

  • Moézio Leivas
    avatar
    Código:
    @Override
    public void processAI() {
    Rect bounds = new Rect((int) pos.getX() - 5, (int) pos.getY() - 5,
    (int) pos.getX() + 5, (int) pos.getY() + 5);

    for (Entity ent : pieces.getPieces()) {
    if (ent == this)
    continue;
    if (ent instanceof BlockableEntity)
    if (bounds.intersect(ent.getBounds())) {
    Vector2D n = ((BlockableEntity) ent).getNormal();
    // r = v-2 * v.dot(n) * n
    dir = dir.minus(n.multiply(2).multiply(dir.dot(n)));
    }
    }
    move();
    }

    Como colidir uma bolinha com outra?

Escrever um comentário
Your Contact Details:
Gravatar enabled
Comentário:
[b] [i] [u] [url] [quote] [code] [img]   
:angry::0:confused::cheer:B):evil::silly::dry::lol::kiss::D:pinch::(:shock:
:X:side::):P:unsure::woohoo::huh::whistle:;):S:!::?::idea::arrow:
Security
Por favor coloque o código anti-spam que você lê na imagem.
LAST_UPDATED2