存档

2014年1月 的存档

ios7内购、Game Center 实现 in-App Purchases & Game Center

2014年1月27日 没有评论

猴子原创,欢迎转载。转载请注明: 转载自Cocos2D开发网–Cocos2Dev.com,谢谢!

原文地址: http://www.cocos2dev.com/?p=514

昨天使用ios7SDK build的时候,发现了几个warning,原来以前写的内购方法,有些在ios7下弃用了。今天改了下,顺便代码也发上。

PGStoreKitManager.h

//
//  PGStoreKitManager.h
//  OCPhysicGame
//
//  Created by LiuYanghui on 14-1-26.
//  Copyright (c) 2014年 LiuYanghui. All rights reserved.
//

#import <Foundation/Foundation.h>
#import <GameKit/GameKit.h>
#import <StoreKit/StoreKit.h>

@class ViewController;
@interface PGStoreKitManager : NSObject<GKGameCenterControllerDelegate, SKPaymentTransactionObserver, SKProductsRequestDelegate>
{
    UIAlertView *_loadingAlert;
    BOOL _enableGameCenter;
}

@property (nonatomic, readwrite, strong) ViewController* viewController;
+ (PGStoreKitManager *)getInstance;

// game center ----------------------------------------
/**
 登陆gamecenter,请先设置setViewController
 */
- (void)authenticateLocalPlayer;

/**
 上传积分
 */
- (void)reportScore : (NSString*)identifier hiScore:(int64_t)score;

/**
 上传成就
 */
- (void)reportAchievementIdentifier : (NSString*)identifier percentComplete:(float)percent;

/**
 显示排行版
 */
- (void)showLeaderboard : (NSString*)leaderboard;

/**
 显示成就
 */
- (void)showAchievements;


// iap  ----------------------------------------
/**
 初始化内消费
 */
- (void)initStoreKit;

/**
 购买产品
 */
- (void)purchaseItem: (NSString*)identifier;


@end

PGStoreKitManager.m


//
//  PGStoreKitManager.m
//  OCPhysicGame
//
//  Created by LiuYanghui on 14-1-26.
//  Copyright (c) 2014年 LiuYanghui. All rights reserved.
//

#import "PGStoreKitManager.h"
#import "ViewController.h"

@implementation PGStoreKitManager

+ (PGStoreKitManager *)getInstance
{
    static PGStoreKitManager *mgr = nil;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        mgr = [[self alloc] init];
    });
    return mgr;
}

- (id)init
{
    self = [super init];
    if (self) {
        [self initData];
        return self;
    }
    return nil;
}

- (void)initData
{
    _enableGameCenter = NO;
    _viewController = nil;
}

- (void)showMessage:(NSString *)title Message:(NSString *)msg
{
    UIAlertView *alert = [[UIAlertView alloc] initWithTitle:title message:msg delegate:self cancelButtonTitle:@"确定" otherButtonTitles:nil, nil];
    [alert show];
}

- (void)showLoadingView:(NSString *)title
{
    _loadingAlert= [[UIAlertView alloc] initWithTitle:title message:@"" delegate:self cancelButtonTitle:nil otherButtonTitles:nil, nil];
    [_loadingAlert show];
}

- (void)removeLoadingView
{
    [_loadingAlert dismissWithClickedButtonIndex:0 animated:YES];
}

#pragma mark - GameCenter
- (void)authenticateLocalPlayer
{
    GKLocalPlayer* localPlayer = [GKLocalPlayer localPlayer];
    if ([localPlayer isAuthenticated] == NO) {
        localPlayer.authenticateHandler = ^(UIViewController *viewController,
          NSError *error) {
            if (error) {
                _enableGameCenter = NO;
            }else{
                _enableGameCenter = YES;
                if(viewController) {
                    [_viewController presentViewController:viewController animated:YES completion:nil];
                }
            }
        };
    }else{
        _enableGameCenter = YES;
    }
}

/**
 上传积分
 */
- (void)reportScore : (NSString*)identifier hiScore:(int64_t)score;
{
    if (score < 0 || !_enableGameCenter)
		return;
	GKScore *scoreBoard = [[GKScore alloc] initWithLeaderboardIdentifier:identifier];
    scoreBoard.value = score;
    [GKScore reportScores:@[scoreBoard] withCompletionHandler:^(NSError *error) {
        if (error) {
            // handle error
        }
    }];
}

/**
 上传成就
 */
- (void)reportAchievementIdentifier : (NSString*)identifier percentComplete:(float)percent
{
    if (percent < 0 || !_enableGameCenter)
		return;
	
    GKAchievement *achievement = [[GKAchievement alloc] initWithIdentifier: identifier];
    if (achievement){
		achievement.percentComplete = percent;
        [GKAchievement reportAchievements:@[achievement] withCompletionHandler:^(NSError *error) {
            if (error) {
                // handle error
            }
        }];
    }
}

/**
 显示排行版
 */
- (void)showLeaderboard : (NSString*)leaderboard
{
    if (!_enableGameCenter)
		return;
    GKGameCenterViewController *gameCenterViewController = [[GKGameCenterViewController alloc] init];
    gameCenterViewController.viewState = GKGameCenterViewControllerStateLeaderboards;
    gameCenterViewController.gameCenterDelegate = self;
    [_viewController presentViewController:gameCenterViewController animated:YES completion:nil];
}

/**
 显示成就
 */
- (void)showAchievements
{
    if (!_enableGameCenter)
		return;

    GKGameCenterViewController *gameCenterViewController = [[GKGameCenterViewController alloc] init];
    gameCenterViewController.viewState = GKGameCenterViewControllerStateAchievements;
    gameCenterViewController.gameCenterDelegate = self;
    [_viewController presentViewController:gameCenterViewController animated:YES completion:nil];
}

#pragma mark gameCenterViewController Close回调
- (void)gameCenterViewControllerDidFinish:(GKGameCenterViewController *)gameCenterViewController
{
    [_viewController dismissViewControllerAnimated:YES completion:nil];
}





//---------------------------------------------------------
#pragma mark - IAP
- (BOOL)canProcessPayments
{
    if ([SKPaymentQueue canMakePayments]) {
        return YES;
    } else {
        return NO;
    }
}


/**
 初始化内消费
 */
- (void)initStoreKit
{
    [[SKPaymentQueue defaultQueue] addTransactionObserver:self];
}

/**
 购买产品
 */
- (void)purchaseItem: (NSString *)identifier
{
    [self showLoadingView:@"Access Store..."];
    
    if (![self canProcessPayments]) {
        NSLog(@"1.失败-->SKPaymentQueue canMakePayments NO");
        [self removeLoadingView];
        return;
    }
    NSLog(@"1.成功-->请求产品信息...%@", identifier);
    
    // 使用请求商品信息式购买
    SKProductsRequest *request= [[SKProductsRequest alloc]
                                 initWithProductIdentifiers: [NSSet setWithObject: identifier]];
    request.delegate = self;
    [request start];
}

// SKProductsRequest 的回调
- (void)productsRequest:(SKProductsRequest *)request didReceiveResponse:(SKProductsResponse *)response
{
    NSArray *myProduct = response.products;

    if (myProduct.count == 0) {
        NSLog(@"2.失败-->无法获取产品信息,购买失败。invalidProductIdentifiers = %@",response.invalidProductIdentifiers);
        [self removeLoadingView];
        return;
    }
    NSLog(@"2.成功-->获取产品信息成功,正在购买...");
    SKPayment * payment = [SKPayment paymentWithProduct:myProduct[0]];
    [[SKPaymentQueue defaultQueue] addPayment:payment];
}

// SKPayment 的回调
- (void)paymentQueue:(SKPaymentQueue *)queue updatedTransactions:(NSArray *)transactions
{
    NSLog(@"3.成功-->接收苹果购买数据,正在处理...");
    for (SKPaymentTransaction *transaction in transactions){
        switch (transaction.transactionState){
            case SKPaymentTransactionStatePurchased:
                [self completeTransaction:transaction];
                break;
                
            case SKPaymentTransactionStateFailed:
                [self failedTransaction:transaction];
                break;
                
            case SKPaymentTransactionStateRestored:
                [self restoreTransaction:transaction];
                break;
                
            default:
                break;
        }
    }
}

