GithubHelp home page GithubHelp logo

isabella232 / cocos2dx-levelup Goto Github PK

View Code? Open in Web Editor NEW

This project forked from thuskey/cocos2dx-levelup

0.0 0.0 0.0 5.05 MB

Cocos2d-x F2P game progression library - worlds, levels, missions, scores, records and more. Part of The SOOMLA Framework - for game design, economy modeling and faster development.

Home Page: http://soomla.com

License: Apache License 2.0

Shell 0.30% JavaScript 27.92% C++ 47.36% Objective-C 14.35% Java 4.41% Objective-C++ 5.24% Makefile 0.42%

cocos2dx-levelup's Introduction

Looking for great devs who want maintain and moderate this project !!

If you want to take over... contact us at [email protected]

This project is a part of The SOOMLA Framework, which is a series of open source initiatives with a joint goal to help mobile game developers do more together. SOOMLA encourages better game design, economy modeling, social engagement, and faster development.

cocos2dx-levelup

cocos2dx-levelup is a library built for easily modeling game structure and user progression, and allows rapid protoyping using a standard and simplified model. It acts as sort of a 'blueprint' for the game, modeling worlds/levels, gates to levels, missions and rewards that can be completed and achieved. All this is backed by SOOMLA's core tools, and can be easily integrated with more SOOMLA modules, like cocos2dx-store for IAP, or cocos2dx-profile for social related functions.

cocos2dx-levelup is the implementation of the LevelUp module for the Cocos2d-x framework, using the C++ flavour.

Contents

Model Overview

Generally, the SOOMLA sources contain detailed documentation on the different entities and how to use them, but here's a quick glance:

Model Overview

World / Level

A Level is pretty clear, and most games have them. A simple example is an Angry Birds single level, where you need to knock out all the pigs. It measures specific things, such as duration it takes to complete, and can be started and ended.

A World is a more general concept than a Level (a Level Is-a World), and can have innerWorlds to create hierarchies. Another example from Angry Birds is level pages and episodes, which contain the actual levels.

The Initial World is a container world for all worlds and levels in the game. We use the Initial World to intialize the LevelUp module.

Score

A Score is something which can be accumulated or measured within a World (or Level of course). It can be incremented or decremented based on user actions, and recorded at the completion of the World / Level.

This, in turn, can later be applied to high scores or best times, or treated as collectibles that can be awarded upon completion.

Gate

A Gate is a closed portal from one World to the next. It can be unlocked in many different ways (according to Gate type), and can also be combined into a GatesList to build more complex Gates.

Mission/Challenge

A Mission is a single task a player can complete in a game, usually for a Reward.

A Challenge is a set of Missions that need to be completed, so it's a big Mission built out of several smaller Missions.

Reward

A Reward is some kind of perk or status a player can achieve in the game. This can be either a badge, a virtual item from the game's economy (sword, coins etc.) or anything you can think of, really (unlocking game content or levels comes to mind).

Download

Pre baked zip:

From sources:

  • Clone this repository recursively: git clone --recursive https://github.com/soomla/cocos2dx-levelup.git
  • Run ./build_all from project directory
  • Take created binaries from build directory and use it!

Getting Started (With pre-built libraries - RECOMMENDED)

If you want to develop with sources, refer to the Working with sources section below.

