首页 > 代码库 > libgdx 制作技能冷却图标

libgdx 制作技能冷却图标

本篇随笔记录如何制作一个技能冷却的图标。抛砖引玉了,如需实际应用还得好好整理代码。

表示技能冷却,计时等无非就两种吧,一是长条状,参照/扩展progressbar即可,另外一个就是方形或者圆形的了吧。

很多有技能条的游戏UI一般都是用的是方形技能图标,如魔兽世界,暗黑三,War3.....

在这里我们试着做一个出来,先看看效果图吧(很次,见尿了,以后可以在指针和边框上加上动画或粒子效果)

 

该组件分为4层,从下往上依次为:技能原图标ground,裁剪效果层,指针层,外边框。当然也可以加入更多,或者只有两层(ground和裁剪效果)。

上代码:

  1 public class ColdDownIcon extends Image {  2   3   4     private TextureRegion texture;//裁剪画的纹理  5     private TextureRegion ground;//背景纹理,裁剪镂空后要露出来的,也就是原始技能图标  6     private TextureRegion outerRing;//图标外圈  7     private Image handEffect;//指针效果,本来打算使用粒子效果的  8   9     private PolygonSpriteBatch polyBatch;//画多边形的 10  11     private Vector2 center; 12     private Vector2 centerTop;//从上面中间开始 13     private Vector2 leftTop; 14     private Vector2 leftBottom; 15     private Vector2 rightBottom; 16     private Vector2 rightTop; 17     private Vector2 progressPoint; 18     private float[] fv;//裁剪画图使用的点阵{point1.x,point1.y,point2.x,point2.y  ......} 19     private Vector2 intersectPoint;//当前切割在边上的点 20  21     //当前正在切割的位置 22     private IntersectAt intersectAt; 23     private float liveTime;//本次cd已执行时间 24     private float coldDownTime;//cd一次所需时间 25     private boolean startColdDown; 26  27     //当前切割位置的枚举 28     public enum IntersectAt { 29         NONE, TOP, BOTTOM, LEFT, RIGHT; 30     } 31  32     public ColdDownIcon(TextureRegion ground,TextureRegion outerRing, PolygonSpriteBatch polyBatch,Image handEffect,float coldDownTime) 33     { 34         super(ground); 35         this.ground = ground; 36         this.texture = ground; 37         this.outerRing = outerRing; 38         this.polyBatch = polyBatch; 39         this.handEffect = handEffect; 40         this.handEffect.setVisible(false); 41  42         handEffect.setOrigin(this.getWidth()/2,this.getHeight()/2); 43         this.coldDownTime = coldDownTime; 44         //计算各点内部坐标 45         center = new Vector2(this.getWidth()/2, this.getHeight()/2); 46         centerTop = new Vector2(this.getWidth()/2, this.getHeight()); 47         leftTop = new Vector2(0, this.getHeight()); 48         leftBottom = new Vector2(0, 0); 49         rightBottom = new Vector2(this.getWidth(), 0); 50         rightTop = new Vector2(this.getWidth(), this.getHeight()); 51         progressPoint = new Vector2(this.getWidth()/2, this.getHeight()/2); 52  53         setColor(Color.RED); 54  55         setPercentage(0); 56     } 57  58     public void startColdDown(){ 59         this.startColdDown = true; 60         this.liveTime = 0; 61         this.setPercentage(0); 62         this.handEffect.setVisible(true); 63     } 64  65     public void endColdDown(){ 66         this.startColdDown = false; 67         this.liveTime = 0; 68         this.setPercentage(0); 69         this.handEffect.setVisible(false); 70     } 71  72     //计算切线的最远点 73     private Vector2 IntersectPoint(Vector2 line) 74     { 75         Vector2 v = new Vector2(); 76         boolean isIntersect; 77  78         //check top 79         isIntersect = Intersector.intersectSegments(leftTop, rightTop, center, line, v);//切割线和上边的交点v 80  81         //check bottom 82         if (isIntersect) { intersectAt = IntersectAt.TOP; return v; } 83         else isIntersect = Intersector.intersectSegments(leftBottom, rightBottom, center, line, v); 84  85         //check left 86         if (isIntersect) { intersectAt = IntersectAt.BOTTOM; return v; } 87         else isIntersect = Intersector.intersectSegments(leftTop, leftBottom, center, line, v); 88  89         //check bottom 90         if (isIntersect) { intersectAt = IntersectAt.LEFT; return v; } 91         else isIntersect = Intersector.intersectSegments(rightTop, rightBottom, center, line, v); 92  93         if (isIntersect) { intersectAt = IntersectAt.RIGHT; return v; } 94         else 95         { 96             intersectAt = IntersectAt.NONE; 97             return null; 98         } 99     }100 101     //设置百分比,顺时针102     private void setPercentage(float percent)103     {104         //100 % = 360 degree105         //==> percent % => (percent * 360 / 100) degree106 107         float angle = convertToRadians(90); //percent = 0 => angle = -90108         angle -= convertToRadians(percent * 360 / 100);109 110         float len = this.getWidth() > this.getHeight() ? this.getWidth() : this.getHeight();111         float dy = (float) (Math.sin(angle) * len);112         float dx = (float) (Math.cos(angle) * len);113         Vector2 line = new Vector2(center.x + dx, center.y + dy);114 115         intersectPoint = IntersectPoint(line);116         //117         float l = intersectPoint.dst(center.x,center.y);118         float sy = 2*l/getHeight();119 120         handEffect.setScaleY(sy);121 122 123         if (intersectAt == IntersectAt.TOP)124         {125             if (intersectPoint.x >= this.getWidth()/2) //126             {127                 //128                 fv = new float[] {129                         center.x,130                         center.y,131                         centerTop.x,132                         centerTop.y,133                         leftTop.x,134                         leftTop.y,135                         leftBottom.x,136                         leftBottom.y,137                         rightBottom.x,138                         rightBottom.y,139                         rightTop.x,140                         rightTop.y,141                         intersectPoint.x,142                         intersectPoint.y143                 };144             }145             else146             {147                 fv = new float[] { // c?t bên trái c?nh148                         center.x,149                         center.y,150                         centerTop.x,151                         centerTop.y,152                         intersectPoint.x,153                         intersectPoint.y154                 };155 156             }157         }158         else if (intersectAt == IntersectAt.BOTTOM)159         {160             fv = new float[] {161                     center.x,162                     center.y,163                     centerTop.x,164                     centerTop.y,165                     leftTop.x,166                     leftTop.y,167                     leftBottom.x,168                     leftBottom.y,169                     intersectPoint.x,170                     intersectPoint.y171             };172 173         }174         else if (intersectAt == IntersectAt.LEFT)175         {176             fv = new float[] {177                     center.x,178                     center.y,179                     centerTop.x,180                     centerTop.y,181                     leftTop.x,182                     leftTop.y,183                     intersectPoint.x,184                     intersectPoint.y185             };186 187         }188         else if (intersectAt == IntersectAt.RIGHT)189         {190             fv = new float[] {191                     center.x,192                     center.y,193                     centerTop.x,194                     centerTop.y,195                     leftTop.x,196                     leftTop.y,197                     leftBottom.x,198                     leftBottom.y,199                     rightBottom.x,200                     rightBottom.y,201                     intersectPoint.x,202                     intersectPoint.y203             };204         }205         else // if (intersectAt == IntersectAt.NONE)206         {207             //不绘制208             fv = null;209         }210     }211 212     //重新绘制函数213     @Override214     public void draw(Batch batch, float parentAlpha) {215 //        super.draw(batch, parentAlpha);216         batch.draw(ground,this.getX(),this.getY());217 218         if (fv != null&&this.startColdDown) {//画裁剪了的图219             batch.end(); //注意这里!!!先把原来的停掉220             drawMe();221             batch.begin(); //注意这里!!再开始!222         }223         if(handEffect.isVisible()){224             handEffect.setX(this.getX());225             handEffect.setY(this.getY());226             handEffect.draw(batch,parentAlpha);227         }228 229         batch.draw(outerRing,this.getX(),this.getY());230     }231 232     @Override233     public void act(float delta) {234         super.act(delta);235         if(this.startColdDown){//开始冷却了,计时236             this.liveTime = this.liveTime+delta;237             if(this.liveTime>this.coldDownTime){//超出停止238                 this.endColdDown();239             }else{240                 float percent = this.liveTime*100/this.coldDownTime;241                 this.setPercentage(percent);242                 handEffect.setVisible(true);243                 handEffect.setRotation(-percent * 360 / 100);244             }245         }246     }247 248     //按点阵列区域绘制图像249     public void drawMe()250     {251         //裁剪252         EarClippingTriangulator e = new EarClippingTriangulator();253         ShortArray sv = e.computeTriangles(fv);254 255         //创建 polygonRegion.256         PolygonRegion polyReg = new PolygonRegion( texture, fv, sv.toArray());257 258         //创建 polySprite.259         PolygonSprite poly = new PolygonSprite(polyReg);260 261         //(position, origin, rotation, color)262         poly.setOrigin(this.getOriginX(), this.getOriginY());263         poly.setPosition(this.getX(), this.getY());264         poly.setRotation(this.getRotation());265         poly.setColor(this.getColor());266 267         //绘制268         polyBatch.begin();269         poly.draw(polyBatch);270         polyBatch.end();271     }272 273 274 275 //-----------------------------------------------------------------276 277 278     float convertToDegrees(float angleInRadians)279     {280         float angleInDegrees = angleInRadians * 57.2957795f;281         return angleInDegrees;282     }283 284     float convertToRadians(float angleInDegrees)285     {286         float angleInRadians = angleInDegrees * 0.0174532925f;287         return angleInRadians;288     }289 290 }

 

public class ColdDownTester2 extends ApplicationAdapter implements InputProcessor {    private Stage stage;    private static final Logger LOGGER = new Logger(ColdDownTester2.class.getName(),Application.LOG_DEBUG);    private Texture ground;    private Texture hand;    private Texture outerRing;    private ColdDownIcon icon;    @Override    public void create () {        Gdx.app.setLogLevel(Application.LOG_DEBUG);        stage = new Stage();        Gdx.input.setInputProcessor(this);        ground = new Texture(Gdx.files.internal("frostbolt-1.png"));        hand = new Texture(Gdx.files.internal("frostbolt-3.png"));        outerRing = new Texture(Gdx.files.internal("frostbolt-4.png"));        icon = new ColdDownIcon(new TextureRegion(ground),new TextureRegion(outerRing),new PolygonSpriteBatch(),new Image(hand),3.0f);        stage.addActor(icon);    }    @Override    public void render () {        Gdx.gl.glClearColor(0.2f, 0.2f, 0.2f, 1);        Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);        stage.act();        stage.draw();    }    @Override    public void dispose() {        stage.dispose();        super.dispose();    }    @Override    public void resize(int width, int height) {        stage.getViewport().update(width,height);        super.resize(width, height);    }    @Override    public boolean keyDown(int keycode) {        if(keycode == Input.Keys.J){            icon.startColdDown();        }        return false;    }    @Override    public boolean keyUp(int keycode) {        return false;    }    @Override    public boolean keyTyped(char character) {        return false;    }    @Override    public boolean touchDown(int screenX, int screenY, int pointer, int button) {        return false;    }    @Override    public boolean touchUp(int screenX, int screenY, int pointer, int button) {        return false;    }    @Override    public boolean touchDragged(int screenX, int screenY, int pointer) {        return false;    }    @Override    public boolean mouseMoved(int screenX, int screenY) {        return false;    }    @Override    public boolean scrolled(int amount) {        return false;    }}

 

裁剪计算代码参考了越南人的代码,从哪来的找不到了,官网应该也有。

以上代码只为了显示看看效果,并未关心dispose等。icon代码仍需完善,缩放旋转现在应该是有问题的,自行解决,无关本文了。

 

libgdx 制作技能冷却图标