jump on sprite touch using box2d - c++

I am new cocos2dx developer.I am using cocos2dx v3.7.1. now i want to jump sprite on touch the sprite.I refer many answer but i am confused.
i implement below code in HelloWorld.cpp file
Scene* HelloWorld::createScene()
{
auto scene = Scene::createWithPhysics();
scene->getPhysicsWorld()->setDebugDrawMask(PhysicsWorld::DEBUGDRAW_ALL);
//scene->getPhysicsWorld()->setGravity(Vec2(0,0.0));
auto layer = HelloWorld::create();
layer->SetPhysicsWorld( scene->getPhysicsWorld() );
scene->addChild(layer);
return scene;
}
// on "init" you need to initialize your instance
bool HelloWorld::init()
{
//////////////////////////////
// 1. super init first
if ( !Layer::init() )
{
return false;
}
auto dispatcher = Director::getInstance()->getEventDispatcher();
auto touchListener = EventListenerTouchOneByOne::create();
touchListener->setSwallowTouches(true);
touchListener->onTouchBegan = CC_CALLBACK_2(HelloWorld::onTouchBegan, this);
touchListener->onTouchEnded = CC_CALLBACK_2(HelloWorld::onTouchEnded, this);
touchListener->onTouchMoved = CC_CALLBACK_2(HelloWorld::onTouchMoved, this);
dispatcher->addEventListenerWithSceneGraphPriority(touchListener, this);
sprite3 = Sprite::create("kartoon.png");
sprite3->setPosition(Point(40,40));
sprite3->setAnchorPoint(Vec2(0,0)); spritibody=PhysicsBody::createBox(sprite3->getContentSize(),PhysicsMaterial(0,1,0));
sprite3->setPhysicsBody( spritibody );
spritibody->setDynamic(true);
this->addChild(sprite3,4);
this->schedule(SEL_SCHEDULE(&HelloWorld::chek),0.01f);
return true;
}
void HelloWorld::chek()
{
if (sprite3->getPosition().y>109) {
yvel-=0.1;
}
else{
if(yvel!=6)
{
xvel=0;
yvel=0;
}
}
sprite3->setPosition(Vec2(sprite3->getPosition().x+xvel,sprite3->getPosition().y+yvel));
}
bool HelloWorld::onTouchBegan(Touch* touch, Event* event)
{
CCLOG("onTouchBegan x = %f, y = %f", touch->getLocation().x, touch->getLocation().y);
auto target = static_cast<Sprite*>(event->getCurrentTarget());
Point locationInNode = target->convertToNodeSpace(touch->getLocation());
if(sprite3->boundingBox().containsPoint(locationInNode))
{
// spritibody->setVelocity(Vec2(2, 0));
spritibody->applyImpulse(Vec2(0,40));
sprite3->setPhysicsBody(spritibody);
spritibody->setGravityEnable(true);
}
return true;
}
In this when i tap on sprite, its jump continous and after some type sprite3 go out off screen.But i want to only jump one time when i tap on sprite3.
plese help me.

Related

cocos2d - collision callback doesn't invoke

