Cocos2d-x入門之旅[4]場景


我們之前講了場景圖(Scene Graph) 的概念,繼續之前你先要知道

  • 場景圖決定了場景內節點對象的渲染順序
  • 渲染時 z-order 值大的節點對象會后繪制,值小的節點對象先繪制

HelloWorld

你還記得HelloWorld場景是如何啟動的么?回看我們工程里的AppDelegate.cpp,滾到applicationDidFinishLaunching()的尾部:

// create a scene. it's an autorelease object
auto helloWorldscene = HelloWorld::createScene();
// run
director->runWithScene(helloWorldscene);

Ctrl+鼠標左鍵 點選createScene()查看定義,可以看到這個函數在HelloWorldScnen.h內聲明,在HelloWorldScnen.cpp內定義

// HelloWorldScnen.h
static cocos2d::Scene* createScene();

// HelloWorldScnen.cpp
Scene* HelloWorld::createScene()
{
    return HelloWorld::create();
}

我們可以通過該函數獲取一個HelloWorld場景對象

之后就是場景的初始化,菜單,精靈等對象的Set都在這里進行

bool HelloWorld::init()
{
    ...
}

最后我們看到一個回調函數

void HelloWorld::menuCloseCallback(Ref* pSender)
{
    //Close the cocos2d-x game scene and quit the application
    Director::getInstance()->end();
}

C++基礎差的同學可能還不理解回調的概念,但你只需要知道,這個函數實現了:HelloWorld場景內點擊關閉按可鈕關閉窗口 的功能,就行了、

SecondScene

現在我們對着HelloWorld的代碼來創建一個SecondScene

和HelloWorld一樣,首先我們需要一份SecondScene.h存放聲明,然后是一份SecondScene.cpp存放定義

注意VS內新建文件時,一定要保存到Class文件夾內,不然你是不能直接include“xxxxxx”的(萬惡的VS默認保存路徑不是Class

修改到項目目錄下的Class

SecondScene.h

首先是套一層宏保護到頭尾

#ifndef __SECOND_SCENE_H__
#define __SECOND_SCENE_H__

#endif // __SECOND_SCENE_H__

然后

#include "cocos2d.h"

現在我開始我們要做一點點小變化,我們讓SecondScene繼承Layer而不是Scene

class SecondScene : public cocos2d::Layer {
public:
	static cocos2d::Scene* createScene();
	virtual bool init();
	CREATE_FUNC(SecondScene);
    //暫時不需要回調函數
};

實際上之前的cocos實例工程里HelloWorld都是繼承自Layer的,不知為何現在改了,但是無妨,我們借此機會介紹Layer和Scene的區別

SecondScene.cpp

首先要include我們之前寫好的SecondScene.h,為了方便我們也和HelloWorld一樣using namespace cocos2d

你可能看到了HelloWorld.cpp里寫的是USING_NS_CC而不是using namespace cocos2d,但其實效果是一樣的

接下來我們定義creatSceen()函數,也和HelloWorld::createScene()略有不同

Scene* SecondScene::createScene() {
    //創建一個Scene類的對象scene
	auto scene = Scene::create();
    //創建一個SecondScene類的對象layer
	auto SecondScene = SecondScene::create();
    //把layer添加到scene里
	scene->addChild(layer);
    //返回scene
	return scene;
}

理解起來很簡單:首先我們創建了一個Scene類的對象scene,然后創建了一個SecondScene類的對象layer(別忘了我們的SecondScene繼承自layer),再把layer添加到了scene里,最后返回我們的scene

之后就可以開始寫初始化函數了

bool SecondScene::init() {
	auto visibleSize = Director::getInstance()->getVisibleSize();
	Vec2 origin = Director::getInstance()->getVisibleOrigin();

	Label* label = Label::create("Second Test", "fonts/Marker Felt.ttf", 24);
	label->setPosition(
		Vec2(
			origin.x + visibleSize.width / 2,
			origin.y + visibleSize.height - label->getContentSize().height
		)
	);
    
	this->addChild(label);	// 默認z-order=0

	return true;
}

我們不用加太多東西,加入一個label讓自己知道這是SecondScene場景就行

現在我們去程序的入口,AppDelegate.cpp里看看,還記得啟動HelloWorld場景的那兩行代碼么,我們改成啟動SecondScene場景:

(記得先要加入#include "SecondScene.h"到AppDelegate.cpp里)

// create a scene. it's an autorelease object
auto helloWorldscene = HelloWorld::createScene();
// run
director->runWithScene(helloWorldscene);

改成

auto secondScene = SecondScene::createScene();
director->runWithScene(secondScene);

運行測試:

沒有問題

場景切換

接下來我們把AppDelegate.cpp還原回去(Crtl+Z),讓程序運行時還是從HelloWorld場景開始,然后嘗試使用回調函數切換到SecondScene

由於我們要在HelloWorld切換到Second,所以我們需要在HelloWorld場景里添加一個回調事件,剛好HelloWolrd里就有一個關閉按鈕的回調,我們改改代碼就行(這里重點是演示如何切換,真的不是我懶)

追蹤到HelloWorld::menuCloseCallback()

Director::getInstance()->END改成

Director::getInstance()->replaceScene(
    SecondScene::createScene()
);

運行測試,不出意外再點擊HelloWorld右下角的關閉按鈕,就會一瞬間切換到Second

切換動畫

Cocos內置了很多切換場景的動畫,比如

Director::getInstance()->replaceScene(
    TransitionSlideInT::create(
        3.0f, SecondScene::createScene()
    )
);

運行,Second會在3秒內從上平滑切換掉HelloWorld

別的切換動畫就不贅述了,和Actions又異曲同工之妙,各自己試試吧

場景棧

我們之前都是在使用replaceScene進行場景切換,replaceScene會使前一個場景被釋放(簡單來說就是刪掉了,不再占用內存,想找回來只能重新創建一個),節省了內存資源,但有時我們不希望場景被釋放怎么辦呢

Cocos還提供了 推進pushScene()和彈出popScene兩種方法,把一系列場景存儲到棧內,按需彈出(釋放)和推進新場景

是一種數據結構,你可以簡單理解為一個彈匣,對棧有兩種操作:

  1. 入棧(push),裝入子彈
  2. 出棧(pop),射出子彈

子彈總是最上面的先被射出(pop時棧頂的元素最先出棧),也就是“先進后出”

新加入場景時使用pushScene(),新舊場景就會被存入場景棧,新在上舊在下(也就是說舊的場景沒有釋放),popScene會將新的場景釋放,舊的場景就被彈了上來原來的位子,顯示舊場景

你可以在場景初始化函數內寫一段等待x秒的代碼(換個思路,可以寫一個計時器),驗證pop后顯示的舊場景不是新創建的:

bool HelloWorld::init()
{
 	... 
        
    for(int i = 0; i <19999999; i++)// 耗時操作   
        
    ...
}

發揮你的奇思妙想,還有什么方法,自己實驗一下

層和場景

這個好理解,想想你玩過的2d游戲,或者Photoshop的圖層界面,一個場景里可以有好幾個層

場景內創建層很簡單:

Layer* layer2 = Layer::create();

當然一個層必須添加到場景內才會生效,層無法離開場景獨立存在

之后的學習中我們會進一步體會到層的作用


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM