Android拼图游戏开发全纪录5

今天我们终于可以把这个项目给结束掉啦,有了前几天的准备,相信最后一天还是比较轻松的,国际惯例:

最后要完成的就是我们的主要功能--拼图界面。

布局比较简单,在前几天就已经做好了,现在我们要做的是以下几件事情:

1、计时记步:这个是游戏基本都有的功能,其实也比较简单,记录成功移动的步数、显示一个计时器就行了。

2、处理图片,调整为合适的大小比例:这个方法在前几天已经实现了

3、点击GridView后移动图片:是否能移动的方法已经在前几天实现了

4、判断是否拼图完成:唉,也已经实现了

5、点击原图按钮:显示原图:只要显示一个ImageView就可以了

6、点击重置按钮:将传进来的这张图片重新处理一遍流程

基本思路写完了,看来很复杂的事情,是不是梳理下就觉得很简单了,很多准备工作做好了,会让我们的思路变的更清晰。

package com.xys.xpuzzle.activity;

import java.io.File;
import java.util.ArrayList;
import java.util.List;
import java.util.Timer;
import java.util.TimerTask;

import android.app.Activity;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.animation.Animation;
import android.view.animation.AnimationUtils;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.Button;
import android.widget.GridView;
import android.widget.ImageView;
import android.widget.RelativeLayout;
import android.widget.RelativeLayout.LayoutParams;
import android.widget.TextView;
import android.widget.Toast;

import com.xys.xpuzzle.R;
import com.xys.xpuzzle.adapter.GridItemsAdapter;
import com.xys.xpuzzle.bean.ItemBean;
import com.xys.xpuzzle.util.GameUtil;
import com.xys.xpuzzle.util.ImagesUtil;
import com.xys.xpuzzle.util.ScreenUtil;

/**
 * 拼图逻辑主界面:面板显示
 *
 * @author xys
 *
 */
public class PuzzleMain extends Activity implements OnClickListener {

    // 选择的图片
    private Bitmap picSelected;
    // 拼图完成时显示的最后一个图片
    public static Bitmap lastBitmap;
    // PuzzlePanel
    private GridView gv_puzzle_main_detail;
    private int resId;
    private String picPath;
    private ImageView imageView;
    // Button
    private Button btnBack;
    private Button btnImage;
    private Button btnRestart;
    // 显示步数
    private TextView tv_puzzle_main_counts;
    // 计时器
    private TextView tv_Timer;
    // 切图后的图片
    private List<Bitmap> bitmapItemLists = new ArrayList<Bitmap>();
    // GridView适配器
    private GridItemsAdapter adapter;
    // 设置为N*N显示
    public static int type = 2;
    // Flag 是否已显示原图
    private boolean isShowImg;
    // 步数显示
    public static int countIndex = 0;
    // 计时显示
    public static int timerIndex = 0;
    // 计时器类
    private Timer timer;

    /**
     * UI更新Handler
     */
    private Handler handler = new Handler() {

	@Override
	public void handleMessage(Message msg) {
	    switch (msg.what) {
	    case 1:
		// 更新计时器
		timerIndex++;
		tv_Timer.setText("" + timerIndex);
		break;
	    default:
		break;
	    }
	}
    };