I'am trying to build a simple game with a ball and target,
and I want to increse the score when the ball touch the target,
but the callback "onContactBegin" doesnt invoke.
There is a target("goal") in the button of the screen, and when the user touch the screen the ball created and start moving.
#include <string>
#include "HelloWorldScene.h"
#define COCOS2D_DEBUG 1
USING_NS_CC;
enum class PhysicsCategory {
None = 0,
Goal = (1 << 0),
Ball = (1 << 1),
All = PhysicsCategory::Goal | PhysicsCategory::Ball
};
Scene* HelloWorld::createScene()
{
auto scene = Scene::create();
auto layer = HelloWorld::create();
scene->addChild(layer);
return scene;
}
bool HelloWorld::init()
{
CCLOG("Init");
if ( !Layer::init() )
{
return false;
}
Size visibleSize = Director::getInstance()->getVisibleSize();
Point origin = Director::getInstance()->getVisibleOrigin();
height = visibleSize.height;
width = visibleSize.width;
score = 0;
m_score_label = Label::createWithTTF(Itos(score), "fonts/Marker Felt.ttf", 24);
auto vSize = Director::getInstance()->getVisibleSize();
m_score_label->setPosition(Point(origin.x + vSize.width/2,
origin.y + vSize.height - m_score_label->getContentSize().height));
this->addChild(m_score_label, 1);
goal = Sprite::create("images.jpg");
goal->setPosition(Point((visibleSize.width / 2) + origin.x , (visibleSize.height / 6) + origin.y));
auto goalSize = goal->getContentSize();
auto physicsBody = PhysicsBody::createBox(Size(goalSize.width , goalSize.height),
PhysicsMaterial(0.1f, 1.0f, 0.0f));
physicsBody->setCategoryBitmask((int)PhysicsCategory::Goal);
physicsBody->setCollisionBitmask((int)PhysicsCategory::None);
physicsBody->setContactTestBitmask((int)PhysicsCategory::Ball);
goal->setPhysicsBody(physicsBody);
mySprite = Sprite::create("CloseNormal.png");
mySprite->setPosition(Point((visibleSize.width / 2) + origin.x , (visibleSize.height / 2) + origin.y));
this->addChild(mySprite);
this->addChild(goal);
CCScaleBy* action = CCScaleBy::create(3,5);
mySprite->runAction(action);
auto eventListener = EventListenerTouchOneByOne::create();
eventListener->onTouchBegan = CC_CALLBACK_2(HelloWorld::onTouchBegan, this);
this->getEventDispatcher()->addEventListenerWithSceneGraphPriority(eventListener, this);
auto contactListener = EventListenerPhysicsContact::create();
contactListener->onContactBegin = CC_CALLBACK_1(HelloWorld::onContactBegan, this);
this->getEventDispatcher()->addEventListenerWithSceneGraphPriority(contactListener, this);
return true;
}
bool HelloWorld::onTouchBegan(Touch *touch, Event *unused_event) {
cocos2d::Sprite * sp = Sprite::create("CloseNormal.png");
sp->setPosition(Point(touch->getLocation().x , touch->getLocation().y));
MoveTo *action = MoveTo::create(2, Point(width ,0) );
auto ballSize = sp->getContentSize();
auto physicsBody = PhysicsBody::createBox(Size(ballSize.width , ballSize.height),
PhysicsMaterial(0.1f, 1.0f, 0.0f));
physicsBody->setDynamic(true);
physicsBody->setCategoryBitmask((int)PhysicsCategory::Ball);
physicsBody->setCollisionBitmask((int)PhysicsCategory::None);
physicsBody->setContactTestBitmask((int)PhysicsCategory::Goal);
sp->setPhysicsBody(physicsBody);
sp->runAction( action );
this->addChild(sp);
return true;
}
void HelloWorld::menuCloseCallback(Ref* pSender)
{
#if (CC_TARGET_PLATFORM == CC_PLATFORM_WP8) || (CC_TARGET_PLATFORM == CC_PLATFORM_WINRT)
MessageBox("You pressed the close button. Windows Store Apps do not implement a close button.","Alert");
return;
#endif
Director::getInstance()->end();
#if (CC_TARGET_PLATFORM == CC_PLATFORM_IOS)
exit(0);
#endif
}
bool HelloWorld::onContactBegan(PhysicsContact &contact)
{
CCLOG("onContactBegan");
auto nodeA = contact.getShapeA()->getBody()->getNode();
auto nodeB = contact.getShapeB()->getBody()->getNode();
nodeA->removeFromParent();
nodeB->removeFromParent();
++score ;
m_score_label->setString(Itos(score));
return true;
}
std::string HelloWorld::Itos ( int num )
{
std::ostringstream ss;
ss << num;
return ss.str();
}
HelloWorld.cpp
Scene* HelloWorld::createScene() {
auto scene = Scene::createWithPhysics();
auto layer = HelloWorld::create();
layer->setPhysicsWorld(scene->getPhysicsWorld());
scene->getPhysicsWorld()->setDebugDrawMask(PhysicsWorld::DEBUGDRAW_ALL);
scene->addChild(layer);
return scene;
}
bool GameScene::didBeginContact(cocos2d::PhysicsContact &contact) {
PhysicsBody *bodyA = contact.getShapeA()->getBody();
PhysicsBody *bodyB = contact.getShapeB()->getBody();
}
HelloWorld.h
cocos2d::PhysicsWorld *physicsWorld;
void setPhysicsWorld(cocos2d::PhysicsWorld *withWorld) {physicsWorld = withWorld;};
bool didBeginContact(cocos2d::PhysicsContact &contact);

