I am a beginner working with graphics. Right now I have an image displayed in random places on the screen. What I would like to do that if the image is touched, it should be replaced by another image. How can I do that?
Another thing I currently am using a class within a class.Thanks
public class MainActivity extends ActionBarActivity implements OnTouchListener{
MyGameGraphics myGraphics;
TextView tvScore, tvPlayerScore;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
tvScore = (TextView)findViewById(R.id.showScore);
tvPlayerScore = (TextView)findViewById(R.id.playerScore);
myGraphics = new GraphicsMain(this);
myGraphics.setOnTouchListener(this);
setContentView(myGraphics);
}
#Override
protected void onPause(){
super.onPause();
myGraphics.pause();
}
#Override
protected void onResume(){
super.onResume();
myGraphics.resume();
}
#Override
public boolean onTouch(View arg0, MotionEvent event) {
// TODO Auto-generated method stub
// How to change image using touch event here?
return false;
}
public class MyGameGraphics extends SurfaceView implements Runnable {
SurfaceHolder ourHolder;
Thread ourThread = null;
Boolean isRunning = false;
int[] images = new int[]{R.drawable.image1, R.drawable.image2};
public MyGameGraphics(Context context) {
super(context);
ourHolder = getHolder();
}
public void pause(){
isRunning = false;
while(true){
try {
ourThread.join();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
break;
}
ourThread = null;
}
public void resume(){
isRunning = true;
ourThread = new Thread(this);
ourThread.start();
}
#Override
public void run() {
while(isRunning){
if(!ourHolder.getSurface().isValid())
continue;
Canvas ourCanvas = ourHolder.lockCanvas();
ourCanvas.drawRGB(0, 0, 0);
Random rn = new Random();
int location = rn.nextInt(12);
for(int i = 0; i < 500; i++){
try {
Random rn2 = new Random();
int generateWidthLocation = rn2.nextInt(420);
int generateHeightLocation = rn2.nextInt(600);
Bitmap btmp = BitmapFactory.decodeResource(getResources(), images[location]);
ourCanvas.drawBitmap(btmp, generateWidthLocation, generateHeightLocation, null);
ourThread.sleep(3000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
break;
}
ourHolder.unlockCanvasAndPost(ourCanvas);
}
}
}
}
In the OnTouch method, the event parameter has two functions : event.getX() and event.getY().
Then you just need to keep the generateWidthLocation and generateHeightLocation for the current position and you can easily determine if the image is touched or not (you also need to keep the height/width of the image).
You might need to check if the OnTouch method is called when the user touches the screens, moves his finger or stops to touch it : event.getAction() which is either MotionEvent.ACTION_DOWN, MotionEvent.ACTION_MOVE or MotionEvent.ACTION_UP.
EDIT : In your MyGameGraphics add the following properties :
int[] images = new int[] { R.drawable.image1, R.drawable.image2 };
int currentXImageLocation = 0;
int currentYImageLocation = 0;
int currentImageWidth = 0;
int currentImageHeight = 0;
And after ourCanvas.drawBitmap(btmp, generateWidthLocation, generateHeightLocation, null); add :
currentXImageLocation = generateWidthLocation;
currentYImageLocation = generateHeightLocation;
currentImageHeight = btmp.getHeight();
currentImageWidth = btmp.getWidth();
Then add this function in your MyGameGraphics class :
public boolean isImageTouched(float x, float y)
{
boolean result = false;
if(x > currentXImageLocation && x < currentXImageLocation + currentImageWidth
&& y > currentYImageLocation && y < currentYImageLocation + currentImageHeight)
{
result = true;
}
return result;
}
And finally in the OnTouch method :
#Override
public boolean onTouch(View arg0, MotionEvent event) {
if(event.getAction() == MotionEvent.ACTION_DOWN)
{
if(myGraphics.isImageTouched(event.getX(), event.getY()))
{
//Image was touched, do something...
}
}
return true;
}
Related
I am running into an issue in my app. When my game ends (when life == 0) I am attempting to switch to a game over screen by using a different activity. When the game ends, the app simply crashes. I have included the XML for the activity I am trying to switch from as well as indicating where the app crashes. If anyone could help out, that would be great! Thanks.
activity_game.XML:
SurfaceView I am trying to switch from once game ends:
public class SVGameView extends SurfaceView implements Runnable {
private SurfaceHolder holder;
Thread thread = null;
volatile boolean running = false;
static final long FPS = 30;
private Sprite sprite;
private long lastClick;
private Bitmap ball, gameOver;
//private int x = 200, y = 200;
private int scorePosX = 100;
private int scorePosY = 100;
private int countScore = 0;
private int life = 1;
public SVGameView(Context context) {
super(context);
thread = new Thread(this);
holder = getHolder();
holder.addCallback(new SurfaceHolder.Callback() {
#Override
public void surfaceDestroyed(SurfaceHolder holder) {
boolean retry = true;
running = false;
while (retry) {
try {
thread.join();
retry = false;
} catch (InterruptedException e) {
}
}
}
#Override
public void surfaceCreated(SurfaceHolder holder) {
running = true;
thread.start();
}
#Override
public void surfaceChanged(SurfaceHolder holder, int format,
int width, int height) {
}
});
ball = BitmapFactory.decodeResource(getResources(), R.drawable.ball2);
gameOver = BitmapFactory.decodeResource(getResources(),R.drawable.endscreen);
sprite = new Sprite(this, ball);
}
#Override
public void run() {
long ticksPS = 1000 / FPS;
long startTime;
long sleepTime;
while (running) {
Canvas c = null;
startTime = System.currentTimeMillis();
try {
c = getHolder().lockCanvas();
synchronized (getHolder()) {
update();
draw(c);
}
} finally {
if (c != null) {
getHolder().unlockCanvasAndPost(c);
}
}
sleepTime = ticksPS-(System.currentTimeMillis() - startTime);
try {
if (sleepTime > 0)
thread.sleep(sleepTime);
else
thread.sleep(10);
} catch (Exception e) {}
}
}
private void update(){
sprite.update();
}
#Override
protected void onDraw(Canvas canvas) {
canvas.drawColor(Color.WHITE);
Paint paint = new Paint();
canvas.drawPaint(paint);
paint.setColor(Color.WHITE);
paint.setTextSize(48);
canvas.drawText("Score: " + countScore, scorePosX, scorePosY, paint);
canvas.drawText("Lives: " + life, 500, 100, paint);
sprite.onDraw(canvas);
//Crashes here
if(life == 0) {
getContext().startActivity(new Intent(getContext(), SVGameOver.class));
}
}
#Override
public boolean onTouchEvent(MotionEvent event) {
if(System.currentTimeMillis()-lastClick > 300){
lastClick = System.currentTimeMillis();
}
synchronized (getHolder()){
if(sprite.isHit(event.getX(), event.getY())){
countScore += 1;
sprite.increase();
}else{
life --;
}
}
return super.onTouchEvent(event);
}
}
Activity I am trying to reach once the game ends:
public class SVGameOver extends Activity {
private Bitmap gameOverScreen;
#Override
protected void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_game);
gameOverScreen = BitmapFactory.decodeResource(getResources(), R.drawable.endscreen);
}
protected void onDraw(Canvas canvas){
canvas.drawBitmap(gameOverScreen, 0,0,null);
}
}
I think logcat is asking you the right question: "have you declared this activity in your AndroidManifest.xml" ?
If you think you did it, It's highly probable you did it in a wrong way, most of the times that you think you added an Activity to the manifest but you are receiving this kind of crash, 99,9% of the time you declared it with a wrong namespace
Declare SVGameOver activity in your AndroidManifest.xml:
<activity
android:name="com.example.welcome.assignment2.SVGameOver">
...
</activity>
What I want to achieve with this program is , when my finger is touching the image and I am moving(dragging) it on the screen , the image should move along , and as soon as I release my finger , the image should remain at the last touched position. But my image keeps moving on the screen from first touched position to last touched position as the loop keeps updating, giving me this effect.
Here is MainGamePanel class which draws image on screen:
public class MainGamePanel extends SurfaceView implements SurfaceHolder.Callback{
private static final String TAG = MainGamePanel.class.getSimpleName();
private MainThread thread;
private Droid droid;
public MainGamePanel(Context context) {
super(context);
getHolder().addCallback(this);
setFocusable(true);
thread = new MainThread(getHolder() , this);
droid = new Droid(BitmapFactory.decodeResource(getResources(), R.drawable.ic_launcher), 50, 50);
}
#Override
public void surfaceChanged(SurfaceHolder holder, int format, int width,
int height) {
// TODO Auto-generated method stub
}
#Override
public void surfaceCreated(SurfaceHolder holder) {
thread.setRunning(true);
thread.start();
}
#Override
public void surfaceDestroyed(SurfaceHolder holder) {
boolean retry = true;
while(retry)
{
try {
thread.join();
retry = false;
} catch (InterruptedException e) { }
}
}
#Override
public boolean onTouchEvent(MotionEvent event) {
if(event.getAction() == MotionEvent.ACTION_DOWN)
{
droid.handleActionDown((int)event.getX(), (int)event.getY());
if(event.getY() > getHeight() - 50)
{
thread.setRunning(false);
((Activity) getContext()).finish();
}
else
{
Log.d(TAG, "Cords: x = "+event.getX()+" ,y = "+event.getY());
}
}
if(event.getAction() == MotionEvent.ACTION_MOVE)
{
if(droid.isTouched())
{
droid.setX((int)event.getX());
droid.setY((int)event.getY());
}
}
if(event.getAction() == MotionEvent.ACTION_UP)
{
if(droid.isTouched())
{
droid.setTouched(false);
}
}
return true;
}
#Override
protected void onDraw(Canvas canvas) {
droid.draw(canvas);
}
}
And here is the handleActionDown method of Droid class:
public void handleActionDown(int eventX, int eventY)
{
if(eventX >=(x - bitmap.getWidth()/2) && (eventX <= x + (bitmap.getWidth()/2)))
{
if(eventY >=(y - bitmap.getHeight()/2) && (y <= y + (bitmap.getHeight()/2)))
{
setTouched(true);
}else
{
setTouched(false);
}
}
else
{
setTouched(false);
}
}
You just need to clear the canvas before drawing the image.
#Override
public void draw(Canvas canvas) {
super.draw(canvas);
//Just call this line
canvas.drawColor(0, Mode.CLEAR);
canvas.drawBitmap(mBitmap1,mBitmap1Point.x-(mBitmap1.getWidth()/2),mBitmap1Point.y-(mBitmap1.getHeight()/2),null);
}
Worked fine for me.
I am using touch listener for an imageview in the listview item .It is working fine when I just do that like an sample application(I mean I have that Listview item as an sample one). But when I put this in a listview it is really becoming very slow.
I just wants to drag the image only horizantally,for that purpose I used ConstrainedDragandDrop View class which I got from the Github.
In my sample application:
public class HorizontalScroll extends Activity {
ImageView full_left,heart;
RelativeLayout rlMainLayout,rlImages,Cartoon_image,half_left,play_btn,centre,centre_leftanimate;
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.inflated_bloops);
half_left=(RelativeLayout)findViewById(R.id.half_left);
Cartoon_image=(RelativeLayout)findViewById(R.id.cartoon_image);
play_btn=(RelativeLayout)findViewById(R.id.play_btn);
heart=(ImageView)findViewById(R.id.ivheart);
ConstrainedDragAndDropView dndView = (ConstrainedDragAndDropView) findViewById(R.id.dndView);
dndView.setDragHandle(findViewById(R.id.cartoon_image),findViewById(R.id.half_left),heart);
dndView.setAllowVerticalDrag(false,HorizontalScroll.this);
}
}
When I used in my Listview:
public class Cars extends BaseAdapter
{
public View getView(int position, View convertView, ViewGroup parent)
{
View v = convertView;
LayoutInflater inflator = getLayoutInflater();
v= inflator.inflate(R.layout.inflated_bloops, null);
ConstrainedDragAndDropView dndView = (ConstrainedDragAndDropView) v.findViewById(R.id.dndView);
dndView.setDragHandle(v.findViewById(R.id.cartoon_image),v.findViewById(R.id.half_left),heart);
dndView.setAllowVerticalDrag(false,FeedModeActivity.this);
RelativeLayout Cartoon_image=(RelativeLayout)v.findViewById(R.id.cartoon_image);
ImageView ivDummy =(ImageView)v.findViewById(R.id.dummy);
try{
loader.DisplayImageRelative( al_new.get(position).replace(" ", "%20"),ivDummy, Cartoon_image);
}
catch(Exception e){
e.printStackTrace();
}
return v;
}
#Override
public int getCount() {
// TODO Auto-generated method stub
return al_new.size();
}
#Override
public Object getItem(int arg0) {
// TODO Auto-generated method stub
return null;
}
#Override
public long getItemId(int position) {
// TODO Auto-generated method stub
return 0;
}
}
Here is my custom dragDrop view:
public class ConstrainedDragAndDropView extends LinearLayout {
Activity main;
protected View dragHandle,half,heart;
protected List<View> dropTargets = new ArrayList<View>();
protected boolean dragging = false;
protected int pointerId;
protected int selectedDropTargetIndex = -1;
protected int lastSelectedDropTargetIndex = -1;
protected int lastDroppedIndex = -1;
protected boolean allowHorizontalDrag = true;
protected boolean allowVerticalDrag = true;
protected DropListener dropListener;
public interface DropListener {
public void onDrop(final int dropIndex, final View dropTarget);
}
public ConstrainedDragAndDropView(Context context) {
super(context);
}
public ConstrainedDragAndDropView(Context context, AttributeSet attrs) {
super(context, attrs);
applyAttrs(context, attrs);
}
#SuppressLint("NewApi")
public ConstrainedDragAndDropView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
applyAttrs(context, attrs);
}
public DropListener getDropListener() {
return dropListener;
}
public void setDropListener(DropListener dropListener) {
this.dropListener = dropListener;
}
public View getDragHandle() {
return dragHandle;
}
public void setDragHandle(View dragHandle,View half_left,View heart) {
this.dragHandle = dragHandle;
this.half=half_left;
this.heart=heart;
setupDragHandle();
}
public List<View> getDropTargets() {
return dropTargets;
}
public void setDropTargets(List<View> dropTargets) {
this.dropTargets = dropTargets;
}
public void addDropTarget(View target) {
if (dropTargets == null) {
dropTargets = new ArrayList<View>();
}
dropTargets.add(target);
}
public boolean isAllowHorizontalDrag() {
return allowHorizontalDrag;
}
public void setAllowHorizontalDrag(boolean allowHorizontalDrag) {
this.allowHorizontalDrag = allowHorizontalDrag;
}
public boolean isAllowVerticalDrag() {
return allowVerticalDrag;
}
public void setAllowVerticalDrag(boolean allowVerticalDrag,Activity c) {
this.allowVerticalDrag = allowVerticalDrag;
this.main=c;
}
protected void applyAttrs(Context context, AttributeSet attrs) {
TypedArray a = context.getTheme().obtainStyledAttributes(attrs, R.styleable.ConstrainedDragAndDropView, 0, 0);
try {
/*
layoutId = a.getResourceId(R.styleable.ConstrainedDragAndDropView_layoutId, 0);
if (layoutId > 0) {
LayoutInflater.from(context).inflate(layoutId, this, true);
}
*/
} finally {
a.recycle();
}
}
protected void setupDragHandle() {
this.setOnTouchListener(new DragAreaTouchListener());
}
protected class DragAreaTouchListener implements OnTouchListener {
public boolean onTouch(View view, MotionEvent motionEvent) {
switch (motionEvent.getAction()) {
case MotionEvent.ACTION_DOWN:
Log.d("Action down", "action down in listener");
onActionDown(view, motionEvent);
break;
case MotionEvent.ACTION_UP:
Log.d("Action up", "action up in listener");
onActionUp(view, motionEvent);
break;
case MotionEvent.ACTION_MOVE:
Log.d("Action move", "action move in listener");
onActionMove(view, motionEvent);
break;
default:
break;
}
return true;
}
}
public static int param;
protected void onActionDown(View view, MotionEvent motionEvent) {
// if we're not already dragging, and the touch position is on the drag handle,
// then start dragging
if(!dragging && isDragHandleTouch(motionEvent)) {
pointerId = motionEvent.getPointerId(0);
Float s1= dragHandle.getX();
param=Integer.valueOf(s1.intValue());
Log.e("param",""+param);
// updateDragPosition(motionEvent);
dragging = true;
Log.d("drag", "drag start");
}
}
protected void onActionUp(View view, MotionEvent motionEvent) {
Log.d("Action up", "action up");
// if we're dragging, then stop dragging
if (dragging && motionEvent.getPointerId(0) == pointerId) {
Log.e("condition","satisfied");
Log.e("x val"+(int)motionEvent.getX(),"y val"+(int)motionEvent.getY());
Log.e("x1"+half.getLeft(),"y1"+half.getTop());
Log.e("x4"+half.getRight(),"y4"+half.getBottom());
Float s1=motionEvent.getX();
Float s2=motionEvent.getY();
int x=Integer.valueOf(s1.intValue());
dragging = false;
int y=Integer.valueOf(s2.intValue());
if((half.getLeft()<x)&&(x<half.getRight())&&((half.getTop()<y)&&(y<half.getBottom())))
{
Log.e("drop","on target");
try {
Thread.sleep(1000);
dragHandle.setX(param);
heart.setVisibility(View.VISIBLE);
Animation pulse = AnimationUtils.loadAnimation(main, R.anim.pulse);
heart.startAnimation(pulse);
// heart.setVisibility(View.GONE);
pulse.setAnimationListener(new AnimationListener() {
public void onAnimationStart(Animation animation) {
// TODO Auto-generated method stub
Log.e("animation","start");
}
public void onAnimationRepeat(Animation animation) {
// TODO Auto-generated method stub
}
public void onAnimationEnd(Animation animation) {
// TODO Auto-generated method stub
Log.e("animation","end");
heart.setVisibility(View.GONE);
}
});
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
// class SimpleThread extends Thread {
//
// public void run() {
//
// try {
// sleep(1000);
// runOnUiThread(new Runnable() {
// public void run() {
// dragHandle.setX(param);
// heart.setVisibility(View.VISIBLE);
//
// Animation pulse = AnimationUtils.loadAnimation(main, R.anim.pulse);
// heart.startAnimation(pulse);
// }
// });
//
// }
// catch (InterruptedException e) {
// // TODO Auto-generated catch block
// e.printStackTrace();
// }
//
// }
// }
//
// new SimpleThread().start();
}
else{
Log.e("drop",""+"outside target");
dragHandle.setX(param);
// TranslateAnimation transAnimation= new TranslateAnimation(x, 300, y, 300);
// transAnimation.setDuration(1000);//set duration
// view.startAnimation(transAnimation);
}
// if()
// updateDragPosition(motionEvent);
Log.d("drag", "drag end");
// find out what drop target, if any, the drag handle was dropped on
int dropTargetIndex = findDropTargetIndexUnderDragHandle();
if(dropTargetIndex >= 0) { // if drop was on a target, select the target
Log.d("drag", "drop on target " + dropTargetIndex);
// selectDropTarget(dropTargetIndex);
// snapDragHandleToDropTarget(dropTargetIndex);
// lastDroppedIndex = dropTargetIndex;
if(dropListener != null) {
dropListener.onDrop(dropTargetIndex, dropTargets.get(dropTargetIndex));
}
} else { // if drop was not on a target, re-select the last selected target
// deselectDropTarget();
// snapDragHandleToDropTarget(lastDroppedIndex);
}
}
else{
Log.e("condition not","satisfied");
}
}
protected void onActionMove(View view, MotionEvent motionEvent) {
Log.d("Action move", "action move");
if (dragging && motionEvent.getPointerId(0) == pointerId) {
updateDragPosition(motionEvent);
int dropTargetIndex = findDropTargetIndexUnderDragHandle();
if(dropTargetIndex >= 0) {
Log.d("drag", "hover on target " + dropTargetIndex);
// selectDropTarget(dropTargetIndex);
} else {
// deselectDropTarget();
}
}
}
#SuppressLint("NewApi")
protected void updateDragPosition(MotionEvent motionEvent) {
// this is where we constrain the movement of the dragHandle
if(allowHorizontalDrag) {
float candidateX = motionEvent.getX() - dragHandle.getWidth() / 2;
if(candidateX > 0 && candidateX + dragHandle.getWidth() < this.getWidth()) {
dragHandle.setX(candidateX);
}
}
if(allowVerticalDrag) {
float candidateY = motionEvent.getY() - dragHandle.getHeight() / 2;
if(candidateY > 0 && candidateY + dragHandle.getHeight() < this.getHeight()) {
dragHandle.setY(candidateY);
}
}
}
#SuppressLint("NewApi")
protected void snapDragHandleToDropTarget(int dropTargetIndex) {
if(dropTargetIndex > -1) {
View dropTarget = dropTargets.get(dropTargetIndex);
float xCenter = dropTarget.getX() + dropTarget.getWidth() / 2;
float yCenter = dropTarget.getY() + dropTarget.getHeight() / 2;
float xOffset = dragHandle.getWidth() / 2;
float yOffset = dragHandle.getHeight() / 2;
float x = xCenter - xOffset;
float y = yCenter - yOffset;
dragHandle.setX(x);
dragHandle.setY(y);
}
}
protected boolean isDragHandleTouch(MotionEvent motionEvent) {
Point point = new Point(
new Float(motionEvent.getRawX()).intValue(),
new Float(motionEvent.getRawY()).intValue()
);
return isPointInView(point, dragHandle);
}
protected int findDropTargetIndexUnderDragHandle() {
int dropTargetIndex = -1;
for(int i = 0; i < dropTargets.size(); i++) {
if(isCollision(dragHandle, dropTargets.get(i))) {
dropTargetIndex = i;
break;
}
}
return dropTargetIndex;
}
/**
* Determines whether a raw screen coordinate is within the bounds of the specified view
* #param point - Point containing screen coordinates
* #param view - View to test
* #return true if the point is in the view, else false
*/
protected boolean isPointInView(Point point, View view) {
int[] viewPosition = new int[2];
view.getLocationOnScreen(viewPosition);
int left = viewPosition[0];
int right = left + view.getWidth();
int top = viewPosition[1];
int bottom = top + view.getHeight();
return point.x >= left && point.x <= right && point.y >= top && point.y <= bottom;
}
#SuppressLint("NewApi")
protected boolean isCollision(View view1, View view2) {
boolean collision = false;
do {
if(view1.getY() + view1.getHeight() < view2.getY()) {
break;
}
if(view1.getY() > view2.getY() + view2.getHeight()) {
break;
}
if(view1.getX() > view2.getX() + view2.getWidth()) {
break;
}
if(view1.getX() + view1.getWidth() < view2.getX()) {
break;
}
collision = true;
} while(false);
return collision;
}
protected void selectDropTarget(int index) {
if(index > -1) {
deselectDropTarget();
selectedDropTargetIndex = index;
dropTargets.get(selectedDropTargetIndex).setSelected(true);
}
}
protected void deselectDropTarget() {
if(selectedDropTargetIndex > -1) {
dropTargets.get(selectedDropTargetIndex).setSelected(false);
lastSelectedDropTargetIndex = selectedDropTargetIndex;
selectedDropTargetIndex = -1;
}
}
}
I'm developing a simple game like BSD robots. This game contains a rather large board (over 40 cells) and it doesn't look nice even at 10 inch tablet. My decision was to scroll (move) surface view and not to scale each figure which size is like finger spot.
I've read tons articles about surface view but I cannot understand how to move it?
My activity code:
package ru.onyanov.robots;
public class MainActivity extends Activity {
public BoardView board;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
getWindow().addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);
requestWindowFeature(Window.FEATURE_NO_TITLE);
board = new BoardView(this);
setContentView(board);
}
}
Class Board:
package ru.onyanov.robots;
public class BoardView extends SurfaceView {
private GameThread mThread;
private boolean running = false;
public final int sizeX = 50;
public final int sizeY = 35;
public final int cellSize = 64;
private int robotCount = 4;
public ArrayList<Cell> cells = new ArrayList<Cell>();
private ArrayList<Robot> robots = new ArrayList<Robot>();
private Hero hero;
public Bitmap imageCell;
public Bitmap imageRobot;
public Bitmap imageHero;
public BoardView(Context context) {
super(context);
makeGraphic();
constructCells();
constructRobots();
hero = new Hero(this, 3, 2, imageHero);
mThread = new GameThread(this);
getHolder().addCallback(new SurfaceHolder.Callback() {
public void surfaceDestroyed(SurfaceHolder holder) {
boolean retry = true;
mThread.setRunning(false);
while (retry) {
try {
mThread.join();
retry = false;
} catch (InterruptedException e) {
}
}
}
public void surfaceCreated(SurfaceHolder holder) {
mThread.setRunning(true);
mThread.start();
}
public void surfaceChanged(SurfaceHolder holder, int format,
int width, int height) {
}
});
}
private void makeGraphic() {
Bitmap cellImageSource = BitmapFactory.decodeResource(getResources(),
R.drawable.cell);
imageCell = Bitmap.createScaledBitmap(cellImageSource, cellSize,
cellSize, false);
imageRobot = BitmapFactory.decodeResource(getResources(),
R.drawable.robot);
imageHero = BitmapFactory.decodeResource(getResources(),
R.drawable.hero);
}
private void constructRobots() {
Robot robot;
Random rand = new Random();
for (int r = 0; r < robotCount; r++) {
int x = rand.nextInt(sizeX);
int y = rand.nextInt(sizeY);
robot = new Robot(this, x, y, imageRobot);
robots.add(robot);
}
return;
}
private void constructCells() {
Cell cell;
for (int y = 0; y < sizeY; y++) {
for (int x = 0; x < sizeX; x++) {
cell = new Cell(this, x, y, imageCell);
cells.add(cell);
}
}
return;
}
protected void onDraw(Canvas canvas) {
canvas.drawColor(Color.WHITE);
Cell cell;
for (int c = 0; c < cells.size(); c++) {
cell = cells.get(c);
cell.onDraw(canvas);
}
Robot robot;
for (int r = 0; r < robots.size(); r++) {
robot = robots.get(r);
robot.onDraw(canvas);
}
hero.onDraw(canvas);
}
public boolean onTouchEvent(MotionEvent e) {
int shotX = (int) e.getX();
int shotY = (int) e.getY();
if (e.getAction() == MotionEvent.ACTION_MOVE){
//TODO move board
showToast("move Board");
} else if (e.getAction() == MotionEvent.ACTION_UP) {
showToast("touchPoint: " + shotX + ", "+shotY);
hero.moveByDirection(shotX, shotY);
this.scrollTo(shotX, shotY);
}
return true;
}
public void showToast(String mes) {
Toast toast = Toast.makeText(getContext(), mes, Toast.LENGTH_LONG);
toast.show();
}
public class GameThread extends Thread {
private BoardView view;
public GameThread(BoardView view) {
this.view = view;
}
public void setRunning(boolean run) {
running = run;
}
public void run() {
while (running) {
Canvas canvas = null;
try {
canvas = view.getHolder().lockCanvas();
synchronized (view.getHolder()) {
onDraw(canvas);
}
canvas.scale(300, 300);
} catch (Exception e) {
} finally {
if (canvas != null) {
view.getHolder().unlockCanvasAndPost(canvas);
}
}
}
}
}
}
Some magic digits here are temporary. Now I just want to move BoardView;
The issue was to add x and y fields to SurfaceView, change them at onTouchEvent and draw all the elements in canvas with x- and y-offset. It's strange that I didn't recieved any answers...
I currently have (among others) these classes:
public class Main extends Activity {
Panel p;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_NO_TITLE);
p = new Panel(this);
setContentView(p);
}
#Override
public boolean onTouchEvent(MotionEvent event) {
p.onTouchEvent(event);
// Make your UI thread sleep.
try {
Thread.sleep(30);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return true;
}
and
public class Panel extends SurfaceView implements SurfaceHolder.Callback {
private ViewThread mThread;
private ArrayList<GraphicsElement> mElements = new ArrayList<GraphicsElement>();
public static int panelHeight;
public static int panelWidth;
private int numberOfElements = 0;
private Paint mPaint;
public Panel(Context context) {
super(context);
getHolder().addCallback(this);
mThread = new ViewThread(this);
mPaint = new Paint();
mPaint.setColor(Color.CYAN);
mPaint.setTextSize(20);
}
public void doDraw(long elapsed, Canvas canvas) {
canvas.drawColor(Color.parseColor("#003045"));
if (!(mElements.size() > 15)) {
synchronized (mElements) {
for (GraphicsElement element : mElements) {
element.doDraw(canvas);
}
canvas.drawText("FPS: " + Math.round(1000f / elapsed) + " Elements: " + numberOfElements, 10, 30, mPaint);
}
} else {
mElements.clear();
numberOfElements = 0;
}
}
public void animate(long elapsedTime) {
synchronized (mElements) {
for (GraphicsElement element : mElements) {
element.animate(elapsedTime);
}
}
}
#Override
public boolean onTouchEvent(MotionEvent event) {
int action = event.getAction();
int xspeed = 0;
int yspeed = 0;
if (action == MotionEvent.ACTION_DOWN || action == MotionEvent.ACTION_MOVE) {
if (event.getX() > panelWidth / 2) {
xspeed = 5;
} else if (event.getX() < panelWidth / 2) {
xspeed = -5;
}
synchronized (mElements) {
for (GraphicsElement element : mElements) {
element.changeSpeed(xspeed, yspeed);
}
}
}
return true;
}
#Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
#Override
public void surfaceCreated(SurfaceHolder holder) {
if (!mThread.isAlive()) {
mThread = new ViewThread(this);
mThread.setRunning(true);
mThread.start();
}
mElements.add(new GraphicsElement(getResources(), 80, 300));
numberOfElements += 1;
}
public void surfaceDestroyed(SurfaceHolder holder) {
I also have ViewThread, just my animation thread, and GraphicsElement, which defines the moving object. My animation is going very slow(on touch), and I think it has something to do with my .sleep() method. Could anyone please help me ?
Edit: I'm using .sleep() because I don't want to flood TouchEvents.
i'm trying to get it like: Check for TouchEvent, Sleep, Check for TouchEvent, Sleep.. etc...
I've had the same issues with touch slowing things down and ended up with a similar approach to yours (sleeping the UI thread on touch events, as recommended by a Google game developer). The thing that seemed to help me was playing with the length of the sleep time. Try increasing it to 70 ms or even more and see if that helps. Most apps don't need a super high sample rate for touch input.
Firstly, you should initialize your Panel inside your onCreate() method.
Panel p = null;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_NO_TITLE);
p = new Panel(this);
setContentView(p);
}
Secondly, I do not understand why you are doing a sleep in your onTouchEvent() handler. Try taking that out, and things should speed up, especially if you think that may be the cause!