4

I am making a app that requires dynamic animations. (Player movements) I'm using the Canvas object to do this. My first question is "Is the Canvas really the best way to handle these animations?", and my second question is "How do I re-draw the player(s) to the Canvas?" Here is my code:

theGame.java:

package birdprograms.freezetag;

import android.app.Activity;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.os.Bundle;
import android.view.View;

public class theGame extends Activity {
    players[] arr = {
            new player(),
            new player(),
            new player(),
            new player()
    };
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(new myView(this));
    }
    public class myView extends View {
        Paint paint = new Paint();
        public myView(Context context) {
            super(context);
            paint.setColor(Color.YELLOW);
        }
        @Override
        public void onDraw(final Canvas canvas) {
            arr[0].update(true, true);
            arr[0].draw(canvas, paint);
        }
    }
}

player.java

package birdprograms.freezetag;

import android.graphics.*;

public class player {
    int y = 0;
    int x = 0;
    int vy = 5;
    int vx = 5;
    int height = y + 15;
    int width = x + 15;
    public void draw(Canvas canvas, Paint paint){
        canvas.drawRect(x,y,width,height,paint);
    }
    public void update(boolean left, boolean top){
        if(left){x += vx; width = x + 15;}
        else{x -= vx; width = x + 15;}
        if(top){y += vy; height = y + 15;}
        else{y -= vy; height = y + 15;}
    }
}
Nathan
  • 71
  • 1
  • 9

3 Answers3

5

You don't really can get the control on when the onDraw will be called: when a view is invalidate then the onDraw will be called at some point in future.

There is a fundamental design flaw in your code: the position of player is modified during the execution of the onDraw : you will be unable to control it.

To move your players every 5 sec : you can use a Handler.postDelayed re-posting the same Runnable every 5 sec. The Runnable will update the player position and then invalidate the View.

Here is some code to illustrate the idea

(Disclaimer: this is pseudo code, it only care about player at index 0, there is more to do to move all the players, ...)

public class myView extends View {
    Paint paint = new Paint();
    public myView(Context context) {
        super(context);
        paint.setColor(Color.YELLOW);
        movePlayer0Runnable.run(); //this is the initial call to draw player at index 0
    }

    @Override
    public void onDraw(final Canvas canvas) {
        super.onDraw(canvas);  //IMPORTANT to draw the background
        arr[0].draw(canvas, paint);
    }

    Handler handler = new Handler(Looper.getMainLooper());
    Runnable movePlayer0Runnable = new Runnable(){
        public void run(){
            arr[0].update(true, true);
            invalidate(); //will trigger the onDraw
            handler.postDelayed(this,5000); //in 5 sec player0 will move again
        }
    }   
    ... 
}
ben75
  • 29,217
  • 10
  • 88
  • 134
0

You can do this by making a timer and setting a schedule fixed rate. Call init in the views constructors.

private void init(){
    Timer timer = new Timer();
    timer.scheduleAtFixedRate(new TimerTask(){
        public void run() {
             postInvalidate();
        }
    }, 0, 5 * 1000L);//5 seconds
}
Gil Julio
  • 812
  • 1
  • 9
  • 18
0

Calling postInvalidateDelayed(5000) inside of the onDraw method as shown in How to animate a path on canvas - android is a bit simpler than the existing answers that spawn timers or runnables. Like them, it's not a high-resolution timer.

Here's a minimal, complete example:

Layout:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:keepScreenOn="true"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:gravity="center"
    android:orientation="vertical"
>
    <view
        class="com.example.foo.FooActivity$Drawer"
        android:layout_width="fill_parent"
        android:layout_height="0dp"
        android:layout_weight="1"
    />
</LinearLayout>

Activity:

package com.example.foo;

import android.app.Activity;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.os.Bundle;
import android.util.AttributeSet;
import android.view.View;

import java.util.Random;

public class FooActivity extends Activity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_foo);
    }

    public static class Drawer extends View {
        private static final int delayMS = 5000;
        private static Random rnd;
        private static Paint paint;
        private static int viewWidth;
        private static int viewHeight;

        public Drawer(Context con, AttributeSet attr) {
            super(con, attr);
            rnd = new Random();
            paint = new Paint(Paint.ANTI_ALIAS_FLAG);
            paint.setStyle(Paint.Style.FILL);
        }

        // https://stackoverflow.com/a/9718512/6243352
        @Override
        protected void onSizeChanged(int xNew, int yNew, int xOld, int yOld) {
            super.onSizeChanged(xNew, yNew, xOld, yOld);
            viewWidth = xNew;
            viewHeight = yNew;
        }

        @Override
        protected void onDraw(final Canvas c) {
            super.onDraw(c);

            // https://stackoverflow.com/a/18617993/6243352
            postInvalidateDelayed(delayMS);

            int color = rnd.nextInt(256);
            paint.setARGB(255, color, color, color);
            c.drawCircle(
                viewWidth / 2,
                viewHeight / 2,
                viewWidth / 4,
                paint
            );
        }
    }
}
ggorlen
  • 44,755
  • 7
  • 76
  • 106