Android tutorial: How to paint, animate, loop and remove a sprite!
Join the DZone community and get the full member experience.
Join For FreeLast week I posted a story about painting on a canvas. Today I want to elaborate on that and talk about sprites. A sprite is a two-dimensional image or animation that is integrated into a larger scene. Initially used to describe graphical objects handled separately of the memory bitmap of a video display, the term has since been applied more loosely to refer to various manner of graphical overlays.
In this tutorial I will show you:
- how to paint a sprite onto the canvas with the onTouch event.
- how to make an AnimatedSprite class
- Extent the AnimatedSprite class to loop the Sprite
You can download the Eclipse source on the bottom of the page.
The base of the Android game development tutorial for today is from a Sample app from the Android developers: LunarLander. I stripped away all useless things and went from there.
If you want to learn more about the basics check out these posts:
For this tutorial I used this png file:
I'll paste in the class that puts the Sprite in the scene:
package com.pxr.gamebase; import android.graphics.Bitmap; import android.graphics.Canvas; import android.graphics.Rect; public class AnimatedSprite { private Bitmap animation; private int xPos; private int yPos; private Rect sRectangle; private int fps; private int numFrames; private int currentFrame; private long frameTimer; private int spriteHeight; private int spriteWidth; private boolean loop; public boolean dispose; public AnimatedSprite() { sRectangle = new Rect(0, 0, 0, 0); frameTimer = 0; currentFrame = 0; xPos = 80; yPos = 200; dispose = false; } public void Initialize(Bitmap bitmap, int height, int width, int fps, int frameCount, boolean loop) { this.animation = bitmap; this.spriteHeight = height; this.spriteWidth = width; this.sRectangle.top = 0; this.sRectangle.bottom = spriteHeight; this.sRectangle.left = 0; this.sRectangle.right = spriteWidth; this.fps = 1000 / fps; this.numFrames = frameCount; this.loop = loop; } public int getXPos() { return xPos; } public int getYPos() { return yPos; } public void setXPos(int value) { xPos = value - (spriteWidth/2); } public void setYPos(int value) { yPos = value - (spriteHeight/2); } public void Update(long gameTime) { if( gameTime > frameTimer + fps) { frameTimer = gameTime; currentFrame += 1; if( currentFrame >= numFrames ) { currentFrame = 0; if(!loop) dispose = true; } sRectangle.left = currentFrame * spriteWidth; sRectangle.right = sRectangle.left + spriteWidth; } } public void draw(Canvas canvas) { Rect dest = new Rect(getXPos(), getYPos(), getXPos() + spriteWidth, getYPos() + spriteHeight); canvas.drawBitmap(animation, sRectangle, dest, null); } }
This class contains all the needed methods to create & animate the Sprite. The most important method's are the Initialize, Update and Draw.
Now we need to utilize this class in our Android game application. Below is the doTouch method from my AnimationView class:
public void doTouch(MotionEvent event){ int action = event.getAction(); float x = event.getX(); // or getRawX(); float y = event.getY(); switch(action){ case MotionEvent.ACTION_DOWN: if(mMode != STATE_RUNNING) setState(STATE_RUNNING); else if(mMode == STATE_RUNNING){ AnimatedSprite a = new AnimatedSprite(); if(b == null) b = BitmapFactory.decodeStream(res.openRawResource(R.drawable.explosion)); a.Initialize(b, 120, 160, 24, 20, true); a.setXPos((int)x); a.setYPos((int)y); synchronized(mSprites){ mSprites.add(a); } } break; } }
This method adds a new AnimatedSprite to the collection that will be drawn. And it sets to position to the position of where Android detected a Touch event.
If you dont want the sprites to loop set the last property of a.Initialize to false
My game loop calls 2 methods: doDraw & updatePhysics. The updatePhysics updates the sprites. The other just paints the Sprites.
updatePhysics:
private void updatePhysics() { long now = System.currentTimeMillis(); // Do nothing if mLastTime is in the future. // This allows the game-start to delay the start of the physics // by 100ms or whatever. if (mLastTime > now) return; if (mLastTime != 0) { int time = (int) (now - mLastTime); frameSampleTime += time; frameSamplesCollected++; if (frameSamplesCollected == 10) { fps = (int) (10000 / frameSampleTime); frameSampleTime = 0; frameSamplesCollected = 0; } } synchronized(mSprites){ for( AnimatedSprite a : mSprites){ a.Update(now); if(a.dispose) mSpritestoRemove.add(a); } } synchronized(mSpritestoRemove){ mSprites.removeAll(mSpritestoRemove); mSpritestoRemove.clear(); } numSprites = mSprites.size(); mLastTime = now; }
doDraw:
private void doDraw(Canvas canvas) { // Draw the background image. Operations on the Canvas accumulate // so this is like clearing the screen. //canvas.drawBitmap(mBackgroundImage, 0, 0, null); canvas.drawColor(Color.BLACK); for( AnimatedSprite a : mSprites){ a.draw(canvas); } if(mMode == STATE_RUNNING ){ canvas.drawText(fps + " fps", getWidth() - 60, getHeight() - 40, textPaint); canvas.drawText(numSprites + " sprites", getWidth() - 60, getHeight() - 20, textPaint); } canvas.restore(); }
Do you have a question or post request about Android game development ? Just leave a comment and ill get to it
Feel free to download & explore the Eclipse project below.
Published at DZone with permission of Mark Mooibroek, DZone MVB. See the original article here.
Opinions expressed by DZone contributors are their own.
Trending
-
AWS Multi-Region Resiliency Aurora MySQL Global DB With Headless Clusters
-
Auto-Scaling Kinesis Data Streams Applications on Kubernetes
-
Java String Templates Today
-
Managing Data Residency, the Demo
Comments