
新建 win32 程序(可以参照这里),写好自己的代码,假设咱们新建一个类PractiseCocos2d,代码如下:
[cpp] view plain copy print
#ifndef __PRACTISE_COCOS2D_H__
#define __PRACTISE_COCOS2D_H__
#include "cocos2dh"
// 播放声音
#include "SimpleAudioEngineh"
class Practise : public cocos2d::CCLayerColor {
public:
virtual bool init();
static cocos2d::CCScene scene();
void callBack(CCObject pSender);
void menuPushSceneCallBack(CCObject pSender);
void menuReplaceSceneCallBack(CCObject pSender);
void menuPopSceneCallBack(CCObject pSender);
CREATE_FUNC(Practise);// 添加启动的回调函数
void onEnter();
Practise layer;
cocos2d::CCSprite pSprite;
Practise():layer(NULL), pSprite(NULL){};
~Practise();
};
#endif // __PRACTISE_COCOS2D_H__
至于实现就不贴了有点乱 呵呵
然后修改 AppDelegatecpp 中applicationDidFinishLaunching() 方法,修改如下:
至于实现不是特别重要,主要是 scene 方法
[cpp] view plain copy print
CCScene Practise::scene()
{
CCScene scene = CCScene::create();
Practise layer = Practise::create();
// layer->autorelease();
scene->addChild(layer);
return scene;
}
简单来说,如果你想不断去执行某个函数,或者每隔一段时间去执行一次某函数,甚至只执行一次,这时,我们就会用到定时器。比如在游戏开发中每隔一段时间要刷新一些数据,或者要随时间的变化而做一些逻辑判断时,就常常用到定时器。
定时器就是指定时间间隔调用指定的函数,去完成特定的功能。
Cocos2d-x定时器为游戏提供定时事件和定时调用服务。所有的Node对象都知道如何调度和取消调度对象,所以也有人管定时器叫调度器。
二使用定时器有以下几个好处:
1每当Node不再可见或已从场景中移除时,定时器会停止。Cocos2d-x暂停时,定时器也会停止,比如Node被删除或setVisible(false)时与其绑定的定时器会被停止,使用Director的Pause()方法暂停游戏时定时器也会被停止掉;
2当Cocos2d-x重新开始时,定时器也会自动继续启动,如执行Director的Resume()方法时;
3Cocos2d-x封装了一个供各种不同平台使用的定时器,就是说cocos的定时器是跨平台的。
三Cocos2d-x调度器分3种:
默认调度器:scheduleUpdate()
自定义调度器:schedule()
单次调度器:scheduleOnce()
四下面我们就来依次看看这3种调度器是怎么使用的:
一).默认调度器:schedulerUpdate()
默认调度器使用Node的刷新事件update方法,该方法在每帧绘制之前都会被调用一次。
我们在使用默认调度器(schedulerUpdate)时候,需要重载Node的update方法来执行自己的逻辑代码。如果需要停止这个调度器,可以使用unschedulerUpdate()方法。
接下来举个例子来看看默认调度器的具体实现,新建一个cocos工程,我们只在HelloWorldSceneh和HelloWorldScenecpp这两个文件中做修改:
1)首先在头文件HelloWorldSceneh里声明重写的update方法,这个方法就是默认调度器的回调函数:
//声明系统自带的schedule回调函数
virtual void update(float t);
2)在HelloWorldScenecpp文件中实现update方法,可以在该方法中执行我们自己的逻辑代码,这里我只做下打印:
//实现schedule的回调函数
void HelloWorld::update(float t)
{
log("update!");
}
3)通过scheduleUpdate()方法执行调度器,该方法是与其回调方法update()绑定到一起的,也就是说该方法一旦被某个Node执行,该Node的update()方法就会被执行,我把它写在cpp文件的 HelloWorld::init()方法中:
//执行系统调度器
this->scheduleUpdate();
运行结果:
可以看到,执行scheduleUpdate()方法后,update()回调方法会不断执行打印,那么这个update()回调方法多久执行一次呢?前面说了,该方法在每帧绘制之前都会被调用一次,所以理论上在无卡顿情况下每秒执行60次update()方法。
二).自定义调度器:schedule()
顾名思义,该调度器就是我们可以对调度进行相关属性的自定义,比如调度事件触发的时间间隔、触发次数等等。
举个例子:
1)在h文件中声明自定义调度器的回调函数,注意该方法不是系统的而是我们自己写的,所以方法名也是我们自己起的:
//声明自定义调度器回调函数
virtual void customScheduleCallback(float t);
2)在cpp文件中实现刚刚声明的回调函数,这里也只做打印:
//实现回调函数
void HelloWorld::customScheduleCallback(float t)
{
log("customScheduleCallback!");
}
3)通过schedule()方法执行自定义调度器,该方法有4个参数:
schedule(SEL_SCHEDULE selector, float interval, unsigned int repeat, float delay)
参数1:selector为要绑定的回调函数;
参数2:interval为事件触发时间间隔;
参数3:repeat为触发一次事件后还会触发的次数,默认值为kRepeatForever,表示无限触发次数;
参数4:delay表示第一次触发之前的延时。
我还把它写在cpp文件的 HelloWorld::init()方法中:
//执行自定义调度器
this->schedule(schedule_selector(HelloWorld::customScheduleCallback),20,5,3);
运行结果:
注意,第三个参数repeat值为5,表示触发一次事件后还会触发5次,所以一共有6次打印,而且每一次打印输出的时间间隔为2秒。
三).单次调度器:scheduleOnce()
单次调度器只进行一次调度,即只执行一次回调函数。该调度器的使用方法和之前2种调度器基本一致,都是声明回调方法、实现回调方法、使用调度器。
举个例子:
1)在h文件中声明单次调度器的回调函数:
//声明单次调度器回调函数
virtual void onceScheduleCallback(float t);
2)在cpp文件中实现回调函数:
//实现回调函数
void HelloWorld::onceScheduleCallback(float t)
{
log("onceScheduleCallback!");
}
3)通过scheduleOnce()方法执行单次调度器,该方法有2个参数:
参数1:要绑定的回调函数
参数2:第一次触发之前的延时
//执行单次调度器
this->scheduleOnce(schedule_selector(HelloWorld::onceScheduleCallback), 3);
运行结果:
可以看到,程序运行3秒后看到了一次打印输出,之后便不再打印了。
最后,一句话总结,使用调度器无非就是使用3个方法:scheduleUpdate()、schedule()、scheduleOnce(),另外写好需要绑定的回调函数,完事!
以上。
点击阅读全文
打开CSDN,阅读体验更佳
Cocos2d-x中关于schedule函数的一点理解_tsbyj的博客
cocos 2dx---schedule(五) zion--6135的博客 238 bool HelloWorld::init() { // 1 super init first if ( !Scene::init() ) { return false; } printf("1\n"); //this->schedule(CC_SCHEDULE_SELECTOR(HelloWorld::
cocos 2dx-Lua使用schedule定时器_平淡风云的博客_lua sched
使用方法很简单 local scheduler = require("frameworkscheduler") local handler = schedulerscheduleGlobal(function() -- 想做的事情 end, 02) -- 调用间隔 schedulerunscheduleGlobal(handler) -- 取消定时器
cocos2d-x学习笔记(13)--schedule rar
cocos2d-x学习笔记(13)--schedule rar
cocos Creator计时器schedule的使用和坑
在游戏开发中,经常会用到计时器,在cocos引擎中,为我们默认提供了多种计时器的使用。在最新的cocos开发工具Cocos Creator中,我们有4种计时器可以使用,分别是js自带的setTimeOut、interval以及cocos的schedule和scheduleOnce,setTimeOut和scheduleOnce都是执行几次 *** 作,指定一定时间后执行,interval和schedule
继续访问
cocos2dx三种定时器的使用以及停止scheduleUpdate,scheduleOnce,schedule(改)
(Sam: 原文作者有笔误,影响理解,这里做了正确的修改) 首先,什么是定时器呢?或许你有时候会想让某个函数不断的去执行,或许只是执行一次,获取你想让他每隔几秒执行一次,ok,这些都可以统统交给定时器来解决。 cocos2dx中有三种定时器:schedule,scheduleUpdate,scheduleOnce。了解其功能便会发现定时器真是太方便了,废话不多说,我们逐一学习一下。
继续访问
CocosCreator-Schedule计时器-设定及触发原理
计时器 JavaScript自带的定时任务 setTimeout 作用:设置一个定时器,在指定时间(毫秒)后触发,调用传入的回调函数。 参数类型:(function/code, delayTime, args…) function: 回调函数 code: 字符串形式的代码,会使用eval()执行,因此不推荐使
继续访问
cocoscreate使用定时器schedule
这是标题普通对象使用定时器注册定时器注销定时器特殊对象使用定时器注册定时器注销定时器 普通对象使用定时器 注册定时器 // 一般会在节点生命周期里的start函数里注册定时器 start () { // schedule函数注册定时器,第一个参数是回调函数,第二个参数是间隔时间,第三个参数是执行多少次,也可以不写,不写就是不停的执行 thisschedule(thisonTimeFuntion, 1, 6); // 这行代码表示每秒执行一次onTimeFunti
继续访问
最新发布 Cocos Creator 源码解读之Schedule
creator 里面的计时器相信大家不陌生,但是了解它的原理是必要的,它的运行机制和setInterval有什么不同呢, 先简单说说setInterval的原理:setInterval是每隔一段时间向事件队列里面添加回调函数,如果主线程忙的话调用时间不确定特别容易出问题,由于setInterval只负责定时向队列中添加函数,而不考虑函数的执行,setInterval有一个原则:在向队列中添加回调函数时,如果队列中存在之前由其添加的回调函数,就放弃本次添加(不会影响之后的计时),如果主线程忙的话,之前添加的
继续访问
cocos 2dx--------schedule(五)
bool HelloWorld::init() { // 1 super init first if ( !Scene::init() ) { return false; } printf("1\n"); //this->schedule(CC_SCHEDULE_SELECTOR(HelloWorld::fun_Callback), 10f); //每一秒运行依次fun_Callback()函数 //this->sc
继续访问
Cocos2d-x lua 使用定时器
打开一个定时器:schedulerID = ccDirector:getInstance():getScheduler():scheduleScriptFunc(调用的function, 定时时间(秒), 是否暂停(true, false)) 关闭定时器:ccDirector:getInstance():getScheduler():unscheduleScriptEntry(schedul
继续访问
Cocos-2dx lua 定时器
Cocos2dx 3x Lua 中定时器的两种使用方式:(1)self:scheduleUpdateWithPriorityLua(update, priority) > 参数一:刷新函数 > 参数二:刷新优先级 其中 self 为 Node类 的子类。 该方法默认为每帧都刷新一次,无法自定义刷新时间间隔。(2)scheduler:scheduleScriptFunc(update, inteval, false)
继续访问
Cocos2d-x 3x基础学习: 定时器更新schedule/update
大部分游戏中定时器是不可或缺的,因为即每隔一段时间,就要执行相应的刷新体函数,以更新游戏的画面、时间、进度、敌人的指令等等。 Cocos2d-x为我们提供了定时器schedule相关的 *** 作。其 *** 作函数的定义在CCNode中,所以基本上大多数的引擎类都可以设置定时器,如CCLayer、CCSprite、CCMenu等。 定时器更新的方式分为三类: (1)默认定时器 :scheduleUpdate(); (2)自定义定时器:schedule(); (3)一次性定时器:schedu
继续访问
cocos2dx三种定时器的使用以及停止schedule,scheduleUpdate,scheduleOnce
今天白白跟大家分享一下cocos2dx中定时器的使用方法。
继续访问
Cocos Creator 分帧加载(js - schedule)
效果 loadingFramejs ccClass({ extends: ccComponent, properties: { hello: ccPrefab, content: ccNode, mask: ccNode, // animation: ccAnimation, }, onLoad() { thismaskactive = false; // t
继续访问
cocos2dx调度器schedule
cocos2dx调度器schedule Cocos2d-Lua 引擎中的调度器是用来周期执行某个函数或延时执行某个函数的。功能类似于定时触发器,但它又与游戏紧密结合。 schedule调度器利用了timer类来保存了调度任务的 时间线,重复次数,事件间隔,延迟等数据。timer把相关信息以结构体的形式存进了双向链表_hashForTimers中 每帧更新后Timer做事件累加,根据时间线去触发或者取消更新回调。 每帧更新每帧更新
继续访问
Cocos2d-JS下用schedule实现倒计时
Cocos2d-JS下用schedul实现倒计时 前言 本文所记录的内容是在Cocos Code IDE平台完成的,主要是记录一下2048游戏下用schedule实现倒计时。第一次写博客,如有错误望指教。 提示:以下是本篇文章正文内容,下面案例仅供参考 一、schedule是什么? schedule可以每隔几秒执行某个自定义的函数; 而scheduleOnce是在几秒之后才执行,并且只会执行一次。 二、使用步骤 1定义 代码如下(示例): 先在对应的游戏层定义倒计时时间 var GameLayer =
继续访问
cocos定时器分析
注:COCOS分析的版本为34 COCOS的定时器是通过一个哈希表进行保存的,每一帧循环的时候都会调用定时器的update方法,并传入两帧之间的时间间隔 /void Scheduler::update(float dt)/,在update方法中对哈希表进行轮询调用回调函数。 在轮询调用中将定时器分为四种,其中三种是每一帧必定循环调用的方法,struct _listEntry _upda
继续访问
cocos 定时器schedule
1schedule如其名,以指定的时间间隔调用一个指定的函数。系统最小间隔是frame time(即帧间隔),可以由自己设定帧间隔 selector调用分为:自定义函数和update 另外动画(action)类型也会和定时器有关 如下使用方式: [self schedule:@selector(gameLogic:) interval:10] //表示以1秒时间间隔调用函数game
继续访问
Cocos Creator之schedule第一个时间段不执行的解决方法
1、 schedule的官方文档地址。 2、 介绍如下: 指定回调函数,调用对象等信息来添加一个新的定时器。 如果 paused 值为 true,那么直到 resume 被调用才开始计时。 当时间间隔达到指定值时,设置的回调函数将会被调用。 如果 interval 值为 0,那么回调函数每一帧都会被调用,但如果是这样, 建议使用 scheduleUpdateForTarget 代替。 如果回调函
继续访问
爱上cocos2d-x之十六取消定时器unSchedule
懂得如何创建定时器,当然,我们也要懂得如何取消定时器啦。此文章,建立在前两篇的基础上。 (1)取消默认的定时器,只要一句代码 this->unscheduleUpdate(); 备注:不管我们注册update函数时,用的是一个还是两个参数,在取消时都不需要传递参数,只需传递函数就可以了。 (2)取消自定义的定时器 this->unschedule(schedule_sel
void HelloWorld::addTarget(){
CCSize winSize = CCDirector::sharedDirector()->getWinSize();
CCSprite target = CCSprite::create(Targetpng);
//随机位置
int minY = target->getContentSize()height/20;
int maxY = winSizeheight - target->getContentSize()height/20;
int rangeY = maxY - minY;
int actualY = rand()%rangeY + minY;
target->setPosition(ccp(winSizewidth - target->getContentSize()width/20, actualY));
target->setTag(1);
this->addChild(target);
aarayTarget->addObject(target);
//随机速度
float minDuration = 20;
float maxDuration = 40;
int rangeDuration = maxDuration - minDuration;
float actualDuration = rand()%rangeDuration + minDuration;
CCFiniteTimeAction actionMove = CCMoveTo::create(actualDuration, ccp(0 - target->getContentSize()width/20, actualY));//0代表屏幕外,这句表示在3秒内从初始位置移动到屏幕外
//增加一个回调函数,回收移动到屏幕外的精灵
CCFiniteTimeAction actionMoveDone = CCCallFuncN::create(this, callfuncN_selector(HelloWorld::spriteMoveFinished));
target->runAction(CCSequence::create(actionMove,actionMoveDone,NULL));
}
void HelloWorld::spriteMoveFinished(cocos2d::CCNode sender){
CCSprite sprite = (CCSprite )sender;
// this->removeChild(sprite, true);
if (sprite->getTag() == 1) {
aarayTarget->removeObject(sprite);//清除敌人
}else if(sprite->getTag() == 2){
arrayProjectile->removeObject(sprite);//清除飞镖
}
}
//发射飞镖
void HelloWorld::ccTouchesEnded(cocos2d::CCSet touches, cocos2d::CCEvent event){
CCTouch touch = (CCTouch )touches->anyObject();
CCPoint location = touch->getLocationInView();
location = this->convertTouchToNodeSpace(touch);
CCSize winSize = CCDirector::sharedDirector()->getWinSize();
CCSprite projectile = CCSprite::create(Projectilepng);
projectile->setPosition(ccp(20, winSizeheight/2));
float offX = locationx - projectile->getPositionX();
float offY = locationy - projectile->getPositionY();
if (offX <= 0) {
return;
}
projectile->setTag(2);
this->addChild(projectile);
arrayProjectile->addObject(projectile);
float angle = offY/offX;
float realX= winSizewidth + projectile->getContentSize()width/2;
float realY = realX angle + projectile->getPositionY();
CCPoint finalPosition = ccp(realX, realY);
//获取飞镖飞行时间
float length = sqrtf(realX realX + realYrealY);
float velocity = 480;
float realMoveDuration = length/velocity;
projectile->runAction(CCSequence::create(CCMoveTo::create(realMoveDuration, finalPosition),CCCallFuncN::create(this, callfuncN_selector(HelloWorld::spriteMoveFinished)),NULL));
}
//碰撞检测,消除飞镖和敌人
void HelloWorld::update(cocos2d::CCTime dt){
for (int i = 0; i < aarayTarget->count(); i++) {
CCSprite target = (CCSprite )aarayTarget->objectAtIndex(i);
for (int j = 0; j < arrayProjectile->count(); j++) {
CCSprite projectile = (CCSprite )arrayProjectile->objectAtIndex(j);
if (target->boundingBox()intersectsRect(projectile->boundingBox())) {
aarayTarget->removeObjectAtIndex(i);
arrayProjectile->removeObjectAtIndex(j);
this->removeChild(target);
this->removeChild(projectile);
break;
}
}
}
}
void HelloWorld::menuCloseCallback(CCObject pSender)
{
CCDirector::sharedDirector()->end();
#if (CC_TARGET_PLATFORM == CC_PLATFORM_IOS)
exit(0);
#endif
}
raywenderlichcom/zh-hans/21318/%E5%9C%A8cocos2d%E9%87%8C%E9%9D%A2%E5%A6%82%E4%BD%95%E6%8B%96%E6%8B%BD%E7%B2%BE%E7%81%B5Drag and drop these cute pets with Cocos2D!我收到许多读者来信说,能不能写一个教程,关于如何在cocos2d里面使用touch事件来拖拽精灵(sprite)。既然你们这么要求,我就满足你们啦!在这个教程中,你将学到下列内容:使用touch事件拖拽精灵的基本方法如何通过touch事件来滚动视图本身如何方便地计算坐标如何通过识别手势来实现一些更cool的效果! 为了使事件变得有趣,你将要移动一些非常可爱的动画,它是 我可爱的妻子创作的, 背景则是由 gwebstock创建 这个教程假设你已经有一些基本的cocos2d的知识,同时已经安装了一份cocos2d的版本。如果你对cocos2d还不熟悉,你可能需要先学习一下译者翻译的How To Make A Simple iPhone Game with Cocos2D好了,不多说,准备好键盘,开始吧!Getting Started在实现touch事件之前,首先你需要创建一个基本的cocos2d场景来显示背景和这些动物精灵。打开XCode,点击File\New Project,选择 User Templates\cocos2d XXX\cocos2d Application,再点击“Choose…”。把工程命名为“DragDrop”并点击Save。接下来,继续,下载你需要的 下载完后,解压,然后把这些拖到Resources分组下面。确保“ Copy items into destination group’s folder (if needed)”被选中,然后点击Add。在你把导入到工程之后,在Xcode中展开Classes分组,然后选择HelloWorldh。在@interface申明处,像下面所示,申明3个实例变量: CCSprite background; CCSprite selSprite; NSMutableArray movableSprites; 你将使用这些变量才追踪你的背景、当前选中的精灵以及一个在处理touch事件时需要移动的精灵的数组。现在,回到HelloWorldScenem,找到init方法,把它替换成下面的代码: -(id) init { if((self = [super init])) { CGSize winSize = [CCDirector sharedDirector]winSize; [CCTexture2D setDefaultAlphaPixelFormat:kCCTexture2DPixelFormat_RGB565]; background = [CCSprite spriteWithFile:@"blue-shooting-starspng"]; backgroundanchorPoint = ccp(0,0); [self addChild:background]; [CCTexture2D setDefaultAlphaPixelFormat:kCCTexture2DPixelFormat_Default]; movableSprites = [[NSMutableArray alloc] init]; NSArray images = [NSArray arrayWithObjects:@"birdpng", @"catpng", @"dogpng", @"turtlepng", nil]; for(int i = 0; i < imagescount; ++i) { NSString image = [images objectAtIndex:i]; CCSprite sprite = [CCSprite spriteWithFile:image]; float offsetFraction = ((float)(i+1))/(imagescount+1); spriteposition = ccp(winSizewidthoffsetFraction, winSizeheight/2); [self addChild:sprite]; [movableSprites addObject:sprite]; } } return self; } 这里有一些新的知识点需要引入,让我们一步步来学习吧!加载背景这个方法的第一部分加载了一张本场景的背景(blue-shooting-starspng)。注意,这里把的锚点(anchor point)设置成的左下角(0,0)点。在cocos2d里面,当你设置一个精灵的位置的时候,实际上,你设置的是这个精灵的锚点的位置。默认情况下,的锚点就是的中点。因此,通过把精灵锚点设置成左下角,当你设置精灵位置的时候,实际上你就是指定了精灵的中心位置在左下角。这个方法并没有设置背景的位置,因此背景的位置默认情况下是(0,0)。因此,的实际位置就是在(0,0)。(因此设置精灵位置是相对于锚点来的,锚点在左下角,因此的左下角就位于屏幕的左下角)。因此,这个有800个像素宽,那么超过的部分就在屏幕之外了。另外需要注意的一点就是,在加载之前,转换了一下像素格式。在默认情况下,cocos2d里面加载,它们是作为32位的加载进来的。这意味着每个像素占4个字节的内存空间。当你需要非常高质量的显示效果时,非常好!但是,有时候需要折中一下,因为以前的设备内存很有限,如果全部使用32的像素格式来加载的话,会造成内存消耗过多。当你加载大的的时候(比如背景),最佳实践是使用16位的像素格式来加载–也就是牺牲一点质量来减少内存开销。cocos2d里面有很多不同的像素格式 –这个教程中,我们选择16位的像素格式,RGB565,因为背景一般不需要透明效果。(少了Alpha通道,RGBA就是有Alpha通道)加载init方法的另外一部分,就是循环遍历一个数组,然后创建精灵并且计算精灵放置的坐标。这些精灵会一字排开,显示在屏幕上。同时把这些精灵的引用保存在movableSprites数组里面,这个数组后面会使用到。最后,我们需要一些清理内存的 *** 作。找到dealloc方法,然后添加下列代码: [movableSprites release]; movableSprites = nil; 就这么多!编译并运行,你将看到一排非常可爱的小动物,在等待你touch呢!基于touch事件选取精灵现在,我们将编写一些代码基于用户的touch事件来决定哪一个精灵被选到了。第一步,就是激活你的HelloWorldLayer层,让它能够接收touch事件。在init方法的最后添加下列代码: [[CCTouchDispatcher sharedDispatcher] addTargetedDelegate:self priority:0 swallowsTouches:YES]; 注意,这是一种新的方式来激活层的touch事件–老的方式就是,设置层的isTouchEnabled属性为Yes,然后实现ccTouchesBegan方法。如果你非常关心,这个新的方法和旧的方法的优缺点的话,可以参考译者翻译的 《如何使用cocos2d制作基于tiled地图的游戏教程》 接下来,在HelloWorldScenem的底部添加一些新的方法: - (void)selectSpriteForTouch:(CGPoint)touchLocation { CCSprite newSprite = nil; for (CCSprite sprite in movableSprites) { if (CGRectContainsPoint(spriteboundingBox, touchLocation)) { newSprite = sprite; break; } } if (newSprite != selSprite) { [selSprite stopAllActions]; [selSprite runAction:[CCRotateTo actionWithDuration:01 angle:0]]; CCRotateTo rotLeft = [CCRotateBy actionWithDuration:01 angle:-40]; CCRotateTo rotCenter = [CCRotateBy actionWithDuration:01 angle:00]; CCRotateTo rotRight = [CCRotateBy actionWithDuration:01 angle:40]; CCSequence rotSeq = [CCSequence actions:rotLeft, rotCenter, rotRight, rotCenter, nil]; [newSprite runAction:[CCRepeatForever actionWithAction:rotSeq]]; selSprite = newSprite; } } - (BOOL)ccTouchBegan:(UITouch )touch withEvent:(UIEvent )event { CGPoint touchLocation = [self convertTouchToNodeSpace:touch]; [self selectSpriteForTouch:touchLocation]; return TRUE; } 第一个方法(selectSpriteForTouch)是一个帮助方法,这个方法遍历movableSprites数组中的所有精灵,查找第一个精灵位置与touch点位置相交的精灵。注意,CCNode有一个辅助属性叫做boundingBox,它返回精灵的边界矩形。这比你自己手动计算精灵的边界矩形要好多了。因为,第一,它更简单;第二,它考虑了精灵的位置坐标变换。(比如锚点变了,要执行相应的矩阵变换,具体可以参考源代码,这些就不再细说了。)如果找到一个匹配的精灵,那么就让这个精灵执行一些动画,这样用户就知道哪个精灵被选中了。如果动画还没执行完,又选中另一个精灵了,那么就中断前一个精灵的动画。这里的动画效果,使用了一系列的CCAction来实现的。最后,ccTouchBegan方法基于用户的touch事件调用上面的方法。注意,这里把touch坐标点从UIView的坐标系转换成了结点坐标系。为了实现这个目的,通过调用CCNode的一个辅助函数,convertTouchToNodeSpace。这个方法做了以下三件事:计算touch视图(也就是屏幕)的touch点位置(使用locaitonInView方法)转换touch坐标点为OpenGL坐标点(使用convertToGL方法)转换OpenGL坐标系为指定结点的坐标系(使用convertToNodeSpace方法)这是一个非常常用的转换过程,所以提供这个方法可以节约很多时间。编译并运行代码,并且用手触摸这些动物。当你点中一个精灵的时候,它就会以一种非常可爱的方式旋转,表明它被你选中啦!基于touch事件移动精灵和背景层是时候让小动物移动了!基本的思想就是实现ccTouchMoved回调函数,然后计算本次touch点到上一次touch点之间的距离。如果一个动物被选中,将按照计算出来的touch偏移量来移动它。如果动物没有被选中,那就移动整个层,因此用户可以从左至右滚动层。在编写代码之前,让我们花点时间来讨论一下,如何在cocos2d里面滚动一个层。首先,看到下面两张:如你所见,你设置背景锚点在左下角(0,0),前景其它部分就在屏幕之外。黑色框框表示当前可见的区域,也就是屏幕范围。因此,如果你将往右边滚动100个像素,你可以把整个cocos2d的层往左移动100个像素,如第二张图所示。同时,你要确保不会移得太多。比如,你不能够把层往右移动,因为那样左边就是空白的了。现在,你了解了一些背景信息,让我们看看代码怎么写吧!在文件的最后添加下列新的方法: - (CGPoint)boundLayerPos:(CGPoint)newPos { CGSize winSize = [CCDirector sharedDirector]winSize; CGPoint retval = newPos; retvalx = MIN(retvalx, 0); retvalx = MAX(retvalx, -backgroundcontentSizewidth+winSizewidth); retvaly = selfpositiony; return retval; } - (void)panForTranslation:(CGPoint)translation { if (selSprite) { CGPoint newPos = ccpAdd(selSpriteposition, translation); selSpriteposition = newPos; } else { CGPoint newPos = ccpAdd(selfposition, translation); selfposition = [self boundLayerPos:newPos]; } } - (void)ccTouchMoved:(UITouch )touch withEvent:(UIEvent )event { CGPoint touchLocation = [self convertTouchToNodeSpace:touch]; CGPoint oldTouchLocation = [touch previousLocationInView:touchview]; oldTouchLocation = [[CCDirector sharedDirector] convertToGL:oldTouchLocation]; oldTouchLocation = [self convertToNodeSpace:oldTouchLocation]; CGPoint translation = ccpSub(touchLocation, oldTouchLocation); [self panForTranslation:translation]; } 第一个方法(boundLayerPos),用来确保你在滚动层的时候不会超出背景的边界。你传递一个目标点坐标,然后相应地修改x值,保证不会超出边界。如果你不是很理解的话,可以拿出纸和笔,结合上面给出的,自己动手画一画。接来的方法(panForTranslation)基于传入的目标点位置移动精灵(如果有精灵被选中就移动之,否则移动整个层)。具体的做法就是设置精灵或者层的位置。最后一个方法(ccTouchMoved)是一个回调函数,它在你拖动屏幕上的手指时调用。像之前一样,把touch坐标转换成局部node坐标。因为没有一个辅助方法可以把前一个层的touch坐标转换成node坐标,因此,我们需要手工地调用那3个方法来执行这个 *** 作。然后,计算touch偏移量,通过把当前的点坐标减去上一个点坐标,然后调用panForTranslation方法。编译并运行,现在,你可以通过拖拽来移动精灵和层啦!如何在cocos2d里面识别手势这里还有另一种方式来实现刚刚的touch处理–通过使用手势识别!手势识别是新版本的ios sdk增加的内容(iOS SDK 32引入)。说实话,这个功能太棒了!首先,你不再不需写一大堆代码来检测“点击(tap)、双击(double tap)、滑过(swipe)、平移(pan),挤压(pinch)“的区别了。你只需要创建一个手势识别对象,然后把它加到view里面。当有相应的手势发生的时候,会给你一个回调通知。它非常容易使用,在cocos2d里面使用也非常方便。让我们看看它是如何工作的。首先,回到init方法,把注册touch的调用注释掉,因为你将使用一种新的方法: //[[CCTouchDispatcher sharedDispatcher] addTargetedDelegate:self priority:0 swallowsTouches:YES]; 然后,回到DragDropAppDelegatem,找到applicationDidFinishLaunching方法,把最后一行替换掉: CCScene scene = [HelloWorld scene]; HelloWorld layer = (HelloWorld ) [scenechildren objectAtIndex:0]; UIPanGestureRecognizer gestureRecognizer = [[[UIPanGestureRecognizer alloc] initWithTarget:layer action:@selector(handlePanFrom:)] autorelease]; [viewControllerview addGestureRecognizer:gestureRecognizer]; [[CCDirector sharedDirector] runWithScene:scene]; 这段代码获得HelloWorld层的引用(它是HelloWorldScene的唯一孩子节点),然后,创建一个UIPanGestureRecognizer对象。注意,为了创建手势对象,你必须初使化它,并且指定回调函数–在本例中就是handlePanFrom方法。创建完手势识别对象后,你需要把它加入到OpenGL视图中(viewControllerview)。接下来,在HelloWorldScenem底部加入下面的代码: - (void)handlePanFrom:(UIPanGestureRecognizer )recognizer { if (recognizerstate == UIGestureRecognizerStateBegan) { CGPoint touchLocation = [recognizer locationInView:recognizerview]; touchLocation = [[CCDirector sharedDirector] convertToGL:touchLocation]; touchLocation = [self convertToNodeSpace:touchLocation]; [self selectSpriteForTouch:touchLocation]; } else if (recognizerstate == UIGestureRecognizerStateChanged) { CGPoint translation = [recognizer translationInView:recognizerview]; translation = ccp(translationx, -translationy); [self panForTranslation:translation]; [recognizer setTranslation:CGPointZero inView:recognizerview]; } else if (recognizerstate == UIGestureRecognizerStateEnded) { if (!selSprite) { float scrollDuration = 02; CGPoint velocity = [recognizer velocityInView:recognizerview]; CGPoint newPos = ccpAdd(selfposition, ccpMult(velocity, scrollDuration)); newPos = [self boundLayerPos:newPos]; [self stopAllActions]; CCMoveTo moveTo = [CCMoveTo actionWithDuration:scrollDuration position:newPos]; [self runAction:[CCEaseOut actionWithAction:moveTo rate:1]]; } } } 这个回调函数在pan手势开始、变更(用户连续拖拽)和结束的时候被触发。通过判别不同的状态来处理不同的行为。 当手势开始的时候,把touch坐标转换成node坐标,然后调用之前写好的selectSpriteForTouch方法。 当手势变更的时候,需要计算出手势移动偏移量。这里使用手势对象的方法translationInView来获得连续的偏移量。注意,这里需要把y值设置成负值。因为UIKit的坐标和OpenGL坐标系统不一样。(UIKit 左上角是(0,0),而OpenGL左下角的坐标是(0,0)。 之后把recognizer设置为0,因为这个移动是连续的,而我们只需要得到离散的偏移量。 当手势结束的时候,这里有一些新的代码。另一个非常cool的事情就是,你可以通过UIPanGestureRocognizer对象可以得到Pan移动的速度。你可以使用这个速度来滑动层,这个效果就像你使用tableview一样。 因此,这个部分包含一些代码,基于移动的速度来计算移动点。然后运行CCMoveTo action(使用CCEaseOut效果会更好)。 编译并运行代码,你可以通过手势识别来滑动层啦!何去何从这里有本教程的完整源代码到目前为止,你应该知道如何在cocos2d里面使用touch事件来移动精灵了。同时,你也了解了在cocos2d里面如何使用手势识别对象。 现在,你可以尝试扩展本范例,可以使用不同的手势识别对象,比如挤压(pinch)和旋转(rotate)手势识别对象。 如果大家看教程有什么不明白的地方,都可以拿出来,大家一起讨论,共同提高!
欢迎分享,转载请注明来源:内存溢出
微信扫一扫
支付宝扫一扫
评论列表(0条)