I need to call invalidate() method from my MainActivity class. I can call it from my CanvasView class, but from MainActivity, it gives me an error. Says invalidate is non-static method. How do I get past this? I have searched and tried some solutions, but haven't got it to work.
I want to delete drawn items from the screen, but when I select Undo from menu list, it won't update the screen. Only when I touch the screen, it Undos elements.
My CanvasView class
package com.example.HW3;
import java.util.ArrayList;
import java.util.List;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.Point;
import android.graphics.Rect;
import android.os.Handler;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
/**
* Android Kimp.
* #author Martin
*
*/
public class CanvasView extends View {
/**
* Rectangles.
*/
private Rect rectangle = new Rect();
/**
* These help calculating rectangle coordinates.
*/
private float d1 = 0, d2 = 0;
/**
* Canvas.
*/
private Canvas canvas = new Canvas();
/**
* Paint to draw shapes.
*/
private Paint paint = new Paint();
/**
* Paint to draw shapes.
*/
private Paint paint2 = new Paint();
/**
* Paint to draw shapes.
*/
private Paint paint3 = new Paint();
/**
* Paint to draw shapes.
*/
private Paint paint4 = new Paint();
/**
* Path.
*/
private Path path = new Path();
/**
* Point.
*/
private Point point = new Point();
/**
* List for lines.
*/
private static List<Path> lines = new ArrayList<Path>();
private static List<Path> lines2 = new ArrayList<Path>();
/**
* List for points.
*/
private static List<Point> points = new ArrayList<Point>();
private static List<Point> points2 = new ArrayList<Point>();
/**
* List for rectangles.
*/
private static List<Rect> rectangles = new ArrayList<Rect>();
private static List<Rect> rectangles2 = new ArrayList<Rect>();
private static List<Integer> elements = new ArrayList<Integer>();
private static List<Integer> elements2 = new ArrayList<Integer>();
/**
* Touch coordinates.
*/
private float x, startX, endX;
/**
* Touch coordinates.
*/
private float y, startY, endY;
/**
* This checks whether user draws a line or a point.
*/
private int whichShape;
private boolean touchStarted = false;
/**
* Enum to hold the value of DrawMode, whether user wants to draw lines or rectangles.
*
*/
public enum undoRedo {
DoUndoRedo, DoNothing
};
public static undoRedo currentState = undoRedo.DoNothing;
public enum DrawMode {
/**
* DrawMode possibilities.
*/
FreeDrawMode, RectDrawMode, SelectAndDrag
};
/**
* Sets current DrawMode, when application starts.
*/
public static DrawMode currentDrawMode = DrawMode.FreeDrawMode;
/**
* Sets DrawMode.
* #param newDrawMode
*/
final Handler handler = new Handler();
/**
* Runnable interface to detect long press.
*/
Runnable mLongPressed = new Runnable() {
public void run() {
for (int i = 0; i < getRectangles().size(); i++) {
Log.i("", "Long press!");
Rect a = getRectangles().get(i);
System.out.println(a + " " + i);
double x = getRectangles().get(i).left;
System.out.println(a + " " + x);
currentDrawMode = DrawMode.SelectAndDrag;
}
}
};
/**
* CanvasView.
* #param context
* #param attrs
*/
public CanvasView(Context context, AttributeSet attrs) {
super(context, attrs);
paint.setAntiAlias(true);
paint.setStrokeWidth(3);
paint.setColor(Color.BLACK);
paint.setStyle(Paint.Style.STROKE);
paint.setStrokeJoin(Paint.Join.ROUND);
paint2.setAntiAlias(true);
paint2.setStrokeWidth(3);
paint2.setColor(Color.RED);
paint2.setStyle(Paint.Style.STROKE);
paint2.setStrokeJoin(Paint.Join.ROUND);
paint3.setAntiAlias(true);
paint3.setColor(Color.BLACK);
paint3.setStrokeWidth(3);
paint3.setStyle(Paint.Style.STROKE);
paint3.setStrokeJoin(Paint.Join.ROUND);
paint4.setAntiAlias(true);
paint4.setColor(Color.BLACK);
paint4.setStrokeWidth(3);
paint4.setStyle(Paint.Style.STROKE);
paint4.setShadowLayer(10,5,5,Color.BLACK);
paint4.setStrokeJoin(Paint.Join.ROUND);
}
#Override
protected void onDraw(Canvas canvas) {
for (Rect r : getRectangles()) {
canvas.drawRect(r, paint);
}
canvas.drawRect(rectangle, paint3);
for (Path p : getLines()) {
canvas.drawPath(p, paint);
}
canvas.drawPath(path, paint2);
for (Point point : getPoints()) {
canvas.drawCircle(point.x, point.y, 1, paint);
}
}
#Override
public boolean onTouchEvent(MotionEvent event) {
x = event.getX();
y = event.getY();
if (event.getAction() == MotionEvent.ACTION_DOWN) {
handler.postDelayed(mLongPressed, 500);
}
if ((event.getAction() == MotionEvent.ACTION_MOVE)
|| (event.getAction() == MotionEvent.ACTION_UP)) {
handler.removeCallbacks(mLongPressed);
}
if (currentDrawMode == DrawMode.FreeDrawMode) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
// Set new starting point
paint2.setColor(Color.RED);
path = new Path();
path.moveTo(x, y);
touchStarted = true;
break;
case MotionEvent.ACTION_MOVE:
touchStarted = false;
path.lineTo(x, y);
break;
case MotionEvent.ACTION_UP:
if (touchStarted) {
point = new Point();
point.x = (int) x;
point.y = (int) y;
paint2.setColor(Color.BLACK);
whichShape = 1;
getElements().add(whichShape);
getPoints().add(point);
getElements2().clear();
touchStarted = false;
System.out.println("here");
} else {
System.out.println("there");
paint2.setColor(Color.BLACK);
whichShape = 2;
getElements().add(whichShape);
getLines().add(path);
getElements2().clear();
}
break;
default:
return false;
}
} else if (currentDrawMode == DrawMode.RectDrawMode) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
// Set a new starting point
rectangle = new Rect();
paint3.setColor(Color.RED);
startX = event.getX();
startY = event.getY();
System.out.println("down");
break;
case MotionEvent.ACTION_MOVE:
endX = event.getX();
endY = event.getY();
System.out.println("move");
System.out.println(startX + " " + endX + " " + startY + " " + endY);
if (startX >= endX && startY >= endY) {
rectangle.set((int) endX, (int) endY, (int) startX,
(int) startY);
canvas.drawRect(rectangle, paint2);
} else if (startX >= endX && startY <= endY) {
d1 = startX + (endX - startX);
d2 = startY + (endY - startY);
rectangle.set((int) d1, (int) startY, (int) startX,
(int) d2);
canvas.drawRect(rectangle, paint3);
} else if (startX <= endX && startY >= endY) {
d1 = startY + (endY - startY);
d2 = startX + (endX - startX);
rectangle.set((int) startX, (int) d1, (int) d2,
(int) startY);
canvas.drawRect(rectangle, paint3);
System.out.println("olen siin");
} else {
rectangle.set((int) startX, (int) startY, (int) endX,
(int) endY);
canvas.drawRect(rectangle, paint3);
}
break;
case MotionEvent.ACTION_UP:
System.out.println("up");
paint3.setColor(Color.BLACK);
whichShape = 3;
getElements().add(whichShape);
getRectangles().add(rectangle);
getElements2().clear();
break;
default:
return false;
}
} else if (currentDrawMode == DrawMode.SelectAndDrag) {
switch (event.getAction()) {
case MotionEvent.ACTION_MOVE:
break;
case MotionEvent.ACTION_UP:
break;
default:
return false;
}
}
// Makes our view repaint and call onDraw
invalidate();
return true;
}
public static List<Integer> getElements() {
return elements;
}
public static void setElements(List<Integer> elements) {
CanvasView.elements = elements;
}
public static List<Point> getPoints() {
return points;
}
public static void setPoints(List<Point> points) {
CanvasView.points = points;
}
public static List<Path> getLines() {
return lines;
}
public static void setLines(List<Path> lines) {
CanvasView.lines = lines;
}
public static List<Rect> getRectangles() {
return rectangles;
}
public static void setRectangles(List<Rect> rectangles) {
CanvasView.rectangles = rectangles;
}
public static List<Point> getPoints2() {
return points2;
}
public static void setPoints2(List<Point> points2) {
CanvasView.points2 = points2;
}
public static List<Integer> getElements2() {
return elements2;
}
public static void setElements2(List<Integer> elements2) {
CanvasView.elements2 = elements2;
}
public static List<Path> getLines2() {
return lines2;
}
public static void setLines2(List<Path> lines2) {
CanvasView.lines2 = lines2;
}
public static List<Rect> getRectangles2() {
return rectangles2;
}
public static void setRectangles2(List<Rect> rectangles2) {
CanvasView.rectangles2 = rectangles2;
}
}
My MainActivity class
package com.example.HW3;
import com.example.HW3.CanvasView.undoRedo;
import com.example.androiddrawing.R;
import android.app.Activity;
import android.app.AlertDialog;
import android.content.DialogInterface;
import android.os.Bundle;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
import android.view.Window;
import android.view.WindowManager;
/**
* Android application.
* #author Martin
*
*/
public class MainActivity extends Activity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_NO_TITLE);
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
WindowManager.LayoutParams.FLAG_FULLSCREEN);
setContentView(R.layout.activity_main);
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.main, menu);
return true;
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle action bar item clicks here. The action bar will
// automatically handle clicks on the Home/Up button, so long
// as you specify a parent activity in AndroidManifest.xml.
int id = item.getItemId();
if (id == R.id.default_drawing) {
CanvasView.currentDrawMode = CanvasView.DrawMode.FreeDrawMode;
return true;
} else if (id == R.id.draw_rectangle) {
CanvasView.currentDrawMode = CanvasView.DrawMode.RectDrawMode;
return true;
} else if (id == R.id.undo) {
int listSize = CanvasView.getElements().size();
System.out.println(CanvasView.getElements().size());
if (CanvasView.getElements().size() == 0) {
return true;
} else if (CanvasView.getElements().get(listSize - 1) == 1) {
// I WANT TO CALL INVALIDATE() FROM HERE CanvasView.getPoints2().add(CanvasView.getPoints().get(CanvasView.getPoints().size() - 1));
CanvasView.getElements2().add(1);
CanvasView.getPoints().remove(CanvasView.getPoints().size() - 1);
CanvasView.getElements().remove(CanvasView.getElements().size() - 1);
CanvasView.currentState = CanvasView.undoRedo.DoUndoRedo;
return true;
} else if (CanvasView.getElements().get(listSize - 1) == 2) {
CanvasView.getLines2().add(CanvasView.getLines().get(CanvasView.getLines().size() - 1));
CanvasView.getElements2().add(2);
CanvasView.getLines().remove(CanvasView.getLines().size() - 1);
CanvasView.getElements().remove(CanvasView.getElements().size() - 1);
CanvasView.currentState = CanvasView.undoRedo.DoUndoRedo;
return true;
} else if (CanvasView.getElements().get(listSize - 1) == 3) {
CanvasView.getRectangles2().add(CanvasView.getRectangles2().get(CanvasView.getRectangles2().size() - 1));
CanvasView.getElements2().add(3);
CanvasView.getRectangles().remove(CanvasView.getRectangles().size() - 1);
CanvasView.getElements().remove(CanvasView.getElements().size() - 1);
CanvasView.currentState = CanvasView.undoRedo.DoUndoRedo;
return true;
}
return true;
} else if (id == R.id.redo) {
int listSize2 = CanvasView.getElements2().size();
System.out.println(CanvasView.getElements2().size());
if (CanvasView.getElements2().size() == 0) {
return true;
} else if (CanvasView.getElements2().get(listSize2 - 1) == 1) {
CanvasView.getPoints().add(CanvasView.getPoints2().get(CanvasView.getPoints2().size() - 1));
CanvasView.getPoints2().remove(CanvasView.getPoints2().size() - 1);
CanvasView.getElements2().remove(CanvasView.getElements2().size() - 1);
CanvasView.getElements().add(1);
CanvasView.currentState = CanvasView.undoRedo.DoUndoRedo;
return true;
} else if (CanvasView.getElements2().get(listSize2 - 1) == 2) {
CanvasView.getLines().add(CanvasView.getLines2().get(CanvasView.getLines2().size() - 1));
CanvasView.getLines2().remove(CanvasView.getLines2().size() - 1);
CanvasView.getElements2().remove(CanvasView.getElements().size() - 1);
CanvasView.getElements().add(2);
CanvasView.currentState = CanvasView.undoRedo.DoUndoRedo;
return true;
} else if (CanvasView.getElements2().get(listSize2 - 1) == 3){
CanvasView.getRectangles().add(CanvasView.getRectangles2().get(CanvasView.getRectangles2().size() - 1));
CanvasView.getRectangles2().remove(CanvasView.getRectangles2().size() - 1);
CanvasView.getElements2().remove(CanvasView.getElements2().size() - 1);
CanvasView.getElements().add(3);
CanvasView.currentState = CanvasView.undoRedo.DoUndoRedo;
return true;
}
return true;
}
return super.onOptionsItemSelected(item);
}
#Override
public void onBackPressed() {
AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setTitle("Exit");
builder.setMessage("Are You Sure?");
builder.setNegativeButton("Yes", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
dialog.dismiss();
System.exit(0);
}
});
builder.setPositiveButton("No", new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int which) {
dialog.dismiss();
}
});
AlertDialog alert = builder.create();
alert.show();
}
}
Activiti_main.xml
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="#+id/rect"
tools:context="com.example.HW3.MainActivity" >
<com.example.HW3.CanvasView
android:layout_width="match_parent"
android:layout_height="match_parent" />
</RelativeLayout>
I am assuming you have defined your CanvasView in your res/layout/activity_main.xml (and assigned it an id, say "custom_view")
You should not call your Canvas methods statically (directly from the class itself) but from the actual instance created by Android. You can get it by changing your MainActivity to something like this:
public class MainActivity extends Activity {
private CanvasView canvasView;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_NO_TITLE);
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
WindowManager.LayoutParams.FLAG_FULLSCREEN);
setContentView(R.layout.activity_main);
canvasView = findViewById(R.id.custom_view)
}
...
#Override
public boolean onOptionsItemSelected(MenuItem item) {
...
canvasView.invalidate();
...
}
You mention the error states that invalidate() isn't a static method. Are you sure you're calling myCanvasInstance.invalidate() and NOT CanvasView.invalidate()?
See these code below to make it clearer:
protected void onCreate(Bundle savedInstanceState) {
// This won't work.
CanvasView.invalidate();
// This will.
CanvasView myView = new CanvasView();
myView.invalidate();
}
In fact, your code seem like treating all method calls as a static call. I don't know whether this is a typo or you are really doing it in your code. The thing is, that's not the right way to do it - CanvasView is a class, not an instance/object. You should interact with the instance, not with the class.
For starters, change these line (and all those that are similar to it):
CanvasView.getElements().size();
CanvasView.getElements2().add(1);
CanvasView.getLines().remove(CanvasView.getLines().size() - 1);
etc.
to something that looks like this:
// Define this on the top of your class (outside of any methods).
CanvasView myView;
// Do this on your onCreate() method.
myView = new CanvasView();
// ..and then code like these WILL work; even outside of onCreate().
myView.invalidate();
myView.getElements().size();
myView.getElements2().add(1);
myView.getLines().remove(CanvasView.getLines().size() - 1);
etc.
Hope this helped you.
Related
I am trying to use one MainActivity.java class in Android Studio to control an RC car, I am still in the works as this is an early prototype code.
I am currently struggling on why my surfaceHolder.getSurface().isValid() is returning false every time. I cannot find any help besides implementing a Callback class, however, previously I have been able to use precisely the same lines of code mimicking my surfaceHolder and never needed a Callback class, the only exception was the class extended SurfaceView which this one does not because I can only extend one class. Below is my code:
package com.example.hughman.cccontrol;
import android.graphics.Point;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.Display;
import android.view.MotionEvent;
import android.view.View;
import android.view.Window;
import android.view.WindowManager;
import android.view.SurfaceView;
import android.view.SurfaceHolder;
import android.widget.ImageButton;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Paint;
public class MainActivity extends AppCompatActivity implements View.OnClickListener, Runnable{
private ImageButton breakButton, connectButton;
private Bitmap left_thumb, left_thumb_resized, right_thumb_resized;
private Context context;
private int screenW, screenH, thumb_x, thumb_y, drag_x, drag_y, current_thumb = -1;
private Canvas canvas;
private Paint paint = new Paint();
private SurfaceHolder surfaceHolder;
private Thread thread;
#Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
SurfaceView surfaceView = new SurfaceView(this);
paint.setAntiAlias(true);
//puts the app in full screen mode
requestWindowFeature(Window.FEATURE_NO_TITLE);
this.getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN);
setContentView(R.layout.activity_main);
surfaceHolder = surfaceView.getHolder();
//initalize screen size
Display display = getWindowManager().getDefaultDisplay();
Point size = new Point();
display.getSize(size);
screenH = size.x;
screenW = size.x;
//initialize buttons
breakButton = findViewById(R.id.breakbutton);
connectButton = findViewById(R.id.connectbutton);
breakButton.setOnClickListener(this);
connectButton.setOnClickListener(this);
left_thumb = BitmapFactory.decodeResource(this.getResources(), R.drawable.thumbstick);
left_thumb_resized = Bitmap.createScaledBitmap(left_thumb, 500, 500, false);
right_thumb_resized = Bitmap.createScaledBitmap(left_thumb, 500, 500, false);
thread = new Thread(this);
thread.start();
}
#Override
public void run() {
if(current_thumb == -1) {
drawInitialBitmap();
}
else
{
reDraw(drag_x, drag_y);
}
System.out.println("Run Test");
setFPS();
}
public void drawInitialBitmap()
{
thumb_x = 800;
thumb_y = (screenH / 2) + 250;
if (surfaceHolder.getSurface().isValid()) {
System.out.println("Hello");
canvas = surfaceHolder.lockCanvas();
canvas.drawBitmap(left_thumb_resized, thumb_x, thumb_y, paint);
canvas.drawBitmap(right_thumb_resized, thumb_x * 2, thumb_y, paint);
surfaceHolder.unlockCanvasAndPost(canvas);
}
}
public void reDraw(int x, int y)
{
if (surfaceHolder.getSurface().isValid()) {
canvas = surfaceHolder.lockCanvas();
if (current_thumb == 1) {
canvas.drawBitmap(left_thumb_resized, x, y, paint);
} else if (current_thumb == 2) {
canvas.drawBitmap(right_thumb_resized, x, y, paint);
}
surfaceHolder.unlockCanvasAndPost(canvas);
}
}
//method for when user selects an xml button
public void onClick(View v) {
if (v == connectButton) {
//prompts to connect to Bluetooth
System.out.println("ConectButton");
}
else if(v == breakButton)
{
System.out.println("BreakButton");
//halt all motors
}
}
public boolean onTouchEvent(MotionEvent event){
int action = event.getAction();
int drag_x = (int) event.getX(); // or getRawX();
int drag_y = (int) event.getY();
switch(action){
case MotionEvent.ACTION_DOWN:
if (drag_x >= thumb_x && drag_x < (thumb_x + left_thumb_resized.getWidth())
&& drag_y >= thumb_y && drag_y < (thumb_y + left_thumb_resized.getHeight())) {
current_thumb = 1;
return true;
}
else if (drag_x >= thumb_x * 2 && drag_x < ((thumb_x * 2) + right_thumb_resized.getWidth())
&& drag_y >= thumb_y && drag_y < (thumb_y + right_thumb_resized.getHeight())) {
current_thumb = 2;
return true;
}
break;
case MotionEvent.ACTION_MOVE:
if(current_thumb != -1)
{
System.out.println(Math.sqrt(Math.pow(drag_x - thumb_x, 2) + Math.pow(drag_y - thumb_y, 2)));
System.out.println(Math.sqrt(Math.pow(drag_x - (thumb_x * 2), 2) + Math.pow(drag_y - thumb_y, 2)));
//move left thumb
return true;
}
break;
case MotionEvent.ACTION_UP:
current_thumb = -1;
drawInitialBitmap();
break;
default:
}
return false;
}
public void setFPS() {
try {
thread.sleep(17);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
Everything runs fine and builds properly, but neither thumb sticks are being drawn. I haven't restricted the movement of the thumb sticks, but later on I will add that. As for now, I want to be able to drag them in the direction I want to move, using the distance function to simply figure out how far I ideally want to be able to drag them.
Is it possible to do this without extending SufaceView? Or making a Callback class? Why? Below I will add the code from my previous project where I did not use a Callback class, keep in mind the code is messy as we had multiple people working on the project and it had a required deadline of 24 hours.
package com.example.michael.doyouknowdeway;
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.widget.ImageButton;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Rect;
import android.media.MediaPlayer;
import android.view.MotionEvent;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
/**
* Created by michael on 1/27/18.
* The big class that does most of the work for the code, sets the overall view of the game, getting
* the character, tiles, and player motions all together for a working game. Took us the most time
* to work on with many bugs occuring along de wae.
*/
public class GameView extends SurfaceView implements Runnable{
//
volatile boolean isPlaying = true, init = true, isPassOver = true;
private Thread gameThread = null;
private SurfaceHolder surfaceHolder;
private Canvas canvas;
private Context context;
private Activity activity;
private int screenWidth = 0, screenHeight = 0, move_const = 1;
private Player player;
private MediaPlayer jumpNoise, eatNoise;
private Bitmap backgroundImage;
private MediaPlayer backgroundMusic;
private MediaPlayer endGameSound;
private Bitmap backgroundImageResized;
Tile currentTile, nextTile;
private ScheduledExecutorService executorService;
private Paint paint = new Paint();
private Paint textPaint = new Paint();
private FireBall fireball;
private int scoreCount = 0, passOver;
private Bitmap endImage;
private Bitmap endImageResized;
private Bitmap run1, podCount;
private Bitmap run1Resized, podCountResized;
private Bitmap run2;
private Bitmap playerJumpImage;
private boolean isRun1 = false;
private ImageButton redoButton;
//starts of the program, creating the background for the game based on the dimensions of the
//phone being used
public GameView(Context context, int screenX, int screenY) {
super(context);
//load images into game
backgroundImage = BitmapFactory.decodeResource(context.getResources(), R.drawable.background_sky);
backgroundImageResized = Bitmap.createScaledBitmap(backgroundImage, screenX, screenY, false);
podCount = BitmapFactory.decodeResource(context.getResources(), R.drawable.detergent_pod);
run1 = BitmapFactory.decodeResource(context.getResources(), R.drawable.knuckles_run);
run1Resized = Bitmap.createScaledBitmap(run1, 200, 200, false);
podCountResized = Bitmap.createScaledBitmap(podCount, 100, 100, false);
run2 = BitmapFactory.decodeResource(context.getResources(), R.drawable.ugandan_knuckle);
playerJumpImage = BitmapFactory.decodeResource(context.getResources(), R.drawable.knucklesjump);
//load sounds into game
jumpNoise = MediaPlayer.create(context, R.raw.jump_takeoff);
eatNoise = MediaPlayer.create(context, R.raw.eat_1);
backgroundMusic = MediaPlayer.create(context, R.raw.music_baby);
endGameSound = MediaPlayer.create(context, R.raw.end_game);
//initialize other important stuff
textPaint.setColor(Color.WHITE);
textPaint.setTextSize(72);
textPaint.setStyle(Paint.Style.FILL);
paint.setAntiAlias(true);
screenWidth = screenX;
screenHeight = screenY;
activity = (Activity) context;
backgroundMusic.start();
this.context = context;
player = new Player(context, screenX, screenY);
fireball = new FireBall(context, screenX, screenY);
currentTile = new Tile(context, 3, screenWidth + 400, screenHeight);
currentTile.fillTile();
surfaceHolder = getHolder();
//controls "running" animation
executorService = Executors.newSingleThreadScheduledExecutor();
executorService.scheduleAtFixedRate(new Runnable() {
#Override
public void run() {
if(!player.isJumping) {
if (!isRun1) {
run1Resized = Bitmap.createScaledBitmap(run1, 200, 200, false);
isRun1 = true;
} else {
run1Resized = Bitmap.createScaledBitmap(run2, 200, 200, false);
isRun1 = false;
}
}
}
}, 0, 200, TimeUnit.MILLISECONDS); //can change "speed" of run by altering the second param
}
/**
* Main game loop
*/
public void run() {
while (isPlaying) {
update();
draw();
setFPS();
}
}
/**
* Redraws the screen in the new positions, creating continuous movement for the game
*/
public void draw() {
if (surfaceHolder.getSurface().isValid()) {
canvas = surfaceHolder.lockCanvas();
canvas.drawColor(Color.WHITE);
canvas.drawBitmap(backgroundImageResized, 0, 0, paint);
canvas.drawBitmap(podCountResized, 0, 0, paint);
String scoreCountStr = Integer.toString(scoreCount);
if(0 >= (currentTile.getLength() * 100) - move_const)
{
currentTile = new Tile(nextTile);
isPassOver = true;
nextTile = null;
move_const = 0;
}
if(init) {
init = false;
for (int i = 0; i < currentTile.getLength(); i++) {
for (int j = currentTile.getHeight() - 1; j >= 0; j--) {
if (currentTile.getBlock(i, j) != null) {
canvas.drawBitmap(currentTile.getBlock(i, j).getImage(), (i * 100), (j * 100) + 10, paint);
}
}
}
}
else
{
for (int i = 0; i < currentTile.getLength(); i++) {
for (int j = currentTile.getHeight() - 1; j >= 0; j--) {
if (currentTile.getBlock(i, j) != null) {
canvas.drawBitmap(currentTile.getBlock(i, j).getImage(), (i * 100) - move_const, (j * 100) + 10, paint);
}
if (nextTile != null) {
if (i < nextTile.getLength() && j < nextTile.getHeight()) {
if (nextTile.getBlock(i, j) != null) {
canvas.drawBitmap(nextTile.getBlock(i, j).getImage(), ((i + currentTile.getLength()) * 100) - move_const, (j * 100) + 10, paint);
}
}
}
}
}
move_const += 10;
}
if(fireball.isShooting) {
canvas.drawBitmap(fireball.getImage(), fireball.getXVal(), fireball.getYVal(), paint);
}
canvas.drawBitmap(run1Resized,player.getXVal(), player.getYVal(), paint);
canvas.drawText(scoreCountStr, 120, 80, textPaint);
//releases the canvas to be redrawn again
surfaceHolder.unlockCanvasAndPost(canvas);
}
}
/**
* updates the positions of everything on the screen if needed
*/
public void update() {
player.update();
if(fireball.isShooting) {
fireball.update(player);
}
if((((currentTile.getLength() - (screenWidth/100) )* 100) - move_const <= 200) && nextTile == null){
nextTile = currentTile.getNextTile();
}
if(player.getYVal() >= screenHeight || player.getXVal() <= 0){
gameOver();
}
detectCollisions();
}
//initially sets player to not be colliding - changed almost instantly
static boolean isColliding = false;
//
/**
* Detects collisions so the player can collect tide pods and jump off of surfaces.
*/
public void detectCollisions(){
int highestY = 9;
int currentX = (250 + move_const)/100;
if(currentX >= currentTile.getLength() && isPassOver)
{
passOver = -10;
isPassOver = false;
}
else
{
passOver= -25; //arbitrary
}
for(int i = 0; i < currentTile.getHeight(); i++)
{
if(currentX >= currentTile.getLength())
{
passOver += 10;
if(nextTile.getBlock(passOver/100, i) != null)
{
if(!nextTile.getBlock(passOver/100, i).isPod())
{
highestY = i;
break;
}
}
}
else if(currentTile.getBlock(currentX, i) != null)
{
if(!currentTile.getBlock(currentX, i).isPod())
{
highestY = i;
break;
}
}
else
{
highestY = -1;
}
}
checkGroundCollision(highestY);
checkTidePodCollision(currentTile, nextTile);
checkForwardCollision(nextTile, currentX, highestY, passOver);
}
/**
* Method used to check if the player has hit a wall in front of them.
* #param next - the next tile
* #param x - player x position
* #param y - player y position
* #param passOver - the location being passed over.
*/
public void checkForwardCollision(Tile next, int x, int y, int passOver)
{
boolean collision = false;
Rect rect = new Rect();
if(next != null && passOver >= 0)
{
rect.top = y * 100;
rect.bottom = screenHeight;
rect.left = passOver + (player.getBitmap().getWidth() / 2);
rect.right = passOver + (player.getBitmap().getWidth() / 2) + 100;
collision = Rect.intersects(player.getHitBox(), rect);
}
else
{
rect.top = y * 100;
rect.bottom = screenHeight;
rect.left = (x+1)* 100;
rect.right = (x+2) * 100;
collision = Rect.intersects(player.getHitBox(), rect);
}
//if collision is true, half player movement until its not true
}
/**
* Method that checks if a player has hit a tidepod, if so, adds to score count
* #param current - the current tile
* #param next - the next tile
*/
public void checkTidePodCollision(Tile current, Tile next)
{
if(next != null && !isPassOver)
{
for(double iter: next.getTidePods())
{
int x = (int) iter;
int y = (int) (iter - x)*10;
boolean hit = podCollision(x, y);
if(hit)
{
eatNoise.start();
scoreCount += 10;
System.out.println("Cur Next: " + x + " || " + y);
nextTile.setNullBlock(x, y);
return;
}
}
}
else
{
for(double iter: current.getTidePods())
{
int x = (int) iter;
double temp = x;
int y = (int) ((iter - temp)*10.00);
boolean hit = podCollision(x, y);
if(hit)
{
eatNoise.start();
scoreCount += 10;
System.out.println("Current: " + x + " || " + y);
currentTile.setNullBlock(x, y);
return;
}
}
}
}
//compliment to the previous method
private boolean podCollision(int x, int y) {
Rect tideRect = new Rect();
if(isPassOver && x < 3)
{
System.out.println("TEST: " + x + " || " + y);
tideRect.top = (y * 100);
tideRect.left = x * 100 + passOver + 10;
tideRect.right = (x + 2) * 100 + passOver;
tideRect.bottom = (y + 2) * 100 + 10;
}
else {
tideRect.top = y * 100;
tideRect.left = x * 100 - move_const + 10;
tideRect.right = (x + 2) * 100 - move_const;
tideRect.bottom = (y + 2) * 100 + 10;
}
return Rect.intersects(player.getHitBox(), tideRect);
}
/**
* Method used for jumping off of the ground.
* #param highestY
*/
private void checkGroundCollision(int highestY) {
Rect blockRect = new Rect();
boolean GroundCollision;
if(highestY >= 0) {
blockRect.top = (highestY) * 100 - 25;
blockRect.left = 200;
blockRect.right = 300;
//changed this valued -- this is to remind myself
blockRect.bottom = highestY * 100 + 25; //still needs work //make player hitbox just his feet
GroundCollision = Rect.intersects(player.getFeetBox(), blockRect);
System.out.println("WWWWWW : " + GroundCollision);
}
else
{
GroundCollision = false;
}
if(GroundCollision){
isColliding = true;
} else {
player.isFalling = true;
isColliding = false;
}
}
/**
* Sets the FPS to roughly 60 fps
*/
public void setFPS() {
try {
gameThread.sleep(17);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
/**
* Method that
*/
public void gameOver() {
//end image is not currently working
endImage = BitmapFactory.decodeResource(context.getResources(), R.drawable.end_game);
endImageResized = Bitmap.createScaledBitmap(endImage, 100, 200, false);
canvas.drawBitmap(endImageResized, screenWidth/2, screenHeight/2, paint);
//free up memory from bitmaps
backgroundImage.recycle();
backgroundImage = null;
backgroundImageResized.recycle();
backgroundImageResized = null;
podCount.recycle();
podCount = null;
podCountResized.recycle();
podCountResized = null;
backgroundImage.recycle();
backgroundImage = null;
run1.recycle();
run1 = null;
run1Resized.recycle();
run1Resized = null;
run2.recycle();
run2 = null;
playerJumpImage.recycle();
playerJumpImage = null;
backgroundMusic.stop();
Runtime.getRuntime().gc(); //manually run garbage collector
endGameSound.start();
context.startActivity(new Intent(context,MainActivity.class));
}
/**
* Method used to dictate what to do when the android screen is touched.
* #param event - the type of touch on the screen
* #return - true when screen is touched
*/
public boolean onTouchEvent(MotionEvent event){
int touchAction = event.getAction();
if(touchAction == MotionEvent.ACTION_DOWN){
if(event.getX() < (screenWidth / 2)) {
jumpNoise.start();
if(!player.isJumping && !player.isFalling) {
player.setYval(player.getYVal());
player.isJumping = true;
run1Resized = Bitmap.createScaledBitmap(playerJumpImage, 200, 200, false);
}
else if(player.getJumpCount() < 1)
{
player.setYval(player.getYVal());
player.incrJump();
player.isJumping = true;
run1Resized = Bitmap.createScaledBitmap(playerJumpImage, 200, 200, false);
}
} else {
fireball.setOnScreen(true);
}
}
return true;
}
/**
* Method that pauses the game when necessary (i.e when home button is pressed)
*/
public void pause() {
isPlaying = false;
backgroundMusic.pause();
try {
gameThread.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
/**
* Resumes the game after a pause
*/
public void resume() {
isPlaying = true;
backgroundMusic.start();
gameThread = new Thread(this);
gameThread.start();
}
}
Thank you for your time & any help is appreciated!
EDIT: Also using bitmaps to redraw etc. as that is what I am used to.
I'm following this tutorial, but after completing step 6, I'm left with an error: "MyGestureDetector cannot be resolved to a type" when I try to instantiate a "new MyGestureDetector()".
Code:
package com.example.rotatingdialer;
import android.os.Bundle;
import android.app.Activity;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Matrix;
import android.view.GestureDetector;
import android.view.GestureDetector.SimpleOnGestureListener;
import android.view.Menu;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnTouchListener;
import android.view.ViewTreeObserver.OnGlobalLayoutListener;
import android.widget.ImageView;
public class MainActivity extends Activity {
private static Bitmap imageOriginal, imageScaled;
private static Matrix matrix;
private ImageView dialer;
private int dialerHeight, dialerWidth;
private GestureDetector detector;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// load the image only once
if (imageOriginal == null) {
imageOriginal = BitmapFactory.decodeResource(getResources(), R.drawable.ic_launcher);
}
// initialize the matrix only once
if (matrix == null) {
matrix = new Matrix();
} else {
// not needed, you can also post the matrix immediately to restore the old state
matrix.reset();
}
detector = new GestureDetector(this, new MyGestureDetector());
dialer = (ImageView) findViewById(R.id.imageView_ring);
dialer.setOnTouchListener(new MyOnTouchListener());
dialer.getViewTreeObserver().addOnGlobalLayoutListener(new OnGlobalLayoutListener() {
#Override
public void onGlobalLayout() {
// method called more than once, but the values only need to be initialized one time
if (dialerHeight == 0 || dialerWidth == 0) {
dialerHeight = dialer.getHeight();
dialerWidth = dialer.getWidth();
// resize
Matrix resize = new Matrix();
resize.postScale((float)Math.min(dialerWidth, dialerHeight) / (float)imageOriginal.getWidth(), (float)Math.min(dialerWidth, dialerHeight) / (float)imageOriginal.getHeight());
imageScaled = Bitmap.createBitmap(imageOriginal, 0, 0, imageOriginal.getWidth(), imageOriginal.getHeight(), resize, false);
// translate to the image view's center
float translateX = dialerWidth / 2 - imageScaled.getWidth() / 2;
float translateY = dialerHeight / 2 - imageScaled.getHeight() / 2;
matrix.postTranslate(translateX, translateY);
dialer.setImageBitmap(imageScaled);
dialer.setImageMatrix(matrix);
}
}
});
}
/**
* Simple implementation of an {#link OnTouchListener} for registering the dialer's touch events.
*/
private class MyOnTouchListener implements OnTouchListener {
private double startAngle;
#Override
public boolean onTouch(View v, MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
startAngle = getAngle(event.getX(), event.getY());
break;
case MotionEvent.ACTION_MOVE:
double currentAngle = getAngle(event.getX(), event.getY());
rotateDialer((float) (startAngle - currentAngle));
startAngle = currentAngle;
break;
case MotionEvent.ACTION_UP:
break;
}
detector.onTouchEvent(event);
return true;
}
/**
* Simple implementation of a {#link SimpleOnGestureListener} for detecting a fling event.
*/
private class MyGestureDetector extends SimpleOnGestureListener {
#Override
public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
dialer.post(new FlingRunnable(velocityX + velocityY));
return true;
}
}
/**
* A {#link Runnable} for animating the the dialer's fling.
*/
private class FlingRunnable implements Runnable {
private float velocity;
public FlingRunnable(float velocity) {
this.velocity = velocity;
}
#Override
public void run() {
if (Math.abs(velocity) > 5) {
rotateDialer(velocity / 75);
velocity /= 1.0666F;
// post this instance again
dialer.post(this);
}
}
}
/**
* #return The angle of the unit circle with the image view's center
*/
private double getAngle(double xTouch, double yTouch) {
double x = xTouch - (dialerWidth / 2d);
double y = dialerHeight - yTouch - (dialerHeight / 2d);
switch (getQuadrant(x, y)) {
case 1:
return Math.asin(y / Math.hypot(x, y)) * 180 / Math.PI;
case 2:
return 180 - Math.asin(y / Math.hypot(x, y)) * 180 / Math.PI;
case 3:
return 180 + (-1 * Math.asin(y / Math.hypot(x, y)) * 180 / Math.PI);
case 4:
return 360 + Math.asin(y / Math.hypot(x, y)) * 180 / Math.PI;
default:
return 0;
}
}
/**
* #return The selected quadrant.
*/
private int getQuadrant(double x, double y) {
if (x >= 0) {
return y >= 0 ? 1 : 4;
} else {
return y >= 0 ? 2 : 3;
}
}
/**
* Rotate the dialer.
*
* #param degrees The degrees, the dialer should get rotated.
*/
private void rotateDialer(float degrees) {
matrix.postRotate(degrees, dialerWidth/2, dialerHeight/2);
dialer.setImageMatrix(matrix);
// dialer.setImageBitmap(Bitmap.createBitmap(imageScaled, 0, 0, imageScaled.getWidth(), imageScaled.getHeight(), matrix, true));
}
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.main, menu);
return true;
}
}
...did I go wrong somewhere? Thanks!
The simplest way to do this (that is, without refactoring the class structure of these 4 classes (Activity, touch listener, gesture detector, fling runnable)) is to call it as follows. You'll have to move your MyTouchListener instantiation out into a separate declaration, and then you can use that to create a new instance of the MyGestureDetector class:
MyOnTouchListener onTouchListener = new MyOnTouchListener();
detector = new GestureDetector(this, onTouchListener.new MyGestureDetector());
dialer = (ImageView) findViewById(R.id.imageView_ring);
dialer.setOnTouchListener(onTouchListener);
I want to make a class which captures a human signature for my Android app. I have this code so far:
public class DrawView extends View implements OnTouchListener {
private static final String TAG = "DrawView";
List<Point> points = new ArrayList<Point>();
Paint paint = new Paint();
long oldTime = 0;
public DrawView(Context context) {
super(context);
setFocusable(true);
setFocusableInTouchMode(true);
this.setOnTouchListener(this);
// paint.setColor(Color.BLACK);
// paint.setAntiAlias(true);
paint = new Paint(Paint.ANTI_ALIAS_FLAG);
paint.setStyle(Paint.Style.STROKE);
paint.setStrokeWidth(2);
paint.setColor(Color.BLACK);
}
#Override
public void onDraw(Canvas canvas) {
Path path = new Path();
if (points.size() > 1) {
for (int i = points.size() - 2; i < points.size(); i++) {
if (i >= 0) {
Point point = points.get(i);
if (i == 0) {
Point next = points.get(i + 1);
point.dx = ((next.x - point.x) / 3);
point.dy = ((next.y - point.y) / 3);
} else if (i == points.size() - 1) {
Point prev = points.get(i - 1);
point.dx = ((point.x - prev.x) / 3);
point.dy = ((point.y - prev.y) / 3);
} else {
Point next = points.get(i + 1);
Point prev = points.get(i - 1);
point.dx = ((next.x - prev.x) / 3);
point.dy = ((next.y - prev.y) / 3);
}
}
}
}
boolean first = true;
for (int i = 0; i < points.size(); i++) {
Point point = points.get(i);
if (first) {
first = false;
path.moveTo(point.x, point.y);
} else {
Point prev = points.get(i - 1);
path.cubicTo(prev.x + prev.dx, prev.y + prev.dy, point.x
- point.dx, point.y - point.dy, point.x, point.y);
}
}
canvas.drawPath(path, paint);
}
public boolean onTouch(View view, MotionEvent event) {
if (event.getAction() != MotionEvent.ACTION_UP) {
Point point = new Point();
point.x = event.getX();
point.y = event.getY();
points.add(point);
invalidate();
return true;
}
return super.onTouchEvent(event);
}
public boolean checkTime() {
//Check if there was an input 400 ms ago
long newTime = System.currentTimeMillis();
long diffirence = newTime - oldTime;
if (oldTime == 0) {
oldTime = System.currentTimeMillis();
return true;
} else if (diffirence <= 400) {
oldTime = System.currentTimeMillis();
return true;
}
return false;
}
}
class Point {
float x, y;
float dx, dy;
#Override
public String toString() {
return x + ", " + y;
}
}
The problem is that the line will connect to the latest point when I start drawing again, even when I stop drawing for a while. This is of course not very useful for capturing human signatures, that's why I created the checkTime method. If you stop drawing for 400ms it returns false, when you start drawing again it will start a new line which is not connected to the old line. I only just don't know how I can implement my method, I tried a lot but the line keeps connecting to the latest point, maybe someone can help me.
It's probably faster to create the path in onTouch and only draw it in onDraw.
Replace onTouch with
Path path = new Path();
int prevx=0;
int prevy=0;
int prevdx=0;
int prevdy=0;
public boolean onTouch(View view, MotionEvent event)
{
int x = event.getX();
int y = event.getY();
int dx = (x-prevx)/3;
int dy = (y-prevy)/3;
if(event.getAction() == MotionEvent.ACTION_DOWN)
{
path.moveTo(x, y);
}
if(event.getAction() == MotionEvent.ACTION_MOVE)
{
path.cubicTo(prevx + prevdx, prevy + prevdy, x - dx, y - dy, x, y);
}
prevx=x;
prevy=y;
prevdx=dx;
prevdy=dy;
invalidate();
return true;
}
onDraw will be just
public void onDraw(Canvas canvas)
{
canvas.drawPath(path, paint);
}
I used this post from Lars Vogel, but many thanks to Marc Van Daele!
This is code wich paints the View:
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
public class SingleTouchEventView extends View {
private Paint paint = new Paint();
private Path path = new Path();
public SingleTouchEventView(Context context, AttributeSet attrs) {
super(context, attrs);
paint.setAntiAlias(true);
paint.setStrokeWidth(6f);
paint.setColor(Color.BLACK);
paint.setStyle(Paint.Style.STROKE);
paint.setStrokeJoin(Paint.Join.ROUND);
}
#Override
protected void onDraw(Canvas canvas) {
canvas.drawPath(path, paint);
}
#Override
public boolean onTouchEvent(MotionEvent event) {
float eventX = event.getX();
float eventY = event.getY();
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
path.moveTo(eventX, eventY);
return true;
case MotionEvent.ACTION_MOVE:
path.lineTo(eventX, eventY);
break;
case MotionEvent.ACTION_UP:
// nothing to do
break;
default:
return false;
}
// Schedules a repaint.
invalidate();
return true;
}
}
You have to call this activity to start paiting:
import android.app.Activity;
import android.os.Bundle;
public class SingleTouchActivity extends Activity {
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(new SingleTouchEventView(this, null));
}
}
What is the best way drawing a hero and moving it? I just need the best code for doing that. Before writing this i found a way, but when i made the surface holder transparent, i realised that the code is drawing new bitmap in the front of the old one every milisecond. That way looks kind of laggy to me, but maymie i'm not right. Please help me. Actualy i'm kind of confused...
Anyway, here's the code that i think is laggy:
MainThread.java
/**
*
*/
package com.workspace.pockethero;
import android.graphics.Canvas;
import android.util.Log;
import android.view.SurfaceHolder;
/**
* #author impaler
*
* The Main thread which contains the game loop. The thread must have access to
* the surface view and holder to trigger events every game tick.
*/
public class MainThread extends Thread {
private static final String TAG = MainThread.class.getSimpleName();
// Surface holder that can access the physical surface
private SurfaceHolder surfaceHolder;
// The actual view that handles inputs
// and draws to the surface
private MainGamePanel gamePanel;
// flag to hold game state
private boolean running;
public void setRunning(boolean running) {
this.running = running;
}
public MainThread(SurfaceHolder surfaceHolder, MainGamePanel gamePanel) {
super();
this.surfaceHolder = surfaceHolder;
this.gamePanel = gamePanel;
}
#Override
public void run() {
Canvas canvas;
canvas = this.surfaceHolder.lockCanvas();
Log.d(TAG, "Starting game loop");
while (running) {
canvas = null;
// try locking the canvas for exclusive pixel editing
// in the surface
try {
synchronized (surfaceHolder) {
// update game state
this.gamePanel.update();
// render state to the screen
// draws the canvas on the panel
this.gamePanel.render(canvas);
}
} finally {
// in case of an exception the surface is not left in
// an inconsistent state
if (canvas != null) {
surfaceHolder.unlockCanvasAndPost(canvas);
}
} // end finally
}
}
}
MainGamePanel.java
/**
*
*/
package com.workspace.pockethero;
import com.workspace.pockethero.model.Droid;
import com.workspace.pockethero.buttons.*;
import android.content.Context;
import android.content.res.Resources;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.drawable.Drawable;
import android.util.Log;
import android.view.MotionEvent;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.View;
/**
* #author impaler
* This is the main surface that handles the ontouch events and draws
* the image to the screen.
*/
public class MainGamePanel extends SurfaceView implements
SurfaceHolder.Callback {
private static final String TAG = MainGamePanel.class.getSimpleName();
private MainThread thread;
public Droid droid;
public Butt butt;
public Butt1 butt1;
public Butt2 butt2;
public Butt3 butt3;
public Buttz buttz;
public Buttz1 buttz1;
public Buttz2 buttz2;
public Buttz3 buttz3;
public Buttx buttx;
public Build build;
public int decentreX;
public int decentreY;
public int debottomA;
public boolean moved;
public boolean moved1;
public boolean moved2;
public boolean moved3;
public boolean moved4;
public boolean moved5;
public boolean moved6;
public boolean moved7;
private Drawable myImage;
public boolean mapPainted;
public MainGamePanel(Context context) {
super(context);
// adding the callback (this) to the surface holder to intercept events
getHolder().addCallback(this);
// create droid and load bitmap
decentreX = PocketHero.centreX;
decentreY = PocketHero.centreY;
debottomA = PocketHero.bottomA;
droid = new Droid(BitmapFactory.decodeResource(getResources(), R.drawable.herod), decentreX, decentreY);
butt = new Butt(BitmapFactory.decodeResource(getResources(), R.drawable.button), 110, debottomA - 70);
butt1 = new Butt1(BitmapFactory.decodeResource(getResources(), R.drawable.button1), 70, debottomA - 110);
butt2 = new Butt2(BitmapFactory.decodeResource(getResources(), R.drawable.button2), 30, debottomA - 70);
butt3 = new Butt3(BitmapFactory.decodeResource(getResources(), R.drawable.button3), 70, debottomA - 30);
buttz = new Buttz(BitmapFactory.decodeResource(getResources(), R.drawable.zbutton), 110, debottomA - 110);
buttz1 = new Buttz1(BitmapFactory.decodeResource(getResources(), R.drawable.zbutton1), 30, debottomA - 110);
buttz2 = new Buttz2(BitmapFactory.decodeResource(getResources(), R.drawable.zbutton2), 30, debottomA - 30);
buttz3 = new Buttz3(BitmapFactory.decodeResource(getResources(), R.drawable.zbutton3), 110, debottomA - 30);
buttx = new Buttx(BitmapFactory.decodeResource(getResources(), R.drawable.xbutton), 70, debottomA - 70);
build = new Build(BitmapFactory.decodeResource(getResources(), R.drawable.building), 500, 200);
// create the game loop thread
//300 indicates start position of bitmapfield on screen
thread = new MainThread(getHolder(), this);
// make the GamePanel focusable so it can handle events
setFocusable(true);
this.setOnTouchListener(new OnTouchListener() {
public boolean onTouch(View V, MotionEvent event) {
if (event.getAction() == MotionEvent.ACTION_DOWN) {
// delegating event handling to the droid
handleActionDown((int)event.getX(), (int)event.getY());
} if (event.getAction() == MotionEvent.ACTION_MOVE) {
handleActionDown((int)event.getX(), (int)event.getY());
// the gestures
} if (event.getAction() == MotionEvent.ACTION_UP) {
// touch was released
if (droid.touched) {
droid.setTouched(false);
}
if (droid.touched1) {
droid.setTouched1(false);
}
if (droid.touched2) {
droid.setTouched2(false);
}
if (droid.touched3) {
droid.setTouched3(false);
}
}
return true;
}
});
}
public void surfaceChanged(SurfaceHolder holder, int format, int width,
int height) {
}
public void surfaceCreated(SurfaceHolder holder) {
// at this point the surface is created and
// we can safely start the game loop
thread.setRunning(true);
thread.start();
}
public void surfaceDestroyed(SurfaceHolder holder) {
Log.d(TAG, "Surface is being destroyed");
// tell the thread to shut down and wait for it to finish
// this is a clean shutdown
boolean retry = true;
while (retry) {
try {
thread.join();
retry = false;
} catch (InterruptedException e) {
// try again shutting down the thread
}
}
Log.d(TAG, "Thread was shut down cleanly");
}
public void render(Canvas canvas) {
canvas.drawColor(Color.TRANSPARENT);
droid.draw(canvas);
butt.draw(canvas);
butt1.draw(canvas);
butt2.draw(canvas);
butt3.draw(canvas);
buttz.draw(canvas);
buttz1.draw(canvas);
buttz2.draw(canvas);
buttz3.draw(canvas);
buttx.draw(canvas);
}
/**
* This is the game update method. It iterates through all the objects
* and calls their update method if they have one or calls specific
* engine's update method.
*/
public void update() {
droid.update();
}
public void handleActionDown(int eventX, int eventY) {
if (eventX >= (butt.x - butt.bitmap.getWidth() / 2) && (eventX <= (butt.x + butt.bitmap.getWidth()/2))) {
if (eventY >= (buttz.y - buttz.bitmap.getHeight() / 2) && (eventY <= (buttz3.y + buttz3.bitmap.getHeight() / 2))) {
// droid touched
droid.setTouched(true);
} else {
droid.setTouched(false);
}
} else {
droid.setTouched(false);
}
if (eventX >= (buttz1.x - buttz1.bitmap.getWidth() / 2) && (eventX <= (buttz.x + buttz.bitmap.getWidth()/2))) {
if (eventY >= (butt1.y - butt1.bitmap.getHeight() / 2) && (eventY <= (butt1.y + butt1.bitmap.getHeight() / 2))) {
// droid touched
droid.setTouched1(true);
} else {
droid.setTouched1(false);
}
}else {
droid.setTouched1(false);
}
if (eventX >= (butt2.x - butt2.bitmap.getWidth() / 2) && (eventX <= (butt2.x + butt2.bitmap.getWidth()/2))) {
if (eventY >= (buttz1.y - buttz1.bitmap.getHeight() / 2) && (eventY <= (buttz2.y + buttz2.bitmap.getHeight() / 2))) {
// droid touched
droid.setTouched2(true);
} else {
droid.setTouched2(false);
}
}else {
droid.setTouched2(false);
}
if (eventX >= (buttz2.x - buttz2.bitmap.getWidth() / 2) && (eventX <= (buttz3.x + buttz3.bitmap.getWidth()/2))) {
if (eventY >= (butt3.y - butt3.bitmap.getHeight() / 2) && (eventY <= (butt3.y + butt3.bitmap.getHeight() / 2))) {
// droid touched
droid.setTouched3(true);
} else {
droid.setTouched3(false);
}
}else {
droid.setTouched3(false);
}
if (droid.touched & !droid.touched1 & !droid.touched3) {
if (!moved) {
droid.bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.heror);
moved = true;
}
}else {
moved = false;
}if (droid.touched1 & !droid.touched & !droid.touched2){
if (!moved1) {
droid.bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.herou);
moved1 = true;
}
}else {
moved1 = false;
} if (droid.touched2 & !droid.touched1 & !droid.touched3){
if (!moved2) {
droid.bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.herol);
moved2 = true;
}
}else {
moved2 = false;
} if (droid.touched3 & !droid.touched2 & !droid.touched){
if (!moved7) {
droid.bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.herod);
moved7 = true;
}
}else {
moved7 = false;
} if (droid.touched & droid.touched1){
if (!moved3) {
droid.bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.herour);
moved3 = true;
}
}else {
moved3 = false;
} if (droid.touched1 & droid.touched2){
if (!moved4) {
droid.bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.heroul);
moved4 = true;
}
}else {
moved4 = false;
} if (droid.touched2 & droid.touched3){
if (!moved5) {
droid.bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.herodl);
moved5 = true;
}
}else {
moved5 = false;
} if (droid.touched3 & droid.touched){
if (!moved6) {
droid.bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.herodr);
moved6 = true;
}
}else {
moved6 = false;
}
}
}
and the Droid.java
/**
*
*/
package com.workspace.pockethero.model;
import android.graphics.Bitmap;
import android.graphics.Canvas;
/**
* This is a test droid that is dragged, dropped, moved, smashed against
* the wall and done other terrible things with.
* Wait till it gets a weapon!
*
* #author impaler
*
*/
public class Droid {
public Bitmap bitmap; // the actual bitmap
public int x; // the X coordinate
public int y; // the Y coordinate
public boolean touched; // if droid is touched/picked up
public boolean touched1; // if droid is touched/picked up
public boolean touched2; // if droid is touched/picked up
public boolean touched3; // if droid is touched/picked up
public Droid(Bitmap bitmap, int x, int y) {
this.bitmap = bitmap;
this.x = x;
this.y = y;
}
public Bitmap getBitmap() {
return bitmap;
}
public void setBitmap(Bitmap bitmap) {
this.bitmap = bitmap;
}
public int getX() {
return x;
}
public void setX(int x) {
this.x = x;
}
public int getY() {
return y;
}
public void setY(int y) {
this.y = y;
}
public void draw(Canvas canvas) {
canvas.drawBitmap(bitmap, x - (bitmap.getWidth() / 2), y - (bitmap.getHeight() / 2), null);
}
/**
* Method which updates the droid's internal state every tick
*/
public void setTouched(boolean touched) {
this.touched = touched;
}
public boolean isTouched() {
return touched;
}
public void setTouched1(boolean touched) {
this.touched1 = touched;
}
public boolean isTouched1() {
return touched1;
}
public void setTouched2(boolean touched) {
this.touched2 = touched;
}
public boolean isTouched2() {
return touched2;
}
public void setTouched3(boolean touched) {
this.touched3 = touched;
}
public boolean isTouched3() {
return touched3;
}
public void update() {
if (touched & !touched1 & !touched3) {
x += 1;
}else if (touched1 & !touched & !touched2){
y -= 1;
}else if (touched2 & !touched1 & !touched3){
x -= 1;
}else if (touched3 & !touched2 & !touched){
y += 1;
}else if (touched & touched1){
x += 1;
y -= 1;
}else if (touched1 & touched2){
x -= 1;
y -= 1;
}else if (touched2 & touched3){
x -= 1;
y += 1;
}else if (touched3 & touched){
x += 1;
y += 1;
}
}
/**
* Handles the {#link MotionEvent.ACTION_DOWN} event. If the event happens on the
* bitmap surface then the touched state is set to <code>true</code> otherwise to <code>false</code>
* #param eventX - the event's X coordinate
* #param eventY - the event's Y coordinate
*/
}
there are also other classes created for each button, but i didnt pasted them here, because the are practicly the same as droid.java
Re-drawing the whole frame each loop is the correct way to draw/move sprites and perform anything with canvas.
The buffer is cleared each frame and you need to re-draw the background and all objects at their specified position.
In your code render() and update() will not be called more frequently than approximately every 16milliseconds~ (60 frames per second), so all you have to think about is drawing the onscreen scene.
I'm not sure what you mean by 'laggy', maybe you have a performance issue related to the size of your Bitmaps or phone performance, but I hope this is close to what you were looking for.
Please help with the following code - I need a dialog box with a button to appear when the game puzzle is completed. Thank you!
Here's the code:
Sudoku.java
package org.example.sudoku;
import android.app.Activity;
import android.app.AlertDialog;
import android.content.DialogInterface;
import android.content.Intent;
import android.os.Bundle;
import android.util.Log;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.View.OnClickListener;
public class Sudoku extends Activity implements OnClickListener {
private static final String TAG = "Sudoku";
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
// Set up click listeners for all the buttons
View continueButton = findViewById(R.id.continue_button);
continueButton.setOnClickListener(this);
View newButton = findViewById(R.id.new_button);
newButton.setOnClickListener(this);
View aboutButton = findViewById(R.id.about_button);
aboutButton.setOnClickListener(this);
View exitButton = findViewById(R.id.exit_button);
exitButton.setOnClickListener(this);
}
#Override
protected void onResume() {
super.onResume();
Music.play(this, R.raw.main);
}
#Override
protected void onPause() {
super.onPause();
Music.stop(this);
}
public void onClick(View v) {
switch (v.getId()) {
case R.id.continue_button:
startGame(Game.DIFFICULTY_CONTINUE);
break;
// ...
case R.id.about_button:
Intent i = new Intent(this, About.class);
startActivity(i);
break;
// More buttons go here (if any) ...
case R.id.new_button:
openNewGameDialog();
break;
case R.id.exit_button:
finish();
break;
}
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
super.onCreateOptionsMenu(menu);
MenuInflater inflater = getMenuInflater();
inflater.inflate(R.menu.menu, menu);
return true;
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.settings:
startActivity(new Intent(this, Prefs.class));
return true;
// More items go here (if any) ...
}
return false;
}
/** Ask the user what difficulty level they want */
private void openNewGameDialog() {
new AlertDialog.Builder(this)
.setTitle(R.string.new_game_title)
.setItems(R.array.difficulty,
new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialoginterface,
int i) {
startGame(i);
}
})
.show();
}
/** Start a new game with the given difficulty level */
private void startGame(int i) {
Log.d(TAG, "clicked on " + i);
Intent intent = new Intent(Sudoku.this, Game.class);
intent.putExtra(Game.KEY_DIFFICULTY, i);
startActivity(intent);
}
}
Game.Java
package org.example.sudoku;
import android.app.Activity;
import android.app.Dialog;
import android.os.Bundle;
import android.util.Log;
import android.view.Gravity;
import android.widget.Toast;
public class Game extends Activity {
private static final String TAG = "Sudoku";
public static final String KEY_DIFFICULTY =
"org.example.sudoku.difficulty";
private static final String PREF_PUZZLE = "puzzle" ;
public static final int DIFFICULTY_EASY = 0;
public static final int DIFFICULTY_MEDIUM = 1;
public static final int DIFFICULTY_HARD = 2;
protected static final int DIFFICULTY_CONTINUE = -1;
private int puzzle[] = new int[9 * 9];
private final String easyPuzzle =
"360000000004230800000004200" +
"070460003820000014500013020" +
"001900000007048300000000045";
private final String mediumPuzzle =
"650000070000506000014000005" +
"007009000002314700000700800" +
"500000630000201000030000097";
private final String hardPuzzle =
"009000000080605020501078000" +
"000000700706040102004000000" +
"000720903090301080000000600";
private PuzzleView puzzleView;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Log.d(TAG, "onCreate");
int diff = getIntent().getIntExtra(KEY_DIFFICULTY,
DIFFICULTY_EASY);
puzzle = getPuzzle(diff);
calculateUsedTiles();
puzzleView = new PuzzleView(this);
setContentView(puzzleView);
puzzleView.requestFocus();
// ...
// If the activity is restarted, do a continue next time
getIntent().putExtra(KEY_DIFFICULTY, DIFFICULTY_CONTINUE);
}
#Override
protected void onResume() {
super.onResume();
Music.play(this, R.raw.game);
}
#Override
protected void onPause() {
super.onPause();
Log.d(TAG, "onPause");
Music.stop(this);
// Save the current puzzle
getPreferences(MODE_PRIVATE).edit().putString(PREF_PUZZLE,
toPuzzleString(puzzle)).commit();
}
/** Given a difficulty level, come up with a new puzzle */
private int[] getPuzzle(int diff) {
String puz;
switch (diff) {
case DIFFICULTY_CONTINUE:
puz = getPreferences(MODE_PRIVATE).getString(PREF_PUZZLE,
easyPuzzle);
break;
// ...
case DIFFICULTY_HARD:
puz = hardPuzzle;
break;
case DIFFICULTY_MEDIUM:
puz = mediumPuzzle;
break;
case DIFFICULTY_EASY:
default:
puz = easyPuzzle;
break;
}
return fromPuzzleString(puz);
}
/** Convert an array into a puzzle string */
static private String toPuzzleString(int[] puz) {
StringBuilder buf = new StringBuilder();
for (int element : puz) {
buf.append(element);
}
return buf.toString();
}
/** Convert a puzzle string into an array */
static protected int[] fromPuzzleString(String string) {
int[] puz = new int[string.length()];
for (int i = 0; i < puz.length; i++) {
puz[i] = string.charAt(i) - '0';
}
return puz;
}
/** Return the tile at the given coordinates */
private int getTile(int x, int y) {
return puzzle[y * 9 + x];
}
/** Change the tile at the given coordinates */
private void setTile(int x, int y, int value) {
puzzle[y * 9 + x] = value;
}
/** Return a string for the tile at the given coordinates */
protected String getTileString(int x, int y) {
int v = getTile(x, y);
if (v == 0)
return "";
else
return String.valueOf(v);
}
/** Change the tile only if it's a valid move */
protected boolean setTileIfValid(int x, int y, int value) {
int tiles[] = getUsedTiles(x, y);
if (value != 0) {
for (int tile : tiles) {
if (tile == value)
return false;
}
}
setTile(x, y, value);
calculateUsedTiles();
return true;
}
/** Open the keypad if there are any valid moves */
protected void showKeypadOrError(int x, int y) {
int tiles[] = getUsedTiles(x, y);
if (tiles.length == 9) {
Toast toast = Toast.makeText(this,
R.string.no_moves_label, Toast.LENGTH_SHORT);
toast.setGravity(Gravity.CENTER, 0, 0);
toast.show();
} else {
Log.d(TAG, "showKeypad: used=" + toPuzzleString(tiles));
Dialog v = new Keypad(this, tiles, puzzleView);
v.show();
}
}
/** Cache of used tiles */
private final int used[][][] = new int[9][9][];
/** Return cached used tiles visible from the given coords */
protected int[] getUsedTiles(int x, int y) {
return used[x][y];
}
/** Compute the two dimensional array of used tiles */
private void calculateUsedTiles() {
for (int x = 0; x < 9; x++) {
for (int y = 0; y < 9; y++) {
used[x][y] = calculateUsedTiles(x, y);
// Log.d(TAG, "used[" + x + "][" + y + "] = "
// + toPuzzleString(used[x][y]));
}
}
}
/** Compute the used tiles visible from this position */
private int[] calculateUsedTiles(int x, int y) {
int c[] = new int[9];
// horizontal
for (int i = 0; i < 9; i++) {
if (i == y)
continue;
int t = getTile(x, i);
if (t != 0)
c[t - 1] = t;
}
// vertical
for (int i = 0; i < 9; i++) {
if (i == x)
continue;
int t = getTile(i, y);
if (t != 0)
c[t - 1] = t;
}
// same cell block
int startx = (x / 3) * 3;
int starty = (y / 3) * 3;
for (int i = startx; i < startx + 3; i++) {
for (int j = starty; j < starty + 3; j++) {
if (i == x && j == y)
continue;
int t = getTile(i, j);
if (t != 0)
c[t - 1] = t;
}
}
// compress
int nused = 0;
for (int t : c) {
if (t != 0)
nused++;
}
int c1[] = new int[nused];
nused = 0;
for (int t : c) {
if (t != 0)
c1[nused++] = t;
}
return c1;
}
}
PuzzleView.java
package org.example.sudoku;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Rect;
import android.graphics.Paint.FontMetrics;
import android.graphics.Paint.Style;
import android.os.Bundle;
import android.os.Parcelable;
import android.util.Log;
import android.view.KeyEvent;
import android.view.MotionEvent;
import android.view.View;
import android.view.animation.AnimationUtils;
public class PuzzleView extends View {
private static final String TAG = "Sudoku";
private static final String SELX = "selX";
private static final String SELY = "selY";
private static final String VIEW_STATE = "viewState";
private static final int ID = 42;
private float width; // width of one tile
private float height; // height of one tile
private int selX; // X index of selection
private int selY; // Y index of selection
private final Rect selRect = new Rect();
private final Game game;
public PuzzleView(Context context) {
super(context);
this.game = (Game) context;
setFocusable(true);
setFocusableInTouchMode(true);
// ...
setId(ID);
}
#Override
protected Parcelable onSaveInstanceState() {
Parcelable p = super.onSaveInstanceState();
Log.d(TAG, "onSaveInstanceState");
Bundle bundle = new Bundle();
bundle.putInt(SELX, selX);
bundle.putInt(SELY, selY);
bundle.putParcelable(VIEW_STATE, p);
return bundle;
}
#Override
protected void onRestoreInstanceState(Parcelable state) {
Log.d(TAG, "onRestoreInstanceState");
Bundle bundle = (Bundle) state;
select(bundle.getInt(SELX), bundle.getInt(SELY));
super.onRestoreInstanceState(bundle.getParcelable(VIEW_STATE));
return;
}
#Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
width = w / 9f;
height = h / 9f;
getRect(selX, selY, selRect);
Log.d(TAG, "onSizeChanged: width " + width + ", height "
+ height);
super.onSizeChanged(w, h, oldw, oldh);
}
#Override
protected void onDraw(Canvas canvas) {
// Draw the background...
Paint background = new Paint();
background.setColor(getResources().getColor(
R.color.puzzle_background));
canvas.drawRect(0, 0, getWidth(), getHeight(), background);
// Draw the board...
// Define colors for the grid lines
Paint dark = new Paint();
dark.setColor(getResources().getColor(R.color.puzzle_dark));
Paint hilite = new Paint();
hilite.setColor(getResources().getColor(R.color.puzzle_hilite));
Paint light = new Paint();
light.setColor(getResources().getColor(R.color.puzzle_light));
// Draw the minor grid lines
for (int i = 0; i < 9; i++) {
canvas.drawLine(0, i * height, getWidth(), i * height,
light);
canvas.drawLine(0, i * height + 1, getWidth(), i * height
+ 1, hilite);
canvas.drawLine(i * width, 0, i * width, getHeight(),
light);
canvas.drawLine(i * width + 1, 0, i * width + 1,
getHeight(), hilite);
}
// Draw the major grid lines
for (int i = 0; i < 9; i++) {
if (i % 3 != 0)
continue;
canvas.drawLine(0, i * height, getWidth(), i * height,
dark);
canvas.drawLine(0, i * height + 1, getWidth(), i * height
+ 1, hilite);
canvas.drawLine(i * width, 0, i * width, getHeight(), dark);
canvas.drawLine(i * width + 1, 0, i * width + 1,
getHeight(), hilite);
}
// Draw the numbers...
// Define color and style for numbers
Paint foreground = new Paint(Paint.ANTI_ALIAS_FLAG);
foreground.setColor(getResources().getColor(
R.color.puzzle_foreground));
foreground.setStyle(Style.FILL);
foreground.setTextSize(height * 0.75f);
foreground.setTextScaleX(width / height);
foreground.setTextAlign(Paint.Align.CENTER);
// Draw the number in the center of the tile
FontMetrics fm = foreground.getFontMetrics();
// Centering in X: use alignment (and X at midpoint)
float x = width / 2;
// Centering in Y: measure ascent/descent first
float y = height / 2 - (fm.ascent + fm.descent) / 2;
for (int i = 0; i < 9; i++) {
for (int j = 0; j < 9; j++) {
canvas.drawText(this.game.getTileString(i, j), i
* width + x, j * height + y, foreground);
}
}
if (Prefs.getHints(getContext())) {
// Draw the hints...
// Pick a hint color based on #moves left
Paint hint = new Paint();
int c[] = { getResources().getColor(R.color.puzzle_hint_0),
getResources().getColor(R.color.puzzle_hint_1),
getResources().getColor(R.color.puzzle_hint_2), };
Rect r = new Rect();
for (int i = 0; i < 9; i++) {
for (int j = 0; j < 9; j++) {
int movesleft = 9 - game.getUsedTiles(i, j).length;
if (movesleft < c.length) {
getRect(i, j, r);
hint.setColor(c[movesleft]);
canvas.drawRect(r, hint);
}
}
}
}
// Draw the selection...
Log.d(TAG, "selRect=" + selRect);
Paint selected = new Paint();
selected.setColor(getResources().getColor(
R.color.puzzle_selected));
canvas.drawRect(selRect, selected);
}
#Override
public boolean onTouchEvent(MotionEvent event) {
if (event.getAction() != MotionEvent.ACTION_DOWN)
return super.onTouchEvent(event);
select((int) (event.getX() / width),
(int) (event.getY() / height));
game.showKeypadOrError(selX, selY);
Log.d(TAG, "onTouchEvent: x " + selX + ", y " + selY);
return true;
}
#Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
Log.d(TAG, "onKeyDown: keycode=" + keyCode + ", event="
+ event);
switch (keyCode) {
case KeyEvent.KEYCODE_DPAD_UP:
select(selX, selY - 1);
break;
case KeyEvent.KEYCODE_DPAD_DOWN:
select(selX, selY + 1);
break;
case KeyEvent.KEYCODE_DPAD_LEFT:
select(selX - 1, selY);
break;
case KeyEvent.KEYCODE_DPAD_RIGHT:
select(selX + 1, selY);
break;
case KeyEvent.KEYCODE_0:
case KeyEvent.KEYCODE_SPACE: setSelectedTile(0); break;
case KeyEvent.KEYCODE_1: setSelectedTile(1); break;
case KeyEvent.KEYCODE_2: setSelectedTile(2); break;
case KeyEvent.KEYCODE_3: setSelectedTile(3); break;
case KeyEvent.KEYCODE_4: setSelectedTile(4); break;
case KeyEvent.KEYCODE_5: setSelectedTile(5); break;
case KeyEvent.KEYCODE_6: setSelectedTile(6); break;
case KeyEvent.KEYCODE_7: setSelectedTile(7); break;
case KeyEvent.KEYCODE_8: setSelectedTile(8); break;
case KeyEvent.KEYCODE_9: setSelectedTile(9); break;
case KeyEvent.KEYCODE_ENTER:
case KeyEvent.KEYCODE_DPAD_CENTER:
game.showKeypadOrError(selX, selY);
break;
default:
return super.onKeyDown(keyCode, event);
}
return true;
}
public void setSelectedTile(int tile) {
if (game.setTileIfValid(selX, selY, tile)) {
invalidate();// may change hints
} else {
// Number is not valid for this tile
Log.d(TAG, "setSelectedTile: invalid: " + tile);
startAnimation(AnimationUtils.loadAnimation(game,
R.anim.shake));
}
}
private void select(int x, int y) {
invalidate(selRect);
selX = Math.min(Math.max(x, 0), 8);
selY = Math.min(Math.max(y, 0), 8);
getRect(selX, selY, selRect);
invalidate(selRect);
}
private void getRect(int x, int y, Rect rect) {
rect.set((int) (x * width), (int) (y * height), (int) (x
* width + width), (int) (y * height + height));
}
// ...
}
Maybe an AlertDialog?http://developer.android.com/guide/topics/ui/dialogs.html#AlertDialog