// 结束交易
- (void) completeTransaction: (SKPaymentTransaction*)transaction
{
    NSLog(@"4.成功-->结束交易 SKPaymentTransactionStatePurchased");
    [self removeLoadingView];
	// 记录交易和提供产品 这两方法必须处理
    [self recordTransaction: transaction];
    [self provideContent: transaction.payment.productIdentifier];
	
    // 移除 transaction from the payment queue.
    [[SKPaymentQueue defaultQueue] finishTransaction: transaction];
}

// 重置交易
- (void) restoreTransaction: (SKPaymentTransaction*)transaction
{
    NSLog(@"4.成功-->重置交易 SKPaymentTransactionStateRestored");
    [self recordTransaction: transaction];
    [self provideContent: transaction.originalTransaction.payment.productIdentifier];
    [[SKPaymentQueue defaultQueue] finishTransaction: transaction];
}

// 交易失败
- (void) failedTransaction: (SKPaymentTransaction*)transaction
{
    [self removeLoadingView];
    NSLog(@"4.成功-->交易失败 SKPaymentTransactionStateRestored error.code:%d",(int)transaction.error.code);
    [[SKPaymentQueue defaultQueue] finishTransaction: transaction];
}

// 交易记录
- (void) recordTransaction: (SKPaymentTransaction*)transacation
{
    NSLog(@"4.成功-->交易记录, 可以在此处存储记录");
}

// 提供产品
- (void) provideContent: (NSString*)identifier
{
    NSLog(@"4.成功-->交易成功,请提供产品 identifier = %@", identifier);
    
    [self removeLoadingView];
    [self showMessage:@"Success" Message:@"You have successfully purchased."];
}

@end

注释已经写的很清楚了,再有不清楚的可以留言。

分类: 未分类 标签:

【cocos2d-x 手游研发小技巧(5)获取网络图片缓存并展示】

2014年1月27日 没有评论

今天是年前最后一天上班了,最后一天上班,祝大家马上有各种东西,最后一天也给写一点干货,就是获取网络图片;

经过自己简单封装了一下,实现了获取网络图片,按照比例展示出来,实现方法是cocos2dx – http的异步方法,相信有很多地方都会使用

到着这个需求;比如获取玩家的头像。

我就直接贴代码了,只需一个类就可以搞定;

HttpGetImg.h

#ifndef __HttpGetImg__
#define __HttpGetImg__

#include "cocos2d.h"
#include "HttpRequest.h"
#include "HttpClient.h"
USING_NS_CC_EXT;
using namespace std;
USING_NS_CC;

class HttpGetImg : public cocos2d::CCLayer
{
public:
    
    HttpGetImg();
    ~HttpGetImg();
    //获取网络图片,需要地址
    static void GetHttpImg(CCObject* obj, string imgurl,int number);
    
    void onHttpRequestRptImg(cocos2d::extension::CCHttpClient *sender, cocos2d::extension::CCHttpResponse *response);

    //按原来默认头像比例设置新图片大小
    static void setImgSize(int oldhead_w,int oldhead_h,CCSprite* sprite);
    
    //创建图片覆盖原有图片
    static void CreateImg(CCSprite* tagSprite,CCSprite* oldSprite,CCTexture2D* texture,int newTag);
private:
    
};

#endif /* HttpGetImg */

HttpGetImg.cpp

#include "HttpGetImg.h"
#include "../DataModel/GlobalInfo.h"
#include "../GameConfig.h"
#include "../Commen/PublicDoFunc.h"
HttpGetImg::HttpGetImg(void)
{
    
}

void HttpGetImg::GetHttpImg(CCObject* obj, string imgurl,int number)
{
    CCHttpRequest* request = new CCHttpRequest();
    // required fields
    request->setUrl(imgurl.c_str());
    request->setRequestType(CCHttpRequest::kHttpGet);
    request->setResponseCallback(obj, httpresponse_selector(HttpGetImg::onHttpRequestRptImg));
    // optional fields
    char thisnumber[10] = "";
    sprintf(thisnumber, "%d",number);
    request->setTag(thisnumber);
    CCHttpClient::getInstance()->send(request);
    request->release();
}

