Libgdx专题系列:对象篇源码分析 Sprite

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/wu928320442/article/details/17165223

声明:

本系列文章使用的Libgdx版本均为0.99版本

Libgdx游戏开发交流群 323876830

 

Sprite即精灵,用于使用SpriteBatch,引用几何图形,颜色和纹理信息,来进行2D精灵绘制。 精灵有一个位置和一个给定的宽和高的大小。

位置是相对于通过SpriteBatch的begin和矩阵指定的坐标原点的。 精灵是一个矩形, 他的位置(x,y)是相对于矩形的左下角来的, 精灵有

一个环绕的中心点, 用来旋转和放缩的,但是旋转和放缩操作并不会对中心点进行修改。中心点的位置是相对于精灵的左下角来的。

首先来看看他是处理纹理的?

查看构造方法的时候, 看到他调用了

setRegion(srcX, srcY, srcWidth, srcHeight);

方法,看来还是使用TextureRegion的做法,这里要注意下,Sprite重写了TextureRegion的

public void setRegion (float u, float v, float u2, float v2)

方法,并对顶点纹理坐标值进行了赋值。

	public void setRegion (float u, float v, float u2, float v2) {
		super.setRegion(u, v, u2, v2);

		float[] vertices = Sprite.this.vertices;
		vertices[U1] = u;
		vertices[V1] = v2;

		vertices[U2] = u;
		vertices[V2] = v;

		vertices[U3] = u2;
		vertices[V3] = v;

		vertices[U4] = u2;
		vertices[V4] = v2;
	}

 

颜色的赋值也是比较直接的,四个顶点的color都是同样的值。

	public void setColor (float color) {
		float[] vertices = this.vertices;
		vertices[C1] = color;
		vertices[C2] = color;
		vertices[C3] = color;
		vertices[C4] = color;
	}


可以对精灵设置大小

	public void setSize (float width, float height) {
		this.width = width;
		this.height = height;

		if (dirty) return;

		float x2 = x + width;
		float y2 = y + height;
		float[] vertices = this.vertices;
		vertices[X1] = x;
		vertices[Y1] = y;

		vertices[X2] = x;
		vertices[Y2] = y2;

		vertices[X3] = x2;
		vertices[Y3] = y2;

		vertices[X4] = x2;
		vertices[Y4] = y;

		if (rotation != 0 || scaleX != 1 || scaleY != 1) dirty = true;
	}


设置旋转放缩中心点

	public void setOrigin (float originX, float originY) {
		this.originX = originX;
		this.originY = originY;
		dirty = true;
	}


对于平移变换,这里给出了几个方便使用的方法

public void setX (float x)

public void setY (float y)

public void translateX (float xAmount)

public void translateY (float yAmount)

public void translate (float xAmount, float yAmount)


这里操作的4个顶点的值对应的值为

	static public final int X1 = 0;
	static public final int Y1 = 1;
	static public final int C1 = 2;
	static public final int U1 = 3;
	static public final int V1 = 4;
	static public final int X2 = 5;
	static public final int Y2 = 6;
	static public final int C2 = 7;
	static public final int U2 = 8;
	static public final int V2 = 9;
	static public final int X3 = 10;
	static public final int Y3 = 11;
	static public final int C3 = 12;
	static public final int U3 = 13;
	static public final int V3 = 14;
	static public final int X4 = 15;
	static public final int Y4 = 16;
	static public final int C4 = 17;
	static public final int U4 = 18;
	static public final int V4 = 19;


每一个顶点都有x,y,c,u,v信息,分别对应坐标,颜色, uv纹理映射信息

 

旋转变换

public void setRotation (float degrees)
public void rotate (float degrees)


上面两个方法都是内部改变属性值,绘制的时候响应的坐标改变的。

public void rotate90 (boolean clockwise)

这个方法是根据改变纹理的旋转角度来达到旋转变换目的的,跟前两个有所不同,这个改变后,以后都是这个纹理角度了, 他不会更改顶点的坐标

信息来处理旋转,只是改变顶点的uv信息调整。

