切换Prefab的保存模式

Unity中prefab的默认保存模式是Mixed的,用文本编辑器打开会出现乱码和部分文本,可以通过Edit—>Project Settings—>Editor将Asset Serialization Mode改为Force Text再保存就能显示全文本了。

git

git add不仅用于新增文件,改动的文件也需要使用它加入commit队列

git commit -m “这里是提交注释”

git push

Resources.Load和Asset

Resources.Load 加载Resources文件夹里指定路径的asset
AssetBundle 支持通过WWW类来使用流式的assets
Resources.Load从一个默认打进游戏包里的AssetBundle加载资源,而AssetBundle的方式是自己创建、管理AssetBundle文件并从中加载资源,两者本质上没有区别。

AssetBundle的加载:
CreateFromFile从硬盘加载一个AssetBundle文件
CreateFromMemory异步从内存数据创建一个AssetBundle
CreateFromMemoryImmediate同步从内存数据创建一个AssetBundle
AssetBundle加载完毕后只是在内存里创建了AssetBundle的数据结构,此时还没有assets的概念。

Assets的加载:
AssetBundle.Load等加载asset的方法才会从AssetBundle中创建一个asset,这里面可能包括了GameObject、Transform、Texture、Mesh、Material、Shader等各种资源。
当使用asset(prefab) Instantiate出一个对象时,是对这个asset进行复制(clone)加引用的过程:
GameObject、Transform是复制出来的;
Texture、TerrainData是引用原asset的;
Mesh、Material是复制和引用同时存在的。
因此这里需要注意:当Instantiate出的对象未Destory前不能卸载它引用的asset,而当对象Destory后需要通过Resources.UnloadUnusedAssets来释放不再引用的asset。

AssetBundle的卸载:
public void Unload(bool unloadAllLoadedObjects);
unloadAllLoadedObjects为true时将卸载AsserBundle的同时会卸载从AssetBundle中加载出来的assets,如果此时还有对象引用着这些assets时会不安全。
unloadAllLoadedObjects为false时只会卸载AssetBundle,要卸载从AssetBundle中加载出来的assets时需要在合适的时机调用Resources.UnloadUnusedAssets。

http://game.ceeger.com/forum/read.php?tid=4394

Objective-C

https://developer.apple.com/library/mac/documentation/Cocoa/Conceptual/ProgrammingWithObjectiveC/Introduction/Introduction.html

Protocol的定义形式:
@protocol ProtocolName
// list of methods and properties
@end

通过属性引用一个实现了Protocol的对象:
@property (weak) id <XYZPieChartViewDataSource> dataSource;

Protocol中可以定义必须实现的方法和可选实现的方法,默认是必须实现的。使用关键字@optional和@required可以声明它们以下的方法是可选或必须实现的:
@protocol XYZPieChartViewDataSource
– (NSUInteger)numberOfSegments;
– (CGFloat)sizeOfSegmentAtIndex:(NSUInteger)segmentIndex;
@optional
– (NSString *)titleForSegmentAtIndex:(NSUInteger)segmentIndex;
– (BOOL)shouldExplodeSegmentAtIndex:(NSUInteger)segmentIndex;
@required
– (UIColor *)colorForSegmentAtIndex:(NSUInteger)segmentIndex;
@end

调用Protocol中的可选方法时需要通过respondsToSelector:和@selector()先检查对象是否实现了该方法:
NSString *thisSegmentTitle;
if ([self.dataSource respondsToSelector:@selector(titleForSegmentAtIndex:)]) {
thisSegmentTitle = [self.dataSource titleForSegmentAtIndex:index];
}

Protocol可以继承:
@protocol MyProtocol <NSObject>

@end

类实现多个协议:
@interface MyClass : NSObject <MyProtocol, AnotherProtocol, YetAnotherProtocol>

@end
注意:编译器不会合成协议中声明的属性。

Block也是OC对象,其定义形式为:
^{
NSLog(@”This is a block”);
}
^ double (double firstValue, double secondValue) {
return firstValue * secondValue;
}

