转自:http://www.apkbus.com/android-58419-1-1.html
接着实战第四讲,我们做一个总结(手都要断了啊!!!TAT)。
SDK版俄罗斯方块源码下载(我们移植工作的素材)
Tetris_slide.rar(537.04 KB, 下载次数: 42)
实战一到五移植后的源码:
libgdxTetris.rar(3.93 MB, 下载次数: 92)
初步的移植其实已经完成了。
当然我们现在还有一些移植进来的函数没有用到,比如save(),read()函数等等,因为这些函数都是保存进度,读取进度的时候用的,我们先实现游戏功能,其他的我们一步步来。
我们来看看目前的代码。
![16.jpg 16.jpg](http://www.apkbus.com/data/attachment/forum/201207/10/2222333ejpesme5w3qs8eq.jpg)
有五个部分
1. Bricks.java,这个类我们是直接从原来的工程中复制过来的,没有做任何的修改。
2. TetrisGame.java,抽象类Game的实现,用于管理不同的Screen,里面的代码非常短:
- 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;
- }
- }
3. GameScreen.java,这是游戏主界面,由一个TetrisGame管理,修改后的代码如下(里面有的方法暂时没有用到,是直接从原项目中拿过来的,比如存档功能我们将用到这些函数,而这些功能的实现我们将在后面慢慢加上)。注意,其中有大量的分辨率适配的代码,当然我们还是做一个简单的适配,只适配QVGA,HVGA,WVGA(其实FWVGA显示也没有什么问题)。
- 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();
- }
- }
- }
其中写了大量的注释,这里没有做过多的解释,至于其各个方法的意思,想来光是看这些方法的名字也就能知道,我们这几讲的主要目的是实现一个现成的SDK版本的俄罗斯方块的代码的移植工作,
至于SDK版本是怎么实现的,大家可以看看两个版本的代码,并做一些比对,就很容易看出来了。
4. UiScreen.java,这就是主界面Screen,样式如下图,我们对按钮添加了监听器,设置按下去的时候切换到游戏界面。注意,其中有大量的分辨率适配的代码,当然我们还是做一个简单的适配,只适配QVGA,HVGA,WVGA(其实FWVGA显示也没有什么问题)
- 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);
- }
- }
5.UiActivity.java,这就是一个AndroidApplication了,代码也很简单,直接贴出来
- 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);
- }
- }
![14.png 14.png](http://www.apkbus.com/data/attachment/forum/201207/10/222702268jso4p51q6vv2o.png)
![17.png 17.png](http://www.apkbus.com/data/attachment/forum/201207/10/22270605e8y8kickitbje3.png)
初步的移植工作就算结束了,这时候我们按退出键游戏就完全退出了,不像SDK,
版本那样可以回到主界面并且有提示对话框,而且不能保存进度
,由于初次移植,没有必要要求一步到位,因此我觉得先将游戏功能实现了就可以。剩下的一系列功能我们将一步步实现。敬请期待接下来的Testin 杯libgdx游戏引擎系列教程。