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

本文介绍了如何在cocos2d-x游戏中使用c++和Objective-C混编调用iOS设备的摄像头。由于cocos2d-x本身不支持此功能,需要借助原生代码实现。通过一个详细的步骤和代码示例,展示了从检查设备、初始化到设置代理的关键过程。需要注意的是,混编中cocos2d的类需以cocos2d::前缀,并确保项目设置允许设备旋转为竖屏,以避免运行时错误。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

这几天在研究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设备改为竖屏。改好后,运行代码,点击屏幕,此时完美弹出摄像头。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值