文档章节

Libgdx学习笔记:使用ShapeRenderer绘制贝塞尔曲线路线图

flyoahc
 flyoahc
发布于 2015/12/30 14:39
字数 938
阅读 571
收藏 0


上图红色路径即为贝塞尔曲线的路线。

核心思路:

获取贝塞尔曲线上的所有的点,然后通过ShapeRenderer画线即可。


代码展示:

package com.oahcfly.chgame.core.ui;

import com.badlogic.gdx.graphics.Color;
import com.badlogic.gdx.graphics.g2d.Batch;
import com.badlogic.gdx.graphics.glutils.ShapeRenderer;
import com.badlogic.gdx.graphics.glutils.ShapeRenderer.ShapeType;
import com.badlogic.gdx.math.Bezier;
import com.badlogic.gdx.math.Vector2;
import com.oahcfly.chgame.core.mvc.CHActor;

/**
 * 
 * 贝塞尔路线 : 使用ShapeRenderer绘制
 * @author haocao
 *
 */
public class CHBezierLine extends CHActor {

	// 以左上角为原点进行绘制的
	private ShapeRenderer shapeRenderer;
	private Bezier<Vector2> bezier;
	// 点列表
	private Vector2[] points;
	// 线条颜色
	private Color lineColor = Color.RED;

	public CHBezierLine (Bezier<Vector2> bezier) {
		this(bezier, Color.RED);
	}

	public CHBezierLine (Bezier<Vector2> bezier, Color lineColor) {
		updateBezier(bezier);
		this.lineColor = lineColor;
		shapeRenderer = new ShapeRenderer();
		shapeRenderer.setAutoShapeType(true);
	}

	/**
	 * 更新贝塞尔曲线参数
	 * @param bezier
	 */
	public void updateBezier (Bezier<Vector2> bezier) {
		this.bezier = bezier;
		// 计算所有点
		int dis = (int)(this.bezier.points.get(this.bezier.points.size - 1).x - this.bezier.points.get(0).x);
		if (dis == 0) {
			dis = (int)(this.bezier.points.get(this.bezier.points.size - 1).y - this.bezier.points.get(0).y);
		}
		points = new Vector2[dis];
		for (int i = 0; i < dis; i++) {
			float t = i * 1f / dis;
			Vector2 out = new Vector2();
			this.bezier.valueAt(out, t);
			points[i] = out;
		}
	}

	@Override
	public void draw (Batch batch, float parentAlpha) {
		batch.flush();

		// 设置用于渲染的投影矩阵
		getStage().getCamera().update();
		shapeRenderer.setProjectionMatrix(getStage().getCamera().combined);

		shapeRenderer.begin(ShapeType.Line);
		shapeRenderer.setColor(this.lineColor);
		for (int i = 0, l = points.length - 1; i < l; i++) {
			Vector2 cur = points[i];
			Vector2 next = points[i + 1];
			shapeRenderer.line(cur, next);
		}
		shapeRenderer.end();

		// 结束本次绘制
		batch.end();
		// 重新开始新的
		batch.begin();

	}

	@Override
	public boolean remove () {
		// TODO Auto-generated method stub
		shapeRenderer.dispose();
		return super.remove();
	}

}

关联代码:

package com.oahcfly.chgame.core.mvc;

import com.badlogic.gdx.graphics.Color;
import com.badlogic.gdx.graphics.Texture;
import com.badlogic.gdx.graphics.g2d.Batch;
import com.badlogic.gdx.graphics.g2d.Sprite;
import com.badlogic.gdx.graphics.g2d.TextureAtlas.AtlasRegion;
import com.badlogic.gdx.graphics.g2d.TextureRegion;
import com.badlogic.gdx.math.Rectangle;
import com.badlogic.gdx.scenes.scene2d.Actor;
import com.badlogic.gdx.utils.Align;
import com.badlogic.gdx.utils.Array;
import com.badlogic.gdx.utils.Pool;
import com.badlogic.gdx.utils.Pool.Poolable;
import com.badlogic.gdx.utils.Pools;
import com.oahcfly.chgame.core.Chao;

/** <pre>
 * 二次封装的actor
 * 
 * date: 2014-12-11
 * </pre>
 * 
 * @author caohao */
public class CHActor extends Actor implements Poolable {
	private int tag;

	private Texture bgTexture;

	private TextureRegion bgTextureRegion;

	private Sprite sprite;

	public CHActor () {
	}

	/**
	 * 绑定一个精灵,此时CHActor的属性会同步到精灵上。
	 * @param sprite
	 */
	public void bindSprite (Sprite sprite) {
		this.sprite = sprite;
		setSize(this.sprite.getWidth(), this.sprite.getHeight());
		setOrigin(Align.center);
	}