同C语言里函数指针可以指向一个函数一样,OC里可以使用Block Pointer:
void (^simpleBlock)(void);

Block能抓住闭包范围内的值,但它不能改变值。如果Block要改变一个被Block抓住的变量的值,需要对该变量使用__block修饰符。
注意:Block若抓住了self时,可能引起强引用循环引用的问题。
解决循环引用的问题可以在Block内部使用__weak的self:
– (void)configureBlock {
XYZBlockKeeper * __weak weakSelf = self;
self.block = ^{
[weakSelf doSomething]; // capture the weak reference
// to avoid the reference cycle
}
}

Class中使用属性引用Block时要使用copy属性修饰符:
@interface XYZObject : NSObject
@property (copy) void (^blockProperty)(void);
@end

Operation Queues是Cocoa进行任务调度的一个途径。可以创建一个NSOperation实例将一个任务及其需要的数据封装起来,然后将它加入一个NSOperationQueue来执行。
使用NSBlockOperation创建一个使用Block的Operation:
NSBlockOperation *operation = [NSBlockOperation blockOperationWithBlock:^{

}];

// schedule task on main queue:
NSOperationQueue *mainQueue = [NSOperationQueue mainQueue];
[mainQueue addOperation:operation];

// schedule task on background queue:
NSOperationQueue *queue = [[NSOperationQueue alloc] init];
[queue addOperation:operation];

Block也可以使用Grand Central Dispatch (GCD)控制的Dispatch Queues来执行。
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);

dispatch_async(queue, ^{
NSLog(@”Block for asynchronous execution”);
});

UIButton Normal状态颜色不对的问题

今天试验一个方案的时候遇到了一个UIButton的问题:按钮显示出来的时候Normal状态的颜色被设置成了Color.grey。正常情况下应该是Color.white,之前也从未遇到过这个问题,觉得挺奇怪的。

开始怀疑是不是代码里调用了设置按钮disable状态的方法,或者播放了TweenColor动画,但是经过一番搜索后无果。于是想着新建一个空的场景,里面只创建一个UIButton,排除其它因素的影响来看看它的表现是否正常。结果也是编辑器的状态下显示正常,而Play的时候TweenColor自动将其颜色由Color.white变为了Color.grey。

最后只能拿出UIButton的源码查看并调试了。UIButton的源码里有一个UpdateColor方法,它的作用正是通过TweenColor动画改变按钮颜色。

UpdateColor选择在此处下断,发现UIButton在OnEnable的时候确实改变了按钮的颜色。

UpdateColor下断为什么会改变按钮颜色呢?原来OnEnable里判断isEnabled为false了,而isEnabled为false的情况有三种:1、UIButton为禁用状态;2、未设置collider;3、collider为禁用状态。

OnEnable和isEnabled检查自己创建按钮的过程,为了快速试验方案只是创建了一个GameObject绑定上UISprite和UIButton,确实忘了设置collider。问题原因找到了,但仔细想想UIButton这里的细节可以做些更人性化的改动。因为通常情况下UI加入按钮肯定是要响应点击等事件的,而UIButton完成这些任务又必须要collider来配合,所以对于UIButton里collider未设置的情况可以输出一个warning来提醒使用者。

解决更新Mac OS X后MacVim无法使用的问题

前段时间更新了Mac OS X到Yosemite 10.10.1,今天要用到MacVim时突然发现不能用了,表现为通过GUI打开时只有MacVim的菜单却没有窗口,通过终端打开时提示:

dyld: Library not loaded: /System/Library/Perl/5.12/darwin-thread-multi-2level/CORE/libperl.dylib
Referenced from: /Applications/MacVim.app/Contents/MacOS/Vim
Reason: image not found
Trace/BPT trap: 5

查到问题是由于新系统里Perl 5.12的动态库也升级了,解决办法是下载MacVim最新的Release版本或者下载源码在新系统上编译即可。

这里有关于该问题的讨论:https://code.google.com/p/macvim/issues/detail?id=484&q=Mavericks

这里有MacVim的源码和Release:https://github.com/b4winckler/macvim

