cocos2d-x 调用iOS摄像头 c++ 和 OC混编

来源:互联网 发布:淘宝自动打款时间 编辑:程序博客网 时间:2024/05/29 19:36

这几天在研究cocos2d-x中调用摄像头的功能。


cocos2d-x本身没有这个功能,只能调用原声代码实现。这就涉及到了c++和OC混编码。网上找了好久,都没有什么靠谱的例子。大多数都是下面这种

-(id) init{        if( (self=[super init] )) {                CCMenuItem *menuItem1 = [CCMenuItemImage itemFromNormalImage:@"phone_nor.png"                                                       selectedImage:@"phone_pre.png"                                                              target:self                                                            selector:@selector(getPhoto:)];            CCMenu *menu = [CCMenu menuWithItems:menuItem1,nil];        [menu setPosition(40, 40)];        [self addChild:menu];    }    return self;    }-(void)getPhoto:(UIImagePickerControllerSourceType)sourceType{        UIImagePickerController *picker    = [[UIImagePickerController alloc]init];    picker.delegate = self;    picker.sourceType = UIImagePickerControllerSourceTypeCamera;    picker.wantsFullScreenLayout = YES;    [picker presentModalViewController:picker animated:YES];        [[[CCDirector sharedDirector] openGLView] addSubview:picker.view];}

写的不清不楚。最重要的就是这条

picker.delegate = self;
这个self不是坑爹么。按照我的理解,这个代码绝对是要写到cocos2d的scene或者layer类中。self就是node的子类。怎么可能做代理?????

后来好不容易找到http://www.cnblogs.com/hanhongmin/p/3498102.html这个教程,才算是豁然开朗。

下面详细记录下我的代码。争取让大部分新手也可以看懂


首先看文件结构


注意,这个HelloWorldScene必须是.mm后缀的,因为只有.mm后缀的文件,才可以既写cpp的代码,又写oc的代码

我们主要关注HelloWorldScene和PickerDelegate这两个类


HelloWorldScene.h

#ifndef __HELLOWORLD_SCENE_H__#define __HELLOWORLD_SCENE_H__#include "cocos2d.h"class HelloWorld : public cocos2d::Layer{public:    static cocos2d::Scene* createScene();    virtual bool init();    CREATE_FUNC(HelloWorld);    static void showCamera();};#endif // __HELLOWORLD_SCENE_H__

注意这个showCamera方法,这里面是实现调用摄像头的代码,我尝试过非静态方法,结果报错,不知道为什么,以后有时间研究下。

还有一点。因为是混编。所以很多cocos2d的类,比如Scene和之后的Size等,都要写成cocos2d::Scene的形式。不这么写会怎么样?报错呗。为什么要这么写?这个,亲,你实在太基础了。我教不了你了。回去看看编程入门的书籍吧还是。


PickerDelegate.h

#ifndef RonDemo_PickerDelegate_h#define RonDemo_PickerDelegate_h#import <Foundation/Foundation.h>@interface PickerDelegate : NSObject<UINavigationControllerDelegate,UIImagePickerControllerDelegate>@end#endif

这个就是我们最重要的代理类的头文件了。就像我之前说的那个坑爹的问题
picker.delegate = self;
这个self就可以换成我们的代理类了。注意,代理类继承的可是NSObject,不是cocos2d的Node或者其他什么东西。这样才可以做代理用。

至于

<UINavigationControllerDelegate,UIImagePickerControllerDelegate>
这两个协议是什么?好吧,我承认,我也不知道。反正写不写都正常运行。UINavigationControllerDelegate应该是真的不用。另外一个肯定是跟摄像头有关的代理了。只是目前我仅仅把摄像头调用出来,没做其他事情,所以没有发现而已,后期我会去研究的。


PickerDelegate.m

