我正在制作一个需要动态动画的应用程序。(玩家动作)我正在使用Canvas
对象来执行此操作。我的第一个问题是"Canvas
真的是处理这些动画的最佳方式吗?我的第二个问题是"如何将玩家重新绘制到Canvas
?这是我的代码:
游戏.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);
}
}
}
播放器.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;}
}
}
你实际上无法控制何时调用onDraw
:当视图无效时,onDraw
将在将来的某个时候被调用。
您的代码中存在一个基本的设计缺陷:在执行onDraw
期间修改了播放器的位置:您将无法控制它。
移动一次玩家 :您可以使用每 5 秒重新发布相同Runnable
的Handler.postDelayed
。Runnable
将更新玩家位置,然后使视图失效。
这里有一些代码来说明这个想法
(免责声明:这是伪代码,它只关心索引 0 处的玩家,还有更多的事情要做来移动所有玩家,...
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
}
}
...
}
您可以通过制作计时器并设置计划固定速率来执行此操作。在视图构造函数中调用 init。
private void init(){
Timer timer = new Timer();
timer.scheduleAtFixedRate(new TimerTask(){
public void run() {
postInvalidate();
}
}, 0, 5 * 1000L);//5 seconds
}
在 onDraw
方法中调用postInvalidateDelayed(5000)
,如如何在画布上对路径进行动画处理中所示 - android 比生成计时器或可运行对象的现有答案简单一些。像他们一样,它不是一个高分辨率的计时器。
下面是一个最小、完整的示例:
布局:
<?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>
活动:
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
);
}
}
}