2014년 11월 26일 수요일

Cocos2d-x Scene 노드를 Lua 스크립트로 실시간 제어하기

Cocos2d-x의 경우 Unity 처럼 Scene 에디터와 통합된 개발환경이 아니기 때문에 Scene을 구성하는 각각의 자식 노드를 생성하기 위해 직접 코드를 작성해야 한다. 물론 CocoStudio 같은 에디터를 사용하면 Scene 구성을 좀 더 편하게 할 수 있지만 이미 한참 진행된 프로젝트의 경우 적용하기가 쉽지 않다. UI의 경우 프로젝트 진행 중 Look and feel이 여러번 바뀌는 경우가 많은데 UI 수정 작업 시간의 대부분은 노드의 위치를 새롭게 변경하기 위해 반복적으로 코드를 컴파일하고 실행, 확인하느라 소모되는 경우가 많다. 다음은 Scene 노드를 Lua 스크립트로 제어할 수 있도록 작성된 코드로 특정 노드의 상태(위치 등)를 Lua 스크립트를 통해 변경, 확인이 가능하다.

DebugNode.h
#ifndef __DEBUG_NODE_H__
#define __DEBUG_NODE_H__

#include "cocos2d.h"

USING_NS_CC;

class DebugNode : public Node {
public:
  DebugNode();
  virtual ~DebugNode();

  CREATE_FUNC(DebugNode);

public:
  virtual bool init();
  void apply(const std::string &script);

private:
  std::string m_script;
};

#endif

DebugNode.cpp
#include 
#include 

#include "DebugNode.h"

DebugNode::DebugNode() {
  m_script = "";
}

DebugNode::~DebugNode() {
  stopAllActions();
}

bool DebugNode::init() {
  Node::init();
  return true;
}

void DebugNode::apply(const std::string &script) {
  m_script = script;

  LuaEngine *luaEngine = LuaEngine::getInstance();
  ScriptEngineManager::getInstance()->setScriptEngine(luaEngine);

  auto L = luaEngine->getLuaStack()->getLuaState();

  // DebugNode의 부모 Node를 루아 스크립트 전역 변수 rootNode로 지정한다.
  luaEngine->getLuaStack()->pushObject(getParent(), "cc.Node");
  lua_setglobal(L, "rootNode");

  // 지정된 스크립트 파일을 실행한다.
  luaEngine->executeScriptFile(m_script.c_str());

  // 이후 1초 마다 스트립트를 재실행한다.
  auto action = RepeatForever::create(
    Sequence::createWithTwoActions(
      DelayTime::create(1.0f),
      CallFunc::create(
        [&]() {
          LuaEngine::getInstance()->reload(m_script.c_str());
        })));
  runAction(action);
}

제어할 Scene 노드의 자식으로 DebugNode 객체를 생성해서 추가하고 apply 함수를 호출하면 1초에 한 번씩 지정된 Lua 스트립트 파일을 실행하는데 제어할 Scene 자식 노드는 setName 함수를 사용하여 유일한 이름을 지정해 주어야 한다. 다음의 샘플은 Cocos2d-x에 포함된 cpp-empty-test 프로젝트에 DebugNode를 적용한 부분의 코드 조각이다.

HelloWorldScene.cpp
bool HelloWorld::init()
{
  (생략)
    
  /////////////////////////////
  // 3. add your codes below...

  // add a label shows "Hello World"
  // create and initialize a label
    
  auto label = LabelTTF::create("Hello World", "Arial", TITLE_FONT_SIZE);

  // 스크립트에서 참조할 이름을 지정한다.
  label->setName("label");
    
  (생략)

  auto debugNode = DebugNode::create();
  this->addChild(debugNode);
  debugNode->apply("HelloWorldScene.lua");
    
  return true;
}

HelloWorldScene.lua
label = rootNode:getChildByName("label")
label:setPosition(100, 200)

HelloWorldScene.lua 파일을 텍스트 에디터에서 열고 setPosition의 인자를 변경한 후에 저장하면 바로 위치 값이 적용되는 것을 확인할 수 있다.


댓글 없음:

댓글 쓰기