    /**
     * 计时器线程
     */
    private TimerTask timerTask;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
	super.onCreate(savedInstanceState);
	setContentView(R.layout.xpuzzle_puzzle_detail_main);
	// 获取选择的图片
	Bitmap picSelectedTemp;
	// 选择默认图片还是自定义图片
	resId = getIntent().getExtras().getInt("picSelectedID");
	picPath = getIntent().getExtras().getString("picPath");
	if (resId != 0) {
	    picSelectedTemp = BitmapFactory.decodeResource(getResources(), resId);
	} else {
	    picSelectedTemp = BitmapFactory.decodeFile(picPath);
	}
	type = getIntent().getExtras().getInt("type", 2);
	// 对图片处理
	handlerImage(picSelectedTemp);
	// 初始化Views
	initViews();
	// 生成游戏数据
	generateGame();
	// GridView点击事件
	gv_puzzle_main_detail.setOnItemClickListener(new OnItemClickListener() {

	    @Override
	    public void onItemClick(AdapterView<?> arg0, View view, int position, long arg3) {
		// 判断是否可移动
		if (GameUtil.isMoveable(position)) {
		    // 交换点击Item与空格的位置
		    GameUtil.swapItems(GameUtil.itemBeans.get(position), GameUtil.blankItemBean);
		    // 重新获取图片
		    recreateData();
		    // 通知GridView更改UI
		    adapter.notifyDataSetChanged();
		    // 更新步数
		    countIndex++;
		    tv_puzzle_main_counts.setText("" + countIndex);
		    // 判断是否成功
		    if (GameUtil.isSuccess()) {
			// 将最后一张图显示完整
			recreateData();
			bitmapItemLists.remove(type * type - 1);
			bitmapItemLists.add(lastBitmap);
			// 通知GridView更改UI
			adapter.notifyDataSetChanged();
			Toast.makeText(PuzzleMain.this, "拼图成功!", Toast.LENGTH_LONG).show();
			gv_puzzle_main_detail.setEnabled(false);
			timer.cancel();
			timerTask.cancel();
		    }
		}
	    }
	});
	// 返回按钮点击事件
	btnBack.setOnClickListener(this);
	// 显示原图按钮点击事件
	btnImage.setOnClickListener(this);
	// 重置按钮点击事件
	btnRestart.setOnClickListener(this);
    }

    /**
     * Button点击事件
     */
    @Override
    public void onClick(View v) {
	switch (v.getId()) {
	// 返回按钮点击事件
	case R.id.btn_puzzle_main_back:
	    PuzzleMain.this.finish();
	    break;
	// 显示原图按钮点击事件
	case R.id.btn_puzzle_main_img:
	    Animation animShow = AnimationUtils.loadAnimation(PuzzleMain.this, R.anim.image_show_anim);
	    Animation animHide = AnimationUtils.loadAnimation(PuzzleMain.this, R.anim.image_hide_anim);
	    if (isShowImg) {
		imageView.startAnimation(animHide);
		imageView.setVisibility(View.GONE);
		isShowImg = false;
	    } else {
		imageView.startAnimation(animShow);
		imageView.setVisibility(View.VISIBLE);
		isShowImg = true;
	    }
	    break;
	// 重置按钮点击事件
	case R.id.btn_puzzle_main_restart:
	    cleanConfig();
	    generateGame();
	    recreateData();
	    // 通知GridView更改UI
	    tv_puzzle_main_counts.setText("" + countIndex);
	    adapter.notifyDataSetChanged();
	    gv_puzzle_main_detail.setEnabled(true);
	    break;
	default:
	    break;
	}
    }

    /**
     * 生成游戏数据
     */
    private void generateGame() {
	// 切图 获取初始拼图数据 正常顺序
	new ImagesUtil().createInitBitmaps(type, picSelected, PuzzleMain.this);
	// 生成随机数据
	GameUtil.getPuzzleGenerator();
	// 获取Bitmap集合
	for (ItemBean temp : GameUtil.itemBeans) {
	    bitmapItemLists.add(temp.getBitmap());
	}

	// 数据适配器
	adapter = new GridItemsAdapter(this, bitmapItemLists);
	gv_puzzle_main_detail.setAdapter(adapter);

	// 启用计时器
	timer = new Timer(true);
	// 计时器线程
	timerTask = new TimerTask() {

	    @Override
	    public void run() {
		Message msg = new Message();
		msg.what = 1;
		handler.sendMessage(msg);
	    }
	};
	// 每1000ms执行 延迟0s
	timer.schedule(timerTask, 0, 1000);
    }

    /**
     * 添加显示原图的View
     */
    private void addImgView() {
	RelativeLayout relativeLayout = (RelativeLayout) findViewById(R.id.rl_puzzle_main_main_layout);
	imageView = new ImageView(PuzzleMain.this);
	imageView.setImageBitmap(picSelected);
	int x = (int) (picSelected.getWidth() * 0.9F);
	int y = (int) (picSelected.getHeight() * 0.9F);
	LayoutParams params = new LayoutParams(x, y);
	params.addRule(RelativeLayout.CENTER_IN_PARENT);
	imageView.setLayoutParams(params);
	relativeLayout.addView(imageView);
	imageView.setVisibility(View.GONE);
    }

    /**
     * 返回时调用
     */
    @Override
    protected void onStop() {
	super.onStop();
	// 清空相关参数设置
	cleanConfig();
	this.finish();
    }

    /**
     * 清空相关参数设置
     */
    private void cleanConfig() {
	// 清空相关参数设置
	GameUtil.itemBeans.clear();
	// 停止计时器
	timer.cancel();
	timerTask.cancel();
	countIndex = 0;
	timerIndex = 0;
	// 清除拍摄的照片
	if (picPath != null) {
	    // 删除照片
	    File file = new File(MainActivity.TEMP_IMAGE_PATH);
	    if (file.exists()) {
		file.delete();
	    }
	}
    }

    /**
     * 重新获取图片
     */
    private void recreateData() {
	bitmapItemLists.clear();
	for (ItemBean temp : GameUtil.itemBeans) {
	    bitmapItemLists.add(temp.getBitmap());
	}
    }

    /**
     * 对图片处理 自适应大小
     *
     * @param bitmap
     */
    private void handlerImage(Bitmap bitmap) {
	// 将图片放大到固定尺寸
	int screenWidth = ScreenUtil.getScreenSize(this).widthPixels;
	int screenHeigt = ScreenUtil.getScreenSize(this).heightPixels;
	picSelected = new ImagesUtil().resizeBitmap(screenWidth * 0.8f, screenHeigt * 0.6f, bitmap);
    }

    /**
     * 初始化Views
     */
    private void initViews() {
	// Button
	btnBack = (Button) findViewById(R.id.btn_puzzle_main_back);
	btnImage = (Button) findViewById(R.id.btn_puzzle_main_img);
	btnRestart = (Button) findViewById(R.id.btn_puzzle_main_restart);
	// Flag 是否已显示原图
	isShowImg = false;

	// GV
	gv_puzzle_main_detail = (GridView) findViewById(R.id.gv_puzzle_main_detail);
	// 设置为N*N显示
	gv_puzzle_main_detail.setNumColumns(type);
	LayoutParams gridParams = new RelativeLayout.LayoutParams(picSelected.getWidth(), picSelected.getHeight());
	// 水平居中
	gridParams.addRule(RelativeLayout.CENTER_HORIZONTAL);
	// 其他格式属性
	gridParams.addRule(RelativeLayout.BELOW, R.id.ll_puzzle_main_spinner);
	// Grid显示
	gv_puzzle_main_detail.setLayoutParams(gridParams);
	gv_puzzle_main_detail.setHorizontalSpacing(0);
	gv_puzzle_main_detail.setVerticalSpacing(0);

	// TV步数
	tv_puzzle_main_counts = (TextView) findViewById(R.id.tv_puzzle_main_counts);
	tv_puzzle_main_counts.setText("" + countIndex);
	// TV计时器
	tv_Timer = (TextView) findViewById(R.id.tv_puzzle_main_time);
	tv_Timer.setText("0秒");

	// 添加显示原图的View
	addImgView();
    }
}