	@Override
	public void draw (Batch batch, float parentAlpha) {
		if (clipRectangleArr.size > 0) {
			for (Rectangle cRectangle : clipRectangleArr) {
				this.drawCore(batch, parentAlpha, cRectangle);
			}
		} else {
			this.drawCore(batch, parentAlpha, null);
		}
	}

	/**
	 * 核心绘制
	 * @param batch
	 * @param parentAlpha
	 * @param clipRectangle
	 */
	private void drawCore (Batch batch, float parentAlpha, Rectangle clipRectangle) {
		boolean clipok = false;
		// 开始裁剪
		if (clipRectangle != null) {
			batch.flush(); // 绘制之前添加的元素,如果不添加此处代码,后面的裁剪会导致之前的纹理也会被裁剪
			clipok = clipBegin(getX() + clipRectangle.x, getY() + clipRectangle.y, clipRectangle.width, clipRectangle.height);
		}

		Color color = getColor();
		batch.setColor(color.r, color.g, color.b, color.a);

		float x = getX();
		float y = getY();
		float scaleX = getScaleX();
		float scaleY = getScaleY();

		float width = getWidth();
		float height = getHeight();

		if (bgTexture != null) {
			batch.draw(bgTexture, x, y, getOriginX(), getOriginY(), getWidth(), getHeight(), scaleX, scaleY, getRotation(), 0, 0,
				(int)width, (int)height, false, false);
		}

		if (bgTextureRegion != null) {
			if (bgTextureRegion instanceof Sprite) {
				Sprite sprite = (Sprite)bgTextureRegion;
				sprite.setColor(batch.getColor());
				sprite.setOrigin(getOriginX(), getOriginY());
				sprite.setPosition(x, y);
				sprite.setScale(scaleX, scaleY);
				sprite.setSize(width, height);
				sprite.setRotation(getRotation());
				sprite.draw(batch);
			} else {
				batch.draw(bgTextureRegion, x, y, getOriginX(), getOriginY(), width, height, scaleX, scaleY, getRotation());
			}
		}

		if (sprite != null) {
			sprite.setColor(color);
			sprite.setOrigin(getOriginX(), getOriginY());
			sprite.setPosition(x, y);
			sprite.setScale(scaleX, scaleY);
			sprite.setSize(width, height);
			sprite.setRotation(getRotation());
			sprite.draw(batch);
		}

		// 绘制完背景后进行其他内容绘制
		drawAfterBg(batch);

		// 提交裁剪内容
		if (clipok) {
			batch.flush();
			clipEnd();
		}
	}

	public void drawAfterBg (Batch batch) {
	};

	public void setBgTexture (Texture bgTexture) {
		this.bgTexture = bgTexture;
		if (bgTexture != null) {
			setSize(bgTexture.getWidth(), bgTexture.getHeight());
		}
		setOrigin(Align.center);
	}

	/** <pre>
	 * 使用缓存池
	 * 
	 * date: 2015-1-3
	 * </pre>
	 * 
	 * @author caohao
	 * @return */
	@SuppressWarnings("unchecked")
	public static <T extends CHActor> T obtain (Class<T> type) {
		Pool<CHActor> pool = (Pool<CHActor>)Pools.get(type);
		CHActor actor = pool.obtain();
		actor.setBgTexture(null);
		return (T)actor;
	}

	public static CHActor obtain () {
		return obtain(CHActor.class);
	}

	@Override
	public void reset () {
		this.bgTexture = null;
		this.bgTextureRegion = null;
		clipRectangleArr.clear();
		setScale(1);
		setRotation(0);
		clear();
		setUserObject(null);
		this.setColor(new Color(1, 1, 1, 1));
		setStage(null);
		setParent(null);
		setVisible(true);
		setName(null);
		setOrigin(Align.center);
		setPosition(0, 0);
	}

	public Texture getBgTexture () {
		return bgTexture;
	}

	public TextureRegion getBgTextureRegion () {
		return bgTextureRegion;
	}

	public void setBgTextureRegion (TextureRegion textureRegion) {
		this.bgTextureRegion = textureRegion;
		if (bgTextureRegion != null) {
			if (bgTextureRegion instanceof Sprite) {
				Sprite sprite = (Sprite)bgTextureRegion;
				setSize(sprite.getWidth(), sprite.getHeight());
			} else if (bgTextureRegion instanceof AtlasRegion) {
				AtlasRegion atlasRegion = (AtlasRegion)bgTextureRegion;
				bgTextureRegion = Chao.plistCenter.createSprite(atlasRegion);
				Sprite sprite = (Sprite)bgTextureRegion;
				setSize(sprite.getWidth(), sprite.getHeight());
			} else {
				setSize(bgTextureRegion.getRegionWidth(), bgTextureRegion.getRegionHeight());
			}
		}

		setOrigin(Align.center);
	}

