// // GameScene.cpp // RedCore2 // // Created by Gabriel Capella on 31/05/17. // // #include "GameScene.h" #include "SimpleAudioEngine.h" #include "BlocksLayer.h" #include "Ball.h" #include "params.h" USING_NS_CC; Scene* GameScene::createScene(int level) { auto scene = Scene::createWithPhysics(); Size visibleSize = Director::getInstance()->getVisibleSize(); //choose whitch part need to draw, Joint, Shape, Contact, None or All // scene->getPhysicsWorld()->setDebugDrawMask(PhysicsWorld::DEBUGDRAW_ALL); GameScene* layer = GameScene::create(); scene->addChild(layer); auto material = PHYSICSBODY_MATERIAL_DEFAULT; material.density = 1.0f; material.restitution = 1.0f; material.friction = 0.0f; // the edge of the screen auto body = PhysicsBody::createEdgeBox(visibleSize, material); auto edgeNode = Node::create(); edgeNode->setPosition(Point(visibleSize.width/2,visibleSize.height/2)); body->setDynamic(false); edgeNode->setPhysicsBody(body); scene->addChild(edgeNode); auto blocks = BlocksLayer::create(); blocks->setLevel(level); blocks->setPosition(visibleSize.width/2, visibleSize.height); layer->addChild(blocks, 20); layer->setLevel(level); // inicializa os callbacks dos power ups/downs auto delay_save_level = DelayTime::create(10.0); CallFunc *runCallback_save_level = CallFunc::create(CC_CALLBACK_0(GameScene::saveLevel, layer)); auto seq_save_level = Sequence::create(delay_save_level, runCallback_save_level, nullptr); auto delay_triple_balls = DelayTime::create(10.0); CallFunc *runCallback_triple_balls = CallFunc::create(CC_CALLBACK_0(GameScene::tripleBallsAppearance, layer)); auto seq_triple_balls = Sequence::create(delay_triple_balls, runCallback_triple_balls, nullptr); auto delay_raquete_ball = DelayTime::create(5.0); CallFunc *runCallback_raquete_ball = CallFunc::create(CC_CALLBACK_0(GameScene::raqueteBallAppearance, layer)); auto seq_raquete_ball = Sequence::create(delay_raquete_ball, runCallback_raquete_ball, nullptr); layer->runAction(seq_save_level); layer->runAction(seq_triple_balls); layer->runAction(seq_raquete_ball); return scene; } // on "init" you need to initialize your instance bool GameScene::init() { ////////////////////////////// // 1. super init first if ( !Layer::init() ) { return false; } this->over = false; // https://www.freesound.org/people/schademans/sounds/13290/ FileUtils::getInstance()->addSearchPath("res"); auto audio = CocosDenshion::SimpleAudioEngine::getInstance(); audio->preloadEffect("pipe.wav"); audio->preloadEffect("metal.wav"); audio->preloadEffect("bomb.wav"); audio->preloadEffect("win.wav"); auto visibleSize = Director::getInstance()->getVisibleSize(); Vec2 origin = Director::getInstance()->getVisibleOrigin(); // Adiona o fundo auto bg = LayerColor::create(COLOR_back); this->addChild(bg); auto ball = Ball::create(); ball->setPosition(visibleSize.width / 2, RAQUETE_ALTURA+BALL_SIZE); ball->throwBall(); this->addChild(ball, 21); // Inicialmente tem 1 bola ball_count = 1; raquete = DrawNode::create(); raquete_size = RAQUETE_WIDTH; float py = RAQUETE_HEIGHT/2.0; float pxl = - RAQUETE_WIDTH/2; float pxr = RAQUETE_WIDTH/2; raquete->drawSegment(Vec2(pxl, py), Vec2(pxr, py), py, Color4F(COLOR_grey)); raquete->setPositionX(visibleSize.width/2); raquete->setPositionY(RAQUETE_ALTURA); auto bsize = Size(RAQUETE_WIDTH+RAQUETE_HEIGHT, RAQUETE_HEIGHT); auto physicsBody = PhysicsBody::createBox(bsize, PhysicsMaterial(0.1f, 1.0f, 0.0f)); physicsBody->setPositionOffset(Vec2(0, RAQUETE_HEIGHT/2)); physicsBody->setGravityEnable(false); physicsBody->setDynamic(false); physicsBody->setContactTestBitmask(0xFFFFFFFF); raquete->setTag(RACKET_TAG); raquete->addComponent(physicsBody); this->addChild(raquete); auto listener1 = EventListenerTouchOneByOne::create(); // trigger when you push down listener1->onTouchBegan = [=](Touch* touch, Event* event){ raquete->setPositionX(touch->getLocation().x); float px = touch->getLocation().x; if (px >= RAQUETE_WIDTH/2 && px < visibleSize.width - RAQUETE_WIDTH/2) raquete->setPositionX(touch->getLocation().x); return true; // if you are consuming it }; // trigger when moving touch listener1->onTouchMoved = [=](Touch* touch, Event* event){ float px = touch->getLocation().x; if (px >= RAQUETE_WIDTH/2 && px <= visibleSize.width - RAQUETE_WIDTH/2) raquete->setPositionX(touch->getLocation().x); }; // Add listener _eventDispatcher->addEventListenerWithSceneGraphPriority(listener1, this); // the edge of bottom auto body = PhysicsBody::createEdgeBox(Size(visibleSize.width, 0)); auto edgeNode = Node::create(); edgeNode->setPosition(Point(visibleSize.width/2, 0)); body->setDynamic(false); edgeNode->setTag(BOTTOM_TAG); body->setContactTestBitmask(0xFFFFFFFF); edgeNode->setPhysicsBody(body); this->addChild(edgeNode); // Evento no contato das bolas auto contactListener = EventListenerPhysicsContact::create(); contactListener->onContactBegin = CC_CALLBACK_1(GameScene::onContactBegin, this); _eventDispatcher->addEventListenerWithSceneGraphPriority(contactListener, this); return true; } bool GameScene::onContactBegin(PhysicsContact& contact) { auto nodeA = contact.getShapeA()->getBody()->getNode(); auto nodeB = contact.getShapeB()->getBody()->getNode(); if (nodeA && nodeB && nodeA->getTag() != nodeB->getTag()) { //CCLOG("%d %d", nodeB->getTag(), nodeA->getTag()); if (nodeB->getTag() > nodeA->getTag()) { auto tmp = nodeB; nodeB = nodeA; nodeA = tmp; } // sempre B < A if (nodeB->getTag() == BLOCK_TAG) { auto audio = CocosDenshion::SimpleAudioEngine::getInstance(); audio->playEffect("pipe.wav"); nodeB->removeFromParentAndCleanup(true); } else if (nodeB->getTag() == INDESTRUCTIBLE_BLOCK_TAG) { auto audio = CocosDenshion::SimpleAudioEngine::getInstance(); audio->playEffect("metal.wav"); } else if (nodeB->getTag() == BOTTOM_TAG && nodeA->getTag() == BALL_TAG) { caseBallCollision(nodeA); } else if (nodeB->getTag() == CORE_TAG && nodeA->getTag() == BALL_TAG) { caseBallCore(nodeB, nodeA); } else if (nodeB->getTag() == BALL_TAG && nodeA->getTag() == CORE_TAG) { caseBallCore(nodeA, nodeB); } else if (nodeB->getTag() == SAVE_TAG && nodeA->getTag() == RACKET_TAG) { caseSaveLevel(nodeB); } else if (nodeB->getTag() == THREE_BALLS_TAG && nodeA->getTag() == RACKET_TAG) { caseTripleBalls(nodeB); } else if (nodeB->getTag() == RACKET_BALL_TAG && nodeA->getTag() == RACKET_TAG) { caseRaqueteBall(nodeB); } else if (nodeB->getTag() == SAVE_TAG && nodeA->getTag() == BOTTOM_TAG) { nodeB->removeFromParentAndCleanup(true); } else if (nodeB->getTag() == THREE_BALLS_TAG && nodeA->getTag() == BOTTOM_TAG) { nodeB->removeFromParentAndCleanup(true); } else if (nodeB->getTag() == RACKET_BALL_TAG && nodeA->getTag() == BOTTOM_TAG) { nodeB->removeFromParentAndCleanup(true); } } return true; } void GameScene::caseBallCollision (Node *ball) { // Destrói a bola que tocou o fundo ball_count--; auto audio = CocosDenshion::SimpleAudioEngine::getInstance(); audio->playEffect("bomb.wav"); ParticleSun* m_emitter = ParticleSun::create(); m_emitter->setPosition(ball->getPosition()); m_emitter->setDuration(1); this->getScene()->addChild(m_emitter); ball->removeFromParentAndCleanup(true); if (ball_count == 0) { this->over = true; auto visibleSize = Director::getInstance()->getVisibleSize(); auto text = Label::createWithTTF("Game Over...", "fonts/Marker Felt.ttf", 40); text->setPosition(visibleSize.width/2, visibleSize.height/2); this->addChild(text); UserDefault *userdata = UserDefault::getInstance(); level = userdata->getIntegerForKey("level", 0); auto menu_item_start = MenuItemFont::create("Restart", CC_CALLBACK_1(GameScene::NextLevel, this)); menu_item_start->setPosition(text->getPosition()); menu_item_start->setPositionY(menu_item_start->getPositionY()-50); auto *menu = Menu::create(menu_item_start, NULL); menu->setPosition(Point(0, 0)); this->addChild(menu, 30); } } void GameScene::caseBallCore (Node *core, Node *ball) { auto scaleBy = ScaleBy::create(1.0f, 20.0f); core->getPhysicsBody()->setEnabled(false); core->runAction(scaleBy); auto audio = CocosDenshion::SimpleAudioEngine::getInstance(); audio->playEffect("win.wav"); auto callbackRotate = CallFunc::create([=](){ auto visibleSize = Director::getInstance()->getVisibleSize(); auto menu_item_start = MenuItemFont::create("Next Level", CC_CALLBACK_1(GameScene::NextLevel, this)); menu_item_start->setPosition(Point(visibleSize.width / 2, (visibleSize.height / 2))); auto *menu = Menu::create(menu_item_start, NULL); menu->setPosition(Point(0, 0)); this->addChild(menu, 30); }); // create a sequence with the actions and callbacks auto seq = Sequence::create(scaleBy, callbackRotate, nullptr); core->runAction(seq); ball->removeFromParentAndCleanup(true); } void GameScene::caseSaveLevel(Node *powerup_ball) { if (!this->over) { Size visibleSize = Director::getInstance()->getVisibleSize(); // Salva o nivel! UserDefault *userdata = UserDefault::getInstance(); userdata->setIntegerForKey("level", this->level); userdata->setDoubleForKey("time", (double) time(NULL)); userdata->flush(); auto text = Label::createWithTTF("Level Saved!", "fonts/Marker Felt.ttf", 40); text->setPosition(visibleSize.width/2, visibleSize.height/2); this->addChild(text); text->runAction(FadeOut::create(3)); } powerup_ball->removeFromParentAndCleanup(true); } void GameScene::NextLevel(Ref *pSender) { auto scene = GameScene::createScene(this->level + 1); Director::getInstance()->replaceScene(scene); //Director::getInstance()->end(); } void GameScene::setLevel(int level) { this->level = level; char level_text[256]; sprintf(level_text,"Level %d", this->level); auto text = Label::createWithTTF(level_text, "fonts/Marker Felt.ttf", 30); text->setAnchorPoint(Vec2()); text->setPosition(10, 10); this->addChild(text); } // Power-up: salva o nível atual void GameScene::saveLevel() { if (rand_0_1() < DROP_LEVEL_SAVE && this->over == false){ Size visibleSize = Director::getInstance()->getVisibleSize(); auto ball_draw = DrawNode::create(); ball_draw->drawDot(Vec2(0, 0), BALL_SIZE/3.0, Color4F(COLOR_green)); auto material = PHYSICSBODY_MATERIAL_DEFAULT; material.density = 0.0f; material.restitution = 1.0f; material.friction = 0.0f; //set friction here auto physicsBody = PhysicsBody::createCircle(BALL_SIZE/3.0, material); physicsBody->setGravityEnable(true); physicsBody->setVelocity(Vec2(0,0)); physicsBody->setLinearDamping(0.0); physicsBody->setMass(1.0f); physicsBody->setContactTestBitmask(0xFFFFFFFF); physicsBody->setGroup(-1); ball_draw->addComponent(physicsBody); ball_draw->setTag(SAVE_TAG); ball_draw->setPosition(visibleSize.width * rand_0_1(), visibleSize.height); this->addChild(ball_draw); } auto delay = DelayTime::create(rand_0_1()*10.0+3.0); CallFunc *runCallback = CallFunc::create(CC_CALLBACK_0(GameScene::saveLevel, this)); auto seq = Sequence::create(delay, runCallback, nullptr); this->runAction(seq); } // Power-up: deixa 3 bolas na tela ao invés de 1 void GameScene::tripleBallsAppearance() { if (rand_0_1() < DROP_TRIPLE_BALL && this->over == false){ Size visibleSize = Director::getInstance()->getVisibleSize(); auto ball_draw = DrawNode::create(); ball_draw->drawDot(Vec2(0, 0), BALL_SIZE/3.0, Color4F(COLOR_pink)); auto material = PHYSICSBODY_MATERIAL_DEFAULT; material.density = 0.0f; material.restitution = 1.0f; material.friction = 0.0f; auto physicsBody = PhysicsBody::createCircle(BALL_SIZE/3.0, material); physicsBody->setGravityEnable(true); physicsBody->setVelocity(Vec2(0,0)); physicsBody->setLinearDamping(0.0); physicsBody->setMass(1.0f); physicsBody->setContactTestBitmask(0xFFFFFFFF); physicsBody->setGroup(-1); ball_draw->addComponent(physicsBody); ball_draw->setTag(THREE_BALLS_TAG); ball_draw->setPosition(visibleSize.width * rand_0_1(), visibleSize.height); this->addChild(ball_draw); } auto delay = DelayTime::create(rand_0_1()*10.0); CallFunc *runCallback = CallFunc::create(CC_CALLBACK_0(GameScene::tripleBallsAppearance, this)); auto seq = Sequence::create(delay, runCallback, nullptr); this->runAction(seq); } void GameScene::caseTripleBalls(Node *powerup_ball) { if (!over) { Size visibleSize = Director::getInstance()->getVisibleSize(); auto text = Label::createWithTTF("Triple Balls!", "fonts/Marker Felt.ttf", 40); text->setPosition(visibleSize.width/2, visibleSize.height/2 + 2); this->addChild(text); text->runAction(FadeOut::create(3)); // cria as bolas e as adiciona no cenário for (int i = ball_count; i < 3; i++, ball_count++) { auto ball = Ball::create(); ball->setPosition(raquete->getPositionX(), RAQUETE_ALTURA+BALL_SIZE+i); ball->throwBall(); this->addChild(ball, 21); } } powerup_ball->removeFromParentAndCleanup(true); } void GameScene::raqueteBallAppearance() { if (rand_0_1() < DROP_RACKET_BALL && this->over == false){ Size visibleSize = Director::getInstance()->getVisibleSize(); auto ball_draw = DrawNode::create(); ball_draw->drawDot(Vec2(0, 0), BALL_SIZE/3.0, Color4F(COLOR_blue)); auto material = PHYSICSBODY_MATERIAL_DEFAULT; material.density = 0.0f; material.restitution = 1.0f; material.friction = 0.0f; auto physicsBody = PhysicsBody::createCircle(BALL_SIZE/3.0, material); physicsBody->setGravityEnable(true); physicsBody->setVelocity(Vec2(0,0)); physicsBody->setLinearDamping(0.0); physicsBody->setMass(1.0f); physicsBody->setContactTestBitmask(0xFFFFFFFF); physicsBody->setGroup(-1); ball_draw->addComponent(physicsBody); ball_draw->setTag(RACKET_BALL_TAG); ball_draw->setPosition(visibleSize.width * rand_0_1(), visibleSize.height); this->addChild(ball_draw); } auto delay = DelayTime::create(rand_0_1()*10.0); CallFunc *runCallback = CallFunc::create(CC_CALLBACK_0(GameScene::raqueteBallAppearance, this)); auto seq = Sequence::create(delay, runCallback, nullptr); this->runAction(seq); } /* Power-up/down: 50% de chance de dobrar o tamanho da raquete, e 50% de chance de diminuir seu tamanho pela metade. Para não ficar muito fácil/difícil, impusemos tamanho mínimo/máximo da raquete. */ void GameScene::caseRaqueteBall(Node *powerup_ball) { if (!over) { char power_text[256]; if (rand_0_1() < 0.5) { if (raquete_size <= RAQUETE_WIDTH * 4) { sprintf(power_text, "Doubled racket size!"); raquete_size *= 2; } } else { if (raquete_size >= RAQUETE_WIDTH / 4) { sprintf(power_text, "Doubled racket size!"); raquete_size /= 2; } } Size visibleSize = Director::getInstance()->getVisibleSize(); auto text = Label::createWithTTF(power_text, "fonts/Marker Felt.ttf", 40); text->setPosition(visibleSize.width/2, visibleSize.height/2 + 2); this->addChild(text); text->runAction(FadeOut::create(3)); //cria uma nova raquete e substitui a antiga raquete auto new_raquete = DrawNode::create(); float py = RAQUETE_HEIGHT/2.0; float pxl = - raquete_size/2; float pxr = raquete_size/2; new_raquete->drawSegment(Vec2(pxl, py), Vec2(pxr, py), py, Color4F(COLOR_grey)); new_raquete->setPositionX(raquete->getPositionX()); new_raquete->setPositionY(RAQUETE_ALTURA); auto bsize = Size(raquete_size+RAQUETE_HEIGHT, RAQUETE_HEIGHT); auto physicsBody = PhysicsBody::createBox(bsize, PhysicsMaterial(0.1f, 1.0f, 0.0f)); physicsBody->setPositionOffset(Vec2(0, RAQUETE_HEIGHT/2)); physicsBody->setGravityEnable(false); physicsBody->setDynamic(false); physicsBody->setContactTestBitmask(0xFFFFFFFF); new_raquete->setTag(RACKET_TAG); new_raquete->addComponent(physicsBody); raquete->removeFromParentAndCleanup(true); raquete = new_raquete; this->addChild(raquete); } powerup_ball->removeFromParentAndCleanup(true); }