Corona中文站

强大、易学的跨平台(iOS/Android)开发框架。QQ群1:74390406(满) 群2:221929599

导航

五分钟学会Corona(四) - Images, Shapes, 和Text
关于Display Object

所有在屏幕上发生的绘制,都是通过创建DisplayObject来完成的。任何显示在屏幕上的东西,都是DisplayObject的实例。但你不能直接创建display object,而是直接创建display object的某种特例,例如rect、circle,image,text等。

这些对象都是第一类型。你可用它们产生动画,把它们变成按钮,等等。

你通过调用一个特定的函数来创建display object。这显式地把你创建的对象添加到其他对象的上面。DisplayObject是被设计用来作为公共功能的协议,所以你不能显示的创建一个Display Object对象本身。

相反,有具体特定类型的构造工厂,例如display.newRect()创建一个向量对象。

所有的display object构造器,显式地把新创建的对象的父对象设置为当前的stage object。(目前,在Corona中有且只有一个stage。Group对象可以被创建用来象stage一样组织对象)。大多数函数都有一个可选的parentGroup参数,用来指定对象的父对象为某个特定的group。

Display Object的所有实例,都非常类似于一个Lua table。这意味着你可以添加你自己的属性给对象,只要不和它们之前的属性和方法名冲突。Group对象(包含stage对象)有一些轻微的怪癖,下面将会讨论到;也可以参看文章后面专门的一节: "Display Objects vs. Tables"

此外,所有的display object都共同具有一下属性和对象方法:

公共属性

属性可通过.操作符进行访问。例如如果我们有一个Display Object,我们可以这样修改其alpha值到50%:object.alpha = 0.5。

下面是所有display object共享的通用属性:

object.alpha i对象的透明度。0表示透明,1.0表示不透明,默认值为1.0。

注意,这个alpha属性不同于在例如form(r,g,b[,a])中的a参数。form中alpha参数的范围是0-255,就像红绿蓝通道的范围一样,因为这时候每个通道是一个8位的颜色值。

object.height 对象高度,在本地坐标系中

object.isVisible c控制对象是否在屏幕上可见。true 可见而 false 相反。

object.isHitTestable 允许一个对象继续接收 hit events ,即便它是不可见的。如果 true, object将无论是否可见都接收hit events。如果false, events 将只发送给可见对象。

object.length [read-only] 不推荐,建议使用 group.numChildren. 对于 Group Object, 表示子对象的个数。否则为0。

object.parent [read-only] 返回对象的父group object。

object.rotation 当前旋转角度(角度值)

object.contentBounds 是一个table,包含如下属性:xMin, xMax, yMin, yMax,这些是基于屏幕坐标系的。一般用于映射一个object到屏幕坐标系。

object.contentHeight 在屏幕坐标系下的高度。

object.contentWidth 在屏幕坐标系下的宽度。

object.width 基于本地坐标。

object.x 指定object相对于父对象的x位置(本地坐标系)- the parent’s origin。更进一步说,它提供是对象的参考点相对于父对象的x位置。改变这个值,将会在x方向上移动这个对象。只改变对象的参考点,将不移动对象而改变对象的x和y值。

object.xOrigin 指定对象原点相对于父对象 origin 点的x位置。这个属性是参考本地坐标系的。改变这个值,将会在x方向上移动对象。

object.xReference 定义对象参考点相对于对象的 origin点的x位置。它是相对于对象中另一个点,而不是父对象。概念上讲,参考点其实就是伸缩和旋转发生所需的定位点。有时候,也叫注册点。对于大多数display object来说,这个值默认为0,这意味着origin和参考点的x的x位置是一样的。这个属性只是定义一个参考点,所以改变这个属性的值,并不会改变对象的位置。

object.xScale get 获得和设置x方向的伸缩因子。值0.5代表在x方向上把object缩小的原来的50%。

object.y 指定object相对于父对象的y位置(本地坐标系)- the parent’s origin。更进一步说,它提供是对象的参考点相对于父对象的y位置。改变这个值,将会在y方向上移动这个对象。只改变对象的参考点,将不移动对象而改变对象的x和y值。