Cocos2d-x 3.2 EventListener not working in child Sprite

Briefly, I have two sprites, one of which is a child of another.
With each sprite related the event listener, as described there.
If both sprites are child nodes of the layer, then everything works great.
Now I need to second sprite is a child node of the first sprite.
But in this case, the second sprite does not respond to events in general.
I'm in a panic and have no idea what's wrong and how to fix it. Please help.
Here's a simplified example:
.h
#ifndef __HELLOWORLD_SCENE_H__
#define __HELLOWORLD_SCENE_H__
#include "cocos2d.h"
class HelloWorld : public cocos2d::Layer
{
public:
// there's no 'id' in cpp, so we recommend returning the class instance pointer
static cocos2d::Scene* createScene();
// Here's a difference. Method 'init' in cocos2d-x returns bool, instead of returning 'id' in cocos2d-iphone
virtual bool init();
// a selector callback
void menuCloseCallback(cocos2d::Ref* pSender);
// implement the "static create()" method manually
CREATE_FUNC(HelloWorld);
};
class PlaySprite : public cocos2d::Sprite
{
public:
virtual bool init();
CREATE_FUNC(PlaySprite);
void addEvent();
bool touchBegan(cocos2d::Touch* touch, cocos2d::Event* event);
};
class InPlaySprite : public cocos2d::Sprite
{
public:
virtual bool init();
CREATE_FUNC(InPlaySprite);
void addEvent();
bool touchBegan(cocos2d::Touch* touch, cocos2d::Event* event);
};
#endif // __HELLOWORLD_SCENE_H__
.cpp
#include "HelloWorldScene.h"
USING_NS_CC;
Scene* HelloWorld::createScene()
{
// 'scene' is an autorelease object
auto scene = Scene::create();
// 'layer' is an autorelease object
auto layer = HelloWorld::create();
// add layer as a child to scene
scene->addChild(layer);
// return the scene
return scene;
}
// on "init" you need to initialize your instance
bool HelloWorld::init()
{
if ( !Layer::init() )
{
return false;
}
Size visibleSize = Director::getInstance()->getVisibleSize();
Vec2 origin = Director::getInstance()->getVisibleOrigin();
// add a "close" icon to exit the progress. it's an autorelease object
auto closeItem = MenuItemImage::create(
"CloseNormal.png",
"CloseSelected.png",
CC_CALLBACK_1(HelloWorld::menuCloseCallback, this));
closeItem->setPosition(Vec2(origin.x + visibleSize.width - closeItem->getContentSize().width/2 ,
origin.y + closeItem->getContentSize().height/2));
auto menu = Menu::create(closeItem, NULL);
menu->setPosition(Vec2::ZERO);
this->addChild(menu, 1);
/////////////////////////////
// 3. add your codes below...
auto sprite1 = PlaySprite::create();
this->addChild(sprite1);
auto sprite2 = InPlaySprite::create();
// !!!
sprite1->addChild(sprite2);
return true;
}
void HelloWorld::menuCloseCallback(Ref* pSender)
{
Director::getInstance()->end();
}
bool PlaySprite::init()
{
if(!Sprite::init())
return false;
// to do
Size visibleSize = Director::getInstance()->getVisibleSize();
this->setTexture("1.png");
this->setPosition(visibleSize.width / 2, visibleSize.height / 2);
this->addEvent();
return true;
}
void PlaySprite::addEvent()
{
auto listener = EventListenerTouchOneByOne::create();
listener->setSwallowTouches(true);
listener->onTouchBegan = [=](Touch* touch, Event* event)
{
return this->touchBegan(touch, event);
};
_eventDispatcher->addEventListenerWithSceneGraphPriority(listener, this);
}
bool PlaySprite::touchBegan(Touch* touch, Event* event)
{
auto target = (Sprite* ) event->getCurrentTarget();
auto rect = this->getBoundingBox();
if(rect.containsPoint(touch->getLocation()))
{
this->setTexture("1d.png");
return true;
}
return false;
}
bool InPlaySprite::init()
{
if(!Sprite::init())
return false;
// to do
Size visibleSize = Director::getInstance()->getVisibleSize();
this->setTexture("2.png");
this->setPosition(150.0f, 150.0f);
this->addEvent();
return true;
}
void InPlaySprite::addEvent()
{
auto listener = EventListenerTouchOneByOne::create();
listener->setSwallowTouches(true);
listener->onTouchBegan = [=](Touch* touch, Event* event)
{
return this->touchBegan(touch, event);
};
_eventDispatcher->addEventListenerWithSceneGraphPriority(listener, this);
}
bool InPlaySprite::touchBegan(Touch* touch, Event* event)
{
// auto target = (Sprite* ) event->getCurrentTarget();
auto rect = this->getBoundingBox();
if(rect.containsPoint(touch->getLocation()))
{
this->setTexture("2d.png");
return true;
}
return false;
}
Classes PlaySprite and InPlaySprite are are very similar because this is a very simplified example.
I think your problem is that you are swallowing touch events in the parent sprite when you call
listener->setSwallowTouches(true);
If you make that call inside of PlaySprite::addEvent() with false instead, I suspect things will work out for you.

