Android 完成拼图后就可抽奖游戏开发
发布日期:2021-06-30 22:37:19 浏览次数:2 分类:技术文章

本文共 37641 字,大约阅读时间需要 125 分钟。

一、概述:

1、如果开发简单的游戏不使用Cocos2d的话,最简单的方法就是使用surfaceview绘制游戏界面了,然后依次绘制各类控件

2、本游戏包含两部分,第一部分是拼图游戏的开发,第二部分是抽奖游戏部分的开发
如图:
这里写图片描述

二、拼图游戏的原理:

1)在asset文件里放置几张图片,然后使用随机方法调出里面的图片

Random random = new Random();int nextIndex = random.nextInt(4);mBitmap = BitmapUtil.getImageFromAssetsFile(getContext(), "g" + nextIndex + ".jpg");

2)把调出来的图片进行分割,这里使用了网上流行的类

/** * 图片切割 * @Project    App_View * @Package    com.android.view.puzzle * @author     chenlin * @version    1.0 * @Date       2015年5月20日 */public class ImageSplitter {
public static List
split(Bitmap bm, int piece) { //获得piece * piece大小的集合 List
pieces = new ArrayList
(piece * piece); //原来图片的宽高 int width = bm.getWidth(); int height = bm.getHeight(); //取最小的才能生成正方形的图片 int pieceWidth = Math.min(width, height) / piece; // piece = 6 for (int i = 0; i < piece; i++) { for (int j = 0; j < piece; j++) { ImagePiece imagePiece = new ImagePiece(); // i =0 j=0,1,2,3,4,5 index = 0,1,2,3,4,5 // i =1 j=0,1,2,3,4,5 index = 6,7,8,9,10,11 // i =2 j=0,1,2,3,4,5 index = 12, imagePiece.index = j + i * piece; //指的是坐标位置 i = 0; j=0,1,2,3,4,5 ,从横向创建图片 int xPos = j * pieceWidth;//当i=0时,从0,1,2,3,4,5开始添加图片 int yPos = i * pieceWidth;//此时y坐标不变 imagePiece.bitmap = Bitmap.createBitmap(bm, xPos, yPos, pieceWidth, pieceWidth); pieces.add(imagePiece); } } return pieces; }}

3)然后打乱图片的原来的循序

mItemBitmaps = ImageSplitter.split(mBitmap, mColumn);Logger.i(TAG, "mItemBitmaps.size()=" + mItemBitmaps.size());// 打乱集合里图片的顺序Collections.sort(mItemBitmaps, new Comparator
() { @Override public int compare(ImagePiece lhs, ImagePiece rhs) { return Math.random() > 0.5 ? 1 : -1; }});

4)在onMeasure方法里初始化

首先得到每个控件的宽度

// 得到子控件的宽度mItemWidth = (mWidth - 2 * mPadding - (mColumn - 1) * mMargin) / mColumn;

然后创建一个mColumn * mColumn列的ImageView数组

依次把分割的图片设置到里面,并给每张图片设置id,目的是在移动的时候切换图片和判断是否完成拼图

ImagePiece imagePiece = mItemBitmaps.get(i);// 必须初始化,否则会报空指针异常ImageView item = new ImageView(getContext());item.setOnClickListener(this);item.setImageBitmap(imagePiece.bitmap);mItemViews[i] = item;item.setId(i + 1);// 存储索引,以后根据索引来切换图片和判断是否成功!item.setTag(i + "_" + imagePiece.index);

5)做完上面步骤后要开始排列图片,当到达mColumn时,把图片往下排排列

RelativeLayout.LayoutParams param = new RelativeLayout.LayoutParams(mItemWidth, mItemWidth);    // ---设置item的margin------------------------------    // 如果不是最后一列,设置margin,相当于i
0判断 if (i % mColumn != 0) {
// 因为i>0,所以i-1>=0,不会越界 // 把第i个item放置在i-1个item的右边 param.addRule(RelativeLayout.RIGHT_OF, mItemViews[i - 1].getId()); } // 当一行的数目大于mColumn时,item就往下一行排列 if ((i + 1) > mColumn) { param.topMargin = mMargin; param.addRule(RelativeLayout.BELOW, mItemViews[i - mColumn].getId()); }

6)最后添加到surfaceview里

addView(item, param);

7)如何实现图片的切换呢?

这里我们使用的是平移动画,在原来的视图上创建一个动画层RelativeLayout

/**     * 创建动画层     */    private RelativeLayout setUpAnimLayout() {        if (mAnimLayout == null) {            mAnimLayout = new RelativeLayout(getContext());            addView(mAnimLayout);        }        return mAnimLayout;    }

然后根据原来的tag得到点击的两张图片,放置到动画层

ImageView first = addItemView((String) mFirst.getTag(), mFirst);ImageView second = addItemView((String) mSecond.getTag(), mSecond);mAnimLayout.addView(first);mAnimLayout.addView(second);

开始平移动画:

// 创建动画,一个是从mFirst到mSecond,另一个是mSecond到mFirstTranslateAnimation anim = tranAnim(first, mSecond, mFirst);tranAnim(second, mFirst, mSecond);anim.setAnimationListener(animationListener);

