edo1z blog

プログラミングなどに関するブログです

Android 横スクロールゲームをつくってみる


地面とボールをつくりました。ボールは既にタッチするとジャンプするようになっています。このページで作成したタッチするとジャンプし、ジャンプ中にタッチすると2段ジャンプする仕様です。ちなみに、タッチをし続けるとジャンプ力が増すようになっています。これからこれをベースに横スクロールゲームを作ってみます。

雲を表示する



とりあえず適当に雲を作りました。現時点のコードを記載します。

//HellowWorld.java

package net.npaka.helloworld;

import android.app.Activity;
import android.os.Bundle;
import android.view.Window;

public class HelloWorld extends Activity {
    @Override
    public void onCreate(Bundle bundle) {
        super.onCreate(bundle);
        requestWindowFeature(Window.FEATURE_NO_TITLE);
        setContentView(new HellowView(this));
    }
}


//HellowView.java

package net.npaka.helloworld;

import android.content.Context;
import android.content.res.Resources;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Rect;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.MotionEvent;

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

 private int ww = 762;
 private int wh = 480;
 private Thread thread;
 private SurfaceHolder holder;
 private Paint paint = new Paint();
 private Ball ball = new Ball();
 private Cloud cloud = new Cloud();
 private Bitmap cloud_img;

 public HellowView(Context context){
  super(context);

  holder = getHolder();
  holder.addCallback(this);
  holder.setFixedSize(ww,wh);

  Resources r = getResources();
  cloud_img = BitmapFactory.decodeResource(r, R.drawable.cloud);

  paint.setAntiAlias(true);
  paint.setStyle(Paint.Style.FILL);
  paint.setColor(Color.argb(255,154,54,54));
 }

 public void surfaceCreated(SurfaceHolder holder){
  thread = new Thread(this);
  thread.start();
 }

 public void surfaceChanged(SurfaceHolder holder,
   int format,int w,int h){
 }

 public void surfaceDestroyed(SurfaceHolder holder){
  thread = null;
 }

 public void run(){
  Canvas canvas;
  while(thread!=null){
   canvas = holder.lockCanvas();
   canvas.drawColor(Color.BLACK);
   cloud.view(canvas);
   canvas.drawRect(new Rect(0,480-50,762,480),paint);
   ball.view(canvas);
   holder.unlockCanvasAndPost(canvas);

   try{
    Thread.sleep(10);
   }catch(Exception e){
   }
  }
 }

 @Override
 public boolean onTouchEvent(MotionEvent event){
  int action = event.getAction();
  if(action == 0){
   if(ball.jumpFlag == true){
    ball.jumpFlag2 = true;
   }else{
    ball.jumpFlag = true;
    ball.touchTime = 1;
   }
  }else if(action == 1){
   ball.touchTime = 0;
  }
  return true;
 }

 class Cloud{
  int x1 = 50;
  int y1 = 50;
  int x2 = x1+350;
  int y2 = y1+100;
  int x3 = x2+300;
  int y3 = y2-50;

  public void view(Canvas canvas){
   canvas.drawBitmap(cloud_img, x1,y1, null);
   canvas.drawBitmap(cloud_img, x2,y2, null);
   canvas.drawBitmap(cloud_img, x3,y3, null);
  }
 }

 class Ball{
  int r = 20;
  int x = r*2+50;
  float y_base = wh-r-50;
  float y = y_base;
  float vy = -8;
  float g = 0.2F;
  boolean jumpFlag = false;
  boolean jumpFlag2 = false;
  boolean jump2finFlag = false;
  int touchTime = 0;
  Paint paint = new Paint();

  public Ball(){
   paint.setAntiAlias(true);
   paint.setStyle(Paint.Style.FILL);
   paint.setColor(Color.argb(255,255,255,255));
  }

  public void view(Canvas canvas){
   canvas.drawCircle(x, y, r, paint);
   if(jumpFlag){
    paint.setColor(Color.argb(255,0,255,255));
    if(jumpFlag2){
     paint.setColor(Color.argb(255,255,255,0));
     if(!jump2finFlag){
      vy = -6;
      jump2finFlag = true;
     }
    }else if(touchTime > 0){
     paint.setColor(Color.argb(255,0,255,0));
     vy = -8;
     touchTime ++;
     if(touchTime >20){
      touchTime = 0;
     }
    }
    y += vy;
    vy += g;
    if(y>=y_base){
     y = y_base;
     vy = -8;
     jumpFlag = false;
     jumpFlag2 = false;
     jump2finFlag = false;
     paint.setColor(Color.argb(255,255,255,255));
    }
   }
  }
 }
}


