제목 그대로입니다. 객체 재활용에 대해 가르침을 얻고자 이렇게 게시물을 작성해 봅니다.


사연은 이렇습니다;

런너 게임을 개발 중인데, 뭐가 꼬였는지 드래그를 하면 높은 확률로 애니메이션이 주춤거리며 제대로 동작하지 않는다는 거죠.


총 세 가지 애니메이션이 있습니다.


private Character m_Character;

private Character m_Character_Jump;

private Character m_Character_Roll;


차례대로


1. 디폴트 애니메이션 - 달리는 애니메이션( 이미지를 담고 있는 객체명 "m_Character" )

2. 위로 드래그 시 (Down - Move - Up 의 과정을 거쳐 실행) 폴짝 뛰는 애니메이션( "m_Character_Jump" )

3. 아래로 드래그 시 ( 동일한 MotionEvent를 거친 후 실행 ) 장애물 피해 구르는 애니메이션 ( "m_Character_Roll" )



짚히는 구석이 한두 군데가 아니지만 몇 가지로 간추려 보았습니다.


1. ( 각각 다른 객체를 사용하는 바람에 ) Update 과정에서 무언가가 꼬였다

2. Jump나 Roll 시에도 좌표값을 달리는(Run) 애니메이션 객체에서 받아온다는 점

3. 이미지의 좌표값을 지정해 주는 메소드 SetPostion의 사용이 부적절하다



대충 이 세 가지라고 생각합니다. 높은 확률로 잘못 짚었겠지만 말입니다 ㅠ ㅂ0


여기서 제가 알고 싶은 건 1번 문제의 답입니다사실 전부


 혹시 여러 객체를 사용하려다 무언가가 꼬인 건 아닐까? 


 해서 하나의 객체를 재활용하면 될까 싶어 쓰던 객체에 그대로 new를 덮어 씌우기도 하고

 

 먼저 null을 준 다음 다시 new를 줘 보기도 하고....


 하지만 결과는 참담했습니다. 게임이 미친듯이 느려지는데다 애니메이션은 제대로 실행도 안 되더군요.


 그나마도 LargeHeap을 안 줬으면 그대로 튕겼겠죠ㅠㅠㅠㅋㅋㅋ큐ㅜㅠㅠㅠㅠ 


아마 new를 한 번만 줘야 하는데 조건문을 잘못 걸어 계속 new를 주게 되는 바람에 그렇지 싶습니다.



 으아아아므아믄아ㅡ 미치겠습니다. 살려 주세요, 이걸로 한 달 동안 헤매니까 정신이 나갈 것 같습니다.


 아니, 사실은 이걸로 한 달 동안 헤맨 건 아니지만 어쨌든 게임이 한 달 동안 진행이 없으니까 이젠 별별 게 다 걸리고 미칠 것 같습니다.


 이걸 해결해야 굴러서 장애물을 피할 수 있는데 자꾸 주춤거리기만 하고ㅠㅠㅠㅠㅠㅠㅠㅠㅠㅠㅠㅠ


 그리고 장애물도 겹쳐서 나옵니다. 장애물이 생성될 때 일정 거리를 두고 생성이 되어야 하는데 그것도 안 되고ㅜㅜㅜㅜㅜㅜㅜㅜㅜㅜㅜㅜㅜ 사실 이게 가장 큰 문제입니다






@SuppressLint("UseValueOf")

@SuppressWarnings("unused")

