/******************************************************************** * Nomes: Gabriel Capella Números USP: 8962078 * João Herique Luciano 8535957 * * Tarefa: RedCore - EP2 MAC0463 * Arquivo: GameScene.cpp * Descrição: Implementação do cenário e do mecanismo de jogo ********************************************************************/ #include "GameScene.h" #include "SimpleAudioEngine.h" #include "GameScene/BlocksLayer.h" #include "GameScene/Ball.h" #include "GameScene/Paddle.h" #include "params.h" USING_NS_CC; Scene* GameScene::createScene(int level) { auto scene = Scene::createWithPhysics(); Size visibleSize = Director::getInstance()->getVisibleSize(); #if DEBUG scene->getPhysicsWorld()->setDebugDrawMask(PhysicsWorld::DEBUGDRAW_ALL); #endif GameScene* layer = GameScene::create(); scene->addChild(layer); // parede da tela auto body = PhysicsBody::createEdgeBox(visibleSize, PhysicsMaterial(0.0f, 1.0f, 0.0f)); auto edgeNode = Node::create(); edgeNode->setPosition(Point(visibleSize.width/2,visibleSize.height/2)); body->setDynamic(false); edgeNode->setPhysicsBody(body); scene->addChild(edgeNode); // parede de baixo auto bottom_body = PhysicsBody::createEdgeBox(Size(visibleSize.width, 0)); auto bottomNode = Node::create(); bottomNode->setPosition(Point(visibleSize.width/2, 0)); bottom_body->setDynamic(false); bottomNode->setTag(BOTTOM_TAG); bottom_body->setContactTestBitmask(0xFFFFFFFF); bottomNode->setPhysicsBody(bottom_body); layer->addChild(bottomNode); 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); CallFunc *runCallback_triple_balls = CallFunc::create(CC_CALLBACK_0(GameScene::tripleBallsAppearance, layer)); CallFunc *runCallback_paddle_ball = CallFunc::create(CC_CALLBACK_0(GameScene::paddleBallAppearance, layer)); CallFunc *runCallback_superball = CallFunc::create(CC_CALLBACK_0(GameScene::superBallAppearance, layer)); layer->runAction(seq_save_level); layer->runAction(runCallback_triple_balls); layer->runAction(runCallback_paddle_ball); layer->runAction(runCallback_superball); layer->addAndThrowBall(); return scene; } bool GameScene::init() { // 1. super init first if ( !Layer::init() ) { return false; } over = false; last_touch = time(NULL); 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(); width = visibleSize.width; height = visibleSize.height; Vec2 origin = Director::getInstance()->getVisibleOrigin(); // Adiciona o fundo auto bg = LayerColor::create(COLOR_back); addChild(bg); paddle = Paddle::create(); paddle->setPositionX(width/2); paddle->listen(width); addChild(paddle); // Registra evento de contato de objetos auto contactListener = EventListenerPhysicsContact::create(); contactListener->onContactBegin = CC_CALLBACK_1(GameScene::onContactBegin, this); _eventDispatcher->addEventListenerWithSceneGraphPriority(contactListener, this); balls = Node::create(); addChild(balls, 21); power_ups = Node::create(); addChild(power_ups, 20); return true; } void GameScene::addAndThrowBall() { Ball* ball = Ball::create(); while (paddle->getPositionX() == 0.0); ball->setPosition(paddle->getPositionX(), PADDLE_ALTURA+BALL_SIZE+0.1); ball->throwBall(); balls->addChild(ball, 21); } bool GameScene::onContactBegin(PhysicsContact& contact) { auto nodeA = contact.getShapeA()->getBody()->getNode(); auto nodeB = contact.getShapeB()->getBody()->getNode(); if (nodeA && nodeB && nodeA->getTag() != nodeB->getTag() && !over) { if (nodeB->getTag() > nodeA->getTag()) { auto tmp = nodeB; nodeB = nodeA; nodeA = tmp; } if (nodeA->getTag() == BALL_TAG) { last_touch = time(NULL); } // 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) { if (nodeA->getTag() == BALL_TAG) { Ball* ball = (Ball*) nodeA; if (ball->superball) { nodeB->removeFromParentAndCleanup(true); ball->resetNormalball(); } } 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() == PADDLE_TAG) { caseSaveLevel(nodeB); } else if (nodeB->getTag() == THREE_BALLS_TAG && nodeA->getTag() == PADDLE_TAG) { caseTripleBalls(nodeB); } else if (nodeB->getTag() == SUPERBALL_TAG && nodeA->getTag() == PADDLE_TAG) { caseSuperBall(nodeB); } else if (nodeB->getTag() == PADDLE_BALL_TAG && nodeA->getTag() == PADDLE_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() == PADDLE_BALL_TAG && nodeA->getTag() == BOTTOM_TAG) { nodeB->removeFromParentAndCleanup(true); } else if (nodeB->getTag() == SUPERBALL_TAG && nodeA->getTag() == BOTTOM_TAG) { nodeB->removeFromParentAndCleanup(true); } } return true; } void GameScene::caseBallCollision (Node *ball) { auto audio = CocosDenshion::SimpleAudioEngine::getInstance(); audio->playEffect("bomb.wav"); ParticleSun* m_emitter = ParticleSun::create(); m_emitter->setPosition(ball->getPosition()); m_emitter->setDuration(1); addChild(m_emitter); ball->removeFromParentAndCleanup(true); if (balls->getChildrenCount() == 0) { over = true; removeBallsAndPowersUP (); auto text = Label::createWithTTF(MSG_OVER, FONT, 40); text->setPosition(width/2, height/2); addChild(text); auto menu_item_start = MenuItemFont::create(MSG_RESTART, CC_CALLBACK_1(GameScene::NextLevel, this)); menu_item_start->setFontNameObj(FONT); 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)); 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([=](){ level = level + 1; auto menu_item_start = MenuItemFont::create(MSG_NEXT_LEVEL, CC_CALLBACK_1(GameScene::NextLevel, this)); menu_item_start->setFontNameObj(FONT); menu_item_start->setPosition(Point(width / 2, (height / 2))); auto *menu = Menu::create(menu_item_start, NULL); menu->setPosition(Point(0, 0)); addChild(menu, 30); }); // cria uma sequencia com as ações e callbacks auto seq = Sequence::create(scaleBy, callbackRotate, nullptr); core->runAction(seq); removeBallsAndPowersUP(); } void GameScene::caseSaveLevel(Node *powerup_ball) { UserDefault *userdata = UserDefault::getInstance(); userdata->setIntegerForKey("level", level); userdata->setDoubleForKey("time", (double) time(NULL)); userdata->flush(); alert(MSG_LEVEL_SAVED); powerup_ball->removeFromParentAndCleanup(true); } void GameScene::NextLevel(Ref *pSender) { auto scene = GameScene::createScene(level); Director::getInstance()->replaceScene(scene); } void GameScene::setLevel(int level) { this->level = level; char level_text[256]; sprintf(level_text,"Level %d", level); auto text = Label::createWithTTF(level_text, FONT, 30); text->setAnchorPoint(Vec2()); text->setPosition(10, 10); addChild(text); } void GameScene::saveLevel() { if (over) return; if (rand_0_1() < DROP_LEVEL_SAVE) createPowerUpBody(COLOR_green, SAVE_TAG); delayCallback(CC_CALLBACK_0(GameScene::saveLevel, this)); } void GameScene::tripleBallsAppearance() { if (over) return; double delta = (time(NULL)-last_touch); if (rand_0_1() < delta*DROP_TRIPLE_BALL ){ last_touch = time(NULL); if (balls->getChildrenCount() < 3) createPowerUpBody(COLOR_pink, THREE_BALLS_TAG); } delayCallback(CC_CALLBACK_0(GameScene::tripleBallsAppearance, this)); } void GameScene::caseTripleBalls(Node *powerup_ball) { alert(MSG_TRIPE_BALLS); while (!over && balls->getChildrenCount() < 3) addAndThrowBall(); powerup_ball->removeFromParentAndCleanup(true); } void GameScene::paddleBallAppearance() { if (over) return; if (rand_0_1() < DROP_PADDLE_BALL && over == false) createPowerUpBody(COLOR_blue, PADDLE_BALL_TAG); delayCallback(CC_CALLBACK_0(GameScene::paddleBallAppearance, this)); } void GameScene::casePaddleBall(Node *powerup_ball) { if (!over) { if (rand_0_1() < 0.5) { alert(MSG_DOUBLE_PADDLE); paddle->doubleSize(); } else { alert(MSG_HALF_PADDLE); paddle->halfSize(); } } powerup_ball->removeFromParentAndCleanup(true); } void GameScene::alert(std::string text) { if (!over) { auto display_label = Label::createWithTTF(text, FONT, 40); display_label->setPosition(width/2, height/2); addChild(display_label); display_label->runAction(FadeOut::create(3)); } } void GameScene::superBallAppearance() { if (over) return; if (rand_0_1() < DROP_SUPER_BALL) createPowerUpBody(COLOR_orange, SUPERBALL_TAG); delayCallback(CC_CALLBACK_0(GameScene::superBallAppearance, this)); } void GameScene::caseSuperBall(Node *powerup_ball) { if (over) return; alert(MSG_SUPER_BALL); Vector balls_vector = balls->getChildren(); Ball* ball = (Ball*) balls_vector.at(0); ball->setSuperball(); powerup_ball->removeFromParentAndCleanup(true); } void GameScene::removeBallsAndPowersUP () { balls->removeAllChildrenWithCleanup(true); power_ups->removeAllChildrenWithCleanup(true); paddle->removeFromParentAndCleanup(true); } void GameScene::createPowerUpBody(Color4B color, int tag) { auto ball_draw = DrawNode::create(); ball_draw->drawDot(Vec2(0, 0), BALL_SIZE/3.0, Color4F(color)); auto material = PhysicsMaterial(0.0f, 1.0f, 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(tag); ball_draw->setPosition(width * rand_0_1(), height); power_ups->addChild(ball_draw, 20); } void GameScene::delayCallback(const std::function &func) { auto delta = POWER_UP_INTERVAL/4.0 * rand_minus1_1(); auto delay = DelayTime::create(POWER_UP_INTERVAL+delta); CallFunc *runCallback = CallFunc::create(func); auto seq = Sequence::create(delay, runCallback, nullptr); runAction(seq); }