I made an infinite background for an Android 2D game but the background scrolls only one time and doesn't loop. How can I fix this?
Another question: How do I make this same background fall from the top to bottom? For a game
.
This is my class (code):
public class GameView extends View implements Runnable {
private static final int INTERVAL = 10;
private boolean running = true;
private int y;
private Paint paint;
private int z = 0;
int sx;
Bitmap background;
public GameView(Context context){
super(context);
paint = new Paint();
background = BitmapFactory.decodeResource(getResources(), R.drawable.back);
Thread myThread = new Thread(this);
myThread.setPriority(Thread.MIN_PRIORITY);
myThread.start();
}
#Override
public void run() {
while (running) {
try {
Thread.sleep(INTERVAL);
} catch (InterruptedException e) {
Log.e("Game", "Gameloop finished!");
}
update();
}
}
private void update() {
if (y < getHeight()) {
y += 5;
} else {
y = 0;
}
postInvalidate();
}
public void draw(Canvas canvas) {
super.draw(canvas);
z = z-10;
if(z == -sx) {
z = 0;
canvas.drawBitmap(background, z, 0, null);
} else {
canvas.drawBitmap(background, z, 0, null);
}
}
public void release() {
running = false;
}
}
Related
This message is being displayed when i try to generate a signed apk
Error in surfaceView implements Runnable class should provide a default constructor (a public constructor with no arguments)"
and yet surfaceView implements Runnable does not support a default constructor... when I I try to put a default constructor an error comes again
the class doesn't allow a default constructor
what else could be done to solve this problem?
Here is my code
public class view extends SurfaceView implements
Runnable {
volatile boolean playing;
private Thread gameThread = null;
private king myKing;
private Paint paint;
private Canvas canvas;
private SurfaceHolder surfaceHolder;
private lebel myLebel;
private fire myFire;
private worldking peace;
int screenX;
int countCollisions;
boolean flag ;
int i;
private boolean isGameOver ;
private boolean congrats;
int score;
int highScore[] = new int[4];
SharedPreferences sharedPreferences;
public view(Context context, int screenX, int screenY) {
super(context);
myKing = new king(context, screenX, screenY);
surfaceHolder = getHolder();
paint = new Paint();
myLebel = new lebel(context, screenX, screenY);
myFire = new fire(context);
peace = new worldking(context, screenX, screenY);
this.screenX = screenX;
countCollisions = 0;
isGameOver = false;
congrats= false;
score = 0;
}
#Override
public void run() {
while (playing) {
update();
draw();
control();
}
}
private void update() {
score++;
myKing.update();
myFire.setX(-250);
myFire.setY(-250);
if (myLebel.getX() == screenX) {
flag = true;
}
myLebel.update(myKing.getSpeed());
if (Rect.intersects(myKing.getDetectCollision(),
myLebel.getDetectCollision())) {
myFire.setX(myLebel.getX());
myFire.setY(myLebel.getY());
myLebel.setX(-200);
}
peace.update(myKing.getSpeed());
if (Rect.intersects(myKing.getDetectCollision(),
peace.getDetectCollision())) {
myFire.setX(peace.getX());
myFire.setY(peace.getY());
playing = false;
isGameOver = true;
myLebel.setX(-200);
}
}
private void draw() {
if (surfaceHolder.getSurface().isValid()) {
canvas = surfaceHolder.lockCanvas();
canvas.drawColor(Color.BLACK);
paint.setTextSize(30);
paint.setColor(WHITE);
canvas.drawText("SCORE:"+score,100,50,paint);
canvas.drawBitmap(
myKing.getBitmap(),
myKing.getX(),
myKing.getY(),
paint);
canvas.drawBitmap(
myLebel.getBitmap(),
myLebel.getX(),
myLebel.getY(),
paint
);
canvas.drawBitmap(
myFire.getBitmap(),
myFire.getX(),
myFire.getY(),
paint
);
canvas.drawBitmap(
peace.getBitmap(),
peace.getX(),
peace.getY(),
paint
);
if(isGameOver){
paint.setTextSize(100);
paint.setColor(WHITE);
paint.setTextAlign(Paint.Align.CENTER);
int yPos=(int) ((canvas.getHeight() / 2) -
((paint.descent() + paint.ascent()) / 2));
canvas.drawText("Oops! Try
Again !",canvas.getWidth()/2,yPos,paint);
}
surfaceHolder.unlockCanvasAndPost(canvas);
}
}
private void control() {
try {
gameThread.sleep(17);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public void pause() {
playing = false;
try {
gameThread.join();
} catch (InterruptedException e) {
}
}
public void resume() {
playing = true;
gameThread = new Thread(this);
gameThread.start();
}
This is my first time working with android, and I'm having some trouble drawing on a canvas repeatedly inside a thread. It seems that it only gets drawn once, although the thread is running which I made sure using a toast that popped up each time the thread executed (I've removed it because it was bothering me) but the thread is running and the code inside gets executed, it just sort of doesn't redraw...
public class GameActivity extends Activity implements Runnable{
ImageView gameView;
public int screenWidth, screenHeight, objectSize;
private static int FPS = 30;
private boolean rightPressed = false, leftPressed = false;
private Player player;
private Thread thread;
private Canvas canvas;
private Bitmap blankBitmap;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Display display = getWindowManager().getDefaultDisplay();
Point size = new Point();
display.getSize(size);
screenWidth = size.x;
screenHeight = size.y;
objectSize = screenWidth/8;
player = new Player(objectSize, screenWidth/2 - objectSize/2, screenHeight - (objectSize+10));
blankBitmap = Bitmap.createBitmap(screenWidth,screenHeight,Bitmap.Config.ARGB_8888);
canvas = new Canvas(blankBitmap);
gameView = new ImageView(this);
gameView.setImageBitmap(blankBitmap);
draw();
setContentView(gameView);
thread = new Thread(this);
thread.start();
}
#Override
public boolean onTouchEvent(MotionEvent event) {
if(event.getAction() == MotionEvent.ACTION_DOWN) {
leftPressed = true;
if((int)event.getX()<=screenWidth/2){
leftPressed = true;
rightPressed = false;
Toast.makeText(this, "left", Toast.LENGTH_SHORT).show();
}
if((int)event.getX()>screenWidth/2){
rightPressed = true;
leftPressed = false;
Toast.makeText(this, "right", Toast.LENGTH_SHORT).show();
}
}
if(event.getAction() == MotionEvent.ACTION_UP) {
rightPressed = false;
leftPressed = false;
Toast.makeText(this, "released", Toast.LENGTH_SHORT).show();
}
return super.onTouchEvent(event);
}
public void draw(){
canvas.drawColor(Color.argb(255, 255, 255, 255));
player.draw(canvas);
}
#Override
public void run() {
while (!player.shouldDie()) {
try {
runOnUiThread(new Runnable() {
#Override
public void run() {
if (!rightPressed && !leftPressed) player.setDx(0);
if(rightPressed) player.setDx(player.getSpeed());
if(leftPressed) player.setDx(-player.getSpeed());
player.update();
draw();
}
});
Thread.sleep(1000/FPS);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
I also checked that the x of the player does actually change, and if I manually set the dx to like 100 it does actually move the first time it is executed, but not later even though the thread is still running
anyway, here's the Player.class
public class Player {
private int health, size, x, y;
private double dx, speed;
private Paint paint;
public Player(int size, int x, int y){
health = 3;
speed = 1;
dx = 0;
this.size = size;
this.x = x;
this.y = y;
paint = new Paint();
paint.setColor(Color.argb(255, 26, 128, 182));
}
public void draw(Canvas canvas){
canvas.drawRect(x, y, x+size, y+size, paint);
}
public void update(){
x += dx;
}
public void hurt(){
health--;
}
public boolean shouldDie(){
if(health<=0)return true;
return false;
}
public void posToast(Context context){
Toast.makeText(context, "X: " + x, Toast.LENGTH_SHORT).show();
}
public int getHealth() {
return health;
}
public void setHealth(int health) {
this.health = health;
}
public Paint getPaint() {
return paint;
}
public double getSpeed() {
return speed;
}
public void setSpeed(double speed) {
this.speed = speed;
}
public int getSize() {
return size;
}
public void setSize(int size) {
this.size = size;
}
public double getDx() {
return dx;
}
public void setDx(double dx) {
this.dx = dx;
}
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;
}
}
If anyone sees anything wrong in here I'd appreciate some help as I'm really confused as to why this doesn't work, especially since this is my first time working with android.
Seems you forgot to call rePaint() method. In Android, you have something called inValidate() which does redraw your canvas. You can either add in player draw method or activity draw method. That should do the trick.
I am working on a small simple game in which the hurdles coming out from top and there is an static ball which can only move on x-axis.When the hurdles coming out from top the user have to move the ball to avoid the collision.
I am placing 3 moving hurdles at a time.but my problem is they are coming out together i.e all three hurdles have the same y-axis values.I want it to come out one by one with some specific distance.
How can i achieve this.
Here is my GamePanel Class:
public class GamePanel extends SurfaceView implements Runnable {
private Thread thread = null;
private Ball ball;
private SurfaceHolder surfaceHolder;
private Paint paint;
private Canvas canvas;
volatile boolean playing = true;
private int hurdleCount = 3;
private Hurdles[] hurdles;
private int screenX, screenY;
private Rect ball_detectCollision;
public GamePanel(Context context, final int screenX, final int screenY) {
super(context);
ball = new Ball(context, screenX, screenY);
surfaceHolder = getHolder();
this.screenX = screenX;
this.screenY = screenY;
paint = new Paint();
canvas = new Canvas();
hurdles = new Hurdles[hurdleCount];
for (int i = 0; i < hurdleCount; i++) {
hurdles[i] = new Hurdles(context, screenX, screenY);
}
ball_detectCollision = new Rect(ball.getBall_x(), ball.getBall_y(), ball.getBitmap().getWidth(), ball.getBitmap().getHeight());
surfaceHolder.addCallback(new SurfaceHolder.Callback() {
#Override
public void surfaceCreated(SurfaceHolder holder) {
System.out.println("Surface Created");
}
#Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
System.out.println("Surface Changed");
thread = new Thread(GamePanel.this);
thread.start();
}
#Override
public void surfaceDestroyed(SurfaceHolder holder) {
System.out.println("Surface Destroyed");
}
});
}
private void draw() {
canvas = surfaceHolder.lockCanvas();
canvas.drawColor(Color.RED);
canvas.drawBitmap(ball.getBitmap(), updatedValue, ball.getBall_y(), paint);
ball.setBall_x(updatedValue);
ball_detectCollision.left = ball.getBall_x();
ball_detectCollision.top = screenY - ball.getBitmap().getHeight() - 260;
ball_detectCollision.right = ball.getBall_x() + ball.getBitmap().getWidth();
ball_detectCollision.bottom = screenY - ball.getBitmap().getHeight() - 260 + ball.getBitmap().getHeight();
for (int i = 0; i < hurdleCount; i++) {
canvas.drawBitmap(hurdles[i].getBitmap(), hurdles[i].getX(), hurdles[i].getY(), paint);
}
surfaceHolder.unlockCanvasAndPost(canvas);
}
#Override
public void run() {
while (playing) {
update();
draw();
control();
}
}
private void update() {
for (int i = 0; i < hurdleCount; i++) {
hurdles[i].update();
if (Rect.intersects(getBall_detectCollision(), hurdles[i].getDetectCollision())) {
System.out.println("Collision Detected");
playing = false;
Handler handler = new Handler(Looper.getMainLooper());
handler.post(new Runnable() {
#Override
public void run() {
showGameOverMessage();
}
});
}
}
}
public void pause() {
playing = false;
try {
thread.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
And this is my Hurdle Class
public class Hurdles {
private Bitmap bitmap;
private int x;
private int y;
private int speed = 20;
private int maxX;
private int minX;
private int maxY;
private int minY;
private Rect detectCollision;
public Hurdles(Context context, int screenX, int screenY) {
bitmap = BitmapFactory.decodeResource(context.getResources(), R.drawable.hurdle);
maxX = screenX - bitmap.getWidth();
maxY = screenY;
minX = 0;
minY = 0;
Random generator = new Random();
detectCollision = new Rect(x, y, bitmap.getWidth(), bitmap.getHeight());
x = generator.nextInt(maxX);
y = minY;
}
public void update() {
y += speed;
if (y > maxY - getBitmap().getHeight()) {
Random generator = new Random();
y = minY;
x = generator.nextInt(maxX);
}
detectCollision.left = x;
detectCollision.right = x + bitmap.getWidth();
detectCollision.top = y;
detectCollision.bottom = y + bitmap.getHeight();
}
If you want to add delay/gap between hurdles, you can do it in your GamePanel constructor like :
public GamePanel(Context context, final int screenX, final int screenY) {
super(context);
int gapBetweenHurdles = 100;
int gap = 0;
for (int i = 0; i < hurdleCount; i++) {
//(screenY - gap) will move your hurdle above the screen
hurdles[i] = new Hurdles(context, screenX, screenY - gap);
//increment the gap
gap += gapBetweenHurdles;
}
......
}
So the gap between the hurdles is 100 pixels as i have written randomly. If you want specific gap, you can set gapBetweenHurdles to some percentage of the screen height.
EDIT:
You have to pass the initial X and Y position to the hurdle constructor and then in update method of the hurdle class increment the Y value and in Hurdle class, getY() should return Y.
Try changing the code like this:
handler.postDelayed(new Runnable() {
#Override
public void run() {
showGameOverMessage();
}
},timeOffsetInMillis);
If the gaps can be the same you can set timeOffsetInMillis = i * gapInMillis
I have a SurfaceView on wich am drawing a small circle periodically with a special thread
but i want to when i press the surfaceView the thread stops drawing the circle and when i repress it the thread resume drawing the circle again.
I tried with thread methods and i can stop temporarily it with its sleep() method but i did not understand how to use wait and notify and i even found some exemples but did not get help from them
My code is :
public class GameView extends SurfaceView implements SurfaceHolder.Callback {
private float x = 100;
private float y = 100;
private int radius = 20;
private Paint paint;
private SurfaceHolder mSurfaceHolder;
private DrawingThread mTh ead;
private Context myContext;
public GameView(Context context) {
super(context);
this.myContext = context;
setWillNotDraw(false);
paint = new Paint();
paint.setAntiAlias(true);
paint.setColor(Color.GREEN);
paint.setStyle(Paint.Style.STROKE);
paint.setTextAlign(Paint.Align.LEFT);
mSurfaceHolder = getHolder();
mSurfaceHolder.addCallback(this);
}
public void onDraw(Canvas canvas){
canvas.drawCircle(x, y, radius, paint);
}
public boolean onTouchEvent(MotionEvent event) {
int eventaction = event.getAction();
int X = (int)event.getX();
int Y = (int)event.getY();
switch (eventaction ) {
case MotionEvent.ACTION_DOWN:
// I want to do my job here
break;
case MotionEvent.ACTION_MOVE:
break;
case MotionEvent.ACTION_UP:
break;
}
invalidate();
return true;
}
#Override
public void surfaceChanged(SurfaceHolder holder, int format, int width,
int height) {
}
#Override
public void surfaceCreated(SurfaceHolder holder) {
mThread = new DrawingThread(mSurfaceHolder, myContext);
mThread.mRun = true;
mThread.start();
}
#Override
public void surfaceDestroyed(SurfaceHolder holder) {
}
public final class DrawingThread extends Thread {
public boolean att = true;
public long delaiAttente = 1000;
boolean mRun;
Canvas mcanvas;
SurfaceHolder surfaceHolder;
Context context;
public DrawingThread(SurfaceHolder sholder, Context ctx)
{
surfaceHolder = sholder;
context = ctx;
mRun = false;
}
void setRunning(boolean bRun)
{
mRun = bRun;
}
boolean keepDrawing = true;
#Override
public void run() {
while (keepDrawing) {
Canvas canvas = null;
try {
canvas = mSurfaceHolder.lockCanvas();
synchronized (mSurfaceHolder) {
draw(canvas);
}
}
catch(Exception e){
}
finally {
if (canvas != null)
mSurfaceHolder.unlockCanvasAndPost(canvas);
}
waitThreaed();
}
}
public void waitThreaed() {
try {
x = (float) (getWidth()*Math.random());
y = (float) (getHeight()*Math.random());
this.sleep(1000);
postInvalidate();
} catch (InterruptedException e) {
}
}
}
}
Can't you just use something like this:
Timer drawTimer = new Timer("draw");
updateTimer.schedule(new TimerTask() {
public void run() {
draw();
}
}, 0, 1000);
private void draw() {
runOnUiThread(new Runnable() {
public void run() { ...}}}
I don't see why you need to subclass Thread.
In the main activity I have a handler to exchange messages with the bluetooth service. This works fine.
Now, I want launch second activity (SurfaceViewAnimation). I do this with:
startActivity (new Intent (this, SurfaceViewAnimation.class));
but I want change some attributes of SufaceViewAnimation class from main activity when it receives a command for bluetooth.
How I can do this?
The code of SufaceViewAnimation class is:
class BouncingBallView extends SurfaceView implements SurfaceHolder.Callback {
private BouncingBallAnimationThread bbThread = null;
private int xPosition = getWidth()/2;
private int yPosition = getHeight()/2;
private int xDirection = 20;
private int yDirection = 40;
private static int radius = 20;
private static int ballColor = Color.RED;
public BouncingBallView(Context ctx, AttributeSet attrs, int defStyle) {
super(ctx, attrs, defStyle);
getHolder().addCallback(this);
}
public void onDraw(Canvas canvas) {
super.onDraw(canvas);
Paint paint = new Paint();
paint.setColor(Color.BLACK);
canvas.drawRect(0,0,getWidth(),getHeight(), paint);
paint.setColor(ballColor);
canvas.drawCircle(xPosition, yPosition, radius, paint);
}
public void surfaceCreated(SurfaceHolder holder) {
if (bbThread!=null) return;
bbThread = new BouncingBallAnimationThread(getHolder());
bbThread.start();
}
public void surfaceChanged(SurfaceHolder holder,int format, int width, int height) { }
public void surfaceDestroyed(SurfaceHolder holder) {
bbThread.stop = true;
}
private class BouncingBallAnimationThread extends Thread {
public boolean stop = false;
private SurfaceHolder surfaceHolder;
public BouncingBallAnimationThread(SurfaceHolder surfaceHolder) {
this.surfaceHolder = surfaceHolder;
}
public void run() {
while (!stop) {
xPosition += xDirection;
yPosition += yDirection;
if (xPosition<0) {
xDirection = -xDirection;
xPosition = radius; }
if (xPosition>getWidth()-radius) {
xDirection = -xDirection;
xPosition = getWidth()-radius; }
if (yPosition<0) {
yDirection = -yDirection;
yPosition = radius; }
if (yPosition>getHeight()-radius) {
yDirection = -yDirection;
yPosition = getHeight()-radius-1; }
Canvas c = null;
try {
c = surfaceHolder.lockCanvas(null);
synchronized (surfaceHolder) {
onDraw(c);
}
} finally {
if (c != null) surfaceHolder.unlockCanvasAndPost(c);
}
}
}
}
public boolean onTouchEvent(MotionEvent event) {
if (event.getAction() != MotionEvent.ACTION_DOWN) return false;
if (xDirection!=0 || yDirection!=0)
xDirection = yDirection = 0;
else {
xDirection = (int) event.getX() - xPosition;
yDirection = (int) event.getY() - yPosition;
}
if(ballColor==Color.RED)
ballColor=Color.GREEN;
else
ballColor=Color.RED;
return true;
}
public void setxDirection(int xDirection) {
this.xDirection = xDirection;
}
public void setyDirection(int yDirection) {
this.yDirection = yDirection;
}
public void setballColor(int ballColor) {
this.ballColor = ballColor;
}
public void setradius(int radius) {
this.radius = radius;
}
}
public class SurfaceViewAnimation extends Activity {
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(new BouncingBallView(this,null,0));
}
}
If you want to change the data in SurfaceViewAnimation while SurfaceViewAnimation is running, you're best off with creating an own handler.
Besides that you can fall back to basic Inter(Process/Activity)Communication using Handlers, static variables or the Observer pattern.