自认为注释、代码风格还是不错的,希望大家喜欢。

PS:需要源代码的朋友请留言,其实根据这个思路自己去实现下,对自己是有很大提高的,如果能优化我的代码,那就更好了,可以一起学习交流下。

时间: 2024-10-18 20:19:31

Android拼图游戏开发全纪录5的相关文章

Android拼图游戏开发全纪录0

最近刚完成一个Android的小项目--拼图游戏.项目并不复杂,但也是一个完整的项目,用到的知识点还是比较丰富的. 做完之后照例进行下总结: 需求定义: 1.选择图片后进入拼图界面,可以选择默认图片或者自定义图片,即从图库选择或者从相机拍照. 2.可以设置游戏的难度,即选择拼图为NXN结构. 3.自动打乱拼图的顺序,利用倒置和算法,确保生成的数据有解. 4.拼图过程中可以查看原图. 5.拼图具有计时.记步功能. 6.完成拼图后显示全部图片并提升拼图成功. 7.可以查看历史记录. *8.利用IDA

Android拼图游戏开发全纪录2

今天我们主要来讨论下拼图游戏的可行性解的问题,其实不要小看拼图游戏,他其实是人工智能算法中很著名的15puzzle问题,网上已经有很多关于这个问题的解释,我就做个搬运工好了. 随机生成的15puzzle大约有%50是无解的,本文将就随机生成的谜题的可解性加以讨论. 设有如下矩阵: 12 1 10 2 7 11 4 14 5 x 9 15 8 13 6 3 将其排成水平的,有:12,1,10,2,7,11,4,14,5,X,9,15,8,13,6,3.并记该序列为A 定义:"倒置变量值"

Android拼图游戏开发全纪录3