最后实现动画在监听事件里

private AnimationListener animationListener = new AnimationListener() {        @Override        public void onAnimationStart(Animation animation) {            isAniming = true;            mFirst.setVisibility(View.INVISIBLE);            mSecond.setVisibility(View.INVISIBLE);        }        @Override        public void onAnimationRepeat(Animation animation) {        }        @Override        public void onAnimationEnd(Animation animation) {            String firstTag = (String) mFirst.getTag();            String secondTag = (String) mSecond.getTag();            // 得到在list中索引位置            String[] firstImageIndex = firstTag.split("_");            String[] secondImageIndex = secondTag.split("_");            // 根据索引获得图片,并交换图片            mFirst.setImageBitmap(mItemBitmaps.get(Integer.parseInt(secondImageIndex[0])).bitmap);            mSecond.setImageBitmap(mItemBitmaps.get(Integer.parseInt(firstImageIndex[0])).bitmap);            // 设置标记            mFirst.setTag(secondTag);            mSecond.setTag(firstTag);            mFirst.setVisibility(View.VISIBLE);            mSecond.setVisibility(View.VISIBLE);            mFirst = mSecond = null;            mAnimLayout.removeAllViews();            checkSuccess();            isAniming = false;        }    };

8)平移完成后,如何判断是否成功了,这里的依据是依次得到排列后每个tag里存储的index与图片原来的index对比,如果一致就说明成功了

/**     * 下一关     */    private void nextLevel() {        this.removeAllViews();        mAnimLayout = null;        mColumn++;        if (mColumn > 5) {            showNextDialog("恭喜你,全部过关了!有奖品等着您哦!", "开始抽奖");        } else {            initBitmap();            initItem();        }    }

9)完成后,如果就over了,那就没人玩你开发的游戏了,此时我们要设置下一关

然后重新绘制裁剪图片,增加难度