NGUI源码剖析之UIRect

UIRect是一个代表UI矩形区的抽象类。一个矩形区有上、下、左、右四边,因此UIRect中有4个锚点分别指示这四边anchor的位置:
public AnchorPoint leftAnchor = new AnchorPoint();
public AnchorPoint rightAnchor = new AnchorPoint(1f);
public AnchorPoint bottomAnchor = new AnchorPoint();
public AnchorPoint topAnchor = new AnchorPoint(1f);

有bottom-left、top-left、top-right、bottom-right四个角:
public abstract Vector3[] localCorners { get; }
public abstract Vector3[] worldCorners { get; }

每个矩形区是一个UI的容器,因此UIRect可以组成一个树状结构:
BetterList<UIRect> mChildren即孩子节点列表,OnInit、OnDisable及ParentHasChanged时将进行动态的Add和Remove。
UIRect mParent即父节点,会从该UIRect绑定的GameObject进行回溯寻找,bool mParentFound表示其有没有进行过回溯寻找。

NGUI中UIRoot是所有UI对象的根节点,UIRect中的UIRoot mRoot就指向了该节点,bool mRootSet表示其有没有进行过回溯寻找。

UIRect里为了加速访问绑定的GameObject及其Transform做了缓存:
protected GameObject mGo;
protected Transform mTrans;
public GameObject cachedGameObject { get { if (mGo == null) mGo = gameObject; return mGo; } }
public Transform cachedTransform { get { if (mTrans == null) mTrans = transform; return mTrans; } }

Camera mMyCam为负责渲染UIRect绑定的GameObject这一层的Camera,bool mAnchorsCached表示其以及4个锚点的数据有没有设置好。
bool mStarted:UnityEngine是否回调了Start方法
bool mChanged:父对象中有值(如alpha)改变时将其设置为true,用于刷新表现。
int mLastInvalidate:通过Time.frameCount记录下最后调用Invalidate的帧数。
int mUpdateFrame:通过Time.frameCount记录已经Update过的帧数。

UIRect中的主要功能在Update里:
1、通过mAnchorsCached判断是否需要更新锚点的相关数据,需要则通过ResetAnchors来更新数据。
2、通过mUpdateFrame与Time.frameCount判断该帧是否已经经过Update处理,处理过则本次Update结束了。
3、分别判断4个锚点是否有设置,有的话则判断该锚点的rect是否已经经过Update处理,未处理过则调用其Update方法。
4、判断4个锚点是否至少有1个有设置,则调用OnAnchor方法。
5、调用OnUpdate方法继续处理。
OnAnchor和OnUpdate方法均是抽象方法,需要由UIRect的子类自己来实现:
protected abstract void OnAnchor ();
protected virtual void OnUpdate () { }

NGUI源码剖析之UIRect.AnchorPoint

AnchorPoint(锚点)用于定位对象相对于目标对象在水平或垂直方向的位置。
Transform target即目标对象。
UIRect rect即目标对象上绑定的UIRect组件,可能为null。
Camera targetCam为负责渲染目标对象这一层的Camera。
int absolute为对象相对于目标对象在水平或垂直方向的偏移量。
float relative有三个取值0f、0.5f、1f。
锚点应用于UIRect中,UIRect中有上、下、左、右4个锚点分别用于定位其四条边的位置。
若目标对象无对应的UIRect时,目标对象的位置即其中心点的位置(target.position)。水平方向计算其与leftAnchor的偏移时会先通过对对象UIRect的worldCorners[0](bottom-left corner)和worldCorners[1](top-left corner)进行线性插值计算出UIRect的左边中心点,这两个中心点的x差值即偏移量。
若目标对象有对应的UIRect时,锚点定位对象相对于目标对象水平方向的位置时分为left、center和right对齐,垂直方向则分为top、center和bottom对齐。这种情况下在Unity编辑器中设置好一个锚点后,可以随时在left/center/right和top/center/bottom间切换,NGUI会保持对象的位置并且动态计算出新的对齐方式下对象与目标对象的偏移量。
参考文章:Explanation Local Vs Global Space