canvas应用之各种游戏转盘

来源:互联网 发布:java程序设计基础pdf 编辑:程序博客网 时间:2024/05/16 15:12

canvas应用之各种游戏转盘


    转盘的画法网上有很多,好多都是H5或CSS方式实现的,我这里是Android中实现方式,也算是多种转盘形式集合吧,对canvas的绘制能力的提高会有一定的帮助。先来看下有关绘制过程中重要参数等的个人理解:

radian :弧度
angle :角度
所以由角度变成弧度,再变成余弦值:
   double radians = Math.toRadians(30 + startAngle);
   float cos = (float) (Math.cos(radians) * r + r);
 
也就是:double cos = (Math.cos(Math.toRadians(startAngle);
注意:只有变为弧度后才能使用Math.cos(),求余弦值,切记,切记;

还有手机屏幕坐标系与数学坐标系是不同的哦:
0--------------------------->X轴|  1234|1|| 坐标一区|2||3|V Y轴

RectF rectF = new RectF(float left, float top, float right, float bottom);
rectF中的参数理解:左:左边线的X坐标值;上:上边线的Y坐标值;右:右边线的X坐标值;下:下边线的Y坐标值;
  
 扇形圆弧的绘制
    canvas.drawArc(RectF rectF, float startAngle, float sweepAngle, boolean useCenter,Paint paint);
其会根据rectF中给的四个坐标,自动确定圆心点坐标,然后再根据 startAngle设置弧线的起始线位置, startAngle=0起点是x轴正方向,sweepAngle是绘制弧线的角度,若sweepAngle为正则逆时针绘制弧线,sweepAngle为负数则顺时针绘制弧线(注意使用数学极坐标方式),useCenter表示是否使用
中心;

Paint字体属性的设置方法
    Typeface font = Typeface.create(Typeface.SANS_SERIF, Typeface.BOLD);
    p.setTypeface( font ); 

对paint等的理解:
    mCanvas.drawText(char[] text, int index, int count, float x, float y,Paint paint)中,paint绘制的文字都是冲上的(文字竖直),无论你无论你是上下或是斜着写,所绘制的单个文字都是冲上的;
而mCanvas.drawTextOnPath(@NonNull String text, @NonNull Path path, float hOffset,float vOffset, @NonNull Paint paint);文字会根据路径path的绘制方向,而随之改变文字的显示方向;hOffset表示"path的前端"处空出来的空间大小(值为正则增大间隙空间,负值则反向减小空间),vOffset表示"path垂直"方向偏移的大小(正值向内偏移,负值向外偏移);

对于旋转绘制问题,有两种方式
方式一:
    mCanvas.drawText(@NonNull String text, float x, float y, @NonNull Paint paint);
    mCanvas.rotate(everyAngle ,r,r);  //替换方式1:旋转的是带有文字的“纸——mCanvas”,此时笔(View的坐  标)是不动的

方式二:
  for (int i = 0; i < size; i++) {
            drawText(InitAngle  + 3*halfAngle, strs[i],radius, textPaint, canvas, rectF);
            InitAngle += everyAngle; //替换方式2:以改变绘制的角度来实现旋转绘制
  }

两种方式的区别:
    用rotate,相当于采用了相同的绘制模板,所以绘制出来的文字等样式是相同的(其他条件不变的话,如角度、坐标),而采用角度叠加方式,所有的文字等都属于新样式绘制的(角度改变了绘制的坐标),所以绘制的文字效果可能是不同的;

直接这么说也许不太好懂,下面结合具体情况和代码再来看试试:



下边是自定义View中onDraw代码:
    @Override    protected void onDraw(Canvas canvas) {        super.onDraw(canvas);        final int paddingLeft = getPaddingLeft();        final int paddingRight = getPaddingRight();        final int paddingTop = getPaddingTop();        final int paddingBottom = getPaddingBottom();        int width = getWidth() - paddingLeft - paddingRight;        int height = getHeight() - paddingTop - paddingBottom;        int MinValue = Math.min(width, height);        radius = MinValue / 2;        RectF rectF = new RectF(getPaddingLeft(), getPaddingTop(), width, height);        float angle = InitAngle; //这里的扇形背景与文字或图片需要相差30度,因为文字和图片要在30度角处(背景中间处)显示        //扇形背景绘制        for (int i = 0; i < size; i++) {            if (i % 2 == 0) {                canvas.drawArc(rectF, angle, everyAngle, true, dPaint);            } else {                canvas.drawArc(rectF, angle, everyAngle, true, sPaint);            }            angle += everyAngle;        }        //图片和文字绘制        for (int i = 0; i < size; i++) {            //在此处加3*halfAngle只是为了显示正确,这和直接给InitAngle赋值决定pos是不一样的//            drawIcon(width / 2, height / 2, radius, InitAngle  + 3*halfAngle, i, canvas);            drawText(InitAngle + everyAngle, strs[i], radius, textPaint, canvas, rectF);            InitAngle += everyAngle;  //方式1:以改变绘制的角度来实现旋转绘制,可用方式1替换        }    }

drawText代码:
private void drawText(float startAngle, String string, int r, Paint mTextPaint, Canvas mCanvas, RectF mRange) {/************************************* 1 文字圆弧状显示 *********************************///设计思路:沿着弧线方向对字符串进行绘制,注意textPaint.setTextAlign(Paint.Align.CENTER);设定的绘制的起始位置值,这里字间距没办法修改        Path path = new Path();        path.addArc(mRange, startAngle, everyAngle);  //startAngle就决定了初始位置//        mTextPaint.setTextAlign(Paint.Align.LEFT);//        float textWidth = mTextPaint.measureText(string);//        //文字水平偏移量,偏移到扇形中间位置(作用与textPaint.setTextAlign(Paint.Align.CENTER)等同)//        float hOffset = (float) (r * Math.PI / size - textWidth / 2);        float vOffset = r / 4;        mTextPaint.setTypeface(Typeface.create(Typeface.MONOSPACE, Typeface.NORMAL)); //字体设置        mCanvas.drawTextOnPath(string, path, 0, vOffset, mTextPaint);    }

drawIcon代码:
 private void drawIcon(int xx, int yy, int mRadius, float startAngle, int i, Canvas mCanvas) {        int imgWidth = mRadius / 4;        float angle = (float) Math.toRadians(startAngle);        float x = (float) (xx + mRadius / 2 * Math.cos(angle));        float y = (float) (yy + mRadius / 2 * Math.sin(angle));        // 确定绘制图片的位置        RectF rect = new RectF(x - imgWidth * 3 / 4, y - imgWidth * 3 / 4, x + imgWidth                * 3 / 4, y + imgWidth * 3 / 4);        Bitmap bitmap = bitmaps.get(i);        mCanvas.drawBitmap(bitmap, null, rect, null);    }



代码实现只需要替换drawText方法中代码即可:

/********************************* 2 文字横扫同向模式 ********************************///设计思路:采用直线型路径path由中心向外绘制每个字符串,字符串首字符与圆心距离用转盘内部小同心圆的半径作为限定, path的两个点坐标可由两圆半径算得        //使文字竖着摆放显示,(但文字方向有点问题)        mTextPaint.setTextAlign(Paint.Align.CENTER);        Rect bounds = new Rect();        mTextPaint.getTextBounds(string,0,1,bounds);        int wordHeight = bounds.height();        Path path1 = new Path();        //分别计算x,y初始的坐标        double radians = Math.toRadians(startAngle + halfAngle);  //startAngle的正负决定旋转方向,负为顺时针旋转 halfAngle为调整位置显示值        float bigX = (float) (Math.cos(radians) * r + r);//大圆坐标,此固定值在开发时不需要放到循环中        float bigY =  r + (float) Math.sin(radians) * r;        double cos = Math.cos(radians);        double sin = Math.sin(radians);        float smallR = r/3; //内圆半径,也是字符串与圆心的距离        //内部小圆x,y坐标        float smallX = (float)(cos * smallR + r);  //小圆坐标        float smallY = (float) (sin * smallR + r);//采用从圆心向外发射画法//        path1.moveTo(bigX,bigY); //采用直线路径法绘制文字,这里的hOffset1代表也可称为文字竖直偏移量//        path1.lineTo(smallX,smallY);         path1.moveTo(smallX,smallY);   //设置文字显示方向倒转        path1.lineTo(bigX,bigY);        mCanvas.drawTextOnPath(string, path1, 0, wordHeight/2, mTextPaint);

 
    多状态显示型(字体还可能都是对齐摆放的)            横扫多变型(字体对齐和倾斜摆放都有)


drawText方法中代码如下:

/********************************** 3 文字横扫多变模式或多状态显示 ******************************///设计思路:通过给转盘添加同心小圆的方式,确定一条字符串的首个字符位置(以具体坐标定位),其他字符则根据手字符进行适当偏移生成        //该方式文字竖直显示1,但英文显示会有问题        Rect bounds = new Rect();        mTextPaint.getTextBounds(string.substring(0, 1), 0, 1, bounds);        int wordHeight = bounds.height() + 20; //增大字间距        mTextPaint.setTextAlign(Paint.Align.CENTER);        if (isClicked) {            du = halfAngle;    //du决定整体文字朝向,就是以该角度处的文字样式为模板,然后偏移到别的地方,就像是在固定一个地方写字,人不动而纸动        }        double radians = Math.toRadians(startAngle + du);  //startAngle的正负决定旋转方向,负为顺时针旋转        double cos = Math.cos(radians);        double sin = Math.sin(radians);        float smallR = r/3;        //内部小圆x,y坐标        float x = (float)(cos * smallR + r);        float y = (float) (sin * smallR + r);//采用从圆心向外发射画法        for (int j = string.length()-1;j >=0 ;j--) {  //从后往前取文字,文字汇聚式阅读            mCanvas.drawText(string.substring(j, j + 1), (float) (x + wordHeight * cos * (string.length() - j)), (float) (y + wordHeight * sin * (string.length() - j)), textPaint);        }//方式2:旋转的是带有文字的“纸——mCanvas”,此时笔(View的坐标)是不动的,可替换换方式1处代码
//            mCanvas.rotate(everyAngle ,r,r);  





drawText方法中代码如下:

/************************************************* 4 文字发射状显示 ************************************************************///设计思路:采用每个字符串使用一个圆弧,并且每个圆弧都只放一个文字,该字符串的其他文字则根据该文字进行相对位置平移生成        Path path = new Path();        path.addArc(mRange, startAngle, everyAngle);  //startAngle决定了绘制的初始位置,该位置的值可调整以适应扇形背景区域        Rect bounds = new Rect();        //此固定值在开发时不需要放到循环中        mTextPaint.getTextBounds(string.substring(0, 1), 0, 1, bounds);        //14是增加的字间距,因为中英文的文字高度不同,会导致显示效果不均一,这里可以用定值替代        int wordHeight = bounds.height() + 14;        //因绘制文字采用的是由中心向四周发射方式,此处指定vOffset相对path垂直向内偏移量(包括字间距)        int i = 6;        //为了使每串字符串都与圆心保持相同距离,此处采用倒序绘制文字        for (int j = string.length() - 1; j >= 0; j--) {            //若hOffset和vOffset都为0时,该方法会让文字沿着Path路径绘制文本,hOffset参数指定相对path水平偏移,hOffset值为正数则向path正方向偏移,vOffset指定相对path垂直偏移,若vOffset值为正则向下向内偏移;            mCanvas.drawTextOnPath(string.substring(j, j + 1), path,0, wordHeight * i--, textPaint);        }//        mCanvas.rotate(everyAngle ,r,r); //用于替代InitAngle += everyAngle;的第二种实现方式    }

关键要看需求中文字的显示方向和方式都是什么样的,当然大家要是有好的实现和例子可以告诉我哦!

最后附上git上的项目地址:点 我!


1 0
原创粉丝点击