NOTE: LevelUp depends on SOOMLA's other modules: Core, Store, and Profile. This document assumes that you are new to SOOMLA and have not worked with any of the other SOOMLA modules. If this is not the case, and you already have some or all of the other modules, please follow these directions only for the modules you are missing and of course, for the LevelUp module.

  1. If you didn't already, clone the Cocos2d-x framework from here, or download it from the Cocos2d-x website. Make sure the version you clone is supported by cocos2dx-levelup (the tag is the version).

  2. Clone soomla-cocos2dx-core, cocos2dx-store, cocos2dx-profile, and cocos2dx-levelup into the extensions directory located at the root of your Cocos2d-x framework:

    $ git clone [email protected]:soomla/soomla-cocos2dx-core.git extensions/soomla-cocos2dx-core
    
    $ git clone [email protected]:soomla/cocos2dx-store.git extensions/cocos2dx-store
    
    $ git clone [email protected]:soomla/cocos2dx-profile.git extensions/cocos2dx-profile
    
    $ git clone [email protected]:soomla/cocos2dx-levelup.git extensions/cocos2dx-levelup
    
  3. We use a fork of the jansson library for JSON parsing, clone our fork into the external directory at the root of your framework:

    $ git clone [email protected]:soomla/jansson.git external/jansson
    
  4. Make sure to include the Cocos2dxLevelUp.h header whenever you use any of the cocos2dx-levelup functions:

    #include "Cocos2dxLevelUp.h"
  5. Add an instance of your event handler to CCLevelUpEventDispatcher before CCSoomlaLevelUp initialization:

    soomla::CCLevelUpEventDispatcher::getInstance()->addEventHandler(handler);
  6. Initialize CCSoomla, CCSoomlaStore, CCSoomlaProfile, and CCSoomlaLevelUp with the class you just created, a customSecret and other params:

soomla::CCSoomla::initialize("customSecret");

__Dictionary *storeParams = __Dictionary::create();
storeParams->setObject(__String::create("ExamplePublicKey"), "androidPublicKey");

soomla::CCSoomlaStore::initialize(assets, storeParams);

__Dictionary *profileParams = __Dictionary::create(); soomla::CCSoomlaProfile::initialize(profileParams);

// initialWorld - should be created here and contain all worlds and levels of the game
// rewards - should contain a list of all rewards that are given through LevelUp
soomla::CCSoomlaLevelUp::getInstance()->initialize(initialWorld, rewards);