今はこの2つのファイルで構成されています。今後は、HellowViewクラスを改良していきます。私は横スクロールについて全く一般論を知りませんので、まったくもって非効率なことをこれからする可能性があります。ご指摘いただければ幸いです。

雲を動かしてボールが動いているように見せる


修正版HellowView.javaは下記です。

package net.npaka.helloworld;

import java.util.ArrayList;

import android.content.Context;
import android.content.res.Resources;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.PointF;
import android.graphics.Rect;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.MotionEvent;

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

 private int ww = 762;
 private int wh = 480;
 private Thread thread;
 private SurfaceHolder holder;
 private Paint paint = new Paint();
 private Ball ball = new Ball();
 private Cloud cloud  =new Cloud();
 private Bitmap cloud_img;

 public HellowView(Context context){
  super(context);

  holder = getHolder();
  holder.addCallback(this);
  holder.setFixedSize(ww,wh);

  Resources r = getResources();
  cloud_img = BitmapFactory.decodeResource(r, R.drawable.cloud);

  paint.setAntiAlias(true);
  paint.setStyle(Paint.Style.FILL);
  paint.setColor(Color.argb(255,154,54,54));
 }

 public void surfaceCreated(SurfaceHolder holder){
  thread = new Thread(this);
  thread.start();
 }

 public void surfaceChanged(SurfaceHolder holder,
   int format,int w,int h){
 }

 public void surfaceDestroyed(SurfaceHolder holder){
  thread = null;
 }

 public void run(){
  Canvas canvas;
  while(thread!=null){
   canvas = holder.lockCanvas();
   canvas.drawColor(Color.BLACK);
   cloud.view(canvas);
   canvas.drawRect(new Rect(0,480-50,762,480),paint);
   ball.view(canvas);
   holder.unlockCanvasAndPost(canvas);

   try{
    Thread.sleep(10);
   }catch(Exception e){
   }
  }
 }

 @Override
 public boolean onTouchEvent(MotionEvent event){
  int action = event.getAction();
  if(action == 0){
   if(ball.jumpFlag == true){
    ball.jumpFlag2 = true;
   }else{
    ball.jumpFlag = true;
    ball.touchTime = 1;
   }
  }else if(action == 1){
   ball.touchTime = 0;
  }
  return true;
 }

 class Cloud{
  ArrayList<PointF> cloudXY = new ArrayList<PointF>();

  public Cloud(){
   float X = 50;
   float Y = 50;
   for(int i=0;i<5;i++){
    cloudXY.add(new PointF(X,Y));
    X += 300;
    Y = nextY(Y);
   }
  }

  public void view(Canvas canvas){
   for(int i=0;i<cloudXY.size();i++){
    canvas.drawBitmap(cloud_img, cloudXY.get(i).x,cloudXY.get(i).y, null);
    cloudXY.get(i).x -= ball.vx;
    if(cloudXY.get(i).x<-219){
     cloudXY.add(new PointF(cloudXY.get(cloudXY.size()-1).x+300,
       nextY(cloudXY.get(cloudXY.size()-1).y)));
     cloudXY.remove(i);
     i--;
    }
   }
  }

  private float nextY(float Y){
   if(Y==50) return 150;
   if(Y==150) return 100;
   if(Y==100) return 50;
   return 0;
  }
 }

 class Ball{
  float r = 20;
  float x = r*2+50;
  float y_base = wh-r-50;
  float y = y_base;
  float vx = 0.05f;
  float ax = 0.01f;
  float vy = -8;
  float g = 0.2F;
  boolean jumpFlag = false;
  boolean jumpFlag2 = false;
  boolean jump2finFlag = false;
  int touchTime = 0;
  Paint paint = new Paint();

  public Ball(){
   paint.setAntiAlias(true);
   paint.setStyle(Paint.Style.FILL);
   paint.setColor(Color.argb(255,255,255,255));
  }

  public void view(Canvas canvas){
   canvas.drawCircle(x, y, r, paint);
   if(jumpFlag){
    paint.setColor(Color.argb(255,0,255,255));
    if(jumpFlag2){
     paint.setColor(Color.argb(255,255,255,0));
     if(!jump2finFlag){
      vy = -6;
      jump2finFlag = true;
     }
    }else if(touchTime > 0){
     paint.setColor(Color.argb(255,0,255,0));
     vy = -8;
     touchTime ++;
     if(touchTime >20){
      touchTime = 0;
     }
    }
    y += vy;
    vy += g;
    if(y>=y_base){
     y = y_base;
     vy = -8;
     jumpFlag = false;
     jumpFlag2 = false;
     jump2finFlag = false;
     paint.setColor(Color.argb(255,255,255,255));
    }
   }
   if(vx < 50){
    vx += ax;
   }else{
    vx = 50;
   }
  }
 }
}