public class GameState implements IState {


private GameView m_GameView;

private BackGround[] m_Background;

private long m_Timer;

private static int m_Timer_Count;

private Obstacle[] m_Obstacle;


long LastRegenObstacle;

public static int m_Obst_Number;

private static int Temp_XPos;

private static int Temp_YPos;


private static float Drag_Start_Position;

private static float Drag_End_Position;

private int Drag_Offset;

private boolean Action_Flag;

private boolean YPos_Flag;


private Character m_Character;

private Character m_Character_Jump;

private Character m_Character_Roll;

private Character[] m_Character_Life;

private boolean m_HitCheck;


////////////////////////////////////////////////////////////////////////

////////////////////////////////////////////////////////////////////////

////////////////////////////////////////////////////////////////////////

@SuppressWarnings("static-access")

@SuppressLint("UseValueOf")

@Override

public void Init() {

// TODO 자동 생성된 메소드 스텁

m_Background = new BackGround[2];

m_Background[0] = new BackGround();

m_Background[1] = new BackGround(true);

for(int i = 0; i < 2; i++)

{

m_Background[0].init();

m_Background[1].init();

}

Drag_Start_Position = 0;

Drag_End_Position = 0;

Drag_Offset = 0;

Action_Flag = true;

YPos_Flag = false;

m_Timer = System.currentTimeMillis();

m_Timer_Count = 0;

m_Obstacle = new Obstacle[5];

m_Obstacle[0] = new Obstacle_1();

m_Obstacle[1] = new Obstacle_2();

m_Obstacle[2] = new Obstacle_3();

m_Obstacle[3] = new Obstacle_4();

m_Obstacle[4] = new Obstacle_5();


m_Obstacle[0].setPosition(1300, 410);

m_Obstacle[1].setPosition(2000, 410);

m_Obstacle[2].setPosition(2400, 315);

m_Obstacle[3].setPosition(2800, 325);

m_Obstacle[4].setPosition(3200, 195);

LastRegenObstacle = System.currentTimeMillis();

Temp_XPos = 0;

Temp_YPos = 0;

m_Character_Life = new Character[3];

m_Character = new Character(AppManager.getInstance().

GetBitmap(com.play.R.drawable.sprite_run_600850));

m_Character_Jump = new Character(AppManager.getInstance().

GetBitmap(com.play.R.drawable.jump02));

m_Character_Jump.InSpriteData(m_Character_Jump.GetWidth(),

m_Character_Jump.GetHeight(), 1, 1);

m_Character_Roll = new Character(AppManager.getInstance().

GetBitmap(com.play.R.drawable.roll_sprite));

m_Character_Roll.InSpriteData(680, 655, 15, 6);

m_Character_Roll.setPosition(m_Character_Roll.GetDefaultXPos(),

m_Character_Roll.GetDefaultYPos() + 60);

// m_Character_Roll.m_BoundBox.set(m_Character_Roll.GetX() + 50, m_Character_Roll.GetY() + 200,

// m_Character_Roll.GetX() + 100, m_Character_Roll.GetY() + 400);

m_Character_Roll.m_BoundBox.set(50, 400, 150, 500);



for(int i = 0; i < m_Character.m_Life; i++)

{

m_Character_Life[i] = new Character(AppManager.getInstance().

GetBitmap(com.play.R.drawable.heart));


m_Character_Life[i].InSpriteData(300, 300, 1, 1);

m_Character_Life[i].setPosition((100 * i) + 50, 30);

}

m_HitCheck = false;

}


@Override

public void Destroy() {

// TODO 자동 생성된 메소드 스텁

}


////////////////////////////////////////////////////////////////////////

////////////////////////////////////////////////////////////////////////

////////////////////////////////////////////////////////////////////////


@Override

public void Update() {

// TODO 자동 생성된 메소드 스텁

Log.v("Upate Log", "true!");

long GameTime = System.currentTimeMillis();

m_Character.m_BoundBox.set(m_Character.GetX() + 50, m_Character.GetY(),

m_Character.GetX() + m_Character.Get_Current_XPos(), m_Character.GetY() + m_Character.Get_Current_YPos() - 50);

if(Action_Flag == true)

m_Character.Update(GameTime);

else if(Action_Flag == false)

{

switch(Drag_Offset)

{

case 1:

// if(m_Character.Get_Current_YPos() <= 200)

// {

// YPos_Flag = false;

// }

if(YPos_Flag == false)

{

m_Character.SetYPos_Offset(5);

m_Character.Set_Current_YPos(m_Character.Get_Current_YPos()

+ m_Character.GetYPos_Offset());


//m_Character_Jump.Update(GameTime);

}

else if(YPos_Flag == true)

{

m_Character.SetYPos_Offset(-10);

m_Character.Set_Current_YPos(m_Character.Get_Current_YPos()

+ m_Character.GetYPos_Offset());

 

//m_Character_Jump.Update(GameTime);

}

if(m_Character.Get_Current_YPos() <= 200)

{

YPos_Flag = false;

}

if((m_Character.Get_Current_YPos() >= 400) && (m_Character.GetYPos_Offset() > 0))

{

Action_Flag = true;

YPos_Flag = true;

Drag_Offset = 0;

}

m_Character_Jump.setPosition(m_Character_Jump.Get_Current_XPos(),

m_Character_Jump.Get_Current_YPos());

m_Character_Jump.Update(GameTime);

break;

}

case 2:

{

m_Character.m_BoundBox.set(m_Character.GetX() + 50, m_Character.GetY() + 100,

m_Character.GetX() + 100, m_Character.GetY() + 300);

m_Character_Roll.Update(GameTime);

if(System.currentTimeMillis() - m_Timer >= 1500)

{

m_Timer = System.currentTimeMillis();

Action_Flag = true;

}

}

break;

}

}

m_Background[0].Update(GameTime);

m_Background[1].Update(GameTime, true);

if(System.currentTimeMillis() - m_Timer >= 3000)

{

if(m_Timer_Count > 4)

m_Timer_Count = 0;

else

m_Timer_Count++;

}

// for(int i = 0; i < m_Timer_Count; i++){

// if(m_Obstacle[i] != null)

// m_Obstacle[i].Update(GameTime);

//

if(m_Obstacle[0] != null)

m_Obstacle[0].Update(GameTime);

if(m_Obstacle[1] != null)

m_Obstacle[1].Update(GameTime);

if(m_Obstacle[2] != null)

m_Obstacle[2].Update(GameTime);

// if(m_Obstacle[3] != null)

// m_Obstacle[3].Update(GameTime);

// if(m_Obstacle[4] != null)

// m_Obstacle[4].Update(GameTime);

// if(m_Obstacle[1].Get_M_X() < -400)

// m_Obstacle[1].SetCollisionFlag(true);

for(int i = 0; i < 3; i++){

m_Character_Life[i].Update(GameTime);

}

MakeObstacle();

CheckCollision();

}