object.yOrigin 指定对象原点相对于父对象 origin 点的y位置。这个属性是参考本地坐标系的。改变这个值,将会在y方向上移动对象。

object.yReference 定义对象参考点相对于对象的 origin点的y位置。它是相对于对象中另一个点,而不是父对象。概念上讲,参考点其实就是伸缩和旋转发生所需的定位点。有时候,也叫注册点。对于大多数display object来说,这个值默认为0,这意味着origin和参考点的y的y位置是一样的。这个属性只是定义一个参考点,所以改变这个属性的值,并不会改变对象的位置。

object.yScale 获得和设置y方向的伸缩因子。值0.5代表在y方向上把object缩小的原来的50%.

公共对象方法

对象方法一般通过冒号来访问。例如我们有一个display object变量,我们可以用这样把对象向右移动10像素。

object:translate( 10, 0 ).

下面是所有display object共有的对象方法:

object:getParent() 被废弃,建议使用 object.parent。 (是的,你应该放弃使用该API)

object:rotate( deltaAngle ) 高效地增加deltaAngle (角度)到当前的rotation属性。旋转。

object:scale( sx, sy ) 高效的把object的 xScale 和 yScale,分别乘以sx和sy。如果当前的 xScale 和 yScale 是 0.5,且 sx 和 sy 也是 0.5, 那结果导致 xScale 和 yScale 都变成0.25。该对象将会从原始大小的50%变成25%。

object:setReferencePoint( referencePoint ) 设置参考点到,要么object的中心(默认),要么object的边界矩形上的点。参数 referencePoint 应该为下面值当中的一个:

• display.CenterReferencePoint

• display.TopLeftReferencePoint

• display.TopCenterReferencePoint

• display.TopRightReferencePoint

• display.CenterRightReferencePoint

• display.BottomRightReferencePoint

• display.BottomCenterReferencePoint

• display.BottomLeftReferencePoint

• display.CenterLeftReferencePoint

按照设计,一个对象的参考点被相对于对象的本地origin静态的定位的。这意味着如果你用 setReferencePoint() 显式设置一个参考点,然后修改这个object的height或者width,参考点将不再指向同一个点。

改变对象的参考点,将会无需移动object而改变object的x和y值。

这会导致一个不可预料的结果,尤其是text对象:赋予不同的字符串给一个object的text属性改变了object的width,而不是它的参考点,这就改变了object的对齐方式。这个问题的解决办法,就是在赋予新的字符串之后,重设object的参考点和x位置。下面的代码提示这种方法(这些概念同样对其他类型的display object有效,例如image和shapes)。

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16
-- 一个text object被创建并在x=20处向左对齐

local textObj = display.newText("A short string", 0,0, nil, 14);

textObj:setReferencePoint(display.CenterLeftReferencePoint);

textObj.x = 20;



-- 然后,textObj.text被赋予一个不同长度的新字符串,

-- 导致object的width被改变,而没改变它的reference point.

-- 因此,文本不在x =20处向左对齐

textObj.text = "This string has several more characters than before..."



-- Work-around:

-- Reset这个text object的参考点和x

-- after you update its text property:

textObj.text = "This string has several more characters than before..."

textObj:setReferencePoint(display.CenterLeftReferencePoint);

textObj.x = 20


object:translate( deltaX, deltaY ) 高效的增加deltaX和deltaY到 x 和 y 属性上。这将会改变object的位置。

object:removeSelf( ) 删除这个display object,并且释放它的内存,你需要确保不再有别的变量引用到它。这等价于在同一个display object上 调用group:remove(IndexOrChild) ,但这语法上更简单一些。 removeSelf() 语法在其他情况也支持,例如物理子系统中参看 removing physics joints 。

在应用程序向导的 removing objects properly 一节中可以找到更多关于内存管理和显示对象删除方面的知识。

Images

DisplayObject当中的一种位图对象。

