isKindOfClass和isMemberOfClass 都是NSObject的比较Class的方法
但两个有很大区别:
isKindOfClass来确定一个对象是否是一个类的成员,或者是派生自该类的成员
isMemberOfClass只能确定一个对象是否是当前类的成员
例如:我们已经成NSObject派生了自己的类,isMemberOfClass不能检测任何的类都是基于NSObject类这一事实,而isKindOfClass可以。
[[NSMutableData data] isKindOfClass:[NSData class]]; // YES [[NSMutableData data] isMemberOfClass:[NSData class]]; // NO 例: - (void) testIsKindOfClass { Class1 *c1=[Class1 new]; if ([c1 isKindOfClass: [NSObject class]]) { NSLog(@"c1 is a kind of NSObject."); } if ([c1 isMemberOfClass:[Class1 class]]) { NSLog(@"c1 is Member of Class1 !"); } if (![c1 isMemberOfClass:[NSObject class]]) { NSLog(@"c1 is't Member of NSObject !"); } } 输出结果; c1 is a kind of NSObject . c1 is Member of Class1 ! c1 is't Member of NSObject !
Fmt包
import "fmt"
简介 ▾
Package fmt包含有格式化I/O函数,类似于C语言的printf和scanf。格式字符串的规则来源于C但更简单一些。
输出
格式:
一般:
%v 基本格式的值。当输出结构体时,扩展标志(%+v)添加成员的名字。the value in a default format.
when printing structs, the plus flag (%+v) adds field names
%#v 值的Go语法表示。
%T 值的类型的Go语法表示。
%% 百分号。
布尔型:
%t 值的true或false
整型:
%b 二进制表示
%c 数值对应的Unicode编码字符
%d 十进制表示
%o 八进制表示
%q 单引号
%x 十六进制表示,使用a-f
%X 十六进制表示,使用A-F
%U Unicode格式: U+1234,等价于"U+%04X"
浮点数:
%b 无小数部分、两位指数的科学计数法,和strconv.FormatFloat的'b'转换格式一致。举例:-123456p-78
%e 科学计数法,举例:-1234.456e+78
%E 科学计数法,举例:-1234.456E+78
%f 有小数部分,但无指数部分,举例:123.456
%g 根据实际情况采用%e或%f格式(以获得更简洁的输出)
%G 根据实际情况采用%E或%f格式(以获得更简洁的输出)
字符串和byte切片类型:
%s 直接输出字符串或者[]byte
%q 双引号括起来的字符串
%x 每个字节用两字符十六进制数表示(使用小写a-f)
%X 每个字节用两字符十六进制数表示(使用大写A-F)
指针:
%p 0x开头的十六进制数表示
木有'u'标志。如果是无类型整数,自然会打印无类型格式。类似的,没有必要去区分操作数的大小(int8, int64)。
宽度和精度格式化控制是指的Unicode编码字符的数量(不同于C的printf,它的这两个因子指的是字节的数量。)两者均可以使用'*'号取代(任一个或两个都),此时它们的值将被紧接着的参数控制,这个操作数必须是整型。
对于数字,宽度设置总长度,精度设置小数部分长度。例如,格式%6.2f 输出123.45。
对于字符串,宽度是输出字符数目的最低数量,如果不足会用空格填充。精度是输出字符数目的最大数量,超过则会截断。
其它符号:
+ 总是输出数值的正负号;对%q(%+q)将保证纯ASCII码输出
- 用空格在右侧填充空缺而不是默认的左侧。
# 切换格式:在八进制前加0(%#o),十六进制前加0x(%#x)或0X(%#X);废除指针的0x(%#p);
对%q (%#q)如果可能的话输出一个无修饰的字符串;
对%U(%#U)如果对应数值是可打印字符输出该字符。
' ' 对数字(% d)空格会留一个空格在数字前并忽略数字的正负号;
对切片和字符串(% x, % X)会以16进制输出。
0 用前置0代替空格填补空缺。
每一个类似Printf的函数,都会有一个同样的Print函数,此函数不需要format字符串,等价于对每一个参数设置为%v。另一个变体Println会在参数之间加上空格并在输出结束后换行。
如果参数是一个接口值,将使用内在的具体实现的值,而不是接口本身,%v参数不会被使用。如下:
var i interface{} = 23
fmt.Printf("%v\n", i)
将输出23。
如果参数实现了Formatter接口,该接口可用来更好的控制格式化。
如果格式(标志对Println等是隐含的%v)是专用于字符串的(%s %q %v %x %X),还提供了如下两个规则:
1. 如果一个参数实现了error接口,Error方法会用来将目标转化为字符串,随后将被按给出的要求格式化。
2. 如果参数提供了String方法,这个方法将被用来将目标转换为字符串,然后将按给出的格式标志格式化。
为了避免有可能的递归循环,例如:
type X string
func (x X) String() string { return Sprintf("<%s>", x) }
会在递归循环前转换值:
func (x X) String() string { return Sprintf("<%s>", string(x)) }
错误的格式:
如果提供了一个错误的格式标志,例如给一个字符串提供了%d标志,生成的字符串将包含对该问题的描述,如下面的例子:
错误或未知的格式标志: %!verb(type=value)
Printf("%d", hi): %!d(string=hi)
太多参数: %!(EXTRA type=value)
Printf("hi", "guys"): hi%!(EXTRA string=guys)
缺少参数: %!verb(MISSING)
Printf("hi%d"): hi %!d(MISSING)
使用非整数提供宽度和精度: %!(BADWIDTH) or %!(BADPREC)
Printf("%*s", 4.5, "hi"): %!(BADWIDTH)hi
Printf("%.*s", 4.5, "hi"): %!(BADPREC)hi
所有的错误都使用"%!"起始,(紧随单字符的格式标志)以括号包围的错误描述结束。
输入
一系列类似的函数读取格式化的文本,生成值。Scan,Scanf和Scanln从os.Stdin读取;Fscan,Fscanf和Fscanln 从特定的io.Reader读取;Sscan,Sscanf和Sscanln 从字符串读取;Scanln,Fscanln和Sscanln在换行时结束读取,并要求数据连续出现;Scanf,Fscanf和Sscanf会读取一整行以匹配格式字符串;其他的函数将换行看着空格。
Scanf, Fscanf, and Sscanf根据格式字符串解析数据,类似于Printf。例如,%x将读取一个十六进制数,%v将读取值的默认表示。
格式行为类似于Printf,但有如下例外:
%p没有提供
%T没有提供
%e %E %f %F %g %G是等价的,都可以读取任何浮点数或者复合数(非复数,指科学计数法表示的带指数的数)
%s 和 %v字符串使用这两个格式读取时会因为空格而结束
不设格式或者使用%v读取整数时,如果前缀为0(八进制)或0x(十六进制),将按对应进制读取。
宽度在输入中被解释(%5s意思是最多从输入读取5个字符赋值给一个字符串),但输入系列函数没有解释精度的语法(木有%5.2f,只有%5f)。
输入系列函数中的格式字符串,所有非空的空白字符(除了换行符之外),无论在输入里还是格式字符串里,都等价于1个空白字符。格式字符串必须匹配输入的文本,如果不匹配将停止读取数据并返回函数已经赋值的参数的数量。
所有的scan系列函数,如果参数包含Scan方法(或者说实现了Scanner接口),该参数将使用该方法读取文本。另外,如果被填写的参数的数量少于提供的参数的数量,将返回一个错误。
所有要被输入的参数都应该是基础类型或者实现了Scanner接口的数据类型的指针。
注意:Fscan等函数可以从输入略过一些字符读取需要的字符并返回,这就意味着一个循环的读取程序可能会跳过输入的部分数据。当数据间没有空白时就会导致出现问题。如果读取这提供给Fscan系列函数ReadRune 方法,这个方法可以用来读取字符。如果读取者还提供了UnreadRune 方法,该方法将被用来保存字符以使成功的调用不会丢失数据。为了给一个没有这些功能的读取者添加这俩方法,使用bufio.NewReader。
目录
func Errorf(format string, a ...interface{}) error
func Fprint(w io.Writer, a ...interface{}) (n int, err error)
func Fprintf(w io.Writer, format string, a ...interface{}) (n int, err error)
func Fprintln(w io.Writer, a ...interface{}) (n int, err error)
func Fscan(r io.Reader, a ...interface{}) (n int, err error)
func Fscanf(r io.Reader, format string, a ...interface{}) (n int, err error)
func Fscanln(r io.Reader, a ...interface{}) (n int, err error)
func Print(a ...interface{}) (n int, err error)
func Printf(format string, a ...interface{}) (n int, err error)
func Println(a ...interface{}) (n int, err error)
func Scan(a ...interface{}) (n int, err error)
func Scanf(format string, a ...interface{}) (n int, err error)
func Scanln(a ...interface{}) (n int, err error)
func Sprint(a ...interface{}) string
func Sprintf(format string, a ...interface{}) string
func Sprintln(a ...interface{}) string
func Sscan(str string, a ...interface{}) (n int, err error)
func Sscanf(str string, format string, a ...interface{}) (n int, err error)
func Sscanln(str string, a ...interface{}) (n int, err error)
type Formatter
type GoStringer
type ScanState
type Scanner
type State
type Stringer
Package files
doc.go format.go print.go scan.go
func Errorf
func Errorf(format string, a ...interface{}) error
Errorf根据格式字符串和参数表生成一个字符串,该字符串满足error接口。
func Fprint
func Fprint(w io.Writer, a ...interface{}) (n int, err error)
Fprint将所有参数都使用默认的格式写入w。如果相邻两个参数都不是字符串时,会在参数间添加空白。函数返回写入的字节数和任何遇到的错误。
func Fprintf
func Fprintf(w io.Writer, format string, a ...interface{}) (n int, err error)
Fprintf根据格式字符串将参数写入w。函数返回写入的字节数和任何遇到的错误。
func Fprintln
func Fprintln(w io.Writer, a ...interface{}) (n int, err error)
Fprintln将所有参数都使用默认的格式写入w并在最后添加换行。如果相邻两个参数都不是字符串时,会在参数间添加空白。函数返回写入的字节数和任何遇到的错误。
func Fscan
func Fscan(r io.Reader, a ...interface{}) (n int, err error)
Fscan从r读取文本,将连续的空白分割的数据存入连续的参数里。换行视同空白。它返回成功读取的参数的数量。如果少于提供的参数的数量,返回值err将报告原因。
func Fscanf
func Fscanf(r io.Reader, format string, a ...interface{}) (n int, err error)
Fscanf从r读取文本,根据格式字符串顺序将数据存入参数中。它返回成功解析并存入的参数的数量。
func Fscanln
func Fscanln(r io.Reader, a ...interface{}) (n int, err error)
Fscanln类似Fscanf,但会在换行符中止,并且存入最后一条后时读取位置必须有换行或者结束符。
func Print
func Print(a ...interface{}) (n int, err error)
Print将所有参数都使用默认的格式写入标准输出。如果相邻两个参数都不是字符串时,会在参数间添加空白。函数返回写入的字节数和任何遇到的错误。
func Printf
func Printf(format string, a ...interface{}) (n int, err error)
Printf根据格式字符串将参数写入标准输出。函数返回写入的字节数和任何遇到的错误。
func Println
func Println(a ...interface{}) (n int, err error)
Println将所有参数都使用默认的格式写入标准输出并在最后添加换行。如果相邻两个参数均非字符串时,会在参数间添加空白。函数返回写入的字节数和任何遇到的错误。
func Scan
func Scan(a ...interface{}) (n int, err error)
Scan从标准输入读取文本,将空白分割的连续数据顺序存入参数里。换行视同空白。它返回成功读取的参数的数量。如果少于提供的参数的数量,返回值err将报告原因。
func Scanf
func Scanf(format string, a ...interface{}) (n int, err error)
Scanf从标准输入读取文本,根据格式字符串顺序将数据存入参数中。它返回成功解析并存入的参数的数量。
func Scanln
func Scanln(a ...interface{}) (n int, err error)
Scanln类似Scan,但会在换行符中止,并且存入最后一条后时读取位置必须有换行或者结束符。
func Sprint
func Sprint(a ...interface{}) string
Sprint将所有参数都使用默认的格式写入并生成一个字符串。如果相邻两个参数都不是字符串时,会在参数间添加空白。
func Sprintf
func Sprintf(format string, a ...interface{}) string
Sprintf根据格式字符串将参数写入并返回生成的字符串。
func Sprintln
func Sprintln(a ...interface{}) string
Sprintln将所有参数都使用默认的格式写入并生成一个字符串。如果相邻两个参数都不是字符串时,会在参数间添加空白。字符串最后会添加换行符。
func Sscan
func Sscan(str string, a ...interface{}) (n int, err error)
Sscan从字符串读取文本,将空白分割的连续数据顺序存入参数里。换行视同空白。它返回成功读取的参数的数量。如果少于提供的参数的数量,返回值err将报告原因。
func Sscanf
func Sscanf(str string, format string, a ...interface{}) (n int, err error)
Scanf从字符串读取文本,根据格式字符串顺序将数据存入参数中。它返回成功解析并存入的参数的数量。
func Sscanln
func Sscanln(str string, a ...interface{}) (n int, err error)
Sscanln类似Sscan,但会在换行符中止,并且存入最后一条后时读取位置必须有换行或者结束符。
type Formatter
type Formatter interface {
Format(f State, c rune)
}
Formatter是一个供用户定制的格式化接口。Format方法的实现可能需要调用Sprintf 或Fprintf(f)等函数来生成输出。
type GoStringer
type GoStringer interface {
GoString() string
}
GoStringer接口由任意包含GoString方法的数据实现,这个方法定义了数据的Go语法格式。GoString方法用来在使用%#v格式标志时输出值。
type ScanState
type ScanState interface {
// ReadRune函数从输入读取下一个Unicode符号。如果在Scanln,Fscanln或Sscanln中调用,本函数会在读取到第一个'\n'或达到最大宽度时返回EOF。
ReadRune() (r rune, size int, err error)
// UnreadRune会让ReadRune的下一次调用返回同一个字符。
UnreadRune() error
// SkipSpace跳过输入的空白。换行被视为空白(Scanln,Fscanln和Sscanln例外,这三个函数里换行符视为EOF)。
SkipSpace()
// Token方法会在skipSpace为真时跳过输入中的空白,并返回一个满足f(c)的Unicode字符。如果f是nil,则使用!unicode.IsSpace(c)(即返回第一个非空格Unicode字符);
// 即是说,本函数只对非空字符起效。换行符视为空白字符(Scanln,Fscanln和Sscanln例外,这三个函数里换行符视为EOF)。
// 返回的切片类型指向共享的数据,该数据可以被下一次Token的调用(使用ScanState接口作为输入调用Scan函数)中或者调用返回的Scan方法时重写。
Token(skipSpace bool, f func(rune) bool) (token []byte, err error)
// Width返回width选项的值以及其是否被设定。
Width() (wid int, ok bool)
// 因为ReadRune用接口实现,Read方法应该永远不被scan程序调用,一个好使的ScanState实现应该保证总是从Read返回错误。
Read(buf []byte) (n int, err error)
}
ScanState是一个交给用户定制的Scanner接口的参数的接口。Scanner接口可能会进行一次一个字符的扫描或者要求ScanState去探测下一个空白分隔的token。
type Scanner
type Scanner interface {
Scan(state ScanState, verb rune) error
}
任何实现了Scan方法的对象都实现了Scanner接口,Scan方法会从输入读取数据并将处理结果存入接受端,接收端必须是有效的指针。Scan方法会被任何Scan、Scanf、Scanln等函数调用,只要对应的参数实现了该方法。
type State
type State interface {
// Write可被调用以发出格式化的输出。
Write(b []byte) (ret int, err error)
// Width返回宽度的值及其是否被设定。
Width() (wid int, ok bool)
// Precision返回精度的值及其是否被设定。
Precision() (prec int, ok bool)
// Flag返回符号(正负号……)的值是否被设定。
Flag(c int) bool
}
State是一个提供给Formatter接口的输出参数的接口。它提供对io.Writer接口的、使用提供的数据对参数格式化后的访问。
type Stringer
type Stringer interface {
String() string
}
Stringer接口被任何实现了String方法的类型自动实现,该方法定义了该类型的“原生”格式。String方法用来输出参数,当使用%s或%v格式时,或者被Print等不使用格式字符串的函数输出时。
1楼Vestigge前天 13:33支持一下算是第一篇非转载的文章了~
在这里推荐个Unity3d很多功能效果的脚本集合的网站,也是部门老大发现给我的~
http://wiki.unity3d.com/index.php?title=Scripts/General
本人也是个初级的开发者,这里只是作为一个学习的总结,如果哪里的理解错了,欢迎纠正。
帧动画的实现可以用第三方的插件,类似2DToolkit,可以很容易的实现帧动画,但有时还是不要太过于依赖第三方的插件。有时间还是得自己研究如何实现,不能一直穿着别人的内裤啊~
这个是本次项目的最终效果图:
关于在Unity3d下如何用代码生成面,这里雨松MOMO已经有相关的博文:
http://www.xuanyusong.com/archives/780
理解下一张Material的坐标系,这里用了网上找的一张图片:
每个Material都有自己的这个坐标系。
而如果需要把一张纹理贴到一个面上,则需要把贴图上的UV坐标(UV坐标就是上面的坐标系)对应到面的每个顶点上,如图(又是网上的图片):
比如有下面一张图片:
图片总宽高为:192x152,单张精灵的宽高为48x38;
如果我们只想显示左上角的1张图片,代码如下
using UnityEngine; using System.Collections; public class ViewImage : MonoBehaviour { public int widthCount , heightCount; //图片的宽高比例// public float width = 48,height = 38; //素材贴图// public Material material; //顶点数// private int verticesCount = 4; private Vector2 size; private Mesh mesh; public int frameIndex = 0; private MeshRenderer meshRenderer; // Use this for initialization void Start () { initFace(); } /// <summary> /// 初始化一个面 /// </summary> private void initFace(){ //得到MeshFilter对象// MeshFilter meshFilter = gameObject.GetComponent<MeshFilter>(); if(meshFilter == null){ //为null时,自动添加// meshFilter = gameObject.AddComponent<MeshFilter>(); meshRenderer = gameObject.AddComponent<MeshRenderer>(); meshRenderer.sharedMaterial = material; } //得到对应的网格对象// mesh = meshFilter.mesh; //三角形顶点的坐标数组// Vector3[] vertices = new Vector3[verticesCount]; //得到三角形的数量// int trianglesCount = verticesCount - 2; //三角形顶点数组// int[] triangles = new int[verticesCount *3]; float tmpWidth = 1.0f; float tmpHeight = 1.0f ; vertices[0] = new Vector3(0,0,0); vertices[1] = new Vector3(0,tmpHeight,0); vertices[2] = new Vector3(tmpWidth,0,0); vertices[3] = new Vector3(tmpWidth,tmpHeight,0); mesh.vertices = vertices; /* * * 如果下面的顶点连线看不明白,看这里 triangles[0] = 0; triangles[1] = 1; triangles[2] = 2; triangles[3] = 1; triangles[4] = 3; triangles[5] = 2; */ //起始三角形顶点// int start = 0; //结束三角形的顶点// int end = 2; for(int i = start; i <end; i++) { for(int j = 0; j < 3; j++) { if( i%2 ==0) { triangles[3*i + j] = i +j; }else { triangles[3*i + j] = i + 2-j; } } } mesh.triangles = triangles; Vector3 localScale = new Vector3(width,height,1.0f); transform.localScale = localScale; size = new Vector2 (1.0f / widthCount , 1.0f / heightCount); setUVPosition(frameIndex,mesh); } //设置uv坐标 private void setUVPosition(int index,Mesh mesh){ //得到相对于图片的行列坐标// int uIndex = index % widthCount; //列坐标// int vIndex = index / heightCount; //行坐标// //左下角的坐标点;// Vector2 vertices0 = new Vector2 (uIndex * size.x, 1.0f - size.y - vIndex * size.y); //左上角坐标// Vector2 vertices1 = new Vector2(vertices0.x , vertices0.y + size.y); //右下角坐标// Vector2 vertices2 = new Vector2(vertices0.x + size.x , vertices0.y ); //右上角坐标// Vector2 vertices3 = new Vector2(vertices0.x + size.x , vertices0.y + size.y); mesh.uv = new Vector2[]{vertices0 , vertices1 , vertices2 , vertices3}; } }
代码上面都有注释,这里关于用图片的素材球的Shader说明下,一开始我用Transparent/Diffuse,但是在运行时,切换uv坐标时控制台打印了Shader wants normals, but the mesh doesn't have them 这个消息。Google下也不知道为什么,最后用Unlit/Transparent就没有打印了,所以哪位大神知道原因告诉我下~~
继续,现在已经可以从一张大贴图中显示其中的一张图片了,接下来整理成动画就是把这些帧图片整合在一起,在Update里头切换就KO了,代码如下:
//控制动画帧数// public int[] aniArray; void Update(){ if(Time.frameCount % 8 == 0){ int len = aniArray.Length; int curIndex = aniArray[frameIndex]; setUVPosition(curIndex,mesh); frameIndex ++; frameIndex %= len; } }
下面是项目的一张截图,用红线圈起来的部分是动画帧的下标数组。
WidgetCount:大贴图x方向上有多少张图片。
HeightCount:大贴图y方向上有多少张图片。
Width:分隔的小贴图的宽度。
Height:f分隔的小贴图的高度。
FrameIndex:当前播放到第几帧的下标。
Ani Array:帧动画的下标集合数组。
O了,这篇其实好早就在写,但一直没去完成..今天光棍就顺便完成掉~