	@Override
	public boolean remove () {
		boolean remove = super.remove();
		if (remove) {
			Pools.free(this);
		}
		return remove;
	}

	public int getTag () {
		return tag;
	}

	public void setTag (int tag) {
		this.tag = tag;
	}

	private Array<Rectangle> clipRectangleArr = new Array<Rectangle>();

	/**
	 * 添加裁剪矩形,范围为当前Actor的显示区域即:(0,0)~(w,h) 左下角
	 * @param rectangle
	 */
	public void addClipRectangle (Rectangle rectangle) {
		clipRectangleArr.add(rectangle);
	}

	public Sprite getSprite () {
		return sprite;
	}

	private Rectangle boundsRectangle;

	@Override
	protected void sizeChanged () {
		if (boundsRectangle == null) {
			boundsRectangle = new Rectangle();
		}
		boundsRectangle.width = getWidth();
		boundsRectangle.height = getHeight();
	}

	/**
	 * 用于碰撞检测的矩形区域
	 * @return
	 */
	public Rectangle getBoundsRectangle () {
		boundsRectangle.x = getX();
		boundsRectangle.y = getY();
		return boundsRectangle;
	}

}



基于Libgdx开发的开源游戏框架CHGame:

http://git.oschina.net/oahcfly/CHGameFrame


© 著作权归作者所有

共有 人打赏支持
flyoahc
粉丝 12
博文 37
码字总数 15728
作品 0
南京
程序员
私信 提问
Libgdx学习笔记:封装贝塞尔曲线动作

对贝塞尔曲线不熟悉的,请自行百度了解下。在Libgdx中,已经提供了Bezier类。 // 起点,控制点,控制点,终点Bezier<Vector2> bezier = new Bezier<Vector2>(new Vector2(10, 300), new Vect...

flyoahc
2015/12/30
141
0
用canvas绘制一个曲线动画——深入理解贝塞尔曲线

摘要:在前端开发中,贝赛尔曲线无处不在:这篇文章我准备从实现一个非常简单的曲线动画效果入手,帮助大家彻底地弄懂什么是贝塞尔曲线,以及它有哪些特性,文章中有一点点数学公式,但是都非...

hujiulong/blog
2018/01/04
0
0
OpenGL超级宝典笔记——贝塞尔曲线和曲面

参数方程表现形式 在中学的时候,我们都学习过直线的参数方程:y = kx + b;其中k表示斜率,b表示截距(即与y轴的交点坐标)。类似地,我们也可以用一个参数方程来表示一条曲线。1962年,法国...

Mario_Q
2013/12/11
0
0
Android中moveTo、lineTo、quadTo、cubicTo、arcTo详解(实例)

最近在写android画图经常用到这几个,一开始还真不知道这个方法,更不用说能不能分清楚它们了,所以特此来做个小笔记,记录下moveTo、lineTo、quadTo、cubicTo、arcTo的作用,在自定义view的...

小湘西
2015/10/05
111
0
UIBezierPath 基础(一)

首先了解贝塞尔曲线的初始化方法都有那些,可以根据不同的需求来初始化;其次设置贝塞尔曲线的绘制路线;最后把贝塞尔曲线设置为layer的path,把layer添加到相应的view就能显示出你要绘制的贝...

Sunnyyangzx
2017/12/14
0
0

没有更多内容

加载失败,请刷新页面

加载更多

Java单例模式学习记录

在项目开发中经常能遇见的设计模式就是单例模式了,而实现的方式最常见的有两种:饿汉和饱汉(懒汉)。由于日常接触较多而研究的不够深入,导致面试的时候被询问到后有点没底,这里记录一下学习...

JerryLin123
昨天
3
0
VSCODE 无法调试

VSCODE 无法调试 可以运行 可能的原因: GCC 的参数忘了加 -g

shzwork
昨天
4
0
理解去中心化 稳定币 DAI

随着摩根大通推出JPM Coin 稳定币,可以预见稳定币将成为区块链落地的一大助推器。 坦白来讲,对于一个程序员的我来讲(不懂一点专业经济和金融),理解DAI的机制,真的有一点复杂。耐心看完...

Tiny熊
昨天
4
0
5.线程实现

用于线程实现的Python模块 Python线程有时称为轻量级进程,因为线程比进程占用的内存少得多。 线程允许一次执行多个任务。 在Python中,以下两个模块在一个程序中实现线程 - _thread 模块 th...

Eappo_Geng
昨天
6
0
ServiceLoader

创建一个接口文件在resources资源目录下创建META-INF/services文件夹在services文件夹中创建文件,以接口全名命名创建接口实现类 内容me.zzp.ar.d.PostgreSQLDialectme.zzp.ar.d.Hype...

Cobbage
昨天
6
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部