加载一个Image

display.newImage( filename [, baseDirectory] [, left, top] ) 返回一个image object。它从filenname中加载image数据,并且默认在system.ResourceDirectory 中寻找这个文件。如果你指定了参数 baseDirectory, 它将会从你指定的文件夹开始寻找(see system.pathForFile for valid values of baseDirectory)。支持 PNG和 JPEG 文件格式.

myImage = display.newImage( "image.png", 10, 20 )

myImage2 = display.newImage( "image.png" )

你可以可选的指定image的左上角的坐标位置。如果你不提供left和top,那么image居于原点。

本地origin在image的中心;参考点也被初始化到这个点上。这意味着,一旦图片在屏幕上,任何对x或y的访问将参考image的中心点坐标,而不是 display.newImage()指定的 left, top值。你可以通过指定一个不同的参考点给image来修改这个行为。

通过上面的代码多次加载相同的图片文件,并不会使用额外的纹理内存,因为Corona将会自动重新使用来自第一个image实例的纹理数据。

Image的自动伸缩

display.newImage() 的默认行为是自动伸缩的大图片。他会节省纹理内存。然而,当你有时不想具备图片自伸缩的特性时,有一个可选的布尔标志手动设置:

为了修改 autoscaling,按图片自身实际大小显示,可使用可选的 isFullResolution参数。默认情况下,为false,但是如果你指定为true,新的图片将会被加载:

display.newImage( [parentGroup,] filename [, baseDirectory] [, x, y] [,isFullResolution] )

myImage = display.newImage( "image.png", 10, 20, true )

有一些限制和提示:

• 索引的PNG图片文件不被支持。

• 灰度图像目前不支持,图像必须时RGB的。

• 如果纹理的大小超过设备的大小,图片还将会被自动伸缩。通常是 1024x1024 (iPhone 3G) 或 2048x2048 (iPhone 3GS, iPad).

• 如果你再次重新加载了同一个图片,随后调用display.newImage时,函数将会自动忽略本次你传入的 isFullResolution 参数,而偷偷使用第一次传递的该参数。换句话说,你第一次加载一个文件的方法,影响到你下次加载同样文件时的自动伸缩设置。这是因为Corona通过自动重用已经加载的纹理,来节省纹理内存。结果,你可以多次使用同一个图片,而无需消耗额外的纹理内存。


动态分辨率图像

动态分辨率图片之前用到的普通图片是一样的,只不过Corona会自动在更高分辨率的设备上替换成更高分辨率的图片。这可以让你不用修改你的代码,让你在更老的iphone上的程序,在iPhone4上使用两倍分辨率的图象。但是这个特性让你亲手去处理多屏幕部署带来的更大复杂性,包括比如不同设备的分辨率也许不是简单2:1比例的。

Dynamic image resolution works in conjunction with dynamic content scaling, which is discussed in the "Configuring Projects" section of the API Reference.

加载一个动态分辨率图像

语法:

display.newImageRect( [parentGroup,] filename [, baseDirectory] w, h ),

如下:

• w 是图像的内容宽度

• h 是图像的内容高度

实际图像选择将依赖 Corona 来确定的当前content的scale,当前屏幕和基本content尺寸的比例被定义在config.lua中。基于这个scale,Corona使用一个叫做imageSuffix的table(也定义在config.lua),列出了同一个图像家族的后缀,以在可用的图片选择中匹配最合适的。例如,你可以定义个图像后缀“@2”来指明2x分辨率图像,但是你也可以选择其他命名后缀或者其他乘数。

myDynamicImage = display.newImageRect( "baseImage.png", 100, 100 )

有一点很重要,需要记住:提供的两个数字,是基本图像的大小,而不是图像在屏幕上的位置。这个基本大小,必须在加载时被定义,所以Corona直到如何用更高分辨率的替代图片来渲染。

For a full discussion of how to use this feature, see the documentation on dynamic image resolution in the "Configuring Projects" section.

创建形状

