Android game loop lag increases drastically over time - java

I am making this simple 2D canvas game using SurfaceView for android and am having this problem with my game loop: the fps immensely lowers as time goes on. I found the design for the game loop from this article: deWiTTERS Game Loop.
GamePanel.java
package jacobmahoney.guardianofearth;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Point;
import android.view.Display;
import android.view.MotionEvent;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.WindowManager;
public class GamePanel extends SurfaceView implements SurfaceHolder.Callback {
private MainThread thread;
private SpaceshipObject spaceship;
private LeftCircle leftCircle;
private RightCircle rightCircle;
private int screenWidth;
private int screenHeight;
public GamePanel(Context context) {
super(context);
getHolder().addCallback(this);
thread = new MainThread(getHolder(), this);
setFocusable(true);
getScreenSize(context);
spaceship = new SpaceshipObject(screenWidth, screenHeight);
leftCircle = new LeftCircle(screenWidth, screenHeight);
rightCircle = new RightCircle(screenWidth, screenHeight);
}
public void getScreenSize(Context context) {
WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
Display display = wm.getDefaultDisplay();
Point size = new Point();
display.getRealSize(size);
screenWidth = size.x;
screenHeight = size.y;
}
#Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
}
#Override
public void surfaceCreated(SurfaceHolder holder) {
thread = new MainThread(getHolder(), this);
thread.setRunning(true);
thread.start();
}
#Override
public void surfaceDestroyed(SurfaceHolder holder) {
boolean retry = true;
while (retry) {
try {
thread.setRunning(false);
thread.join();
} catch(Exception e) {
e.printStackTrace();
}
retry = false;
}
}
public void update() {
rightCircle.update();
}
#Override
public void draw(Canvas canvas) {
super.draw(canvas);
canvas.drawColor(Color.BLUE);
spaceship.draw(canvas);
leftCircle.draw(canvas);
rightCircle.draw(canvas);
}
}
MainThread.java
package jacobmahoney.guardianofearth;
import android.graphics.Canvas;
import android.util.Log;
import android.view.SurfaceHolder;
public class MainThread extends Thread {
private SurfaceHolder surfaceHolder;
private GamePanel gamePanel;
private boolean running;
public static Canvas canvas;
public void setRunning(boolean running) {
this.running = running;
}
public MainThread(SurfaceHolder surfaceHolder, GamePanel gamePanel) {
super();
this.surfaceHolder = surfaceHolder;
this.gamePanel = gamePanel;
}
#Override
public void run() {
int TICKS_PER_SECOND = 50;
int SKIP_TICKS = 1000 / TICKS_PER_SECOND;
int MAX_FRAMESKIP = 10;
long next_game_tick = System.currentTimeMillis();
int loops;
long prev = System.currentTimeMillis();
while (running) {
Log.d("MainThread", "" + (System.currentTimeMillis() - prev)); // this value drastically increases over time
prev = System.currentTimeMillis();
loops = 0;
while (System.currentTimeMillis() > next_game_tick && loops < MAX_FRAMESKIP) {
this.gamePanel.update();
next_game_tick += SKIP_TICKS;
loops++;
}
canvas = this.surfaceHolder.lockCanvas();
this.gamePanel.draw(canvas);
surfaceHolder.unlockCanvasAndPost(canvas);
}
}
}
Any help would be greatly appreciated, thanks!
EDIT:
After commenting out all the instances of the game objects: leftCircle, rightCircle, and spaceship completely from GamePanel.java, I didn't have the issue where the game gets increasingly laggy over time, which I guess is obvious. Then when I put just the spaceship game object back into the mix, the game still got increasingly laggy over time, but at a smaller rate than it was when I had all three game objects drawing to the canvas.
I am completely stumped, I have literally no idea what could be causing this... any ideas?
EDIT2:
removed
EDIT3:
Found out what the issue was. It was a problem with the code I was using to draw paths for each object. I forgot to place a path.reset() and path.close() before and after the code I used to draw the path. Also I removed my edit2 because I made a comment in the heat of my frustration, that was unwarranted.

Related

Java Game freezing on mouse click

