# Bitmap mit OnClickListener



## Laren (23. Mrz 2012)

Hi,

Wir haben aktuell ein Spieleprojekt für die Uni, dass über Android realisiert werden soll.
Jetzt wollte ein mal ein kleines Projekt machen, wo man per Fingerklick z.b. kleine Marios ausschalten kann, die auf dem Bildschirm nacheinander erscheinen.

Mein Problem ist jetzt nur, dass ich ein ein "GameView" Klasse mit einem Bitmap "mario" habe, ich aber nicht weis, wie ich einen OnClickListener bei dem Bitmap erstellen kann. 
Was kann man tun?

Viele Grüße


```
public class GameView extends View{
	public GameView(Context context) {
		super(context);
		
	}
	@Override
	protected void onDraw(Canvas canvas) {
		super.onDraw(canvas);
		
		Bitmap mario = BitmapFactory.decodeResource(getResources(),
				R.drawable.djtk6ou8);
		canvas.drawBitmap(mario, 50, 50, null);
		
		
		
	}
}
```


----------



## schlingel (23. Mrz 2012)

Du musst den OnClickHandler deiner GameView und nicht dem Bitmap hinzufügen.

In dem Handler musst du dann anhand der Koordinaten bestimmen ob dein Mario angeklickt wurde oder nicht.


----------



## Laren (23. Mrz 2012)

danke dir, ich habs jetzt geändert, aber beim click, passiert leider gar nichts, eigentlich sollte er das Bitmap ändern?


```
public class GameView extends View implements OnClickListener{
	private Canvas ca;
	private Bitmap bmp;
	private float x=50;
	private float y=50;
	
	public GameView(Context context) {
		super(context);
		
		
	}
	@Override
	protected void onDraw(Canvas canvas) {
		// TODO Auto-generated method stub
		this.ca=canvas;
		super.onDraw(ca);
		bmp = BitmapFactory.decodeResource(getResources(),
				R.drawable.djtk6ou8);
		ca.drawBitmap(bmp, x, y, null);
		invalidate();
		
		
		
	}

	public void onClick(View v) {
		bmp = BitmapFactory.decodeResource(getResources(),
				R.drawable.ic_launcher);
		ca.drawBitmap(bmp, x, y, null);
	}
	
}
```


----------



## schlingel (23. Mrz 2012)

Geh doch mal deinen Code durch:

1. Du definierst deine Klasse GameView die von View ableitet und den OnClickListener implementiert. Das heißt ein jedes GameView-Objekt ist auch ein View-Objekt sowie ein OnClickListener-Objekt. Der OnClickListener hat nur die geklickte View als Parameter, aber nicht die Koordinaten des Klicks. (Mein Fehler, da hab ich Swing u. Android verwechselt.)
2. Du hast deine X und deine Y Koordinaten.
3. Machst du weder etwas mit x und y noch mit dem OnClickListener.

Was musst du machen?

- Das Objekt muss OnTouchListener implementieren. Siehe auch hier wie das geht.
- Im Touch-Event musst du die X und Y Koordinaten auf die des Klicks setzen.
- Du musst deinem GameView-Objekt noch sagen, dass es auf Klicks reagieren soll. Am besten im Konstruktor. 

```
this.setOnTouchListener(this);
```


----------



## Laren (31. Mrz 2012)

Sorry, ich bekomme es nicht hin
Eigentlich müsste doch jetzt, egal wo ich hin klicke das Bitmap geändert werden, oder?

Grüße


```
import android.app.Activity;
import android.os.Bundle;

public class KillMarioActivity extends Activity {
    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(new GameView(this));
        }
}
```


```
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnTouchListener;



public class GameView extends View implements OnTouchListener{
	private Canvas canvas;
	private Bitmap bmp;
	private float x=50;
	private float y=50;
	
	public GameView(Context context) {
		super(context);		
		this.setOnTouchListener(this);
	}
	
	/* (non-Javadoc)
	 * @see android.view.View#onDraw(android.graphics.Canvas)
	 */
	@Override
	protected void onDraw(Canvas canvas) {
		this.canvas=canvas;
		super.onDraw(canvas);
		bmp = BitmapFactory.decodeResource(getResources(),
				R.drawable.djtk6ou8);
		canvas.drawBitmap(bmp, x, y, null);
		invalidate();
				
	}
	
	/* (non-Javadoc)
	 * @see android.view.View.OnTouchListener#onTouch(android.view.View, android.view.MotionEvent)
	 */
	public boolean onTouch(View v, MotionEvent event) {
		bmp = BitmapFactory.decodeResource(getResources(),
				R.drawable.ic_launcher);
		canvas.drawBitmap(bmp, x, y, null);
		invalidate();
		return false;
	}
		
}
```


