iOS原生App新增cocos2d js游戏模块 实现步骤介绍
作者:单永杰 联系方式:qq(405399323)北京多宝灵动科技有限公司 url 欢迎大家使用铃声多多,
儿歌多多,壁纸多多等一些列多多软件,并提出意见和建议。
-
用语解释:
a. iOS原生App:基于iOS原生框架创建的工程,使用iOS基本UI组件和基于原生组件的自定义组件;
b. js游戏模块:js游戏只是一个模块,作为App的一部分存在于应用中,可以从app进入游戏模块,也可以从游戏
场景退出,回到原生app场景;游戏模块和原生场景 属于同一个进程; -
需求:
a. 游戏模块和原生场景属于同一个进程,可以从原生场景进入游戏场景,也可以从游戏场景退出,进入原生界面;
b. 所有游戏所需资源,包括js游戏文件和资源文件,均为从服务端下载;
c. 原生场景列出 游戏列表,使用这种方式切换,可以不影响原生App其他功能的情况下,畅玩不同的游戏; -
实现步骤:
第一部分:创建并编译工程;
a. 下载 cocos2d js V3.2(勿用之前版本,实现此种需求需修改地方太多)
b. 按照文档安装 cocos2d:执行 setup.py;
c. 使用cocos命令,新建工程;
d. 使用cocos命令,编译iOS平台版本:cocos compile -p ios
第二部分:实现需求;
a. 找到iOS工程文件,位于:cocos_game/frameworks/runtime-src/proj.ios_mac
b. 打开工程,进入我们的正题;修改文件列表: (1) AppDelegate.cpp a. 增加方法:PopView,用于 弹出 游戏场景; b. 增加jsb定义,用于和Objective C代码交互; 代码如下: bool PopView( JSContext *cx, uint32_t argc, jsval *vp){ OcJsInteractive::popGameView(); return 1; } void register_jsb_kenko_all(JSContext* cx, JSObject* obj){ JS_DefineFunction(cx, obj, "JS_POP_GAME", PopView, 0, 0); } OcJsInteractive交互定义: OcJsInteractive.h文件: class OcJsInteractive { public: static void popGameView(); }; OcJsInteractive.mm文件: #import "OcJsInteractive.h" #import "Notification.h" void OcJsInteractive::popGameView(){ postNotificationName:NOTI_QUIT_GAME object:nil]; } c. applicationDidFinishLaunching方法修改: sc->addRegisterCallback(register_jsb_kenko_all);//添加jsb定义,用于退出游戏场景; sc->start(); sc->runScript("script/jsb_boot.js"); sc->setBasePath("");//设置 js文件和资源文件 路径; (2) 修改ScriptingCore类, 增加setBasePath方法; .h文件: void setBasePath(const char* str_search_path); .cpp文件 void ScriptingCore::setBasePath(const char* str_search_path){ cocos2d::FileUtils::getInstance()->addSearchPath(str_search_path); } (3) 修改 CCDirector.cpp,参见 https://github.com/cocos2d/cocos2d-x/pull/9746/files 但是 还有不完善的地方:在 restartDirector()方法结尾,增加代码: startAnimation(); resume(); (4) 增加 MainViewController类,作为启动游戏的界面; 增加 按钮,代码见附件; 修改 RootViewController类,代码见附录; (5) 使用 ZipArchive第三方SDK,用于解压缩 下载下来的 游戏包;
-
注意点:
- project.json: 定义了 cocos引擎的一些参数,诸如帧率等;清空 jsFiles列表,因为下载下来的js
文件是不确定的; - 下载的js包中的 main.js需要修改
require所需要包含的 js文件;切记需要放在 cc.game.onStart函数内部,此时引擎才成功加载起来,
可以保证所有js游戏文件的解析;否则会报诸如:cc.Layer XXXX not defined;
- project.json: 定义了 cocos引擎的一些参数,诸如帧率等;清空 jsFiles列表,因为下载下来的js
-
优缺点解析:
(1)优点就是使用cocos2d js 顺利的解决了开题中的需求
(2)缺点就是:退出游戏时,引擎并没有退出仍然占用内存资源。最理想的就是:能做到需要时成功加载引擎,
不需要时,可以干净的清理,毕竟移动设备上的内存资源还是很宝贵的。 cocos2d js还需加油。最重要的:谢谢panda大神的帮助,欣赏这种热心帮助技术人员解决问题的态度;谢谢顺哥的指点;
-
附录:
MainViewController代码://
// MainViewController.m
// BabyNumber
//
// Created by 单永杰 on 15-1-16.
//
//
#import “MainViewController.h”
#import “AppController.h”
#import “cocos2d.h”
#import “platform/ios/CCEAGLView-ios.h”
#import “ScriptingCore.h”
#import “RootViewController.h”
#import “ZipArchive.h”
static RootViewController* _gameView = nil;
@interface MainViewController (){
}
@end
@implementation MainViewController
-
(id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = ;
if (self) {
// Custom initialization
}
return self;
} -
(void)viewDidLoad
{
;
// Do any additional setup after loading the view.UIButton* btn_game = ;
btn_game.frame = CGRectMake(50, 50, 100, 50);
];
;
[btn_game addTarget:self action:@selector(onBtnClick) forControlEvents:
(UIControlEventTouchUpInside)];
;_gameView = nil;
} -
(void)didReceiveMemoryWarning
{
;
// Dispose of any resources that can be recreated.
} -
(BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)
interfaceOrientation {
return UIInterfaceOrientationIsLandscape( interfaceOrientation );
}
// For ios6, use supportedInterfaceOrientations & shouldAutorotate instead
-
(NSUInteger) supportedInterfaceOrientations{
#ifdef __IPHONE_6_0
return UIInterfaceOrientationMaskAllButUpsideDown;
#endif
} -
(BOOL) shouldAutorotate {
return YES;
}
//fix not hide status on ios7
-
(BOOL)prefersStatusBarHidden
{
return YES;
} -
(void)viewDidUnload {
;
// Release any retained subviews of the main view.
// e.g. self.myOutlet = nil;
} -
(void)dealloc {
;
_gameView = nil;
;
} -
(void)onBtnClick{
/* 解压缩相关代码 /
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
NSURL url_game = ;
NSError* error = nil;
NSData* data = ;
if (!error) {
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSCachesDirectory,
NSUserDomainMask, YES);
NSString *path = ;
NSString zipPath = ;
;
if (!error) {
ZipArchive zip_archive = init];
;
if () {
;dispatch_sync(dispatch_get_main_queue(), ^{ bool first_run = false; if(!cocos2d::Director::getInstance()->getOpenGLView()){ _gameView = initWithNibName:nil bundle:nil]; _gameView.wantsFullScreenLayout = YES; CCEAGLView *__glView = [CCEAGLView viewWithFrame: CGRectMake(0, 0, 1136, 640) pixelFormat: kEAGLColorFormatRGBA8 depthFormat: GL_DEPTH24_STENCIL8_OES //_OES preserveBackbuffer: NO sharegroup: nil multiSampling: NO numberOfSamples: 0 ]; ; [__glView setFrame:CGRectMake(0, 0, .bounds.size.height, .bounds.size.width)]; _gameView.view = __glView; cocos2d::GLView *glview = cocos2d::GLViewImpl:: createWithEAGLView((__bridge void*)__glView); cocos2d::Director::getInstance()->setOpenGLView(glview); first_run = true; } ScriptingCore::getInstance()->setBasePath(); [self presentViewController:_gameView animated:YES completion:^{ if (first_run) { cocos2d::Application::getInstance()->run(); }else { ScriptingCore::getInstance()->setBasePath (); ScriptingCore::getInstance()->reset(); } }]; }); } } }
});
];
}
@end
RootViewController 代码:
/****************************************************************************
Copyright © 2010-2011 cocos2d-x.org
Copyright © 2010 Ricardo Quesada
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the “Software”), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
****************************************************************************/
#import “RootViewController.h”
#import “cocos2d.h”
#import “platform/ios/CCEAGLView-ios.h”
#import “Notification.h”
#import “ScriptingCore.h”
@implementation RootViewController
//Implement viewDidLoad to do additional setup after loading the view, typically
// from a nib.
-
(id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = ;
if (self) {
// Custom initialization
NSLog(@“game view created”);
addObserver:self selector:@selector
(quitGame) name:NOTI_QUIT_GAME object:nil];
}
return self;
} -
(void)viewDidLoad
{
;
// Do any additional setup after loading the view.
setStatusBarHidden:YES];if (UIInterfaceOrientationIsPortrait(self.interfaceOrientation)) {
if ( respondsToSelector:@selector(setOrientation:)]) {
SEL selector = NSSelectorFromString(@“setOrientation:”);
NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:
];
;
];
int val = UIInterfaceOrientationLandscapeRight;
;
;
}
}cocos2d::GLView *glview = cocos2d::Director::getInstance()->getOpenGLView();
if (glview)
{
cocos2d::CCEGLView eaglview = (cocos2d::CCEGLView) glview->getEAGLView();if (eaglview) { CGSize s = .bounds.size; cocos2d::Application::getInstance()->applicationScreenSizeChanged((int) s.width, (int) s.height); }
}
}
#pragma mark
#pragma mark ----- hide status bar & view scape left delegate -
(BOOL) shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)
toInterfaceOrientation{
return UIInterfaceOrientationIsLandscape(toInterfaceOrientation);;
} -
(BOOL) shouldAutorotate{
return NO;
}
// -
(UIInterfaceOrientation)preferredInterfaceOrientationForPresentation{
return UIInterfaceOrientationLandscapeRight;
}
// -
(NSUInteger)supportedInterfaceOrientations{
return UIInterfaceOrientationMaskLandscape;
} -
(void)didRotateFromInterfaceOrientation:(UIInterfaceOrientation)
fromInterfaceOrientation {
;cocos2d::GLView *glview = cocos2d::Director::getInstance()->getOpenGLView();
if (glview)
{
cocos2d::CCEGLView eaglview = (cocos2d::CCEGLView) glview->getEAGLView();if (eaglview) { CGSize s = CGSizeMake(eaglview->getFrameSize().width, eaglview->getFrameSize().height); cocos2d::Application::getInstance()->applicationScreenSizeChanged ((int) s.width, (int) s.height); }
}
}
//fix not hide status on ios7
-
(BOOL)prefersStatusBarHidden
{
return YES;
} -
(void)quitGame{
setStatusBarHidden:NO];
// removeObserver:self];[self dismissViewControllerAnimated:YES completion:^{
cocos2d::Director::getInstance()->pause();
cocos2d::Director::getInstance()->stopAnimation();
NSLog(@“dismiss game view”);
}];
} -
(void)dealloc {
;
}
@end