本文介绍了如何使Android的精灵的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!
问题描述
我正在开发一个游戏,其中包括精灵。
目前我加载一个位图,并用矩形来从位图右框架。
加载位图的问题需要太多的记忆,我将无法加载多个精灵在同一时间。
什么是我的选择做精灵在Android的?
解决方案
/ *这是Sprite类* /
进口android.graphics *。
进口android.graphics.Canvas;
进口android.graphics.Paint;
进口android.graphics.Rect;
公共类雪碧{
INT X;
私人诠释Ÿ;
私人布尔知名度= TRUE;
私人位图精灵;
私人诠释verticalFrame,horizontalFrame;
私人诠释frameWidth,frameHeight;
私人INT序列[] =新INT [1];
私人诠释MAXFRAME = 0;
私人诠释currentFrame;
私人诠释色彩;
私人矩形SRC;
私人矩形DEST;
私人诠释frameCount;
民营涂料P =新的油漆();
私人诠释spInitX,spInitY;
私人诠释旋转= 0;
私人浮动currentRotateAngle = 0;
//私有图形克;
公众持股量velocityY;
公众持股量velocityX;
公众诠释的高度;
公共雪碧(位图精灵){
this.sprite =精灵;
this.frameWidth = sprite.getWidth();
this.frameHeight = sprite.getHeight();
setFrameCount();
}
公共雪碧(位图精灵,诠释frameWidth,诠释frameHeight){
this.sprite =精灵;
this.frameWidth = frameWidth;
this.frameHeight = frameHeight;
setFrameCount();
}
公共无效旋转(浮动角){
currentRotateAngle =角;
}
公共无效setImage(位图BM,诠释frameWidth,诠释frameHeight){
this.sprite = BM;
this.frameWidth = frameWidth;
this.frameHeight = frameHeight;
}
公共位图getBitmap(){
返回精灵;
}
公共无效漆(帆布油画){
dest.offsetTo(getX()以,的getY());
// g.drawImage(精灵,X,Y,src.left,src.top,frameWidth,frameHeight);
canvas.drawBitmap(精灵,SRC,DEST,NULL);
}
公众诠释getMaxFrame(){
返回MAXFRAME;
}
公众诠释getFrameSequenceLength(){
返回sequence.length;
}
公共无效setFrameSequence(INT序列[]){
序列= SEQ;
}
公共无效previousFrame(){
如果(sequence.length→1){
如果(frameCount大于0){
的setFrame(序列[frameCount]);
frameCount--;
}其他{
frameCount = sequence.length - 1;
的setFrame(序列[frameCount]);
}
}其他{
的setFrame(frameCount);
如果(frameCount大于0){
frameCount ++;
}其他{
frameCount = MAXFRAME - 1;
}
}
}
公共无效与setPixel(INT X,int y)对{
spInitX = X;
spInitY = Y;
}
公共无效nextFrame(){
如果(sequence.length→1){
如果(frameCount< sequence.length){
的setFrame(序列[frameCount]);
frameCount ++;
}其他{
frameCount = 0;
的setFrame(序列[frameCount]);
}
}其他{
的setFrame(frameCount);
如果(frameCount< MAXFRAME){
frameCount ++;
}其他{
frameCount = 0;
}
}
}
公众诠释的getFrame(){
返回currentFrame;
}
公共无效setPosition两种(INT X,int y)对{
this.x = X;
this.y = Y;
}
公共无效setFrameCount(){
verticalFrame = sprite.getHeight()/ frameHeight;
horizontalFrame = sprite.getWidth()/ frameWidth;
SRC =新的矩形(0,0,frameWidth,frameHeight);
DEST =新的矩形(0,0,frameWidth,frameHeight);
MAXFRAME = verticalFrame * horizontalFrame;
}
公共无效的setFrame(INT帧){
如果(帧LT; MAXFRAME){
currentFrame =帧;
}
INT HF = currentFrame%horizontalFrame;
INT VF = currentFrame / horizontalFrame;
src.left = HF * frameWidth;
src.right = src.left + frameWidth;
src.top = VF * frameHeight;
src.bottom = src.top + frameHeight;
}
公共布尔collidesWith(雪碧SP,布尔CL){
INT maxHGap =(的getWidth()+ sp.getWidth())/ 2;
INT maxVGap =(的getHeight()+ sp.getHeight())/ 2;
INT X = getX()以+的getWidth()/ 2;
INT Y = getY()以+的getHeight()/ 2;
INT X1 = sp.getX()+ sp.getWidth()/ 2;
INT Y1 = sp.getY()+ sp.getHeight()/ 2;
如果(Math.abs(X - X1)LT; maxHGap和放大器;&安培; Math.abs(Y - Y1)< maxVGap){
返回true;
}
返回false;
}
公共无效的setVisible(布尔V){
可见= V;
}
公众最终布尔可见性(){
返回知名度;
}
公众诠释的getX(){
返回X;
}
公众诠释getY()以{
返回是;
}
公共无效setX的(INT X){
this.x = X;
}
公共无效塞蒂(int y)对{
this.y = Y;
}
公共无效移动(INT的Movex,诠释moveY){
setX的(的getX()+ MOVEX);
塞蒂(getY()以+ moveY);
//this.y+=y;
//this.x+=x;
}
公众最终诠释的getWidth(){
返回frameWidth;
}
公众最终诠释的getHeight(){
返回frameHeight;
}
公共无效setEventY(int i)以{
// TODO自动生成方法存根
}
公众诠释getEventY(){
// TODO自动生成方法存根
返回0;
}
}
/ *创建主线程类也* /
进口java.text.DecimalFormat中;
进口android.graphics.Canvas;
进口android.util.Log;
进口android.view.SurfaceHolder;
公共类MainThread继承Thread {
布尔isPaused得到;
私有静态最后字符串变量= MainThread.class.getSimpleName();
//所需的FPS
私人最终静态INT MAX_FPS = 50;
//要跳过的帧的最大数量的
私人最终静态INT MAX_FRAME_SKIPS = 5;
//帧周期
私人最终静态INT FRAME_PERIOD = 1000 / MAX_FPS;
/ *工具和统计* /
私人DecimalFormat的DF =新的DecimalFormat(0 ##); // 2 DP
//我们将读取统计每一秒
私人最终静态INT STAT_INTERVAL = 1000; // 女士
//一般会通过存储计算
//最后n个新鲜粮食店
私人最终静态INT FPS_HISTORY_NR = 10;
状态储存//最后一次
私人长lastStatusStore = 0;
//状态时间计数器
专用长statusIntervalTimer =0升;
//帧数跳过,因为在比赛开始
专用长totalFramesSkipped =0升;
//帧数在商店周期跳过(1秒)
专用长framesSkippedPerStatCycle =0升;
//在区间数渲染的帧
私人诠释frameCountPerStatCycle = 0;
专用长totalFrameCount =0升;
//最后一个FPS值
私人双人fpsStore [];
//的次数的统计已被读出
私人长statsCount = 0;
//平均FPS,因为在比赛开始
私人双人averageFps = 0.0;
//可以访问物理曲面的曲面保持器
私人SurfaceHolder surfaceHolder;
//处理输入的实际看法
//并绘制到表面
私人GameView GV;
//标志保持比赛状态
私人布尔运行;
公共无效setRunning(布尔运行){
this.running =运行;
}
公共MainThread(SurfaceHolder surfaceHolder,GameView GV){
超();
this.surfaceHolder = surfaceHolder;
this.gv = GV;
}
公共MainThread(设置设置){
// TODO自动生成构造函数存根
}
公共无效setPause(int i)以{
同步(gv.getHolder()){
如果(我== 0){
isPaused得到= FALSE;
}
如果(ⅰ== 1){
isPaused得到= TRUE;
}
}
}
@覆盖
公共无效的run(){
帆布油画;
Log.d(TAG,开始游戏循环);
initTimingElements();
长BEGINTIME; //时间周期开始时,
长timeDiff的; //需要对于周期的时间来执行
INT睡眠时间; //毫秒休眠(℃,如果我们后面)
INT framesSkipped; //被跳过的帧数
睡眠时间= 0;
而(运行){
帆布= NULL;
//尝试锁定画布独家像素编辑
//在表面
尝试 {
画布= this.surfaceHolder.lockCanvas();
同步(surfaceHolder){
BEGINTIME = System.currentTimeMillis的();
framesSkipped = 0; //重新设置帧跳过
//更新游戏状态
this.gv.update();
//渲染状态屏幕
//绘制在画布面板
this.gv.render(画布);
//计算多久没循环取
timeDiff测量= System.currentTimeMillis的() - BEGINTIME;
//计算睡眠时间
睡眠时间=(INT)(FRAME_PERIOD - timeDiff测量);
如果(休眠时间大于0){
//如果睡眠时间> 0就好了
尝试 {
//发送线程睡眠很短的时间
//为节电非常有用
视频下载(睡眠时间);
}赶上(InterruptedException异常E){
}
}
而(睡眠时间及℃,安培;&安培; framesSkipped&所述; MAX_FRAME_SKIPS){
//我们需要迎头赶上
this.gv.update(); //更新勿使
睡眠时间+ = FRAME_PERIOD; //添加帧周期检查
//如果在下一帧
framesSkipped ++;
}
如果(framesSkipped大于0){
Log.d(TAG,跳过+ framesSkipped);
}
//统计
framesSkippedPerStatCycle + = framesSkipped;
//调用例程来存储收集的统计数据
storeStats();
}
}赶上(InterruptedException的E1){
// TODO自动生成的catch块
e1.printStackTrace();
} 最后 {
//在发生异常的表面不留在
//不一致的状态
如果(帆布!= NULL){
surfaceHolder.unlockCanvasAndPost(画布);
}
} // end最后
}
}
私人无效storeStats(){
frameCountPerStatCycle ++;
totalFrameCount ++;
//假设睡眠的作品每次调用storeStats
//发生在1000 / FPS所以我们只是添加了
// statusIntervalTimer + = FRAME_PERIOD;
//检查实际时间
statusIntervalTimer + =(System.currentTimeMillis的() - statusIntervalTimer);
如果(statusIntervalTimer> = lastStatusStore + STAT_INTERVAL){
//计算的实际帧个人状态检查间隔
双actualFps =(双)(frameCountPerStatCycle /(STAT_INTERVAL / 1000));
//存储最新fps的阵列中
fpsStore [(INT)statsCount%FPS_HISTORY_NR] = actualFps;
//增加的次数的统计数,计算
statsCount ++;
双totalFps = 0.0;
//总结存储的FPS值
的for(int i = 0; I< FPS_HISTORY_NR;我++){
totalFps + = fpsStore [I]
}
//获得平均
如果(statsCount< FPS_HISTORY_NR){
//在情况下,第一10的触发器
averageFps = totalFps / statsCount;
} 其他 {
averageFps = totalFps / FPS_HISTORY_NR;
}
//节省总帧数跳过
totalFramesSkipped + = framesSkippedPerStatCycle;
//状态记录之后重置计数器(1秒)
framesSkippedPerStatCycle = 0;
statusIntervalTimer = 0;
frameCountPerStatCycle = 0;
statusIntervalTimer = System.currentTimeMillis的();
lastStatusStore = statusIntervalTimer;
// Log.d(TAG,平均FPS:+ df.format(averageFps));
gv.setAvgFps(FPS:+ df.format(averageFps));
}
}
私人无效initTimingElements(){
//初始化时序元素
fpsStore =新的双[FPS_HISTORY_NR]
的for(int i = 0; I< FPS_HISTORY_NR;我++){
fpsStore [I] = 0.0;
}
Log.d(TAG +.initTimingElements(),
定时统计数据初始化元素);
}
}
I'm developing a game which includes sprites.
currently I'm loading a bitmap and using Rectangle to get the right frame from the bitmap.
the problem is loading bitmaps takes too much memory and I wont be able to load several sprites at the same time.
what are my alternatives for doing sprite in Android?
解决方案
/* It is Sprite class */
import android.graphics.*;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Rect;
public class Sprite {
int x;
private int y;
private boolean visibility = true;
private Bitmap sprite;
private int verticalFrame,horizontalFrame;
private int frameWidth,frameHeight;
private int sequence[] = new int[1];
private int maxFrame = 0;
private int currentFrame;
private int color;
private Rect src;
private Rect dest;
private int frameCount;
private Paint p = new Paint();
private int spInitX,spInitY;
private int rotate = 0;
private float currentRotateAngle = 0;
//private Graphics g;
public float velocityY;
public float velocityX;
public int height;
public Sprite(Bitmap sprite){
this.sprite = sprite;
this.frameWidth = sprite.getWidth();
this.frameHeight = sprite.getHeight();
setFrameCount();
}
public Sprite(Bitmap sprite,int frameWidth,int frameHeight){
this.sprite = sprite;
this.frameWidth = frameWidth;
this.frameHeight = frameHeight;
setFrameCount();
}
public void rotate(float angle){
currentRotateAngle = angle;
}
public void setImage(Bitmap bm,int frameWidth,int frameHeight){
this.sprite = bm;
this.frameWidth = frameWidth;
this.frameHeight = frameHeight;
}
public Bitmap getBitmap(){
return sprite;
}
public void paint(Canvas canvas){
dest.offsetTo(getX(), getY());
// g.drawImage(sprite, x, y,src.left,src.top,frameWidth,frameHeight);
canvas.drawBitmap(sprite, src, dest, null);
}
public int getMaxFrame(){
return maxFrame;
}
public int getFrameSequenceLength(){
return sequence.length;
}
public void setFrameSequence(int seq[]){
sequence = seq;
}
public void previousFrame(){
if(sequence.length > 1){
if(frameCount > 0){
setFrame(sequence[frameCount]);
frameCount--;
}else{
frameCount = sequence.length - 1;
setFrame(sequence[frameCount]);
}
}else{
setFrame(frameCount);
if(frameCount > 0){
frameCount++;
}else{
frameCount = maxFrame - 1;
}
}
}
public void setPixel(int x,int y){
spInitX = x;
spInitY = y;
}
public void nextFrame(){
if(sequence.length > 1){
if(frameCount < sequence.length){
setFrame(sequence[frameCount]);
frameCount++;
}else{
frameCount = 0;
setFrame(sequence[frameCount]);
}
}else{
setFrame(frameCount);
if(frameCount < maxFrame){
frameCount++;
}else{
frameCount = 0;
}
}
}
public int getFrame(){
return currentFrame;
}
public void setPosition(int x,int y){
this.x = x;
this.y = y;
}
public void setFrameCount(){
verticalFrame = sprite.getHeight() / frameHeight;
horizontalFrame = sprite.getWidth() / frameWidth;
src = new Rect(0,0,frameWidth,frameHeight);
dest = new Rect(0,0,frameWidth,frameHeight);
maxFrame = verticalFrame * horizontalFrame;
}
public void setFrame(int frame){
if(frame < maxFrame){
currentFrame = frame;
}
int hf = currentFrame % horizontalFrame;
int vf = currentFrame / horizontalFrame;
src.left = hf * frameWidth;
src.right = src.left + frameWidth;
src.top = vf * frameHeight;
src.bottom = src.top + frameHeight;
}
public boolean collidesWith(Sprite sp,boolean cl){
int maxHGap = (getWidth() + sp.getWidth())/2;
int maxVGap = (getHeight() + sp.getHeight())/2;
int x = getX() + getWidth()/2;
int y = getY() + getHeight()/2;
int x1 = sp.getX() + sp.getWidth()/2;
int y1 = sp.getY() + sp.getHeight()/2;
if(Math.abs(x - x1) < maxHGap && Math.abs(y - y1) < maxVGap){
return true;
}
return false;
}
public void setVisible(boolean v){
visibility = v;
}
public final boolean isVisible(){
return visibility;
}
public int getX(){
return x;
}
public int getY(){
return y;
}
public void setX(int x) {
this.x = x;
}
public void setY(int y) {
this.y = y;
}
public void move(int moveX,int moveY){
setX(getX()+moveX);
setY(getY()+moveY);
//this.y+=y;
//this.x+=x;
}
public final int getWidth(){
return frameWidth;
}
public final int getHeight(){
return frameHeight;
}
public void setEventY(int i) {
// TODO Auto-generated method stub
}
public int getEventY() {
// TODO Auto-generated method stub
return 0;
}
}
/*Create Main Thread Class Also */
import java.text.DecimalFormat;
import android.graphics.Canvas;
import android.util.Log;
import android.view.SurfaceHolder;
public class MainThread extends Thread {
boolean isPaused;
private static final String TAG = MainThread.class.getSimpleName();
// desired fps
private final static int MAX_FPS = 50;
// maximum number of frames to be skipped
private final static int MAX_FRAME_SKIPS = 5;
// the frame period
private final static int FRAME_PERIOD = 1000 / MAX_FPS;
/* Stuff for stats */
private DecimalFormat df = new DecimalFormat("0.##"); // 2 dp
// we'll be reading the stats every second
private final static int STAT_INTERVAL = 1000; // ms
// the average will be calculated by storing
// the last n FPSs
private final static int FPS_HISTORY_NR = 10;
// last time the status was stored
private long lastStatusStore = 0;
// the status time counter
private long statusIntervalTimer = 0l;
// number of frames skipped since the game started
private long totalFramesSkipped = 0l;
// number of frames skipped in a store cycle (1 sec)
private long framesSkippedPerStatCycle = 0l;
// number of rendered frames in an interval
private int frameCountPerStatCycle = 0;
private long totalFrameCount = 0l;
// the last FPS values
private double fpsStore[];
// the number of times the stat has been read
private long statsCount = 0;
// the average FPS since the game started
private double averageFps = 0.0;
// Surface holder that can access the physical surface
private SurfaceHolder surfaceHolder;
// The actual view that handles inputs
// and draws to the surface
private GameView gv;
// flag to hold game state
private boolean running;
public void setRunning(boolean running) {
this.running = running;
}
public MainThread(SurfaceHolder surfaceHolder, GameView gv) {
super();
this.surfaceHolder = surfaceHolder;
this.gv = gv;
}
public MainThread(Setting setting) {
// TODO Auto-generated constructor stub
}
public void setPause(int i) {
synchronized (gv.getHolder()) {
if (i == 0) {
isPaused = false;
}
if (i == 1) {
isPaused = true;
}
}
}
@Override
public void run() {
Canvas canvas;
Log.d(TAG, "Starting game loop");
initTimingElements();
long beginTime; // the time when the cycle begun
long timeDiff; // the time it took for the cycle to execute
int sleepTime; // ms to sleep (<0 if we're behind)
int framesSkipped; // number of frames being skipped
sleepTime = 0;
while (running) {
canvas = null;
// try locking the canvas for exclusive pixel editing
// in the surface
try {
canvas = this.surfaceHolder.lockCanvas();
synchronized (surfaceHolder) {
beginTime = System.currentTimeMillis();
framesSkipped = 0; // resetting the frames skipped
// update game state
this.gv.update();
// render state to the screen
// draws the canvas on the panel
this.gv.render(canvas);
// calculate how long did the cycle take
timeDiff = System.currentTimeMillis() - beginTime;
// calculate sleep time
sleepTime = (int) (FRAME_PERIOD - timeDiff);
if (sleepTime > 0) {
// if sleepTime > 0 we're OK
try {
// send the thread to sleep for a short period
// very useful for battery saving
Thread.sleep(sleepTime);
} catch (InterruptedException e) {
}
}
while (sleepTime < 0 && framesSkipped < MAX_FRAME_SKIPS) {
// we need to catch up
this.gv.update(); // update without rendering
sleepTime += FRAME_PERIOD; // add frame period to check
// if in next frame
framesSkipped++;
}
if (framesSkipped > 0) {
Log.d(TAG, "Skipped:" + framesSkipped);
}
// for statistics
framesSkippedPerStatCycle += framesSkipped;
// calling the routine to store the gathered statistics
storeStats();
}
} catch (InterruptedException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
} finally {
// in case of an exception the surface is not left in
// an inconsistent state
if (canvas != null) {
surfaceHolder.unlockCanvasAndPost(canvas);
}
} // end finally
}
}
private void storeStats() {
frameCountPerStatCycle++;
totalFrameCount++;
// assuming that the sleep works each call to storeStats
// happens at 1000/FPS so we just add it up
// statusIntervalTimer += FRAME_PERIOD;
// check the actual time
statusIntervalTimer += (System.currentTimeMillis() - statusIntervalTimer);
if (statusIntervalTimer >= lastStatusStore + STAT_INTERVAL) {
// calculate the actual frames pers status check interval
double actualFps = (double) (frameCountPerStatCycle / (STAT_INTERVAL / 1000));
// stores the latest fps in the array
fpsStore[(int) statsCount % FPS_HISTORY_NR] = actualFps;
// increase the number of times statistics was calculated
statsCount++;
double totalFps = 0.0;
// sum up the stored fps values
for (int i = 0; i < FPS_HISTORY_NR; i++) {
totalFps += fpsStore[i];
}
// obtain the average
if (statsCount < FPS_HISTORY_NR) {
// in case of the first 10 triggers
averageFps = totalFps / statsCount;
} else {
averageFps = totalFps / FPS_HISTORY_NR;
}
// saving the number of total frames skipped
totalFramesSkipped += framesSkippedPerStatCycle;
// resetting the counters after a status record (1 sec)
framesSkippedPerStatCycle = 0;
statusIntervalTimer = 0;
frameCountPerStatCycle = 0;
statusIntervalTimer = System.currentTimeMillis();
lastStatusStore = statusIntervalTimer;
// Log.d(TAG, "Average FPS:" + df.format(averageFps));
gv.setAvgFps("FPS: " + df.format(averageFps));
}
}
private void initTimingElements() {
// initialise timing elements
fpsStore = new double[FPS_HISTORY_NR];
for (int i = 0; i < FPS_HISTORY_NR; i++) {
fpsStore[i] = 0.0;
}
Log.d(TAG + ".initTimingElements()",
"Timing elements for stats initialised");
}
}
这篇关于如何使Android的精灵的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!