スクリーンキャプチャは下記です。写真だと見た目は変わりません。


雲は高速で流れていきますが、ボールが動いているようには見えません。雲は現実世界でも勝ってに動くので、木とか動かないものを動かす必要がありそうです。

サボテンも動かして更にボールが動いて見えるようにする


サボテンを植えることにしました。
修正版コードはこれです。

package net.npaka.helloworld;

import java.util.ArrayList;
import java.util.Random;

import android.content.Context;
import android.content.res.Resources;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.PointF;
import android.graphics.Rect;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.MotionEvent;

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

 private int ww = 762;
 private int wh = 480;
 private Thread thread;
 private SurfaceHolder holder;
 private Paint paint = new Paint();
 private Ball ball = new Ball();
 private Cloud cloud  = new Cloud();
 private Saboten saboten = new Saboten();
 private Bitmap cloud_img;
 private Bitmap sabo_img;

 public HellowView(Context context){
  super(context);

  holder = getHolder();
  holder.addCallback(this);
  holder.setFixedSize(ww,wh);

  Resources r = getResources();
  cloud_img = BitmapFactory.decodeResource(r, R.drawable.cloud);
  sabo_img = BitmapFactory.decodeResource(r, R.drawable.saboten);

  paint.setAntiAlias(true);
  paint.setStyle(Paint.Style.FILL);
  paint.setColor(Color.argb(255,154,54,54));
 }

 public void surfaceCreated(SurfaceHolder holder){
  thread = new Thread(this);
  thread.start();
 }

 public void surfaceChanged(SurfaceHolder holder,
   int format,int w,int h){
 }

 public void surfaceDestroyed(SurfaceHolder holder){
  thread = null;
 }

 public void run(){
  Canvas canvas;
  while(thread!=null){
   canvas = holder.lockCanvas();
   canvas.drawColor(Color.argb(255,0,150,200));
   cloud.view(canvas);
   saboten.view(canvas);
   canvas.drawRect(new Rect(0,480-50,762,480),paint);
   ball.view(canvas);
   holder.unlockCanvasAndPost(canvas);

   try{
    Thread.sleep(10);
   }catch(Exception e){
   }
  }
 }

 @Override
 public boolean onTouchEvent(MotionEvent event){
  int action = event.getAction();
  if(action == 0){
   if(ball.jumpFlag == true){
    ball.jumpFlag2 = true;
   }else{
    ball.jumpFlag = true;
    ball.touchTime = 1;
   }
  }else if(action == 1){
   ball.touchTime = 0;
  }
  return true;
 }

 class Cloud{
  ArrayList<PointF> cloudXY = new ArrayList<PointF>();

  public Cloud(){
   float X = 50;
   float Y = 50;
   for(int i=0;i<5;i++){
    cloudXY.add(new PointF(X,Y));
    X += 300;
    Y = nextY(Y);
   }
  }

  public void view(Canvas canvas){
   for(int i=0;i<cloudXY.size();i++){
    canvas.drawBitmap(cloud_img, cloudXY.get(i).x,cloudXY.get(i).y, null);
    cloudXY.get(i).x -= ball.vx;
    if(cloudXY.get(i).x<-219){
     cloudXY.add(new PointF(cloudXY.get(cloudXY.size()-1).x+300,
       nextY(cloudXY.get(cloudXY.size()-1).y)));
     cloudXY.remove(i);
     i--;
    }
   }
  }

  private float nextY(float Y){
   if(Y==50) return 150;
   if(Y==150) return 100;
   if(Y==100) return 50;
   return 0;
  }
 }

 class Saboten{
  ArrayList<PointF> saboXY = new ArrayList<PointF>();
  float Y = wh-50-213;
  Random rnd = new Random();

  public Saboten(){
   float X = 400;
   for(int i=0;i<4;i++){
    saboXY.add(new PointF(X,Y));
    X += (200+rnd.nextInt(300));
   }
  }

  public void view(Canvas canvas){
   for(int i=0;i<saboXY.size();i++){
    canvas.drawBitmap(sabo_img, saboXY.get(i).x,saboXY.get(i).y, null);
    saboXY.get(i).x -= ball.vx;
    if(saboXY.get(i).x<-194){
     saboXY.add(new PointF(saboXY.get(saboXY.size()-1).x+200+rnd.nextInt(300),Y));
     saboXY.remove(i);
     i--;
    }
   }
  }
 }

 class Ball{
  float r = 20;
  float x = r*2+50;
  float y_base = wh-r-50;
  float y = y_base;
  float vx = 0.05f;
  float ax = 0.01f;
  float vy = -8;
  float g = 0.2F;
  boolean jumpFlag = false;
  boolean jumpFlag2 = false;
  boolean jump2finFlag = false;
  int touchTime = 0;
  Paint paint = new Paint();

  public Ball(){
   paint.setAntiAlias(true);
   paint.setStyle(Paint.Style.FILL);
   paint.setColor(Color.argb(255,255,255,255));
  }

  public void view(Canvas canvas){
   canvas.drawCircle(x, y, r, paint);
   if(jumpFlag){
    paint.setColor(Color.argb(255,0,255,255));
    if(jumpFlag2){
     paint.setColor(Color.argb(255,255,255,0));
     if(!jump2finFlag){
      vy = -6;
      jump2finFlag = true;
     }
    }else if(touchTime > 0){
     paint.setColor(Color.argb(255,0,255,0));
     vy = -8;
     touchTime ++;
     if(touchTime >20){
      touchTime = 0;
     }
    }
    y += vy;
    vy += g;
    if(y>=y_base){
     y = y_base;
     vy = -8;
     jumpFlag = false;
     jumpFlag2 = false;
     jump2finFlag = false;
     paint.setColor(Color.argb(255,255,255,255));
    }
   }
   if(vx < 10){
    vx += ax;
   }else{
    vx = 10;
   }
  }
 }
}