I working on a small project and came across something that I didn't know how to fix. I tried looking into threads to see if this was the problem, but couldn't find anything to help me. The problem is that whenever I click on the frame, the key input, animations, etc, all freeze.
Here's the code for the main class: (let me know if you need code from any of the other classes, but I think the problem lies here)
package me.runeglaive.main;
import java.awt.BorderLayout;
import java.awt.Canvas;
import java.awt.Graphics;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.image.BufferStrategy;
import javax.swing.JFrame;
import me.runeglaive.gamestate.GameStateManager;
public class Game extends Canvas implements Runnable{
private static final long serialVersionUID = 1L;
public static int height = 360;
public static int width = height * 16 / 9;
public static int scale = 2;
private JFrame frame;
private Graphics g;
private boolean running = true;
GameStateManager gsm;
public Game(){
frame = new JFrame("Game");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(this, BorderLayout.CENTER);
frame.pack();
frame.setSize(width * scale, height * scale);
frame.setResizable(false);
frame.setLocationRelativeTo(null);
frame.setVisible(true);
gsm = new GameStateManager();
init();
MouseListener ml = new MouseListener(){
public void mousePressed(MouseEvent e) {
gsm.mousePressed(e);
}
public void mouseReleased(MouseEvent e) {
gsm.mouseReleased(e);
}
public void mouseClicked(MouseEvent e) {}
public void mouseEntered(MouseEvent e) {}
public void mouseExited(MouseEvent e) {}
};
KeyListener kl = new KeyListener(){
public void keyPressed(KeyEvent k) {
gsm.keyPressed(k);
}
public void keyReleased(KeyEvent k) {
gsm.keyReleased(k);
}
public void keyTyped(KeyEvent k) {
}
};
frame.addKeyListener(kl);
frame.addMouseListener(ml);
frame.setFocusable(true);
}
public void init(){
}
public void update(double delta){
gsm.update(delta);
}
public void render(){
//double buffering
BufferStrategy bs = getBufferStrategy();
if (bs == null){
createBufferStrategy(2);
return;
}
g = bs.getDrawGraphics();
//clear screen
g.clearRect(0, 0, getWidth(), getHeight());
//Draw gameState
gsm.render(g);
g.dispose();
bs.show();
}
public synchronized void start(){
running = true;
new Thread(this).start();
}
public synchronized void stop(){
running = false;
}
public void run() {
//initialize time loop variables
long lastLoopTime = System.nanoTime();
final int TARGET_FPS = 60;
final long OPTIMAL_TIME = 1000000000 / TARGET_FPS;
double lastFpsTime = 0;
while(running)
{
//Calculate since last update
long now = System.nanoTime();
long updateLength = now - lastLoopTime;
lastLoopTime = now;
double delta = updateLength / ((double)OPTIMAL_TIME);
//update frame counter
lastFpsTime += updateLength;
//update FPS counter
if(lastFpsTime >= 1000000000)
{
lastFpsTime = 0;
}
//game updates
update(delta);
//graphics (gameState)
render();
try{
Thread.sleep((Math.abs(lastLoopTime - System.nanoTime() + OPTIMAL_TIME)/1000000));
}catch(InterruptedException e){
System.out.println("Error in sleep");
}
}
}
public static void main(String args[]){
new Game().start();
}
}
Heres the Game State Manager:
package me.runeglaive.gamestate;
import java.awt.Graphics;
import java.awt.event.KeyEvent;
import java.awt.event.MouseEvent;
import java.util.ArrayList;
public class GameStateManager {
private ArrayList<GameState> states;
private int currentState;
public static final int MENUSTATE = 0;
public static final int MAINSTATE = 1;
public GameStateManager(){
states = new ArrayList<GameState>();
states.add(new MenuState(this));
states.add(new MainState(this));
setState(MAINSTATE);
}
public void setState(int state){
currentState = state;
states.get(state).init();
}
public int getCurrentState(){
return currentState;
}
public void update(double delta){
states.get(currentState).update(delta);
}
public void render(Graphics g){
states.get(currentState).render(g);
}
public void keyPressed(KeyEvent k){
states.get(currentState).keyPressed(k);
}
public void keyReleased(KeyEvent k){
states.get(currentState).keyReleased(k);
}
public void mousePressed(MouseEvent e){
states.get(currentState).mousePressed(e);
}
public void mouseReleased(MouseEvent e){
states.get(currentState).mouseReleased(e);
}
}
What is the code for gsm.mousePressed(e); and gsm.mouseReleased(e) please? :)
You're misusing Java Swing. You shall not create an own thread and redraw the scene programmatically, since this interferes with the threading model of the input queue.
If you're using swing, then instead of starting an own thread, start up a swing timer. Call the update from the event listener of the timer. Instead of calling render, issue a repaint() on the frame and override the painting code of the frame if you want to play nice.
http://www.oracle.com/technetwork/java/painting-140037.html
In case of AWT, there is both system triggered painting and application triggered paiting.
The code you're doing is a perfectly valid brute force game coder thinking - and perfectly valid if you're having a full control on the screen. In case of Swing, this is not the case, as Swing does take care of a lot more. If you're messing with Mr.Swing, it will bite you sooner or later ;-)
If you prefer taking this game development more seriously, look for a Java 2D game engine, or a Java 3D game engine (such as jMonkey) which takes care of all the details and offer working vertical retrace sync - which is unavoidable for smooth movements. Note that your BufferStrategy will not take care of that, this topic is a way more complex.