Corona中的形状用vector对象来创建。Vector对象是DisplayObject的一种。下列函数会返回一个lua table,分别是矩形,圆角矩形,原型:

display.newRect( [parentGroup,] left, top, width, height ) 在 (left, top)处创建一个矩形。 本地origin位于矩形的中心;参考点也被初始化在本地origin处。默认情况下,没有填充颜色和笔触。

display.newRoundedRect( [parentGroup,] left, top, width, height, cornerRadius ) 在(left, top)处创建一个圆角矩形。圆角的半径是 cornerRadius。 本地origin位于矩形的中心; 参考点也被初始化在本地origin处。默认情况下,没有填充颜色和笔触。

display.newCircle( [parentGroup,] xCenter, yCenter, radius ) 创建了一个中心位于(xCenter, yCenter)的圆形。本地origin位于圆的中心。参考点被初始化在本地origin处。默认情况下,没有填充颜色和笔触。

设置笔触大小,填充色和笔触颜色

object.strokeWidth 以像素位单位设置笔触的大小。注意,笔触大小被分为内部和外部两个部分。笔触是位于object边框的中间,但当笔触大小是奇数,Corona把数字整除2(比如:3/2=1;1/2=0),将其设置到内部大小;深剩余部分是外部大小。这个规则避免了处理边界时候的含糊不清,比如一个3像素的笔触,也许内部1一个像素,而外部2个像素。

一种情况是如果矩形充满了屏幕,一个大小位1的笔触会完全绘制在屏幕外。所以还需要,通过添加一个笔触来增加object的宽度和高度,如两倍笔触外部的数值。

object:setFillColor( r, g, b [, a] ) 每个参数的范围都在0到255。Alpha是一个可选参数,默认值是255(不透明)。

object:setStrokeColor( r, g, b [, a] ) 每个参数的范围都在0到255。Alpha是一个可选参数,默认值是255(不透明)。

画线

display.newLine( )



画线系列API可以绘制连接的线段,通过Corona向量引擎还可以带上颜色的笔触大小。线条对象是标准的Corona display object,并且可以象其他display object一样移动和伸缩。笔触和颜色属性也可以在object绘制完成之后,再次改变。

线条是指定了端点的一系列顶点组成的线段。线有笔触大小,通过“width”参数。目前,多线段可以有尖角连接。换句话说,一个角连接就是一个点,而不是圆角,是开始和结束对接上的。

目前线条API一般如下:

local a = display.newLine( [parent,] x1,y1, x2,y2 )a:setColor( r, g, b, a )a:append( x, y [,... ] )a.width = strokeWidth

代码范例:

local star = display.newLine( 0,-110, 27,-35 )

star:append( 105,-35, 43,16, 65,90, 0,45, -65,90, -43,15, -105,-35, -27,-35, 0,-110 )

star:setColor( 255, 102, 102, 255 )

star.width = 3

参看 Graphics/PolyLines 范例代码,一个在iPhone和iPad上运行的动画范例。

文本

display.newText( [parentGroup,] string, x, y, font, size ) 基于左上角x,y创建一个文本对象。本地origin是文本的中心。参考点被初始化在本地origin上。默认情况下,没有文本颜色。

font参数是字体名称的字符串。你可以通过 获得一个 native.getFontNames() 可用的字体数组。 另外,你也可以传入下面常量来代替字符串:

• native.systemFont

• native.systemFontBold

设置文本大小,颜色和字符串值

object.size 是文本的大小。

object:setTextColor( r, g, b [, a] ) 每个参数的范围都在0到255。Alpha是一个可选参数,默认值是255(不透明)。

object.text i包含文本字段的字符串,可以用来修改文本对象的文本内容。

1

2

3

4

5
local myText = display.newText( "Hello, World", 0, 0, "Helvetica", 16 )

myText:setTextColor(0, 0, 255)



--Change the value of myText

myText.text = "Hello, Universe!"


使用自定义字体

