2009-09-16 5 views
12

안드로이드 용 타일 기반 게임을 만들고 싶습니다. 지금은 각 타일을 별도의 비트 맵으로 그립니다. 문자열을 읽고 레벨을 그리는 데 어떤 문자가 있는지에 따라 다른 타일을 그려주는 큰 for 루프가 있습니다.성능 저하없이 안드로이드 게임에서 화면에 비트 맵을 많이 그리는 방법

사용자가 스크롤 동작을 사용하여 화면을 스크롤 할 수 있도록 허용했습니다. 그러나 게임은 너무 느립니다. 사용자가 스크롤 한 후 화면을 업데이트하는 데 시간이 오래 걸립니다. 각 타일의 비트 맵을 개별적으로 그려야하기 때문입니다.

레벨을 그리는 더 빠른 방법은 무엇입니까? 모든 타일을 하나의 비트 맵으로 병합 할 수 있다고 생각했습니다. 그러나 나는 이것을 어떻게하는지 모른다. 어떤 아이디어? 당신이 문제를 볼 수 있도록 어쨌든 여기

내 코드입니다 :

package org.example.tutorial2d; 

import android.app.Activity; 
import android.os.Bundle; 
import android.view.GestureDetector; 
import android.view.MotionEvent; 
import android.view.GestureDetector.OnGestureListener; 

import org.example.tutorial2d.Panel; 

public class Tutorial2D extends Activity implements OnGestureListener { 

GestureDetector gestureScanner; 
Panel main; 

/** Called when the activity is first created. */ 
@Override 
public void onCreate(Bundle savedInstanceState) { 
    super.onCreate(savedInstanceState); 

    gestureScanner = new GestureDetector(this); 

    //requestWindowFeature(Window.FEATURE_NO_TITLE);  
    main = new Panel(this); 
    setContentView(main);  

} 

@Override 
public boolean onTouchEvent(MotionEvent me) 
{ 
return gestureScanner.onTouchEvent(me); 
} 

@Override 
public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) 
{ 
main.handleScroll(distanceX,distanceY); 
return true; 
} 

//////////////////// 
/////////////////// 
////////////////// 
@Override 
public boolean onDown(MotionEvent e) 
{ 
return true; 
} 

@Override 
public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) 
{ 
return true; 
} 

@Override 
public void onLongPress(MotionEvent e){ } 

@Override 
public void onShowPress(MotionEvent e) { }  

@Override 
public boolean onSingleTapUp(MotionEvent e)  
{ 
return true; 
} 
//////////////////// 
/////////////////// 
////////////////// 
} 

그리고 수행하는 클래스를 모든 작업 : 전에 안드로이드를위한 프로그램 적이

package org.example.tutorial2d; 

import android.content.Context; 
import android.graphics.Bitmap; 
import android.graphics.BitmapFactory; 
import android.graphics.Canvas; 
import android.graphics.Color; 
import android.graphics.drawable.Drawable; 
import android.util.Log; 
import android.view.View; 
import org.example.tutorial2d.Point; 