/**     * 下一关     */    private void nextLevel() {        this.removeAllViews();        mAnimLayout = null;        //增加难度        mColumn++;        if (mColumn > 5) {            showNextDialog("恭喜你,全部过关了!有奖品等着您哦!", "开始抽奖");        } else {            initBitmap();            initItem();        }    }

好了,说了这么多,还没贴上源码

三、拼图游戏的源码

/** * 拼图 *  * @Project App_View * @Package com.android.view.puzzle * @author chenlin * @version 1.0 * @Date 2015年5月20日 * @Note TODO */public class PuzzleView extends RelativeLayout implements OnClickListener {
private static final String TAG = "puzzle"; /** 设置Item的数量n*n;默认为3 */ private int mColumn = 3; /** 布局的宽度 */ private int mWidth; /** padding 整个控件四周的距离 ,不是子view之间的距离 */ private int mPadding; /** 子view横向与纵向的边距 */ private int mMargin = 3; /** 存放所有的Item */ private ImageView[] mItemViews; /** Item的宽度 */ private int mItemWidth; /** 拼图的图片 */ private Bitmap mBitmap; /** 存放切完以后的图片bean */ private List
mItemBitmaps; /** 是否是第一次 */ private boolean once; // -构造方法---------------------------------- public PuzzleView(Context context, AttributeSet attrs) { this(context, attrs, 0); } public PuzzleView(Context context) { this(context, null); } public PuzzleView(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); init(); } // ---初始化----------------------------- private void init() { mMargin = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, mMargin, getResources().getDisplayMetrics()); // 设置Layout的内边距,四边一致,设置为四内边距中的最小值 mPadding = min(getPaddingLeft(), getPaddingTop(), getPaddingRight(), getPaddingBottom()); } /** * 获得最小的整数 * * @param params * @return */ private int min(int... params) { int min = params[0]; for (int p : params) { if (p < min) { min = p; } } return min; } /** * onMeasure里面主要就是获得到布局的宽度,然后进行图片的准备,以及初始化我们的Item,为Item设置宽度和高度 */ @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { super.onMeasure(widthMeasureSpec, heightMeasureSpec); // 这样写是为了横屏时宽度不变 mWidth = Math.min(getMeasuredHeight(), getMeasuredWidth()); if (!once) { initBitmap(); initItem(); } once = true; // 设定子view的大小,因为每个view都是正方形的图片 setMeasuredDimension(mWidth, mWidth); } /** * 准备图片 */ private void initBitmap() { if (mBitmap == null) { // assert文件里读取图片 Random random = new Random(); int nextIndex = random.nextInt(4); mBitmap = BitmapUtil.getImageFromAssetsFile(getContext(), "g" + nextIndex + ".jpg"); Logger.i(TAG, "mBitmap=" + mBitmap); } mItemBitmaps = ImageSplitter.split(mBitmap, mColumn); Logger.i(TAG, "mItemBitmaps.size()=" + mItemBitmaps.size()); // 打乱集合里图片的顺序 Collections.sort(mItemBitmaps, new Comparator
() { @Override public int compare(ImagePiece lhs, ImagePiece rhs) { return Math.random() > 0.5 ? 1 : -1; } }); } private void initItem() { // 得到子控件的宽度 mItemWidth = (mWidth - 2 * mPadding - (mColumn - 1) * mMargin) / mColumn; // 初始化数组 mItemViews = new ImageView[mColumn * mColumn]; // 循环添加子控件到数组里,并添加监听事件及设置宽高 for (int i = 0; i < mItemViews.length; i++) { ImagePiece imagePiece = mItemBitmaps.get(i); // 必须初始化,否则会报空指针异常 ImageView item = new ImageView(getContext()); item.setOnClickListener(this); item.setImageBitmap(imagePiece.bitmap); mItemViews[i] = item; item.setId(i + 1); // 存储索引,以后根据索引来切换图片和判断是否成功! item.setTag(i + "_" + imagePiece.index); RelativeLayout.LayoutParams param = new RelativeLayout.LayoutParams(mItemWidth, mItemWidth); // ---设置item的margin------------------------------ // 如果不是最后一列,设置margin,相当于i
0判断 if (i % mColumn != 0) {
// 因为i>0,所以i-1>=0,不会越界 // 把第i个item放置在i-1个item的右边 param.addRule(RelativeLayout.RIGHT_OF, mItemViews[i - 1].getId()); } // 当一行的数目大于mColumn时,item就往下一行排列 if ((i + 1) > mColumn) { param.topMargin = mMargin; param.addRule(RelativeLayout.BELOW, mItemViews[i - mColumn].getId()); } addView(item, param); } } /** 点击的时候实现图片的交换 */ private ImageView mFirst; private ImageView mSecond; /** 动画运行的标志位 */ private boolean isAniming; @Override public void onClick(View v) { if (isAniming) return; /** * 如果两次点击是同一个 */ if (mFirst == v) { mFirst.setColorFilter(null); mFirst = null; return; } if (mFirst == null) { mFirst = (ImageView) v; mFirst.setColorFilter(Color.parseColor("#55FF0000")); } else { mSecond = (ImageView) v; // 开始交换图片 exchangeView(); } } // ------------------------------------------------------------- /** * 使用值动画交换两个Item的图片 */ private void exchangeView2() { mFirst.setColorFilter(null); AnimatorSet animatorSetFirst = animSet(mFirst, mSecond); animSet(mSecond, mFirst); animatorSetFirst.addListener(animatorListener); } private AnimatorSet animSet(ImageView iv1, ImageView iv2) { AnimatorSet set = new AnimatorSet(); ObjectAnimator animX = ObjectAnimator.ofFloat(iv1, "translationX", 0, iv2.getLeft() - iv1.getLeft()); ObjectAnimator animY = ObjectAnimator.ofFloat(iv1, "translationY", 0, iv2.getTop() - iv1.getTop()); set.playTogether(animX, animY); set.setDuration(300); set.start(); return set; } private AnimatorListener animatorListener = new AnimatorListener() { @Override public void onAnimationStart(Animator animation) { isAniming = true; mFirst.setVisibility(View.INVISIBLE); mSecond.setVisibility(View.INVISIBLE); } @Override public void onAnimationRepeat(Animator animation) { } @Override public void onAnimationEnd(Animator animation) { String firstTag = (String) mFirst.getTag(); String secondTag = (String) mSecond.getTag(); // 得到在list中索引位置 String[] firstImageIndex = firstTag.split("_"); String[] secondImageIndex = secondTag.split("_"); // 根据索引获得图片,并交换图片 mFirst.setImageBitmap(mItemBitmaps.get(Integer.parseInt(secondImageIndex[0])).bitmap); mSecond.setImageBitmap(mItemBitmaps.get(Integer.parseInt(firstImageIndex[0])).bitmap); // 设置标记 mFirst.setTag(secondTag); mSecond.setTag(firstTag); mFirst.setVisibility(View.VISIBLE); mSecond.setVisibility(View.VISIBLE); mFirst = mSecond = null; // mAnimLayout.removeAllViews(); isAniming = false; } @Override public void onAnimationCancel(Animator animation) { } }; /** 动画层 */ private RelativeLayout mAnimLayout; /** * 使用平移动画交换两个Item的图片 */ private void exchangeView() { mFirst.setColorFilter(null); // 创建一个布局,用来做动画层,里面有两个imageview作为添加图片 mAnimLayout = setUpAnimLayout(); ImageView first = addItemView((String) mFirst.getTag(), mFirst); ImageView second = addItemView((String) mSecond.getTag(), mSecond); mAnimLayout.addView(first); mAnimLayout.addView(second); // 创建动画,一个是从mFirst到mSecond,另一个是mSecond到mFirst TranslateAnimation anim = tranAnim(first, mSecond, mFirst); tranAnim(second, mFirst, mSecond); anim.setAnimationListener(animationListener); } private AnimationListener animationListener = new AnimationListener() { @Override public void onAnimationStart(Animation animation) { isAniming = true; mFirst.setVisibility(View.INVISIBLE); mSecond.setVisibility(View.INVISIBLE); } @Override public void onAnimationRepeat(Animation animation) { } @Override public void onAnimationEnd(Animation animation) { String firstTag = (String) mFirst.getTag(); String secondTag = (String) mSecond.getTag(); // 得到在list中索引位置 String[] firstImageIndex = firstTag.split("_"); String[] secondImageIndex = secondTag.split("_"); // 根据索引获得图片,并交换图片 mFirst.setImageBitmap(mItemBitmaps.get(Integer.parseInt(secondImageIndex[0])).bitmap); mSecond.setImageBitmap(mItemBitmaps.get(Integer.parseInt(firstImageIndex[0])).bitmap); // 设置标记 mFirst.setTag(secondTag); mSecond.setTag(firstTag); mFirst.setVisibility(View.VISIBLE); mSecond.setVisibility(View.VISIBLE); mFirst = mSecond = null; mAnimLayout.removeAllViews(); checkSuccess(); isAniming = false; } }; /** * 平移 * * @param iv * @param imageViews * @return */ private TranslateAnimation tranAnim(ImageView iv, ImageView... imageViews) { TranslateAnimation anim = new TranslateAnimation(0, imageViews[0].getLeft() - imageViews[1].getLeft(), 0, imageViews[0].getTop() - imageViews[1].getTop()); anim.setDuration(300); anim.setFillAfter(true); iv.startAnimation(anim); return anim; } /** * 判断是否成功 原理:遍历每个item,对比存储的index是否与i相同 */ protected void checkSuccess() { boolean isSuccess = true; for (int i = 0; i < mItemViews.length; i++) { ImageView item = mItemViews[i]; if (getIndexByTag((String) item.getTag()) != i) { isSuccess = false; } } if (isSuccess) { showNextDialog("恭喜你,过关了!", "下一关"); } } /** * 显示下一关的对话框 */ private void showNextDialog(String content, final String buttonText) { DialogHelper.showDialog(getContext(), content , "提示!", buttonText, new OnDialogListener(){ @Override public void onClick() { if ("下一关".equals(buttonText)) { nextLevel(); }else if ("抽奖".equals(buttonText)) { GameUtil.startActivity(getContext(), PrizeActivity.class); } } }); } /** * 下一关 */ private void nextLevel() { this.removeAllViews(); mAnimLayout = null; mColumn++; if (mColumn > 5) { showNextDialog("恭喜你,全部过关了!有奖品等着您哦!", "开始抽奖"); } else { initBitmap(); initItem(); } } /** * 添加第一个ImageView */ private ImageView addItemView(String tag, ImageView original) { ImageView iv = new ImageView(getContext()); iv.setImageBitmap(mItemBitmaps.get(getImageIndexByTag(tag)).bitmap); LayoutParams params = new LayoutParams(mItemWidth, mItemWidth); params.leftMargin = original.getLeft() - mPadding; params.topMargin = original.getTop() - mPadding; iv.setLayoutParams(params); return iv; } /** * 根据标记获得索引 * * @param tag * @return */ private int getImageIndexByTag(String tag) { String[] strs = tag.split("_"); return Integer.parseInt(strs[0]); } /** * 获得图片的真正索引 * * @param tag * @return */ private int getIndexByTag(String tag) { String[] split = tag.split("_"); return Integer.parseInt(split[1]); } /** * 创建动画层 */ private RelativeLayout setUpAnimLayout() { if (mAnimLayout == null) { mAnimLayout = new RelativeLayout(getContext()); addView(mAnimLayout); } return mAnimLayout; } /** * 交换两个Item的图片 */ private void exchangeView1() { mFirst.setColorFilter(null); String firstTag = (String) mFirst.getTag(); String secondTag = (String) mSecond.getTag(); // 得到在list中索引位置 String[] firstImageIndex = firstTag.split("_"); String[] secondImageIndex = secondTag.split("_"); // 根据索引获得图片,并交换图片 mFirst.setImageBitmap(mItemBitmaps.get(Integer.parseInt(secondImageIndex[0])).bitmap); mSecond.setImageBitmap(mItemBitmaps.get(Integer.parseInt(firstImageIndex[0])).bitmap); // 设置标记 mFirst.setTag(secondTag); mSecond.setTag(firstTag); mFirst = mSecond = null; } // -------------------------------------------------------------- public int getmColumn() { return mColumn; } public void setmColumn(int mColumn) { this.mColumn = mColumn; } public int getmMargin() { return mMargin; } public void setmMargin(int mMargin) { this.mMargin = mMargin; } public Bitmap getmBitmap() { return mBitmap; } public void setmBitmap(Bitmap mBitmap) { this.mBitmap = mBitmap; }}

四、抽奖游戏的原理

1、首先创建一个prizeview继承surfaceview,搭建好基本的框架

import android.content.Context;import android.graphics.Canvas;import android.graphics.PixelFormat;import android.util.AttributeSet;import android.view.SurfaceHolder;import android.view.SurfaceHolder.Callback;import android.view.SurfaceView;public class PrizeView extends SurfaceView implements Callback, Runnable{
private SurfaceHolder mHolder; /** * 与SurfaceHolder绑定的Canvas */ private Canvas mCanvas; /** * 用于绘制的线程 */ private Thread t; /** * 线程的控制开关 */ private boolean isRunning; public PrizeView (Context context) { this(context, null); } public PrizeView (Context context, AttributeSet attrs) { super(context, attrs); mHolder = getHolder(); mHolder.addCallback(this); setZOrderOnTop(true);// 设置画布 背景透明 mHolder.setFormat(PixelFormat.TRANSLUCENT); // 设置可获得焦点 setFocusable(true); setFocusableInTouchMode(true); // 设置常亮 this.setKeepScreenOn(true); } @Override public void surfaceCreated(SurfaceHolder holder) { // 开启线程 isRunning = true; t = new Thread(this); t.start(); } @Override public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) { // TODO Auto-generated method stub } @Override public void surfaceDestroyed(SurfaceHolder holder) { // 通知关闭线程 isRunning = false; } @Override public void run() { while (isRunning) { long start = System.currentTimeMillis(); draw(); long end = System.currentTimeMillis(); try { if (end - start < 50) { Thread.sleep(50 - (end - start)); } } catch (InterruptedException e) { e.printStackTrace(); } } } private void draw() { try { // 获得canvas mCanvas = mHolder.lockCanvas(); if (mCanvas != null) { // drawSomething.. } } catch (Exception e) { } finally { if (mCanvas != null) mHolder.unlockCanvasAndPost(mCanvas); } }}

2、定义变量,

1)总共有六个奖项,所以需要六张图片及相关的文字
2)转盘旋转时需要速度及旋转开始的角度
3)判断是否停止等等

{private static final String TAG = "tag";    /** 判断是否运行 */    private boolean isRunning;    /** 执行线程 */    private Thread mThread;    /** 画布 */    private Canvas mCanvas;    /** 处理器 */    private SurfaceHolder mHolder;    /** 图片文字 */    private String[] mTexts = new String[] { "单反相机", "IPAD", "恭喜发财", "IPHONE", "妹子一只", "恭喜发财" };    /** 转盘颜色 */    private int[] mColors = new int[] { 0xFFFFC300, 0xFFF17E01, 0xFFFFC300, 0xFFF17E01, 0xFFFFC300, 0xFFF17E01 };    /** 图片资源 */    private int[] mImgs = new int[] { R.drawable.danfan, R.drawable.ipad, R.drawable.f040, R.drawable.iphone, R.drawable.meizi,            R.drawable.f040 };    /** 图片 */    private Bitmap[] mBitmaps;    /** 盘块的图片 */    private int mCount = mImgs.length;    /** 绘制盘块的范围 */    private RectF mRange = new RectF();    /** 圆的直径 */    private int mRadius;    /** 绘制盘快的画笔 */    private Paint mArcPaint;    /** 绘制文字的画笔 */    private Paint mTextPaint;    /** 滚动的速度 */    private double mSpeed;    /** 盘块的开始旋转角度 */    private volatile float mStartAngle = 0;    /** 是否点击了停止 */    public boolean isShouldEnd;    /** 控件的中心位置 */    private int mCenter;    /** 控件的padding,这里我们认为4个padding的值一致,以paddingleft为标准 */    private int mPadding;    /** 背景图的bitmap */    private Bitmap mBgBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.bg2);    /** 文字大小 */private float mTextSize = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, 20, getResources().getDisplayMetrics());    }