你可以嵌入一个字体到你的app中。这需要你把字体文件加入到你的工程目录中。你必须有嵌入字体的合法权限。在iOS中,你必须用 UIAppFonts plist entry 来注册字体。但这只能工作在iOS3.2或更高版本,android1.6或更版本。( Harrowprint字体使用实例代码见这里 here)。在plist entry中包含了字体的扩展,被写在build.settings文件中。下面这个例子未包含android部分:

1

2

3

4

5

6

7

8

9

10

11

12

13
settings =

{

iphone =

{

plist =

{

UIAppFonts =

{

"Harrowprint.ttf"

}

},

},

}


当创建字体对象的时候,可以指向这个字体。你必须使用通过 native.getFontNames() 获得的字体名,而非文件名。

1
local text = display.newText( "Hello Harrowprint font!", 0, 0, "Harrowprint", 50 )


Group

Group对象是display object的一个特定类型。你可以添加其他display object作为一个group对象的子对象。你也可删除它们。甚至如果一个对象不可见,它也会保持在group对象中,直到它显式地被删除。这样,为了最小化内存消耗,你应该显式地删除所有不再需要的对象。

所有对象都隐式地被加入到当前的stage中,而stage也是一种group对象。(目前,在Corona中只有唯一一个stage,这个stage就表示整个屏幕)

group对象的子对象,可以其他display object(vector、group,等等)。它们可以用整数索引来访问。第一个子对象的索引是1。

注意

Lua table 库函数例如 table.insert 和 ipairs(table) 在group对象 中是不兼容的!这也包括获得组大小的,#table将返回table的大小,对group或其他任何display object都不行。为了获取group的大小(组中成员的个数),请使用 group.numChildren。

创建groups

display.newGroup() c创建一个你可以在其上添加和删除子display object对象的group。 一开始,group上没有任何子对象。本地 origin就是父对象的origin;参考点被初始化到本地origin。

获得组的子成员的个数 (Size)

group.numChildren 返回子成员的个数。你可以通过整数索引来访问子成员:

local group = display.newGroup()

group:insert( rect1 ) -- 假设rect是一个存在的display object

group:insert( rect2 ) -- 假设rect2是一个存在的display object



for i=1, group.numChildren do

local child = group[i]

local description = (child.isVisible and "visible") or "not visible"

print( "child["..i.."] is " .. description )

end


从Group中插入和删除对象

group:insert( [index,] child, [, resetTransform] ) 在index位置向组中插入子元素,必要时移动其他元素。index默认值是n+1,n是group中子元素个数。

resetTransform参数决定子元素的transform发生什么。当其为false,子元素的本地位置,旋转,伸缩属性被保留,除了本地origin是相对于新的父组,而不是相对前父组。当其为true,子对象的transform为重置(比如,x,y,rotation,xScale,yScale属性都被分别设置为0,0,0,1,1)。 resetTransform的默认值是false。移动一个对象到它的兄弟对象前面,是用再插入的方法:

object.parent:insert( object ).

注意

如果把一个display object插入到一个group,然后再把同一个object插入另一个group,那么这个display object将被从原来组中删除。一个object以此只能存在于一个group中。下面范例代码说明了这些:


1

2

3

4

5

6

7

8

9

10

11
local txt=display.newText('Hello',0,0)

local g1=display.newGroup()

local g2=display.newGroup()



-- Insert text object into g1

g1:insert(txt)

-- Insert same text object into g2

g2:insert(txt)



print("g1[1]: " .. tostring(g1[1])) -- prints nil

print("g2[1]: " .. tostring(g2[1])) -- prints textObject


group:remove( indexOrChild ) 通过指定 indexOrChild 从group中删除 display object ,必须时移动其他元素。indexOrChild参数可以是group中子对象的index位置,也可是子display object。这两种情况,函数都返回删除的display object。



Stage

Stage对象是Group对象的一个特定类型,所以所有group的方法和属性,对stage对象都有效。概念上讲,stage是所有display object和group的根组。你可用 display.getCurrentStage() 访问当前的stage object。

所有对象被隐式加入当前的stage。(目前,Corona中只有唯一一个stage,这个stage就是整个屏幕)

