2010년 12월 31일 금요일

예제 안드로이드 게임 - 퍼즐 버블

안드로이드 게임 소스

package b.pb;
import java.io.IOException;
import java.io.InputStream;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.FloatBuffer;
import java.nio.ShortBuffer;
import javax.microedition.khronos.egl.EGLConfig;
import javax.microedition.khronos.opengles.GL10;
import b.pb.R;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.media.MediaPlayer;
import android.opengl.*;
import android.os.SystemClock;
import android.util.Log;
import android.view.MotionEvent;
import android.view.VelocityTracker;
import android.view.View;
public class AndroPB implements GLSurfaceView.Renderer ,
 View.OnTouchListener
{
 int  VIEW_LEFT= 0;
 int  VIEW_TOP= 320;
 int  VIEW_WIDTH= 240;
 int  VIEW_HEIGHT =320;
 final int  NUM_MAX_BALL= 100;
 final int  NUM_BOARD_ROW= 11;
 final int  NUM_BOARD_COL= 8;
 final int  CONSOLE_HEIGHT =40;
 int  SCORE_LEFT =(VIEW_LEFT+3);
 int  SCORE_TOP;
 int  SCORE_WIDTH =(8*10);
 int  SCORE_HEIGHT =14;
 int  TIME_LEFT =(VIEW_LEFT+3);
 int  TIME_TOP;
 int  TIME_WIDTH =(8*10);
 int  TIME_HEIGHT= 14;
 int  CUR_BALL_X =(int)(VIEW_LEFT+VIEW_WIDTH/2);
 int  CUR_BALL_Y;
 int  NEXT_BALL_X =(int)(VIEW_LEFT+VIEW_WIDTH/2+CONSOLE_HEIGHT);
 int  NEXT_BALL_Y;
 final int  NUM_FRAME_BALL= 15;
 //Animation Stage
 final int  AS_NONE =0;
 final int  AS_FLOAT= 1;
 final int  AS_SINK =2;
 final float  SPEED_ANIMATION= 6;
 final int  NUM_BALL_TYPE= 9;
 final float  ROOT3        =1.73205080756887729352744634150590f;
 final float  V_SHOOTER     = 0.00310000000000000000000000000000f;
 final float  RAD_SHOOTER_LOWEST= 0.17453292519943295769236907684886f;
 final float RAD_90     =  1.57079632679489661923132169163975f ;
 final float RAD_SHOOTER_HIGHEST =2.96705972839036028077027430643060f;
 float BALL_REALRADIUS   =15.50f;
 int  BALL_PIXELRADIUS  =15;
 int  BALL_PIXELDIAMETER= 30;
 float  D_COLLISION     =29.5f;
 final float MAX_BONDING_SPEED =5000;
 final float MAX_BONDING_SPEED_NSB =750;
 final String FNAME_BALL ="ball.bmp";
 final int  NUM_MAX_FNAME =20;
 final int  ABF_FALLBALL =0x00000001;
 final int  ABF_SHOOTBALL =0x00000002;
 float SPEED_MOVE_NEXT;

 float frametime=0.03f;
 class BoardBall
 {
  boolean bExist;
  byte BallType;
  byte AniStage;
  float AniIndex;
  byte bProof;
 };
 class ActiveBall
 {
  byte bExist;
  byte bVisible;
  byte BallType;
  float AniIndex;
  byte AniStage;
  int Flag;
  int Age;
  float x,y;
  float vx,vy;
 };
 class Shooter
 {
  boolean bShotEnable;
  //
  byte Cur_BallType;
  int Cur_AniStage;
  float Cur_AniIndex;
  float Cur_x,Cur_y;
  //
  byte Next_BallType;
  int Next_AniStage;
  float Next_AniIndex;
  Shooter()
  {
   bShotEnable=false;
  }
 };
 class NearSameBall
 {
  int row,col;
 };
 class Console
 {
  float Time;//스테이지 시간
  float ShotTime;//일정시간이 지나면 자동발사
  int Score;//게임 점수
  Shooter S;//발사대 정보
  Console()
  {
   S=new Shooter();
  }
 };
 class BallPhysics
 {
  float g;
  float max_speed;
  float LifeTime;
 };
 class GAME
 {
  short nStage;
  String[] pStageFileName;
 };
 class STAGE
 {
  short nBall;
  String pBGMFileName;
  String pBGIFileName;
 };
 class OPTION
 {
  int Level;
  int bSound;
 };
 class FloatPoint
 {
  float x,y;
 };
 class IntegerPoint
 {
  int x,y;
 };

 OPTION Option;
 class RECT
 {
  public int left,top,right,bottom;
 };
 IntegerPoint CircleTable[];
 FloatPoint XYTable[];
 BallPhysics BPTable[];
 //Balls Data
 BoardBall BB[];
 ActiveBall AB[];
 int nAB=0;
 int nABTail=0;
 int nBB=0;
 //계기판
 Console CS;
 MediaPlayer snd_float,snd_glass,snd_metal,snd_nsb,snd_shooting,
  snd_sink,snd_stageclear,snd_stageend,snd_stagestart,snd_stone;
 //game,stage data
 GAME Game;
 STAGE CurStage;
 int nCurStage=0;
 Context ctx;
 public AndroPB(Context ctxi)
 {
  ((DefaultActivity)ctxi).glview.setOnTouchListener(this);
  ctx=ctxi;
  BB=new BoardBall[NUM_BOARD_ROW*NUM_BOARD_COL];
  for(int i=0;i<NUM_BOARD_ROW*NUM_BOARD_COL;i++)
   BB[i]=new BoardBall();
  AB=new ActiveBall[NUM_MAX_BALL];
  for(int i=0;i<NUM_MAX_BALL;i++)
   AB[i]=new ActiveBall();
  Game=new GAME();
  CurStage=new STAGE();
  Option=new OPTION();
  CS=new Console();
 
  snd_float=MediaPlayer.create(ctx,R.raw.floating);
  snd_glass=MediaPlayer.create(ctx,R.raw.glass);
  snd_metal=MediaPlayer.create(ctx,R.raw.metal);
  snd_nsb=MediaPlayer.create(ctx,R.raw.nsb);
  snd_shooting=MediaPlayer.create(ctx,R.raw.shooting);
  snd_sink=MediaPlayer.create(ctx,R.raw.sink);
  snd_stageclear=MediaPlayer.create(ctx,R.raw.stage_clear);
  snd_stageend=MediaPlayer.create(ctx,R.raw.stage_end);
  snd_stagestart=MediaPlayer.create(ctx,R.raw.stage_start);
  snd_stone=MediaPlayer.create(ctx,R.raw.stone);
 
  CircleTable=new IntegerPoint[2*6];
  CircleTable[0]=new IntegerPoint();
  CircleTable[0].x=-1;
  CircleTable[0].y=1;
  CircleTable[1]=new IntegerPoint();
  CircleTable[1].x=-1;
  CircleTable[1].y=0;
  CircleTable[2]=new IntegerPoint();
  CircleTable[2].x=-1;
  CircleTable[2].y=-1;
  CircleTable[3]=new IntegerPoint();
  CircleTable[3].x=0;
  CircleTable[3].y=-1;
  CircleTable[4]=new IntegerPoint();
  CircleTable[4].x=1;
  CircleTable[4].y=0;
  CircleTable[5]=new IntegerPoint();
  CircleTable[5].x=0;
  CircleTable[5].y=1;
  CircleTable[6]=new IntegerPoint();
  CircleTable[6].x=0;
  CircleTable[6].y=1;
  CircleTable[7]=new IntegerPoint();
  CircleTable[7].x=-1;
  CircleTable[7].y=0;
  CircleTable[8]=new IntegerPoint();
  CircleTable[8].x=0;
  CircleTable[8].y=-1;
  CircleTable[9]=new IntegerPoint();
  CircleTable[9].x=1;
  CircleTable[9].y=-1;
  CircleTable[10]=new IntegerPoint();
  CircleTable[10].x=1;
  CircleTable[10].y=0;
  CircleTable[11]=new IntegerPoint();
  CircleTable[11].x=1;
  CircleTable[11].y=1;
 
  XYTable=new FloatPoint[NUM_BOARD_ROW*NUM_BOARD_COL];
  for(int i=0;i<NUM_BOARD_ROW*NUM_BOARD_COL;i++)
   XYTable[i]=new FloatPoint();
 
  BPTable=new BallPhysics[9];
  BPTable[0]=new BallPhysics();
  BPTable[0].g=400;
  BPTable[0].max_speed=2000;
  BPTable[0].LifeTime=12;
 
  BPTable[1]=new BallPhysics();
  BPTable[1].g=400;
  BPTable[1].max_speed=2000;
  BPTable[1].LifeTime=12;
 
  BPTable[2]=new BallPhysics();
  BPTable[2].g=400;
  BPTable[2].max_speed=2000;
  BPTable[2].LifeTime=12;
 
  BPTable[3]=new BallPhysics();
  BPTable[3].g=400;
  BPTable[3].max_speed=2000;
  BPTable[3].LifeTime=12;
 
  BPTable[4]=new BallPhysics();
  BPTable[4].g=400;
  BPTable[4].max_speed=2000;
  BPTable[4].LifeTime=12;
 
  BPTable[5]=new BallPhysics();
  BPTable[5].g=400;
  BPTable[5].max_speed=2000;
  BPTable[5].LifeTime=12;
 
  BPTable[6]=new BallPhysics();
  BPTable[6].g=400;
  BPTable[6].max_speed=2000;
  BPTable[6].LifeTime=12;
 
  BPTable[7]=new BallPhysics();
  BPTable[7].g=400;
  BPTable[7].max_speed=2000;
  BPTable[7].LifeTime=12;
 
  BPTable[8]=new BallPhysics();
  BPTable[8].g=400;
  BPTable[8].max_speed=2000;
  BPTable[8].LifeTime=12;
 }
 public void onDrawFrame(GL10 gl)
 {
  try
  {
   gl.glDisable(GL10.GL_DITHER);
   gl.glTexEnvx(GL10.GL_TEXTURE_ENV,GL10.GL_TEXTURE_ENV_MODE,GL10.GL_MODULATE);
   gl.glClearColor(0,0,0,1);
   gl.glClear(GL10.GL_COLOR_BUFFER_BIT|GL10.GL_DEPTH_BUFFER_BIT);

   CS.Time+=frametime;
   if(CS.S.bShotEnable==true && nBB!=0)
    CS.ShotTime-=frametime;
  
   PlayMain(gl);
  }
  catch(Exception ex)
  {
   ex.printStackTrace();
   Log.v("",ex.toString());
  }
 }

 protected void draw_ball(GL10 gl,int x,int y,int balltype,int ani_stage)
 {
  float rr=BALL_REALRADIUS;
  float xx=x;
  float yy=y;
  float[] coords=
  {
   xx-rr,yy-rr,
   xx+rr,yy-rr,
   xx+rr,yy+rr,
   xx-rr,yy+rr,
  };
 
  vtx_rect.clear();
  for(int i=0;i<4;i++)
  {
   for(int j=0;j<2;j++)
   {
    vtx_rect.put(coords[i*2+j]);
   }
  }
  vtx_rect.position(0);
 
  int row=balltype;
  int col=ani_stage;
  double adj=307/512.0;
  float[] tcoords=
  {
   (float)((1/15.0)*(col+1)),(float)((1/9.0)*adj*(row+1)),
   (float)((1/15.0)*(col+0)),(float)((1/9.0)*adj*(row+1)),
   (float)((1/15.0)*(col+0)),(float)((1/9.0)*adj*(row+0)),
   (float)((1/15.0)*(col+1)),(float)((1/9.0)*adj*(row+0)),
  };
 
  tc_rect.clear();
  for(int i=0;i<4;i++)
  {
   for(int j=0;j<2;j++)
   {
    tc_rect.put(tcoords[i*2+j]);
   }
  }
  tc_rect.position(0);
 
  gl.glColor4f(1,1,1,1);
  gl.glVertexPointer(2,GL10.GL_FLOAT,0,vtx_rect);
  gl.glTexCoordPointer(2,GL10.GL_FLOAT,0,tc_rect);
  gl.glDrawElements(GL10.GL_TRIANGLES,6,GL10.GL_UNSIGNED_SHORT,idx_rect);
 }

 private FloatBuffer vtx_rect;
 private FloatBuffer tc_rect;
 private ShortBuffer idx_rect;
 private int balltex;
 protected void prepareResource(GL10 gl) throws IOException
 {
  ByteBuffer vbb=ByteBuffer.allocateDirect(4*2*4);
  vbb.order(ByteOrder.nativeOrder());
  vtx_rect=vbb.asFloatBuffer();
 
  ByteBuffer ibb=ByteBuffer.allocateDirect(6*2);
  ibb.order(ByteOrder.nativeOrder());
  idx_rect=ibb.asShortBuffer();
 
  ByteBuffer tbb=ByteBuffer.allocateDirect(4*2*4);
  tbb.order(ByteOrder.nativeOrder());
  tc_rect=tbb.asFloatBuffer();
 
  float[] coords=
  {
   -0.5f,-0.5f,
   0.5f,-0.5f,
   0.5f,0.5f,
   -0.5f,0.5f,
  };
 
  for(int i=0;i<4;i++)
  {
   for(int j=0;j<2;j++)
   {
    vtx_rect.put(coords[i*2+j]);
   }
  }
 
  int row=0,col=14;
  float[] tcoords=
  {
   (1/15.0f)*(col+1),(1/9.0f)*(row+1),
   (1/15.0f)*(col+0),(1/9.0f)*(row+1),
   (1/15.0f)*(col+0),(1/9.0f)*(row+0),
   (1/15.0f)*(col+1),(1/9.0f)*(row+0),
  };
 
  for(int i=0;i<4;i++)
  {
   for(int j=0;j<2;j++)
   {
    tc_rect.put(tcoords[i*2+j]);
   }
  }
 
  short[] idx={0,1,2,0,2,3};
  for(int i=0;i<6;i++)
  {
   idx_rect.put(idx[i]);
  }
 
  vtx_rect.position(0);
  idx_rect.position(0);
  tc_rect.position(0);
 
  loadbitmap(gl);
 
  LoadGame();
 }

 protected void loadbitmap(GL10 gl) throws IOException
 {
  gl.glEnable(GL10.GL_TEXTURE_2D);
  int[] textures=new int[1];
  gl.glGenTextures(1,textures,0);
  balltex=textures[0];
  gl.glBindTexture(GL10.GL_TEXTURE_2D,balltex);
 
  gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MIN_FILTER,
    GL10.GL_NEAREST);
  gl.glTexParameterf(GL10.GL_TEXTURE_2D,
    GL10.GL_TEXTURE_MAG_FILTER,
    GL10.GL_LINEAR);
  gl.glTexParameterx(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_WRAP_S,
  GL10.GL_REPEAT);
  gl.glTexParameterx(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_WRAP_T,
  GL10.GL_REPEAT);
 
  gl.glTexEnvf(GL10.GL_TEXTURE_ENV,GL10.GL_TEXTURE_ENV_MODE,GL10.GL_REPLACE);
  InputStream is=ctx.getAssets().open(FNAME_BALL);
  Bitmap bitmap;
  bitmap=BitmapFactory.decodeStream(is);
  is.close();
  GLUtils.texImage2D(GL10.GL_TEXTURE_2D,0,bitmap,0);
  bitmap.recycle();
 }
 public void onSurfaceChanged(GL10 gl,int width,int height)
 {
  VIEW_LEFT= 0;
  VIEW_WIDTH= width;
  VIEW_HEIGHT =height;
  VIEW_TOP= VIEW_HEIGHT;
  BALL_PIXELDIAMETER= (int)(VIEW_WIDTH/(float)NUM_BOARD_COL);
  BALL_REALRADIUS   =(float)BALL_PIXELDIAMETER/2; 
  BALL_PIXELRADIUS  =BALL_PIXELDIAMETER/2;
 
  SCORE_LEFT =(VIEW_LEFT+3);
  SCORE_TOP= (VIEW_TOP-VIEW_HEIGHT+CONSOLE_HEIGHT-4);
  SCORE_WIDTH =(8*10);
  SCORE_HEIGHT =14;
  TIME_LEFT =(VIEW_LEFT+3);
  TIME_TOP =(VIEW_TOP-VIEW_HEIGHT+CONSOLE_HEIGHT-22);
  TIME_WIDTH =(8*10);
  TIME_HEIGHT= 14;
  CUR_BALL_X =(int)(VIEW_LEFT+VIEW_WIDTH/2);
  CUR_BALL_Y =(int)BALL_PIXELDIAMETER;
 
  SPEED_MOVE_NEXT=BALL_PIXELDIAMETER*2;
  NEXT_BALL_X =(int)(VIEW_LEFT+VIEW_WIDTH/2+BALL_PIXELDIAMETER);
  NEXT_BALL_Y =(int)BALL_PIXELDIAMETER;
  CS.S.bShotEnable=false;
  CS.S.Cur_x=NEXT_BALL_X;
  CS.S.Cur_y=CUR_BALL_Y;
 
  D_COLLISION=BALL_PIXELDIAMETER;
  gl.glViewport(0,0,VIEW_WIDTH,VIEW_HEIGHT);
  gl.glMatrixMode(GL10.GL_PROJECTION);
  gl.glLoadIdentity();
  gl.glMatrixMode(GL10.GL_MODELVIEW);
  gl.glLoadIdentity();
 
  GLU.gluOrtho2D(gl,0,VIEW_WIDTH,0,VIEW_HEIGHT);
  MakeXYTable();
 }
 public void onSurfaceCreated(GL10 gl,EGLConfig config)
 {
  gl.glDisable(GL10.GL_DITHER);
  gl.glHint(GL10.GL_PERSPECTIVE_CORRECTION_HINT,GL10.GL_FASTEST);
  gl.glClearColor(0.0f,0.0f,0.0f,1);
  gl.glShadeModel(GL10.GL_SMOOTH);
  gl.glEnable(GL10.GL_DEPTH_TEST);
  try
  {
   gl.glEnable(GL10.GL_TEXTURE_2D);
   prepareResource(gl);
  }
  catch(IOException e)
  {
   e.printStackTrace();
  }
 }
 void MakeXYTable()
 {
  int i,j;
  for(i=0;i<NUM_BOARD_ROW;i++)
  {
   for(j=0;j<NUM_BOARD_COL;j++)
   {
    if(i%2==0)
    {
     XYTable[i*NUM_BOARD_COL+j].x=VIEW_LEFT+BALL_PIXELRADIUS+BALL_PIXELDIAMETER*j;
     XYTable[i*NUM_BOARD_COL+j].y=VIEW_TOP-BALL_PIXELRADIUS-(ROOT3/2)*(BALL_PIXELDIAMETER+1.2f)*i;
    }
    else
    {
     XYTable[i*NUM_BOARD_COL+j].x=VIEW_LEFT+BALL_PIXELDIAMETER+BALL_PIXELDIAMETER*j;
     XYTable[i*NUM_BOARD_COL+j].y=VIEW_TOP-BALL_PIXELRADIUS-(ROOT3/2)*(BALL_PIXELDIAMETER+1.2f)*i;
    }
   }
  }
 }
 //----------------------------------------------알고리즘---------//
 float Distance2D(float x1,float y1,float x2,float y2)
 {
     return (float)Math.sqrt( (x2-x1)*(x2-x1) + (y2-y1)*(y2-y1) );
 }

 class int_pair
 {
  public int row,col;
 };
 int_pair GetNearestBB(float x,float y,int Base_row,int Base_col)
 {
  int k;
  int minIndex_Circle=0;
  float minD_Circle=99999;//충분히 큰수
  float curD_Circle;
  float x1,y1;
  int EvenOdd=Base_row%2;
  int row,col;
  for(k=0;k<6;k++)
  {
   row=Base_row+CircleTable[EvenOdd*6+k].y;
   col=Base_col+CircleTable[EvenOdd*6+k].x;
   //홀수줄(1,3,5,...)에서 마지막 열은 사용안한다.
   int EvenOdd_me=row%2;
   if((EvenOdd_me==1)&&(col>=(NUM_BOARD_COL-1)))
    continue;
  
   if(row<0 || row>=NUM_BOARD_ROW) continue;
   if(col<0 || col>=NUM_BOARD_COL) continue;
   x1=XYTable[row*NUM_BOARD_COL+col].x;
   y1=XYTable[row*NUM_BOARD_COL+col].y;
   curD_Circle=Distance2D(x1,y1,x,y);
   if(curD_Circle<minD_Circle)
   {
    if(BB[row*NUM_BOARD_COL+col].bExist==false)
    {
     minD_Circle=curD_Circle;
     minIndex_Circle=k;
    }
   }
  }
 
  //충돌한 곳의 BB어레이상의 열,행 위치
  int_pair ip=new int_pair();
  ip.row=Base_row+CircleTable[EvenOdd*6+minIndex_Circle].y;
  ip.col=Base_col+CircleTable[EvenOdd*6+minIndex_Circle].x;
  return ip;
 }
 int MakeNSB(NearSameBall[] pNSB,int SRC_row,int SRC_col,byte SRC_BallType)
 {
  int i,j,k;
  int s;
  int EvenOdd;
  int row,col;
  IntegerPoint[] SameTypeBall=new IntegerPoint[NUM_MAX_BALL];
  for(i=0;i<NUM_MAX_BALL;i++)
   SameTypeBall[i]=new IntegerPoint();
  int STBIndex=0;
  for(i=0;i<NUM_BOARD_ROW;i++)
  {
   for(j=0;j<NUM_BOARD_COL;j++)
   {
    if((BB[i*NUM_BOARD_COL+j].bExist==true)&&
      (BB[i*NUM_BOARD_COL+j].BallType==SRC_BallType))
    {
     SameTypeBall[STBIndex].x=j;
     SameTypeBall[STBIndex].y=i;
     STBIndex++;
    }
   }
  }
  NearSameBall[] NSB=pNSB;
  int NSBIndex=0;
  int nPrevCSB=0,nCurCSB=1;
  int PrevCSBIndex=0;
  NSB[NSBIndex].row=SRC_row;
  NSB[NSBIndex].col=SRC_col;
  NSBIndex++;
  while(true)
  {
   nPrevCSB=nCurCSB;
   nCurCSB=0;
   for(i=0;i<nPrevCSB;i++)
   {
    EvenOdd=NSB[PrevCSBIndex+i].row%2;
    for(j=0;j<6;j++)
    {
     row=NSB[PrevCSBIndex+i].row+CircleTable[EvenOdd*6+j].y;
     col=NSB[PrevCSBIndex+i].col+CircleTable[EvenOdd*6+j].x;
     for(k=0;k<STBIndex;k++)
     {
      if((SameTypeBall[k].x==col)&&(SameTypeBall[k].y==row))
      {
       for(s=0;s<NSBIndex;s++)
       {
        if((NSB[s].col==col)&&(NSB[s].row==row))
         break;
       }
       if(s==NSBIndex)
       {
        NSB[NSBIndex].row=row;
        NSB[NSBIndex].col=col;
        NSBIndex++;
        nCurCSB++;
       }
       break;
      }
     }
    }
   }
   if(nCurCSB==0)
    break;
   PrevCSBIndex=NSBIndex-nCurCSB;
  }
  return NSBIndex;
 }
 void ShootSB(float v_x,float v_y)
 {
  if(!AddAB_SB(v_x,v_y))
  {
   CS.S.Cur_x=CUR_BALL_X;
   CS.S.Cur_y=CUR_BALL_Y;
   return;
  }
  CS.S.bShotEnable=false;
  CS.ShotTime=10-(nCurStage/(float)Game.nStage)*9;
  CS.S.Cur_BallType=CS.S.Next_BallType;
  CS.S.Cur_AniIndex=14;
  CS.S.Cur_AniStage=AS_NONE;
  CS.S.Cur_x=NEXT_BALL_X;
  CS.S.Cur_y=CUR_BALL_Y;
  CS.S.Next_BallType=RandomBallType();
  CS.S.Next_AniIndex=0;
  CS.S.Next_AniStage=AS_FLOAT;
  snd_sink.start();
 }

 byte RandomBallType()
 {
  byte nBallType=NUM_BALL_TYPE;
  if(nCurStage==1) nBallType=1;
  else if(nCurStage==2) nBallType=2;
  else if(nCurStage==3) nBallType=3;
  else if(nCurStage==4) nBallType=4;
  else if(nCurStage==5) nBallType=5;
  else if(nCurStage==6) nBallType=6;
  else if(nCurStage==7) nBallType=7;
  else if(nCurStage==8) nBallType=8;
  else nBallType=9;
  return (byte)((Math.random()*100000)%(nBallType));
 }
 //시작------------------공들사이의 충돌처리--------------------------//
 void AB_AB_Collision(int i)
 {
  int j;
  float Angle;
  float Vecx,Vecy;
  float S;//공의 속력
  float S_Collision;//충돌시 영향을 미치는 성분의 크기
  float D;//공사이의 거리
  for(j=0;j<nABTail;j++)
  {
   if(AB[j].bExist==1)
   {
    if(i==j)
     continue;
    D=Distance2D(AB[j].x,AB[j].y,AB[i].x,AB[i].y);
    if(D<=D_COLLISION)
    {
     if(AB[i].y>0)
      snd_glass.start();
    
     Vecx=(AB[j].x-AB[i].x)/D;
     Vecy=(AB[j].y-AB[i].y)/D;
    
     //위치보정
     float penet_depth=D_COLLISION-D;
     //+0.3 : prevents collision checking twice
     AB[i].x-=Vecx*(penet_depth+0.3);
     AB[i].y-=Vecy*(penet_depth+0.3);
    
     S=(float)Math.sqrt((AB[i].vx*AB[i].vx)+(AB[i].vy*AB[i].vy));
     Angle=(float)(Math.atan2(Vecy,Vecx)-Math.atan2(AB[i].vy,AB[i].vx));
    
     S_Collision=(float)(S*Math.cos(Angle));
     if(S_Collision<=0)
      continue;
     //snd_metal.start();
     Vecx*=S_Collision;
     Vecy*=S_Collision;
     AB[i].vx-=(Vecx);
     AB[i].vy-=(Vecy);
     AB[j].vx+=(Vecx);
     AB[j].vy+=(Vecy);
    }
   }
  }
 }
 void AB_BB_Collision(int i)
 {
  int j,k;
  float Angle,Vecx,Vecy;
  float S;
  float S_Collision;
  float D;
  for(j=0;j<NUM_BOARD_ROW;j++)
  {
   for(k=0;k<NUM_BOARD_COL;k++)
   {
    if(BB[j*NUM_BOARD_COL+k].bExist==true)
    {
     D=Distance2D(XYTable[j*NUM_BOARD_COL+k].x,XYTable[j*NUM_BOARD_COL+k].y,AB[i].x,AB[i].y);
     //충돌이 이루어 졌다면...
     if(D<=D_COLLISION)
     {
      if(AB[i].y>0)
       snd_glass.start();
     
      NearSameBall[] NSB=new NearSameBall[NUM_MAX_BALL];
      for(int s=0;s<NUM_MAX_BALL;s++)
       NSB[s]=new NearSameBall();
      int nNSB=0;
      int row,col;
     
      Vecx=(XYTable[j*NUM_BOARD_COL+k].x-AB[i].x)/D;
      Vecy=(XYTable[j*NUM_BOARD_COL+k].y-AB[i].y)/D;
     
      //위치보정
      float penet_depth=D_COLLISION-D;
      AB[i].x-=Vecx*penet_depth;
      AB[i].y-=Vecy*penet_depth;
      //SB의 속력
      S=(float)Math.sqrt((AB[i].vx*AB[i].vx)+(AB[i].vy*AB[i].vy));
      Angle=(float)(Math.atan2(Vecy,Vecx)-Math.atan2(AB[i].vy,AB[i].vx));
      S_Collision=(float)(S*Math.cos(Angle));
      if(S_Collision<=0)
       continue;
      //충돌된 AB[i]와 BB[j*NUM_BOARD_COL+k]의 볼 타입이 다른경우 처리
      if(AB[i].BallType!=BB[j*NUM_BOARD_COL+k].BallType)
      {
       if(AB[i].Flag==ABF_FALLBALL)
       {
        Vecx*=S_Collision;
        Vecy*=S_Collision;
        AB[i].vx-=(2*Vecx);
        AB[i].vy-=(2*Vecy);
        return;
       }
       else if(AB[i].Flag==ABF_SHOOTBALL)
       {
        if(S_Collision>=MAX_BONDING_SPEED)
        {
         Vecx*=S_Collision;
         Vecy*=S_Collision;
         AB[i].vx-=(2*Vecx);
         AB[i].vy-=(2*Vecy);
         return;
        }
       }
      }
      AB[i].bExist=0;
      nAB--;
      int_pair ip=GetNearestBB(AB[i].x,AB[i].y,j,k);
      row=ip.row;
      col=ip.col;
      nNSB=MakeNSB(NSB,row,col,AB[i].BallType);
      //충돌속도가 충분히 크면서 같은색 근처공이 3개 이상이면 AB에 추가한다
      //또는 충돌속도가 만족되지않아도 같은색 근처공이 5개이상이면 AB에 추가한다
      if((S_Collision>=MAX_BONDING_SPEED_NSB && nNSB>=3) || nNSB>=10 ||
        (AB[i].Flag==ABF_FALLBALL && nNSB>=3))
      {
       //AB에 추가
       AddAB_NSB(NSB,nNSB,AB[i].BallType);
       AddAB_FB();
      }
      else
      {
       //BB에 AB[i]추가
       BB[row*NUM_BOARD_COL+col].bExist=true;
       BB[row*NUM_BOARD_COL+col].BallType=AB[i].BallType;
       BB[row*NUM_BOARD_COL+col].AniStage=AS_NONE;
       BB[row*NUM_BOARD_COL+col].AniIndex=14;
       BB[row*NUM_BOARD_COL+col].bProof=1;
       nBB++;
      }
      return;
     }
    }
   }
  }
  //}
 }
 //끝------------------공들사이의 충돌처리--------------------------//
 //AB가 존재하면 각각의 AB를 처리한다.
 //중력적용,움직이기,천정 벽 의 충돌처리,콘솔밑으로 떨어졌을때 안보이기
 //나이가 생명시간보다 커지면 없애기
 //AB끼리의 충돌처리
 //BB와의 충돌처리에서 연쇄 충돌효과 일으키기...
 void ProcessAB()
 {
  int i;
  for(i=0;i<nABTail;i++)
  {
   if(AB[i].bExist==0)
    continue;
   //AB[i]의 나이가 그공의 생명시간보다 커지면 서서히 없어진다.
   //{
   AB[i].Age+=frametime;
   if(AB[i].Age>=BPTable[AB[i].BallType].LifeTime)
   {
    //
    AB[i].AniIndex-=SPEED_ANIMATION*frametime;
    if(AB[i].AniIndex<0)
    {
     AB[i].bExist=0;
     nAB--;
     continue;
    }
   }
   //}
   //중력적용
   AB[i].vy-=BPTable[AB[i].BallType].g*frametime;
   //AB 움직이기
   AB[i].x+=AB[i].vx*frametime;
   AB[i].y+=AB[i].vy*frametime;
   //AB[i] 벽 충돌처리
   //{
   if((AB[i].x<=VIEW_LEFT+BALL_PIXELRADIUS)&&(AB[i].vx<0))
   {
    AB[i].vx=-AB[i].vx;
   }
   else if((AB[i].x>=(VIEW_LEFT+VIEW_WIDTH-BALL_PIXELRADIUS))&&(AB[i].vx>0))
   {
    AB[i].vx=-AB[i].vx;
   }
   //}
   //AB 끼리의 충돌처리
   //{
   AB_AB_Collision(i);
   //}
   //AB[i] 와 BB어레이 와의 충돌처리
   //{
   AB_BB_Collision(i);
   //}
   //AB[i]가 콘솔 밑으로 떨어졌을때...
   //{
   if((AB[i].y<=(VIEW_TOP-VIEW_HEIGHT-BALL_PIXELRADIUS))&&(AB[i].bVisible==1))
   {
    if(AB[i].Flag==ABF_FALLBALL)
    {
     CS.Score++;
    }
    else if(AB[i].Flag==ABF_SHOOTBALL)
    {
     snd_nsb.start();
     AddBB();
    }
    //강제로 제거하도록 나이값을 크게 설정
    AB[i].Age=1000;
    AB[i].bVisible=0;
   }
   //}
   //AB[i]와 천장과의 충돌처리...
   //{
   if((AB[i].y>=(VIEW_TOP-BALL_PIXELRADIUS))&&(AB[i].bVisible==1))
   {
    AB[i].y=(VIEW_TOP-BALL_PIXELRADIUS);
    AB[i].vy=-AB[i].vy;
   }
   //}
  }
 }
 void ProcessBB()
 {
  int i,j;
  //BB의 에니메이션 처리
  for(i=0;i<NUM_BOARD_ROW;i++)
  {
   for(j=0;j<NUM_BOARD_COL;j++)
   {
    if(BB[i*NUM_BOARD_COL+j].bExist==true)
    {
     if(BB[i*NUM_BOARD_COL+j].AniStage==AS_FLOAT)
     {
      BB[i*NUM_BOARD_COL+j].AniIndex+=SPEED_ANIMATION*frametime;
      if(BB[i*NUM_BOARD_COL+j].AniIndex>=14)
      {
       BB[i*NUM_BOARD_COL+j].AniIndex=14;
       BB[i*NUM_BOARD_COL+j].AniStage=AS_NONE;
      }
     }
    }
   }
  }
  for(i=0;i<NUM_BOARD_COL;i++)
  {
   if(BB[10*NUM_BOARD_COL+i].bExist==true)
   {
    snd_stageend.start();
    SystemClock.sleep(2500);
    LoadStage(1);
    break;
   }
  }
 }
 void ProcessCS()
 {
  //에니메이션 처리
  //{
  if(!CS.S.bShotEnable && CS.S.Cur_x!=CUR_BALL_X)
  {
   CS.S.Cur_x-=SPEED_MOVE_NEXT*frametime;
   if(CS.S.Cur_x<=CUR_BALL_X)
   {
    CS.S.Cur_x=CUR_BALL_X;
    CS.S.bShotEnable=true;
   }
  }
  //else
  {
   if(CS.S.Next_AniStage==AS_FLOAT)
   {
    CS.S.Next_AniIndex+=SPEED_ANIMATION*frametime;
    if(CS.S.Next_AniIndex>=14)
    {
     CS.S.Next_AniIndex=14;
     CS.S.Next_AniStage=AS_NONE;
    }
   }
   else if(CS.S.Next_AniStage==AS_SINK)
   {
    CS.S.Next_AniIndex-=SPEED_ANIMATION*frametime;
    if(CS.S.Next_AniIndex<=0)
    {
     CS.S.Next_AniIndex=0;
     CS.S.Next_AniStage=AS_NONE;
    }
   }
  }
  //}
  if((CS.S.bShotEnable==true)&&(CS.ShotTime<=0))
  {
   ShootSB((float)Math.random()*1600.0f-800,800.0f);
  }
 }
 void AddBB()
 {
  int i;
  int row,col;
  int add_row,add_col;
  int EvenOdd;
  while(true)
  {
   add_row=(int)((Math.random()*100000)%NUM_BOARD_ROW);
   EvenOdd=add_row%2;
   add_col = (int)((EvenOdd==0) ? ((Math.random()*100000)%
    NUM_BOARD_COL) : ((Math.random()*100000)%NUM_BOARD_COL-1));
   if(BB[add_row*NUM_BOARD_COL+add_col].bExist==false)
   {
    for(i=0;i<6;i++)
    {
     row=add_row+CircleTable[EvenOdd*6+i].y;
     col=add_col+CircleTable[EvenOdd*6+i].x;
    
     int EvenOdd_me=row%2;
     if(EvenOdd_me==1 && (col>=NUM_BOARD_COL-1)) continue;
     if((row==-1)||(row==NUM_BOARD_ROW)||(col==-1)||(col==NUM_BOARD_COL))
      continue;
     if(BB[row*NUM_BOARD_COL+col].bExist==true)
      break;
    }
    if((add_row==0) || (i!=6))
    {
     BB[add_row*NUM_BOARD_COL+add_col].bExist=true;
     BB[add_row*NUM_BOARD_COL+add_col].AniIndex=0;
     BB[add_row*NUM_BOARD_COL+add_col].AniStage=AS_FLOAT;
     BB[add_row*NUM_BOARD_COL+add_col].BallType=RandomBallType();
     nBB++;
     return;
    }
   }
  }
 }
 void AddAB_FB()
 {
  int i,j,k;
  int s,t;
  int row,col;
  int EvenOdd;
  int ABIndex=0;
  //천정에서 떨어진 공들 AB에 추가
  //{
  //bProof 플래그 초기화
  for(i=0;i<NUM_BOARD_COL;i++)
   if(BB[0*NUM_BOARD_COL+i].bExist==true)
    BB[0*NUM_BOARD_COL+i].bProof=1;
  for(i=1;i<NUM_BOARD_ROW;i++)
  {
   for(j=0;j<NUM_BOARD_COL;j++)
   {
    if(BB[i*NUM_BOARD_COL+j].bExist==true)
    {
     BB[i*NUM_BOARD_COL+j].bProof=0;
    }
   }
  }
  //천정에서 두번째 줄부터 왼쪽 - 아래 로(한줄당 두번) 스캔하면서 천정과 닿았는지 검사 -- bProof 이용
  //다시 아래에서 위로 검사... -- 이렇게 6번해야 완벽하게 결과가 나옴...
  //t : 스캔 줄방향  i : 현재 줄  j : 스캔 열방향  k : 현재 열 s : CircleTable 에서 1-4까지
  int scan_col,scan_row;
  for(t=0;t<6;t++)
  {
   for(i=1;i<NUM_BOARD_ROW;i++)
   {
    scan_row = ((t%2)==0) ? i : (NUM_BOARD_ROW-1-i);
    EvenOdd=scan_row%2;
    for(j=0;j<2;j++)
    {
     for(k=0;k<NUM_BOARD_COL;k++)
     {
      scan_col = (j==0) ? k : (NUM_BOARD_COL-1-k);
      if(BB[scan_row*NUM_BOARD_COL+scan_col].bExist==true)
      {
       for(s=0;s<6;s++)
       {
        row=scan_row+CircleTable[EvenOdd*6+s].y;
        col=scan_col+CircleTable[EvenOdd*6+s].x;
       
        int EvenOdd_me=row%2;
        if(EvenOdd_me==1 && (col>=NUM_BOARD_COL-1)) continue;
        if((col<0)||(col>=NUM_BOARD_COL))
         continue;
        if((row<0)||(row>=NUM_BOARD_ROW))
         continue;
        if((BB[row*NUM_BOARD_COL+col].bExist==true)&&
         (BB[row*NUM_BOARD_COL+col].bProof==1))
        {
         BB[scan_row*NUM_BOARD_COL+scan_col].bProof=1;
         break;
        }
       }
      }
     }
    }
   }
  }
  //nABTail최소화
  if(nABTail!=0)
   while((nABTail!=0) && (AB[nABTail-1].bExist==0)){nABTail--;}
  while(AB[ABIndex].bExist==1){ABIndex++;}
  for(i=1;i<NUM_BOARD_ROW;i++)
  {
   for(j=0;j<NUM_BOARD_COL;j++)
   {
    if((BB[i*NUM_BOARD_COL+j].bExist==true)&&(BB[i*NUM_BOARD_COL+j].bProof==0))
    {
     AB[ABIndex].AniIndex=14;
     AB[ABIndex].AniStage=AS_NONE;
     AB[ABIndex].BallType=BB[i*NUM_BOARD_COL+j].BallType;
     AB[ABIndex].Flag=ABF_FALLBALL;
     AB[ABIndex].x=XYTable[i*NUM_BOARD_COL+j].x;
     AB[ABIndex].y=XYTable[i*NUM_BOARD_COL+j].y;
     AB[ABIndex].vx=500*((float)((Math.random()*100000)%100)/200);
     AB[ABIndex].vy=500*((float)((Math.random()*100000)%100)/200);
     AB[ABIndex].Age=0;
     AB[ABIndex].bVisible=1;
     AB[ABIndex].bExist=1;
     //BB어레이에서 삭제 -- AB로 이동
     BB[i*NUM_BOARD_COL+j].bExist=false;
     while(AB[ABIndex].bExist==1){ABIndex++;}
     nAB++;
     nBB--;
    }
   }
  }
  //}
  if(ABIndex>=nABTail){nABTail=(ABIndex+1);}
 }
 void AddAB_NSB(NearSameBall[] pNSB,int nBall,int BallType)
 {
  int i;
  int row,col;
  int ABIndex=0;
  //nABTail최소화
  if(nABTail!=0)
   while((nABTail!=0) && (AB[nABTail-1].bExist==0)){nABTail--;}
  //NSB를 AB에 추가
  //{
  nAB+=nBall;
  while(AB[ABIndex].bExist==1){ABIndex++;}
  for(i=0;i<nBall;i++)
  {
   row=((pNSB[i])).row;
   col=((pNSB[i])).col;
   AB[ABIndex].AniIndex=14;
   AB[ABIndex].AniStage=AS_NONE;
   AB[ABIndex].BallType=(byte)BallType;
   AB[ABIndex].Flag=ABF_FALLBALL;
   AB[ABIndex].x=XYTable[row*NUM_BOARD_COL+col].x;
   AB[ABIndex].y=XYTable[row*NUM_BOARD_COL+col].y;
   AB[ABIndex].vx=700*((float)((Math.random()*100000)%100)/200);
   AB[ABIndex].vy=700*((float)((Math.random()*100000)%100)/200);
   AB[ABIndex].Age=0;
   AB[ABIndex].bVisible=1;
   AB[ABIndex].bExist=1;
   //BB어레이에서 삭제 -- AB로 이동
   BB[row*NUM_BOARD_COL+col].bExist=false;
   while(AB[ABIndex].bExist==1){ABIndex++;}
  }
  if(ABIndex>=nABTail){nABTail=(ABIndex+1);}
  nBB-=(nBall-1);//1은 슛볼 또는 AB중 BB에 붙은공을 의미
  //}
 }
 boolean AddAB_SB(float v_x,float v_y)
 {
  double spd=Math.sqrt(v_x*v_x+v_y*v_y);
  if(spd==0.0) return false;
  int ABIndex=0;
  //nABTail최소화
  if(nABTail!=0)
   while((nABTail!=0) && (AB[nABTail-1].bExist==0)){nABTail--;}
  while(AB[ABIndex].bExist==1){ABIndex++;}
  AB[ABIndex].bExist=1;
  AB[ABIndex].AniIndex=CS.S.Cur_AniIndex;
  AB[ABIndex].AniStage=AS_NONE;
  AB[ABIndex].BallType=CS.S.Cur_BallType;
  AB[ABIndex].Flag=ABF_SHOOTBALL;
  AB[ABIndex].bVisible=1;
  AB[ABIndex].Age=0;
  float maxspeed=BPTable[AB[ABIndex].BallType].max_speed;
  double tgtspd=Math.min(maxspeed,spd);
  double mult=tgtspd/spd;
  float vx=(float)((double)v_x*mult);
  float vy=(float)((double)v_y*mult);
  AB[ABIndex].vx=(float)vx;
  AB[ABIndex].vy=(float)vy;
  AB[ABIndex].x=CS.S.Cur_x;
  AB[ABIndex].y=CS.S.Cur_y;
  nAB++;
  if(ABIndex>=nABTail){nABTail=(ABIndex+1);}
 
  return true;
 }
 void LoadGame()
 {
  int i;
  Game.nStage=30;
  Game.pStageFileName=new String[Game.nStage]; 
  for(i=0;i<Game.nStage;i++)
  {
   Game.pStageFileName[i]=new String("");
  }
 
  //Loads Fonts...
  //{
//  pDDSWhiteFont=DDLoadBitmap(pDD,"font_fixedsys_white.bmp",0,0,1);
//  DDSetColorKey(pDDSWhiteFont,RGB(0,0,0));
//
//  pDDSRedFont=DDLoadBitmap(pDD,"font_fixedsys_red.bmp",0,0,1);
//  DDSetColorKey(pDDSRedFont,RGB(255,255,255));
//
//  pDDSBlueFont=DDLoadBitmap(pDD,"font_fixedsys_blue.bmp",0,0,0);
//  DDSetColorKey(pDDSBlueFont,RGB(255,255,255));
  //}
  Option.bSound=1;
  Option.Level=0;
 
  LoadStage(1);
 }
 int LoadStage(int stage)
 {
  int i,j;
  nCurStage=stage;
  CurStage.nBall=(byte)stage;
  nBB=0;
  //Loads Total Ball Data to BB - BoardBall Array
  //{
  for(i=0;i<NUM_BOARD_ROW;i++)
  {
   for(j=0;j<NUM_BOARD_COL;j++)
   {
    BB[i*NUM_BOARD_COL+j].bExist=false;
    BB[i*NUM_BOARD_COL+j].AniIndex=14;
    BB[i*NUM_BOARD_COL+j].AniStage=1;
   }
  }
  for(i=0;i<CurStage.nBall;i++)
  {
   AddBB();
  }
  //}
  for(i=0;i<NUM_MAX_BALL;i++)
  {
   AB[i].bExist=0;
  }
  CS.Score=0;
  CS.Time=0;
  CS.S.bShotEnable=false;
  CS.ShotTime=10-(nCurStage/(float)Game.nStage)*9;
  CS.S.Cur_AniIndex=14;
  CS.S.Cur_BallType=RandomBallType();
  CS.S.Cur_x=NEXT_BALL_X;
  CS.S.Cur_y=CUR_BALL_Y;
  CS.S.Next_AniIndex=14;
  CS.S.Next_BallType=RandomBallType();
  nAB=0;
  nABTail=0;
 
  snd_stagestart.start();
  return 1;
 }
 void ReleaseStage(int stage)
 {
  int i,j;
  //BB초기화
  for(i=0;i<NUM_BOARD_ROW;i++)
  {
   for(j=0;j<NUM_BOARD_COL;j++)
   {
    BB[i*NUM_BOARD_COL+j].bExist=false;
    BB[i*NUM_BOARD_COL+j].AniIndex=14;
    BB[i*NUM_BOARD_COL+j].AniStage=1;
   }
  }
 }

 void DrawBB(GL10 gl)
 {
  int i,j;
  for(i=0;i<NUM_BOARD_ROW-1;i++)
  {
   for(j=0;j<NUM_BOARD_COL;j++)
   {
    if(BB[i*NUM_BOARD_COL+j].bExist==true)
    {
     draw_ball(gl,(int)XYTable[i*NUM_BOARD_COL+j].x,(int)XYTable[i*NUM_BOARD_COL+j].y,
      (int)BB[i*NUM_BOARD_COL+j].BallType,(int)BB[i*NUM_BOARD_COL+j].AniIndex);
    }
   }
  }
  for(i=0;i<NUM_BOARD_COL;i++)
  {
   if(BB[(NUM_BOARD_ROW-1)*NUM_BOARD_COL+i].bExist==true)
   {   
    draw_ball(gl,(int)XYTable[(NUM_BOARD_ROW-1)*NUM_BOARD_COL+i].x,
    (int)XYTable[(NUM_BOARD_ROW-1)*NUM_BOARD_COL+i].y,
    (int)BB[(NUM_BOARD_ROW-1)*NUM_BOARD_COL+i].BallType,
    (int)BB[(NUM_BOARD_ROW-1)*NUM_BOARD_COL+i].AniIndex);
   }
  }
 }
 void DrawAB(GL10 gl)
 {
  int i;
  for(i=0;i<nABTail;i++)
  {
   if((AB[i].bVisible==1)&&(AB[i].bExist==1))
   {
    draw_ball(gl,(int)AB[i].x,(int)AB[i].y,
     (int)AB[i].BallType,(int)AB[i].AniIndex);
   }
  }
 }
 void DrawConsole(GL10 gl)
 {
  //next ball
  draw_ball(gl,(int)NEXT_BALL_X,(int)NEXT_BALL_Y,
   (int)CS.S.Next_BallType,(int)CS.S.Next_AniIndex);
  //current ball
  draw_ball(gl,(int)CS.S.Cur_x,(int)CS.S.Cur_y,
   (int)CS.S.Cur_BallType,(int)CS.S.Cur_AniIndex);
  //arrow
  //time shot
//  if(CS.S.bShotEnable==true)
//  {
//   ZeroMemory(szTemp,sizeof(szTemp));
//   sprintf(szTemp,"%d",CS.ShotTime);
//   if((CS.ShotTime)>=(int)(TIME_SHOT*0.3f))
//    DrawText(pDDSBuffer,pDDSBlueFont,szTemp,CUR_BALL_X-12,CUR_BALL_Y-8);
//   else
//    DrawText(pDDSBuffer,pDDSRedFont,szTemp,CUR_BALL_X-12,CUR_BALL_Y-8);
//  }
  //score
//  ZeroMemory(szTemp,sizeof(szTemp));
//  sprintf(szTemp,"Score:%4d",CS.Score);
//  DrawText(pDDSBuffer,pDDSWhiteFont,szTemp,SCORE_LEFT,SCORE_TOP);
// 
//  //stage number
//  ZeroMemory(szTemp,sizeof(szTemp));
//  sprintf(szTemp,"Time:%4d",CS.Time);
//  DrawText(pDDSBuffer,pDDSWhiteFont,szTemp,TIME_LEFT,TIME_TOP);
//
//  //limit line
//  pDDSBuffer->GetDC(&hdc);
//  hpe=CreatePen(PS_SOLID,1,RGB(255,255,255));
//  holdpe=(HPEN)SelectObject(hdc,hpe);
//  MoveToEx(hdc,VIEW_LEFT,VIEW_TOP+VIEW_HEIGHT-40,NULL);
//  LineTo(hdc,VIEW_LEFT+VIEW_WIDTH,VIEW_TOP+VIEW_HEIGHT-40);
//  SelectObject(hdc,holdpe);
//  DeleteObject(hpe);
//  pDDSBuffer->ReleaseDC(hdc);
 }
 long t2;
 void PlayMain(GL10 gl)
 {
  long t1=SystemClock.elapsedRealtime();
  frametime=(t1-t2)/1000.0f;
  if(frametime>0.1f)
   frametime=0.1f;
  t2=t1;
 
  //process
  ProcessCS();
  ProcessBB();
  ProcessAB();
 
  if((nBB<=0)&&(nAB<=0))
  {
   snd_stageclear.start();
   SystemClock.sleep(2500);
   ++nCurStage;
   if(nCurStage>=Game.nStage)
   {
    snd_stageclear.start();
    SystemClock.sleep(2500);
    snd_stageclear.start();
    SystemClock.sleep(2500);
    snd_stageclear.start();
    SystemClock.sleep(2500);
    nCurStage=1;
   }
   LoadStage(nCurStage);
  }
  gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);
  gl.glEnableClientState(GL10.GL_TEXTURE_COORD_ARRAY);
  gl.glActiveTexture(GL10.GL_TEXTURE0);
  gl.glBindTexture(GL10.GL_TEXTURE_2D,balltex);
  //gl.glEnable(GL10.GL_ALPHA_TEST);
  //gl.glAlphaFunc(GL10.GL_GREATER,0);
  gl.glEnable(GL10.GL_BLEND);
  gl.glBlendFunc(GL10.GL_ONE,GL10.GL_ONE);
 
  //draw
  DrawBB(gl);
  DrawAB(gl);
  DrawConsole(gl);
 }

 void DrawText(int font_tex,String sztext,int x,int y)
 {
//  char index;
//  RECT rect1,rect2;
//  int StringIndex=0,start_x=x;
//
//  while(*(sztext+StringIndex)!=0)
//  {
//   if(*(sztext+StringIndex)==CR)
//   {
//    y+=14;
//    StringIndex+=2;
//    x=start_x;
//    continue;
//   }
//
//   if(*(sztext+StringIndex)==' ')
//   {
//    x+=8;
//    StringIndex++;
//    continue;
//   }
//
//   rect1.left=x;
//   x+=8;
//   rect1.top=y;
//   rect1.right=(rect1.left)+8;
//   rect1.bottom=(rect1.top)+14;
//   index=*(sztext+StringIndex)-33;
//   rect2.top=0;
//   rect2.bottom=14;
//   rect2.left=index*8;
//   rect2.right=(rect2.left)+8;
//   pDDSDest->Blt(&rect1,pDDSfont,&rect2,DDBLT_KEYSRC,NULL);
//   StringIndex++;
  //}
 }
 private VelocityTracker vTracker=null;
 private boolean Ball_Dragging=false;
 private float pick_diff_x=0,pick_diff_y=0;
 public boolean onTouch(View v,MotionEvent event)
 {
  int action=event.getAction();
  switch(action)
  {
  case MotionEvent.ACTION_DOWN:
   {
    if(vTracker==null) vTracker=VelocityTracker.obtain();
    else vTracker.clear();
    RECT r=new RECT();
    r.left=(int)(VIEW_WIDTH/2-BALL_PIXELRADIUS*2.3f);
    r.bottom=(int)(VIEW_HEIGHT-BALL_PIXELDIAMETER-BALL_PIXELRADIUS*2.3f);
    r.right=(int)(r.left+BALL_PIXELDIAMETER*2.3f);
    r.top=(int)(r.bottom+BALL_PIXELDIAMETER*2.3f);
    if(CS.S.bShotEnable && event.getX()>r.left && event.getX()<r.right &&
     event.getY()>r.bottom && event.getY()<r.top)
    {
     pick_diff_x=event.getX()-CS.S.Cur_x;
     pick_diff_y=(VIEW_HEIGHT-event.getY())-CS.S.Cur_y;
     Ball_Dragging=true;
    }
    break;
   }
  case MotionEvent.ACTION_MOVE:
   {
    vTracker.addMovement(event);
    vTracker.computeCurrentVelocity(1000);
    RECT r=new RECT();
    r.left=(int)(VIEW_WIDTH/2-BALL_PIXELRADIUS*2.3f);
    r.bottom=(int)(VIEW_HEIGHT-BALL_PIXELDIAMETER-BALL_PIXELRADIUS*2.3f);
    r.right=(int)(r.left+BALL_PIXELDIAMETER*2.3f);
    r.top=(int)(r.bottom+BALL_PIXELDIAMETER*2.3f);
    if(Ball_Dragging)
    {
     CS.S.Cur_x=event.getX()-pick_diff_x;
     CS.S.Cur_y=(VIEW_HEIGHT-event.getY())-pick_diff_y;
    }
    if(Ball_Dragging && !(event.getX()>r.left && event.getX()<r.right &&
     event.getY()>r.bottom && event.getY()<r.top))
    {
     ShootSB(vTracker.getXVelocity()*1.6f,-vTracker.getYVelocity()*1.6f);
     Ball_Dragging=false;
    }
    break;
   }
  case MotionEvent.ACTION_UP:
  case MotionEvent.ACTION_CANCEL:
   {
    if(Ball_Dragging)
    {
     ShootSB(vTracker.getXVelocity()*1.6f,-vTracker.getYVelocity()*1.6f);
     Ball_Dragging=false;
    }
    vTracker.recycle();
    vTracker=null;
    break;
   }
  }
  return true;
 }
}


package b.pb;
import android.app.Activity;
import android.opengl.GLSurfaceView;
import android.os.Bundle;
import android.util.Log;
import android.view.Window;
public class DefaultActivity extends Activity
{
 public GLSurfaceView glview;
 public void onCreate(Bundle savedInstanceState)
 {
  try
  {
   super.onCreate(savedInstanceState);
   glview=new GLSurfaceView(this);
   glview.setEGLConfigChooser(false);
   glview.setRenderer(new AndroPB(this));
   glview.setRenderMode(GLSurfaceView.RENDERMODE_CONTINUOUSLY);
   getWindow().requestFeature(Window.FEATURE_NO_TITLE);
   setContentView(glview);
  }
  catch(Exception ex)
  {
   ex.printStackTrace();
   Log.v("",ex.toString());
  }
 }

 protected void onResume()
 {
  super.onResume();
  glview.onResume();
 }

 protected void onPause()
 {
  super.onPause();
  glview.onPause();
 }
}