本文介绍了如何使Android的精灵的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在开发一个游戏,其中包括精灵。

目前我加载一个位图,并用矩形来从位图右框架。

加载位图的问题需要太多的记忆,我将无法加载多个精灵在同一时间。

什么是我的选择做精灵在Android的?

解决方案

  / *这是Sprite类* /
进口android.graphics *。
进口android.graphics.Canvas;
进口android.graphics.Paint;
进口android.graphics.Rect;

公共类雪碧{

INT X;
私人诠释Ÿ;
私人布尔知名度= TRUE;
私人位图精灵;
私人诠释verticalFrame,horizo​​ntalFrame;
私人诠释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;
    horizo​​ntalFrame = sprite.getWidth()/ frameWidth;
    SRC =新的矩形(0,0,frameWidth,frameHeight);
    DEST =新的矩形(0,0,frameWidth,frameHeight);
    MAXFRAME = verticalFrame * horizo​​ntalFrame;
 }

公共无效的setFrame(INT帧){

      如果(帧LT; MAXFRAME){
          currentFrame =帧;
      }
      INT HF = currentFrame%horizo​​ntalFrame;
      INT VF = currentFrame / horizo​​ntalFrame;
      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的精灵的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

09-26 23:44