今天我们要继续开发Android游戏拼图,今天同样是做一些准备工作,昨天我们把界面的准备工作做好了,今天呢,我们想想,要完成一个拼图,我们还需要做哪些准备. 首先,我们需要一个工具类,去获取屏幕的相关信息,让我们的程序去自动适应不同分辨率大小的屏幕: package com.xys.xpuzzle.util; import android.content.Context; import android.util.DisplayMetrics; import android.view.Displa

Android拼图游戏开发全纪录4

今天我们主要实现我们的主界面:国际惯例: 界面我们已经在第一天做好了,今天我们就要实现这个界面的功能, 分析一下,这个界面包含以下几个功能: 1.显示游戏的难度:使用popupwindow,选择后改变显示的数字 2.显示默认的待拼图图片,包含一张选择自定义的图片:这个比较简单,只是GridView的最简单应用而已 3.自定义按钮功能:调用系统图册和相机 4.查看记录和了解更多:这个也是一般的应用需求,比较简单 package com.xys.xpuzzle.activity; import ja

Android拼图游戏的设计逻辑,从切图到交互动画,从关卡到倒计时,实例提高!

Android拼图游戏的设计逻辑,从切图到交互动画,从关卡到倒计时,实例提高! 群英传的最后一章,我大致的看了一下这个例子,发现鸿洋大神也做过,就参考两个人的设计逻辑,感觉都差不多,就这样实现起来了 一.切图工具类 我们九宫格嘛,肯定要一个切图的工具,把一个图片给切成九张,那具体是怎么实现呢?我们先写一个bean来存储一切的状态 ImagePiece package com.lgl.ninegame.utils; import android.graphics.Bitmap; /** * * C

《Android 3D游戏开发技术宝典——OpenGL ES 2.0》——2.5节2D动画的开发

2.5 2D动画的开发 Android 3D游戏开发技术宝典--OpenGL ES 2.0 虽然本书是着重介绍3D的开发技术,但在大部分的3D应用中也需要有不少的2D界面,如菜单.帮助等.本节将介绍一般用于开发游戏中2D界面的SurfaceView类的使用.其继承自View类,但与View的不同之处在于,View更新画面必须是在UI线程中(也可以理解为主线程中),而SurfaceView更新画面可以在自定义线程中进行,大大方便了开发. 提示 关于Android下的多线程问题,读者可以参考笔者在人

《Android 3D游戏开发技术宝典——OpenGL ES 2.0》——1.5节Android应用程序运行的机制

1.5 Android应用程序运行的机制 Android 3D游戏开发技术宝典--OpenGL ES 2.0 上一节介绍了如何搭建Android开发环境.如何开发Hello Android应用程序以及Android应用程序的调试,接下来在本节中将简要地介绍Android应用程序的运行机制. 1.5.1 应用程序的系统架构 Android平台由应用程序.应用程序框架.Android运行时.系统库以及底层Linux内核构成,详细结构如图1-54所示. 说明 应用程序层里面包含的就是需要读者去发挥创意

《Android 3D游戏开发技术宝典——OpenGL ES 2.0》——1.4节Hello Android应用程序的开发

1.4 Hello Android应用程序的开发 Android 3D游戏开发技术宝典--OpenGL ES 2.0 本节首先将介绍如何在Eclipse中创建一个基于Android的Hello World应用程序,之后将简单介绍Android应用程序的调试,为读者以后学习高级开发铺平道路. 1.4.1 第一个Android应用程序 本小节将向读者介绍如何在Eclipse中创建一个基于Android的Hello World应用程序,基本步骤如下所列. (1)首先打开Eclipse,然后依次选择Fi

《Android 3D游戏开发技术宝典——OpenGL ES 2.0》——2.1节游戏中的音效

2.1 游戏中的音效 Android 3D游戏开发技术宝典--OpenGL ES 2.0 一款好游戏,除了具备优质的画面和较高的可玩性之外,还应该有出色的音效.音效一般指的是游戏中发生特定行为或进行特定操作时播放的效果音乐或为了渲染整体气氛播放的背景音,如远处隆隆的炮声.怪物死亡的惨叫声.由远而近的脚步声等. 通过开发人员精心准备的声音特效,结合游戏的场景,可以渲染出一种紧张刺激的氛围,使玩家产生身临其境的感觉.这就像电影中的声音特效一样,假如没有了合适的音效,那么游戏和电影一样,真实感会大打折