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

转自: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




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


 

我们来看看目前的代码。


 

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


 

有五个部分



 

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



 

2. TetrisGame.java,抽象类Game的实现,用于管理不同的Screen,里面的代码非常短:
  1. public class TetrisGame extends Game {
  2. Screen screen;
  3. @Override
  4. public void create() {
  5. // TODO Auto-generated method stub
  6. setScreen(screen);
  7. }
  8. public TetrisGame(Screen screen) {
  9. super();
  10. // TODO Auto-generated constructor stub
  11. this.screen=screen;
  12. }


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

  2. Texture texture;
  3. TextureRegion background;
  4. SpriteBatch batch;
  5. Texture[] image;
  6. UiActivity activity;
  7. BitmapFont bf;
  8. //用21*10的数组表示21*10的方格
  9. //frame代表已经固定下来的所有方块
  10. int[][] frame=new int [21][10];

  11. //temframe代表固定下来的方块和空中正在飞行的方块的数组,由于还有方块在空中,因此
  12. //此数组一直在变化,我们用它来直接绘图。
  13. int[][] temframe=new int[21][10];

  14. //我们很容易发现所有七中方块都可以画在一个4*4的小方格内
  15. int[][] bricks=new int[4][4];

  16. //当前Brick
  17. Bricks brick;

  18. //随机产生方块
  19. protected Random rand=new Random(6);

  20. //位图数组,用来存储方块图形
  21. boolean isplaying=true;
  22. boolean isflying;
  23. int x;
  24. int y;
  25. int score=0;
  26. //调整难度,这是调整线程睡眠时间的量,值越小,速度越快
  27. long speed=600;
  28. //保存当前屏幕长宽高,用于适配,在我们这个游戏默认竖屏的情况下
  29. int min;
  30. int max;
  31. //还是一样,判断这个Screen是不是第一次显示,只有在第一次显示的时候需要初始化资源
  32. boolean hasini;
  33. //适配触摸灵敏度
  34. int left;
  35. int right;
  36. int roll;
  37. int below;
  38. @Override
  39. public void dispose() {
  40. // TODO Auto-generated method stub

  41. }

  42. @Override
  43. public void hide() {
  44. // TODO Auto-generated method stub
  45. isplaying=false;
  46. }

  47. public GameScreen(UiActivity activity) {
  48. super();
  49. this.activity=activity;
  50. // TODO Auto-generated constructor stub
  51. }

  52. @Override
  53. public void pause() {
  54. // TODO Auto-generated method stub
  55. isplaying=false;
  56. }

  57. @Override
  58. public void render(float arg0) {
  59. // TODO Auto-generated method stub
  60. // TODO Auto-generated method stub
  61. Gdx.gl.glClear(GL10.GL_COLOR_BUFFER_BIT);
  62. Gdx.gl.glClearColor(0f,0f,0f,0f);
  63. //绘图前要调用begin()方法
  64. batch.begin();
  65. batch.draw(background, 0,0);
  66. for(int i=0;i<21;i++)
  67. for(int j=0;j<10;j++)
  68. //根据屏幕大小做了一个简单的适配,只适配了QVGA,HVGA,WVGA
  69. if(temframe[i][j]!=0){
  70. if(max>=320&&max<480){
  71. batch.draw(image[temframe[i][j]-1], (float)(50+14*j), max-(float)(25+14*(i+1)),14,14);
  72. bf.draw(batch,"得分"+score, 210f, 200f);
  73. }
  74. if(max>=480&&max<800){
  75. batch.draw(image[temframe[i][j]-1], (float)(80+16*j), max- (float)(70+16*(i+1)),16,16);
  76. bf.draw(batch, "得分"+score, 280, 320);
  77. }
  78. if(max>=800){
  79. batch.draw(image[temframe[i][j]-1], (float)(100+28*j),max-(float)(120+28*(i+1)),28,28);
  80. bf.draw(batch, "得分"+score, 400, 540);
  81. }
  82. }
  83. //结束时要调用end()方法
  84. batch.end();
  85. if(Gdx.input.isTouched()){
  86. int x=Gdx.input.getX();
  87. int y=Gdx.input.getY();
  88. if(x<(min/2)&&((y/x)>(max/min))&&y<(max-max*x/min)){
  89. left++;
  90. if(left%3==0)
  91. toLeft();
  92. }
  93. if(x>(min/2)&&(y/x<(max/min))&&y>(max-max*x/min)){
  94. right++;
  95. if(right%3==0)
  96. toRight();
  97. }
  98. if(((y/x)<(max/min))&&y<(max-max*x/min)){
  99. roll++;
  100. if(roll%3==0)
  101. roll();
  102. }
  103. if(((y/x)>(max/min))&&y>(max-max*x/min)){
  104. below++;
  105. if(below%2==0)
  106. toBelow();
  107. }
  108. }

  109. }

  110. @Override
  111. public void resize(int arg0, int arg1) {
  112. // TODO Auto-generated method stub

  113. }

  114. @Override
  115. public void resume() {
  116. // TODO Auto-generated method stub

  117. }

  118. @Override
  119. public void show() {
  120. int width=Gdx.graphics.getWidth();
  121. int height=Gdx.graphics.getHeight();
  122. max=width>height?width:height;
  123. min=width>height?height:width;
  124. isplaying=true;
  125. //还是一样,做一个简单的适配
  126. if(max>=320&&max<480)
  127. max=320;
  128. if(max>=480&&max<800)
  129. max=480;
  130. if(max>=800)
  131. max=800;
  132. // TODO Auto-generated method stub
  133. new Thread(new Runnable() {

  134. @Override
  135. public void run() {
  136. // TODO Auto-generated method stub
  137. try{
  138. while(isplaying==true){
  139. if(!isflying){
  140. switch((int) Math.round(Math.random() * 7)){
  141. case 0:brick=new COBrick((int) rand.nextInt(6));System.out.println("O!"+brick.color);break;
  142. case 1:brick=new CLBrick((int) rand.nextInt(6));System.out.println("L!"+brick.color);break;
  143. case 2:brick=new CLLBrick((int) rand.nextInt(6));System.out.println("LL!"+brick.color);break;
  144. case 3:brick=new CSBrick((int) rand.nextInt(6));System.out.println("S!"+brick.color);break;
  145. case 4:brick=new CSSBrick((int) rand.nextInt(6));System.out.println("SS!"+brick.color);break;
  146. case 5:brick=new CIBrick((int) rand.nextInt(6));System.out.println("I!"+brick.color);break;
  147. case 6:brick=new CCBrick((int) rand.nextInt(6));System.out.println("C!"+brick.color);break;
  148. }
  149. x=0;
  150. y=3;
  151. isflying=true;
  152. try{
  153. bricks=brick.checkori(brick.ori);
  154. }catch(NullPointerException e){
  155. brick=new CSSBrick((int) rand.nextInt(6));
  156. bricks=brick.checkori(brick.ori);
  157. }
  158. }
  159. toBelow();
  160. Thread.sleep(speed);
  161. }
  162. }catch (InterruptedException e){

  163. }
  164. }
  165. }).start();
  166. if(!hasini){
  167. batch=new SpriteBatch();
  168. image=new Texture[6];
  169. bf=new BitmapFont();
  170. //初始化背景图片
  171. texture=new Texture(Gdx.files.internal("background2"+max+".png"));
  172. background=new TextureRegion(texture,0,0,min,max);
  173. //初始化方块图片
  174. for(int i=1;i<=6;i++){
  175. image[i-1]=new Texture(Gdx.files.internal(i+".png"));
  176. hasini=true;
  177. }
  178. }
  179. }
  180. //向左移动
  181. public void toLeft(){
  182. if(checkcollide(x,((int)(y-1)),bricks,frame)){
  183. System.out.print("Left");
  184. y-=1;
  185. copy();
  186. }
  187. }
  188. //向右移动
  189. public void toRight(){
  190. if(checkcollide(x,((int)(y+1)),bricks,frame)){
  191. y+=1;
  192. copy();
  193. }

  194. }
  195. //向下移动
  196. public void toBelow(){
  197. System.out.println("In below!");
  198. try{
  199. if(bricks!=null){
  200. if(checkcollide(((int)(x+1)),y,bricks,frame)){
  201. x+=1;
  202. copy();
  203. }
  204. else {
  205. if(checkfull()){
  206. UiActivity.gameover=true;
  207. }
  208. for(int i=0;i<4;i++)
  209. for(int j=0;j<4;j++){
  210. if(bricks[i][j]!=0)
  211. frame[x+i][y+j]=bricks[i][j];
  212. }
  213. isflying=false;
  214. bricks=null;
  215. for(int i=0;i<21;i++){
  216. int flag=1;
  217. for(int j=0;j<10;j++){
  218. if(frame[i][j]==0)
  219. flag=0;
  220. }
  221. if(flag==1){
  222. for(int k=i;k>0;k--)
  223. frame[k]=frame[k-1].clone();
  224. for(int p=0;p<10;p++)
  225. frame[0][p]=0;
  226. score+=100;
  227. }
  228. }
  229. }
  230. }
  231. }catch(NullPointerException e){
  232. e.printStackTrace();
  233. }
  234. }
  235. //旋转
  236. public void roll(){
  237. if(checkcollide(x,y,brick.checkori((int)(brick.ori+1)),frame)){
  238. brick.ori+=1;
  239. bricks=brick.checkori(brick.ori);
  240. copy();
  241. }

  242. }
  243. //更新temframe里的内容,用于实时绘图
  244. public void copy(){
  245. for(int k=0;k<21;k++)
  246. temframe[k]=frame[k].clone();
  247. for(int i=0;i<4;i++)
  248. for(int j=0;j<4;j++)
  249. if(bricks[i][j]!=0&&temframe[x+i][y+j]==0)
  250. temframe[x+i][y+j]=bricks[i][j];
  251. }
  252. public boolean checkcollide(int x,int y,int[][]bricks,int[][]frame){
  253. if(bricks!=null)
  254. {
  255. int max_x=0,min_x=3,max_y=0,min_y=3;
  256. boolean collide=true;
  257. for(int i=0;i<4;i++)
  258. for(int j=0;j<4;j++)
  259. if(bricks[i][j]!=0){
  260. if(j<min_y)
  261. min_y=j;
  262. if(j>max_y)
  263. max_y=j;
  264. if(i>max_x)
  265. max_x=i;
  266. if(i<min_x)
  267. min_x=i;
  268. }
  269. if((max_x+x)>20||(max_y+y)>10||y+min_y<0)
  270. collide=false;
  271. try{
  272. int i;
  273. int j;
  274. for(i=0;i<=max_x;i++)
  275. for(j=min_y;j<=max_y;j++)
  276. if(bricks[i][j]!=0&&frame[x+i][y+j]!=0){
  277. collide=false;
  278. }
  279. }catch(ArrayIndexOutOfBoundsException e){
  280. return false;
  281. }
  282. return collide;
  283. }
  284. return false;
  285. }
  286. //判断是否方块到顶,游戏结束
  287. public boolean checkfull(){
  288. for(int i=0;i<21;i++)
  289. for(int j=0;j<10;j++){
  290. if(temframe[i][j]!=frame[i][j])
  291. return false;
  292. }
  293. return true;
  294. }

  295. public void save(String fileName, String fileContent) throws Exception {
  296. FileOutputStream fileOutputStream = activity.openFileOutput(
  297. fileName, Context.MODE_PRIVATE);
  298. fileOutputStream.write(fileContent.getBytes());
  299. }
  300. public String read(String fileName) throws Exception {
  301. FileInputStream fileInputStream = activity.openFileInput(fileName);
  302. ByteArrayOutputStream byteArray = new ByteArrayOutputStream();

  303. byte[] buffer = new byte[1024];
  304. int len = 0;
  305. while ((len = fileInputStream.read(buffer)) > 0) {
  306. byteArray.write(buffer, 0, len);
  307. };
  308. return byteArray.toString();
  309. }
  310. public void savedata(){
  311. String framedata="";
  312. for(int i=0;i<21;i++)
  313. for(int j=0;j<10;j++){
  314. framedata+=Integer.toString(frame[i][j])+",";
  315. }
  316. framedata+=Integer.toString(score);
  317. try {
  318. save("Tetris_slide.txt",framedata);
  319. } catch (Exception e) {
  320. // TODO Auto-generated catch block
  321. e.printStackTrace();
  322. }
  323. }

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



 

4. UiScreen.java,这就是主界面Screen,样式如下图,我们对按钮添加了监听器,设置按下去的时候切换到游戏界面。注意,其中有大量的分辨率适配的代码,当然我们还是做一个简单的适配,只适配QVGA,HVGA,WVGA(其实FWVGA显示也没有什么问题)
  1. public class UiScreen implements Screen {
  2. Texture texture;
  3. TextureRegion background;
  4. boolean hasini;
  5. SpriteBatch batch;
  6. Stage stage;
  7. Button start;
  8. int width;
  9. int height;
  10. //边长的最大值和最小值
  11. int max;
  12. int min;
  13. Texture tx1;
  14. Texture tx2;
  15. Texture tx3;
  16. UiActivity activity;


  17. public UiScreen(UiActivity activity){
  18. super();
  19. this.activity=activity;
  20. // TODO Auto-generated constructor stub
  21. }

  22. @Override
  23. public void dispose() {
  24. // TODO Auto-generated method stub

  25. }

  26. @Override
  27. public void hide() {
  28. // TODO Auto-generated method stub
  29. }

  30. @Override
  31. public void pause() {
  32. // TODO Auto-generated method stub
  33. }

  34. @Override
  35. public void render(float arg0) {
  36. // TODO Auto-generated method stub
  37. Gdx.gl.glClear(GL10.GL_COLOR_BUFFER_BIT);
  38. Gdx.gl.glClearColor(0f,0f,0f,0f);

  39. batch.begin();
  40. batch.draw(background,0,0,min,max);
  41. batch.end();

  42. //舞台绘制要在背景绘制之后,不然背景会覆盖在按钮表面,我们就看不到按钮了
  43. stage.act(Gdx.graphics.getDeltaTime());
  44. stage.draw();
  45. }

  46. @Override
  47. public void resize(int arg0, int arg1) {
  48. // TODO Auto-generated method stub

  49. }

  50. @Override
  51. public void resume() {
  52. // TODO Auto-generated method stub

  53. }


  54. @Override
  55. public void show() {
  56. // TODO Auto-generated method stub

  57. //做一个简单的适配。这里解释一下为什么不直接令max=height,原因在于有时候我们从锁屏回到游戏,
  58. //从横屏切换到竖屏或者从竖屏切换到横屏的时候,libGdx有时候会来不及切换,也就是说我们可能
  59. //getWidth得到的是实际的height值,getHeight得到的是实际的width值,所以这里增加一个长宽哪一个
  60. //更大的语句,这样就不会出错了
  61. width=Gdx.graphics.getWidth();
  62. height=Gdx.graphics.getHeight();
  63. max=width>height?width:height;
  64. min=width>height?height:width;
  65. //再做一个简单的适配
  66. if(max>=320&&max<480)
  67. max=320;
  68. if(max>=480&&max<800)
  69. max=480;
  70. if(max>=800)
  71. max=800;
  72. if(!hasini){
  73. batch=new SpriteBatch();
  74. stage=new Stage(min,max,true);
  75. texture=new Texture(Gdx.files.internal("background"+max+".jpg"));

  76. //新建一个Button

  77. tx2 = new Texture(Gdx.files.internal("button1.png"));
  78. tx1 = new Texture(Gdx.files.internal("button2.png"));
  79. tx3 = new Texture(Gdx.files.internal("button3.png"));
  80. NinePatch n1 = new NinePatch(tx1, 14, 14, 18, 18);
  81. NinePatch n2 = new NinePatch(tx2, 14, 14, 18, 18);
  82. NinePatch n3 = new NinePatch(tx3, 14, 14, 18, 18);
  83. start= new Button( new ButtonStyle(n1, n2, n3, 0f, 0f, 0f, 0f), "Start");
  84. start.setClickListener(new ClickListener() {

  85. @Override
  86. public void click(Actor arg0, float arg1, float arg2) {
  87. // TODO Auto-generated method stub
  88. activity.tg.setScreen(activity.gs);
  89. }
  90. });
  91. //让按钮的位置处在正中间
  92. start.x=(min-tx2.getWidth())/2;
  93. stage.addActor(start);

  94. //重点在这条语句,我们只取了texture的一部分,红色的多余部分我们没有取
  95. background=new TextureRegion(texture, 0, 0, min, max);
  96. hasini=true;
  97. }
  98. //这句话是必须的,而且在if(hasini)之外,无论资源是否加载完成,每次显示的时候我们都养将当前屏幕
  99. //设置能够接受用户输入
  100. Gdx.input.setInputProcessor(stage);
  101. }

  102. }
复制代码
5.UiActivity.java,这就是一个AndroidApplication了,代码也很简单,直接贴出来
  1. public class UiActivity extends AndroidApplication {
  2. TetrisGame tg;
  3. UiScreen us;
  4. GameScreen gs;
  5. static boolean gameover;
  6. @Override
  7. public void onCreate(Bundle savedInstanceState) {
  8. super.onCreate(savedInstanceState);
  9. requestWindowFeature(Window.FEATURE_NO_TITLE);
  10. getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
  11. WindowManager.LayoutParams.FLAG_FULLSCREEN);
  12. gs=new GameScreen(this);
  13. us=new UiScreen(this);
  14. tg=new TetrisGame(us);
  15. initialize(tg, true);
  16. }
  17. }
复制代码
14.png
2012-7-10 22:27 上传
下载附件(138.64 KB)
17.png
2012-7-10 22:27 上传
下载附件(173.01 KB)



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

版本那样可以回到主界面并且有提示对话框,而且不能保存进度 ,由于初次移植,没有必要要求一步到位,因此我觉得先将游戏功能实现了就可以。剩下的一系列功能我们将一步步实现。敬请期待接下来的Testin 杯libgdx游戏引擎系列教程。

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值