スクリーンキャプチャはこれです。


今度はボールが動いて見えます。ただ高速に動かすと見てるだけで酔って気持ち悪くなったので、最高速度を落としました。サボテンを等間隔に配置すると全く動いているように見えないので、ランダム配置にしました。

ボールを車の絵に変える

今回は車のゲームしてみることにしました。


車が走るようになりました。次に障害物をランダムに出現させます。

障害物をランダムに出現させる

まずは、障害物を1つずつサボテンと同じようにランダムに出現させてみます。下記の修正版コードにより、左のような岩が一つずつ出現しました。

修正版コードです。

package net.npaka.helloworld;

import java.util.ArrayList;
import java.util.Random;

import android.content.Context;
import android.content.res.Resources;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.PointF;
import android.graphics.Rect;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.MotionEvent;

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

 private int ww = 762;
 private int wh = 480;
 private Thread thread;
 private SurfaceHolder holder;
 private Paint paint = new Paint();
 private Car car = new Car();
 private Cloud cloud  = new Cloud();
 private Saboten saboten = new Saboten();
 private Rock rock = new Rock();
 private Bitmap cloud_img;
 private Bitmap sabo_img;
 private Bitmap car_img;
 private Bitmap rock_img;

 public HellowView(Context context){
  super(context);

  holder = getHolder();
  holder.addCallback(this);
  holder.setFixedSize(ww,wh);

  Resources r = getResources();
  cloud_img = BitmapFactory.decodeResource(r, R.drawable.cloud);
  sabo_img = BitmapFactory.decodeResource(r, R.drawable.saboten);
  car_img = BitmapFactory.decodeResource(r, R.drawable.car);
  rock_img = BitmapFactory.decodeResource(r, R.drawable.rock);

  paint.setAntiAlias(true);
  paint.setStyle(Paint.Style.FILL);
  paint.setColor(Color.argb(255,154,54,54));
 }

 public void surfaceCreated(SurfaceHolder holder){
  thread = new Thread(this);
  thread.start();
 }

 public void surfaceChanged(SurfaceHolder holder,
   int format,int w,int h){
 }

 public void surfaceDestroyed(SurfaceHolder holder){
  thread = null;
 }

 public void run(){
  Canvas canvas;
  while(thread!=null){
   canvas = holder.lockCanvas();
   canvas.drawColor(Color.argb(255,0,150,200));
   cloud.view(canvas);
   saboten.view(canvas);
   canvas.drawRect(new Rect(0,480-50,762,480),paint);
   rock.view(canvas);
   car.view(canvas);
   holder.unlockCanvasAndPost(canvas);

   try{
    Thread.sleep(10);
   }catch(Exception e){
   }
  }
 }

 @Override
 public boolean onTouchEvent(MotionEvent event){
  int action = event.getAction();
  if(action == 0){
   if(car.jumpFlag == true){
    car.jumpFlag2 = true;
   }else{
    car.jumpFlag = true;
    car.touchTime = 1;
   }
  }else if(action == 1){
   car.touchTime = 0;
  }
  return true;
 }

 class Cloud{
  ArrayList<PointF> cloudXY = new ArrayList<PointF>();

  public Cloud(){
   float X = 50;
   float Y = 50;
   for(int i=0;i<5;i++){
    cloudXY.add(new PointF(X,Y));
    X += 300;
    Y = nextY(Y);
   }
  }

  public void view(Canvas canvas){
   for(int i=0;i<cloudXY.size();i++){
    canvas.drawBitmap(cloud_img, cloudXY.get(i).x,cloudXY.get(i).y, null);
    cloudXY.get(i).x -= car.vx;
    if(cloudXY.get(i).x<-219){
     cloudXY.add(new PointF(cloudXY.get(cloudXY.size()-1).x+300,
       nextY(cloudXY.get(cloudXY.size()-1).y)));
     cloudXY.remove(i);
     i--;
    }
   }
  }

  private float nextY(float Y){
   if(Y==50) return 150;
   if(Y==150) return 100;
   if(Y==100) return 50;
   return 0;
  }
 }

 class Saboten{
  ArrayList<PointF> saboXY = new ArrayList<PointF>();
  float Y = wh-50-213;
  Random rnd = new Random();

  public Saboten(){
   float X = 400;
   for(int i=0;i<4;i++){
    saboXY.add(new PointF(X,Y));
    X += (200+rnd.nextInt(300));
   }
  }

  public void view(Canvas canvas){
   for(int i=0;i<saboXY.size();i++){
    canvas.drawBitmap(sabo_img, saboXY.get(i).x,saboXY.get(i).y, null);
    saboXY.get(i).x -= car.vx;
    if(saboXY.get(i).x<-194){
     saboXY.add(new PointF(saboXY.get(saboXY.size()-1).x+200+rnd.nextInt(300),Y));
     saboXY.remove(i);
     i--;
    }
   }
  }
 }

 class Rock{
  ArrayList<PointF> rockXY = new ArrayList<PointF>();
  float Y = wh-50-85;
  Random rnd = new Random();

  public Rock(){
   float X = 1000;
   for(int i=0;i<2;i++){
    rockXY.add(new PointF(X,Y));
    X += (500+rnd.nextInt(300));
   }
  }

  public void view(Canvas canvas){
   for(int i=0;i<rockXY.size();i++){
    canvas.drawBitmap(rock_img, rockXY.get(i).x,rockXY.get(i).y, null);
    rockXY.get(i).x -= car.vx;
    if(rockXY.get(i).x<-85){
     rockXY.add(new PointF(rockXY.get(rockXY.size()-1).x+500+rnd.nextInt(300),Y));
     rockXY.remove(i);
     i--;
    }
   }
  }

 }

 class Car{
  float x = 150;
  float y_base = wh-80-50;
  float y = y_base;
  float vx = 0.05f;
  float ax = 0.01f;
  float vy = -8;
  float g = 0.2F;
  boolean jumpFlag = false;
  boolean jumpFlag2 = false;
  boolean jump2finFlag = false;
  int touchTime = 0;

  public void view(Canvas canvas){
   canvas.drawBitmap(car_img, x,y, null);
   if(jumpFlag){
    if(jumpFlag2){
     if(!jump2finFlag){
      vy = -6;
      jump2finFlag = true;
     }
    }else if(touchTime > 0){
     vy = -8;
     touchTime ++;
     if(touchTime >20){
      touchTime = 0;
     }
    }
    y += vy;
    vy += g;
    if(y>=y_base){
     y = y_base;
     vy = -8;
     jumpFlag = false;
     jumpFlag2 = false;
     jump2finFlag = false;
    }
   }
   if(vx < 10){
    vx += ax;
   }else{
    vx = 10;
   }
  }
 }
}