设置焦点

stage:setFocus( displayObject [, touchID] ) 设置display object为将来的hit event的目标。如果displayObject传nil,则表示修复hit event分发器的默认行为。这一般用来实现按钮的外观改变,当一个用户按下它时。


其他显示函数

display.captureScreen( saveToAlbum ) 捕获屏幕的内容,并且返回一个image对象,屏幕 的左上角为其origin。如果 saveToAlbum为true,那么将会添加图片到你的设备相册中;在模拟器中,它将保存到桌面。

display.getCurrentStage( ) 返回当前的stage对象的引用,它是所有display object和group的根组。目前,Corona有一个stage单例,所以这个函数永远返回同一个对象(指向整个屏幕)。

display.save( displayObject, filename [, baseDirectory] ) 把displayObject引用的显示对象写入到jpeg图像中并保存在filename中。而这个display object必须正处在显示层次中;否则图片将无法保存。如果这个display object是一个group对象,那么它所有的子对象都会被渲染。参数 baseDirectory是可选的。其值可以是 system.DocumentsDirectory (默认), 也可以是 system.TemporaryDirectory.

display.setStatusBar( mode ) 隐藏或改变状态栏的外观。这个mode参数必须为以下值中的一个:

• display.HiddenStatusBar

• display.DefaultStatusBar

• display.TranslucentStatusBar

• display.DarkStatusBar


Content尺寸属性

display.contentWidth 显示content原始宽度属性,只读,单位像素。默认这个值就是屏幕宽度,但是也可以通过config.lua中的content伸缩因素来指定为另一个值。

display.contentHeight 显示content原始高度属性,只读,单位像素。默认这个值就是高度宽度,但是也可以通过config.lua中的content伸缩因素来指定为另一个值。

display.viewableContentWidth 一个只读属性,包含可视屏幕区域的宽度,单位像素,且在原始content的坐标系内。这很有用,因为这取决于使用了哪一种动态伸缩模式,以及用于显示content的设备的宽高比。一些原始content将会被拉伸,比如部分在屏幕外时。

display.viewableContentHeight 一个只读属性,包含可视屏幕区域的高度,单位像素,且在原始content的坐标系内。这很有用,因为这取决于使用了哪一种动态伸缩模式,以及用于显示content的设备的宽高比。一些原始content将会被拉伸,比如部分在屏幕外时。

display.statusBarHeight 一个只读属性,基于像素,表示状态栏的高度。(只在iOS设备有效)。

Display Objects vs. Tables: 一个技术性讨论

在这一节的开始,我们说到display object的行为和lua中的table很“相似”。这个规则的一个例外,就是你不能设置display object的 metatable。这是因为在这个特殊情况下,我们的C++和Lua集成的固有特性。

Corona的display object是本地C++内部内向。这种lua实现绑定本地指针的方法是通过“userdata”,其metatable已经被设置了。Userdta的metatable不能被Lua代码替换;这是Lua自身定义的(参看Lua编程指南)

通常,绑定的lua的本地对象并不会象table,关于这个问题Corona中有很多现成的例子。这样的对象,可以有属性或方法,但是不能扩展。相反,Corona的display object的行为看上去还是很象table的--这是很方便的特性,另外也会有一个“user data”的字段,允许你访问你自己关联到display object上的数据。用此方法,提供这样的功能到display object中,对于最终用户来说会更加简便,也可以有更多扩展。所以底层的本地桥接,会受到lua自身特点的约束,所以我们看到这种架构选择,已经作为Corona的基础设计特性。根本上,Corona是一个基于快速开发设计的C++/OpenGL引擎框架,产品承诺在display object上可使用metatable的这些好处。
<< 五分钟学会Corona(三) - 基础函数五分钟学会Corona(五) - DisplayObject和Stage >>

发表评论:

◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。

最近发表

Powered By Z-Blog 1.8 Walle Build 100427 Copyright 2011-2015 BuildApp.Net. All Rights Reserved.