public class Panel extends View { 

private int scrollX = 0; 
private int scrollY = 0; 

public Panel(Context context) 
{ 
    super(context); 
} 

@Override 
public void onDraw(Canvas canvas) 
{ 
    /*Bitmap scratch; 
    //Drawable scratch; 
    //scratch = getContext().getResources().getDrawable(
    //  R.drawable.icon); 
    canvas.drawColor(Color.BLACK); 
    //scratch.draw(canvas); 
    int origin = 0; 
    scratch = BitmapFactory.decodeResource(getResources(), R.drawable.horizontal5); 
    canvas.drawBitmap(scratch, origin, origin, null); 
    int width = scratch.getWidth(); 
    int height = scratch.getHeight(); 
    scratch = BitmapFactory.decodeResource(getResources(), R.drawable.room4entrynesw3x3); 
    canvas.drawBitmap(scratch, origin + width, origin - 32, null); 
    */ 

    String sucide_mission = 
"     wwwww\n" + 
"     wfffw\n" + 
"     wfffw\n" + 
"     wfffw\n" + 
"     wwfww\n" + 
"     wfw\n" + 
"     wfw\n" + 
"     wfw\n" + 
"    wwwwwwwfwwwwwfw\n" + 
"    wfffffffffffffw\n" + 
"    wfwwwwwfwwwwwfw\n" + 
"  wwwww wfw wfw wfw\n" + 
"wwwwwwfffwwwwwfwwwwwfwwwwwfw\n" + 
"fffffffffffffffffffffffffffw\n" + 
"wwwwwwfffwwwwwwwwwwwfwwwwwfw\n" + 
"  wwfww   wfw\n" + 
"  wfw   wfw\n" + 
"  wfw   wfw\n" + 
"  wfw   wfw\n" + 
"  wfw   wfw\n" + 
"  wwfww   wfw\n" + 
"  wfffwwfw  fff\n" + 
"  wffffffw  www\n" + 
"  wfffwwfw\n" + 
"  wwwww"; 

    canvas.drawColor(Color.BLACK); 
    int x = 0, y = 0; 

    for (int i = 0; i < sucide_mission.length(); i++) 
    { 
     Bitmap tileImage; 
     char tile = sucide_mission.charAt(i); 

     Log.d("Draw tiles", Character.toString(tile) + " " + x + "," + y); 

     switch (tile) 
     { 
      case 'w': 
       if (x < tileImage = BitmapFactory.decodeResource(getResources(), R.drawable.walla); 
       canvas.drawBitmap(tileImage, x - scrollX, y - scrollY, null); 
       x += 32; 
       break; 
      case 'f': 
       tileImage = BitmapFactory.decodeResource(getResources(), R.drawable.floore); 
       canvas.drawBitmap(tileImage, x - scrollX, y - scrollY, null); 
       x += 32; 
       break; 
      case ' ': 
       x += 32; 
       break; 
      case '\n': 
       y += 32; 
       x = 0; 
       break; 
     } 

    } 

    //canvas.drawBitmap(adapt, 0, 0, paint); 
    //canvas.drawBitmap(corner, origin -scrollX , origin -scrollY, paint); 

} 

public void handleScroll(float distX, float distY) 
{ 
     // X-Axis //////////////////////////////// 

     if(distX > 6.0) 
     { 
      if(scrollX < 460) 
      { 
       scrollX += 30; 
      } 
     } 
     else if(distX < -6.0) 
     { 
      if(scrollX >= 30) 
      { 
       scrollX -= 30; 
      } 
     } 
     //////////////////////////////////////////// 

     // Y-AXIS ////////////////////////////////// 
     if(distY > 6.0) 
     { 
      if(scrollY < 100) 
      { 
       scrollY += 30; 
      } 
     } 
     else if(distY < -6.0) 
     { 
      if(scrollY >= 30) 
      { 
       scrollY -= 30; 
      } 
     }    
     //////////////////////////////////////////// 

     if((scrollX <= 480) && (scrollY <= 120)) 
     { 
      //adapt = Bitmap.createBitmap(bmp, scrollX, scrollY, 320, 480); 
      invalidate(); 
     } 
} 
} 
+3

: 당신이보기를 사용하는, 서피스 뷰 SurfaceView는 거의 확실하게 당신이 원하는 동안. –

답변

28

렌더링 된 모든 타일마다 각 비트 맵 이미지의 새 인스턴스를 만드는 것처럼 보입니다. 어쩌면 그렇게하는 대신 각 타일 유형에 대해 하나의 인스턴스를 만들 수 있습니까? 예 :

private Bitmap wallTile = BitmapFactory.decodeResource(getResources(), R.drawable.walla); 
private Bitmap floorTile = BitmapFactory.decodeResource(getResources(), R.drawable.floore); 

그런 다음 타일을 그릴 때마다 동일한 타일 인스턴스를 다시 사용하십시오. 그래도 작동하지 않는다면 코드의 어떤 부분이 가장 오랜 시간이 걸리는지 확인하고 코드가 실행되는 시간을 최소화하거나 슬림화하려고 시도해야합니다.

면책 조항 : Android 프로그래머가 아닙니다.

+0

고마워요. 제 프로그램이 고쳤습니다. –

3

, 그래서

BitmapFactory.decodeResource(getResources(), R.drawable.walla); 

이 비트를 '이 커버 아래에 가고,하지만 가정 무슨 약 100 % 모르겠어요 코드가 이동하여 비트 맵을 메모리로로드하면 그리면 각 비트 맵을 다시로드하는 것처럼 보입니다.

과거에 작은 게임을 개발할 때 수행 한 작업은 레벨을로드하고 필요한 모든 리소스를 한 번 메모리에로드 한 다음 다시 사용하는 것입니다.

15

문제는 아주 분명합니다. 당신은 단지 많은 지옥을 새고 있습니다. LogCat을 살펴보면 내가 의미하는 바를 알 수 있습니다. 1. 각 프레임마다 문자열을 할당하지 마십시오. 문자열이있는 모든 연산이 메모리 누수와 같아 지므로이 변수는 불변입니다. 대신에 수정하는 간단한 char [] 객체를 사용하십시오. 2. 비트 맵 객체 만들기를 반복해서 반복합니다. DecodeBitmap 메서드는 내부적으로 각 호출에 대해 비트 맵 개체를 할당한다고 가정합니다. 모든 프레임에서 그렇게하는 것이 좋지 않습니다.

엄지 손가락 -> 메모리 누수와 버디의 경우 GC는 그리기를 할 때 매우 비싼 작업입니다.

0

프로그래머가 아닌 사람이 생각한 다른 생각은 스크롤하는 등의 큰 타일 배경을 만들 수 있으며 배경 위에 움직일 수있는 항목 (플레이어, npc, 항목)이 그려지는 두 번째 최상위 레이어입니다. 따라서 스크롤링 속도는 빨라지고 전반적인 렌더링은 줄어들어야합니다. 위의 다른 제안에서 언급했듯이 이미 렌더링 된 타일을 참조하는 것보다 자원 집약적 일 수 있다고 상상해보십시오. 그러나 그렇지 않을 수도 있습니다.:-)