Do I need to set addEventListenerWithSceneGraphPriority for each sprite I want to detect?

i want to detect which sprite has been touched.
if I do :
auto listener = EventListenerTouchOneByOne::create();
listener->setSwallowTouches(true);
listener->onTouchBegan = CC_CALLBACK_2(HelloWorld::onTouchBegan, this);
listener->onTouchMoved = CC_CALLBACK_2(HelloWorld::onTouchMoved, this);
listener->onTouchEnded = CC_CALLBACK_2(HelloWorld::onTouchEnded, this);
_eventDispatcher->addEventListenerWithSceneGraphPriority(listener, this);
_eventDispatcher->addEventListenerWithSceneGraphPriority(listener->clone(), mySprite);
and then in my touch method I do:
bool HelloWorld::onTouchBegan(Touch* touch, Event* event)
auto spriteBlock = static_cast<Block*>(event->getCurrentTarget());
the sprite is detected fine.
the problem is I have like 20 sprites on the layer and I need to be able to detect them all
do I need to set
_eventDispatcher->addEventListenerWithSceneGraphPriority(listener->clone(), mySprite);
for each sprite?
No, you do not need add eventListener to all sprites.
You need an event listener for the parent node of the sprites.
Try this:
bool HelloWorld::onTouchBegan(Touch *touch, Event *event) {
Node *parentNode = event->getCurrentTarget();
Vector<Node *> children = parentNode->getChildren();
Point touchPosition = parentNode->convertTouchToNodeSpace(touch);
for (auto iter = children.rbegin(); iter != children.rend(); ++iter) {
Node *childNode = *iter;
if (childNode->getBoundingBox().containsPoint(touchPosition)) {
//childNode is the touched Node
//do the stuff here
return true;
}
}
return false;
}
It is iterate in reverse order because you will touch the sprite with the highest z-index in place (if they overlapping).
Hope, this help.
Yes You have to add an eventlistener to each sprite
and to detect the touches on each
you have to add this in the touch began function
bool OwlStoryScene0::onTouchBegan(cocos2d::Touch *touch, cocos2d::Event *event) {
cocos2d::Touch *touched = (Touch *) touch;
Point location = touched->getLocationInView();
location = Director::getInstance()->convertToGL(location);
auto target = static_cast<Sprite*>(event->getCurrentTarget());
Point locationInNode = target->convertToNodeSpace(touch->getLocation());
Size s = target->getContentSize();
Rect rect = Rect(0, 0, s.width, s.height);
if (rect.containsPoint(locationInNode) && target == SPRITE) {
//DoSomething
}
else if (rect.containsPoint(locationInNode) && target == SPRITE) {
//DoSomething
}
return false;
}
Hope this works for you