////////////////////////////////////////////////////////////////////////

////////////////////////////////////////////////////////////////////////

////////////////////////////////////////////////////////////////////////

public void CheckCollision()

{

for(int i = 0; i < 3; i++){

if(m_Obstacle[i] != null)

if(m_Obstacle[i].m_BoundFlag){

if(CollisionManager.CheckBoxToBox(m_Character.m_BoundBox, m_Obstacle[i].m_BoundBox) 

||(CollisionManager.CheckBoxToBox(m_Character_Roll.m_BoundBox, m_Obstacle[i].m_BoundBox))){

//m_Character.destroyPlayer();

m_Obstacle[i].SetCollisionFlag(false);

AppManager.getInstance().GetGameView().VIBE();

if(m_Character.GetLife() <= 0)

{

AppManager.getInstance().GetGameView().ChangeGameState(new DeadState());

}

return ;

}

}

}

}

////////////////////////////////////////////////////////////////////////

////////////////////////////////////////////////////////////////////////

////////////////////////////////////////////////////////////////////////

@Override

public void Render(Canvas canvas) {

// TODO 자동 생성된 메소드 스텁

m_Background[0].Draw(canvas);

m_Background[1].Draw(canvas);

// for(int i = 0; i < m_Timer_Count; i++){

if(m_Obstacle[0] != null)

m_Obstacle[0].Draw(canvas);

if(m_Obstacle[1] != null)

m_Obstacle[1].Draw(canvas);

if(m_Obstacle[2] != null)

m_Obstacle[2].Draw(canvas);

// if(m_Obstacle[3] != null)

// m_Obstacle[3].Draw(canvas);

// if(m_Obstacle[4] != null)

// m_Obstacle[4].Draw(canvas);

// }

for(int i = 0; i < 3; i++){

if(m_Character.GetLife() >= 3)

m_Character_Life[i].DrawLife(canvas);

else if(m_Character.GetLife() >= 2)

{

m_Character_Life[0].DrawLife(canvas);

m_Character_Life[1].DrawLife(canvas);

}

else if(m_Character.GetLife() >= 1)

m_Character_Life[0].DrawLife(canvas);

}

if(Action_Flag)

m_Character.Draw(canvas, true, m_HitCheck);

else if(!Action_Flag)

{

if(Drag_Offset == 1)

{

m_Character_Jump.Draw(canvas, false, m_HitCheck);

}

else if(Drag_Offset == 2)

{

m_Character_Roll.Draw(canvas, true, m_HitCheck);

}

}

}


////////////////////////////////////////////////////////////////////////

////////////////////////////////////////////////////////////////////////

////////////////////////////////////////////////////////////////////////

public void MakeObstacle()

