开发者

How is Animation implemented in Android

I had a small question.If i want to make a man run in android one way of doing this is to get images of the man in different position and display them at different positions.But often,this does not work very well and it appears as two different images are being drawn.Is there any other way through which i can implement custom animation.(Like create a cu开发者_Python百科stom image and telling one of the parts of this image to move).


The way i do it is to use sprite sheets for example (Not my graphics!):

How is Animation implemented in Android

You can then use a class like this to handle your animation:

public class AnimSpriteClass {

private Bitmap mAnimation;
private int mXPos;
private int mYPos;
private Rect mSRectangle;
private int mFPS;
private int mNoOfFrames;
private int mCurrentFrame;
private long mFrameTimer;
private int mSpriteHeight;
private int mSpriteWidth;

public AnimSpriteClass() {
    mSRectangle = new Rect(0,0,0,0);
    mFrameTimer =0;
    mCurrentFrame =0;
    mXPos = 80;
    mYPos = 200;
}

public void Initalise(Bitmap theBitmap, int Height, int Width, int theFPS, int theFrameCount) {
    mAnimation = theBitmap;
    mSpriteHeight = Height;
    mSpriteWidth = Width;
    mSRectangle.top = 0;
    mSRectangle.bottom = mSpriteHeight;
    mSRectangle.left = 0;
    mSRectangle.right = mSpriteWidth;
    mFPS = 1000 /theFPS;
    mNoOfFrames = theFrameCount;
}
public void Update(long GameTime) {
    if(GameTime > mFrameTimer + mFPS ) {
        mFrameTimer = GameTime;
        mCurrentFrame +=1;

        if(mCurrentFrame >= mNoOfFrames) {
            mCurrentFrame = 0;
        }
    }

    mSRectangle.left = mCurrentFrame * mSpriteWidth;
    mSRectangle.right = mSRectangle.left + mSpriteWidth;
}

public void draw(Canvas canvas) {
    Rect dest = new Rect(getXPos(), getYPos(), getXPos() + mSpriteWidth,
                getYPos() + mSpriteHeight);

    canvas.drawBitmap(mAnimation, mSRectangle, dest, null);
}
  • mAnimation - This is will hold the actual bitmap containing the animation.
  • mXPos/mYPos - These hold the X and Y screen coordinates for where we want the sprite to be on the screen. These refer to the top left hand corner of the image.
  • mSRectangle - This is the source rectangle variable and controls which part of the image we are rendering for each frame.
  • mFPS - This is the number of frames we wish to show per second. 15-20 FPS is enough to fool the human eye into thinking that a still image is moving. However on a mobile platform it’s unlikely you will have enough memory 3 – 10 FPS which is fine for most needs.
  • mNoOfFrames -This is simply the number of frames in the sprite sheet we are animating.
  • mCurrentFrame - We need to keep track of the current frame we are rendering so we can move to the next one in order.~
  • mFrameTimer - This controls how long between frames.
  • mSpriteHeight/mSpriteWidth -These contain the height and width of an Individual Frame not the entire bitmap and are used to calculate the size of the source rectangle.

Now in order to use this class you have to add a few things to your graphics thread. First declare a new variable of your class and then it can be initialised in the constructor as below.

Animation = new OurAnimatedSpriteClass();
Animation.Initalise(Bitmap.decodeResource(res, R.drawable.stick_man), 62, 39, 20, 20);

In order to pass the value of the bitmap you first have to use the Bitmap Factory class to decode the resource. It decodes a bitmap from your resources folder and allows it to be passed as a variable. The rest of the values depend on your bitmap image.

In order to be able to time the frames correctly you first need to add a Game timer to the game code. You do this by first adding a variable to store the time as show below.

private long mTimer;

We now need this timer to be updated with the correct time every frame so we need to add a line to the run function to do this.

public void run() {
    while (mRun) {
        Canvas c = null;
        mTimer = System.currentTimeMillis(); /////This line updates timer
        try {
            c = mSurfaceHolder.lockCanvas(null);
            synchronized (mSurfaceHolder) {
                Animation.update(mTimer);
                doDraw(c);
            }....

then you just have to add Animation.draw(canvas); your Draw function and the animation will draw the current frame in the right place.


When you describe : " one way of doing this is to get images of the man in different position and display them at different positions", this is indeed not only a programming technique to render animation but a general principle that is applied in every form of animation : it applies to making movies, making comics, computer gaming, etc, etc.

Our eyes see at the frequency of 24 images per second. Above 12 frames per second, your brain gets the feeling of real, fluid, movement.

So, yes, this is the way, if you got the feeling movement is not fuild, then you have to increase frame rate. But that works.

Moving only one part of an image is not appropriate for a small sprite representing a man running. Nevertheless, keep this idea in mind for later, when you will be more at ease with animation programming, you will see that this applies to bigger areas that are not entirely drawn at every frame in order to decresase the number of computations needed to "make a frame". Some parts of a whole screen are not "recomputed" every time, this technique is called double buffer and you should soon be introduced to it when making games.

But for now, you should start by making your man run, replacing quickly one picture by another. If movement is not fuild either increase frame rate (optimize your program) or choose images that are closer to each other.

Regards, Stéphane

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