cocos2d-x CCControlSlider doesn't slide

i try to follow the cocose2d-x 2.2 Test file :
cocos2d-x-2.2\samples\Cpp\TestCpp\Classes\SchedulerTest\SchedulerTest.h
i implemented the slider control and i see it and the :
virtual bool ccTouchBegan(CCTouch* touch, CCEvent* event);
virtual void ccTouchMoved(CCTouch* touch, CCEvent* event);
virtual void ccTouchEnded(CCTouch* touch, CCEvent* event);
function are triggerd just right when i try to slide
but its not sliding at all this is what i have :
the default close menu is working find :
bool HelloWorld::init()
{
//////////////////////////////
// 1. super init first
if ( !CCLayer::init() )
{
return false;
}
CCSize visibleSize = CCDirector::sharedDirector()->getVisibleSize();
CCPoint origin = CCDirector::sharedDirector()->getVisibleOrigin();
/////////////////////////////
// 2. add a menu item with "X" image, which is clicked to quit the program
// you may modify it.
// add a "close" icon to exit the progress. it's an autorelease object
CCMenuItemImage *pCloseItem = CCMenuItemImage::create(
"CloseNormal.png",
"CloseSelected.png",
this,
menu_selector(HelloWorld::menuCloseCallback));
pCloseItem->setPosition(ccp(origin.x + visibleSize.width - pCloseItem->getContentSize().width/2 ,
origin.y + pCloseItem->getContentSize().height/2));
// create menu, it's an autorelease object
CCMenu* pMenu = CCMenu::create(pCloseItem, NULL);
pMenu->setPosition(CCPointZero);
this->addChild(pMenu, 1);
bSliderCtlTouched = false;
this->setTouchEnabled(true);
this->schedule(schedule_selector(HelloWorld::tick));
return true;
}
void HelloWorld::tick(float dt)
{
;
}
void HelloWorld::onEnter()
{
CCLayer::onEnter();
CCSize s = CCDirector::sharedDirector()->getWinSize();
m_pSliderCtl = sliderCtl();
m_pSliderCtl->retain();
m_pSliderCtl->setPosition(ccp(s.width / 2.0f, s.height - (m_pSliderCtl->getContentSize().height*2)));
this->addChild(m_pSliderCtl,1);
}
CCControlSlider* HelloWorld::sliderCtl()
{
CCControlSlider * slider = CCControlSlider::create("extensions/sliderTrack2.png","extensions/sliderProgress2.png" ,"extensions/sliderThumb.png");
slider->addTargetWithActionForControlEvents(this, cccontrol_selector(HelloWorld::sliderAction), CCControlEventValueChanged);
slider->setMinimumValue(-3.0f);
slider->setMaximumValue(3.0f);
slider->setValue(1.0f);
return slider;
}
void HelloWorld::sliderAction(CCObject* pSender, CCControlEvent controlEvent)
{
bSliderCtlTouched =true;
CCControlSlider* pSliderCtl = (CCControlSlider*)pSender;
float scale;
scale = pSliderCtl->getValue();
}
void HelloWorld::registerWithTouchDispatcher()
{
// higher priority than dragging
CCDirector* pDirector = CCDirector::sharedDirector();
pDirector->getTouchDispatcher()->addTargetedDelegate(this,0, true);
}
bool HelloWorld::ccTouchBegan(CCTouch* touch, CCEvent* event)
{
if(bSliderCtlTouched)
CCLOGWARN("bSliderCtlTouched is true");
CCPoint touchLocation = touch->getLocation();
CCPoint location = convertToNodeSpace( touchLocation );
CCSize screenSize = CCDirector::sharedDirector()->getWinSize();
float screenSizeW = screenSize.width;
//CCLOGWARN("pos: %f,%f -> %f,%f", touchLocation.x, touchLocation.y, location .x, location .y);
b2Vec2 locationWorld = b2Vec2(location.x/PTM_RATIO, location.y/PTM_RATIO);
float halfScreen = screenSize.width/2;
if(location.x <= halfScreen)
{
left = true;
right = false;
}
else
{
left = false;
right = true;
}
#ifdef MOUSEJOINT
return isNodeTouched(locationWorld);
#else
return true;
#endif
}
void HelloWorld::ccTouchMoved(CCTouch* touch, CCEvent* event)
{
if (!bSliderCtlTouched)
{
return;
}
CCPoint touchLocation = touch->getLocation();
CCPoint location = convertToNodeSpace( touchLocation );
b2Vec2 locationWorld = b2Vec2(location.x/PTM_RATIO, location.y/PTM_RATIO);
}
void HelloWorld::ccTouchEnded(CCTouch* touch, CCEvent* event)
{
if(bSliderCtlTouched)
{
bSliderCtlTouched = false;
}
CCPoint touchLocation = touch->getLocation();
CCPoint nodePosition = convertToNodeSpace( touchLocation );
}
As far as your question was unanswered about 7 months, I will answer your question for the new version of cocos2d-x. This code works for cocos2d-x 3.0:
cocos2d::extension::ControlSlider* slider = cocos2d::extension::ControlSlider::create(
"images/buttons/container.png", "images/buttons/progress.png", "images/buttons/knob.png");
slider->setPosition(200, 200);
slider->setMinimumValue(0);
slider->setMaximumValue(10);
slider->setValue(3);
slider->addTargetWithActionForControlEvents(this, cccontrol_selector(IntroView::valueChangedCallback), cocos2d::extension::Control::EventType::VALUE_CHANGED);
addChild(slider);
void IntroView::valueChangedCallback(Ref* sender, cocos2d::extension::Control::EventType evnt)
{
float value = static_cast<cocos2d::extension::ControlSlider*>(sender)->getValue();
CCLOG(std::to_string(value).c_str());
}
Don't forget to #include "GUI/CCControlExtension/CCControlExtensions.h" and use libExtensions in your project.

