與2.x相比,節點類Node的屬性和功能做了大幅度的修改與增加。
Node類是絕大部分類的父類(並不是所有的類,例如Director類是直接繼承Ref類的),如Scene、Layer、Sprite以及精靈集合SpriteBatchNode等等等等的父類都是Node。
Node類包含了一些基本的屬性、節點相關、Action動作的執行、以及定時器等相關的操作。
當然Node也有父類,其父類爲Ref。
繼承關係如下:
一個節點的主要特點:
> 他們可以包含其他的節點對象(addChild, getChildByTag, removeChild, etc)
> 他們可以安排定期的回調(schedule, unschedule, etc)
> 他們可以執行一些動作(runAction, stopAction, etc)
> 子類節點通常意味着(單一的/所有的):
> 重寫初始化資源並且可以安排回調
> 創建回調來操作進行的時間
> 重寫“draw”來渲染節點
> 節點的屬性有:位置、縮放、旋轉、傾斜、錨點、內容大小、可見性
下面將介紹一下節點主要常用的一些操作函數,以及新的功能特性。
(1)節點的屬性
(2)節點的操作
(3)動作相關Action
(4)定時器相關schedule
(5)整合NodeRBGA類
(6)查找子節點enumerateChildren
(7)渲染順序zOrder
(8)座標轉換
1、節點的屬性
節點的屬性有:位置、縮放、旋轉、傾斜、錨點、內容大小、可見性。
//
/**
* 位置Position
* 設置節點的座標(x,y).在OpenGL中的座標
* 增加3D座標
* 增加標準化座標設置
*/
virtual void setPosition(const Vec2 &position); //Vec2座標
virtual void setPosition(float x, float y); //(x,y),比Vec2更有效率
virtual void setPositionX(float x);
virtual void setPositionY(float y);
virtual const Vec2& getPosition() const;
virtual void getPosition(float* x, float* y) const;
virtual float getPositionX(void) const;
virtual float getPositionY(void) const;
//增加3D座標
virtual void setPosition3D(const Vec3& position); //Vec3座標
virtual Vec3 getPosition3D() const;
virtual void setPositionZ(float positionZ);
virtual float getPositionZ() const;
//增加標準化座標設置
//Node的位置像素會根據它的父節點的尺寸大小計算
//Size s = getParent()->getContentSize();
//_position = pos * s;
virtual void setNormalizedPosition(const Vec2 &position);
virtual const Vec2& getNormalizedPosition() const;
/**
* 放縮Scale
* 設置節點的放縮比例. 對XYZ軸進行放縮
* 例如一張圖片. 放縮它的寬X,高Y,深Z
*/
virtual void setScaleX(float scaleX); //放縮寬X
virtual void setScaleY(float scaleY); //放縮高Y
virtual void setScaleZ(float scaleZ); //放縮深Z
virtual void setScale(float scaleX, float scaleY); //X放縮fScaleX倍,Y放縮fScaleY倍
virtual void setScale(float scale); //XYZ同時放縮scale倍
virtual float getScaleX() const;
virtual float getScaleY() const;
virtual float getScaleZ() const;
virtual float getScale() const; //當x,y放縮因子相同時,得到該節點的縮放因子
/**
* 旋轉Rotation
* 設置節點的旋轉角度. 負順,正逆時針旋轉
* 增加3D旋轉
*/
virtual void setRotation(float rotation);
virtual float getRotation() const;
//增加3D旋轉
virtual void setRotation3D(const Vec3& rotation);
virtual Vec3 getRotation3D() const;
/**
* 傾斜Skew
* 設置XY軸的傾斜角度
* setRotationalSkew() 模擬Flash的傾斜功能
* setSkew() 使用真正的傾斜功能
*/
virtual void setSkewX(float skewX); //水平旋轉傾斜.負順時針變形
virtual void setSkewY(float skewY); //垂直旋轉傾斜
virtual void setRotationSkewX(float rotationX);
virtual void setRotationSkewY(float rotationY);
virtual float getSkewX() const;
virtual float getSkewY() const;
virtual float getRotationSkewX() const;
virtual float getRotationSkewY() const;
/**
* 錨點AnchorPoint
* 錨點就像一枚圖釘,將圖片釘在屏幕上.而錨點就是圖片的座標.
* 當然圖釘可以釘在圖片的左下角,右上角,或者中心都可以.
* (0,0)表示左下角,(1,1)表示右上角
* 默認的錨點是(0.5,0.5),即節點的正中心
*/
virtual void setAnchorPoint(const Vec2& anchorPoint); //標準化的錨點
virtual const Vec2& getAnchorPoint() const; //標準化的錨點
virtual const Vec2& getAnchorPointInPoints() const; //返回絕對像素的錨點,即屏幕座標
//是否忽略錨點的設置
//若忽略錨點設置,錨點永遠爲(0,0)
//默認值是false, 但是在Layer和Scene中是true
//這是一個內部方法,僅僅被Layer和Scene使用,不要自行調用!
virtual void ignoreAnchorPointForPosition(bool ignore);
virtual bool isIgnoreAnchorPointForPosition() const;
/**
* 內容大小ContentSize
* contentSize依然是相同的,無論節點是縮放或者旋轉
* 所有的節點都有大小,圖層和場景有相同的屏幕大小
*/
virtual void setContentSize(const Size& contentSize);
virtual const Size& getContentSize() const;
/**
* 可見性Visible
*/
virtual void setVisible(bool visible);
virtual bool isVisible() const;
//
2、節點的操作
節點的操作有:標記、名字、自定義數據、父節點管理、子節點管理、其他操作管理。
//
/**
* 標記與名字 Tag and Name
* setTag : 給節點設置一個編號
* setName : 給節點設置一個名字
*/
virtual void setTag(int tag);
virtual void setName(const std::string& name);
virtual int getTag() const;
virtual std::string getName() const;
/**
* 自定義數據UserData/Object
* setUserData : 設置一個用戶自定義的數據. 可以爲一個數據塊, 結構體或者一個對象.
* setUserObject : 設置一個用戶自定義的對象. 和userData類似, 但它是一個對象而不是void*
*/
virtual void setUserData(void *userData);
virtual void setUserObject(Ref *userObject);
virtual void* getUserData();
virtual Ref* getUserObject();
/**
* 設置父節點Parent
* setParent , removeFromParent
*/
virtual void setParent(Node* parent);
virtual Node* getParent();
virtual void removeFromParent();
virtual void removeFromParentAndCleanup(bool cleanup); //true則刪除該節點的所有動作及回調函數.
/**
* 管理子節點Child
* addChild ,
* getChildBy** , getChildren , getChildrenCount
* removeChild , removeAllChildren
* reorderChild , sortAllChildren
*/
//添加子節點
//localZOrder Z軸順序爲了繪畫的優先權
//tag 節點編號,可通過tag獲取子節點
//name 節點名字,可通過name獲取子節點
virtual void addChild(Node * child);
virtual void addChild(Node * child, int localZOrder);
virtual void addChild(Node* child, int localZOrder, int tag);
virtual void addChild(Node* child, int localZOrder, const std::string &name);
//獲取子節點
virtual Node* getChildByTag(int tag) const;
virtual Node* getChildByName(const std::string& name) const;
virtual Vector<Node*>& getChildren(); //獲得所有子節點,並以Vector數組返回
virtual ssize_t getChildrenCount() const; //子節點總數
//刪除子節點
virtual void removeChild(Node* child, bool cleanup = true);
virtual void removeChildByTag(int tag, bool cleanup = true);
virtual void removeChildByName(const std::string &name, bool cleanup = true);
virtual void removeAllChildren(); //刪除所有節點
virtual void removeAllChildrenWithCleanup(bool cleanup); //cleanup爲true則刪除子節點的所有動作
//重排子節點
//重新排序一個子節點,設定一個新的z軸的值
//child 它必須是已經添加的
//localZOrder Z軸順序爲了繪畫優先級
virtual void reorderChild(Node * child, int localZOrder);
virtual void sortAllChildren(); //重新排序所有子節點
/**
* 其他操作管理
*/
virtual void onEnter(); //節點開始進入舞臺時調用.即創建時調用.
virtual void onEnterTransitionDidFinish(); //節點進入舞臺後調用.即創建完後調用.
virtual void onExit(); //節點離開舞臺時調用.即移除時調用
virtual void onExitTransitionDidStart(); //節點離開舞臺前調用.
//繪製節點
virtual void draw() final;
//遞歸訪問所有子節點,並重新繪製
virtual void visit() final;
//返回包含Node(節點)的Scene(場景).
//若不屬於任何的場景,它將返回nullptr
virtual Scene* getScene() const;
//返回節點在父節點座標中的矩形邊界框
virtual Rect getBoundingBox() const;
//暫停所有的活動着的動作和調度器
virtual void cleanup();
//
3、動作相關Action
動作管理:運行、暫停、取消等操作。
//
/**
* 動作管理Action
* setActionManager
* runAction , stopAction , getActionByTag , getNumberOfRunningActions
*/
//設置被所有動作使用的ActionManager對象
//如果你設置了一個新的ActionManager, 那麼之前創建的動作將會被刪除
virtual void setActionManager(ActionManager* actionManager);
virtual ActionManager* getActionManager();
Action* runAction(Action* action); //執行一個動作
Action* getActionByTag(int tag); //獲取動作, 根據tag標記
void stopAllActions(); //暫停動作
void stopAction(Action* action); //暫停動作
void stopActionByTag(int tag); //暫停動作
ssize_t getNumberOfRunningActions() const; //獲取正在運行的動作數量
//
4、定時器相關schedule
定時器管理,默認定時器、自定義定時器、一次性定時器。
//
/**
* 定時器管理schedule
* setScheduler
* scheduleUpdate : 默認定時器
* schedule : 自定義定時器
* scheduleOnce : 一次性定時器
*/
//設置一個調度器對象,來調度所有的“update”和定時器
//如果你設置了一個新的調度器,那麼之前創建的timers/update將會被刪除。
virtual void setScheduler(Scheduler* scheduler);
virtual Scheduler* getScheduler(); //得到調度器對象
//開啓默認定時器.刷新次數爲60次/秒.即每秒60幀.
//與update(float delta)回調函數相對應.
//給予定時器優先級priority.其中priority越小,優先級越高
void scheduleUpdate(void);
void scheduleUpdateWithPriority(int priority);
void unscheduleUpdate(void); //取消默認定時器
virtual void update(float delta); //update爲scheduleUpdate定時器的回調函數.
//設置自定義定時器.默認爲每秒60幀.
//interval : 每隔interval秒,執行一次.
//repeat : 重複次數.
//delay : 延遲時間,即創建定時器delay後開始執行.
void schedule(SEL_SCHEDULE selector, float interval, unsigned int repeat, float delay);
void schedule(SEL_SCHEDULE selector, float interval);
void schedule(SEL_SCHEDULE selector); //默認爲每秒60幀
void scheduleOnce(SEL_SCHEDULE selector, float delay); //只執行一次,delay秒後執行
void unschedule(SEL_SCHEDULE selector); //取消一個自定義定時器
void unscheduleAllSelectors(void); //取消所有定時器
void resume(void); //恢復所有定時器和動作
void pause(void); //暫停所有定時器和動作
//
5、整合NodeRGBA類
整合NodeRGBA類,增加顏色、透明度的設置。
//
/**
* 整合NodeRGBA類
* setOpacity : 透明度
* setColor : 顏色
*/
virtual GLubyte getOpacity() const;
virtual GLubyte getDisplayedOpacity() const;
virtual void setOpacity(GLubyte opacity);
virtual const Color3B& getColor() const;
virtual const Color3B& getDisplayedColor() const;
virtual void setColor(const Color3B& color);
//
6、enumerateChildren
新增的Node::enumerateChildren方法,且支持C++ 11的正則表達式。
用於枚舉某個Node節點的子節點,並讓名字符合"name通配符"的子節點執行callback函數。
且callback函數返回類型應該爲一個bool值,並且返回爲true時,結束查找。
//
virtual void enumerateChildren(const std::string &name, std::function<bool(Node* node)> callback) const;
//
使用舉例:
//
//Find nodes whose name is 'nameToFind' and end with digits.
node->enumerateChildren("nameToFind[[:digit:]]+",
[](Node* node) -> bool { ... return false; // return true to stop at first match });
//Find nodes whose name is 'nameToFind' and end with digits recursively.
node->enumerateChildren("nameToFind[[:digit:]]+",
[](Node* node) -> bool { ... return false; // return true to stop at first match });
//
通配符匹配舉例:
//
//搜索語法選項
'//' : 遞歸訪問所有子節點, 只能放在搜索串的開頭位置
'..' : 搜索移至node的父節點, 只能放在某個字符串的結束位置
'/' : 搜索移至node的子節點, 可以放在任何位置,除了搜索串的開頭位置
//代碼舉例
enumerateChildren("//MyName", ...) : 遞歸訪問Node的所有子節點。查找匹配 "MyName" 的子節點
enumerateChildren("[[:alnum:]]+", ...) : 在Node的兒子節點中查找。 所有項
enumerateChildren("A[[:digit:]]", ...) : 在Node的兒子節點中查找。 名字爲 "A0","A1",...,"A9" 的子節點
enumerateChildren("Abby/Normal", ...) : 在Node的孫子節點中查找。 其節點爲"Normal",且父節點爲"Abby"
enumerateChildren("//Abby/Normal", ...): 遞歸訪問Node的所有子節點。其節點爲"Normal",且父節點爲"Abby"
//
注意:使用gccV4.8或更低版本構建的程序運行時會崩潰。由於OTHER_LDFLAGS不能在Xcode6 beta3中使用,在iOS上我們使用包括64位庫文件fat library。但Xcode 5.0或更低版本不支持這種方式。
所以:
* Android編譯需要NDK R9D以上版本
* Linux編譯需要GCC4.9以上版本
* iOS編譯需要 Xcode5.1以上版本
7、渲染順序
在2.x中是使用Zorder來控制節點渲染的先後順序的。而在3.x中渲染的順序則是由兩個因素決定。
> 全局Z順序:GlobalZOrder。所有節點之間對比。
> 局部Z順序:LocalZOrder。 兄弟節點之間對比。
且Z順序越小,最先渲染。
7.1、全局Z順序
> 定義渲染節點的順序,擁有全局Z順序越小的節點,最先渲染。
> 假設:兩個或者更多的節點擁有相同的全局Z順序,那麼渲染順序無法保證。唯一的例外是如果節點的全局Z順序爲零,那麼場景圖順序是可以使用的。
> 默認的,所有的節點全局Z順序都是零。這就是說,默認使用場景圖順序來渲染節點。
> 全局Z順序是非常有用的當你需要渲染節點按照不同的順序而不是場景圖順序。
> 侷限性: 全局Z順序不能夠被擁有繼承“SpriteBatchNode”的節點使用。
//
virtual void setGlobalZOrder(float globalZOrder);
virtual float getGlobalZOrder() const;
//
7.2、局部Z順序
> LocalZOrder是“key”(關鍵)來分辨節點和它兄弟節點的相關性。
> 父節點將會通過LocalZOrder的值來分辨所有的子節點。如果兩個節點有同樣的LocalZOrder,那麼先加入子節點數組的節點將會比後加入的節點先得到渲染,那麼先加入的節點會被後加入的節點遮蓋[update 20140927]。
> 同樣的,場景圖使用“In-Order(按順序)”遍歷數算法來遍歷。並且擁有小於0的LocalZOrder的值的節點是“left”子樹(左子樹) 所以擁有大於0的LocalZOrder的值得節點是“right”子樹(右子樹)。
//
//設置這個節點的局部Z順序((相對於兄弟節點))
virtual void setLocalZOrder(int localZOrder);
virtual int getLocalZOrder() const;
//
8、座標轉換
參考:http://www.tairan.com/archives/5739
8.1、座標轉換函數
座標分爲兩種座標:
> 世界座標:就是相對節點的世界座標。
> 局部座標:就是相對節點的座標。
//
/**
* 座標轉換convertTo
* WorldSpace : 世界座標
* NodeSpace : 局部座標
*
*/
//把世界座標, 轉換到當前節點的本地座標系中
//基於Anchor Point, 把基於當前節點的本地座標系下的座標, 轉換到世界座標系中
Vec2 convertToNodeSpace(const Vec2& worldPoint) const;
Vec2 convertToNodeSpaceAR(const Vec2& worldPoint) const;
//把基於當前節點的本地座標系下的座標, 轉換到世界座標系中
//基於Anchor Point. 把世界座標, 轉換到當前節點的本地座標系中
Vec2 convertToWorldSpace(const Vec2& nodePoint) const;
Vec2 convertToWorldSpaceAR(const Vec2& nodePoint) const;
//把觸點座標, 轉換到當前節點的本地座標系中
Vec2 convertTouchToNodeSpace(Touch * touch) const;
Vec2 convertTouchToNodeSpaceAR(Touch * touch) const;
//
8.2、舉例
> node1座標爲:(20,40), 錨點(0,0)。
> node2座標爲:(-5,-20),錨點(1,1)。
> Vec2 point1 = node1->convertToNodeSpace(node2->getPosition());
結果爲:(-25,-60)。(即:相對node1節點座標位置,的,相對座標)
分析 :node2相對node1節點的座標爲:(-5,-20) - (20,40) 。
也就是說:node2相對node1的座標位置。
> Vec2 point2 = node1->convertToWorldSpace(node2->getPosition());
結果爲:(15,20)。(即:相對node1的世界座標系統下,的,世界座標)
分析 :將node1作爲參照,轉換到世界座標爲:(20,40) + (-5,-20) 。
也就是說:node2的座標現在被看做是相對node1的座標位置,然後轉換到世界座標。
8.3、在屏幕觸控中的應用
判斷觸摸點是否觸摸到某個精靈圖片sp的內部區域。
//
bool HelloWorld::onTouchBegan(Touch *touch, Event *unused_event)
{
//將觸點座標, 轉換爲相對節點sp的, 相對座標
Vec2 point = sp->convertTouchToNodeSpace(touch);
//構造sp的尺寸矩形
Size size = sp->getContentSize();
Rect rect = Rect(0, 0, size.width, size.height);
//判斷觸點是否觸摸到sp內部
if (rect.containsPoint(point)) {
CCLog("點中");
return true;
}
return false;
}
//