onClick hierarchy
I'm creating some little sprites with a bmp inside the constructor of another view as background. But when I click the sprites, that have their onClickListener, the view I'm clicking is the backgr开发者_如何学JAVAound view.
Some code:
My constructor:
public ToposGameView(Context context) {
super(context);
moles = new ArrayList<MoleSprite>();
setFocusable(true);
setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
Log.i(tag, "Click en GameView");
}
});
gameLoopThread = new GameLoopThread(this);
int id = 0;
for(int x = 0; x<3; x++){
for(int y = 0; y<4 ; y++){
MoleSprite mole = new MoleSprite(this, x*WIDTH/3, HEIGHT/6+y*HEIGHT/6, FRONT);
mole.setId(id);
id++;
moles.add(mole);
}
}
holder = getHolder();
holder.addCallback(new Callback() {
@Override
public void surfaceDestroyed(SurfaceHolder arg0) {
boolean retry=true;
gameLoopThread.setRunning(false);
while(retry){
try{
gameLoopThread.join();
retry=false;
}catch(InterruptedException i){
}
}
}
@Override
public void surfaceCreated(SurfaceHolder arg0) {
gameLoopThread.setRunning(true);
gameLoopThread.start();
}
@Override
public void surfaceChanged(SurfaceHolder arg0, int arg1, int arg2,
int arg3) {
// TODO Auto-generated method stub
}
});
}
Sprite's constructor:
public MoleSprite(ToposGameView gameView, int x, int y, int direction) {
super(gameView.getContext()); //TODO
bmp = BitmapFactory.decodeResource(getResources(), R.drawable.bad1);
this.width = bmp.getWidth() / BMP_COLUMNS;
this.height = bmp.getHeight() / BMP_ROWS;
this.x=x;
this.y= y;
this.setClickable(true);
this.setFocusable(true);
this.setFocusableInTouchMode(true);
setOnClickListener(this);
setOnTouchListener(this);
//I don't know what else to do!
}
It's my first question, please ask me for more info.
Edit1:
public class MoleSprite extends View implements OnClickListener, OnTouchListener{
public class ToposGameView extends SurfaceView{
Your mixing Surface drawing with View drawing. Surfaces are great for rapid asynchronous redraws (such as games), but they are not View containers. That is, there is no addView method on SurfaceView that is required for events and layouts.
As such, you will need to implement onClick handling on your SurfaceView and manually implement the detection of which Sprite is being clicked (e.g., is the click event within the sprite's x/y/width/height bounding box).
Also, it doesn't make sense for MoleSprite to extend View if used this way. I expect you'll want to make your own Sprite base class to support the bounding boxes and drawing callbacks. You can also add the onClick(..) interface to the Spirte base class, but you'll probably also want to keep separate lists for drawable/moveable/clickable items to optimize your list iterations as you develop your game.
Good luck!
i don't know what your GameLoopThread is doing, but it should be calling your surface's onDraw method, and updatePhysics method.
the update physics will loop through your sprites and give them information, like the current game time, so they can move the proper distance, change the animation frame, or whatever.
for a sprite base class I use something like this (but mine handles animations, accelerations and other stuff):
public class Sprite {
private Rect mScreenRect;
public Sprite() {
// init some stuff here, if you need it
// especially, somewhere in your init functions
// set your bounding rect
this.mScreenRect = Rect(xl, yt, xr, yb);
}
setStuff(int thing) {
// like setX(), setY()
}
// here is the good stuff
public boolean isTouched(int x, int y) {
if(mScreenRect.contains(x, y))
return true;
else
return false;
}
// also include a function to draw the graphic
public void drawGraphic(Canvas canvas) {
canvas.drawBitmap(mBitmap, mScreenRect.left, mScreenRect.top, null);
}
}
then, in your surface view you need to use the:
@Override
public boolean onTouchEvent(MotionEvent event) {
// this setup will move the sprite on the screen
switch(event.getAction()) {
case MotionEvent.ACTION_DOWN:
if(sprite.isTouched(event.getX(), event.getY()) {
// do your stuff
}
break;
case MotionEvent.ACTION_MOVE:
// handle the moving pointer
sprite.setCoords(event.getX(), event.getY());
break;
case MotionEvent.ACTION_UP:
// handle the exiting pointer
sprite.setCoords(event.getX(), event.getY());
break;
}
}
then in the surface view again:
@Override
public void onDraw(Canvas canvas) {
sprite.drawGraphic(canvas)
}
there are other posts that cover this in a more detailed manner, but this will get you started.
精彩评论