您的位置:首页 > 其它

libgdx游戏引擎教程实战篇(五)移植俄罗斯方块(附源码)

2013-03-11 14:24 417 查看
转自:http://www.apkbus.com/android-58419-1-1.html

接着实战第四讲,我们做一个总结(手都要断了啊!!!TAT)。

SDK版俄罗斯方块源码下载(我们移植工作的素材)


Tetris_slide.rar(537.04
KB, 下载次数: 42)

2012-7-10 22:21 上传
点击文件名下载附件

下载积分: 下载豆 -2

实战一到五移植后的源码:


libgdxTetris.rar(3.93
MB, 下载次数: 92)

2012-7-10 22:21 上传
点击文件名下载附件

下载积分: 下载豆 -2

[align=left]初步的移植其实已经完成了。当然我们现在还有一些移植进来的函数没有用到,比如save(),read()函数等等,因为这些函数都是保存进度,读取进度的时候用的,我们先实现游戏功能,其他的我们一步步来。[/align]

[align=left]我们来看看目前的代码。[/align]

[align=left][/align]



2012-7-10 22:22 上传
下载附件(39.53 KB)

[align=left]有五个部分[/align]

[align=left]1. Bricks.java,这个类我们是直接从原来的工程中复制过来的,没有做任何的修改。[/align]

[align=left]2. TetrisGame.java,抽象类Game的实现,用于管理不同的Screen,里面的代码非常短:[/align]

public class TetrisGame extends Game {

Screen screen;

@Override

public void create() {

// TODO Auto-generated method stub

setScreen(screen);

}

public TetrisGame(Screen screen) {

super();

// TODO Auto-generated constructor stub

this.screen=screen;

}

}

复制代码
[align=left]3. GameScreen.java,这是游戏主界面,由一个TetrisGame管理,修改后的代码如下(里面有的方法暂时没有用到,是直接从原项目中拿过来的,比如存档功能我们将用到这些函数,而这些功能的实现我们将在后面慢慢加上)。注意,其中有大量的分辨率适配的代码,当然我们还是做一个简单的适配,只适配QVGA,HVGA,WVGA(其实FWVGA显示也没有什么问题)。[/align]

public class GameScreen implements Screen {

Texture texture;

TextureRegion background;

SpriteBatch batch;

Texture[] image;

UiActivity activity;

BitmapFont bf;

//用21*10的数组表示21*10的方格

//frame代表已经固定下来的所有方块

int[][] frame=new int [21][10];

//temframe代表固定下来的方块和空中正在飞行的方块的数组,由于还有方块在空中,因此

//此数组一直在变化,我们用它来直接绘图。

int[][] temframe=new int[21][10];

//我们很容易发现所有七中方块都可以画在一个4*4的小方格内

int[][] bricks=new int[4][4];

//当前Brick

Bricks brick;

//随机产生方块

protected Random rand=new Random(6);

//位图数组,用来存储方块图形

boolean isplaying=true;

boolean isflying;

int x;

int y;

int score=0;

//调整难度,这是调整线程睡眠时间的量,值越小,速度越快

long speed=600;

//保存当前屏幕长宽高,用于适配,在我们这个游戏默认竖屏的情况下

int min;

int max;

//还是一样,判断这个Screen是不是第一次显示,只有在第一次显示的时候需要初始化资源

boolean hasini;

//适配触摸灵敏度

int left;

int right;

int roll;

int below;

@Override

public void dispose() {

// TODO Auto-generated method stub

}

@Override

public void hide() {

// TODO Auto-generated method stub

isplaying=false;

}

public GameScreen(UiActivity activity) {

super();

this.activity=activity;

// TODO Auto-generated constructor stub

}

@Override

public void pause() {

// TODO Auto-generated method stub

isplaying=false;

}

@Override

public void render(float arg0) {

// TODO Auto-generated method stub

// TODO Auto-generated method stub

Gdx.gl.glClear(GL10.GL_COLOR_BUFFER_BIT);

Gdx.gl.glClearColor(0f,0f,0f,0f);

//绘图前要调用begin()方法

batch.begin();

batch.draw(background, 0,0);

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

for(int j=0;j<10;j++)

//根据屏幕大小做了一个简单的适配,只适配了QVGA,HVGA,WVGA

if(temframe[i][j]!=0){

if(max>=320&&max<480){

batch.draw(image[temframe[i][j]-1], (float)(50+14*j), max-(float)(25+14*(i+1)),14,14);

bf.draw(batch,"得分"+score, 210f, 200f);

}

if(max>=480&&max<800){

batch.draw(image[temframe[i][j]-1], (float)(80+16*j), max- (float)(70+16*(i+1)),16,16);

bf.draw(batch, "得分"+score, 280, 320);

}

if(max>=800){

batch.draw(image[temframe[i][j]-1], (float)(100+28*j),max-(float)(120+28*(i+1)),28,28);

bf.draw(batch, "得分"+score, 400, 540);

}

}

//结束时要调用end()方法

batch.end();

if(Gdx.input.isTouched()){

int x=Gdx.input.getX();

int y=Gdx.input.getY();

if(x<(min/2)&&((y/x)>(max/min))&&y<(max-max*x/min)){

left++;

if(left%3==0)

toLeft();

}

if(x>(min/2)&&(y/x<(max/min))&&y>(max-max*x/min)){

right++;

if(right%3==0)

toRight();

}

if(((y/x)<(max/min))&&y<(max-max*x/min)){

roll++;

if(roll%3==0)

roll();

}

if(((y/x)>(max/min))&&y>(max-max*x/min)){

below++;

if(below%2==0)

toBelow();

}

}

}

@Override

public void resize(int arg0, int arg1) {

// TODO Auto-generated method stub

}

@Override

public void resume() {

// TODO Auto-generated method stub

}

@Override

public void show() {

int width=Gdx.graphics.getWidth();

int height=Gdx.graphics.getHeight();

max=width>height?width:height;

min=width>height?height:width;

isplaying=true;

//还是一样,做一个简单的适配

if(max>=320&&max<480)

max=320;

if(max>=480&&max<800)

max=480;

if(max>=800)

max=800;

// TODO Auto-generated method stub

new Thread(new Runnable() {

@Override

public void run() {

// TODO Auto-generated method stub

try{

while(isplaying==true){

if(!isflying){

switch((int) Math.round(Math.random() * 7)){

case 0:brick=new COBrick((int) rand.nextInt(6));System.out.println("O!"+brick.color);break;

case 1:brick=new CLBrick((int) rand.nextInt(6));System.out.println("L!"+brick.color);break;

case 2:brick=new CLLBrick((int) rand.nextInt(6));System.out.println("LL!"+brick.color);break;

case 3:brick=new CSBrick((int) rand.nextInt(6));System.out.println("S!"+brick.color);break;

case 4:brick=new CSSBrick((int) rand.nextInt(6));System.out.println("SS!"+brick.color);break;

case 5:brick=new CIBrick((int) rand.nextInt(6));System.out.println("I!"+brick.color);break;

case 6:brick=new CCBrick((int) rand.nextInt(6));System.out.println("C!"+brick.color);break;

}

x=0;

y=3;

isflying=true;

try{

bricks=brick.checkori(brick.ori);

}catch(NullPointerException e){

brick=new CSSBrick((int) rand.nextInt(6));

bricks=brick.checkori(brick.ori);

}

}

toBelow();

Thread.sleep(speed);

}

}catch (InterruptedException e){

}

}

}).start();

if(!hasini){

batch=new SpriteBatch();

image=new Texture[6];

bf=new BitmapFont();

//初始化背景图片

texture=new Texture(Gdx.files.internal("background2"+max+".png"));

background=new TextureRegion(texture,0,0,min,max);

//初始化方块图片

for(int i=1;i<=6;i++){

image[i-1]=new Texture(Gdx.files.internal(i+".png"));

hasini=true;

}

}

}

//向左移动

public void toLeft(){

if(checkcollide(x,((int)(y-1)),bricks,frame)){

System.out.print("Left");

y-=1;

copy();

}

}

//向右移动

public void toRight(){

if(checkcollide(x,((int)(y+1)),bricks,frame)){

y+=1;

copy();

}

}

//向下移动

public void toBelow(){

System.out.println("In below!");

try{

if(bricks!=null){

if(checkcollide(((int)(x+1)),y,bricks,frame)){

x+=1;

copy();

}

else {

if(checkfull()){

UiActivity.gameover=true;

}

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

for(int j=0;j<4;j++){

if(bricks[i][j]!=0)

frame[x+i][y+j]=bricks[i][j];

}

isflying=false;

bricks=null;

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

int flag=1;

for(int j=0;j<10;j++){

if(frame[i][j]==0)

flag=0;

}

if(flag==1){

for(int k=i;k>0;k--)

frame[k]=frame[k-1].clone();

for(int p=0;p<10;p++)

frame[0][p]=0;

score+=100;

}

}

}

}

}catch(NullPointerException e){

e.printStackTrace();

}

}

//旋转

public void roll(){

if(checkcollide(x,y,brick.checkori((int)(brick.ori+1)),frame)){

brick.ori+=1;

bricks=brick.checkori(brick.ori);

copy();

}

}

//更新temframe里的内容,用于实时绘图

public void copy(){

for(int k=0;k<21;k++)

temframe[k]=frame[k].clone();

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

for(int j=0;j<4;j++)

if(bricks[i][j]!=0&&temframe[x+i][y+j]==0)

temframe[x+i][y+j]=bricks[i][j];

}

public boolean checkcollide(int x,int y,int[][]bricks,int[][]frame){

if(bricks!=null)

{

int max_x=0,min_x=3,max_y=0,min_y=3;

boolean collide=true;

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

for(int j=0;j<4;j++)

if(bricks[i][j]!=0){

if(j<min_y)

min_y=j;

if(j>max_y)

max_y=j;

if(i>max_x)

max_x=i;

if(i<min_x)

min_x=i;

}

if((max_x+x)>20||(max_y+y)>10||y+min_y<0)

collide=false;

try{

int i;

int j;

for(i=0;i<=max_x;i++)

for(j=min_y;j<=max_y;j++)

if(bricks[i][j]!=0&&frame[x+i][y+j]!=0){

collide=false;

}

}catch(ArrayIndexOutOfBoundsException e){

return false;

}

return collide;

}

return false;

}

//判断是否方块到顶,游戏结束

public boolean checkfull(){

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

for(int j=0;j<10;j++){

if(temframe[i][j]!=frame[i][j])

return false;

}

return true;

}

public void save(String fileName, String fileContent) throws Exception {

FileOutputStream fileOutputStream = activity.openFileOutput(

fileName, Context.MODE_PRIVATE);

fileOutputStream.write(fileContent.getBytes());

}

public String read(String fileName) throws Exception {

FileInputStream fileInputStream = activity.openFileInput(fileName);

ByteArrayOutputStream byteArray = new ByteArrayOutputStream();

byte[] buffer = new byte[1024];

int len = 0;

while ((len = fileInputStream.read(buffer)) > 0) {

byteArray.write(buffer, 0, len);

};

return byteArray.toString();

}

public void savedata(){

String framedata="";

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

for(int j=0;j<10;j++){

framedata+=Integer.toString(frame[i][j])+",";

}

framedata+=Integer.toString(score);

try {

save("Tetris_slide.txt",framedata);

} catch (Exception e) {

// TODO Auto-generated catch block

e.printStackTrace();

}

}

}

复制代码
[align=left]其中写了大量的注释,这里没有做过多的解释,至于其各个方法的意思,想来光是看这些方法的名字也就能知道,我们这几讲的主要目的是实现一个现成的SDK版本的俄罗斯方块的代码的移植工作,至于SDK版本是怎么实现的,大家可以看看两个版本的代码,并做一些比对,就很容易看出来了。[/align]

[align=left]4. UiScreen.java,这就是主界面Screen,样式如下图,我们对按钮添加了监听器,设置按下去的时候切换到游戏界面。注意,其中有大量的分辨率适配的代码,当然我们还是做一个简单的适配,只适配QVGA,HVGA,WVGA(其实FWVGA显示也没有什么问题)[/align]