Cocos2d-x : Convert from CCTime to SEL_SCEDULE error

I'm a beginner that just followed cocos2d-x's native tutorials and I am faced with a huge wall!
This is my error:
>c:\cocos2d-2.0-x-2.0.3\cocos2dsimplegame\classes\helloworldscene.cpp(86): error C2440: 'type cast' : cannot convert from 'void (__thiscall HelloWorld::* )(cocos2d::CCTime)' to 'cocos2d::SEL_SCHEDULE'
>Pointers to members have different representations; cannot cast between them
My cpp file:
#include "HelloWorldScene.h"
using namespace cocos2d;
CCScene* HelloWorld::scene()
{
CCScene * scene = NULL;
do
{
// 'scene' is an autorelease object
scene = CCScene::create();
CC_BREAK_IF(! scene);
// 'layer' is an autorelease object
HelloWorld *layer = HelloWorld::create();
CC_BREAK_IF(! layer);
// add layer as a child to scene
scene->addChild(layer);
} while (0);
// return the scene
return scene;
}
// on "init" you need to initialize your instance
bool HelloWorld::init()
{
bool bRet = false;
_targets = CCArray::create();
_projectiles = CCArray::create();
do {
////////////////////
// super init first
////////////////////
if ( !CCLayerColor::initWithColor( ccc4(255, 255, 255, 255) ) )
{
return false;
}
////////////////////
// add your codes below..
////////////////////
// 1. Add a menu item with "X" image, which is clicked to quit the program.
// Create a "close" menu item with close icon, it's an auto release object.
CCMenuItemImage *pCloseItem = CCMenuItemImage::itemWithNormalImage(
"CloseNormal.png",
"CloseSelected.png",
this,
menu_selector(HelloWorld::menuCloseCallback));
CC_BREAK_IF(! pCloseItem);
// Place the menu item bottom-right conner.
pCloseItem->setPosition(ccp(CCDirector::sharedDirector()->getWinSize().width - 20, 20));
//Create a menu with the "close" menu item, it's an auto release object.
CCMenu* pMenu = CCMenu::menuWithItems(pCloseItem, NULL);
pMenu->setPosition(CCPointZero);
CC_BREAK_IF(! pMenu);
//Add the menu to HelloWorld layer as a child layer.
this->addChild(pMenu, 1);
//////////////////////
// 2. add your codes below...
CCSize winSize = CCDirector::sharedDirector()->getWinSize();
CCSprite *player = CCSprite::spriteWithFile("Player.png", CCRectMake(0, 0, 27, 40));
player->setPosition(ccp(player->getContentSize().width/2, winSize.height/2));
this->addChild(player);
bRet = true;
} while (0);
// Call game logic about every second
this->schedule( schedule_selector(HelloWorld::gameLogic), 1.0);
// You can shoot the bullet
this->setTouchEnabled(true);
this->schedule( schedule_selector(HelloWorld::update) );
return bRet;
}
void HelloWorld::menuCloseCallback(CCObject* pSender)
{
// "close" menu item clicked
CCDirector::sharedDirector()->end();
}
void HelloWorld::addTarget()
{
CCSprite *target = CCSprite::spriteWithFile("Target.png", CCRectMake(0, 0, 27, 40));
// Determine where to spawn the target along the Y axis
CCSize winSize = CCDirector::sharedDirector()->getWinSize();
int minY = target->getContentSize().height/2;
int maxY = winSize.height - target->getContentSize().height/2;
int rangeY = maxY - minY;
// srand( TimGetTicks() );
int actualY = ( rand() % rangeY ) + minY;
// Create the target slightly off-screen along the right edge,
// and along a random position along the Y axis as calculated
target->setPosition( ccp(winSize.width + (target->getContentSize().width/2), actualY) );
this->addChild(target);
// Determine speed of the target
int minDuration = (int)2.0;
int maxDuration = (int)4.0;
int rangeDuration = maxDuration - minDuration;
// srand( TimGetTicks() );
int actualDuration = ( rand() % rangeDuration ) + minDuration;
// Create the actions
CCFiniteTimeAction* actionMove = CCMoveTo::actionWithDuration( (float)actualDuration, ccp(0 - target->getContentSize().width/2, actualY) );
CCFiniteTimeAction* actionMoveDone = CCCallFuncN::actionWithTarget( this, callfuncN_selector(HelloWorld::spriteMoveFinished) );
target->runAction( CCSequence::actions( actionMove, actionMoveDone, NULL) );
// Add to targets array
target->setTag(1);
_targets->addObject(target);
}
void HelloWorld::spriteMoveFinished(CCNode* sender)
{
CCSprite *sprite = (CCSprite *)sender;
this->removeChild(sprite, true);
if (sprite->getTag() == 1) // target
{
_targets->removeObject(sprite);
}
else if (sprite->getTag() == 2) // projectile
{
_projectiles->removeObject(sprite);
}
}
void HelloWorld::gameLogic(float dt)
{
this->addTarget();
}
void HelloWorld::ccTouchesEnded(CCSet* touches, CCEvent* event)
{
// Choose one of the touches to work with
CCTouch* touch = (CCTouch*)( touches->anyObject() );
CCPoint location = touch->locationInView();
location = CCDirector::sharedDirector()->convertToGL(location);
// Set up initial location of projectile
CCSize winSize = CCDirector::sharedDirector()->getWinSize();
CCSprite *projectile = CCSprite::spriteWithFile("Projectile.png", CCRectMake(0, 0, 20, 20));
projectile->setPosition( ccp(20, winSize.height/2) );
// Determine offset of location to projectile
int offX = location.x - projectile->getPosition().x;
int offY = location.y - projectile->getPosition().y;
// Bail out if we are shooting down or backwards
if (offX <= 0) return;
// OK to add now - we've double checked position
this->addChild(projectile);
// Determine where we wish to shoot the projectile to
int realX = winSize.width + (projectile->getContentSize().width/2);
float ratio = (float)offY / (float)offX;
int realY = (realX * ratio) + projectile->getPosition().y;
CCPoint realDest = ccp(realX, realY);
// Determine the length of how far we're shooting
int offRealX = realX - projectile->getPosition().x;
int offRealY = realY - projectile->getPosition().y;
float length = sqrtf((offRealX * offRealX) + (offRealY * offRealY));
float velocity = 480/1; // 480pixels/1sec
float realMoveDuration = length/velocity;
// Move projectile to actual endpoint
projectile->runAction( CCSequence::actions( CCMoveTo::actionWithDuration(realMoveDuration, realDest), CCCallFuncN::actionWithTarget(this, callfuncN_selector(HelloWorld::spriteMoveFinished)), NULL) );
// Add to projectiles array
projectile->setTag(2);
_projectiles->addObject(projectile);
}
void HelloWorld::update(CCTime dt)
{
CCArray *projectilesToDelete = CCArray::create();
CCObject* arrayItem1;
CCARRAY_FOREACH(_projectiles, arrayItem1)
{
CCSprite* projectile = (CCSprite*)arrayItem1;
CCRect projectileRect = CCRectMake(
projectile->getPosition().x - (projectile->getContentSize().width/2),
projectile->getPosition().y - (projectile->getContentSize().height/2),
projectile->getContentSize().width,
projectile->getContentSize().height);
CCArray* targetsToDelete = CCArray::create();
CCObject* arrayItem2;
CCARRAY_FOREACH(_targets, arrayItem2)
{
CCSprite* target = (CCSprite*) arrayItem2;
CCRect targetRect = CCRectMake(
target->getPosition().x - (target->getContentSize().width/2),
target->getPosition().y - (target->getContentSize().height/2),
target->getContentSize().width,
target->getContentSize().height);
if (CCRect::CCRectIntersectsRect(projectileRect, targetRect))
{
targetsToDelete->addObject(target);
}
}
CCARRAY_FOREACH(targetsToDelete, arrayItem2)
{
CCSprite* target = (CCSprite*) arrayItem2;
_targets->removeObject(target);
this->removeChild(target, true);
}
if (targetsToDelete->count() > 0)
{
projectilesToDelete->addObject(projectile);
}
targetsToDelete->release();
}
CCARRAY_FOREACH(projectilesToDelete, arrayItem1)
{
CCSprite* projectile = (CCSprite*) arrayItem1;
_projectiles->removeObject(projectile);
this->removeChild(projectile, true);
}
projectilesToDelete->release();
}
Maybe this part is a problem:
bool HelloWorld::init()
{
....
this->schedule( schedule_selector(HelloWorld::update) );
....
}
But I don't understand why this part is a problem.
Please, help me!
change CCTime to float.
in old cocos2d-x version, they have ccTime instead of CCTime
but in 2.0 they remove it. since it is duplicated with float.