----------



## schlingel (31. Mrz 2012)

Lass mich raten, der gute Mario bleibt immer an der selben Stelle anstatt dass er dorthin hüpft wo du hintappst?

Prinzipiell hast du ja schon alles richtig gemacht mit dem Handler, allerdings setzt du das x und das y nie neu. Also weiß ja der gekillte Mario nix von seinen neuen Koordinaten.


```
public boolean onTouch(View v, MotionEvent event) {
        x = event.getX();
        y = event.getY();
        invalidate(); // invalidate stößt das zeichnen schon an, also macht 
                         //das canvas.drawBitmap(bmp, x, y, null); hier keinen Sinn.
       
        return false; // warum sagst du, du hast den Event noch nicht gehandelt? Hängen noch andere Handler dran?
    }
```

Damit sollte es dann laufen.


----------



## Laren (3. Apr 2012)

sorry, ich hab mich wohl flasch ausgedrückt, eigentlich soll der Mario durch einen Fingertipp auf ihn irgentwie platt sein
Also ein OnTouchListener auf das Bitmap, das die Grafik ändert.
Ich habe es jetzt schon mit ImageView probiert(wegen dem OnTouchListener) aber da kann ich den Mario nicht so schön über den Bildschirm laufen lassen, wie bei Bitmap.

Viele Grüße


----------



## schlingel (3. Apr 2012)

Dann fehlen hier noch einige Sachen. Folgendes hast du:
- Logik die auf eine Bitmap zeichnet
- Einen Tap-Listener der nichts macht.

Folgendes brauchst du:
- Logik die auf eine Bitmap zeichnet
- Logik die sich merkt wo der Maria gerade ist. (Am besten als Rect speichern)
- Logik im Tap-Listener die um deine x, y-Koordinaten eine Bounding-Box kreiert. Also z.B. so:

```
public boolean onTouch(View v, MotionEvent event) {
        int left = event.getX() - 20 >= 0 ? event.getX() - 20 : event.getX();
        int top = event.getY() - 20 >= 0 ? event.getY() - 20 : event.getY();
        int bottom = top <= v.getHeight() ? top + 40 : v.getHeight();
        int right = left + 40 <= v.getWidth ? left + 40 : v.getWidth();
               
        // mario wurde erwischt
        if(deinMarioObj.boundingBox().intersect(top, left, bottom, right)) {
          deinMarioObj.killed();
        } 

        return false; // warum sagst du, du hast den Event noch nicht gehandelt? Hängen noch andere Handler dran?
    }
```
- Eine Klasse GameObj welche die Zustände lebendig und tot kapselt. Sowie die Position. Wenn sich der Mario bewegen können soll wäre das auch ein gutes Plätzchen um die Logik dafür zu gestalten.

```
public class GameObj {
  private int xSpeed;

  private int ySpeed;

  private int xPos;

  private int yPos;

  private boolean alive;

  private Bitmap bmpAlive;

  private Bitmap bmpDead;

  public GameObj(int xPos, int yPos, int xSpeed, int ySpeed, Bitmap bmpAlive, Bitmap bmpDead) {
    this.xPos = xPos;
    this.yPos = yPos;
    this.xSpeed = xSpeed;
    this.ySpeed = ySpeed;
    this.bmpAlive = bmpAlive;
    this.bmpDead = bmpDead;
    this.alive = true;
  }

  public void tick() {
    xPos += xSpeed;
    yPos += ySpeed;
  }

  public void killed() {
    alive = false;
  }

  public Rect boundingBox() {
  }

  public Bitmap graphic() {
    return alive ? bmpAlive : bmpDead;
  }

  // getter/setter
}
```
- Diese Klasse verwendest du um deinen Mario zu initialisieren. Du kannst diese sehr einfache Klasse auch gerne umschreiben damit der Mario von Wänden abprallt oder ähnliches. Die Zeichenmethode schaut dann so aus:

```
@Override
    protected void onDraw(Canvas canvas) {
        this.canvas=canvas;
        super.onDraw(canvas);
        canvas.drawBitmap(deinMarioObj.graphic(), deinMarioObj.getX(), deinMarioObj.getY(), null);
        invalidate(); // übrigens <- schlechter stil hier die gameloop zu implementieren, die gehört 
                         //eigentlich in einen eigenen thread
                
    }
```


----------



## schlingel (3. Apr 2012)

Ärgerlicherweise kann ich hier nicht meinen Beitrag ändern. Die Methode boundingBox() muss natürlich so programmiert sein:


```
public Rect boundingBox() {
  return new Rect(getX(), getY(), getX() + graphic().getWidth(), getY() + graphic().getHeight());
}
```


----------