衝突判定してみる

むお衝突判定しようとして気づきましたが、このコードじゃ全然だめだ。物理の世界を持ち込むんなら、共通的な物理の世界をコードの中で作っとかないと、たこ足コードになってしまうのう。修正するのがめんどくさいのでこれはここまでにしよう。今今のコードは下記です。衝突判定をして、衝突していた場合、車が岩の上の方にいた場合は岩にのっかり、そうじゃなければ車が跳ね返るようになっています。しかしこれは全然ダメダメコードです。

package net.npaka.helloworld;

import java.util.ArrayList;
import java.util.Random;

import android.content.Context;
import android.content.res.Resources;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.PointF;
import android.graphics.Rect;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.MotionEvent;

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

 private int ww = 762;
 private int wh = 480;
 private Thread thread;
 private SurfaceHolder holder;
 private Paint paint = new Paint();
 private Car car = new Car();
 private Cloud cloud  = new Cloud();
 private Saboten saboten = new Saboten();
 private Rock rock = new Rock();
 private Bitmap cloud_img;
 private Bitmap sabo_img;
 private Bitmap car_img;
 private Bitmap rock_img;

 public HellowView(Context context){
  super(context);

  holder = getHolder();
  holder.addCallback(this);
  holder.setFixedSize(ww,wh);

  Resources r = getResources();
  cloud_img = BitmapFactory.decodeResource(r, R.drawable.cloud);
  sabo_img = BitmapFactory.decodeResource(r, R.drawable.saboten);
  car_img = BitmapFactory.decodeResource(r, R.drawable.car);
  rock_img = BitmapFactory.decodeResource(r, R.drawable.rock);

  paint.setAntiAlias(true);
  paint.setStyle(Paint.Style.FILL);
  paint.setColor(Color.argb(255,154,54,54));
 }

 public void surfaceCreated(SurfaceHolder holder){
  thread = new Thread(this);
  thread.start();
 }

 public void surfaceChanged(SurfaceHolder holder,
   int format,int w,int h){
 }

 public void surfaceDestroyed(SurfaceHolder holder){
  thread = null;
 }

 public void run(){
  Canvas canvas;
  while(thread!=null){
   canvas = holder.lockCanvas();
   canvas.drawColor(Color.argb(255,0,150,200));
   cloud.view(canvas);
   saboten.view(canvas);
   canvas.drawRect(new Rect(0,480-50,762,480),paint);
   rock.view(canvas);
   car.view(canvas);
   holder.unlockCanvasAndPost(canvas);

   try{
    Thread.sleep(10);
   }catch(Exception e){
   }
  }
 }

 @Override
 public boolean onTouchEvent(MotionEvent event){
  int action = event.getAction();
  if(action == 0){
   if(car.jumpFlag == true){
    car.jumpFlag2 = true;
   }else{
    car.jumpFlag = true;
    car.touchTime = 1;
   }
  }else if(action == 1){
   car.touchTime = 0;
  }
  return true;
 }

 class Cloud{
  ArrayList<PointF> cloudXY = new ArrayList<PointF>();

  public Cloud(){
   float X = 50;
   float Y = 50;
   for(int i=0;i<5;i++){
    cloudXY.add(new PointF(X,Y));
    X += 300;
    Y = nextY(Y);
   }
  }

  public void view(Canvas canvas){
   for(int i=0;i<cloudXY.size();i++){
    canvas.drawBitmap(cloud_img, cloudXY.get(i).x,cloudXY.get(i).y, null);
    cloudXY.get(i).x -= car.vx;
    if(cloudXY.get(i).x<-219){
     cloudXY.add(new PointF(cloudXY.get(cloudXY.size()-1).x+300,
       nextY(cloudXY.get(cloudXY.size()-1).y)));
     cloudXY.remove(i);
     i--;
    }
   }
  }

  private float nextY(float Y){
   if(Y==50) return 150;
   if(Y==150) return 100;
   if(Y==100) return 50;
   return 0;
  }
 }

 class Saboten{
  ArrayList<PointF> saboXY = new ArrayList<PointF>();
  float Y = wh-50-213;
  Random rnd = new Random();

  public Saboten(){
   float X = 400;
   for(int i=0;i<4;i++){
    saboXY.add(new PointF(X,Y));
    X += (200+rnd.nextInt(300));
   }
  }

  public void view(Canvas canvas){
   for(int i=0;i<saboXY.size();i++){
    canvas.drawBitmap(sabo_img, saboXY.get(i).x,saboXY.get(i).y, null);
    saboXY.get(i).x -= car.vx;
    if(saboXY.get(i).x<-194){
     saboXY.add(new PointF(saboXY.get(saboXY.size()-1).x+200+rnd.nextInt(300),Y));
     saboXY.remove(i);
     i--;
    }
   }
  }
 }

 class Rock{
  ArrayList<PointF> rockXY = new ArrayList<PointF>();
  float Y = wh-50-85;
  Random rnd = new Random();

  public Rock(){
   float X = 1000;
   for(int i=0;i<2;i++){
    rockXY.add(new PointF(X,Y));
    X += (500+rnd.nextInt(300));
   }
  }

  public void view(Canvas canvas){
   for(int i=0;i<rockXY.size();i++){
    canvas.drawBitmap(rock_img, rockXY.get(i).x,rockXY.get(i).y, null);
    rockXY.get(i).x -= car.vx;
    if(rockXY.get(i).x<-85){
     rockXY.add(new PointF(rockXY.get(rockXY.size()-1).x+500+rnd.nextInt(300),Y));
     rockXY.remove(i);
     i--;
    }
   }
  }

 }

 class Car{
  float x = 150;
  float y_base = wh-80-50;
  float y = y_base;
  float vx = 0.1f;
  float ax = 0.01f;
  float vy = -8;
  float g = 0.2F;
  boolean jumpFlag = false;
  boolean jumpFlag2 = false;
  boolean jump2finFlag = false;
  int touchTime = 0;

  public void view(Canvas canvas){
   canvas.drawBitmap(car_img, x,y, null);
   if(jumpFlag){
    if(jumpFlag2){
     if(!jump2finFlag){
      vy = -6;
      jump2finFlag = true;
     }
    }else if(touchTime > 0){
     vy = -8;
     touchTime ++;
     if(touchTime >20){
      touchTime = 0;
     }
    }
    y += vy;
    vy += g;
    if(y>=y_base){
     y = y_base;
     vy = -8;
     jumpFlag = false;
     jumpFlag2 = false;
     jump2finFlag = false;
    }
   }
   if(vx < 10){
    vx += ax;
   }else{
    vx = 10;
   }
   check_hit_rock();
  }

  public void check_hit_rock(){
   float rl;
   float rr;
   float rt;
   float rb;
   float cl;
   float cr;
   float ct;
   float cb;
   for(int i=0;i<2;i++){
    rl = rock.rockXY.get(i).x;
    rr = rl+85;
    rt = rock.rockXY.get(i).y;
    rb = rt+85;
    cl = x;
    cr = x+100;
    ct = y;
    cb = y+80;
    if(cl<rr&amp;&amp;rl<cr&amp;&amp;ct<rb&amp;&amp;rt<cb){
     if(20>cb-rt){
      y = rt-80;
      jumpFlag2 = false;
      jump2finFlag = false;
     }else{
      vx = -1;
     }
    }

   }
  }
 }
}