Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Making games using JavaScript and Cocos2d

fwdays
April 29, 2014

Making games using JavaScript and Cocos2d

Тарас Товченко

fwdays

April 29, 2014
Tweet

More Decks by fwdays

Other Decks in Programming

Transcript

  1. Plan • A quick guide of Cosos2D • The JavaScript

    propagation • JavaScript binding • Espreso framework • Cocos2d: Tools & Libs
  2. JavaScript propagation Every thing goes to simplified and useful form,

    nobody wants to make simple thing through the hard way. And JavaScript gives this advantage.
  3. JavaScript propagation: Obvious benefits • You can hire several senior

    developers for supporting core functionality - shaders, native features, engine and etc. • And hire a log of juniors (students for instance) for developing game mechanics. • Less money - more games!
  4. JavaScript propagation was created in 1995 for the Web in

    2009 was developed server-side framework how can we use it on the other platforms?
  5. JavaScript binding JSB was developed a few years ago by

    Zynga The JS code is interpreted by SpiderMonkey, Mozilla's JS virtual machine JSB allows calling native code from JS and vice- versa.
  6. JavaScript binding: Native C++ class class EspresoAction : public cocos2d::Action

    { public: static EspresoAction* create(); virtual std::string description() const; virtual cocos2d::Action* clone() const; virtual cocos2d::Action* reverse() const; virtual bool isDone() const { return cocos2d::Action::isDone(); } virtual void startWithTarget(cocos2d::Node *target); virtual void stop() { cocos2d::Action::stop(); } virtual void step(float dt); virtual void update(float time) { cocos2d::Action::update(time); } cocos2d::Node* getTarget() const { return cocos2d::Action::getTarget(); } void setTarget(cocos2d::Node *target) { cocos2d::Action::setTarget(target); } cocos2d::Node* getOriginalTarget() const; void setOriginalTarget(cocos2d::Node *originalTarget); int getTag() const { return cocos2d::Action::getTag(); } void setTag(int tag) { cocos2d::Action::setTag(tag); } protected: EspresoAction() {} };
  7. JavaScript binding: Parsed interface extern JSClass *jsb_es_EspresoAction_class; extern JSObject *jsb_es_EspresoAction_prototype;

    bool js_espreso_EspresoAction_constructor(JSContext *cx, uint32_t argc, jsval … void js_espreso_EspresoAction_finalize(JSContext *cx, JSObject *obj); void js_register_espreso_EspresoAction(JSContext *cx, JSObject *global); void register_all_espreso(JSContext* cx, JSObject* obj); bool js_espreso_EspresoAction_startWithTarget(JSContext *cx, uint32_t argc, … bool js_espreso_EspresoAction_setOriginalTarget(JSContext *cx, uint32_t argc, … bool js_espreso_EspresoAction_clone(JSContext *cx, uint32_t argc, jsval *vp); bool js_espreso_EspresoAction_getOriginalTarget(JSContext *cx, uint32_t argc, … bool js_espreso_EspresoAction_stop(JSContext *cx, uint32_t argc, jsval *vp); bool js_espreso_EspresoAction_update(JSContext *cx, uint32_t argc, jsval *vp); bool js_espreso_EspresoAction_getTarget(JSContext *cx, uint32_t argc, jsval *vp); bool js_espreso_EspresoAction_setTag(JSContext *cx, uint32_t argc, jsval *vp); bool js_espreso_EspresoAction_getTag(JSContext *cx, uint32_t argc, jsval *vp); bool js_espreso_EspresoAction_setTarget(JSContext *cx, uint32_t argc, jsval *vp); bool js_espreso_EspresoAction_isDone(JSContext *cx, uint32_t argc, jsval *vp); bool js_espreso_EspresoAction_reverse(JSContext *cx, uint32_t argc, jsval *vp); bool js_espreso_EspresoAction_create(JSContext *cx, uint32_t argc, jsval *vp);
  8. JavaScript binding: Parsed code bool js_espreso_EspresoAction_startWithTarget(JSContext *cx, uint32_t argc, jsval

    *vp) { jsval *argv = JS_ARGV(cx, vp); bool ok = true; JSObject *obj = JS_THIS_OBJECT(cx, vp); js_proxy_t *proxy = jsb_get_js_proxy(obj); es::EspresoAction* cobj = (es::EspresoAction *)(proxy ? proxy->ptr : NULL); JSB_PRECONDITION2( cobj, cx, false, "Invalid Native Object"); if (argc == 1) { cocos2d::Node* arg0; do { if (!argv[0].isObject()) { ok = false; break; } js_proxy_t *jsProxy; JSObject *tmpObj = JSVAL_TO_OBJECT(argv[0]); jsProxy = jsb_get_js_proxy(tmpObj); arg0 = (cocos2d::Node*)(jsProxy ? jsProxy->ptr : NULL); JSB_PRECONDITION2( arg0, cx, false, "Invalid Native Object"); } while (0); JSB_PRECONDITION2(ok, cx, false, "Error processing arguments"); cobj->startWithTarget(arg0); JS_SET_RVAL(cx, vp, JSVAL_VOID); return true; } JS_ReportError(cx, "wrong number of arguments: %d, was expecting %d", argc, 1); return false; }
  9. JavaScript binding: Parsed code void js_register_espreso_EspresoAction(JSContext *cx, JSObject *global) {

    jsb_es_EspresoAction_class = (JSClass *)calloc(1, sizeof(JSClass)); jsb_es_EspresoAction_class->name = "Action"; jsb_es_EspresoAction_class->addProperty = JS_PropertyStub; jsb_es_EspresoAction_class->delProperty = JS_DeletePropertyStub; jsb_es_EspresoAction_class->getProperty = JS_PropertyStub; jsb_es_EspresoAction_class->setProperty = JS_StrictPropertyStub; jsb_es_EspresoAction_class->enumerate = JS_EnumerateStub; jsb_es_EspresoAction_class->resolve = JS_ResolveStub; jsb_es_EspresoAction_class->convert = JS_ConvertStub; jsb_es_EspresoAction_class->finalize = js_es_EspresoAction_finalize; jsb_es_EspresoAction_class->flags = JSCLASS_HAS_RESERVED_SLOTS(2); static JSFunctionSpec funcs[] = { JS_FN("clone", js_espreso_EspresoAction_clone, 0, JSPROP_PERMANENT | JSPROP_ENUMERATE), JS_FN("stop", js_espreso_EspresoAction_stop, 0, JSPROP_PERMANENT | JSPROP_ENUMERATE), JS_FN("update", js_espreso_EspresoAction_update, 1, JSPROP_PERMANENT | JSPROP_ENUMERATE), JS_FN("setTag", js_espreso_EspresoAction_setTag, 1, JSPROP_PERMANENT | JSPROP_ENUMERATE), JS_FN("getTag", js_espreso_EspresoAction_getTag, 0, JSPROP_PERMANENT | JSPROP_ENUMERATE), JS_FN("isDone", js_espreso_EspresoAction_isDone, 0, JSPROP_PERMANENT | JSPROP_ENUMERATE), JS_FN("ctor", js_es_EspresoAction_ctor, 0, JSPROP_PERMANENT | JSPROP_ENUMERATE), JS_FS_END };
  10. JavaScript binding: Call native from JS cocos2d::Action* EspresoAction::clone() const {

    JSB_AUTOCOMPARTMENT_WITH_GLOBAL_OBJCET js_proxy_t* p = jsb_get_native_proxy(const_cast<EspresoAction*>(this)); if (!p) { CCLOG("JSB: Wrong native object = %p", this); return nullptr; } jsval retval; jsval dataVal = INT_TO_JSVAL(1); ScriptingCore::getInstance() ->executeFunctionWithOwner(OBJECT_TO_JSVAL(p->obj), “clone", 1, &dataVal, &retval); return static_cast<cocos2d::Action*>(JSVAL_TO_PRIVATE(retval)); }
  11. JavaScript binding: Tools you must install clang+llvm-3.3 sudo easy_install pip

    sudo pip install PyYAML sudo pip install Cheetah export NDK_ROOT=/path/to/android-ndk-r9b ./genbindings.py
  12. JavaScript binding: Preferences # what headers to parse headers =

    %(srcdir)s/espreso.h # what classes to produce code for. You can use regular expressions here. When testing the regular # expression, it will be enclosed in "^$", like this: "^Menu*$". classes = EspresoAction EspresoComponent OrientationManager classes_need_extend = EspresoAction EspresoComponent skip = *::[copyWith.* onEnter.* onExit.* ^description$ getObjectType onTouch.* onAcc.* onKey.* onRegisterTouchListener step], OrientationManager::[postOrientation] rename_functions = rename_classes = EspresoComponent::Component, EspresoAction::Action # for all class names, should we remove something when registering in the target VM? remove_prefix = # classes for which there will be no "parent" lookup classes_have_no_parents = EspresoAction EspresoComponent OrientationManager # base classes which will be skipped when their sub-classes found them. base_classes_to_skip = Ref Clonable
  13. Android JNI 1. In JNI - Java native code 2.

    In JSB - Native code JS code In general:
  14. Espreso engine. (Yes with one “s”) https://github.com/tovchenko/espreso 1. Written in

    JS 2. Adds extra functionality to Cocos2d 3. Removes cross-platform mistakes 4. Simplify development process
  15. Espreso engine: Modules 1. Has component system for audio, flash-

    animation, frame-animation 2. Supports auto choosing resolution for any screen size with LODs system SD, HD, HDR 3. Adds useful loader, and object builder functional 4. Has a lot different python scripts for resource compiling for different platforms, making texture atlases, sounds, LODs, and etc. 5. Supports CocoStudio UI Editor format for positioning
  16. Espreso engine: Objects descriptors "zombie": { "render": { "sprite": "z0_walk_0.png",

    "atlas": "zombie" }, "sound": { "add": { "src": "bubble_added", "loop": true, "volume": 0.5 }, "destroy": { "src": "bubbles_destroyed" } }, "animator": "zombie_anim.plist", "music": { "level_1": { "src": "music_1", "loop": true, "volume": 0.9 } } }, "popup1": { "data": "mainScene.json" }
  17. Espreso engine: Objects var holder = es.PlaceHolder.create(es.utils.getProps(builder.make(‘popup1')), builder); var objects

    = holder.makeTree(); objects.setPosition(0.5 * size.width, 0.5 * size.height); this.addChild(objects); var drunkard = es.PlaceHolder.getNodeByTag(objects, objs.DRUNKARD0); this._zombie = es.PlaceHolder.getNodeByTag(objects, objs.ZOMBIE); var cat = es.PlaceHolder.getNodeByTag(objects, objs.CAT); drunkard.runAction(es.PlayArmature.create('Action12')); this._zombie.runAction(es.PlayAnimation.create('walk')); this._zombie.runAction(es.PlaySfx.create('add')); this._zombie.runAction(es.PlayMusic.create('level_1'));}
  18. Cocos2d: Tools CocoStudio • GUI Editor • Animation Editor with

    Flash import • Scene editor • Compatible with CocosBuilder • Use CocoStudio instead CocosBuilder • But now available only for Windows platform!