Hi im trying to get my bitmap to fade in and out. The bitmap is being drawn to a canvas
on a surfaceview. I am also using a sprite class to draw sprites to my canvas:
public class sprite {
static int x, y;
static int xSpeed, ySpeed;
static int height, width;
static Bitmap b;
static CanvasView canView;
static Paint fadePaint;
public sprite(CanvasView canvasView, Bitmap xSpriteSheet) {
// TODO Auto-generated constructor stub
b = xSpriteSheet;
canView = canvasView;
fadePaint.setAlpha(100); //Heres where logcat gives me an error
// divide by 2 for rows in sprite sheet
//4 colums
height = b.getHeight();
width = b.getWidth();
x = 0; y = 0;
xSpeed = 5;
ySpeed = 0;
}
public static void onDraw(Canvas canvas) {
// TODO Auto-generated method stub
Rect src = new Rect(0, 0 , width, height);
Rect dst = new Rect(x, y, x+width, y+height);
update();
canvas.drawBitmap(b, src, dst, fadePaint);
}
private static void update() {
// TODO Auto-generated method stub
x += xSpeed;
}
Heres what my logcat gives me:
FATAL EXCEPTION: Thread-273
java.lang.NullPointerException
at com.mrsai.xsos.sprite.<init>(sprite.java:25)
at com.mrsai.xsos.Game$CanvasView.run(Game.java:101)
at java.lang.Thread.run(Thread.java:856)
It is because you did not initialize the Paint. Change this:
static Paint fadePaint;
To this:
static Paint fadePaint = new Paint();
Related
I am using following code to write "g" inside a circle. "g" must be centered horizontally and vertically inside the circle. But I am not able to, where am I wrong ?
//sv is surfaceview which covers whole screen
sv.getHolder().addCallback(new SurfaceHolder.Callback()
{
#Override
public void surfaceChanged(SurfaceHolder arg0, int arg1, int arg2,
int arg3) {
// TODO Auto-generated method stub
}
#Override
public void surfaceCreated(SurfaceHolder arg0) {
// TODO Auto-generated method stub
// surfaceview width
swidth=sv.getWidth();
sheight=sv.getHeight();
int height = sheight/3;
int mat = Math.min(height,swidth/2);
Paint paint= new Paint(Paint.ANTI_ALIAS_FLAG);
Paint paint1= new Paint(Paint.ANTI_ALIAS_FLAG);
Resources r = getResources();
paint.setColor(Color.CYAN);
paint1.setColor(Color.BLACK);
Canvas c = sv.getHolder().lockCanvas();
c.drawARGB(254, 254, 254, 254);
String t1="g";
int ttwidth=determineMaxTextSize(t1, mat/4);
paint1.setTextSize(ttwidth);
Rect bounds = new Rect();
paint1.getTextBounds(t1, 0, 3, bounds);
c.drawCircle(swidth/4, height+height/2, mat/4, paint);
c.drawText(t1, swidth/4-bounds.width()/2, height+height/2+bounds.height()/2, paint1);
sv.getHolder().unlockCanvasAndPost(c);
}
This is the method used in above code.
private int determineMaxTextSize(String str, float maxWidth)
{
int size = 0;
Paint paint = new Paint();
do {
paint.setTextSize(++ size);
} while(paint.measureText(str) < maxWidth);
return size;
}
Here is what I get when I try 4 different texts.
EDIT:
After editing my code with this
paint1.setTextAlign(Align.CENTER);
String t1="N";
int ttwidth=determineMaxTextSize(t1, mat/4);
paint1.setTextSize(ttwidth);
Rect bounds = new Rect();
paint1.getTextBounds(t1, 0, 3, bounds);
c.drawCircle(swidth/4, height+height/2, mat/4, paint);
c.drawText(t1, swidth/4, height+height/2+bounds.height()/2, paint1);
I get this outcome which is better
However, you can see "g" is still not aligned.
paint1.setTextAlign(Align.CENTER);
String t1="N";
int ttwidth=determineMaxTextSize(t1, mat/4);
paint1.setTextSize(ttwidth);
Rect bounds = new Rect();
paint1.getTextBounds(t1, 0, 3, bounds);
c.drawCircle(swidth/4, height+height/2, mat/4, paint);
c.drawText(t1, swidth/4, height+height/2+bounds.height()/2, paint1);
Above code is the answer
Basically I tried to use a sprite sheet for animation. The aim is to count from 1 to 8 with 1 second interval. The numbers are image on a sprite sheet. The problem is once the number is being drawn to the canvas, it just won't go away. New image just drawn on top of the unwanted old image. Like this:
Is there a way to clear what has been drawn, so that new image can be drawn on a clean canvas?
DrawStripFrame Class:
public class DrawStripFrame extends SurfaceView implements Runnable{
/**variables declared here*/
public DrawStripFrame (Context context){
super (context);
this.context = context;
holder = getHolder();
}
public void setDrawStripFrame(Bitmap bitmap, int width, int height, int columns){
this.bitmap = bitmap;
this.width = width;
this.height = height;
this.columns = columns;
}
}
#Override
public void run(){
while(running){
if(!holder.getSurface().isValid())
continue;
Canvas canvas = holder.lockCanvas();
draw(canvas);
holder.unlockCanvasAndPost(canvas);
}
}
public void draw (Canvas canvas){
update();
/**4 being no. of columns and 2 being no. of row*/
int u = (frame % 4)*(width/4);
int v = (frame / 4)*(height/2);
Rect src = new Rect(u,v,u+(width/4),v+(height/2));
Rect dst = new Rect (0,0, 100,100);
Paint paint = new Paint();
canvas.drawBitmap(bitmap, src, dst, paint);
}
public void resume() {
running = true;
gameloop = new Thread(this);
gameloop.start();
}
public void update (){
frame++;
if (frame>10)
frame = 0;
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
In your case you could just redraw the canvas with a color like this:
public void draw (Canvas canvas){
update();
// clearing canvas
canvas.drawColor(Color.BLUE); // whatever color you need it to be
/**4 being no. of columns and 2 being no. of row*/
int u = (frame % 4)*(width/4);
int v = (frame / 4)*(height/2);
Rect src = new Rect(u,v,u+(width/4),v+(height/2));
Rect dst = new Rect (0,0, 100,100);
Paint paint = new Paint();
canvas.drawBitmap(bitmap, src, dst, paint);
}
My problem is, that I have a Layout class called by an Inflater and I want to run a method from this class to update a picture every few seconds.
I wanted to do this with handlers and the run() method, but my problem is, the picture only updates itself when I am interacting with the screen (clicking my only button).
Do you know what I did wrong?
Here is my GameLayout class:
package de.undeadleech.frogjump;
public class GameLayout extends View implements Runnable
{
private Sprite sprite;
private Bitmap bmp;
private Handler handler = new Handler();
public GameLayout(Context context)
{
super(context);
bmp = BitmapFactory.decodeResource(getResources(), R.drawable.froschanimation);
sprite = new Sprite(bmp, 0, 0, 400, 100, 5, 4);
handler.postDelayed(this, 0);
}
#Override
protected void onDraw(Canvas canvas)
{
sprite.draw(canvas);
}
public void update(long currentTimeMillis)
{
sprite.update(currentTimeMillis);
}
#Override
public void run()
{
sprite.update(System.currentTimeMillis());
handler.postDelayed(this, 0);
}
}
EDIT:
Here is my Sprite class because you wanted to see it:
package de.undeadleech.frogjump;
public class Sprite
{
//private static final String TAG = Sprite.class.getSimpleName();
private Bitmap bitmap; // the animation sequence
private Rect sourceRect; // the rectangle to be drawn from the animation bitmap
private int frameNr; // number of frames in animation
private int currentFrame; // the current frame
private long frameTicker; // the time of the last frame update
private int framePeriod; // milliseconds between each frame (1000/fps)
private int spriteWidth; // the width of the sprite to calculate the cut out rectangle
private int spriteHeight; // the height of the sprite
private int x; // the X coordinate of the object (top left of the image)
private int y; // the Y coordinate of the object (top left of the image)
public Sprite(Bitmap bitmap, int x, int y, int width, int height, int fps, int frameCount)
{
this.bitmap = bitmap;
this.x = x;
this.y = y;
currentFrame = 0;
frameNr = frameCount;
spriteWidth = bitmap.getWidth() / frameCount;
spriteHeight = bitmap.getHeight();
sourceRect = new Rect( 0, 0, spriteWidth, spriteHeight);
framePeriod = 1000 / fps;
frameTicker = 0l;
}
public void update(long gameTime)
{
if (gameTime > frameTicker + framePeriod)
{
frameTicker = gameTime;
// increment the frame
currentFrame++;
if (currentFrame >= frameNr)
{
currentFrame = 0;
}
}
// define the rectangle to cut out sprite
this.sourceRect.left = currentFrame * spriteWidth;
this.sourceRect.right = this.sourceRect.left + spriteWidth;
}
public void draw(Canvas canvas)
{
// where to draw the sprite
Rect destRect = new Rect( x, y, x + spriteWidth, y + spriteHeight);
canvas.drawBitmap(bitmap, sourceRect, destRect, null);
}
}
Instead of posting Runnable you should call invalidate() when you need to redraw your layout. Also you should update state of your Sprite in onDraw method as well.
this is my class.. ı want to use it in my simple game's GameEngine.. but ı didn't understand the problem here.. it doesn't work..
public class Droid {
private Bitmap bitmap;
private int x;
private int y;
private boolean touched;
private Speed speed;
private Paint paint;
public Droid(Resources resources, Bitmap bitmap, int x, int y)
{
this.bitmap = bitmap;
this.x = x;
this.y = y;
// create droid and load bitmap
bitmap = BitmapFactory.decodeResource(resources,
R.drawable.droid_1);
}
public void draw(Canvas canvas)
{
canvas.drawBitmap(bitmap, x - bitmap.getWidth() / 2,
y- bitmap.getHeight() / 2, paint);
}
}
when ı run code, ı see a nullpointerexception at draw() method... how can ı solve this? thanks for help...
MainActivity
public class MainActivity extends Activity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Bitmap bmp = BitmapFactory.decodeResource(getResources(), R.drawable.ic_launcher);
MyView mv = new MyView(this,bmp,100,100);
// pass the bitmap and x and y co-ordinates to the constructor of Myview
setContentView(mv); // set the content to your activity
}
}
Custom view class
public class MyView extends View{ // should extend view
Context c;
private Bitmap bitmap;
private int x;
private int y;
private Paint paint;
public MyView(Context context,Bitmap bmp, int i, int j) {
super(context);
// TODO Auto-generated constructor stub
this.c=context;
this.bitmap=bmp;
this.x=i;
this.y=j;
paint= new Paint();
}
#Override
public void draw(Canvas canvas) // override view on draw and draw the bitmap
{
canvas.drawBitmap(bitmap, x - bitmap.getWidth() / 2,
y- bitmap.getHeight() / 2, paint); // instead of paint you can have null
}
}
// ı hope, ı solved this problem.. finally.. :)
public class Droid {
private Bitmap bitmap;
private int x;
private int y;
private boolean touched;
private Speed speed;
private Paint paint;
public Droid(Resources resources, Bitmap bitmap, int x, int y)
{
paint= new Paint();
// this.bitmap = bitmap; // delete this part, it will work.. :)))
this.x = x;
this.y = y;
// create droid and load bitmap
bitmap = BitmapFactory.decodeResource(resources,
R.drawable.droid_1);
}
public void draw(Canvas canvas)
{
canvas.drawBitmap(bitmap, x - bitmap.getWidth() / 2,
y- bitmap.getHeight() / 2, paint);
}
}
I am using translate animation to make imageview trace a path.Initially I am just making my imageview to translate through a particular set of points but it does not.here is my code in ondraw method:
#Override
public void onDraw(Canvas canvas) {
Log.w(this.getClass().getName(),"onDraw of Balls called");
super.onDraw(canvas);
mCanvas = canvas;
canvas.drawLine(0, 240, 160, 0, mPaint);
canvas.drawLine(160, 0, 320, 240, mPaint);
mBal = (ImageView)findViewById(R.id.strike);
TranslateAnimation mTrans = new TranslateAnimation(0, 240, 160, 0);
mTrans.setDuration(6000);
mTrans.setFillEnabled(true);
mTrans.setFillAfter(true);
mTrans.start();
}
plz help.
=============================================================
Edit 1:-
This is my modified code but the translation is still not working.PLz help
#Override
public void onDraw(Canvas canvas) {
Log.w(this.getClass().getName(),"onDraw of Balls called");
BallsOnDraw(canvas);
}
void BallsOnDraw(Canvas canvas)
{
canvas.drawLine(0, 240, 160, 0, mPaint);
canvas.drawLine(160, 0, 320, 240, mPaint);
TranslateAnimation mTrans = new TranslateAnimation(0, 320, 0,240);
mTrans.setDuration(6000);
SitoliaActivity.mBal.startAnimation(mTrans);
}
You are mixing custom classes with ImageViews and animations. IMHO you should use only one of the methods. Also I don't see that you actually connect the TranslationAnimation with the ImageView itself.
So, one solution would be to use TranslateAnimation, but then you would need to call mBal.startAnimation(mTrans) instead of mTrans.start().
The other solution would be to use a custom view, override onDraw, and handle the animation yourself:
save the current time (System.curentTimeMillis)
draw the Bitmap directly to the Canvas using canvas.drawBitmap(bitmap, x, y, paint);
update the coordinates based on the elapsed time
if the animation should still run, call postInvalidateDelayed(40);
Here is an example custom view:
public class C extends View {
private static final float FROM_X = 400;
private static final float FROM_Y = 100;
private static final float TO_X = 10;
private static final float TO_Y = 400;
private static final int DURATION = 2*1000; // 2 seconds
private Bitmap mImage;
private long mStart = -1;
private Paint mPaint = new Paint();
public C(Context context) {
super(context);
mImage = ((BitmapDrawable)context.getResources().getDrawable(R.drawable.icon)).getBitmap();
}
#Override
public void onDraw(Canvas canvas) {
boolean finished = false;
if (mStart == -1) {
// Time to start the animation
mStart = SystemClock.uptimeMillis();
}
int elapsed = (int)(SystemClock.uptimeMillis() - mStart);
if (elapsed >= DURATION) {
elapsed = DURATION;
finished = true;
}
float x = FROM_X + (TO_X - FROM_X) * elapsed / DURATION;
float y = FROM_Y + (TO_Y - FROM_Y) * elapsed / DURATION;
canvas.drawBitmap(mImage, x, y, mPaint);
if (!finished) {
postInvalidateDelayed(10);
}
}
}