```
- NOTE: *Custom Secret* - is an encryption secret you provide that will be used to secure your data. Choose this secret wisely, you can't change it after you launch your game!
> Initialize `CCSoomlaLevelUp` ONLY ONCE when your application loads.
  1. You'll need to subscribe to levelup events to get notified about Level-Up related events. refer to the Event Handling section for more information.

The next steps are different according to which platform you're using.

####Instructions for iOS

In your XCode project, perform the following steps:

  1. Add jansson (external/jansson/) to your project (just add it as a source folder, make sure to check "create group").

  2. For each of the following XCode projects:

    • Cocos2dXCore.xcodeproj (extensions/soomla-cocos2dx-core/).
    • Cocos2dXStore.xcodeproj (extensions/cocos2dx-store/).
    • Cocos2dXProfile.xcodeproj (extensions/soomla-cocos2dx-profile/).
    • Cocos2dXLevelUp.xcodeproj (extensions/cocos2dx-levelup/).

    Perform the following: - Drag the project into your project - Add its targets to your Build Phases->Target Dependencies - Add the Products (*.a) of the project to Build Phases->Link Binary With Libraries.

  3. Add the following directories to Build Settings->Header Search Paths (with recursive option):

This article assumes you have a cocos2d folder under your project folder and which either contains the Cocos2d-x framework, or links to to its root folder

  • $(SRCROOT)/../cocos2d/extensions/soomla-cocos2dx-core/Soomla
  • $(SRCROOT)/../cocos2d/extensions/soomla-cocos2dx-core/build/ios/headers
  • $(SRCROOT)/../cocos2d/extensions/cocos2dx-store/Soomla
  • $(SRCROOT)/../cocos2d/extensions/cocos2dx-profile/Soomla
  • $(SRCROOT)/../cocos2d/extensions/cocos2dx-profile/build/ios/headers
  • $(SRCROOT)/../cocos2d/extensions/cocos2dx-levelup/Soomla
  1. Make sure you have these 3 Frameworks linked to your XCode project: Security, libsqlite3.0.dylib, StoreKit.

  2. See the last step of cocos2dx-profile instructions for iOS in order to connect the Profile module to a social network provider (in this case Facebook).

That's it! Now all you have to do is build your XCode project and run your game with cocos2dx-levelup.

####Instructions for Android

  1. Import cocos2dx-store, cocos2dx-profile, and cocos2dx-levelup module into your project's Android.mk by adding the following:

    LOCAL_WHOLE_STATIC_LIBRARIES += cocos2dx_store_static # add this line along with your other LOCAL_WHOLE_STATIC_LIBRARIES
    $(call import-module, extensions/cocos2dx-store) # add this line at the end of the file, along with the other import-module calls
    
    LOCAL_WHOLE_STATIC_LIBRARIES += cocos2dx_profile_static # add this line along with your other LOCAL_WHOLE_STATIC_LIBRARIES
    $(call import-module, extensions/cocos2dx-profile) # add this line at the end of the file, along with the other import-module calls
    
    LOCAL_WHOLE_STATIC_LIBRARIES += cocos2dx_levelup_static # add this line along with your other LOCAL_WHOLE_STATIC_LIBRARIES
    $(call import-module, extensions/cocos2dx-levelup) # add this line at the end of the file, along with the other import-module calls
    
  2. Add the following jars to your android project's classpath:

    • From extensions/soomla-cocos2dx-core/build/android

      1. SoomlaAndroidCore.jar
      2. Cocos2dxAndroidCore.jar
      3. square-otto-1.3.2.jar
    • From extensions/cocos2dx-store/build/android

      1. AndroidStore.jar
      2. Cocos2dxAndroidStore.jar
    • From extensions/cocos2dx-profile/build/android

      1. AndroidProfile.jar
      2. Cocos2dxAndroidProfile.jar
    • From extensions/cocos2dx-levelup/build/android

      1. AndroidLevelUp.jar
      2. Cocos2dxAndroidLevelUp.jar
  3. Update your AndroidManifest.xml to include permissions and the SoomlaApp:

    <uses-permission android:name="android.permission.INTERNET"/>
    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
    
    <!-- optional: required for uploadImage from SD card -->
    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
    
    <application ...
    	       android:name="com.soomla.SoomlaApp">
    	       ...
    </application>
  4. See the last step in cocos2dx-store instructions for Android in order to connect the Store module to the desired billing service

  5. See the last step in cocos2dx-profile instructions for Android in order to connect the Profile module to a social network provider (in this case Facebook).

That's it! Don't forget to run the build_native.py script so cocos2dx-levelup sources will be built with cocos2d-x.

Integration with SOOMLA cocos2dx-store

Please follow the steps in cocos2dx-store for the Store part of the setup. Then, you can use the store-related LevelUp classes, such as CCVirtualItemScore or CCVirtualItemReward or CCBalanceGate.

Integration with SOOMLA cocos2dx-profile

Please follow the steps in cocos2dx-profile for the Profile part of the setup. Then, you can use the profile-related LevelUp classes, such as CCSocialLikeMission.

Event Handling

SOOMLA lets you subscribe to levelup events, get notified and implement your own application specific behaviour to them.

Your behaviour is an addition to the default behaviour implemented by SOOMLA. You don't replace SOOMLA's behaviour.

SOOMLA uses the Cocos2d-x EventDispatcher to dispatch its own custom events. The names of such events are defined in CCLevelUpConsts, the received event has a __Dictionary set in its userData which holds all the meta-data for the event. You can subscribe to any event from anywhere in your code.

For example here's how to subscribe to the world completed event:

cocos2d::Director::getInstance()->getEventDispatcher()->addCustomEventListener(soomla::CCLevelUpConsts::EVENT_WORLD_COMPLETED, CC_CALLBACK_1(ExampleScene::onWorldCompleted, this));

Continuing the example, here's how you would handle and extract data from such an event:

void ExampleScene::onWorldCompleted(cocos2d::EventCustom *event) {
  cocos2d::__Dictionary *eventData = (cocos2d::__Dictionary *)event->getUserData();
  soomla::CCWorld *world = dynamic_cast<soomla::CCWorld *>(eventData->objectForKey(soomla::CCLevelUpConsts::DICT_ELEMENT_WORLD));

  // Use world for your needs
}

Each event has its own meta-data, see inline documentation in CCLevelUpEventDispatcher for more information.

Debugging

You can enable debug logging in cocos2dx-levelup by setting SOOMLA_DEBUG in CCSoomlaUtils.h (which is located in soomla-cocos2dx-core submodule) to true. Debug logging can also be enabled at build time by adding -DSOOMLA_DEBUG=1 to APP_CPPFLAGS in your Application.mk on Android, or by setting SOOMLA_DEBUG=1 in your Build Settings' Preprocessor Macros on iOS.

If you want to see debug messages from android-levelup, set the logDebug variable in com.soomla.SoomlaConfig to true.

To see debug messages on iOS, make sure you have also DEBUG=1 in your Build Settings' Preprocessor Macros (for Debug only).

Working with sources

SOOMLA appreciates code contributions! You are more than welcome to extend the capabilities of cocos2dx-levelup.

NOTE: If you would like to contribute, please follow our Documentation Guidelines. Clear, consistent comments will make our code easy to understand.

To integrate cocos2dx-levelup into your game, follow these steps:

  1. Recursively clone soomla-cocos2dx-core, cocos2dx-store, cocos2dx-profile, and cocos2dx-levelup.

    $ git clone --recursive [email protected]:soomla/soomla-cocos2dx-core.git extensions/soomla-cocos2dx-core
    
    $ git clone --recursive [email protected]:soomla/cocos2dx-store.git extensions/cocos2dx-store
    
    $ git clone --recursive [email protected]:soomla/cocos2dx-profile.git extensions/cocos2dx-profile
    
    $ git clone --recursive [email protected]:soomla/cocos2dx-levelup.git extensions/cocos2dx-levelup
    

    OR: If you have already cloned the repositories, to obtain submodules, use command:

    $ git submodule update --init --recursive
    

    NOTE: You should run this command in every repository.

  2. For iOS: Use sourced versions of Linked projects:

    1. extensions/soomla-cocos2dx-core/development/Cocos2dxCoreFromSources.xcodeproj
    2. extensions/cocos2dx-store/development/Cocos2dxStoreFromSources.xcodeproj
    3. extensions/cocos2dx-profile/development/Cocos2dxProfileFromSources.xcodeproj
    4. extensions/cocos2dx-levelup/development/Cocos2dxLevelUpFromSources.xcodeproj
  3. For Android: You can use our "sourced" modules for Android Studio (or IntelliJ IDEA):

    1. extensions/soomla-cocos2dx-core/development/Cocos2dxCoreFromSources.iml
    2. extensions/cocos2dx-store/development/Cocos2dxStoreFromSources.iml
    3. extensions/cocos2dx-profile/development/Cocos2dxProfileFromSources.iml
    4. extensions/cocos2dx-levelup/development/Cocos2dxLevelUpFromSources.iml

How to move from v1.0.x to v1.2.x?

Version 1.2.x is all about making the integration process on iOS and Android easier. If you are using v1.0.x and want to move to v1.2.x follow these steps:

  1. Pull the latest version to your extensions folder
  2. Remove any Soomla-related code in iOS (AppController.mm) and Android (Cocos2dxActivity), especially code related to ServiceManager and any other Services.
  3. In your AppDelegate.cpp: - Change soomla::CCServiceManager::getInstance()->setCommonParams(commonParams); to soomla::CCSoomla::initialize("customSecret"); - Change soomla::CCStoreService::initShared(assets, storeParams); to soomla::CCSoomlaStore::initialize(assets, storeParams); - Change soomla::CCProfileService::initShared(profileParams); to soomla::CCSoomlaProfile::initialize(profileParams); - Remove soomla::CCLevelUpService::initShared(); - Remove any #includes to missing header files, you only need Cocos2dxStore.h, Cocos2dxProfile.h and Cocos2dxLevelUp.h
  4. Remove any reference to EventHandlers and subscribing through Soomla EventDispatchers, instead use the Cocos2d-x EventDispatcher to subscribe to events.

Example Usages

Examples using virtual items are dependent on cocos2dx-store module, with proper CCSoomlaStore initialization and CCStoreAssets definitions. See the cocos2dx-store integration section for more details.

  • CCMission with CCReward (collect 5 stars to get 1 mega star)

    CCVirtualItemReward *virtualItemReward = CCVirtualItemReward::create(__String::create("mega_star_reward_id"),
                                                                     __String::create("MegaStarReward"),
                                                                     __Integer::create(1),
                                                                     megaStarItemId);
     __Array *rewards = __Array::create(virtualItemReward, NULL);
    CCBalanceMission *balanceMission = CCBalanceMission::create(__String::create("star_balance_mission_id"),
                                                               __String::create("StarBalanceMission"),
                                                               rewards,
                                                               starItemId,
                                                               __Integer::create(5));
    
    // use the store to give the items out, usually this will be called from in-game events
    // such as player collecting the stars
    CCStoreInventory::sharedStoreInventory()->giveItem(starItemId->getCString(), 5, &error);
    
    // events posted:
    // 1. onGoodBalanceChanged (Store events)
    // 2. onMissionCompleted (LevelUp events)
    // 3. onRewardGivenEvent (Core events)
    
    // now the mission is complete, and reward given
    balanceMission->isCompleted(); // true
    virtualItemReward->isOwned(); // true
  • CCRecordGate with CCRangeScore

    CCLevel *lvl1 = CCLevel::create(__String::create("lvl1_recordgate_rangescore"));
    CCLevel *lvl2 = CCLevel::create(__String::create("lvl2_recordgate_rangescore"));
    
    __String *scoreId = __String::create("range_score");
    CCRangeScore *rangeScore = CCRangeScore::create(scoreId, CCSRange::create(0.0, 100.0));
    __String *recordGateId = __String::create("record_gate");
    
    CCRecordGate *recordGate = CCRecordGate::create(recordGateId, scoreId, __Double::create(100.0));
    lvl1->addScore(rangeScore);
    
    // Lock level 2 with record gate
    lvl2->setGate(recordGate);
    
    // the initial world
    world->addInnerWorld(lvl1);
    world->addInnerWorld(lvl2);
    
    CCSoomlaLevelUp::getInstance()->initialize(world);
    
    lvl1->start();
    
    // events posted:
    // onLevelStarted (LevelUp events)
    
    rangeScore->inc(100);
    
    lvl1->end(true);
    
    // events posted:
    // onLevelEnded (LevelUp events)
    // onWorldCompleted (lvl1) (LevelUp events)
    // onGateOpened (LevelUp events)
    // [onScoreRecordReached] - if record was broken (LevelUp events)
    
    recordGate->isOpen(); // true
    
    lvl2->canStart(); // true
    lvl2->start();
    lvl2->end(true);
    
    // events posted:
    // onWorldCompleted (lvl2) (LevelUp events)
    
    lvl2->isCompleted(); // true
  • CCVirtualItemScore

    CCLevel *lvl1 = CCLevel::create(__String::create("lvl1_viscore"));
    __String *itemId = __String::create(ITEM_ID_VI_SCORE);
    __String *scoreId = __String::create("vi_score");
    CCVirtualItemScore *virtualItemScore = CCVirtualItemScore::create(scoreId, itemId);
    lvl1->addScore(virtualItemScore);
    
    world->addInnerWorld(lvl1);
    
    CCSoomlaLevelUp::getInstance()->initialize(world);
    
    lvl1->start();
    // events posted:
    // onLevelStarted (LevelUp events)
    
    virtualItemScore->inc(2.0);
    // events posted:
    // onGoodBalanceChanged (Store events)
    
    lvl1->end(true);
    // events posted:
    // onLevelEnded (LevelUp events)
    // onWorldCompleted (lvl1) (LevelUp events)
    // [onScoreRecordChanged] - if record was broken (LevelUp events)
    
    int currentBalance = CCStoreInventory::sharedStoreInventory()->getItemBalance(ITEM_ID_VI_SCORE, &error);
    // currentBalance == 2
  • CCChallenge (Multi-Mission)

    __String *scoreId = __String::create("main_score");
    CCScore *score = CCScore::create(scoreId);
    
    CCMission *mission1 = CCRecordMission::create(__String::create("record1_mission"),
                                                  __String::create("Record 1 mission"),
                                                  scoreId,
                                                  __Double::create(10.0));
    
    CCMission *mission2 = CCRecordMission::create(__String::create("record2_mission"),
                                                  __String::create("Record 2 mission"),
                                                  scoreId,
                                                  __Double::create(100.0));
    
    __Array *missions = __Array::create(mission1, mission2, NULL);
    
    CCBadgeReward *badgeReward = CCBadgeReward::create(__String::create("challenge_badge_reward_id"),
                                                       __String::create("ChallengeBadgeRewardId"));
    __Array *rewards = __Array::create(badgeReward, NULL);
    
    CCChallenge *challenge = CCChallenge::create(__String::create("challenge_id"),
                                                 __String::create("Challenge"),
                                                 missions,
                                                 rewards);
    
    challenge->isCompleted(); //false
    
    CCWorld *world = CCWorld::create(__String::create("initial_world"));
    world->addMission(challenge);
    world->addScore(score);
    
    CCSoomlaLevelUp::getInstance()->initialize(world);
    
    score->setTempScore(20.0);
    score->reset(true);
    
    // events:
    // onMissionCompleted (mission1) (LevelUp events)
    // [onScoreRecordReached] - if record is broken
    
    score->setTempScore(120.0);
    score->reset(true);
    
    // events:
    // onMissionCompleted (mission2) (LevelUp events)
    // onMissionCompleted (challenge) (LevelUp events)
    // onRewardGivenEvent (badgeReward) (Core events)
    
    challenge->isCompleted(); // true
    badgeReward->isOwned(); // true
  • CCGatesList

Note that currently a GatesList gate is automatically opened when sub-gates fulfill the GatesList requirement.

__String *recordGateId1 = __String::create("gates_list_record_gate_id1");
__String *scoreId1 = __String::create("gates_list_score_id1");
__Double *desiredRecord1 = __Double::create(10.0);
__String *recordGateId2 = __String::create("gates_list_record_gate_id2");
__String *scoreId2 = __String::create("gates_list_score_id2");
__Double *desiredRecord2 = __Double::create(20.0);

CCScore *score1 = CCScore::create(scoreId1);
CCScore *score2 = CCScore::create(scoreId2);

CCWorld *world = CCWorld::create(__String::create("initial_world"));
CCLevel *lvl1 = CCLevel::create(__String::create("level1_id"));
lvl1->addScore(score1);
lvl1->addScore(score2);
world->addInnerWorld(lvl1);

CCRecordGate *recordGate1 = CCRecordGate::create(recordGateId1, scoreId1, desiredRecord1);
CCRecordGate *recordGate2 = CCRecordGate::create(recordGateId2, scoreId2, desiredRecord2);

__Array *gates = __Array::create(recordGate1, recordGate2, NULL);

CCGatesListOr *gatesListOR = CCGatesListOr::create(__String::create("gate_list_OR_id"),
                                                  gates);

CCGatesListAnd *gatesListAND = CCGatesListAnd::create(__String::create("gate_list_AND_id"),
                                                      gates);

CCSoomlaLevelUp::getInstance()->initialize(world);

score1->setTempScore(desiredRecord1->getValue());
score1->reset(true);

recordGate1->isOpen(); // true
gatesListOR->isOpen(); // true

gatesListAND->canOpen(); // false (all sub-gates need to be open for AND)
gatesListAND->isOpen(); // false

score2->setTempScore(desiredRecord2->getValue());
score2->reset(true);

recordGate2->isOpen(); // true
gatesListOR->isOpen(); // still true
gatesListAND->isOpen(); // true

Contribution

SOOMLA appreciates code contributions! You are more than welcome to extend the capabilities of SOOMLA.

Fork -> Clone -> Implement -> Add documentation -> Test -> Pull-Request.

IMPORTANT: If you would like to contribute, please follow our Documentation Guidelines. Clear, consistent comments will make our code easy to understand.

SOOMLA, Elsewhere ...

License

Apache License. Copyright (c) 2012-2014 SOOMLA. http://www.soom.la

cocos2dx-levelup's People

Contributors

dimanem avatar eugenebutusov avatar gurdotan avatar hadarhod87 avatar refaelos avatar sluzky avatar vedi avatar

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.