Android studio 2d game fps issue

I am trying do develop may first android game in 2d. I intend to build it from scratch without the use of an engine. I have manage to create the following thread:
import android.graphics.Canvas;
import android.view.SurfaceHolder;
public class MainThread extends Thread {
private int FPS = 30;
private double averageFPS;
private GamePanel gamePanel;
private SurfaceHolder surfaceHolder;
private boolean running;
public static Canvas canvas;
public MainThread(SurfaceHolder surfaceHolder, GamePanel gamePanel) {
super();
this.surfaceHolder = surfaceHolder;
this.gamePanel = gamePanel;
}
#Override
public void run() {
long startTime;
long timeMillis;
long waitTime;
long totalTime = 0;
int frameCount = 0;
// how many milliseconds it take to run through the loop
long targetTime = 1000 / FPS;
while (running) {
startTime = System.nanoTime();
canvas = null;
// try to lock the canvas for pixel editing
try {
canvas = this.surfaceHolder.lockCanvas();
synchronized (surfaceHolder) {
// the main game loop
this.gamePanel.update();
this.gamePanel.draw(canvas);
}
} catch (Exception e) {
} finally {
if (canvas != null) {
try {
surfaceHolder.unlockCanvasAndPost(canvas);
} catch (Exception e) {
e.printStackTrace();
}
}
}
timeMillis = (System.nanoTime() - startTime) / 1000000;
waitTime = targetTime - timeMillis;
try {
System.out.println(waitTime);
this.sleep(waitTime);
} catch (Exception e) {
}
totalTime += System.nanoTime() - startTime;
frameCount++;
if (frameCount == FPS) {
averageFPS = 1000 / ((totalTime / frameCount) / 1000000);
frameCount = 0;
totalTime = 0;
System.out.println(averageFPS);
}
}
}
The problem I have is that the averageFPS keeps dropping when adding stuff to my game. With only the background it works at 30 on my Nexus 5 but upon adding character and obstacles it drops to 22-21.
Is there anyway I can do to optimize this ?
Thank you
UPDATE: my GamePanel looks like this:
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Rect;
import android.graphics.Typeface;
import android.view.MotionEvent;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import java.util.ArrayList;
import java.util.Random;
public class GamePanel extends SurfaceView implements SurfaceHolder.Callback {
public static final int WIDTH = 1920;
public static final int HEIGHT = 1080;
public static float MOVESPEED = -12;
private Random rand = new Random();
private MainThread thread;
private Background bg;
private Treadmill tm;
private Player player;
private ArrayList<Box> boxes;
private int minDistance = 600;
private int score;
public GamePanel(Context context) {
super(context);
// add callback service to the holder to intercept events
getHolder().addCallback(this);
// make gamePanel focusable so it can handle events
setFocusable(true);
}
#Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
}
#Override
public void surfaceDestroyed(SurfaceHolder holder) {
boolean retry = true;
while (retry) {
try {
thread.setRunning(false);
thread.join();
retry = false;
thread = null;
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
#Override
public void surfaceCreated(SurfaceHolder holder) {
// instantiate objects
thread = new MainThread(getHolder(), this);
bg = new Background(BitmapFactory.decodeResource(getResources(), R.drawable.background));
tm = new Treadmill(BitmapFactory.decodeResource(getResources(), R.drawable.ground));
player = new Player(BitmapFactory.decodeResource(getResources(), R.drawable.character));
boxes = new ArrayList<Box>();
//start game loop
thread.setRunning(true);
thread.start();
}
#Override
public boolean onTouchEvent(MotionEvent event) {
if (event.getAction() == MotionEvent.ACTION_DOWN) {
if (player.jump == false) {
player.setVelocity(-14f);
player.setJump(true);
}
return true;
}
return super.onTouchEvent(event);
}
public void update() {
bg.update();
tm.update();
player.update();
if (boxes.size() == 0) {
boxes.add(new Box(BitmapFactory.decodeResource(getResources(), R.drawable.box),
WIDTH));
} else if (boxes.get(boxes.size() - 1).getX() < WIDTH) {
if (WIDTH - boxes.get(boxes.size() - 1).getX() < minDistance) {
boxes.add(new Box(BitmapFactory.decodeResource(getResources(), R.drawable.box),
rand.nextInt(400 - 50) + WIDTH + minDistance));
}
}
for (int i = 0; i < boxes.size(); i++) {
if (boxes.get(i).getX() <= player.getX() && boxes.get(i).getX() >= player.getX() - 12) {
score++;
MOVESPEED -= 0.2;
System.out.println(MOVESPEED);
}
if (collision(boxes.get(i), player)) {
boxes.remove(i);
break;
}
if (boxes.get(i).getX() < -100) {
boxes.remove(i);
break;
}
}
for (int i = 0; i < boxes.size(); i++) {
boxes.get(i).update();
}
}
#Override
public void draw(Canvas canvas) {
final float scaleFactorX = getWidth() / (WIDTH * 1.f);
final float scaleFactorY = getHeight() / (HEIGHT * 1.f);
if (canvas != null) {
final int saveState = canvas.save();
canvas.scale(scaleFactorX, scaleFactorY);
// draw the background
bg.draw(canvas);
tm.draw(canvas);
player.draw(canvas);
for (Box bx : boxes) {
bx.draw(canvas);
}
drawText(canvas);
canvas.restoreToCount(saveState);
}
}
public boolean collision(GameObject a, GameObject b) {
if (Rect.intersects(a.getRectangle(), b.getRectangle())) {
return true;
}
return false;
}
public void drawText(Canvas canvas) {
Paint paint = new Paint();
paint.setColor(Color.BLACK);
paint.setTextSize(50);
paint.setTypeface(Typeface.create(Typeface.DEFAULT, Typeface.BOLD));
canvas.drawText("Score: " + (score), 15, HEIGHT - 20, paint);
}
Thank you for all the help so far
The problem doesn't seem to be in the Main Thread Activity, you followed tutorial fine (Except for the line - System.out.println(waitTime); - but i don't think thats the problem cause.)
The problem is most likely in the GamePanel. ;)
Don't ever use Thread.sleep() in game loops. It is not guaranteed to sleep for the specified amount of time.
Anyway, I think that this is pretty much expected behaviour when using Canvas. If I were you I'd consider using OpenGL ES for anything like graphics rendering. Definitely, this makes it much more complex (even though Android has a lot of things already done for you). But the benefit is quite obvious - you get actual real-time graphics performance.

Handling TouchEvents concurrentModificationException android

I was trying to draw some balloons on screeen using canvas in SurfaceView class, I was successfully able to draw Multiple balloons on canvas and animate them by swapping different images. The problem is When I try touching on Oneballoon I need to remove it from screen .Here I get this exception and I am stuck
Code:
MainActivity:
package com.pradhul.game.touchball;
import android.app.Activity;
import android.os.Bundle;
public class MainActivity extends Activity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(new GameView(this));
/*TODO Hide the bottom navigation bar */
}
}
GameView.java
package com.pradhul.game.touchball;
import android.annotation.SuppressLint;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.util.Log;
import android.view.MotionEvent;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.View;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
public class GameView extends SurfaceView implements SurfaceHolder.Callback, View.OnTouchListener {
private static final int NUM_OF_BALLOONS = 5; //TODO for more than one balloons animations dont work(?)
/*use SurfaceView because we want complete control over the screen.
* unlike extending View class the oDraw() Method will not be called automatically
* from the method onSurfaceCreated() we have to call it Manually and pass a canvas object into it
* */
private final SurfaceHolder holder;
private GameLoopThread gameLoopThread;
private List<Balloon> balloons = new ArrayList<>();
public GameView(Context context) {
super(context);
gameLoopThread = new GameLoopThread(this);
holder = getHolder();
holder.addCallback(this);
createBalloons(NUM_OF_BALLOONS);
this.setOnTouchListener(this);
}
private void createBalloons(int count) {
for(int i=0 ; i< count ;i++){
balloons.add(createBalloon());
}
}
#Override
protected void onDraw(Canvas canvas) {
if(canvas != null) {
canvas.drawColor(Color.WHITE);
for(Balloon balloon : balloons){
try {
gameLoopThread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
balloon.onDraw(canvas);
}
}
}
#SuppressLint("WrongCall")
#Override
public void surfaceCreated(SurfaceHolder holder) {
/*this is called when the view is created*/
gameLoopThread.setRunning(true);
gameLoopThread.start();
}
#Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
}
#Override
public void surfaceDestroyed(SurfaceHolder holder) {
/*pausing game Thread*/
gameLoopThread.setRunning(false);
while (true){
try {
gameLoopThread.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
private Balloon createBalloon(){
return new Balloon(this);
}
#Override
public synchronized boolean onTouch(View v, MotionEvent event) {
Log.d("OnTouch real -", "x: " + event.getX() + ", Y: " + event.getY());
/* for (int i = balloons.size()-1; i >= 0; i--) {
Balloon balloon = balloons.get(i);
Log.d("OnTouch collision -", !balloon.isCollision(event.getX(), event.getY())+"");
if (!balloon.isCollision(event.getX(), event.getY())) {
balloons.remove(0);
break;
}
}*/
Iterator<Balloon> balloonIterator = balloons.iterator();
while(balloonIterator.hasNext()){
Balloon balloon = balloonIterator.next();
balloons.remove(0);
}
return true;
}
}
GameLoopThread.java
package com.pradhul.game.touchball;
import android.annotation.SuppressLint;
import android.graphics.Canvas;
public class GameLoopThread extends Thread {
private GameView view;
private boolean running = false;
public GameLoopThread(GameView view){
this.view = view;
}
public void setRunning(boolean run){
running = run;
}
#SuppressLint("WrongCall")
public void run(){
while (running){
Canvas canvas = null;
try{
canvas = view.getHolder().lockCanvas();
synchronized (view.getHolder()){
view.onDraw(canvas);
}
}finally{
if(canvas != null) {
view.getHolder().unlockCanvasAndPost(canvas);
}
}
}
}
}
Balloon.java
package com.pradhul.game.touchball;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.util.Log;
import java.util.Random;
public class Balloon {
private static final int BALLOON_SPEED = 10;
private int y = 0;
private int x = 0;
private int speed = 1;
private GameView gameView;
private Bitmap balloon;
public Bitmap[] normalBalloons;
private int balloonIndex = 0;
private int normalImages[] = {R.drawable.normal_01,R.drawable.normal_02,R.drawable.normal_03,
R.drawable.normal_04,R.drawable.normal_05,R.drawable.normal_06,R.drawable.normal_07,
R.drawable.normal_08,
};
private int crackingImages[] = {R.drawable.crack_01,R.drawable.crack_02,R.drawable.crack_03,
R.drawable.crack_04, R.drawable.crack_05,R.drawable.crack_04,R.drawable.crack_03,
R.drawable.crack_02
};
private boolean reverseSwap = false;
public Balloon(GameView gameView){
this.gameView = gameView;
normalBalloons = new Bitmap[8];
setUpImages();
}
public void onDraw(Canvas canvas){
/*draws the balloon in canvas */
animateBalloon();
update(canvas.getWidth());
canvas.drawBitmap(balloon, x, y, null);
}
public boolean isCollision(float x2, float y2) {
return x2 > x && x2 < x + balloon.getWidth() && y2 > y && y2 < y + balloon.getHeight();
}
private int getRandomX(int maxVal) {
Random rand = new Random();
return rand.nextInt(maxVal);
}
private void animateBalloon() {
/*Animates the balloon by swapping resource image at each call*/
this.balloon = getBalloons();
Log.d("Balloon",balloonIndex % normalBalloons.length + "");
}
private void update(int canvasWidth) {
/*updates the y position for moving the balloon*/
if (y <= 0){
/*so that the balloon starts from bottom
* gameView will return a height only after the View is ready
* getting 0 in constructor of this class*/
y = gameView.getHeight();
/*x is assigned a random between the width od the canvas
* so that the balloons will appear random positions from below*/
x = getRandomX(canvasWidth - balloon.getWidth());
}
if (y > gameView.getHeight() - balloon.getHeight() - speed) {
speed = -BALLOON_SPEED;
}
y = y + speed;
Log.d("Balloon","Positions:"+x+","+y);
}
private Bitmap getBalloons() {
if(balloonIndex == normalBalloons.length-1) {
reverseSwap = true;
}
if(balloonIndex == 0){
reverseSwap = false;
}
balloonIndex = reverseSwap?balloonIndex-1:balloonIndex+1;
return normalBalloons[balloonIndex];
}
private void setUpImages() {
/*setting up resources array*/
for(int count =0; count < normalImages.length; count++){
Bitmap balloon = BitmapFactory.decodeResource(gameView.getResources(), normalImages[count]);
normalBalloons[count] = balloon;
}
}
}
I am confused that why it causes an error like this , Can anybody can take look at it and suggest me a solution, is this the right way to remove ?
please share any suggestion
Thanks
It's the wrong way to remove.
If you iterate over a Collection / List, and want to remove the current element, you must use Iterator.remove() method.
In your case, simply call balloonIterator.remove() instead of balloons.remove(0)
Even simpler, since you want to remove all elements from the list - you should simply call balloons.clear() and remove the loop completely.
This exception is due to concurrent modification of list balloons.
As soon as you touch surface view onDraw() gets invoked with onTouch(), in which you are working on list balloons.
I think you should add touch listener to balloon instead of GameView.
okay ,
I need to wrap all my code inside a synchronized holder inorder this to work
(don't know much about it)
#Override
public boolean onTouch(View v, MotionEvent event) {
Log.d("OnTouch","x:"+event.getX()+"Y:"+event.getY());
synchronized (getHolder()){
for (int i=0 ;i<balloons.size();i++){
balloons.remove(0);
break;
}
}
return true;
}

want to count time in activity when it starts

a small time based question > I want to get timer in activity I already tryed this code but it runs so fast I offen get " 0 " I want to program to run with no sleep . but to count from 0 to 60 sec
package com.okok;
import java.util.ArrayList;
import java.util.List;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.os.Handler;
import android.os.SystemClock;
import android.view.MotionEvent;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.SurfaceHolder.Callback;
import android.widget.Chronometer;
class GameView extends SurfaceView {
//private Bitmap bmp;
// Chronometer mChronometer;
private SurfaceHolder holder;
private GameLoopThread gameLoopThread;
private List<Sprite> sprites = new ArrayList<Sprite>();
private long lastClick;
private Bitmap bmpBlood;
Handler m_handler;
Runnable m_handlerTask ;
private List<TempSprite> temps = new ArrayList<TempSprite>();
public GameView(Context context) {
super(context);
gameLoopThread = new GameLoopThread(this);
holder = getHolder();
holder.addCallback(new Callback() {
#Override
public void surfaceDestroyed(SurfaceHolder holder) {
}
#Override
public void surfaceCreated(SurfaceHolder holder) {
createSprites();
gameLoopThread.setRunning(true);
gameLoopThread.start();
}
#Override
public void surfaceChanged(SurfaceHolder holder, int format,
int width, int height) {
}
});
bmpBlood = BitmapFactory.decodeResource(getResources(), R.drawable.blast2);
}
private void createSprites() {
sprites.add(createSprite(R.drawable.greenenact));
// sprites.add(createSprite(R.drawable.greenenact));
// sprites.add(createSprite(R.drawable.greenenact));
}
private Sprite createSprite(int resouce) {
Bitmap bmp = BitmapFactory.decodeResource(getResources(), resouce);
return new Sprite(this, bmp);
}
#Override
protected void onDraw(Canvas canvas) {
canvas.drawColor(Color.rgb(21, 181, 195));
for (int i = temps.size() - 1; i >= 0; i--) {
temps.get(i).onDraw(canvas);
}
final int count=0;
m_handler = new Handler();
m_handlerTask = new Runnable()
{
#Override
public void run() {
// do something
if(count=60)
{
m_handler.removeCallbacks(m_handlerTask);
}
count++;
m_handler.postDelayed(m_handlerTask, 5000);
for (Sprite sprite : sprites) {
sprite.onDraw(canvas);
}
}
};
m_handlerTask.run();
}
#Override
public boolean onTouchEvent(MotionEvent event) {
if (System.currentTimeMillis() - lastClick > 500) {
lastClick = System.currentTimeMillis();
synchronized (getHolder()) {
float x = event.getX();
float y =event.getY();
for (int i = sprites.size() - 1; i >= 0; i--) {
Sprite sprite = sprites.get(i);
if (sprite.isCollition(x, y)) {
sprites.remove(sprite);
temps.add(new TempSprite(temps, this, x, y, bmpBlood));
break;
}
}
}
}
return true;
}
}
this is my program I have only one error
can not change count from int to a boolean error
I don't want to use sleep method because my application have sleep method that affect my animation
or give me a program that counts 0 to 60 sec and displays which runs without a sleep method
Use chronometer instead. Here is example ,
Example 2
Use a Handler
Handler m_handler;
Runnable m_handlerTask ;
int count=0;
m_handler = new Handler();
m_handlerTask = new Runnable()
{
#Override
public void run() {
// do something
if(count=60)
{
m_handler.removeCallbacks(m_handlerTask);
}
count++:
m_handler.postDelayed(m_handlerTask, 1000);
// repeat some task every 1 second
}
};
m_handlerTask.run();

Android while touch and touch release

Hi, I have recently started trying to make android apps
and have currently made a few simple ones, but, I am still really confused with the touch methods.
What I'm trying to do is: When your finger is held down on the screen, x increments, but it stops when you release your finger. The problem is that I can't find any method or any way of doing this.
Here is my code:
import java.util.Timer;
import java.util.TimerTask;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.view.MotionEvent;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
public class zombView extends SurfaceView{
private Bitmap bmp, grass, joystick;
private SurfaceHolder holder;
Timer t = new Timer();
float x = 0, y = 0;
boolean forward;
public zombView(Context context) {
super(context);
holder = getHolder();
holder.addCallback(new SurfaceHolder.Callback() {
#Override
public void surfaceDestroyed(SurfaceHolder holder) {
}
#Override
public void surfaceCreated(final SurfaceHolder holder) {
t.scheduleAtFixedRate(new TimerTask(){
public void run(){
Canvas c = holder.lockCanvas(null);
onDraw(c);
holder.unlockCanvasAndPost(c);
if(forward == true){
x++;
}
}
},200,200);
}
#Override
public void surfaceChanged(SurfaceHolder holder, int format,
int width, int height) {
}
});
bmp = BitmapFactory.decodeResource(getResources(), R.drawable.ic_launcher);
grass = BitmapFactory.decodeResource(getResources(), R.drawable.grassland);
joystick = BitmapFactory.decodeResource(getResources(), R.drawable.joystic);
}
#Override
protected void onDraw(Canvas canvas) {
canvas.drawColor(Color.BLACK);
canvas.drawBitmap(grass, getWidth() - getWidth(), getHeight() - getHeight(), null);
canvas.drawBitmap(joystick, getWidth() - getWidth(),joystick.getHeight(), null);
canvas.drawBitmap(bmp, x, y, null);
}
#Override
public boolean onTouchEvent(MotionEvent event) {
if(event.getX() > 10 && event.getX() < 1000){
if(event.getY() > 10 && event.getY() < 1000){
x++;
}
}
return super.onTouchEvent(event);
}
}
The MotionEvent class has a getAction method, which specifies what kind of event did your onTouchEvent method has just received. There are three actions that you will use more often:
ACTION_DOWN, which tells you that the user has just put his finger on the screen;
ACTION_MOVE, which tells that the user is still holding his finger on the screen;
ACTION_UP, which tells that the user has taken his finger off the screen.
Depending on what kind of event has just been acquired by your listener you can change the behavior of your code. For more information check the documentation. Hope this helps.

Categories