2019独角兽企业重金招聘Python工程师标准>>>
效果展示:
图片素材:
1.涉及知识点:Mesh,纹理坐标UV
2.核心思路:
将图片1的外围矩形区域,划分为24个三角形,共26个Mesh顶点。然后根据进度,绘制相应的区域即可。
3.Mesh简述:
public Mesh (VertexDataType type, boolean isStatic, int maxVertices, int maxIndices, VertexAttribute... attributes)
参数依次是:
type,顶点数据类型,
isStatic,网格是否为静态,如果顶点不是变化的,设置为true
maxVertices,最大顶点数
maxIndices,最大指数,一般与maxVertices一样即可
attributes,顶点属性
VertexAttribute
常用顶点属性:顶点坐标,颜色,纹理坐标
属性对应数组元素个数 : 顶点坐标2个(x,y) 颜色4个(r,g,b,a) 纹理2个(u,v)
注:
纹理坐标以左上角为原点(0,0),右下角为(1,1);
顶点坐标以左下角为原点(0,0);
4.代码展示:
package com.oahcfly.chgame.core.ui;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.graphics.Color;
import com.badlogic.gdx.graphics.GL20;
import com.badlogic.gdx.graphics.Mesh;
import com.badlogic.gdx.graphics.Texture;
import com.badlogic.gdx.graphics.VertexAttribute;
import com.badlogic.gdx.graphics.VertexAttributes.Usage;
import com.badlogic.gdx.graphics.g2d.Batch;
import com.badlogic.gdx.graphics.g2d.SpriteBatch;
import com.badlogic.gdx.graphics.glutils.ShaderProgram;
import com.badlogic.gdx.math.Vector2;
import com.badlogic.gdx.scenes.scene2d.Actor;
import com.badlogic.gdx.scenes.scene2d.actions.Actions;
import com.badlogic.gdx.utils.Align;
import com.badlogic.gdx.utils.Array;
import com.oahcfly.chgame.core.Chao;
import com.oahcfly.chgame.core.listener.CHProgressBarListener;
/**
*
* 圆形冷却进度条
* 参考自:http://blog.csdn.net/wuhaishengxxx/article/details/46642791
*
*
* @author haocao
*
*/
public class CHCirclePngProgressBar extends Actor {
// 顶点属性个数:(x,y,color,u,v)
static final int VERTEX_SIZE = 2 + 1 + 2;
static final int MAX_VERTICES = 26;
// 总属性个数
static final int SPRITE_SIZE = MAX_VERTICES * VERTEX_SIZE;
// 属性数组元素个数 : 坐标(x,y) 颜色(r,g,b,a) 纹理(u,v)
public final int POS_COMPONENTS = 2;
public final int COLOR_COMPONENTS = 4;
public final int TEXCOORD_COMPONENTS = 2;
private Texture topTexture, bgTexture;
private Mesh mesh;
private ShaderProgram shader;
private float[] spriteVertices;
// 冷却时长
private float duration;
public CHCirclePngProgressBar (String bgPngPath, String topPngPath, float duration) {
this.duration = duration;
topTexture = Chao.game.getTexture(topPngPath);
bgTexture = Chao.game.getTexture(bgPngPath);
setSize(topTexture.getWidth(), topTexture.getHeight());
setOrigin(Align.center);
/**
* 使用默认的shader
* 一般不指定ShaderProgram,我们使用SpriteBatch的时候都是使用默认的shader
*/
this.shader = SpriteBatch.createDefaultShader();
// 设置顶点数据类型为数组类型
Mesh.VertexDataType vertexDataType = Mesh.VertexDataType.VertexArray;
/**
* :顶点坐标、颜色、纹理坐标
*/
VertexAttribute[] vertexAttributes = new VertexAttribute[3];
vertexAttributes[0] = new VertexAttribute(Usage.Position, POS_COMPONENTS, "a_position");
vertexAttributes[1] = new VertexAttribute(Usage.ColorPacked, COLOR_COMPONENTS, "a_color");
vertexAttributes[2] = new VertexAttribute(Usage.TextureCoordinates, TEXCOORD_COMPONENTS, "a_texCoord0");
this.mesh = new Mesh(vertexDataType, false, MAX_VERTICES, MAX_VERTICES, vertexAttributes);
//
Array pointsArray = generatePoints();
/**
* 初始化顶点数据
*/
spriteVertices = new float[SPRITE_SIZE];
for (int i = 0; i < MAX_VERTICES; i++) {
Vector2 vector2 = pointsArray.get(i);
float tx = vector2.x;
float ty = vector2.y;
spriteVertices[i * 5 + 0] = tx;// 坐标x
spriteVertices[i * 5 + 1] = ty;// 坐标y
Vector2 uVector2 = getUV(tx, ty);
spriteVertices[i * 5 + 3] = uVector2.x;
spriteVertices[i * 5 + 4] = uVector2.y;
}
}
private int progressIdx = 0;
public void startProgress () {
progressIdx = 0;
// 时长
float singleDuration = duration / (MAX_VERTICES - 1);
addAction(Actions.repeat(MAX_VERTICES - 1, Actions.delay(singleDuration, Actions.run(new Runnable() {
@Override
public void run () {
//
progressIdx++;
onProgress();
}
}))));
}
private void onProgress () {
if (progressIdx == 0 && progressBarListener != null) {
progressBarListener.onStart();
}
boolean isEnd = progressIdx == MAX_VERTICES - 1;
if (isEnd && progressBarListener != null) {
progressBarListener.onFinish();
}
if (isEnd) {
stoped = false;
clearActions();
}
}
private boolean stoped = false;
/**
*
*/
public void stopProgress () {
stoped = true;
}
/**
* 进度
*/
public void resetProgress () {
stoped = false;
clearActions();
progressIdx = 0;
}
/**
* 恢复进度
*/
public void resumeProgress () {
stoped = false;
}
/**
* 是否处于进度中
* @return
*/
public boolean isProgressing () {
return progressIdx >= 1;
}
@Override
public void act (float delta) {
if (stoped) return;
super.act(delta);
}
@Override
public void draw (Batch batch, float parentAlpha) {
Color color = getColor();
batch.setColor(color.r, color.g, color.b, color.a);
//调用ShapeRender绘制几何图形时无法实现半透明颜色
Gdx.gl.glEnable(GL20.GL_BLEND);
Gdx.gl.glBlendFunc(GL20.GL_SRC_ALPHA, GL20.GL_ONE_MINUS_SRC_ALPHA);
// 开启图形附上纹理
Gdx.gl20.glEnable(GL20.GL_TEXTURE_2D);
float[] tmpSpriteVertices = new float[5 * (progressIdx + 1)];
float x = getX(Align.center) - bgTexture.getWidth() / 2;
float y = getY(Align.center) - bgTexture.getHeight() / 2;
float fColor = getColor().toFloatBits();
for (int i = 0; i < MAX_VERTICES; i++) {
if (i < progressIdx + 1) {
tmpSpriteVertices[i * 5 + 0] = spriteVertices[i * 5 + 0] + x;// 坐标x
tmpSpriteVertices[i * 5 + 1] = spriteVertices[i * 5 + 1] + y;// 坐标y
tmpSpriteVertices[i * 5 + 2] = fColor;// 颜色
Vector2 uVector2 = getUV(spriteVertices[i * 5 + 0], spriteVertices[i * 5 + 1]);
tmpSpriteVertices[i * 5 + 3] = uVector2.x;// 纹理坐标u
tmpSpriteVertices[i * 5 + 4] = uVector2.y;// 纹理坐标v
}
}
this.bgTexture.bind();
this.mesh.setVertices(tmpSpriteVertices, 0, tmpSpriteVertices.length);
this.mesh.render(this.shader, GL20.GL_TRIANGLE_FAN, 0, tmpSpriteVertices.length / 5);
// 顶部蒙版纹理
batch.draw(topTexture, getX(), getY(), getOriginX(), getOriginY(), getWidth(), getHeight(), getScaleX(), getScaleY(),
getRotation(), 0, 0, (int)getWidth(), (int)getHeight(), false, false);
}
private CHProgressBarListener progressBarListener;
public void setProgressBarListener (CHProgressBarListener progressBarListener) {
this.progressBarListener = progressBarListener;
}
/**
*
*
* @param x 以左下角为基准,范围[0,w]
* @param y 以左下角为基准,范围[0,h]
* @return
*/
private Vector2 getUV (float x, float y) {
Vector2 vector2 = new Vector2(x / bgTexture.getWidth(), 1 - y / bgTexture.getHeight());
return vector2;
}
private Array generatePoints () {
// 原点:左下角
float w = bgTexture.getWidth();
float h = bgTexture.getHeight();
Array array = new Array();
// 圆心
array.add(new Vector2(2 * w / 4, 2 * h / 4));
int MAX_POINTS = 6;
// 右上4
for (int i = MAX_POINTS / 2; i <= MAX_POINTS; i++) {
array.add(new Vector2(i * w / MAX_POINTS, h));
}
// 右侧6
for (int i = MAX_POINTS - 1; i >= 0; i--) {
array.add(new Vector2(w, i * h / MAX_POINTS));
}
// 底6
for (int i = MAX_POINTS - 1; i >= 0; i--) {
array.add(new Vector2(w * i / MAX_POINTS, 0));
}
// 左6
for (int i = 1; i <= MAX_POINTS; i++) {
array.add(new Vector2(0, i * h / MAX_POINTS));
}
// 左上3
for (int i = 1; i <= MAX_POINTS / 2; i++) {
array.add(new Vector2(w * i / MAX_POINTS, h));
}
return array;
}
}
package com.oahcfly.chgame.core.listener;
public interface CHProgressBarListener {
public void onStart ();
public void onFinish ();
}
基于Libgdx开发的开源游戏框架CHGame:
http://git.oschina.net/oahcfly/CHGameFrame