{

if(System.currentTimeMillis() - LastRegenObstacle >= 1000)

{

LastRegenObstacle = System.currentTimeMillis();

for(int i = 0; i <= 2; i++)//for(int i = 0; i <= m_Timer_Count; i++)

{

Temp_XPos = 0;

Temp_YPos = 0;

switch(i)

{

case 0:

{

if(m_Obstacle[i] == null)

m_Obstacle[i] = new Obstacle_1();

m_Obstacle[i].SetCollisionFlag(true);


m_Obst_Number = i;

SetObstacleXPos(200, false);

SetObstacleXPos(((int) Math.random() *1400) + 1500, true);

SetObstacleYPos(m_Obstacle[i].Get_Random_Obstacle_YPos());

Log.v("m_x", "m_x : " + m_Obstacle[i].Get_M_X());

if(m_Obstacle[i].Get_M_X() < -400)

m_Obstacle[i].setPosition(Temp_XPos, Temp_YPos);

Log.v("m_x", "Setposition m_x : " + m_Obstacle[0].Get_M_X());

}

break;

case 1:

{

Log.v("Count Check", "true");

if(m_Obstacle[i] == null)

m_Obstacle[i] = new Obstacle_2();

m_Obstacle[i].SetCollisionFlag(true);

m_Obst_Number = i;

SetObstacleXPos(400, false);

SetObstacleXPos(((int) Math.random() *1800) + 1900, true);

SetObstacleYPos(m_Obstacle[i].Get_Random_Obstacle_YPos());

if(m_Obstacle[i].Get_M_X() < -400)

m_Obstacle[i].setPosition(Temp_XPos, Temp_YPos);

}

break;

case 2:

{

if(m_Obstacle[2] == null)

m_Obstacle[2] = new Obstacle_3();

m_Obstacle[i].SetCollisionFlag(true);

m_Obst_Number = 2;

SetObstacleXPos(400, false);

SetObstacleXPos(((int) Math.random() *2000) + 2100, true);

SetObstacleYPos(m_Obstacle[2].Get_Random_Obstacle_YPos());

if(m_Obstacle[2].Get_M_X() < -400)

m_Obstacle[2].setPosition(Temp_XPos, Temp_YPos);

}

break;

case 3:

{

if(m_Obstacle[3] == null)

m_Obstacle[3] = new Obstacle_4();

m_Obstacle[i].SetCollisionFlag(true);

m_Obst_Number = 3;

SetObstacleXPos(400, false);

SetObstacleXPos(((int) Math.random() *2300) + 2400, true);

SetObstacleYPos(m_Obstacle[3].Get_Random_Obstacle_YPos());

if(m_Obstacle[3].Get_M_X() < -400)

m_Obstacle[3].setPosition(Temp_XPos, Temp_YPos);

}

break;

case 4:

{

if(m_Obstacle[4] == null)

m_Obstacle[4] = new Obstacle_5();

m_Obstacle[i].SetCollisionFlag(true);

m_Obst_Number = 4;

SetObstacleXPos(400, false);

SetObstacleXPos(((int) Math.random() *2500) + 2600, true);

SetObstacleYPos(m_Obstacle[4].Get_Random_Obstacle_YPos());

if(m_Obstacle[4].Get_M_X() < -400)

m_Obstacle[4].setPosition(Temp_XPos, Temp_YPos);

}

break;

}

}

}

}

public void SetObstacleXPos(int XPos, boolean AddFlag)

{

if(!AddFlag)

Temp_XPos = XPos;

else

Temp_XPos += XPos;

}


public void SetObstacleYPos(int YPos)

{

Temp_YPos = YPos;

}

public int GetObstacleXPos()

{

return Temp_XPos;

}

public int GetObstacleYPos()

{

return Temp_YPos;

}


public int GetrandObst()

{

return m_Obst_Number;

}

public int GetTempXPos()

{

return Temp_XPos;

}

////////////////////////////////////////////////////////////////////////

////////////////////////////////////////////////////////////////////////

////////////////////////////////////////////////////////////////////////

@Override

public boolean onKeyDown(int keyCode, KeyEvent event) {

// TODO 자동 생성된 메소드 스텁

return false;

}

@Override

public boolean onTouchEvent(MotionEvent event) {

int m_x = (int) (event.getX());

int m_y = (int) (event.getY());

if (event.getAction() == MotionEvent.ACTION_DOWN) {

Log.v("MoveLog", "true!");

if(Action_Flag == true)

{

Log.v("MoveLog", "true~!");

Drag_Start_Position = event.getY();

}

return true;

}

if(event.getAction() == MotionEvent.ACTION_MOVE) {


if(Action_Flag == true)

{

Drag_End_Position = event.getY();

}

return true;

}

if(event.getAction() == MotionEvent.ACTION_UP){

if(Action_Flag == true)

{

if(Drag_Start_Position > Drag_End_Position + 100)

{

Drag_Start_Position = 0.0f;

Drag_End_Position = 0.0f;

Drag_Offset = 1;

Action_Flag = false;

}

else if(Drag_Start_Position + 100 < Drag_End_Position)

{

Drag_Start_Position = 0.0f;

Drag_End_Position = 0.0f;

Drag_Offset = 2;

Action_Flag = false;

}

return true;

}

}

return false;

}

}