旋转变换,有个环绕点的概念,可以根据某一点进行旋转, 而不一定是图元的中心点,旋转的原理,这里我画了一张图,

 

 这里x0,y0是变换前的坐标,x,y是变换后的坐标,θ为旋转的角度,α是x0,y0与原点之间的夹角,r为到原点的长度。

这里根据数学知识,我们可以得到

x0= r*cosα

y0=r*sinα

x=r*cos(α+θ)=r*cosα*cosθ - r*sinα*sinθ=x0*cosθ-y0*sinθ

y=r*sin(α+θ)=r*sinα*cosθ+r*cosα*sinθ=y0*cosθ+x0*sinθ

这里只是相对于原点的旋转变换,如果遇到根据某一点的要怎么处理呢?

其实他的内部处理是这样的,先相对环绕点进行旋转变换,即把环绕点当做原点,然后把变换后的点根据环绕点的世界坐标,拉到世界坐标点。

这里看一下Libgdx旋转的处理

			float localX = -originX;
			float localY = -originY;
			float localX2 = localX + width;
			float localY2 = localY + height;

首先把坐标位置拉到相对于环绕点的坐标

然后计算环绕点的世界坐标,方便以后计算

			float worldOriginX = this.x - localX;
			float worldOriginY = this.y - localY;

然后计算旋转角的值

    final float cos = MathUtils.cosDeg(rotation);
    final float sin = MathUtils.sinDeg(rotation);

根据上面的我们分析的原理,很容易的知道左下角坐标的坐标

				final float localXCos = localX * cos;
				final float localXSin = localX * sin;
				final float localYCos = localY * cos;
				final float localYSin = localY * sin;

同理x2,y2.

这里计算出来的都是相对于环绕点的相对坐标,还要加上环绕点的世界坐标。

				final float x1 = localXCos - localYSin + worldOriginX;
				final float y1 = localYCos + localXSin + worldOriginY;

好了,左下角的坐标已经计算出来了,其他同理了。

 

 

放缩变换

public void setScale (float scaleXY)

public void setScale (float scaleX, float scaleY)

public void scale (float amount)

放缩变换,有个环绕点的概念,可以根据某一点进行放缩,而不一定是图元的中心点,放缩的原理,这里我画了一张图,

帮助大家理解。

originX,originY是图元相对于左下角的位置坐标,localX,localY为左下角的坐标,localX2,localY2为右上角的坐标,

这里有个worldOriginX,worldOriginY的概念,分别是在世界坐标内环绕点的xy坐标,为什么要计算这个呢?因为当我们根据

放缩重新计算左下角和右上角坐标的时候,可以拿新的左下角和右上角的坐标加上环绕点(放缩不变化)的世界坐标。

			float localX = -originX;
			float localY = -originY;
			float localX2 = localX + width;
			float localY2 = localY + height;
			float worldOriginX = this.x - localX;
			float worldOriginY = this.y - localY;
			if (scaleX != 1 || scaleY != 1) {
				localX *= scaleX;
				localY *= scaleY;
				localX2 *= scaleX;
				localY2 *= scaleY;
			}

根据上面的解释, 上面这段代码页比较好理解了,这里可以发现离环绕点越近,放缩越不明显, 因为localX,localY变化越小,同理,

localX2,localY2越来越大。

然后这里进行赋值

				final float x1 = localX + worldOriginX;
				final float y1 = localY + worldOriginY;
				final float x2 = localX2 + worldOriginX;
				final float y2 = localY2 + worldOriginY;

				vertices[X1] = x1;
				vertices[Y1] = y1;

				vertices[X2] = x1;
				vertices[Y2] = y2;

				vertices[X3] = x2;
				vertices[Y3] = y2;

				vertices[X4] = x2;
				vertices[Y4] = y1;

从上面我们也可以发现, 图元的坐标顺序, 是一个以左下角为起点, 顺时针递增的。看下图表示


 综上的变换, 在SpriteBatch中也有用到,如果遇到这些问题,可以参考这节。


转载请链接原文链接http://blog.csdn.net/wu928320442/article/details/17165223

 


 

展开阅读全文

没有更多推荐了,返回首页