#import "PickerDelegate.h"@implementation PickerDelegate-(id) init{    if(self = [super init])    {    }    return self;}- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info{    //处理数据    UIImage* image = [info valueForKey:UIImagePickerControllerOriginalImage];        [picker dismissModalViewControllerAnimated: YES];}- (void)imagePickerControllerDidCancel:(UIImagePickerController *)picker{    [picker dismissModalViewControllerAnimated: YES];}@end

这里因为是纯oc代码,所以后缀只用.m就可以了

[picker dismissModalViewControllerAnimated: YES];
这句话的意思是关闭摄像头,否则你会发现照完相,或者点击cancel以后,没有任何反应,摄像头还是打开状态。

UIImage* image = [info valueForKey:UIImagePickerControllerOriginalImage];
至于这句话,照完相总归要保存照片吧?这里就是干这个用了。当然,我这次的代码他实际上没有任何用处。这里只是怕大家不知道照下来的照片怎么获得才保留了。


HelloWorldScene.mm

#if (CC_TARGET_PLATFORM == CC_PLATFORM_IOS)#include "PickerDelegate.h"#endif#include "HelloWorldScene.h"USING_NS_CC;Scene* HelloWorld::createScene(){    auto scene = Scene::create();    auto layer = HelloWorld::create();    scene->addChild(layer);    return scene;}bool HelloWorld::init(){    if ( !Layer::init() )    {        return false;    }        cocos2d::Size visibleSize = Director::getInstance()->getVisibleSize();    Vec2 origin = Director::getInstance()->getVisibleOrigin();        auto listener1 = EventListenerTouchOneByOne::create();    listener1->setSwallowTouches(true);    listener1->onTouchBegan = [](Touch* touch, Event* event){        auto target = static_cast<Sprite*>(event->getCurrentTarget());                cocos2d::Point locationInNode = target->convertToNodeSpace(touch->getLocation());        cocos2d::Size s = target->getContentSize();        cocos2d::Rect rect = cocos2d::Rect(0, 0, s.width, s.height);                if (rect.containsPoint(locationInNode))        {            HelloWorld::showCamera();            return true;        }        return false;    };        Director::getInstance()->getEventDispatcher()->addEventListenerWithSceneGraphPriority(listener1, this);        return true;}void HelloWorld::showCamera() {    CCLOG("have camera");    #if (CC_TARGET_PLATFORM == CC_PLATFORM_IOS)        if([UIImagePickerController isCameraDeviceAvailable:UIImagePickerControllerCameraDeviceFront]) {            NSLog(@"有摄像头");            UIImagePickerController* imagePicker = [[UIImagePickerController alloc] init];            [imagePicker setSourceType:UIImagePickerControllerSourceTypeCamera];                        PickerDelegate* delegate = [[PickerDelegate alloc] init];            imagePicker.delegate = delegate;                        [[UIApplication sharedApplication].keyWindow.rootViewController presentModalViewController:imagePicker animated:YES];        }    #endif}

最重要的一个类了

1˜3行。判断是不是ios设备。如果是的话,则引用我们上面写的代理类


5˜26行。实在没什么说的。都是cocos2d-x的基本用法。


28˜45行。为了偷懒,我直接写的点击当前屏幕,就调用静态方法showCamera()来打开摄像头。


50˜64行。打开摄像头的代码。53行,主要用来判断当前设备是否有摄像头

55行,初始化代码

56行,设置我们要打开摄像头,而不是相册或者其他什么东西

58,59行。这个就是我们的代理了。之前一直就是被这里坑了好久。


61行

UIApplication sharedApplication
用来获取当前设备的句柄

keyWindow网上有好多解释,我觉得最合理的就是“当前活动窗口”

rootViewController顾名思义,根节点视图控制器

presentModalViewController

最后通过模态弹出摄像头,反正我看到的大多数例子,都是这么弹的。


到此,如果没有什么意外的话,运行你的代码点击屏幕,会报错。为什么呢?因为摄像头必须是坑爹的竖屏的。然后不明白的同学百度一下cocos2d-x怎么把ios设备改为竖屏。改好后,运行代码,点击屏幕,此时完美弹出摄像头。

0 0
原创粉丝点击