public class UiScreen implements Screen {

Texture texture;

TextureRegion background;

boolean hasini;

SpriteBatch batch;

Stage stage;

Button start;

int width;

int height;

//边长的最大值和最小值

int max;

int min;

Texture tx1;

Texture tx2;

Texture tx3;

UiActivity activity;

public UiScreen(UiActivity activity){

super();

this.activity=activity;

// TODO Auto-generated constructor stub

}

@Override

public void dispose() {

// TODO Auto-generated method stub

}

@Override

public void hide() {

// TODO Auto-generated method stub

}

@Override

public void pause() {

// TODO Auto-generated method stub

}

@Override

public void render(float arg0) {

// TODO Auto-generated method stub

Gdx.gl.glClear(GL10.GL_COLOR_BUFFER_BIT);

Gdx.gl.glClearColor(0f,0f,0f,0f);

batch.begin();

batch.draw(background,0,0,min,max);

batch.end();

//舞台绘制要在背景绘制之后,不然背景会覆盖在按钮表面,我们就看不到按钮了

stage.act(Gdx.graphics.getDeltaTime());

stage.draw();

}

@Override

public void resize(int arg0, int arg1) {

// TODO Auto-generated method stub

}

@Override

public void resume() {

// TODO Auto-generated method stub

}

@Override

public void show() {

// TODO Auto-generated method stub

//做一个简单的适配。这里解释一下为什么不直接令max=height,原因在于有时候我们从锁屏回到游戏,

//从横屏切换到竖屏或者从竖屏切换到横屏的时候,libGdx有时候会来不及切换,也就是说我们可能

//getWidth得到的是实际的height值,getHeight得到的是实际的width值,所以这里增加一个长宽哪一个

//更大的语句,这样就不会出错了

width=Gdx.graphics.getWidth();

height=Gdx.graphics.getHeight();

max=width>height?width:height;

min=width>height?height:width;

//再做一个简单的适配

if(max>=320&&max<480)

max=320;

if(max>=480&&max<800)

max=480;

if(max>=800)

max=800;

if(!hasini){

batch=new SpriteBatch();

stage=new Stage(min,max,true);

texture=new Texture(Gdx.files.internal("background"+max+".jpg"));

//新建一个Button

tx2 = new Texture(Gdx.files.internal("button1.png"));

tx1 = new Texture(Gdx.files.internal("button2.png"));

tx3 = new Texture(Gdx.files.internal("button3.png"));

NinePatch n1 = new NinePatch(tx1, 14, 14, 18, 18);

NinePatch n2 = new NinePatch(tx2, 14, 14, 18, 18);

NinePatch n3 = new NinePatch(tx3, 14, 14, 18, 18);

start= new Button( new ButtonStyle(n1, n2, n3, 0f, 0f, 0f, 0f), "Start");

start.setClickListener(new ClickListener() {

@Override

public void click(Actor arg0, float arg1, float arg2) {

// TODO Auto-generated method stub

activity.tg.setScreen(activity.gs);

}

});

//让按钮的位置处在正中间

start.x=(min-tx2.getWidth())/2;

stage.addActor(start);

//重点在这条语句,我们只取了texture的一部分,红色的多余部分我们没有取

background=new TextureRegion(texture, 0, 0, min, max);

hasini=true;

}

//这句话是必须的,而且在if(hasini)之外,无论资源是否加载完成,每次显示的时候我们都养将当前屏幕

//设置能够接受用户输入

Gdx.input.setInputProcessor(stage);

}

}

复制代码
[align=left]5.UiActivity.java,这就是一个AndroidApplication了,代码也很简单,直接贴出来[/align]

public class UiActivity extends AndroidApplication {

TetrisGame tg;

UiScreen us;

GameScreen gs;

static boolean gameover;

@Override

public void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

requestWindowFeature(Window.FEATURE_NO_TITLE);

getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,

WindowManager.LayoutParams.FLAG_FULLSCREEN);

gs=new GameScreen(this);

us=new UiScreen(this);

tg=new TetrisGame(us);

initialize(tg, true);

}

}

复制代码



2012-7-10 22:27 上传
下载附件(138.64 KB)



2012-7-10 22:27 上传
下载附件(173.01 KB)

初步的移植工作就算结束了,这时候我们按退出键游戏就完全退出了,不像SDK,

版本那样可以回到主界面并且有提示对话框,而且不能保存进度,由于初次移植,没有必要要求一步到位,因此我觉得先将游戏功能实现了就可以。剩下的一系列功能我们将一步步实现。敬请期待接下来的Testin
杯libgdx游戏引擎系列教程。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