libgdx游戏引擎教程实战篇(五)移植俄罗斯方块(附源码)
2013-03-11 14:24
417 查看
转自:http://www.apkbus.com/android-58419-1-1.html
接着实战第四讲,我们做一个总结(手都要断了啊!!!TAT)。
SDK版俄罗斯方块源码下载(我们移植工作的素材)
![](https://oscdn.geek-share.com/Uploads/Images/Content/201303/73cf0ebac5fc248512e1c9aa3ac9ec1c.gif)
Tetris_slide.rar(537.04
KB, 下载次数: 42)
2012-7-10 22:21 上传
点击文件名下载附件
下载积分: 下载豆 -2
实战一到五移植后的源码:
![](https://oscdn.geek-share.com/Uploads/Images/Content/201303/73cf0ebac5fc248512e1c9aa3ac9ec1c.gif)
libgdxTetris.rar(3.93
MB, 下载次数: 92)
2012-7-10 22:21 上传
点击文件名下载附件
下载积分: 下载豆 -2
[align=left]初步的移植其实已经完成了。当然我们现在还有一些移植进来的函数没有用到,比如save(),read()函数等等,因为这些函数都是保存进度,读取进度的时候用的,我们先实现游戏功能,其他的我们一步步来。[/align]
[align=left]我们来看看目前的代码。[/align]
[align=left][/align]
![](https://oscdn.geek-share.com/Uploads/Images/Content/202006/01/fa64664ffad87759c0321b465f66e20a.jpg)
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);
}
}
复制代码
![](https://oscdn.geek-share.com/Uploads/Images/Content/202006/01/920dd3b151e0698d03fed97ce83b08bf.png)
2012-7-10 22:27 上传
下载附件(138.64 KB)
![](https://oscdn.geek-share.com/Uploads/Images/Content/202006/01/31d9461bc728ba246b9df6b6599bbea7.png)
2012-7-10 22:27 上传
下载附件(173.01 KB)
初步的移植工作就算结束了,这时候我们按退出键游戏就完全退出了,不像SDK,
版本那样可以回到主界面并且有提示对话框,而且不能保存进度,由于初次移植,没有必要要求一步到位,因此我觉得先将游戏功能实现了就可以。剩下的一系列功能我们将一步步实现。敬请期待接下来的Testin
杯libgdx游戏引擎系列教程。
接着实战第四讲,我们做一个总结(手都要断了啊!!!TAT)。
SDK版俄罗斯方块源码下载(我们移植工作的素材)
![](https://oscdn.geek-share.com/Uploads/Images/Content/201303/73cf0ebac5fc248512e1c9aa3ac9ec1c.gif)
Tetris_slide.rar(537.04
KB, 下载次数: 42)
2012-7-10 22:21 上传
点击文件名下载附件
下载积分: 下载豆 -2
实战一到五移植后的源码:
![](https://oscdn.geek-share.com/Uploads/Images/Content/201303/73cf0ebac5fc248512e1c9aa3ac9ec1c.gif)
libgdxTetris.rar(3.93
MB, 下载次数: 92)
2012-7-10 22:21 上传
点击文件名下载附件
下载积分: 下载豆 -2
[align=left]初步的移植其实已经完成了。当然我们现在还有一些移植进来的函数没有用到,比如save(),read()函数等等,因为这些函数都是保存进度,读取进度的时候用的,我们先实现游戏功能,其他的我们一步步来。[/align]
[align=left]我们来看看目前的代码。[/align]
[align=left][/align]
![](https://oscdn.geek-share.com/Uploads/Images/Content/202006/01/fa64664ffad87759c0321b465f66e20a.jpg)
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);
}
}
复制代码
![](https://oscdn.geek-share.com/Uploads/Images/Content/202006/01/920dd3b151e0698d03fed97ce83b08bf.png)
2012-7-10 22:27 上传
下载附件(138.64 KB)
![](https://oscdn.geek-share.com/Uploads/Images/Content/202006/01/31d9461bc728ba246b9df6b6599bbea7.png)
2012-7-10 22:27 上传
下载附件(173.01 KB)
初步的移植工作就算结束了,这时候我们按退出键游戏就完全退出了,不像SDK,
版本那样可以回到主界面并且有提示对话框,而且不能保存进度,由于初次移植,没有必要要求一步到位,因此我觉得先将游戏功能实现了就可以。剩下的一系列功能我们将一步步实现。敬请期待接下来的Testin
杯libgdx游戏引擎系列教程。
相关文章推荐
- libgdx游戏引擎教程实战篇(二)移植俄罗斯方块(附源码)
- libgdx游戏引擎教程实战篇(四)移植俄罗斯方块(附源码)
- libgdx游戏引擎教程实战篇(六)移植俄罗斯方块(附源码)
- libgdx游戏引擎教程(十三)演员类的用户交互功能详解(附源码)
- libgdx游戏引擎教程(十)演员类的复杂动画(一)(附源码)
- libgdx游戏引擎教程(十四)libgdx中常用的控件(附源码)
- libgdx游戏引擎教程(十一)演员类的复杂动画(二)(附源码)
- libgdx游戏引擎教程(五)多游戏界面的实现(一)附源码
- libgdx游戏引擎教程(八) libgdx中的用户手势识别(一)附源码
- libgdx游戏引擎教程(九) libgdx中的用户手势识别(二)附源码
- 【Android LibGDX游戏引擎开发教程】第06期:图形图像的绘制(下)图片整合工具的使用
- Android游戏引擎libgdx使用教程7:引擎框架总观
- 【Android LibGDX游戏引擎开发教程】第08期:中文字体的显示和绘制(下)
- Android开发_libgdx游戏引擎教程外篇 优美的自定义进度条 (八)
- libgdx游戏引擎教程(二) ApplicationListener,着手第一个程序!
- 发现一个牛人写的android游戏教程——libgdx引擎
- Android游戏引擎libgdx使用教程2:如何绘制图形
- 【Android LibGDX游戏引擎开发教程】第04期:各个模块的详细介绍
- Android游戏引擎libgdx使用教程5:常用UI类与舞台
- 【Android LibGDX游戏引擎开发教程】第09期:动画类的使用