0

사용자가 스크롤 할 때 전체 화면을 이동하는 방법은 어떻습니까? 창에서 스크롤 할 때 실제로는 반대 방향으로 창을 이동합니다. 아래로 스크롤하면 창문이 위로 움직입니다.

뷰 (그리드)의 모든 요소를 ​​수집하고 전체보기를 이동할 수 있습니다. 이미지를 화면에서 빨리 (빠르게) 렌더링하고 필요 ..

사용할 수있는 예제가 있습니다. 홈 화면에 대한 모든 코드를 가져올 수 있으며 왼쪽에서 오른쪽으로 스크롤된다는 것을 알고 있습니다. 들여다 볼만한 것이 있을지도 모릅니다. 나는 그들이 그 앱을 제대로했다고 확신한다.

+0

아, 한 편; 모든 이미지를 단일보기로 수집하는 경우 하나의 큰 비트 맵으로 생각할 수 있습니다. 그것은 본질적으로 GUI가 무엇입니까. 적어도 화면 렌더링 관점에서. – baash05

2
import android.content.Context; 
import android.graphics.Bitmap; 
import android.graphics.BitmapFactory; 
import android.graphics.Canvas; 
import android.util.AttributeSet; 
import android.view.SurfaceHolder; 
import android.view.SurfaceView; 

public class MapLoader extends SurfaceView implements SurfaceHolder.Callback, 
    Runnable { 

SurfaceHolder holder; 
Thread thread; 

Bitmap grass = BitmapFactory.decodeResource(getResources(), 
     R.drawable.tilemapdemo); 
boolean running = false; 

int[][] grassCoords = new int[][] { { 0, 16, 32, 48, 64 }, 
     { 0, 16, 32, 48, 64 }, { 0, 16, 32, 48, 64 }, 
     { 0, 16, 32, 48, 64 }, { 0, 16, 32, 48, 64 } }; 

public MapLoader(Context context, int width, int height) { 
    super(context); 

    holder = getHolder(); 
    holder.addCallback(this); 
} 

public MapLoader(Context context, AttributeSet attrs) { 
    super(context, attrs); 

    holder = getHolder(); 
    holder.addCallback(this); 
} 

public MapLoader(Context context, AttributeSet attrs, int defStyle) { 
    super(context, attrs, defStyle); 

    holder = getHolder(); 
    holder.addCallback(this); 
} 

public void pause() { 
    running = false; 

    while (running) { 
     try { 
      thread.join(); 
     } catch (InterruptedException e) { 
      e.printStackTrace(); 
     } 
     break; 
    } 
    thread = null; 
} 

public void resume() { 
    running = true; 
    thread = new Thread(this); 
    thread.start(); 

} 

@Override 
public void surfaceChanged(SurfaceHolder holder, int format, int width, 
     int height) { 

    running = true; 
    thread = new Thread(this); 
    thread.start(); 

} 

@Override 
public void surfaceCreated(SurfaceHolder holder) { 
    Canvas c = holder.lockCanvas(); 
    draw(c); 
    holder.unlockCanvasAndPost(c); 

} 

@Override 
public void surfaceDestroyed(SurfaceHolder holder) { 

} 

@Override 
public void run() { 

    while (running == true) { 

     // performs drawing to the canvas 
     if (!holder.getSurface().isValid()) { 

      continue; 
     } 

     Canvas c = holder.lockCanvas(); 

     int x = 0; 
     int y = 0; 

     for (x = 0; x < grassCoords.length; x += grass.getWidth()) { 

      for (y = 0; y < grassCoords.length; y += grass.getHeight()) { 

       c.drawBitmap(grass, x, y, null); 
      } 

     } 

     holder.unlockCanvasAndPost(c); 

    } 

} 

}

여전히 사람에게 중요한 그냥 경우
관련 문제