void HttpGetImg::onHttpRequestRptImg(CCHttpClient *sender, CCHttpResponse *response)
{
    
    char c_tag[20]= "";
    sprintf(c_tag, "%s",response->getHttpRequest()->getTag());
    //    CCLog("%s completed", response->getHttpRequest()->getTag());
    string str_tag = c_tag;
    if (!response)
    {
        return;
    }
    // You can get original request type from: response->request->reqType
    if (0 != strlen(response->getHttpRequest()->getTag()))
    {
        //        CCLog("%s completed", response->getHttpRequest()->getTag());
    }
    
    if (!response->isSucceed())
    {
        CCLog("response failed");
        CCLog("error buffer: %s", response->getErrorBuffer());
        return;
    }
    
    vector<char> *buffer = response->getResponseData();
    
    //create image
    CCImage* img = new CCImage;
    img->initWithImageData((unsigned char*)buffer->data(),buffer->size());
    
    //create texture
    CCTexture2D* texture = new CCTexture2D();
    bool isImg = texture->initWithImage(img);
    img->release();
    
   //将texture存下来 texture
//已下是自己封装的PublicDoFunc异步调用主线程执行换图操作的部分,可以自己去封装 //SEL_CallFuncN pfnCallback =callfuncN_selector(View_Room::upPlayerHead); //CCNode* nd = CCNode::create(); //buffer->clear(); //nd->setTag(CCString::create(str_tag)->intValue()); //PublicDoFunc::toDoFuncN(LAYER_ROOM, pfnCallback,nd); } void HttpGetImg::setImgSize(int oldhead_w,int oldhead_h,CCSprite* sprite) { float s_X=oldhead_w/sprite->getContentSize().width; float s_Y=oldhead_h/sprite->getContentSize().height; sprite->setScaleX(s_X); sprite->setScaleY(s_Y); } void HttpGetImg::CreateImg(CCSprite* tagSprite,CCSprite* oldSprite,CCTexture2D* texture,int newTag) { int oldw =oldSprite->getContentSize().width; int oldh =oldSprite->getContentSize().height; if(texture!=NULL) { CCSprite* sprite = CCSprite::createWithTexture(texture); //按原比例设置 setImgSize(oldw,oldh,sprite); sprite->setPosition(oldSprite->getPosition()); tagSprite->addChild(sprite,1,newTag); texture->release(); } } HttpGetImg::~HttpGetImg(void) { }

 

代码非常简洁简单,先通过:

GetHttpImg(CCObject* obj, string imgurl,int number);

获取到texture,然后把texture存起来,在自己要展示的页面去调用:

CreateImg(CCSprite* tagSprite,CCSprite* oldSprite,CCTexture2D* texture,int newTag)

第一个参数是要展示的父级sprite,第二个是默认头像图片(如果没有下载成功网络图片,显示替代图片),第三个是缓存的texture;

 

效果图:

【cocos2d-x 手游研发小技巧(5)获取网络图片缓存并展示】

 

结束,祝大家新年快乐;

ps:群号(41131516

 

 

 

 

 

分类: 未分类 标签:

【cocos2d-x 手游研发小技巧(4)与Android混编实现换“头像图片”】

2014年1月23日 没有评论

cocos2dx在android平台上的游戏开发中往往会遇到一些混编需求,如:

比方有的社区类游戏需要用到更换玩家的“头像”操作,其实就是调用android servers服务里面的本地图片,以及选取,裁剪图片,裁剪完成往服务器上传图片功能,从而达到换用户头像的操作的功能;

那么用JniHelper 去调用 andriod java里面的类和方法实现混编就能满足我们操作android系统的各种需求:获取本机MAC地址,获取本机名称,甚至还可去操作android后台服务的复杂操作了;

言归正传,我们需要去写好android 的Activity类,这个类主要功能就是 调用android本地图片,选取,裁剪,裁剪玩往服务器上传图片;先看一下我的目录结构:

【cocos2d-x 手游研发小技巧(4)与Android混编实现换“头像图片”】

下面一个是我们游戏的入口主Cocos2dxActivity,上面一个UserInfoActivity.java则是我们真正需要去调用换头像功能的类;

他包含一个userinfo.xml layer 这方面是android开发的知识;

【cocos2d-x 手游研发小技巧(4)与Android混编实现换“头像图片”】

 

userinfo.xml视图文件的界面内容是这样的:

【cocos2d-x 手游研发小技巧(4)与Android混编实现换“头像图片”】

 

具体里面的代码我就不贴了,这里主要不是说怎么搞android开发,整个工程需要的文件图片,我都会上传,大家自取;

以上的UserInfoActivity.java类已经完全实现了上述功能,只需要在工程导入类就行;

ok,功能类实现了,那怎么进行C++调用java呢?,原理是在C++类里面用JniHelper去调用JAVA类里面的某个方法;

现在我想在我C++类里面去调用我游戏入口Cocos2dxActivity(zha_jin_hua.java)里面的一个方法,这个方法主要是执行android的页面跳转,跳转的我的功能类UserInfoActivity.java;

zha_jin_hua.java类方法如下:

    public static Object gotoActivity()
    {
        Intent in = new Intent(zha_jin_hua.getContext(),
                UserInfoActivity.class);
        zha_jin_hua.getContext().startActivity(in);
        
        return null;
    }

这是一个静态类;返回类型为Object,但是我不需要返回值,因为我执行页面跳转,那如果我的需求是获取android模块代码的值,就可以填写对应的返回类型,就可以进行java和c++的相互传值;

在C++类的头文件需要引入:

#if (CC_TARGET_PLATFORM == CC_PLATFORM_ANDROID)
#include <jni.h>
#include "platform/android/jni/JniHelper.h"
#include <android/log.h>

#if 1
#define  LOG_TAG    "JniHelper"
#define  LOGD(...)  __android_log_print(ANDROID_LOG_DEBUG,LOG_TAG,__VA_ARGS__)
#else
#define  LOGD(...)
#endif

#endif

在c++类具体调用时需要如下执行:

void PersonLayer::onHeadTouched()
{
    CCLog("玩家点击头像换头像了");
    BaseSoundControl::PlayEffectMusic(EFFECT_CLICK);
    #if (CC_TARGET_PLATFORM == CC_PLATFORM_ANDROID)
    JniMethodInfo minfo;
    jobject jobj;
        //getStaticMethodInfo方法是调用静态类的,也可以不用调用静态类的getMethodInfo
        bool b = JniHelper::getStaticMethodInfo(minfo,
                                          "com.dcgame.zhajinhua.zha_jin_hua", //类路径
                                          "gotoActivity", //静态方法名
                                          "()Ljava/lang/Object;");//括号里的是参数,后面的是返回值。
        if(!b){
            CCLog("JniHelper::getMethodInfo error...");
        }else{
            CCLog("ready to invoke method...");
            jobj = minfo.env->CallStaticObjectMethod(minfo.classID, minfo.methodID);
        }
    #endif
}

是这样就可以调用Java代码了,去执行了gotoActivity方法,这个方法是静态的,所以用了getStaticMethodInfo,如果不是则用getMethodInfo

完成以上操作还没完,因为我们调用的是android系统头像,需要用到照相功能,所以还的开启这个功能权限;

在AndroidManifest.xml中添加如下代码:

    <uses-permission android:name="android.permission.CAMERA" />
    <uses-feature android:name="android.hardware.camera" />
    <uses-feature android:name="android.hardware.camera.autofocus" />
    <uses-permission android:name="android.permission.READ_LOGS">    

还有一个类,的activity的配置:

<activity android:name="com.xxx.xxxxx.UserInfoActivity"></activity>

ok,配置完成,就可以在android实现换头像操作了,效果如下:

 【cocos2d-x 手游研发小技巧(4)与Android混编实现换“头像图片”】

【cocos2d-x 手游研发小技巧(4)与Android混编实现换“头像图片”】

【cocos2d-x 手游研发小技巧(4)与Android混编实现换“头像图片”】

【cocos2d-x 手游研发小技巧(4)与Android混编实现换“头像图片”】

 

相关图片资源,源码下载地址:

百度云:http://pan.baidu.com/share/link?shareid=1525180823&uk=4097703620&third=15

 ps:cocos2dx研发群(41131516

分类: 未分类 标签:

【cocos2d-x 手游研发—-博彩大转盘】

2014年1月19日 没有评论

博彩大转盘,转盘抽奖的小系统,这是一个很有意思的游戏模块,游戏中增加这样一些趣味的小模块,我会附上源码;

会增进玩家的粘性,每天都想来抽两把试试手气;

我做的这个是个矩形风格的转盘,不是那种圆形的转盘,但是原理是相差不多的;

首先准备一些素材,如:奖品,转盘格子背景,开始按钮等等….

【cocos2d-x 手游研发----博彩大转盘】【cocos2d-x 手游研发----博彩大转盘】

【cocos2d-x 手游研发----博彩大转盘】【cocos2d-x 手游研发----博彩大转盘】【cocos2d-x 手游研发----博彩大转盘】

 

接下来,我想把这个转盘系统单独做在一个class文件夹中,以后可插拔的方便接入任何游戏,建了一个文件夹ZhuanPanSystem;

说一下大概的制作思路,首先是需要格子,来组成一个矩形矩阵,长和宽根据自己需求自己去设置,中间有一个按钮,点了之后,格子

就会变背景,并且循环跑动在矩形格子上,最终根据加速度从快到慢,减速下来停在哪个格子上,便获取到该格子上的奖励;

ok思路一定,看下代码如何实现;

格子:

//创建一个矩阵格子阵
    boxgezi = CCArray::create();
    int bid = 0;
    for (int i = 0; i < 4; i++)
    {
        for (int j = 0; j <=5; j++)
        {

            Zp_BoxData* thisbox = new Zp_BoxData();
            thisbox->set_boxid(bid);
            thisbox->set_boxReward(getReward(bid%6));
            if(bid==4)
            {
                thisbox->set_xuanzhong(true);
            }
            else
            {
                thisbox->set_xuanzhong(false);
            }
            thisbox->set_tag(bid);
            switch (i)
            {
            case 0:
                thisbox->set_point(ccp(55+gezi_w*j,allbd_h-30));
                boxgezi->addObject(thisbox);
                break;
            case 1:
                if(j<=2)
                {
                    thisbox->set_point(ccp(55+gezi_w*5,allbd_h-30-gezi_h-gezi_h*j));
                    boxgezi->addObject(thisbox);
                }
                break;
            case 2:
                thisbox->set_point(ccp(55+gezi_w*5-gezi_w*j,30));
                boxgezi->addObject(thisbox);
                break;
            case 3:
                if(j<=2)
                {
                    thisbox->set_point(ccp(55,30+gezi_h+gezi_h*j));
                    boxgezi->addObject(thisbox);
                }
                break;
            default:

                break;
            }
            bid++;
        }
    }
    vector<int> maua ;

    for (int i = 0; i < boxgezi->count(); i++)
    {
        Zp_BoxData* bdata = (Zp_BoxData*)boxgezi->objectAtIndex(i);
        Gzi* gz = new Gzi(allbd,bdata);
        maua.push_back(bdata->get_boxid());
    }

以上就是利用Gzi类创建出来的一个矩形范围的矩阵转盘,有了矩形转盘,还需要游戏中的点击开始以后,循环转动的效果;

用了一个递归去循环去跑一个加速度的效果的方法:

void TurntableSystem::runTurntableGet(float time)
{
    this->schedule(schedule_selector(TurntableSystem::runAct), time); 
}


void TurntableSystem::runAct(float time)
{
    vector<int> gezi_l = GlobalInfo::getInstance()->get_gizilist();
    //做事儿
    if(gezi_l.size()>0)
    {
        if(fnum>gezi_l.size()-1)
        {
            fnum = 0;
        }
        int bid = gezi_l.at(fnum);
        changeBox(bid,true);
        //再把上一个变回来
        int lastnum = fnum-1;
        if(lastnum<0)
        {
            lastnum=gezi_l.size()-1;
        }
        int lastid = gezi_l.at(lastnum);
        changeBox(lastid,false);
        fnum++;
    }
    runnum++;
    this->unschedule(schedule_selector(TurntableSystem::runAct)); 
    CCLOG("------%f----times=%d-",time,runnum);
    if(runnum<25)
    {
        float nexttime =  time+runnum*0.01f;
        if(nexttime>=1.5f)
        {
            nexttime=1.5f;
        }
        this->schedule(schedule_selector(TurntableSystem::runAct),nexttime);
    }
}

这边我是启动了一个定时器去实现这个递归加速的方法,里面的25目前是固定的跑25格必定停下!!!
以下就牵扯到随机数概率获取奖品的问题了,那么根据咱们策划给的方案,每个格子的概率对应的格子数,和步数

去set这个值就可以了,剩下的工作就很简单了,只需增加随机概率就可以了;

下面我帖一下跑起来的效果图:

 【cocos2d-x 手游研发----博彩大转盘】

开始后循环跑动;

【cocos2d-x 手游研发----博彩大转盘】

 

源码及素材下载资源地址:

百度云盘:http://pan.baidu.com/share/link?shareid=3443771417&uk=4097703620&third=15

分类: 未分类 标签:

Cocos2d-x 3.0 开发(十六)cocos2dx-3.0beta版建立新项目并加载CocoStudio导出文件

2014年1月16日 没有评论

1、概述

    与alpah版相比,beta版中更改了创建的脚本,可以自定义项目的目录,接下来我们看看。先上图:


Cocos2d-x 3.0 开发(十六)cocos2dx-3.0beta版建立新项目并加载CocoStudio导出文件

2、项目创建

    找到 cocos2dx根目录/tools/project-creator/create_project.py文件,双击运行即可。如果未安装python环境,则需要下载安装。脚本运行起来,会显示一个图形界面,用以设置相应的项目名称、Android包名和文件路径。设置好后,点击下面的create按钮创建项目,创建成功后会弹出如图所示提示框。


Cocos2d-x 3.0 开发(十六)cocos2dx-3.0beta版建立新项目并加载CocoStudio导出文件


    这样我们就成功创建了一个项目,找到对应目录运行vs2012,编译运行。


3、添加其他库

    cocos2d-x 3.0 采用了耦合性更强的设计,使得模块更多以库的形式存在于项目中。新版本中我们需要经常添加链接库,下面以对CocoStudio库为例,加载一个用CocoStudio编辑的导出界面。


3.1 制作界面Json

    打开CocoStudio的UI编辑器,编辑一个简单的界面导出,并复制到项目中。如不太会操作,可以参考前面的博客,这里就不再复述。


3.2 添加库项目

    在“解决方案资源管理器”中找到整个解决方案,右击,选择“添加”->“现有项目”。在弹出的对话框中找到“项目目录/cocos2d/cocos/editor-support/cocostudio/proj.win32/libCocoStuido”点击确定,即可加入到解决方案中,效果如图所示:

Cocos2d-x 3.0 开发(十六)cocos2dx-3.0beta版建立新项目并加载CocoStudio导出文件


3.3 添加库项目引用

    找到我们的目标项目“HelloBeta”右击,选择“引用…”。在弹出的属性页中点选下面的“添加新引用”。在弹出的子级对话框中选择我们需要的库,点击确定,即可添加项目对库的引用。


Cocos2d-x 3.0 开发(十六)cocos2dx-3.0beta版建立新项目并加载CocoStudio导出文件


    这样libCocoStudio就被我们添加好了,同样的方法,添加libGUI和libExtension两个库。


3.4 更改代码

    更改代码就没什么特别的了。首先要加入包含目录“$(EngineRoot)cocos/editor-support”和“$(EngineRoot)cocos”。然后去init中更改代码。

#include "cocostudio/CocoStudio.h"

bool HelloWorld::init()
{
    //////////////////////////////
    // 1. super init first
    if ( !Layer::init() )
    {
        return false;
    }
    auto uiLayer = cocostudio::GUIReader::getInstance()->widgetFromJsonFile("HelloBeta.json");
    addChild(uiLayer);

    return true;
}

    编译运行即可。


4、总结

    通过vs2012在解决方案中添加依赖库项目和引用的方法,创建Beta版的Cocos2d-x项目。


    本篇博客出自阿修罗道,转载请注明出处,禁止用于商业用途:http://blog.csdn.net/fansongy/article/details/18366275 

分类: 未分类 标签:

2D游戏中的碰撞检测:圆形与矩形碰撞检测(Javascript&C++版)

2014年1月13日 没有评论

这几天放寒假了,时间也多了起来,当然又有时间搞搞程序了。哈哈~

昨天在开发我的塔防游戏时突然发现人物实际攻击范围比规定的范围小,按理说应该是一样大的,但偏偏不是,我被这个问题搞得糊里糊涂的,一直没想出问题所在。最后询问了一个程序高手——我哥哥。他虽然是搞C++的,但听了我代码解释中有检测圆形碰撞时,他立刻就发现了问题,他告诉我,敌人可以看作是方块,而攻击范围是圆的,如果把敌人弄成圆形进行碰撞检测那必然不准,应该检测矩形和圆形碰撞才行。我听了之后恍然大悟,但是lufylegend中没有这个功能,怎么办呢?我第一想法是对lufy说说,让他老人家实现吧。当我点开Google Talk准备发起对话时,突然又想到一来要是lufy老人家去实现,那要等到猴年马月去了,况且lufy前辈琐事缠身,要是我总是给他提意见不帮忙解决,他老人家是不是想打我啊……最后我还是决定自己来实现吧。但是我没搞过这方面的研究,没有经验,所以一开始有点懵,于是就去Google了一下,发现还真有人讲过,于是就点开看了,不知道是我理解能力不好还是文章写得差(估计都是我理解能力不好……)我看了半晌没看懂,呜呼,无法可想,我当时就失望了。但是文章下面有段C代码,于是我把它移植到js上来,运行了一下,感觉效果还不错,于是就马上跑到github上把代码上传给lufy了,并做了一个demo,并在Google Talk上提醒了lufy叫他老人家测试,结果lufy拿到代码一测试就发现了bug。我X,不愧是大神啊……没有办法,只有另谋出路了。

今早起来,哎呀,天气不错啊,成都好久没有这么爽的天气了。只见空气清新,阳光和煦,真是外出骑车的好机会啊!于是我便和家人一块儿跑到外面溜达了一圈。边走边想矩形和圆形碰撞的事。半天想不明白,呜呼,我只好在路上问了问哥哥。哥哥果然是高手,他想了一会儿便说出了重点,给了我启发。于是回到家,我便马上打开电脑,进行了实验,结果还成功了。当然,按照以往我的习惯,这次小小“发明”也当然也要分享给大家啦~

(以上事情均发生在1月11日和1月12日,所以lufy看到文章开头不要以为走错家门了……)

上面说到了我的塔防游戏,现在已经完工得差不多了~大家可以看看它的一些介绍:http://www.cnblogs.com/yorhom/p/sanguotd.html ,顺便发几张截图,给大伙提提兴趣。

2D游戏中的碰撞检测:圆形与矩形碰撞检测(Javascript&amp;C++版)

2D游戏中的碰撞检测:圆形与矩形碰撞检测(Javascript&amp;C++版)

废话写了一大堆,接下来还是来看看矩形和圆形碰撞实现过程吧。

一,原理介绍

这回有点复杂,不过看懂了还是很好理解的。当然,我不敢保证这种算法在任何情况下都会起效果,如果有同学测试时,发现出现错误,请及时联系我。

我们首先来建立一个以圆心为原点的坐标系:

2D游戏中的碰撞检测:圆形与矩形碰撞检测(Javascript&amp;C++版)

然后要检测碰撞就只有两种情况了。

情况一,矩形全部都在一个象限内,如图:

2D游戏中的碰撞检测:圆形与矩形碰撞检测(Javascript&amp;C++版)

当然,图中只是举个例子,不一定是只在第二象限,任何一个象限都行,只要是矩形全在该象限。

这种情况比较好解决,首先,我们计算出矩形每个角的坐标,然后用勾股定律依次算出这个角到圆心的距离是否小于或者等于半径。设这个角与圆心横坐标之差为d1,纵坐标之差为d2,半径为r,公式表达如下:

2D游戏中的碰撞检测:圆形与矩形碰撞检测(Javascript&amp;C++版)

如果有一个角满足要求说明产生碰撞,返回true。

但是有朋友懵了,怎么判断矩形是不是在一个象限内呢?很简单,只要判断这个矩形左上角和右下角是否在同一个象限内就可以了。于是我们得写个函数来实现判断某两个角是否在同一象限。

函数代码如下:

function isSameQuadrant(cood,objA,objB){
	var coodX = cood.x;
	var coodY = cood.y;
	var xoA = objA.x
	,yoA = objA.y
	,xoB = objB.x
	,yoB = objB.y;
	
	if(xoA-coodX>0 && xoB-coodX>0){
		if((yoA-coodY>0 && yoB-coodY>0) || (yoA-coodY<0 && yoB-coodY<0)){
			return true;
		}
		return false;
	}else if(xoA-coodX<0 && xoB-coodX<0){
		if((yoA-coodY>0 && yoB-coodY>0) || (yoA-coodY<0 && yoB-coodY<0)){
			return true;
		}
		return false;
	}else{
		return false;
	}
}

这个函数原本是准备写到lufylegend中LMath静态类中的,参数原本是LPoint对象,但是这里可以用json,因为LPoint里的x,y属性可以写到json里,函数也就同样取得出值了。函数参数介绍:[cood创建的坐标系原点坐标, objA第一个点坐标, objB第二个点坐标] 这几个参数均为json对象,格式为:

{x:点的x坐标, y:点的y坐标}

函数中的代码还是很好理解的,就是判断一下两个点的x坐标都分别减去原点x坐标,看得出的数正负符号是否相同,然后又用同样的办法算出y轴上的符号是否相同,如果都相同就在同一象限。

有了这个函数,剩下得就好办了,直接代入开头给出的公式进行计算即可。

情况二,矩形跨度两个象限或者两个象限以上

这种情况更好办,我们就可以直接把圆看作一个边长为2r正方形,然后用矩形碰撞算法检测正方形和矩形的碰撞,如下图所示:

2D游戏中的碰撞检测:圆形与矩形碰撞检测(Javascript&amp;C++版)

矩形碰撞的算法是什么呢?很easy,如图:

2D游戏中的碰撞检测:圆形与矩形碰撞检测(Javascript&amp;C++版)

如果要横向判断碰撞的话,判断(x1-x2)的绝对值是否小于或者等于w1/2+w2/2,如果是则横向则有碰撞。纵向判断是一样的,判断(y1-y2)的绝对值是否小于或等于h1/2+h2/2即可。

有了这些算法,我们就可以实现情况2了。

二,Javascript版算法&测试代码

先上代码吧:

function hitTestRectArc(rectObj,arcObj,rectVec,arcR){
	var rw = rectObj.getWidth()
	,rh = rectObj.getHeight()
	,ar = arcObj.getWidth()*0.5
	,rx = rectObj.x
	,ry = rectObj.y
	,ax = arcObj.x
	,ay = arcObj.y;
	
	if(typeof rectVec != UNDEFINED){
		rx += (rw - rectVec[0])*0.5;
		ry += (rh - rectVec[1])*0.5;
		rw = rectVec[0];
		rh = rectVec[1];
	}
	if(typeof arcR != UNDEFINED){
		ax += (ar - arcR);
		ay += (ar - arcR);
		ar = arcR;
	}
	
	var rcx = rx+rw*0.5,rcy = ry+rh*0.5;
	var rltx = rx
	,rlty = ry
	,rlbx = rx
	,rlby = ry+rh
	,rrtx = rx+rw
	,rrty = ry
	,rrbx = rx+rw
	,rrby = ry+rh;
	
	if(
		isSameQuadrant(
			{x:ax,y:ay},
			{x:rltx,y:rlty},
			{x:rrbx,y:rrby}
		)
	){
		var dX1 = Math.abs(ax-rltx),dY1 = Math.abs(ay-rlty);
		var dX2 = Math.abs(ax-rlbx),dY2 = Math.abs(ay-rlby);
		var dX3 = Math.abs(ax-rrtx),dY3 = Math.abs(ay-rrty);
		var dX4 = Math.abs(ax-rrbx),dY4 = Math.abs(ay-rrby);
		
		if(
			(((dX1*dX1) + (dY1*dY1)) <= (ar*ar))
			||(((dX2*dX2) + (dY2*dY2)) <= (ar*ar))
			||(((dX3*dX3) + (dY3*dY3)) <= (ar*ar))
			||(((dX4*dX4) + (dY4*dY4)) <= (ar*ar))
		){
			return true;
		}
		return false;
	}else{
		var result = false;
		var squareX = ax
		,squareY = ay
		,squareW = ar*2
		,squareH = squareW;
		if(
			(Math.abs(squareX-rcx) <= (squareW+rw)*0.5)
			&&(Math.abs(squareY-rcy) <= (squareH+rh)*0.5)
		){
			result = true;
		}
		return result;
	}
}

由于是为lufylegend设计的函数,所以参数为 [ rectObj矩形对象(LSprite或者LShape对象), arcObj圆形对象(LSprite或者LShape对象), rectVec矩形规定大小(可不填), arcR圆形半径(可不填)] 当然,或许些朋友不懂这几行代码:

var rw = rectObj.getWidth()
,rh = rectObj.getHeight()
,ar = arcObj.getWidth()*0.5
,rx = rectObj.x
,ry = rectObj.y
,ax = arcObj.x
,ay = arcObj.y;

好吧,我告诉你,这里用到的是lufylegend中LSprite和LShape,这两个类有x、y属性,还有获取宽度和高度的getWidth()和getHeight(),这里看不懂没关系,你知道是取高度和宽度还有x,y坐标的就行了。当然你要深究,那就看看lufylegend.js的API文档吧:http://lufylegend.com/lufylegend/api ,以下测试代码也用到了lufylegend.js,据说这个引擎是个不错的引擎,想了解的同学,去官方网站看看吧:http://lufylegend.com/lufylegend/ 或者看看我的文章,大多数是讲解有关lufylegend开发的。

示例代码:

init(50,"mylegend",500,250,main);

function main(){
	LGlobal.setDebug(true);
				
	var back = new LSprite();
	back.graphics.drawRect(5,"green",[0,0,LStage.width,LStage.height],true,"lightblue");
	addChild(back);
	
	var cObj = new LSprite();
	cObj.x = 200;
	cObj.y = 120;
	cObj.graphics.drawArc(0,"",[0,0,50,0,2*Math.PI],true,"red");
	back.addChild(cObj);
	
	var rObj = new LSprite();
	rObj.x = 250;
	rObj.y = 70;
	rObj.alpha = 0.8;
	rObj.graphics.drawRect(0,"",[0,0,100,100],true,"green");
	back.addChild(rObj);

	trace(hitTestRectArc(rObj,cObj));
	
	back.addEventListener(LMouseEvent.MOUSE_DOWN,function(e){
		rObj.x = e.offsetX-rObj.getWidth()*0.5;
		rObj.y = e.offsetY-rObj.getHeight()*0.5;
		trace(hitTestRectArc(rObj,cObj));
	});
}

测试链接:http://www.cnblogs.com/yorhom/articles/hitTestRectArc.html

2D游戏中的碰撞检测:圆形与矩形碰撞检测(Javascript&amp;C++版)

三,C++版

C++版我用的是Qt,所以大家运行要在Qt creator里编译运行。

HitTestAlg.h里的代码:

#ifndef HITTESTALG_H
#define HITTESTALG_H

#include <math.h>
#include <QPoint>
#include <QRect>

class CMath
{

public:

	static int pow(int base, int powerOf)
	{
		return (int)::pow((double)base, (double)powerOf);
	}

	static int sqrt(int n)
	{
		return (int)::sqrt((double)n);
	}

	static int abs(int n)
	{
		n = n < 0 ? -n : n;
		return n;
	}

	static int distance(const QPoint& pt1, const QPoint& pt2)
	{
		return CMath::sqrt(CMath::pow(CMath::abs(pt1.x() - pt2.x()), 2) + CMath::pow(CMath::abs(pt1.y() - pt2.y()), 2));
	}

};

class CArc
{

protected:

	int	m_nRadius;
	QPoint	m_ptCenter;

public:

	CArc() : m_nRadius(0), m_ptCenter(0, 0){}
	CArc(const CArc& arc) : m_nRadius(arc.radius()), m_ptCenter(arc.center()){}
	CArc(int radius, QPoint center) : m_nRadius(radius), m_ptCenter(center){}
	CArc(int radius, int centerX, int centerY) : m_nRadius(radius), m_ptCenter(centerX, centerY){}
	~CArc(){}

	void setRadius(int radius){m_nRadius = radius;}
	int radius() const {return m_nRadius;}
	void setCenter(const QPoint& center){m_ptCenter = center;}
	void setCenter(int centerX, int centerY){m_ptCenter = QPoint(centerX, centerY);}
	QPoint center() const {return m_ptCenter;}
	QRect rect() const {return QRect(center().x() - radius(), center().y() - radius(), 2 * radius(), 2 * radius());}

};

class CHitTestAlg
{

protected:

	QRect	m_rtRect;
	CArc	m_arArc;

protected:

	bool locatedSameQuadrant() const
	{
		bool bRes = false;
		int nRectLeft = m_rtRect.left(), nRectTop = m_rtRect.top(), nRectRight = m_rtRect.right(), nRectBottom = m_rtRect.bottom();
		int nArcCenterX = m_arArc.center().x(), nArcCenterY = m_arArc.center().y();
		if((nRectLeft - nArcCenterX >= 0 && nRectRight - nArcCenterX >= 0 && nRectTop - nArcCenterY <= 0 && nRectBottom - nArcCenterY <= 0)
			|| (nRectLeft - nArcCenterX <= 0 && nRectRight - nArcCenterX <= 0 && nRectTop - nArcCenterY <= 0 && nRectBottom - nArcCenterY <= 0)
			|| (nRectLeft - nArcCenterX <= 0 && nRectRight - nArcCenterX <= 0 && nRectTop - nArcCenterY >= 0 && nRectBottom - nArcCenterY >= 0)
			|| (nRectLeft - nArcCenterX >= 0 && nRectRight - nArcCenterX >= 0 && nRectTop - nArcCenterY >= 0 && nRectBottom - nArcCenterY >= 0)
		){
			bRes = true;
		}
		return bRes;
	}

	bool hitTestRect() const
	{
		QRect rtArc = m_arArc.rect();
		bool bRes = false;
		if(CMath::abs(m_rtRect.center().x() - rtArc.center().x()) <= CMath::abs((m_rtRect.width() + rtArc.width()) / 2)
			&& CMath::abs(m_rtRect.center().y() - rtArc.center().y()) <= CMath::abs((m_rtRect.height() + rtArc.height()) / 2)
		){
			bRes = true;
		}
		return bRes;
	}

	bool hitTestAngleArc() const
	{
		bool bRes = false;
		QPoint ptRectTopLeft = m_rtRect.topLeft(), ptRectTopRight = m_rtRect.topRight()
		, ptRectBottomLeft = m_rtRect.bottomLeft(), ptRectBottomRight = m_rtRect.bottomRight()
		, ptArcCenter = m_arArc.center();
		int nArcRadius = m_arArc.radius();

		if(CMath::distance(ptRectTopLeft, ptArcCenter) <= nArcRadius
			|| CMath::distance(ptRectTopRight, ptArcCenter) <= nArcRadius
			|| CMath::distance(ptRectBottomLeft, ptArcCenter) <= nArcRadius
			|| CMath::distance(ptRectBottomRight, ptArcCenter) <= nArcRadius
		){
			bRes = true;
		}
		return bRes;
	}

public:

	CHitTestAlg(const QRect& rect, const CArc& arc) : m_rtRect(rect), m_arArc(arc){}
	~CHitTestAlg(){}

	bool hitTest() const
	{
		bool bRes = false;
		if(locatedSameQuadrant()){
			bRes = hitTestAngleArc();
		}else{
			bRes = hitTestRect();
		}
		return bRes;
	}

};

#endif // HITTESTALG_H

mainwindow.h里的代码:

#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QWidget>
#include "HitTestAlg.h"

class MainWindow : public QWidget
{
	Q_OBJECT

protected:

	QRect		m_rtRect;
	CArc		m_arArc;
	bool		m_bHit;

protected:

	virtual void mouseReleaseEvent(QMouseEvent *mouseEvent);
	virtual void paintEvent(QPaintEvent *paintEvent);

public:

	MainWindow(QWidget *parent = 0);
	~MainWindow();

};

#endif // MAINWINDOW_H

mainwindow.cpp里的代码:

#include <QDebug>
#include <QMouseEvent>
#include <QBrush>
#include <QPainter>
#include "mainwindow.h"

MainWindow::MainWindow(QWidget *parent)
	: QWidget(parent)
	, m_rtRect(0, 0, 100, 50)
	, m_arArc(50, 200, 200)
	, m_bHit(false)
{
	QWidget::showMaximized();
}

MainWindow::~MainWindow()
{
	
}

void MainWindow::mouseReleaseEvent(QMouseEvent *mouseEvent)
{
	if(mouseEvent){
		QPoint ptPos = mouseEvent->pos();
		QRect rtRect;
		rtRect.setX(ptPos.x() - m_rtRect.width() / 2);
		rtRect.setY(ptPos.y() - m_rtRect.height() / 2);
		rtRect.setWidth(m_rtRect.width());
		rtRect.setHeight(m_rtRect.height());
		m_rtRect = rtRect;
		m_bHit = CHitTestAlg(m_rtRect, m_arArc).hitTest();
		QWidget::update();
	}
}

void MainWindow::paintEvent(QPaintEvent *paintEvent)
{
	Q_UNUSED(paintEvent)

	QPainter xPainter(this);
	{
	xPainter.save();
	QBrush xBrush; xBrush.setColor(Qt::red); xBrush.setStyle(Qt::SolidPattern);
	QPen xPen; xPen.setColor(Qt::black); xPen.setStyle(Qt::SolidLine);
	xPainter.setBrush(xBrush);
	xPainter.setPen(xPen);
	xPainter.drawEllipse(m_arArc.center(), m_arArc.radius(), m_arArc.radius());
	xPainter.restore();
	}
	{
	xPainter.save();
	QBrush xBrush; xBrush.setColor(Qt::darkGreen); xBrush.setStyle(Qt::SolidPattern);
	QPen xPen; xPen.setColor(Qt::black); xPen.setStyle(Qt::SolidLine);
	xPainter.setBrush(xBrush);
	xPainter.setPen(xPen);
	xPainter.drawRect(m_rtRect);
	xPainter.restore();
	}
	{
	xPainter.save();
	QString sContent = QString("Hit Test: %1").arg(m_bHit ? "true" : "false");
	QFont ftFont("Tahoma", 12, QFont::DemiBold, true);
	xPainter.setFont(ftFont);
	xPainter.drawText(20, m_arArc.rect().bottom() + 30, sContent);
	xPainter.restore();
	}
}

main.cpp里的代码:

#include <QApplication>
#include "mainwindow.h"

int main(int argc, char *argv[])
{
	QApplication a(argc, argv);
	MainWindow w;
	w.show();
	
	return a.exec();
}

原理和js版是一样的,就不多解释了,在下面我会放出所有代码。C++版运行demo如下:

2D游戏中的碰撞检测:圆形与矩形碰撞检测(Javascript&amp;C++版)
Qt做的界面感觉还是不错的,哈哈~~

源代码下载:http://files.cnblogs.com/yorhom/hitTestRectArc.rar

本文就到此为止,以上就是本篇所有内容,欢迎大家交流。

—————————————————————-

欢迎大家转载我的文章。

转载请注明:转自Yorhom’s Game Box

http://blog.csdn.net/yorhomwang

欢迎继续关注我的博客

分类: html5 标签:

android NDK. libzip stopped to sub folder

2014年1月11日 没有评论

I use libzip to read APK content in native code.

assets/sounds/voice folder “disappeared” for libzip functions only.

  • libzip still see other files.
  • I still can see it in assets/sounds/voice in project folder.
  • I did clean many times.
  • I still can unzip APK file from bin folder and I see all required files. (including files from assets/sounds/voice folder)

I added small logging command and it does not print files from assets/sounds/voice folder. All other files are present.

int inum = zip_get_num_files(apkzip);
for(int i = 0; i < inum; i++){
  const char * name = zip_get_name(apkzip, i, 0);
  __android_log_print(ANDROID_LOG_INFO,"FILEZIP", "zip: %s", name);
}

I have no idea what at what step it is wrong. Had eclipse compressed ZPK with new format that my libzip does not able to read? or what could be a reason.

This is not an answer for libzip, but why you have to use libzip to read apk file in NDK application? In Android NDK, you can use AAsset APIs to get file from the apk. Take a look at “How To Get File In Assets From Android NDK“.

EDITED

It is not available in android-5 that I still use

Ok. So how about Cocos2d-x’s ZipFile? It is based on Minizip.

How to use ZipFile from cocos2dx/platform/android/CCFileUtilsAndroid.cpp

s_pZipFile = new ZipFile(resourcePath, "assets/");
pData = s_pZipFile->getFileData(fullPath.c_str(), pSize);
分类: cocos2d, stackoverflow精选 标签:

How to convert class object to JSon string in Unity3D?

2014年1月7日 没有评论

I’m using SimpleJSON, and I am kinda new to json.

For some reason, no one on google mentions how to convert objects to json strings. They just all say deserialize json strings, or give you an already made json string. Even SimpleJSON’s documentary doesn’t mention it. Why is that?

This is my code. Does anyone know what is the code to convert stuff to a json string?

[System.Serializable]
public class Skill
{
    public bool crush = false;
    public bool parry = false;
    public bool slam = false;
    public bool magic = false;
    public bool evadeUp = false; 
}

public Skill[] allSkills;

Using Newtonking’s JSON parser you can drag the dll into your Plugins folder and reference it (using Newtonsoft;) from there, it’s one of the best serialisers I’ve seen online, I highly recommend using it:

http://james.newtonking.com/json

You can always serialize and deserialize data, to/from JSON using DataContractJsonSerializer, you can refer to MSDN as reference.

Here is a sample code:

Skill skill = new Skill() { crush = false, parry = false, evadeUp = false, magic = false, slam = false };

string jsonString;
DataContractJsonSerializer ser = new DataContractJsonSerializer(typeof(Skill));
using (MemoryStream memoryStream = new MemoryStream())
{
    ser.WriteObject(memoryStream, skill);
    jsonString = Encoding.UTF8.GetString(memoryStream.ToArray());
}

If you want to serialize Skill[] just create your Array or List, then pass typeof(Skill[]) or typeof(List<Skill>) as input parameter to DataContractJsonSerializer class. The rest will be the same.

PS: I always tend to use standard .NET classes and libraries rather than 3rd party tools.

分类: cocos2d, stackoverflow精选 标签:

How to create snake like body in box2d and cocos2dx?

2014年1月3日 没有评论

I am working on similar to snake. I want to make snake body.

Game logic is that:

Snake move up and down. The moving should be like real snake motion.

Here i am getting struck.

How to make body of the snake?

Any idea or reference should help me lot.

Thanks in advance.

Ok, this is going to be a LONG answer.

I put together a quick example of this using some code from other projects and the “snake” part. You can find the entire (cocos2d-x) codebase here on github.

The easiest (and first) thing to do is to build the snake body. From the Box2D standpoint, you can build it out of a series of segments, each connected by the a revolute joint.

  • You want to start with a single body for the head
  • Then iterate with an offset relative to it, creating the segments so
    that they line up next to each other.
  • While you create each segment, link it to the previous one with a
    revolute joint.
  • When you get near the tail, start tapering down the body height.

Here’s the picture of what we’re going for:

How to create snake like body in box2d and cocos2dx?

Here is the “rough” code I used to create it:

   // Constructor
    MovingEntity(b2World& world,const Vec2& position) :
   Entity(Entity::ET_MISSILE,10),
   _state(ST_IDLE)
   {
      // Create the body.
      b2BodyDef bodyDef;
      bodyDef.position = position;
      bodyDef.type = b2_dynamicBody;
      Body* body = world.CreateBody(&bodyDef);
      assert(body != NULL);
      // Store it in the base.
      Init(body);

      // Now attach fixtures to the body.
      FixtureDef fixtureDef;
      PolygonShape polyShape;
      vector<Vec2> vertices;

      const float32 VERT_SCALE = .5;
      fixtureDef.shape = &polyShape;
      fixtureDef.density = 1.0;
      fixtureDef.friction = 1.0;
      fixtureDef.isSensor = false;

      // Nose
      vertices.clear();
      vertices.push_back(Vec2(4*VERT_SCALE,2*VERT_SCALE));
      vertices.push_back(Vec2(4*VERT_SCALE,-2*VERT_SCALE));
      vertices.push_back(Vec2(8*VERT_SCALE,-0.5*VERT_SCALE));
      vertices.push_back(Vec2(8*VERT_SCALE,0.5*VERT_SCALE));
      polyShape.Set(&vertices[0],vertices.size());
      body->CreateFixture(&fixtureDef);
      body->SetLinearDamping(0.25);
      body->SetAngularDamping(0.25);

      // Main body
      vertices.clear();
      vertices.push_back(Vec2(-4*VERT_SCALE,2*VERT_SCALE));
      vertices.push_back(Vec2(-4*VERT_SCALE,-2*VERT_SCALE));
      vertices.push_back(Vec2(4*VERT_SCALE,-2*VERT_SCALE));
      vertices.push_back(Vec2(4*VERT_SCALE,2*VERT_SCALE));
      polyShape.Set(&vertices[0],vertices.size());
      body->CreateFixture(&fixtureDef);

      // NOW, create several duplicates of the "Main Body" fixture
      // but offset them from the previous one by a fixed amount and
      // overlap them a bit.
      const uint32 SNAKE_SEGMENTS = 4;
      Vec2 offset(-4*VERT_SCALE,0*VERT_SCALE);
      b2Body* pBodyA = body;
      b2Body* pBodyB = NULL;
      b2RevoluteJointDef revJointDef;
      revJointDef.collideConnected = false;

      // Add some "regular segments".
      for(int idx = 0; idx < SNAKE_SEGMENTS; idx++)
      {
         // Create a body for the next segment.
         bodyDef.position = pBodyA->GetPosition() + offset;
         pBodyB = world.CreateBody(&bodyDef);
         _segments.push_back(pBodyB);
         // Add some damping so body parts don't 'flop' around.
         pBodyB->SetLinearDamping(0.25);
         pBodyB->SetAngularDamping(0.25);
         // Offset the vertices for the fixture.
         for(int vidx = 0; vidx < vertices.size(); vidx++)
         {
            vertices[vidx] += offset;
         }
         // and create the fixture.
         polyShape.Set(&vertices[0],vertices.size());
         pBodyB->CreateFixture(&fixtureDef);

         // Create a Revolute Joint at a position half way
         // between the two bodies.
         Vec2 midpoint = (pBodyA->GetPosition() + pBodyB->GetPosition());
         revJointDef.Initialize(pBodyA, pBodyB, midpoint);
         world.CreateJoint(&revJointDef);
         // Update so the next time through the loop, we are
         // connecting the next body to the one we just
         // created.
         pBodyA = pBodyB;
      }
      // Make the next bunch of segments get "smaller" each time
      // to make a tail.
      for(int idx = 0; idx < SNAKE_SEGMENTS; idx++)
      {
         // Create a body for the next segment.
         bodyDef.position = pBodyA->GetPosition() + offset;
         pBodyB = world.CreateBody(&bodyDef);
         _segments.push_back(pBodyB);
         // Add some damping so body parts don't 'flop' around.
         pBodyB->SetLinearDamping(0.25);
         pBodyB->SetAngularDamping(0.25);
         // Offset the vertices for the fixture.
         for(int vidx = 0; vidx < vertices.size(); vidx++)
         {
            vertices[vidx] += offset;
            vertices[vidx].y *= 0.75;
         }
         // and create the fixture.
         polyShape.Set(&vertices[0],vertices.size());
         pBodyB->CreateFixture(&fixtureDef);

         // Create a Revolute Joint at a position half way
         // between the two bodies.
         Vec2 midpoint = (pBodyA->GetPosition() + pBodyB->GetPosition());
         revJointDef.Initialize(pBodyA, pBodyB, midpoint);
         world.CreateJoint(&revJointDef);
         // Update so the next time through the loop, we are
         // connecting the next body to the one we just
         // created.
         pBodyA = pBodyB;
      }
      // Give the tail some real "drag" so that it pulls the
      // body straight when it can.
      pBodyB->SetLinearDamping(1.5);
      pBodyB->SetAngularDamping(1.5);

      // Setup Parameters
      SetMaxAngularAcceleration(4*M_PI);
      // As long as this is high, they forces will be strong
      // enough to get the body close to the target position
      // very quickly so the entity does not "circle" the
      // point.
      SetMaxLinearAcceleration(100);
      SetMaxSpeed(10);
      SetMinSeekDistance(1.0);
   }

This will get you the first part of this, a basic body. Here are some notes about the code:

  1. I added damping to the body and even more to tail so it could be
    dragged around and “pull down” on the rest of the links. This makes
    it look smoother when you drag it.
  2. Adjacent body segments don’t collide but non-adjacent segments will, so the snake
    can “hit” itself. You can choose if other parts should collide or
    not.

NOW, getting the body to move the way you want is a bit more tricky. I’m going to show you a picture (and video) first, so you can see where I got it to. All this is in the code base I referenced, so you can tweak it if you like.

First, here is a screenshot of what the snake looked like after I dragged it around a bit.
How to create snake like body in box2d and cocos2dx?

And I took some video you could see it colliding, slowing, etc. (see it here).

When you see it in motion, it is still not perfect, but I think it looks pretty good for a couple hours of work.

To make the snake move, I took the approach of “dragging” it around by its head. The head rotates towards my finger as I drag it (or you can make it follow a path in code, chase something, etc.) and turns its head towards the target. The rest of the body “drags” along, which gives it an “ok” looking motion.

The controller users two different mechanisms to get the body moving:

Body Direction using Seek Behavior

The body uses a “seek” behavior, which works like this:

Below is the code for the ApplyThrust(…) method of a MovingEntity class.

   void ApplyThrust()
   {
      // Get the distance to the target.
      Vec2 toTarget = GetTargetPos() - GetBody()->GetWorldCenter();
      toTarget.Normalize();
      Vec2 desiredVel = GetMaxSpeed()*toTarget;
      Vec2 currentVel = GetBody()->GetLinearVelocity();
      Vec2 thrust = desiredVel - currentVel;
      GetBody()->ApplyForceToCenter(GetMaxLinearAcceleration()*thrust);
   }

This method applies thrust to make the b2Body move towards a target direction. It has a maximum speed it can travel (GetMaxSpeed()) and a maximum linear acceleration (GetMaxLinearAcceleration()) as properties of the class.

If you follow the code and draw the vectors, you will see that what this does is apply thrust to drive your velocity so it is pointing at the position of the target.

Another way to look at it: It acts like a feedback loop in (in vectors) to keep your velocity matched up with the desired velocity. If you just think about it in terms of scalars, it is a little easier to see.

If you are moving to the right (currentVel) at 5 m/s and your maximum speed (desiredVel) is 6 m/s, the thrust will be positive to the right, pushing you faster to the right (desiredVel – currentVel = +1). That is to say, you will speed up to the right.

If you are moving to the right (currentVel) at 7 m/s and your maximum speed (desiredVel) is 6 m/s, the thrust will be negative, point to the left, slowing you down (desiredVel – currentVel = -1).

From update to update of the physics, this makes your body move in the direction of the target at the speed you want.

In your case, you only want to move left and right and let gravity pull your body down. All of this should work well in the context of the physics. You can control how fast your agent speeds up/slows down by controlling the linear acceleration.

Body Rotation using PID Controller

This is a bit complicated (as if the previous part wasn’t).

The idea is to apply torque to the body based on the difference between the angle you want to go to and the angle your body is facing. A PID controller does using the current angle difference (times a proportional constant), the difference over the recent history (integral), and the rate of change of the difference in the angle (derivative). The first two get the body turning and the last one slows it down as it reaches the target angle.

You can see more details on the theory and implementation here.

All of this is encapsulated into a single class in the code, called PIDController.

NOTE: The PIDController in the code base is generic. It does not know anything about box2d, physics, or what it is being used for. It’s like a sorting algorithm…it only cares about the data it is fed and the parameters you set for how it works. It can easily be used in other contexts…and has for ~100 years.

Hopefully this got you going in the right direction. It may have been a little overkill, but I kind of dig this stuff, so it was fun.

You could start modeling the snake as n aligned bodies (I guess circle shapes would get the best result), and attaching them sequentially with a distance joint.

Assuming that the camera would be the same as the classic snake game, you should also set your world’s gravity to 0, 0.

分类: cocos2d, stackoverflow精选 标签:

双击判断

2014年1月2日 没有评论

方法一:移动也会判断成双击 

onTouchesEnded:function(touches, event) {

        var touchOne =touches[0];
        var str = touchOne.getPreviousLocation().x + "/n" + touchOne.getLocation().x;
        this._logLabel.setString(str);
        if (Math.abs(touchOne.getDelta().x) <=6 && Math.abs(touchOne.getDelta().y) <=6  ) {
            var bigger = cc.ScaleBy.create(3, 2);  //变大
            var smaller = bigger.reverse(); // 恢复
            this._ship.runAction(cc.Sequence.create(bigger,smaller));
        }


    },

 

方法二:仅仅判定双击

onTouchesEnded:function(touches, event) {
        var touchOne =touches[0];

        var str = "原坐标:" + "/n"
            + this._lastTouchPos.x + "/n"
            + this._lastTouchPos.y + "/n"
            + "新坐标:" + "/n"
            + touchOne.getLocation().x + "/n"
            + touchOne.getLocation().y + "/n"
        this._posLabel.setString(str);

        // 有效双击判定,只有距离,没加上双击时间判定
        if (Math.abs(cc.pDistance(touchOne.getLocation(),this._lastTouchPos)) < 20) {
            this.onCaptainSkill(null);
        }
        else {
            this._lastTouchPos = touchOne.getLocation();
        }
    },
    onTouchesMoved:function (touches, event) {
        this._posLabel.setString("移动");
        this._lastTouchPos = cc.p(0,0);
        this.processEvent(touches[0]);
    },

 

分类: cocos2d 标签: