I am doing a game .I want creat a counter .It begin from 200 and then 1s reduced about 0 .It my code :
public class GameView extends View{
private int count = 200;
private TimeCountThread timeCountThread;
public GameView(Context context, AttributeSet attrs) {
super(context, attrs);
timeCountThread = new TimeCountThread();
timeCountThread.start();
}
protected void onDraw(Canvas canvas) {
Paint paint = new Paint();
paint.setColor(Color.WHITE);
canvas.drawText("Time :"+count, 10, 35, paint);
}
public class TimeCountThread extends Thread{
public void run(){
while(count > 0){
try {
sleep(1000);
count--;
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
public boolean onTouchEvent(MotionEvent event){
if(event.getAction()==MotionEvent.ACTION_DOWN){
int x1=(int) event.getX();
int y1=(int) event.getY();
Toast.makeText(getContext(), "x1 = "+x1+", y1 ="+y1,1).show();
}
return true;
}
}
Why the counter don't activity .Please help me?
Thanks
I want creat a counter .It begin from 200 and then 1s reduced about 0
You can achieve it by CountDownTimer
Try using a handler with a runnable inside of it. Such as:
Handler handler=new Handler();
Runnable r=new Runnable() {
public void run() {
count--;
if(count > 0) {
handler.postDelayed(this, 1000);
}
}
};
if(count > 0) {
handler.postDelayed(r, 1000);
}
where your
timeCountThread = new TimeCountThread();
timeCountThread.start();
is. Another problem might be that your count is private, but I don't think that that will make that big of a difference.
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>
I am trying to set a text which acts as a timer. I'll create timer easily if i extend Activity class. But i am facing lot of problem in this View class. Here i made a code where radius of circle will be reducing and it will be increased for each touch on screen. Simultaneously i need a timer running on the top. Because i need to increase the reducing speed after every 10 seconds.
So here timer plays an important role. I tried using thread , which should update the text for every 1 second . But it is showing this exception IllegalThreadStateException.
Is there any other way to implement timer in this screen ?
Or What mistake i did in my code..
Thanks for you help friends..
package com.kbt.testcircle;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.os.Handler;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
public class MyView extends View {
int radius = 100,i=0;
boolean freeTouched = false;
Path freePath;
Handler handler = new Handler();
public MyView(Context context) {
super(context);
}
public MyView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public MyView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
public void calThread() {
/*
* Thread th=new Thread(){ public void run(){ try { sleep(2000); } catch
* (InterruptedException e) { // TODO Auto-generated catch block
* e.printStackTrace(); } finally{ radius-=1;
* Log.i("kbt","inside thread 800 seconds"); } } }; th.start();
*/
handler.postDelayed(new Runnable() {
#Override
public void run() {
// TODO Auto-generated method stub
radius -= 1;
Log.i("kbt", "inside thread 800 seconds");
invalidate();
}
}, 500);
Log.i("kbt", "Inside thread");
}
Thread th=new Thread()
{
public void run(){
handler.postDelayed(new Runnable() {
#Override
public void run() {
// TODO Auto-generated method stub
i++;
}
},1000);
}
};
#Override
protected void onDraw(Canvas canvas) throws IllegalThreadStateException
{
// TODO Auto-generated method stub
th.start();
Log.i("kbt","starting");
super.onDraw(canvas);// th.start();
Paint paint = new Paint();
paint.setStyle(Paint.Style.STROKE);
paint.setColor(Color.WHITE);
paint.setStrokeWidth(3);
canvas.drawCircle(getWidth() / 2, getHeight() / 2, radius, paint);
paint.setColor(Color.WHITE);
paint.setStrokeWidth(0);
paint.setTextSize(25);
canvas.drawText("Timer : "+i, getWidth()/4, getHeight()/4, paint);
calThread();
Log.i("kbt", "Inside clled");
}
#Override
public boolean onTouchEvent(MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_UP:
break;
case MotionEvent.ACTION_DOWN:
radius+=5;
invalidate();
/* freeTouched = true;
freePath = new Path();
freePath.moveTo(event.getX(), event.getY()); */
break;
case MotionEvent.ACTION_MOVE:
/* freePath.lineTo(event.getX(), event.getY());
invalidate(); */
break;
}
return true;
}
}
But it is showing this exception IllegalThreadStateException.
It caused by non-runnable or non-threading class. A class that extends View has no background thread on it, so that you get IllegalThreadStateException.
Is there any other way to implement timer in this screen?
Java provided a Timer class to be used for all of class types:
Timer timer = new Timer();
TimerTask task = new TimerTask(){
#Override
public void run() {
// do your thing here
}
};
timer.schedule(task,
1, // delay the task 1ms before executed
10000); // repeating your task every 10000ms, i.e. 10 seconds
If you really one to use a thread, you could only start the thread once. If you want to start thread for many times, use Runnable instead.
I know this may seem like a noob question but I've tried everything. I want to animate a number incrementing. So I set up a view. I made a thread inside the view that loops a certain amount of times. In the loop I call Thread.sleep and then I increment a number. However I'm not sure how to call the invalidate() method to update the view each time it goes through the loop. I've tried a callback but that isn't working. Your help would be appreciated. What I'm trying to increment is the 'centerText' which is drawn using textPaint
public class GameView extends View {
private int backgroundColor;
private int circleColor;
private int radiusFactor;
private Paint circlePaint;
private Paint textPaint;
private Paint text2Paint;
private Paint text3Paint;
private String topMessage;
private String bottomMessage;
private String topMessage2;
private String bottomMessage2;
private String centerText;
private boolean isRunning = false;
private int FPS = 60;
public interface animateThread{
public void updateUI(String text);
}
private animateThread threadCheck = new animateThread(){
#Override
public void updateUI(String text) {
centerText="text";
invalidate();
}
};
public GameView(Context context) {
super(context);
backgroundColor = Color.parseColor("#FF4000");
circleColor = Color.parseColor("#B40404");
radiusFactor = 4;
centerText="?";
circlePaint = new Paint();
circlePaint.setAntiAlias(true);
circlePaint.setColor(circleColor);
textPaint = new Paint();
textPaint.setAntiAlias(true);
textPaint.setColor(Color.WHITE);
textPaint.setTextAlign(Paint.Align.CENTER);
text2Paint = new Paint();
text2Paint.setAntiAlias(true);
text2Paint.setColor(Color.BLACK);
text2Paint.setTextAlign(Paint.Align.CENTER);
text3Paint = new Paint();
text3Paint.setAntiAlias(true);
text3Paint.setColor(Color.BLACK);
text3Paint.setTextAlign(Paint.Align.CENTER);
topMessage = "One in a";
topMessage2="Hundred?";
bottomMessage="Click the Circle";
bottomMessage2="To find out";
}
#Override
public boolean onTouchEvent(MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
break;
case MotionEvent.ACTION_UP:
break;
case MotionEvent.ACTION_MOVE:
break;
}
if(!isRunning) startAnimation(threadCheck);
return true;
}
#Override
protected void onDraw(Canvas canvas) {
setBackgroundColor(backgroundColor);
textPaint.setTextSize(getWidth()/4);
text2Paint.setTextSize(getWidth()/6);
text3Paint.setTextSize(getWidth()/8);
canvas.drawCircle(getWidth()/2, getHeight()/2,getWidth()/radiusFactor,
circlePaint);
canvas.drawText(centerText, getWidth()/2, getHeight()/2-
((textPaint.descent()+textPaint.ascent())/2), textPaint);
canvas.drawText(topMessage, getWidth()/2, ((getHeight()/2-
getWidth()/radiusFactor)/2+((text2Paint.descent()+text2Paint.ascent())/2)),
text2Paint);
canvas.drawText(topMessage2, getWidth()/2, (getHeight()/2-
getWidth()/radiusFactor)/2-((text2Paint.descent()+text2Paint.ascent())),
text2Paint);
canvas.drawText(bottomMessage, getWidth()/2, getHeight()*4/5+
((text3Paint.descent()+text3Paint.ascent())/2), text3Paint);
canvas.drawText(bottomMessage2, getWidth()/2, getHeight()*4/5-
((text3Paint.descent()+text3Paint.ascent())), text3Paint);
}
public void startAnimation(final animateThread mCallback) {
Thread animate = new Thread(new Runnable(){
#Override
public void run() {
isRunning=true;
int count=0;
for (int i=0;i<FPS*5;i++) {
count++;
if(count>100) count = 1;
mCallback.updateUI(count+"");
try {
Thread.sleep(1000/FPS);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
isRunning=false;
}
});
animate.start();
}
}
Anything invoked within
new Thread(new Runnable(){
...
}
Will implicitly run on a non-UI thread. If you want to touch the UI, the code for that task must be forced to run on the UI thread like this:
context.runOnUiThread(new Runnable() {
#Override
public void run() {
updateUI(count+"");
}
});
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!
Is it possible to pass arguments to an Android Handler?? I have two pieces of code.
new Thread(){
public void run(){
for(;;){
uiCallback.sendEmptyMessage(0);
Thread.sleep(2000); //sleep for 2 seconds
}
}
}.start();
private Handler uiCallback = new Handler(){
public void handleMessage(Message msg){
//add a new blossom to the blossom ArrayList!!
blossomArrayList.add(new Blossom(context, R.drawable.blossom));
}
};
I of course get an error because the Handler method cannot see my context. This is probably because of this piece of code
public BoardView(Context context){
super(context);
Context is not visible elsewhere, and I'm wondering if I can pass it as an argument to my Handler.
EDIT: I am posting the two main pieces of code to answer a question about why my Blossom object needs context. I myself am not 100% sure >.> Maybe you could have a look and see what's going on.
public class Blossom{
private Bitmap blossom;
private float blossomX = 0;
private float blossomY = 0;
private Random generator = new Random();
public Blossom(Context context, int drawable)
{
blossom = BitmapFactory.decodeResource(context.getResources(), drawable);
blossomX = generator.nextInt(300);
}
public Bitmap getBitmap()
{
return blossom;
}
public float getBlossomX()
{
return blossomX;
}
public float getBlossomY()
{
return blossomY;
}
public void Fall(Canvas canvas, float boxY)
{
//draws the flower falling
canvas.drawBitmap(blossom, blossomX,
blossomY = blossomY+3 , null);
//collision detection, currently not working after
//implementing random start location
//if(blossomY + 29 == boxY)
//{
//canvas.drawBitmap(blossom,0,0,null);
//}
}
}
public class BoardView extends SurfaceView implements SurfaceHolder.Callback{
Context mContext;
Bitmap box =
(BitmapFactory.decodeResource
(getResources(), R.drawable.box));
private BoardThread thread;
private float box_x = 140;
private float box_y = 378;
private float boxWidth = box.getWidth();
private float boxHeight = box.getHeight();
private ArrayList<Blossom> blossomArrayList = new ArrayList<Blossom>();;
boolean mode = false;
RectF boxRect = new RectF(box_x,box_y, box_x + boxWidth, box_y + boxHeight);
public BoardView(Context context){
super(context);
//surfaceHolder provides canvas that we draw on
getHolder().addCallback(this);
// controls drawings
thread = new BoardThread(getHolder(),this);
//pass variables to instance of Blossom
//for(int i = 0; i <= 3; i++)
//{
//blossomArrayList.add(new Blossom(context, R.drawable.blossom));
//}
new Thread(){
public void run(){
for(;;){
uiCallback.sendEmptyMessage(0);
Thread.sleep(2000); //sleep for 2 seconds
}
}
}.start();
//intercepts touch events
setFocusable(true);
}
#Override
public void onDraw(Canvas canvas){
canvas.drawColor(Color.WHITE);
//draw box and set start location
canvas.drawBitmap(box, box_x - (boxWidth/2),
box_y - (boxHeight/2), null);
for(int i = 0; i<= 3; i++)
{
blossomArrayList.get(i).Fall(canvas, box_y);
}
}
#Override
public boolean onTouchEvent(MotionEvent event){
if(event.getAction() == MotionEvent.ACTION_DOWN){
if(boxRect.contains(event.getX(),event.getY())){
mode = true;
}
}
if(event.getAction() == MotionEvent.ACTION_MOVE) {
if(boxRect.contains(event.getX(),event.getY())){
mode = true;
}
if(mode == true){
box_x = (int)event.getX();
boxRect.set(box_x,box_y, box_x + boxWidth, box_y + boxHeight);
}
}
if(event.getAction() == MotionEvent.ACTION_UP){
mode = false;
}
invalidate();
return true;
}
#Override
public void surfaceChanged(SurfaceHolder holder,
int format, int width, int height ){
}
#Override
public void surfaceCreated(SurfaceHolder holder){
thread.startRunning(true);
thread.start();
}
#Override
public void surfaceDestroyed(SurfaceHolder holder){
thread.startRunning(false);
thread.stop();
}
private Handler uiCallback = new Handler(){
public void handleMessage(Message msg){
//add a new blossom to the blossom ArrayList!!
blossomArrayList.add(new Blossom(context, R.drawable.blossom));
}
};
}
Create a class that extends Handler, and store a weak reference to the context. This will help prevent some memory issues.
public class SomeHandler extends Handler {
// A weak reference to the enclosing context
private WeakReference<Context> mContext;
public SomeHandler (Context context) {
mContext = new WeakReference<Context>(context);
}
public void handleMessage(Message msg) {
// Get an actual reference to the DownloadActivity
// from the WeakReference.
Context context=mContext.get();
...
}
}
What if you create a subclass which extends Handler? That way you could pass any parameters you want.
But just out of curiosity, why does the Blossom object require the context object? It's usually best to separate your logic from GUI dependencies.