我们看似人物在往前走,其实际是背景和陆地再往后退
比如当我们刚上火车后,火车还未开动,但是我们看到窗外一个向后行驶火车后,我们总会感觉自己再像前走,道理是一样的
理解了这点我们就可以找可以动手来做了
首先分析下,这个view可以分为4个部分,1后面的背景,2背景下面的河流,3人物行驶的陆地,4游戏人物本身
我们可以控制1后面背景速度为1向后滚动,背景2稍微快点速度为5向后滚动,3陆地速度要更快>5(随游戏等级增加)向后滚动,人物X静止不动
1、打开eclipse新建一个android工程
2、双换成技术是游戏开发中必然会用到的技术,使游戏成像流畅的进行。使用SurfaceView类可以很容易的实现这个功能。
添加一个GameSurfaceView类,继承SurfaceView父类,实现 SurfaceHolder.Callback,Runnable这几个接口,一个接口用来处理系统消息,另一个接口用来处理线程。 SurfaceHolder用来处理所有的系统消息和绘制,缓冲Canvas也需要用它来实现。在构造函数中实例化一个SurfaceHolder类,并且添加回调函数,以处理系统消息
时间的控制在游戏中极为重要,下面对实现Runnable接口的类填写控制时间代码。 System.currentTimeMillis():方法获取系统时间,以毫秒为单位。经过试验在虚拟机中 平均一次sleep需要10毫秒,因此基础睡眠时间定为10毫秒为基准。重绘时间定为5个基准单位,数据更新时间定为10个基准单位,每次睡眠获取时间差,减掉时间差之后 <=0即实现动作。具体代码如下
public class GameSurfaceView extends SurfaceView implements SurfaceHolder.Callback,Runnable{
private SurfaceHolder mSurfaceHolder = null;
/**控制时间*/
static final long wait_time = 10;
static final long redraw_count = 5;
static final long redraw_time = redraw_count*wait_time;
private long now_time_redraw = redraw_time;
static final long update_count = 10;
static final long update_time = update_count*wait_time;
private long now_time_update = update_time;
public GameSurfaceView(Context context) {
super(context);
// TODO Auto-generated constructor stub
mSurfaceHolder = this.getHolder();
mSurfaceHolder.addCallback(this);
this.setFocusable(true);
}
//数据更新
public void MainUpdate(){
}
@Override
public void draw(Canvas canvas) {
// TODO Auto-generated method stub
//super.draw(canvas);
Canvas c = mSurfaceHolder.lockCanvas();//锁定画布,一般在锁定后就可以通过其返回的画布对象Canvas,在其上面画图等操作了。
//绘图操作....
//
//......
//解锁显示
mSurfaceHolder.unlockCanvasAndPost(c);
}
@Override
public boolean onTouchEvent(MotionEvent event) {
// TODO Auto-generated method stub
int actionType = event.getAction();
if(MotionEvent.ACTION_DOWN == actionType){
//左屏,或右屏按下
int onTouchX = (int) event.getRawX();
if(onTouchX < MainConfig.ScreenWidth/2){
//作屏幕按下操作
}else{
//右屏幕按下操作
}
}
return super.onTouchEvent(event);
}
@Overridepublic void run()
{
// TODO Auto-generated method stub
while(!Thread.currentThread().isInterrupted()){
long time = System.currentTimeMillis();
try {Thread.sleep(wait_time);
} catch (InterruptedException e)
{// TODO Auto-generated catch
e.printStackTrace();
}
long dt = System.currentTimeMillis() - time;
now_time_redraw -=dt;
if(now_time_redraw <= 0){
//重绘this.draw(null);now_time_redraw = redraw_time;
}
now_time_update -=dt;
if(now_time_update <= 0){
MainUpdate();
//更新数据
now_time_update = update_time;
}
}
}
@Overridepublic
void surfaceChanged(SurfaceHolder arg0, int arg1, int arg2, int arg3)
{// TODO Auto-generated method stub//在surface的大小发生改变时激发}
@Overridepublic void surfaceCreated(SurfaceHolder arg0)
{// TODO Auto-generated method stub //在创建时激发,一般在这里调用画图的线程。//初始化
new Thread(this).start();
}
@Overridepublic void surfaceDestroyed(SurfaceHolder arg0) {// TODO Auto-generated method stub //销毁时激发,一般在这里将画图的线程停止、释放。}}
然后我们在draw中绘制每一帧就可以了
我们把四部分都创建一个类,首先是背景类MainGameBg
准备一张背景图
为了实现背景图向后运动我们可以让该类实现Runnable,把他当成线程类,然后让他自己的x向后递减
通过view的getResources().getDrawable方法获取资源中的图片放入Bitmap类型的成员变量中,在run中每过30毫秒刷新一次x值,然后在GameSurfaceView中调用drawBg进行重绘
为了让背景能够流畅的滚动,我们创建2个Bitmap类型的成员,交替滚动,虽然浪费了一些内存,但是这样代码逻辑比较清楚
package com.winheng.model;
import com.example.yhgame.R;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Matrix;
import android.graphics.drawable.BitmapDrawable;
import android.view.View;
public class MainGameBg implements Runnable{
/**背景图*/
private Bitmap bgImg = null;
private Bitmap bgImg2 = null;
/**游戏主背景运动速度*/
static final int bgImagSpeed = 1;
/**主游戏背景宽度*/
static final int bgImagWidth= 961;
/**背景1 X位置*/
private int x1 = 0;
/**背景2 X位置*/
private int x2 = bgImagWidth;
public MainGameBg(View context){
bgImg = ((BitmapDrawable)context.getResources().getDrawable(R.drawable.main_bg1)).getBitmap();
bgImg2 = ((BitmapDrawable)context.getResources().getDrawable(R.drawable.main_bg1)).getBitmap();
}
@Override
public void run() {
while(true){
try {
Thread.sleep(30);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
x1 -= bgImagSpeed;
x2 -= bgImagSpeed;
if(-x1 >= bgImagWidth){
x1 = bgImagWidth-10;
}
if(-x2 >= bgImagWidth){
x2 = bgImagWidth-10;
}
}
}
public void drawBg(Canvas c){
Matrix mtrx = new Matrix();
mtrx.postTranslate(x1, 0);
c.drawBitmap(bgImg, mtrx, null);
Matrix mtrx2 = new Matrix();
mtrx2.postTranslate(x2, 0);
c.drawBitmap(bgImg2, mtrx2, null);
}
}
然后类似背景图一。添加第二个背景,这个背景速度比背景图一稍微快点
package com.winheng.model;
import com.example.yhgame.R;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Matrix;
import android.graphics.drawable.BitmapDrawable;
import android.view.View;
public class MainGameBgS implements Runnable{
static final int gameWidth = 480;
static final int gameHeight= 320;
/**背景图*/
private Bitmap bgImg = null;
private Bitmap bgImg2 = null;
/**游戏主背景运动速度*/
static final int bgImagSpeed = 5;
/**主游戏背景宽度*/
static final int bgImagWidth= 3200;
/**背景1 X位置*/
private int x1 = 0;
/**背景2 X位置*/
private int x2 = bgImagWidth;
private int isdownTime = 0;
public MainGameBgS(View context){
bgImg = ((BitmapDrawable)context.getResources().getDrawable(R.drawable.main_bg2)).getBitmap();
bgImg2 = ((BitmapDrawable)context.getResources().getDrawable(R.drawable.main_bg2)).getBitmap();
}
@Override
public void run() {
// TODO Auto-generated method stub
while(true){
try {
Thread.sleep(30);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
if(isdownTime > 0){
isdownTime--;
x1 -= bgImagSpeed+10;
x2 -= bgImagSpeed+10;
}else{
x1 -= bgImagSpeed;
x2 -= bgImagSpeed;
}
if(-x1 >= bgImagWidth){
x1 = bgImagWidth-10;
}
if(-x2 >= bgImagWidth){
x2 = bgImagWidth-10;
}
}
}
public void drawBg(Canvas c){
Matrix mtrx = new Matrix();
mtrx.postTranslate(x1, 0);
c.drawBitmap(bgImg, mtrx, null);
Matrix mtrx2 = new Matrix();
mtrx2.postTranslate(x2, 0);
c.drawBitmap(bgImg2, mtrx2, null);
}
public void isDown(){
isdownTime = 50;
}
}
然后添加陆地
package com.winheng.model;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Matrix;
import android.graphics.drawable.BitmapDrawable;
import android.view.View;
import com.example.yhgame.R;
public class MainLand implements Runnable{
/**背景图*/
private Bitmap land1 = null;
private Bitmap land2 = null;
private Bitmap land3 = null;
private Bitmap landGirl = null;
/**游戏主背景运动速度*/
private int bgImagSpeed = 9;
/**主游戏背景宽度*/
static final int bgImagWidth= 800;
/**背景1 X位置*/
private int x1 = 0;
/**背景 Y位置*/
private int y = 0;
private Lands lands[] = new Lands[200];
private int isdownTime = 20;
public MainLand(View context){
land1 = ((BitmapDrawable)context.getResources().getDrawable(R.drawable.land1)).getBitmap();
land2 = ((BitmapDrawable)context.getResources().getDrawable(R.drawable.main_land)).getBitmap();
landGirl = ((BitmapDrawable)context.getResources().getDrawable(R.drawable.land1girl)).getBitmap();
if(MainConfig.ScteenType ==1){
y = 300;
}else{
y = 215;
}
//初始化地图
initMap();
}
@Override
public void run() {
// TODO Auto-generated method stub
while(true){
try {
Thread.sleep(30);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
if(isdownTime>0){
isdownTime --;
x1 -= (bgImagSpeed+30);
}else{
x1 -= bgImagSpeed;
}
}
}
public int drawBg(Canvas c){
//地图是否用完
if(-x1/100 >= 190){
x1 = 0;
}
int x = 0;
int index = 0;
for(int i=(-x1/100);i<(-x1/100)+20;i++){
//for(int i=0;i<22;i++){
index++;
if(index == 3){
x = lands[i].getY();
if(i==60){
lands[60].setBitimg(land1);
lands[60].setY(y);
}
}
Matrix mtrx = new Matrix();
mtrx.postTranslate(lands[i].getX() + x1, lands[i].getY());
c.drawBitmap(lands[i].getBitimg(), mtrx, null);
}
return x - 80;
}
public void isDown(){
isdownTime = 50;
}
public void initMap(){
int i;
for(i = 0;i < lands.length;i++){
lands[i] = new Lands();
lands[i].setX(i*100);
}
for(i=0;i<20;i++){
lands[i].setBitimg(land1);
lands[i].setY(y);
}
lands[20].setBitimg(land1);
lands[20].setY(y+300);
lands[21].setBitimg(land1);
lands[21].setY(y+300);
for(i=22;i<30;i++){
lands[i].setBitimg(land1);
lands[i].setY(y-20);
}
for(i=30;i<40;i++){
lands[i].setBitimg(land1);
lands[i].setY(y+20);
}
lands[40].setBitimg(land1);
lands[40].setY(y+300);
for(i=41;i<60;i++){
lands[i].setBitimg(land1);
lands[i].setY(y);
}
lands[60].setBitimg(landGirl);
lands[60].setY(y-170); // 350 - 180 170 300 -215 130
for(i=61;i<80;i++){
lands[i].setBitimg(land1);
lands[i].setY(y+20);
}
lands[80].setBitimg(land1);
lands[80].setY(y+300);
for(i=81;i<100;i++){
lands[i].setBitimg(land1);
lands[i].setY(y-20);
}
for(i=100;i<110;i++){
lands[i].setBitimg(land1);
lands[i].setY(y);
}
lands[110].setBitimg(land1);
lands[110].setY(y+300);
for(i=111;i<120;i++){
lands[i].setBitimg(land1);
lands[i].setY(y);
}
for(i=120;i<130;i++){
lands[i].setBitimg(land1);
lands[i].setY(y-20);
}
for(i=130;i<140;i++){
lands[i].setBitimg(land1);
lands[i].setY(y+20);
}
lands[140].setBitimg(land1);
lands[140].setY(y+300);
for(i=141;i<160;i++){
lands[i].setBitimg(land1);
lands[i].setY(y);
}
for(i=160;i<180;i++){
lands[i].setBitimg(land1);
lands[i].setY(y+20);
}
lands[180].setBitimg(land1);
lands[180].setY(y+300);
for(i=181;i<200;i++){
lands[i].setBitimg(land1);
lands[i].setY(y-20);
}
}
}
最后是摩托车
package com.winheng.model;
import com.example.yhgame.R;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Matrix;
import android.graphics.drawable.BitmapDrawable;
import android.view.View;
public class MainMoto implements Runnable{
//人物图像
private Bitmap moto[] = new Bitmap[4] ;
//人物图像更换速度
private int changeIndex=0;
//人物跳图
private Bitmap motoJump = null;
//人物加速度图
private Bitmap motoJump2 = null;
//当前人物index
private int nowIndex = 0;
//人物x轴
private int x = 90;
//陆地y
private int landY ;
//人物y轴
private int y = 0;
//2跳转动角度
private float rot = 0;
//跳上升时间 10*30
private int upTime = 10;
private View vieContext;
/**
* 1:跳
* 0:降落
* -1:正常
* 2:双跳
* */
private int isDump = -1;
private int isdownTime = 0;
//初始化人物图像
public MainMoto(View context){
vieContext = context;
moto[0] = ((BitmapDrawable)context.getResources().getDrawable(R.drawable.moto0)).getBitmap();
moto[1] = ((BitmapDrawable)context.getResources().getDrawable(R.drawable.moto1)).getBitmap();
moto[2] = ((BitmapDrawable)context.getResources().getDrawable(R.drawable.moto2)).getBitmap();
moto[3] = ((BitmapDrawable)context.getResources().getDrawable(R.drawable.moto3)).getBitmap();
motoJump = ((BitmapDrawable)context.getResources().getDrawable(R.drawable.jump)).getBitmap();
motoJump2= ((BitmapDrawable)context.getResources().getDrawable(R.drawable.jump)).getBitmap();
if(MainConfig.ScteenType == 1){
landY = 220;
y = 220;
}else{
landY = 135;
y = 135;
}
}
@Override
public void run() {
while(true){
try {
Thread.sleep(30);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
if(changeIndex >= 5){
changeIndex = 0;
nowIndex++;
if(nowIndex > 3){
nowIndex = 0;
}
}
changeIndex++;
/**
* 1:跳
* 0:降落
* -1:正常
* 2:双跳
* */
//跳
if(isDump == 1){
y-=9;
x+=1;
upTime--;
//落
}else if(isDump == 0){
x-=1;
y+=10;
//双跳
}else if(isDump == 2){
y-=9;
x+=1;
rot +=15;
upTime--;
}else if(isDump == -1){
y = landY;
}else if(isDump == 3){
y = landY;
}
if(upTime<=0){
upTime = 10;
isDump = 0;
}
//下降到地上
if(y > landY){
y = landY;
if(x>90)x--;
isDump = -1;
}
if(isdownTime > 0){
isdownTime--;
}
if(isdownTime <= 0 && isDump == 3){
isDump = -1;
}
}
}
public void drawBg(Canvas c,int landY){
//人物上车
if(landY <= 130 ){
moto[0] = ((BitmapDrawable)vieContext.getResources().getDrawable(R.drawable.moto0s)).getBitmap();
moto[1] = ((BitmapDrawable)vieContext.getResources().getDrawable(R.drawable.moto1s)).getBitmap();
moto[2] = ((BitmapDrawable)vieContext.getResources().getDrawable(R.drawable.moto2s)).getBitmap();
moto[3] = ((BitmapDrawable)vieContext.getResources().getDrawable(R.drawable.moto3s)).getBitmap();
motoJump = ((BitmapDrawable)vieContext.getResources().getDrawable(R.drawable.jumps)).getBitmap();
motoJump2= ((BitmapDrawable)vieContext.getResources().getDrawable(R.drawable.jumps)).getBitmap();
}else{
this.landY = landY;
}
Matrix mtrx = new Matrix();
// mtrx.setScale(0.33f, 0.33f);
//正常
if(isDump == -1){
mtrx.postTranslate(x, y);
c.drawBitmap(moto[nowIndex], mtrx, null);
//二跳
}else if(isDump == 2){
mtrx.postTranslate(x, y);
mtrx.setTranslate(x, y);
mtrx.preRotate(rot,motoJump.getWidth() / 2f,motoJump.getHeight() / 2f );
c.drawBitmap(moto[nowIndex], mtrx, null);
//加速度
}else if(isDump == 3){
mtrx.postTranslate(x, y);
c.drawBitmap(motoJump2, mtrx, null);
//上升,下降
}else{
mtrx.postTranslate(x, y);
c.drawBitmap(motoJump, mtrx, null);
}
}
//跳
public void dump(){
if(isDump == 1 || isDump ==0){
upTime = 6;
isDump = 2;
}else if(isDump == -1 || isDump == 3){
isDump = 1;
}
}
//加速度
public void down(){
isdownTime = 50;
isDump = 3;
}
}