3、变量在surfaceCreated方法里初始化

@Override    public void surfaceCreated(SurfaceHolder holder) {        // 初始化绘制圆弧的画笔        mArcPaint = new Paint();        mArcPaint.setAntiAlias(true);        mArcPaint.setDither(true);        // 初始化绘制文字的画笔        mTextPaint = new Paint();        mTextPaint.setColor(0xFFffffff);        mTextPaint.setTextSize(mTextSize);        // 绘制圆盘的范围        mRange = new RectF(getPaddingLeft(), getPaddingLeft(), getPaddingLeft() + mRadius, getPaddingLeft() + mRadius);        // 初始化图片        mBitmaps = new Bitmap[mCount];        for (int i = 0; i < mCount; i++) {            mBitmaps[i] = BitmapFactory.decodeResource(getResources(), mImgs[i]);        }        isRunning = true;        mThread = new Thread(this);        mThread.start();    }

4、如何获得转盘的半径呢?在onMeasure里获得

@Override    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {        super.onMeasure(widthMeasureSpec, heightMeasureSpec);        int width = Math.min(getMeasuredWidth(), getMeasuredHeight());        // 直径        mRadius = width - getPaddingLeft() - getPaddingRight();        // padding值        mPadding = getPaddingLeft();        // 中心点        mCenter = mRadius / 2;        // 设置奖盘的范围        setMeasuredDimension(width, width);    }

5、绘制背景

/**     * 绘制背景 根据当前旋转的mStartAngle计算当前滚动到的区域 绘制背景,不重要,完全为了美观     */    private void drawBg() {        mCanvas.drawColor(0xffffffff);        RectF rect = new RectF(mPadding / 2, mPadding / 2, getMeasuredWidth() - mPadding / 2, getMeasuredHeight() - mPadding / 2);        mCanvas.drawBitmap(mBgBitmap, null, rect, null);    }

6、绘制每个奖项的内容,包括盘块、图片、文字等

/**     * 绘制每个块块,每个块块上的文本,每个块块上的图片     */    private void drawItemPan() {        float tmpAngle = mStartAngle;        float sweepAngle = (float) (360 / mCount);        for (int i = 0; i < mCount; i++) {            // 绘制快快            mArcPaint.setColor(mColors[i]);            // mArcPaint.setStyle(Style.STROKE);            mCanvas.drawArc(mRange, tmpAngle, sweepAngle, true, mArcPaint);            drawText(tmpAngle, sweepAngle, mTexts[i]);            // 绘制文本            Logger.i(TAG, "tmpAngle==" + tmpAngle + "  sweepAngle==" + sweepAngle);            // 绘制奖品            drawPrice(tmpAngle, i);            tmpAngle += sweepAngle;        }        // 如果mSpeed不等于0,则相当于在滚动        mStartAngle += mSpeed;        // 点击停止时,设置mSpeed为递减,为0值转盘停止        if (isShouldEnd) {            mSpeed -= 1;        }        if (mSpeed <= 0) {            mSpeed = 0;            isShouldEnd = false;        }    }

1)绘制盘块

mCanvas.drawArc(mRange, tmpAngle, sweepAngle, true, mArcPaint);

2)绘制文字

/**     * 绘制文本     *      * @param tempAngle     * @param sweepAngle     * @param text     */    private void drawText(float tempAngle, float sweepAngle, String text) {        Path path = new Path();        path.addArc(mRange, tempAngle, sweepAngle);        float textWidth = mTextPaint.measureText(text);        // 利用水平偏移让文字居中        float hOffset = (float) (mRadius * Math.PI / mCount / 2 - textWidth / 2);// 水平偏移        float vOffset = mRadius / 2 / 6;// 垂直偏移        mCanvas.drawTextOnPath(text, path, hOffset, vOffset, mTextPaint);    }

3)绘制图片奖项

/**     * 绘制奖品图片     *      * @param tempAngle     * @param i     */    private void drawPrice(float tempAngle, int i) {        // 设置图片的宽度为直径的1/8        int imgWidth = mRadius / 8;        float angle = (float) ((30 + tempAngle) * (Math.PI / 180));        int x = (int) (mCenter + mCenter / 4 + mRadius / 3 * Math.cos(angle));        int y = (int) (mCenter + mCenter / 4 + mRadius / 3 * Math.sin(angle));        // 确定绘制图片的位置        Rect rect = new Rect(x - imgWidth / 2, y - imgWidth / 2, x + imgWidth / 2, y + imgWidth / 2);        mCanvas.drawBitmap(mBitmaps[i], null, rect, null);    }

7、添加按钮事件,让其点击时旋转

/**     * 点击开始旋转     */    public void start(int index) {        // 每项角度大小        float angle = (float) (360 / mCount);        // 中奖角度范围(因为指针向上,所以水平第一项旋转到指针指向,需要旋转210-270;)        float from = 270 - (index + 1) * angle;        float to = from + angle;        // 停下来时旋转的距离        float targetFrom = 4 * 360 + from;        /**         * 
         *  (v1 + 0) * (v1+1) / 2 = target ;          *  v1*v1 + v1 - 2target = 0 ;          *  v1=-1+(1*1 + 8 *1 * target)/2;         * 
*/ float v1 = (float) (Math.sqrt(1 * 1 + 8 * 1 * targetFrom) - 1) / 2; float targetTo = 4 * 360 + to; float v2 = (float) (Math.sqrt(1 * 1 + 8 * 1 * targetTo) - 1) / 2; mSpeed = (float) (v1 + Math.random() * (v2 - v1)); isShouldEnd = false; }

8、判断是否点击了停止与停止动作

/**     * 让圆盘停止滚动     */    public void stop() {        mStartAngle = 0;        isShouldEnd = true;    }    public boolean isStart() {        return mSpeed != 0;    }    public boolean isStop() {        return isShouldEnd;    }

9、最后在主页里实现

public class PrizeActivity extends Activity implements OnClickListener {
private PrizeView mPrizeView; private ImageView mBtnStart; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_prize); mPrizeView = (PrizeView) findViewById(R.id.id_luckypan); mBtnStart = (ImageView) findViewById(R.id.id_start_btn); mBtnStart.setOnClickListener(this); } @Override public void onClick(View v) { if (v == mBtnStart) { if (!mPrizeView.isStart()) { mBtnStart.setImageResource(R.drawable.stop); mPrizeView.start(1); }else { if (!mPrizeView.isStop()) { mBtnStart.setImageResource(R.drawable.start); mPrizeView.stop(); } } } }}

五、抽奖游戏全部源码

package com.android.view.prize;import android.content.Context;import android.graphics.Bitmap;import android.graphics.BitmapFactory;import android.graphics.Canvas;import android.graphics.Paint;import android.graphics.Path;import android.graphics.Rect;import android.graphics.RectF;import android.os.SystemClock;import android.util.AttributeSet;import android.util.TypedValue;import android.view.SurfaceHolder;import android.view.SurfaceHolder.Callback;import android.view.SurfaceView;import com.android.view.R;import com.android.view.tool.Logger;/** * 奖盘 *  * @Project App_View * @Package com.android.view.prize * @author chenlin * @version 1.0 * @Date 2014年11月24日 * @Note TODO */public class PrizeView extends SurfaceView implements Callback, Runnable {
private static final String TAG = "tag"; /** 判断是否运行 */ private boolean isRunning; /** 执行线程 */ private Thread mThread; /** 画布 */ private Canvas mCanvas; /** 处理器 */ private SurfaceHolder mHolder; /** 图片文字 */ private String[] mTexts = new String[] { "单反相机", "IPAD", "恭喜发财", "IPHONE", "妹子一只", "恭喜发财" }; /** 转盘颜色 */ private int[] mColors = new int[] { 0xFFFFC300, 0xFFF17E01, 0xFFFFC300, 0xFFF17E01, 0xFFFFC300, 0xFFF17E01 }; /** 图片资源 */ private int[] mImgs = new int[] { R.drawable.danfan, R.drawable.ipad, R.drawable.f040, R.drawable.iphone, R.drawable.meizi, R.drawable.f040 }; /** 图片 */ private Bitmap[] mBitmaps; /** 盘块的图片 */ private int mCount = mImgs.length; /** 绘制盘块的范围 */ private RectF mRange = new RectF(); /** 圆的直径 */ private int mRadius; /** 绘制盘快的画笔 */ private Paint mArcPaint; /** 绘制文字的画笔 */ private Paint mTextPaint; /** 滚动的速度 */ private double mSpeed; /** 盘块的开始旋转角度 */ private volatile float mStartAngle = 0; /** 是否点击了停止 */ public boolean isShouldEnd; /** 控件的中心位置 */ private int mCenter; /** 控件的padding,这里我们认为4个padding的值一致,以paddingleft为标准 */ private int mPadding; /** 背景图的bitmap */ private Bitmap mBgBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.bg2); /** 文字大小 */ private float mTextSize = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, 20, getResources().getDisplayMetrics()); public PrizeView(Context context, AttributeSet attrs) { this(context, attrs, 0); } public PrizeView(Context context) { this(context, null); } public PrizeView(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); init(); Logger.i(TAG, "mcount==" + mCount); } private void init() { mHolder = getHolder(); mHolder.addCallback(this); // setZOrderOnTop(true);// 设置画布 背景透明 // mHolder.setFormat(PixelFormat.TRANSLUCENT); setFocusable(true);// 设置可获得焦点 setFocusableInTouchMode(true); this.setKeepScreenOn(true);// 设置常亮 } @Override public void run() { while (isRunning) { long start = System.currentTimeMillis(); draw(); long end = System.currentTimeMillis(); // 如果没有达到缓存时间,则休眠 if (end < start + 50) { SystemClock.sleep(50 - (end - start)); } } } /** * */ private void draw() { try { // 获得canvas mCanvas = mHolder.lockCanvas(); if (mCanvas != null) { drawBg(); drawItemPan(); } // 根据当前旋转的mStartAngle计算当前滚动到的区域 caculateScrollArea(mStartAngle); } catch (Exception e) { e.printStackTrace(); } finally { if (mCanvas != null) { mHolder.unlockCanvasAndPost(mCanvas); } } } /** * 根据当前旋转的mStartAngle计算当前滚动到的区域 * * @param startAngle */ private void caculateScrollArea(float startAngle) { // 让指针从水平向右开始计算 float rotate = startAngle + 90; rotate %= 360.0; for (int i = 0; i < mCount; i++) { // 每个的中奖范围 float from = 360 - (i + 1) * (360 / mCount); float to = from + 360 - (i) * (360 / mCount); if ((rotate > from) && (rotate < to)) { Logger.i(TAG, mTexts[i]); return; } } } /** * 让圆盘停止滚动 */ public void stop() { mStartAngle = 0; isShouldEnd = true; } public boolean isStart() { return mSpeed != 0; } public boolean isStop() { return isShouldEnd; } /** * 点击开始旋转 */ public void start(int index) { // 每项角度大小 float angle = (float) (360 / mCount); // 中奖角度范围(因为指针向上,所以水平第一项旋转到指针指向,需要旋转210-270;) float from = 270 - (index + 1) * angle; float to = from + angle; // 停下来时旋转的距离 float targetFrom = 4 * 360 + from; /** *
         *  (v1 + 0) * (v1+1) / 2 = target ;          *  v1*v1 + v1 - 2target = 0 ;          *  v1=-1+(1*1 + 8 *1 * target)/2;         * 
*/ float v1 = (float) (Math.sqrt(1 * 1 + 8 * 1 * targetFrom) - 1) / 2; float targetTo = 4 * 360 + to; float v2 = (float) (Math.sqrt(1 * 1 + 8 * 1 * targetTo) - 1) / 2; mSpeed = (float) (v1 + Math.random() * (v2 - v1)); isShouldEnd = false; } /** * 绘制每个块块,每个块块上的文本,每个块块上的图片 */ private void drawItemPan() { float tmpAngle = mStartAngle; float sweepAngle = (float) (360 / mCount); for (int i = 0; i < mCount; i++) { // 绘制快快 mArcPaint.setColor(mColors[i]); // mArcPaint.setStyle(Style.STROKE); mCanvas.drawArc(mRange, tmpAngle, sweepAngle, true, mArcPaint); drawText(tmpAngle, sweepAngle, mTexts[i]); // 绘制文本 Logger.i(TAG, "tmpAngle==" + tmpAngle + " sweepAngle==" + sweepAngle); // 绘制奖品 drawPrice(tmpAngle, i); tmpAngle += sweepAngle; } // 如果mSpeed不等于0,则相当于在滚动 mStartAngle += mSpeed; // 点击停止时,设置mSpeed为递减,为0值转盘停止 if (isShouldEnd) { mSpeed -= 1; } if (mSpeed <= 0) { mSpeed = 0; isShouldEnd = false; } } /** * 绘制奖品图片 * * @param tempAngle * @param i */ private void drawPrice(float tempAngle, int i) { // 设置图片的宽度为直径的1/8 int imgWidth = mRadius / 8; float angle = (float) ((30 + tempAngle) * (Math.PI / 180)); int x = (int) (mCenter + mCenter / 4 + mRadius / 3 * Math.cos(angle)); int y = (int) (mCenter + mCenter / 4 + mRadius / 3 * Math.sin(angle)); // 确定绘制图片的位置 Rect rect = new Rect(x - imgWidth / 2, y - imgWidth / 2, x + imgWidth / 2, y + imgWidth / 2); mCanvas.drawBitmap(mBitmaps[i], null, rect, null); } /** * 绘制文本 * * @param tempAngle * @param sweepAngle * @param text */ private void drawText(float tempAngle, float sweepAngle, String text) { Path path = new Path(); path.addArc(mRange, tempAngle, sweepAngle); float textWidth = mTextPaint.measureText(text); // 利用水平偏移让文字居中 float hOffset = (float) (mRadius * Math.PI / mCount / 2 - textWidth / 2);// 水平偏移 float vOffset = mRadius / 2 / 6;// 垂直偏移 mCanvas.drawTextOnPath(text, path, hOffset, vOffset, mTextPaint); } /** * 绘制背景 根据当前旋转的mStartAngle计算当前滚动到的区域 绘制背景,不重要,完全为了美观 */ private void drawBg() { mCanvas.drawColor(0xffffffff); RectF rect = new RectF(mPadding / 2, mPadding / 2, getMeasuredWidth() - mPadding / 2, getMeasuredHeight() - mPadding / 2); mCanvas.drawBitmap(mBgBitmap, null, rect, null); } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { super.onMeasure(widthMeasureSpec, heightMeasureSpec); int width = Math.min(getMeasuredWidth(), getMeasuredHeight()); // 直径 mRadius = width - getPaddingLeft() - getPaddingRight(); // padding值 mPadding = getPaddingLeft(); // 中心点 mCenter = mRadius / 2; // 设置奖盘的范围 setMeasuredDimension(width, width); } // --监听事件------------------------------------------------ @Override public void surfaceCreated(SurfaceHolder holder) { // 初始化绘制圆弧的画笔 mArcPaint = new Paint(); mArcPaint.setAntiAlias(true); mArcPaint.setDither(true); // 初始化绘制文字的画笔 mTextPaint = new Paint(); mTextPaint.setColor(0xFFffffff); mTextPaint.setTextSize(mTextSize); // 绘制圆盘的范围 mRange = new RectF(getPaddingLeft(), getPaddingLeft(), getPaddingLeft() + mRadius, getPaddingLeft() + mRadius); // 初始化图片 mBitmaps = new Bitmap[mCount]; for (int i = 0; i < mCount; i++) { mBitmaps[i] = BitmapFactory.decodeResource(getResources(), mImgs[i]); } isRunning = true; mThread = new Thread(this); mThread.start(); } @Override public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) { // TODO Auto-generated method stub } @Override public void surfaceDestroyed(SurfaceHolder holder) { isRunning = false; }}

七、所有游戏源码下载

链接: 密码:8zaa

———————————————————————

(java 架构师全套教程,共760G, 让你从零到架构师,每月轻松拿3万)
有需求者请进站查看,非诚勿扰

https://item.taobao.com/item.htm?spm=686.1000925.0.0.4a155084hc8wek&id=555888526201

01.高级架构师四十二个阶段高

02.Java高级系统培训架构课程148课时
03.Java高级互联网架构师课程
04.Java互联网架构Netty、Nio、Mina等-视频教程
05.Java高级架构设计2016整理-视频教程
06.架构师基础、高级片
07.Java架构师必修linux运维系列课程
08.Java高级系统培训架构课程116课时
(送:hadoop系列教程,java设计模式与数据结构, Spring Cloud微服务, SpringBoot入门)
——————————————————————–

转载地址:https://lovoo.blog.csdn.net/article/details/51495771 如侵犯您的版权,请留言回复原文章的地址,我们会给您删除此文章,给您带来不便请您谅解!

上一篇:Android 材料设计一
下一篇:Android adapter设计模式一 静态设值

发表评论

最新留言

能坚持,总会有不一样的收获!
[***.219.124.196]2024年04月07日 17时49分44秒

关于作者

    喝酒易醉,品茶养心,人生如梦,品茶悟道,何以解忧?唯有杜康!
-- 愿君每日到此一游!

推荐文章