Libgdx学习笔记:UI之技能冷却按钮(新版)

效果展示:

171333_7sVw_1866808.gif

图片素材:

171606_bFOY_1866808.png171606_pwhm_1866808.png

1.涉及知识点:Mesh,纹理坐标UV

2.核心思路:

将图片1的外围矩形区域,划分为24个三角形,共26个Mesh顶点。然后根据进度,绘制相应的区域即可。

3.Mesh简述:

public Mesh (VertexDataType typeboolean isStaticint maxVerticesint 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<Vector2> 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<Vector2> generatePoints () {
		// 原点:左下角
		float w = bgTexture.getWidth();
		float h = bgTexture.getHeight();
		Array<Vector2> array = new Array<Vector2>();
		// 圆心
		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


转载于:https://my.oschina.net/oahcfly/blog/549153

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值