From d940b8dec834de660af753aad1244b16bc3a32a0 Mon Sep 17 00:00:00 2001 From: Grant-Postma Date: Fri, 17 Jul 2020 11:04:50 -0400 Subject: [PATCH 1/4] Function to CreateRectangle. Function to InitializeAuthenticaionLayer. Function to InitializeLoginLayer. Function to InitializeSignUpLayer. --- demos/TicTacToe/Classes/main_menu_scene.cc | 1436 +++++++++++--------- demos/TicTacToe/Classes/main_menu_scene.h | 61 +- 2 files changed, 864 insertions(+), 633 deletions(-) diff --git a/demos/TicTacToe/Classes/main_menu_scene.cc b/demos/TicTacToe/Classes/main_menu_scene.cc index 58f15e11..06d4d9ad 100644 --- a/demos/TicTacToe/Classes/main_menu_scene.cc +++ b/demos/TicTacToe/Classes/main_menu_scene.cc @@ -17,6 +17,7 @@ #include #include "cocos2d.h" +#include "cocos\ui\UIButton.h" #include "cocos\ui\UITextField.h" #include "firebase/util.h" #include "tic_tac_toe_scene.h" @@ -29,6 +30,9 @@ using cocos2d::Color4F; using cocos2d::DelayTime; using cocos2d::DrawNode; using cocos2d::EventListenerTouchOneByOne; +using cocos2d::Menu; +using cocos2d::MenuItem; +using cocos2d::MenuItemSprite; using cocos2d::RepeatForever; using cocos2d::Scene; using cocos2d::Sequence; @@ -36,7 +40,9 @@ using cocos2d::Size; using cocos2d::TextFieldTTF; using cocos2d::TextHAlignment; using cocos2d::Vec2; +using cocos2d::ui::Button; using cocos2d::ui::TextField; +using cocos2d::ui::Widget; static const char* kCreateGameImage = "create_game.png"; static const char* kTextFieldBorderImage = "text_field_border.png"; @@ -63,49 +69,21 @@ bool MainMenuScene::init() { return false; } - // Call the function to initialize the firebase features. + // Initializes the firebase features. this->InitializeFirebase(); - // Create the background to add all of the authentication elements on. The - // visiblity of this node should match kAuthState, disable any - // touch_listeners when not in this state. - auth_background_ = DrawNode::create(); - auto auth_background_border = DrawNode::create(); + // Initializes the authentication layer by creating the background and placing + // all required cocos2d components. + this->InitializeAuthenticationLayer(); - const auto auth_background_size = Size(500, 550); - const auto auth_background_origin = Size(50, 50); - Vec2 auth_background_corners[4]; - auth_background_corners[0] = - Vec2(auth_background_origin.width, auth_background_origin.height); - auth_background_corners[1] = - Vec2(auth_background_origin.width + auth_background_size.width, - auth_background_origin.height); - auth_background_corners[2] = - Vec2(auth_background_origin.width + auth_background_size.width, - auth_background_origin.height + auth_background_size.height); - auth_background_corners[3] = - Vec2(auth_background_origin.width, - auth_background_origin.height + auth_background_size.height); - - Color4F white(1, 1, 1, 1); - auth_background_->drawPolygon(auth_background_corners, 4, Color4F::BLACK, 1, - Color4F::BLACK); - auth_background_border->drawPolygon(auth_background_corners, 4, - Color4F(0, 0, 0, 0), 1, Color4F::WHITE); - auth_background_->addChild(auth_background_border); - - this->addChild(auth_background_, /*layer_index=*/10); + // Initializes the login layer by creating the background and placing all + // required cocos2d components. + this->InitializeLoginLayer(); - // Label the background as Authentication. - auto auth_label = Label::createWithSystemFont("authentication", "Arial", 48); - auth_label->setPosition(Vec2(300, 550)); - auth_background_->addChild(auth_label); + // Initializes the login layer by creating the background and placing all + // required cocos2d components. - // Label to print out all of the login errors. - invalid_login_label_ = Label::createWithSystemFont("", "Arial", 24); - invalid_login_label_->setTextColor(Color4B::RED); - invalid_login_label_->setPosition(Vec2(300, 220)); - auth_background_->addChild(invalid_login_label_); + this->InitializeSignUpLayer(); // Label to display the users record. user_record_label_ = Label::createWithSystemFont("", "Arial", 24); @@ -114,661 +92,873 @@ bool MainMenuScene::init() { user_record_label_->setPosition(Vec2(500, 600)); this->addChild(user_record_label_); - // Label for anonymous sign in. - auto anonymous_login_label = - Label::createWithSystemFont("anonymous sign-in", "Arial", 18); - anonymous_login_label->setTextColor(Color4B::WHITE); - anonymous_login_label->setPosition(Vec2(460, 75)); + auto join_text_field_position = Size(480, 95); + auto join_text_field_size = Size(180, 80); + auto join_text_field = TextField::create("code", "Arial", 48); + join_text_field->setTextHorizontalAlignment(TextHAlignment::CENTER); + join_text_field->setPosition(join_text_field_position); + join_text_field->setAnchorPoint(Vec2::ANCHOR_MIDDLE); + join_text_field->setTouchSize(join_text_field_size); + join_text_field->setTouchAreaEnabled(true); + join_text_field->setMaxLength(/*max_characters=*/4); + join_text_field->setMaxLengthEnabled(true); + + // Adds the event listener to handle the actions for a textfield. + join_text_field->addEventListener( + [this](Ref* sender, TextField::EventType type) { + auto join_text_field = dynamic_cast(sender); + string join_text_field_string = join_text_field->getString(); + // Transforms the letter casing to uppercase. + std::transform( + join_text_field_string.begin(), join_text_field_string.end(), + join_text_field_string.begin(), + [](unsigned char c) -> unsigned char { return std::toupper(c); }); + // Creates a repeating blink action for the cursor. + switch (type) { + case TextField::EventType::ATTACH_WITH_IME: + // Runs the repeated blinking cursor action. + CreateBlinkingCursorAction(join_text_field); + break; + case TextField::EventType::DETACH_WITH_IME: + // Stops the blinking cursor. + join_text_field->stopAllActions(); + break; + case TextField::EventType::INSERT_TEXT: + join_text_field->setString(join_text_field_string); + break; + default: + break; + } + }); - auto anonymous_label_touch_listener = EventListenerTouchOneByOne::create(); + // Set up the constraints of the border so it surrounds the text box. + const auto pos = join_text_field_position; + const auto size = join_text_field_size; + const Vec2 join_text_border_corners[4] = { + Vec2(pos.width - size.width / 2, pos.height - size.height / 2), + Vec2(pos.width + size.width / 2, pos.height - size.height / 2), + Vec2(pos.width + size.width / 2, pos.height + size.height / 2), + Vec2(pos.width - size.width / 2, pos.height + size.height / 2)}; - anonymous_label_touch_listener->onTouchBegan = - [this](cocos2d::Touch* touch, cocos2d::Event* event) -> bool { - const auto bounds = event->getCurrentTarget()->getBoundingBox(); - const auto point = touch->getLocation(); - if (bounds.containsPoint(point)) { - // Use anonymous sign in for the user. - user_result_ = auth_->SignInAnonymously(); - current_state_ = kWaitingAnonymousState; - } + // Creates a border and adds it around the text field. + auto join_text_field_border = DrawNode::create(); + join_text_field_border->drawPolygon(join_text_border_corners, 4, + Color4F(0, 0, 0, 0), 1, Color4F::WHITE); + this->addChild(join_text_field_border); - return true; - }; + // Creates a sprite for the create button and sets its position to the + // center of the screen. TODO(grantpostma): Dynamically choose the location. + auto create_button = Sprite::create(kCreateGameImage); + create_button->setPosition(25, 200); + create_button->setAnchorPoint(Vec2(0, 0)); - // Attach the touch listener to the text field. - Director::getInstance() - ->getEventDispatcher() - ->addEventListenerWithSceneGraphPriority(anonymous_label_touch_listener, - anonymous_login_label); - auth_background_->addChild(anonymous_login_label); - - // Extract the origin, size and position of the text field so that the - // border can be created based on those values. - const auto email_text_field_origin = Vec2(0, 0); - const auto email_text_field_position = Size(110, 350); - const auto text_field_padding = 20; - const auto email_font_size = 36.0; - const auto email_text_field_size = Size(400, 2 * email_font_size); + // Creates a button listener to handle the touch event. + auto create_button_touch_listener = EventListenerTouchOneByOne::create(); - // Set up the constraints of the border so it surrounds the text box. - Vec2 email_border_corners[4] = { - Vec2(email_text_field_position.width - text_field_padding, - email_text_field_position.height), - Vec2(email_text_field_position.width + email_text_field_size.width, - email_text_field_position.height), - Vec2(email_text_field_position.width + email_text_field_size.width, - email_text_field_position.height + email_text_field_size.height), - Vec2(email_text_field_position.width - text_field_padding, - email_text_field_position.height + email_text_field_size.height)}; - - // Creates border and adds it around the text field. - auto email_text_field_border = DrawNode::create(); - email_text_field_border->drawPolygon(email_border_corners, 4, - Color4F(0, 0, 0, 0), 1, Color4F::WHITE); - - // Creates a text field to enter the user's email. - email_text_field_ = cocos2d::TextFieldTTF::textFieldWithPlaceHolder( - "enter an email address", email_text_field_size, TextHAlignment::LEFT, - "Arial", email_font_size); - email_text_field_->setPosition(email_text_field_position); - email_text_field_->setAnchorPoint(Vec2(0, 0)); - email_text_field_->setColorSpaceHolder(Color3B::GRAY); - email_text_field_->setDelegate(this); - - auto email_text_field_touch_listener = EventListenerTouchOneByOne::create(); - - email_text_field_touch_listener->onTouchBegan = - [this](cocos2d::Touch* touch, cocos2d::Event* event) -> bool { + // Set the onTouchBegan event up to a lambda tha will replace the + // MainMenu scene with a TicTacToe scene. + create_button_touch_listener->onTouchBegan = + [this, join_text_field](Touch* touch, Event* event) -> bool { const auto bounds = event->getCurrentTarget()->getBoundingBox(); const auto point = touch->getLocation(); + + // Replaces the scene with a new TicTacToe scene if the touched point is + // within the bounds of the button. if (bounds.containsPoint(point)) { - // Show the on screen keyboard and places character inputs into the text - // field. - auto text_field = dynamic_cast(event->getCurrentTarget()); - text_field->setCursorEnabled(true); - text_field->attachWithIME(); - } else { - auto text_field = dynamic_cast(event->getCurrentTarget()); - text_field->setCursorEnabled(false); - text_field->detachWithIME(); + Director::getInstance()->pushScene( + TicTacToe::createScene(std::string(), database_, user_uid_)); + join_text_field->setString(""); + current_state_ = kWaitingGameOutcome; } return true; }; - // Attach the touch listener to the text field. + // Attach the touch listener to the create game button. Director::getInstance() ->getEventDispatcher() - ->addEventListenerWithSceneGraphPriority(email_text_field_touch_listener, - email_text_field_); + ->addEventListenerWithSceneGraphPriority(create_button_touch_listener, + create_button); - auth_background_->addChild(email_text_field_, /*layer_index=*/1); - auth_background_->addChild(email_text_field_border, /*layer_index=*/1); + // Creates a sprite for the logout button and sets its position to the + auto logout_button = Sprite::create(kLogoutButtonImage); + logout_button->setPosition(25, 575); + logout_button->setAnchorPoint(Vec2(0, 0)); + logout_button->setContentSize(Size(125, 50)); - // Extract the origin, size and position of the text field so that the - // border can be created based on those values. - const auto password_text_field_origin = Vec2(0, 0); - const auto password_text_field_position = Size(110, 250); - const auto password_font_size = 36.0; - const auto password_text_field_size = Size(400, 2 * password_font_size); - - // Set up the constraints of the border so it surrounds the text box. - Vec2 password_border_corners[4] = { - Vec2(password_text_field_position.width - text_field_padding, - password_text_field_position.height), - Vec2(password_text_field_position.width + password_text_field_size.width, - password_text_field_position.height), - Vec2(password_text_field_position.width + password_text_field_size.width, - password_text_field_position.height + - password_text_field_size.height), - Vec2(password_text_field_position.width - text_field_padding, - password_text_field_position.height + - password_text_field_size.height)}; + // Creates a button listener to handle the touch event. + auto logout_button_touch_listener = EventListenerTouchOneByOne::create(); - // Creates a border and adds it around the text field. - auto password_text_field_border = DrawNode::create(); - password_text_field_border->drawPolygon( - password_border_corners, 4, Color4F(0, 0, 0, 0), 1, Color4F::WHITE); - - // Creates a text field to enter the user's password. - password_text_field_ = cocos2d::TextFieldTTF::textFieldWithPlaceHolder( - "enter a password", password_text_field_size, TextHAlignment::LEFT, - "Arial", password_font_size); - password_text_field_->setPosition(password_text_field_position); - password_text_field_->setAnchorPoint(Vec2(0, 0)); - password_text_field_->setColorSpaceHolder(Color3B::GRAY); - password_text_field_->setSecureTextEntry(true); - password_text_field_->setDelegate(this); - - auto password_text_field_touch_listener = - EventListenerTouchOneByOne::create(); - - password_text_field_touch_listener->onTouchBegan = - [this](cocos2d::Touch* touch, cocos2d::Event* event) -> bool { + // Set the onTouchBegan event up to a lambda tha will replace the + // MainMenu scene with a TicTacToe scene. + logout_button_touch_listener->onTouchBegan = [this](Touch* touch, + Event* event) -> bool { const auto bounds = event->getCurrentTarget()->getBoundingBox(); const auto point = touch->getLocation(); + + // Replaces the scene with a new TicTacToe scene if the touched point is + // within the bounds of the button. if (bounds.containsPoint(point)) { - // Shows the on screen keyboard and places character inputs into the text - // field. - auto text_field = dynamic_cast(event->getCurrentTarget()); - text_field->setCursorEnabled(true); - text_field->attachWithIME(); - } else { - auto text_field = dynamic_cast(event->getCurrentTarget()); - text_field->setCursorEnabled(false); - text_field->detachWithIME(); + current_state_ = kAuthMenuState; + user_uid_ = ""; + user_ = nullptr; + user_record_label_->setString(""); } return true; }; - auth_background_->addChild(password_text_field_, /*layer_index=*/1); - auth_background_->addChild(password_text_field_border, /*layer_index=*/1); - - // Attach the touch listener to the text field. + // Attach the touch listener to the logout game button. Director::getInstance() ->getEventDispatcher() - ->addEventListenerWithSceneGraphPriority( - password_text_field_touch_listener, password_text_field_); + ->addEventListenerWithSceneGraphPriority(logout_button_touch_listener, + logout_button); - // Creates the login button and give it a position, anchor point and - // touch_listener. - auto login_button = Sprite::create(kLoginButtonImage); - login_button->setPosition(90, 120); - login_button->setAnchorPoint(Vec2(0, 0)); - login_button->setContentSize(Size(200, 75)); + // Creates a sprite for the join button and sets its position to the center + // of the screen. TODO(grantpostma): Dynamically choose the location and set + // size(). + auto join_button = Sprite::create(kJoinButtonImage); + join_button->setPosition(25, 50); + join_button->setAnchorPoint(Vec2(0, 0)); + join_button->setScale(1.3f); // Creates a button listener to handle the touch event. - auto login_button_touch_listener = EventListenerTouchOneByOne::create(); + auto join_button_touch_listener = EventListenerTouchOneByOne::create(); - // Transition from kAuthState to kWaitingLoginState on button press and set - // user_result_ to SignInWithEmailAndPassword future result. - login_button_touch_listener->onTouchBegan = [this](Touch* touch, - Event* event) -> bool { + // Set the onTouchBegan event up to a lambda tha will replace the + // MainMenu scene with a TicTacToe scene and pass in join_text_field string. + join_button_touch_listener->onTouchBegan = + [join_text_field, this](Touch* touch, Event* event) -> bool { const auto bounds = event->getCurrentTarget()->getBoundingBox(); const auto point = touch->getLocation(); if (bounds.containsPoint(point)) { - // Check the string for a valid email pattern. - if (!std::regex_match(email_text_field_->getString(), email_pattern)) { - invalid_login_label_->setString("invalid email address"); - } else if (password_text_field_->getString().length() < 8) { - invalid_login_label_->setString( - "password must be at least 8 characters long"); + // Get the string from join_text_field. + std::string join_text_field_string = join_text_field->getString(); + if (join_text_field_string.length() == 4) { + Director::getInstance()->pushScene(TicTacToe::createScene( + join_text_field_string, database_, user_uid_)); + current_state_ = kWaitingGameOutcome; + join_text_field->setString(""); } else { - user_result_ = auth_->SignInWithEmailAndPassword( - email_text_field_->getString().c_str(), - password_text_field_->getString().c_str()); - current_state_ = kWaitingLoginState; + join_text_field->setString(""); } } return true; }; - // Attach the touch listener to the login button. + // Attach the touch listener to the join button. Director::getInstance() ->getEventDispatcher() - ->addEventListenerWithSceneGraphPriority(login_button_touch_listener, - login_button); - auth_background_->addChild(login_button, /*layer_index=*/1); + ->addEventListenerWithSceneGraphPriority(join_button_touch_listener, + join_button); - // Creates the sign_up button and give it a position, anchor point and - // touch_listener. - auto sign_up_button = Sprite::create(kSignUpButtonImage); - sign_up_button->setPosition(310, 120); - sign_up_button->setAnchorPoint(Vec2(0, 0)); - sign_up_button->setContentSize(Size(200, 75)); + // Attach the create button, join button and join text field to the + // MainMenu scene. + this->addChild(create_button); + this->addChild(join_button); + this->addChild(logout_button); + this->addChild(join_text_field, /*layer_index=*/1); - // Creates a button listener to handle the touch event. - auto sign_up_button_touch_listener = EventListenerTouchOneByOne::create(); + this->scheduleUpdate(); - // Transition from kAuthState to kWaitingSignUpState on button press and set - // user_result_ to CreateUserWithEmailAndPassword future result. - sign_up_button_touch_listener->onTouchBegan = [this](Touch* touch, - Event* event) -> bool { - const auto bounds = event->getCurrentTarget()->getBoundingBox(); - const auto point = touch->getLocation(); - if (bounds.containsPoint(point)) { - // Check the string for a valid email pattern. - if (!std::regex_match(email_text_field_->getString(), email_pattern)) { - invalid_login_label_->setString("invalid email address"); - } else if (password_text_field_->getString().length() < 8) { - invalid_login_label_->setString( - "password must be at least 8 characters long"); - } else { - user_result_ = auth_->CreateUserWithEmailAndPassword( - email_text_field_->getString().c_str(), - password_text_field_->getString().c_str()); - current_state_ = kWaitingSignUpState; - } - } - return true; - }; + return true; +} - // Attach the touch listener to the sign_up button. - Director::getInstance() - ->getEventDispatcher() - ->addEventListenerWithSceneGraphPriority(sign_up_button_touch_listener, - sign_up_button); - auth_background_->addChild(sign_up_button, /*layer_index=*/1); - - // Creates, sets the position and assigns a placeholder to the text - // field for the user to enter the join game uuid. - TextFieldTTF* join_text_field = - cocos2d::TextFieldTTF::textFieldWithPlaceHolder( - "code", cocos2d::Size(200, 100), TextHAlignment::LEFT, "Arial", 55.0); - join_text_field->setPosition(420, 45); - join_text_field->setAnchorPoint(Vec2(0, 0)); - join_text_field->setColorSpaceHolder(Color3B::WHITE); - join_text_field->setDelegate(this); - - auto join_text_field_border = Sprite::create(kTextFieldBorderImage); - join_text_field_border->setPosition(390, 50); - join_text_field_border->setAnchorPoint(Vec2(0, 0)); - join_text_field_border->setScale(.53f); - this->addChild(join_text_field_border, /*layer_index=*/0); - - // Create a touch listener to handle the touch event. - auto join_text_field_touch_listener = EventListenerTouchOneByOne::create(); - - join_text_field_touch_listener->onTouchBegan = - [join_text_field, this](cocos2d::Touch* touch, - cocos2d::Event* event) -> bool { - const auto bounds = event->getCurrentTarget()->getBoundingBox(); - const auto point = touch->getLocation(); - if (bounds.containsPoint(point)) { - // Show the on screen keyboard and places character inputs into the text - // field. - auto str = join_text_field->getString(); - auto text_field = dynamic_cast(event->getCurrentTarget()); - text_field->setCursorEnabled(true); - text_field->attachWithIME(); - } else { - auto text_field = dynamic_cast(event->getCurrentTarget()); - text_field->setCursorEnabled(false); - text_field->detachWithIME(); - } +// Initialize the firebase auth and database while also ensuring no +// dependencies are missing. +void MainMenuScene::InitializeFirebase() { + LogMessage("Initialize Firebase App."); + ::firebase::App* app; - auto join_text_field_position = Size(480, 95); - auto join_text_field_size = Size(180, 80); - auto join_text_field = TextField::create("code", "Arial", 48); - join_text_field->setTextHorizontalAlignment(TextHAlignment::CENTER); - join_text_field->setPosition(join_text_field_position); - join_text_field->setAnchorPoint(Vec2::ANCHOR_MIDDLE); - join_text_field->setTouchSize(join_text_field_size); - join_text_field->setTouchAreaEnabled(true); - join_text_field->setMaxLength(/*max_characters=*/4); - join_text_field->setMaxLengthEnabled(true); - - // Adds the event listener to handle the actions for a textfield. - join_text_field->addEventListener( - [this](Ref* sender, TextField::EventType type) { - auto join_text_field = dynamic_cast(sender); - string join_text_field_string = join_text_field->getString(); - // Transforms the letter casing to uppercase. - std::transform( - join_text_field_string.begin(), join_text_field_string.end(), - join_text_field_string.begin(), - [](unsigned char c) -> unsigned char { return std::toupper(c); }); - // Creates a repeating blink action for the cursor. - switch (type) { - case TextField::EventType::ATTACH_WITH_IME: - // Runs the repeated blinking cursor action. - join_text_field->runAction( - CreateBlinkingCursorAction(join_text_field)); - break; - case TextField::EventType::DETACH_WITH_IME: - // Stops the blinking cursor. - join_text_field->stopAllActions(); - break; - case TextField::EventType::INSERT_TEXT: - join_text_field->setString(join_text_field_string); - break; - case TextField::EventType::DELETE_BACKWARD: - break; - default: - break; - } - }); - - // Set up the constraints of the border so it surrounds the text box. - const auto pos = join_text_field_position; - const auto size = join_text_field_size; - const Vec2 join_text_border_corners[4] = { - Vec2(pos.width - size.width / 2, pos.height - size.height / 2), - Vec2(pos.width + size.width / 2, pos.height - size.height / 2), - Vec2(pos.width + size.width / 2, pos.height + size.height / 2), - Vec2(pos.width - size.width / 2, pos.height + size.height / 2)}; - - // Creates a border and adds it around the text field. - auto join_text_field_border = DrawNode::create(); - join_text_field_border->drawPolygon(join_text_border_corners, 4, - Color4F(0, 0, 0, 0), 1, Color4F::WHITE); - this->addChild(join_text_field_border); - - // Creates a sprite for the create button and sets its position to the - // center of the screen. TODO(grantpostma): Dynamically choose the location. - auto create_button = Sprite::create(kCreateGameImage); - create_button->setPosition(25, 200); - create_button->setAnchorPoint(Vec2(0, 0)); - - // Creates a button listener to handle the touch event. - auto create_button_touch_listener = EventListenerTouchOneByOne::create(); - - // Set the onTouchBegan event up to a lambda tha will replace the - // MainMenu scene with a TicTacToe scene. - create_button_touch_listener->onTouchBegan = - [this, join_text_field](Touch* touch, Event* event) -> bool { - const auto bounds = event->getCurrentTarget()->getBoundingBox(); - const auto point = touch->getLocation(); - - // Replaces the scene with a new TicTacToe scene if the touched point is - // within the bounds of the button. - if (bounds.containsPoint(point)) { - Director::getInstance()->pushScene( - TicTacToe::createScene(std::string(), database_, user_uid_)); - join_text_field->setString(""); - current_state_ = kWaitingGameOutcome; - } +#if defined(_ANDROID_) + app = ::firebase::App::Create(GetJniEnv(), GetActivity()); +#else + app = ::firebase::App::Create(); +#endif // defined(ANDROID) - return true; - }; - - // Attach the touch listener to the create game button. - Director::getInstance() - ->getEventDispatcher() - ->addEventListenerWithSceneGraphPriority(create_button_touch_listener, - create_button); - - // Creates a sprite for the logout button and sets its position to the - auto logout_button = Sprite::create(kLogoutButtonImage); - logout_button->setPosition(25, 575); - logout_button->setAnchorPoint(Vec2(0, 0)); - logout_button->setContentSize(Size(125, 50)); - - // Creates a button listener to handle the touch event. - auto logout_button_touch_listener = EventListenerTouchOneByOne::create(); - - // Set the onTouchBegan event up to a lambda tha will replace the - // MainMenu scene with a TicTacToe scene. - logout_button_touch_listener->onTouchBegan = [this](Touch* touch, - Event* event) -> bool { - const auto bounds = event->getCurrentTarget()->getBoundingBox(); - const auto point = touch->getLocation(); - - // Replaces the scene with a new TicTacToe scene if the touched point is - // within the bounds of the button. - if (bounds.containsPoint(point)) { - current_state_ = kAuthState; - user_uid_ = ""; - user_ = nullptr; - invalid_login_label_->setString(""); - email_text_field_->setString(""); - password_text_field_->setString(""); - user_record_label_->setString(""); - } + LogMessage("Initialize Firebase Auth and Firebase Database."); - return true; - }; - - // Attach the touch listener to the logout game button. - Director::getInstance() - ->getEventDispatcher() - ->addEventListenerWithSceneGraphPriority(logout_button_touch_listener, - logout_button); - - // Creates a sprite for the join button and sets its position to the center - // of the screen. TODO(grantpostma): Dynamically choose the location and set - // size(). - auto join_button = Sprite::create(kJoinButtonImage); - join_button->setPosition(25, 50); - join_button->setAnchorPoint(Vec2(0, 0)); - join_button->setScale(1.3f); - - // Creates a button listener to handle the touch event. - auto join_button_touch_listener = EventListenerTouchOneByOne::create(); - - // Set the onTouchBegan event up to a lambda tha will replace the - // MainMenu scene with a TicTacToe scene and pass in join_text_field string. - join_button_touch_listener->onTouchBegan = - [join_text_field, this](Touch* touch, Event* event) -> bool { - const auto bounds = event->getCurrentTarget()->getBoundingBox(); - const auto point = touch->getLocation(); - if (bounds.containsPoint(point)) { - // Get the string from join_text_field. - std::string join_text_field_string = join_text_field->getString(); - if (join_text_field_string.length() == 4) { - Director::getInstance()->pushScene(TicTacToe::createScene( - join_text_field_string, database_, user_uid_)); - current_state_ = kWaitingGameOutcome; - join_text_field->setString(""); - } else { - join_text_field->setString(""); - } - } - return true; - }; + // Use ModuleInitializer to initialize both Auth and Database, ensuring no + // dependencies are missing. + database_ = nullptr; + auth_ = nullptr; + void* initialize_targets[] = {&auth_, &database_}; + + const firebase::ModuleInitializer::InitializerFn initializers[] = { + [](::firebase::App* app, void* data) { + LogMessage("Attempt to initialize Firebase Auth."); + void** targets = reinterpret_cast(data); + ::firebase::InitResult result; + *reinterpret_cast<::firebase::auth::Auth**>(targets[0]) = + ::firebase::auth::Auth::GetAuth(app, &result); + return result; + }, + [](::firebase::App* app, void* data) { + LogMessage("Attempt to initialize Firebase Database."); + void** targets = reinterpret_cast(data); + ::firebase::InitResult result; + *reinterpret_cast<::firebase::database::Database**>(targets[1]) = + ::firebase::database::Database::GetInstance(app, &result); + return result; + }}; + + ::firebase::ModuleInitializer initializer; + initializer.Initialize(app, initialize_targets, initializers, + sizeof(initializers) / sizeof(initializers[0])); + + WaitForCompletion(initializer.InitializeLastResult(), "Initialize"); + + if (initializer.InitializeLastResult().error() != 0) { + LogMessage("Failed to initialize Firebase libraries: %s", + initializer.InitializeLastResult().error_message()); + ProcessEvents(2000); + } + LogMessage("Successfully initialized Firebase Auth and Firebase Database."); - // Attach the touch listener to the join button. - Director::getInstance() - ->getEventDispatcher() - ->addEventListenerWithSceneGraphPriority(join_button_touch_listener, - join_button); + database_->set_persistence_enabled(true); +} - // Attach the create button, join button and join text field to the - // MainMenu scene. - this->addChild(create_button); - this->addChild(join_button); - this->addChild(logout_button); - this->addChild(join_text_field, /*layer_index=*/1); +// 1. Creates the background node. +// 2. Adds the error label and layer title label: sign up. +// 3. Adds the id and password text fields and their event listeners. +// 4. Adds the back and sign up button. +void MainMenuScene::InitializeSignUpLayer() { + // Creates a background to add on all of the cocos2d components. The + // visiblity of this node should match kSignUpState and only active this + // layers event listeners. + + // Creates and places the sign_up_background_. + const auto sign_up_background_size = Size(500, 450); + const auto sign_up_background_origin = Size(300, 300); + sign_up_background_ = + this->CreateRectangle(sign_up_background_size, sign_up_background_origin, + /*background_color=*/Color4F::BLACK); + this->addChild(sign_up_background_, /*layer_index=*/10); + + // Creates the layer title label: sign up. + auto layer_title = Label::createWithSystemFont("sign up", "Arial", 48); + layer_title->setAnchorPoint(Vec2(.5, .5)); + layer_title->setPosition(Vec2(300, 475)); + sign_up_background_->addChild(layer_title); + + // Label to output sign up errors. + sign_up_error_label_ = Label::createWithSystemFont("", "Arial", 24); + sign_up_error_label_->setTextColor(Color4B::RED); + sign_up_error_label_->setPosition(Vec2(300, 425)); + sign_up_background_->addChild(sign_up_error_label_); + + // Creates the sign_up_id_. + const auto id_font_size = 28; + const auto id_position = Size(300, 375); + const auto id_size = Size(450, id_font_size * 1.75); + sign_up_id_ = TextField::create("email", "Arial", id_font_size); + sign_up_id_->setPosition(id_position); + sign_up_id_->setTouchAreaEnabled(true); + sign_up_id_->setTouchSize(id_size); + sign_up_background_->addChild(sign_up_id_); + + // Creates the border for the sign_up_id_ text field. + auto id_border = this->CreateRectangle(id_size, id_position); + sign_up_background_->addChild(id_border); + + // Adds the event listener to handle the actions for the sign_up_id_. + sign_up_id_->addEventListener([this](Ref* sender, TextField::EventType type) { + auto sign_up_id_ = dynamic_cast(sender); + switch (type) { + case TextField::EventType::ATTACH_WITH_IME: + // Creates and runs the repeated blinking cursor action. + CreateBlinkingCursorAction(sign_up_id_); + break; + case TextField::EventType::DETACH_WITH_IME: + // Stops the blinking cursor. + sign_up_id_->stopAllActions(); + break; + default: + break; + } + }); + + // Creates the sign_up_password_. + const auto password_font_size = 28; + const auto password_position = Size(300, 300); + const auto password_size = Size(450, password_font_size * 1.75); + sign_up_password_ = + TextField::create("password", "Arial", password_font_size); + sign_up_password_->setPosition(password_position); + sign_up_password_->setTouchAreaEnabled(true); + sign_up_password_->setTouchSize(password_size); + sign_up_password_->setPasswordEnabled(true); + sign_up_background_->addChild(sign_up_password_); + + // Creates the border for the sign_up_password_ text field. + auto password_border = + this->CreateRectangle(password_size, password_position); + sign_up_background_->addChild(password_border); + + // Adds the event listener to handle the actions for the sign_up_password_ + // text field. + sign_up_password_->addEventListener( + [this](Ref* sender, TextField::EventType type) { + auto sign_up_password_ = dynamic_cast(sender); + switch (type) { + case TextField::EventType::ATTACH_WITH_IME: + // Creates and runs the repeated blinking cursor action. + CreateBlinkingCursorAction(sign_up_password_); + break; + case TextField::EventType::DETACH_WITH_IME: + // Stops the blinking cursor. + sign_up_password_->stopAllActions(); + break; + default: + break; + } + }); + + // Creates the password_confirm text_field. + const auto password_confirm_font_size = 28; + const auto password_confirm_position = Size(300, 225); + const auto password_confirm_size = + Size(450, password_confirm_font_size * 1.75); + sign_up_password_confirm_ = TextField::create("confirm password", "Arial", + password_confirm_font_size); + sign_up_password_confirm_->setPosition(password_confirm_position); + sign_up_password_confirm_->setTouchAreaEnabled(true); + sign_up_password_confirm_->setTouchSize(password_confirm_size); + sign_up_password_confirm_->setPasswordEnabled(true); + sign_up_background_->addChild(sign_up_password_confirm_); + + // Creates the border for the sign_up_password_confirm_ text field. + auto password_confirm_border = + this->CreateRectangle(password_confirm_size, password_confirm_position); + sign_up_background_->addChild(password_confirm_border); + + // Adds the event listener to handle the actions for the + // sign_up_password_confirm text field. + sign_up_password_confirm_->addEventListener( + [this](Ref* sender, TextField::EventType type) { + auto sign_up_password_confirm_ = dynamic_cast(sender); + switch (type) { + case TextField::EventType::ATTACH_WITH_IME: + // Creates and runs the repeated blinking cursor action. + CreateBlinkingCursorAction(sign_up_password_confirm_); + break; + case TextField::EventType::DETACH_WITH_IME: + // Stops the blinking cursor. + sign_up_password_confirm_->stopAllActions(); + break; + default: + break; + } + }); + + // Creates the sign_up_button. + auto sign_up_button = Button::create(kSignUpButtonImage, kLoginButtonImage); + sign_up_button->setScale(.5); + sign_up_button->setPosition(Size(300, 130)); + sign_up_background_->addChild(sign_up_button); + + // Adds the event listener to handle touch actions for the sign_up_button. + sign_up_button->addTouchEventListener( + [this](Ref* sender, Widget::TouchEventType type) { + switch (type) { + case Widget::TouchEventType::ENDED: + // Validates the id and passwords are valid, then sets the + // user_result_ future and swaps to kWaitingSignUpState. + if (!std::regex_match(sign_up_id_->getString(), email_pattern)) { + sign_up_error_label_->setString("invalid email address"); + } else if (sign_up_password_->getString().length() < 8) { + sign_up_error_label_->setString( + "password must be at least 8 characters long"); + } else if (sign_up_password_->getString() != + sign_up_password_confirm_->getString()) { + sign_up_error_label_->setString("passwords do not match"); + } else { + sign_up_error_label_->setString(""); + user_result_ = auth_->CreateUserWithEmailAndPassword( + sign_up_id_->getString().c_str(), + sign_up_password_->getString().c_str()); + current_state_ = kWaitingSignUpState; + } + break; + default: + break; + } + }); + + // Creates the back_button. + auto back_button = Button::create(kJoinButtonImage, kSignUpButtonImage); + back_button->setScale(.5); + back_button->setPosition(Size(130, 500)); + sign_up_background_->addChild(back_button); + + // Adds the event listener to return back to the kAuthMenuState. + back_button->addTouchEventListener( + [this](Ref* sender, Widget::TouchEventType type) { + switch (type) { + case Widget::TouchEventType::ENDED: + current_state_ = kAuthMenuState; + break; + default: + break; + } + }); +} - this->scheduleUpdate(); +// 1. Creates the background node. +// 2. Adds the error label and layer title label: login. +// 3. Adds the id and password text fields and their event listeners. +// 4. Adds the back and login button. +void MainMenuScene::InitializeLoginLayer() { + // Creates a background to add on all of the cocos2d components. The + // visiblity of this node should match kLoginState and only active this + // layers event listeners. + + // Creates and places the login_background_. + const auto login_background_size = Size(500, 450); + const auto login_background_origin = Size(300, 300); + login_background_ = + this->CreateRectangle(login_background_size, login_background_origin, + /*background_color=*/Color4F::BLACK); + this->addChild(login_background_, /*layer_index=*/10); + + // Creates the layer title label: login. + auto layer_title = Label::createWithSystemFont("Login", "Arial", 48); + layer_title->setAnchorPoint(Vec2(.5, .5)); + layer_title->setPosition(Vec2(300, 475)); + login_background_->addChild(layer_title); + + // Label to output login errors. + login_error_label_ = Label::createWithSystemFont("", "Arial", 24); + login_error_label_->setTextColor(Color4B::RED); + login_error_label_->setPosition(Vec2(300, 425)); + login_background_->addChild(login_error_label_); + + // Creating the login_id_. + const auto id_font_size = 28; + const auto id_position = Size(300, 375); + const auto id_size = Size(450, id_font_size * 1.75); + login_id_ = TextField::create("email", "Arial", id_font_size); + login_id_->setPosition(id_position); + login_id_->setTouchAreaEnabled(true); + login_id_->setTouchSize(id_size); + login_background_->addChild(login_id_); + + // Creates the border for the login_id_ text field. + auto id_border = this->CreateRectangle(id_size, id_position); + login_background_->addChild(id_border); + + // Adds the event listener to handle the actions for the login_id_. + login_id_->addEventListener([this](Ref* sender, TextField::EventType type) { + auto login_id_ = dynamic_cast(sender); + switch (type) { + case TextField::EventType::ATTACH_WITH_IME: + // Creates and runs the repeated blinking cursor action. + CreateBlinkingCursorAction(login_id_); + break; + case TextField::EventType::DETACH_WITH_IME: + // Stops the blinking cursor. + login_id_->stopAllActions(); + break; + default: + break; + } + }); + + // Creates the login_password_ text field. + const auto password_font_size = 28; + const auto password_position = Size(300, 300); + const auto password_size = Size(450, password_font_size * 1.75); + login_password_ = TextField::create("password", "Arial", password_font_size); + login_password_->setPosition(password_position); + login_password_->setTouchAreaEnabled(true); + login_password_->setTouchSize(password_size); + login_password_->setPasswordEnabled(true); + login_background_->addChild(login_password_); + + // Creates the border for the login_password_ text field. + auto password_border = + this->CreateRectangle(password_size, password_position); + login_background_->addChild(password_border); + + // Adds the event listener to handle the actions for the login_password_ text + // field. + login_password_->addEventListener( + [this](Ref* sender, TextField::EventType type) { + auto login_password_ = dynamic_cast(sender); + switch (type) { + case TextField::EventType::ATTACH_WITH_IME: + // Creates and runs the repeated blinking cursor action. + CreateBlinkingCursorAction(login_password_); + break; + case TextField::EventType::DETACH_WITH_IME: + // Stops the blinking cursor. + login_password_->stopAllActions(); + break; + default: + break; + } + }); + + // Creates the login_button. + auto login_button = Button::create(kLoginButtonImage, kSignUpButtonImage); + login_button->setScale(.5); + login_button->setPosition(Size(300, 200)); + login_background_->addChild(login_button); + + // Adds the event listener to handle touch actions for the login_button. + login_button->addTouchEventListener( + [this](Ref* sender, Widget::TouchEventType type) { + switch (type) { + case Widget::TouchEventType::ENDED: + // Validates the id and passwords are valid, then sets the + // user_result_ future and swaps to kWaitingLoginState. + if (!std::regex_match(login_id_->getString(), email_pattern)) { + login_error_label_->setString("invalid email address"); + } else if (login_password_->getString().length() < 8) { + login_error_label_->setString( + "password must be at least 8 characters long"); + } else { + login_error_label_->setString(""); + user_result_ = auth_->SignInWithEmailAndPassword( + login_id_->getString().c_str(), + login_password_->getString().c_str()); + current_state_ = kWaitingLoginState; + } + break; + default: + break; + } + }); + + // Creates the back_button. + auto back_button = Button::create(kJoinButtonImage, kSignUpButtonImage); + back_button->setScale(.5); + back_button->setPosition(Size(130, 500)); + login_background_->addChild(back_button); + + // Adds the event listener to return back to the kAuthMenuState. + back_button->addTouchEventListener( + [this](Ref* sender, Widget::TouchEventType type) { + switch (type) { + case Widget::TouchEventType::ENDED: + current_state_ = kAuthMenuState; + break; + default: + break; + } + }); +} - return true; - } +// 1. Creates the background node. +// 2. Adds the layer title label: authentication. +// 3. Adds the id and password text fields and their event listeners. +// 4. Adds the back and login button. +void MainMenuScene::InitializeAuthenticationLayer() { + // Creates a background to add on all of the cocos2d components. The + // visiblity of this node should match kAuthMenuState and only active this + // layers event listeners. - // Initialize the firebase auth and database while also ensuring no - // dependencies are missing. - void - MainMenuScene::InitializeFirebase() { - LogMessage("Initialize Firebase App."); - ::firebase::App* app; + // Creates and places the auth_background_. + const auto auth_background_size = Size(500, 550); + const auto auth_background_origin = Size(300, 300); + auth_background_ = + this->CreateRectangle(auth_background_size, auth_background_origin, + /*background_color=*/Color4F::BLACK); + this->addChild(auth_background_, /*layer_index=*/10); -#if defined(_ANDROID_) - app = ::firebase::App::Create(GetJniEnv(), GetActivity()); -#else - app = ::firebase::App::Create(); -#endif // defined(ANDROID) + // Creates the layer title label: authentication. + auto layer_title = Label::createWithSystemFont("authentication", "Arial", 48); + layer_title->setPosition(Vec2(300, 550)); + auth_background_->addChild(layer_title); + + // Creates three buttons for the menu items (login,sign up, and anonymous sign + // in). + // For each menu item button, creates a normal and selected version and attach + // the touch listener. + + // Creates the sign up menu item. + const auto sign_up_normal_item = Sprite::create(kSignUpButtonImage); + sign_up_normal_item->setContentSize(Size(450, 175)); + auto sign_up_selected = Sprite::create(kSignUpButtonImage); + sign_up_normal_item->setContentSize(Size(450, 175)); + sign_up_selected->setColor(Color3B::GRAY); + + auto sign_up_item = MenuItemSprite::create( + sign_up_normal_item, sign_up_selected, [this](Ref* sender) { + auto node = dynamic_cast(sender); + if (node != nullptr) { + current_state_ = kSignUpState; + } + }); + sign_up_item->setTag(0); + + // Creates the login menu item. + const auto login_normal_item = Sprite::create(kLoginButtonImage); + login_normal_item->setContentSize(Size(450, 175)); + auto login_selected_item = Sprite::create(kLoginButtonImage); + login_normal_item->setContentSize(Size(450, 175)); + login_selected_item->setColor(Color3B::GRAY); + + auto login_item = MenuItemSprite::create( + login_normal_item, login_selected_item, [this](Ref* sender) { + auto node = dynamic_cast(sender); + if (node != nullptr) { + current_state_ = kLoginState; + } + }); + login_item->setTag(1); + + // Creates the skip login menu item. + const auto skip_login_normal_item = Sprite::create(kJoinButtonImage); + skip_login_normal_item->setContentSize(Size(450, 175)); + auto skip_login_selected_item = Sprite::create(kJoinButtonImage); + skip_login_selected_item->setContentSize(Size(450, 175)); + skip_login_selected_item->setColor(Color3B::GRAY); + + auto skip_login_item = MenuItemSprite::create( + skip_login_normal_item, skip_login_selected_item, [this](Ref* sender) { + auto node = dynamic_cast(sender); + if (node != nullptr) { + user_result_ = auth_->SignInAnonymously(); + current_state_ = kWaitingAnonymousState; + } + }); + skip_login_item->setTag(2); + + // Combines the individual items to create the menu. + cocos2d::Vector menuItems = {sign_up_item, login_item, + skip_login_item}; + auto menu = Menu::createWithArray(menuItems); + menu->setPosition(Size(290, 260)); + menu->setContentSize(Size(100, 200)); + menu->setScale(.8, .7); + menu->alignItemsVerticallyWithPadding(30.0f); + auth_background_->addChild(menu); +} - LogMessage("Initialize Firebase Auth and Firebase Database."); - - // Use ModuleInitializer to initialize both Auth and Database, ensuring no - // dependencies are missing. - database_ = nullptr; - auth_ = nullptr; - void* initialize_targets[] = {&auth_, &database_}; - - const firebase::ModuleInitializer::InitializerFn initializers[] = { - [](::firebase::App* app, void* data) { - LogMessage("Attempt to initialize Firebase Auth."); - void** targets = reinterpret_cast(data); - ::firebase::InitResult result; - *reinterpret_cast<::firebase::auth::Auth**>(targets[0]) = - ::firebase::auth::Auth::GetAuth(app, &result); - return result; - }, - [](::firebase::App* app, void* data) { - LogMessage("Attempt to initialize Firebase Database."); - void** targets = reinterpret_cast(data); - ::firebase::InitResult result; - *reinterpret_cast<::firebase::database::Database**>(targets[1]) = - ::firebase::database::Database::GetInstance(app, &result); - return result; - }}; - - ::firebase::ModuleInitializer initializer; - initializer.Initialize(app, initialize_targets, initializers, - sizeof(initializers) / sizeof(initializers[0])); - - WaitForCompletion(initializer.InitializeLastResult(), "Initialize"); - - if (initializer.InitializeLastResult().error() != 0) { - LogMessage("Failed to initialize Firebase libraries: %s", - initializer.InitializeLastResult().error_message()); - ProcessEvents(2000); - } - LogMessage("Successfully initialized Firebase Auth and Firebase Database."); +// Updates the user record variables to reflect what is in the database. +void MainMenuScene::UpdateUserRecord() { + ref_ = database_->GetReference("users").Child(user_uid_); + auto future_wins = ref_.Child("wins").GetValue(); + auto future_loses = ref_.Child("loses").GetValue(); + auto future_ties = ref_.Child("ties").GetValue(); + WaitForCompletion(future_wins, "getUserWinsData"); + WaitForCompletion(future_loses, "getUserLosesData"); + WaitForCompletion(future_ties, "getUserTiesData"); + user_wins_ = future_wins.result()->value().int64_value(); + user_loses_ = future_loses.result()->value().int64_value(); + user_ties_ = future_ties.result()->value().int64_value(); + user_record_label_->setString("W:" + to_string(user_wins_) + + " L:" + to_string(user_loses_) + + " T:" + to_string(user_ties_)); +} - database_->set_persistence_enabled(true); - } +// Creates a rectangle of Size size and centered on the origin. +// Optional parameters: background_color, border_color, border_thickness. +DrawNode* MainMenuScene::CreateRectangle(Size size, Vec2 origin, + Color4F background_color, + Color4F border_color, + int border_thickness) { + // Creates the corners of the rectangle. + Vec2 corners[4]; + corners[0] = Vec2(origin.x - (size.width / 2), origin.y - (size.height / 2)); + corners[1] = Vec2(origin.x - (size.width / 2), origin.y + (size.height / 2)); + corners[2] = Vec2(origin.x + (size.width / 2), origin.y + (size.height / 2)); + corners[3] = Vec2(origin.x + (size.width / 2), origin.y - (size.height / 2)); + + // Draws the rectangle. + DrawNode* rectangle = DrawNode::create(); + rectangle->drawPolygon(corners, /*number_of_points=*/4, background_color, + border_thickness, border_color); + return rectangle; +} - // Updates the user record variables to reflect what is in the database. - void MainMenuScene::UpdateUserRecord() { - ref_ = database_->GetReference("users").Child(user_uid_); - auto future_wins = ref_.Child("wins").GetValue(); - auto future_loses = ref_.Child("loses").GetValue(); - auto future_ties = ref_.Child("ties").GetValue(); - WaitForCompletion(future_wins, "getUserWinsData"); - WaitForCompletion(future_loses, "getUserLosesData"); - WaitForCompletion(future_ties, "getUserTiesData"); - user_wins_ = future_wins.result()->value().int64_value(); - user_loses_ = future_loses.result()->value().int64_value(); - user_ties_ = future_ties.result()->value().int64_value(); - user_record_label_->setString("W:" + to_string(user_wins_) + - " L:" + to_string(user_loses_) + - " T:" + to_string(user_ties_)); - } +// Initialize the user records in the database. +void MainMenuScene::InitializeUserRecord() { + ref_ = database_->GetReference("users").Child(user_uid_); + auto future_wins = ref_.Child("wins").SetValue(0); + auto future_loses = ref_.Child("loses").SetValue(0); + auto future_ties = ref_.Child("ties").SetValue(0); + WaitForCompletion(future_wins, "setUserWinsData"); + WaitForCompletion(future_loses, "setUserLosesData"); + WaitForCompletion(future_ties, "setUserTiesData"); + user_wins_ = 0; + user_loses_ = 0; + user_ties_ = 0; + user_record_label_->setString("W:" + to_string(user_wins_) + + " L:" + to_string(user_loses_) + + " T:" + to_string(user_ties_)); +} - // Initialize the user records in the database. - void MainMenuScene::InitializeUserRecord() { - ref_ = database_->GetReference("users").Child(user_uid_); - auto future_wins = ref_.Child("wins").SetValue(0); - auto future_loses = ref_.Child("loses").SetValue(0); - auto future_ties = ref_.Child("ties").SetValue(0); - WaitForCompletion(future_wins, "setUserWinsData"); - WaitForCompletion(future_loses, "setUserLosesData"); - WaitForCompletion(future_ties, "setUserTiesData"); - user_wins_ = 0; - user_loses_ = 0; - user_ties_ = 0; - user_record_label_->setString("W:" + to_string(user_wins_) + - " L:" + to_string(user_loses_) + - " T:" + to_string(user_ties_)); +// Overriding the onEnter method to update the user_record on reenter. +void MainMenuScene::onEnter() { + // if the scene enter is from the game, updateUserRecords and change + // current_state_. + if (current_state_ == kWaitingGameOutcome) { + this->UpdateUserRecord(); + current_state_ = kGameMenuState; } + Layer::onEnter(); +} - // Overriding the onEnter method to update the user_record on reenter. - void MainMenuScene::onEnter() { - // if the scene enter is from the game, updateUserRecords and change - // current_state_. - if (current_state_ == kWaitingGameOutcome) { - this->UpdateUserRecord(); - current_state_ = kGameMenuState; - } - Layer::onEnter(); - } +// Clears all of the labels and text fields on the login and sign up layers. +void MainMenuScene::ClearAuthFields() { + // Clears the login components. + login_id_->setString(""); + login_password_->setString(""); + login_error_label_->setString(""); + + // Clears the sign up components. + sign_up_id_->setString(""); + sign_up_password_->setString(""); + sign_up_password_confirm_->setString(""); + sign_up_error_label_->setString(""); +} - // Updates the previous_state_ when current_state_ != previous_state_: - // - // switch (current_state_) - // (1) kAuthState: makes the auth_background_ visable. - // (2) kGameMenuState: makes the auth_background_ invisable. - // (3) kWaitingAnonymousState: waits for anonymous sign in then swaps to (1). - // (4) kWaitingSignUpState: waits for sign up future completion, - // updates user variables, and swaps to (2). - // (5) kWaitingLoginState: waits for login future completion, - // updates user variables, and swaps to (2). - // (6) kWaitingGameOutcome: waits for director to pop the TicTacToeScene. - void MainMenuScene::update(float /*delta*/) { - if (current_state_ != previous_state_) { - if (current_state_ == kWaitingAnonymousState) { - if (user_result_.status() == firebase::kFutureStatusComplete) { - if (user_result_.error() == firebase::auth::kAuthErrorNone) { - user_ = *user_result_.result(); - user_uid_ = GenerateUid(10); - - this->InitializeUserRecord(); - - current_state_ = kGameMenuState; - } +// Updates the previous_state_ when current_state_ != previous_state_: +// +// switch (current_state_) +// (1) kAuthMenuState: makes the auth_background_ visable. +// (2) kGameMenuState: makes the auth_background_ invisable. +// (3) kWaitingAnonymousState: waits for anonymous sign in then swaps to (1). +// (4) kWaitingSignUpState: waits for sign up future completion, +// updates user variables, and swaps to (2). +// (5) kWaitingLoginState: waits for login future completion, +// updates user variables, and swaps to (2). +// (6) kWaitingGameOutcome: waits for director to pop the TicTacToeScene. +void MainMenuScene::update(float /*delta*/) { + if (current_state_ != previous_state_) { + if (current_state_ == kWaitingAnonymousState) { + if (user_result_.status() == firebase::kFutureStatusComplete) { + if (user_result_.error() == firebase::auth::kAuthErrorNone) { + user_ = *user_result_.result(); + user_uid_ = GenerateUid(10); + + this->InitializeUserRecord(); + + current_state_ = kGameMenuState; } - } else if (current_state_ == kWaitingSignUpState) { - if (user_result_.status() == firebase::kFutureStatusComplete) { - if (user_result_.error() == firebase::auth::kAuthErrorNone) { - user_ = *user_result_.result(); - user_uid_ = user_->uid(); + } + } else if (current_state_ == kWaitingSignUpState) { + if (user_result_.status() == firebase::kFutureStatusComplete) { + if (user_result_.error() == firebase::auth::kAuthErrorNone) { + user_ = *user_result_.result(); + user_uid_ = user_->uid(); - this->InitializeUserRecord(); + this->ClearAuthFields(); + this->InitializeUserRecord(); - current_state_ = kGameMenuState; + current_state_ = kGameMenuState; - } else { - // Change invalid_login_label_ to display the user_create failed. - invalid_login_label_->setString("invalid sign up"); - current_state_ = kAuthState; - } + } else { + // Change invalid_login_label_ to display the user_create failed. + sign_up_error_label_->setString("invalid credentials"); + current_state_ = kSignUpState; } - } else if (current_state_ == kWaitingLoginState) { - if (user_result_.status() == firebase::kFutureStatusComplete) { - if (user_result_.error() == firebase::auth::kAuthErrorNone) { - user_ = *user_result_.result(); - user_uid_ = user_->uid(); - - this->UpdateUserRecord(); - - current_state_ = kGameMenuState; - } else { - // Change invalid_login_label_ to display the auth_result errored. - auto err = user_result_.error_message(); - invalid_login_label_->setString("invalid login"); - current_state_ = kAuthState; - } + } + } else if (current_state_ == kWaitingLoginState) { + if (user_result_.status() == firebase::kFutureStatusComplete) { + if (user_result_.error() == firebase::auth::kAuthErrorNone) { + user_ = *user_result_.result(); + user_uid_ = user_->uid(); + this->ClearAuthFields(); + this->UpdateUserRecord(); + + current_state_ = kGameMenuState; + } else { + // Change invalid_login_label_ to display the auth_result errored. + login_error_label_->setString("invalid credentials"); + current_state_ = kLoginState; } - } else if (current_state_ == kAuthState) { - // Sign out logic, adding auth screen. - auth_background_->setVisible(true); - // Pauses all event touch listeners & then resumes the ones attached to - // auth_background_. - const auto event_dispatcher = - Director::getInstance()->getEventDispatcher(); - event_dispatcher->pauseEventListenersForTarget(this, - /*recursive=*/true); - event_dispatcher->resumeEventListenersForTarget(auth_background_, - /*recursive=*/true); - user_ = nullptr; - previous_state_ = current_state_; - } else if (current_state_ == kGameMenuState) { - // Removes the authentication screen. - auth_background_->setVisible(false); - const auto event_dispatcher = - Director::getInstance()->getEventDispatcher(); - // Resumes all event touch listeners & then pauses the ones - // attached to auth_background_. - event_dispatcher->resumeEventListenersForTarget(this, - /*recursive=*/true); - event_dispatcher->pauseEventListenersForTarget(auth_background_, - /*recursive=*/true); - previous_state_ = current_state_; } + } else if (current_state_ == kAuthMenuState) { + // Sets the authentication layer visable and hides the login & + // sign up layers. + auth_background_->setVisible(true); + login_background_->setVisible(false); + sign_up_background_->setVisible(false); + // Pauses all event touch listeners & then resumes the ones attached to + // auth_background_. + const auto event_dispatcher = + Director::getInstance()->getEventDispatcher(); + event_dispatcher->pauseEventListenersForTarget(this, + /*recursive=*/true); + event_dispatcher->resumeEventListenersForTarget(auth_background_, + /*recursive=*/true); + user_ = nullptr; + previous_state_ = current_state_; + } else if (current_state_ == kLoginState) { + // Sets the login layer visable and hides the authentication & + // sign up layers. + auth_background_->setVisible(false); + sign_up_background_->setVisible(false); + login_background_->setVisible(true); + // Pauses all event touch listeners & then resumes the ones attached to + // login_background_. + const auto event_dispatcher = + Director::getInstance()->getEventDispatcher(); + event_dispatcher->pauseEventListenersForTarget(this, + /*recursive=*/true); + event_dispatcher->resumeEventListenersForTarget(login_background_, + /*recursive=*/true); + user_ = nullptr; + previous_state_ = current_state_; + } else if (current_state_ == kSignUpState) { + // Sets the sign up layer visable and hides the authentication & + // login layers. + auth_background_->setVisible(false); + login_background_->setVisible(false); + sign_up_background_->setVisible(true); + + // Pauses all event touch listeners & then resumes the ones attached to + // sign_up_background_. + const auto event_dispatcher = + Director::getInstance()->getEventDispatcher(); + event_dispatcher->pauseEventListenersForTarget(this, + /*recursive=*/true); + event_dispatcher->resumeEventListenersForTarget(sign_up_background_, + /*recursive=*/true); + user_ = nullptr; + previous_state_ = current_state_; + } else if (current_state_ == kGameMenuState) { + // hides the authentication,login, and sign up layers. + auth_background_->setVisible(false); + login_background_->setVisible(false); + sign_up_background_->setVisible(false); + const auto event_dispatcher = + Director::getInstance()->getEventDispatcher(); + // Resumes all event touch listeners & then pauses the ones + // attached to auth_background_. + event_dispatcher->resumeEventListenersForTarget(this, + /*recursive=*/true); + event_dispatcher->pauseEventListenersForTarget(auth_background_, + /*recursive=*/true); + previous_state_ = current_state_; } - return; } +} - // Returns a repeating action that toggles the cursor of the text field passed - // in based on the toggle_delay. - cocos2d::RepeatForever* MainMenuScene::CreateBlinkingCursorAction( - cocos2d::ui::TextField * text_field) { - // Creates a callable function that shows the cursor and sets the cursor - // character. - const auto show_cursor = CallFunc::create([text_field]() { - text_field->setCursorEnabled(true); - text_field->setCursorChar('|'); - }); - // Creates a callable function that hides the cursor character. - const auto hide_cursor = - CallFunc::create([text_field]() { text_field->setCursorChar(' '); }); - const auto toggle_delay = DelayTime::create(1.0f); - // Aligns the sequence of actions to create a blinking cursor. - auto blink_cursor_action = Sequence::create( - show_cursor, toggle_delay, hide_cursor, toggle_delay, nullptr); - // Creates a forever repeating action based on the blink_cursor_action. - return RepeatForever::create(blink_cursor_action); - } +// Returns a repeating action that toggles the cursor of the text field passed +// in based on the toggle_delay. +void MainMenuScene::CreateBlinkingCursorAction( + cocos2d::ui::TextField* text_field) { + // Creates a callable function that shows the cursor and sets the cursor + // character. + const auto show_cursor = CallFunc::create([text_field]() { + text_field->setCursorEnabled(true); + text_field->setCursorChar('|'); + }); + // Creates a callable function that hides the cursor character. + const auto hide_cursor = + CallFunc::create([text_field]() { text_field->setCursorChar(' '); }); + + // Creates a delay action. + const cocos2d::DelayTime* delay = DelayTime::create(/*delay_durration=*/0.3f); + + // Aligns the sequence of actions to create a blinking cursor. + auto blink_cursor_action = + Sequence::create(show_cursor, delay, hide_cursor, delay, nullptr); + + // Creates a forever repeating action based on the blink_cursor_action. + text_field->runAction(RepeatForever::create(blink_cursor_action)); +} diff --git a/demos/TicTacToe/Classes/main_menu_scene.h b/demos/TicTacToe/Classes/main_menu_scene.h index 589b9c92..aa9c0ecf 100644 --- a/demos/TicTacToe/Classes/main_menu_scene.h +++ b/demos/TicTacToe/Classes/main_menu_scene.h @@ -15,7 +15,7 @@ #ifndef TICTACTOE_DEMO_CLASSES_MAINMENU_SCENE_H_ #define TICTACTOE_DEMO_CLASSES_MAINMENU_SCENE_H_ -#include +#include #include "cocos2d.h" #include "cocos\ui\UITextField.h" @@ -23,6 +23,10 @@ #include "firebase/database.h" #include "firebase/future.h" +using cocos2d::Color4F; +using cocos2d::DrawNode; +using cocos2d::Size; +using cocos2d::Vec2; using std::to_string; class MainMenuScene : public cocos2d::Layer, public cocos2d::TextFieldDelegate { @@ -36,7 +40,9 @@ class MainMenuScene : public cocos2d::Layer, public cocos2d::TextFieldDelegate { // the MainMenuScene::update(float) method. enum kSceneState { kInitializingState, - kAuthState, + kAuthMenuState, + kLoginState, + kSignUpState, kGameMenuState, kWaitingAnonymousState, kWaitingSignUpState, @@ -44,9 +50,10 @@ class MainMenuScene : public cocos2d::Layer, public cocos2d::TextFieldDelegate { kWaitingGameOutcome }; - // Creates an endless blinking cursor action for the textfield passed in. - cocos2d::RepeatForever* MainMenuScene::CreateBlinkingCursorAction( - cocos2d::ui::TextField*); + // Creates and runs an endless blinking cursor action for the textfield passed + // in. + void MainMenuScene::CreateBlinkingCursorAction(cocos2d::ui::TextField*); + // The game loop method for this layer which runs every frame once scheduled // using this->scheduleUpdate(). Acts as the state manager for this scene. void MainMenuScene::update(float) override; @@ -63,9 +70,29 @@ class MainMenuScene : public cocos2d::Layer, public cocos2d::TextFieldDelegate { // screen. void MainMenuScene::InitializeUserRecord(); + // Initializes the authentication layer which includes the background, buttons + // and labels. + void MainMenuScene::InitializeAuthenticationLayer(); + + // Initializes the sign up layer which includes the background, buttons + // and labels. + void MainMenuScene::InitializeSignUpLayer(); + + // Initializes the login layer which includes the background, buttons + // and labels. + void MainMenuScene::InitializeLoginLayer(); + + // Clears the labels and text fields for all authentication layers. + void MainMenuScene::ClearAuthFields(); + + // Creates a rectangle from the size, origin, border_color, background_color, + // and border_thickness. + DrawNode* MainMenuScene::CreateRectangle( + Size size, Vec2 origin, Color4F background_color = Color4F(0, 0, 0, 0), + Color4F border_color = Color4F::WHITE, int border_thickness = 1); + // Initializes the the firebase app, auth, and database. void MainMenuScene::InitializeFirebase(); - // Initializes the instance of a Node and returns a boolean based on if it was // successful in doing so. bool init() override; @@ -74,15 +101,29 @@ class MainMenuScene : public cocos2d::Layer, public cocos2d::TextFieldDelegate { // Node to be used as a background for the authentication menu. cocos2d::DrawNode* auth_background_; + // Node to be used as a background for the login menu. + cocos2d::DrawNode* login_background_; + + // Node to be used as a background for the sign-up menu. + cocos2d::DrawNode* sign_up_background_; + // Labels and textfields for the authentication menu. - cocos2d::Label* invalid_login_label_; + cocos2d::Label* login_error_label_; + cocos2d::Label* sign_up_error_label_; cocos2d::Label* user_record_label_; - cocos2d::TextFieldTTF* email_text_field_; - cocos2d::TextFieldTTF* password_text_field_; + + // Cocos2d components for the login layer. + cocos2d::ui::TextField* login_id_; + cocos2d::ui::TextField* login_password_; + + // Cocos2d components for the sign up layer. + cocos2d::ui::TextField* sign_up_id_; + cocos2d::ui::TextField* sign_up_password_; + cocos2d::ui::TextField* sign_up_password_confirm_; // Variable to track the current state and previous state to check against // to see if the state changed. - kSceneState current_state_ = kAuthState; + kSceneState current_state_ = kAuthMenuState; kSceneState previous_state_ = kInitializingState; // User record variabales that are stored in firebase database. From e77c4c8796d7cc244d36cda514a381c5f7bfff90 Mon Sep 17 00:00:00 2001 From: Grant-Postma Date: Mon, 27 Jul 2020 21:20:49 -0400 Subject: [PATCH 2/4] Creating setup, rebuild and run process. --- demos/TicTacToe/rebuild_demo.py | 68 ++++++++++++++++++++++++++++ demos/TicTacToe/run_demo.py | 78 +++++++++++++++++++++++++++++++++ demos/TicTacToe/setup_demo.py | 15 ++++--- 3 files changed, 156 insertions(+), 5 deletions(-) create mode 100644 demos/TicTacToe/rebuild_demo.py create mode 100644 demos/TicTacToe/run_demo.py diff --git a/demos/TicTacToe/rebuild_demo.py b/demos/TicTacToe/rebuild_demo.py new file mode 100644 index 00000000..7c6a6f2c --- /dev/null +++ b/demos/TicTacToe/rebuild_demo.py @@ -0,0 +1,68 @@ +#!/usr/bin/python +# coding=utf-8 + +# Copyright 2020 Google Inc. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import logging +import os +import subprocess +import sys + +def logger_setup(): + # The root logger of the hierarchy. + logger = logging.getLogger() + logger.setLevel(logging.DEBUG) + + # Add a StreamHandler to log to stdout. + stream_handler = logging.StreamHandler(sys.stdout) + stream_handler.setLevel(logging.DEBUG) + formatter = logging.Formatter( + "%(asctime)s - %(name)s - %(levelname)s - %(message)s") + stream_handler.setFormatter(formatter) + logger.addHandler(stream_handler) + + return logger + +def log_run(dir, logger, cmd): + # Logs the command. + logger.info(cmd) + # Runs the command. + subprocess.call(cmd, cwd=dir, shell=True) + +def main(): + """The main function.""" + # The run_demo.py script directory. + ROOT_DIRECTORY = os.path.dirname(os.path.abspath(__file__)) + + # Sets up the logging format and handler. + logger = logger_setup() + + # Directory paths. + game_name = "tic_tac_toe_demo" + build_dir = os.path.join(ROOT_DIRECTORY,game_name,"build") + + # Checks whether the build directory was created. + if os.path.isdir(build_dir): + logger.info("Building the demo...") + # Builds the tic_tac_toe_demo executable. + log_run(build_dir, logger,"cmake --build .") + else: + logger.error("Build directory does not exist.") + exit() + + +# Check to see if this script is being called directly. +if __name__ == "__main__": + exit(main()) diff --git a/demos/TicTacToe/run_demo.py b/demos/TicTacToe/run_demo.py new file mode 100644 index 00000000..1b0d8982 --- /dev/null +++ b/demos/TicTacToe/run_demo.py @@ -0,0 +1,78 @@ +#!/usr/bin/python +# coding=utf-8 + +# Copyright 2020 Google Inc. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import logging +import os +import subprocess +import sys + +def logger_setup(): + # The root logger of the hierarchy. + logger = logging.getLogger() + logger.setLevel(logging.DEBUG) + + # Add a StreamHandler to log to stdout. + stream_handler = logging.StreamHandler(sys.stdout) + stream_handler.setLevel(logging.DEBUG) + formatter = logging.Formatter( + "%(asctime)s - %(name)s - %(levelname)s - %(message)s") + stream_handler.setFormatter(formatter) + logger.addHandler(stream_handler) + + return logger + +def log_run(dir, logger, cmd): + # Logs the command. + logger.info(cmd) + # Runs the command. + subprocess.call(cmd, cwd=dir, shell=True) + +def main(): + """The main function.""" + # The run_demo.py script directory. + ROOT_DIRECTORY = os.path.dirname(os.path.abspath(__file__)) + + # Sets up the logging format and handler. + logger = logger_setup() + + # Directory paths. + game_name = "tic_tac_toe_demo" + executable_dir = os.path.join(ROOT_DIRECTORY, game_name, "build", "bin", game_name, "Debug") + + # Checks whether the demo was set up properly. + if not os.path.isdir(executable_dir): + logger.error("demo setup is incomplete.") + exit() + + # Checks whether the google-services.json exists in the debug directory. + if not os.path.isfile(os.path.join(executable_dir,"google-services.json")): + logger.error("google-services.json file is missing in Debug directory.") + exit() + + # Checks whether the executable exists in the debug directory. + if os.path.isfile(os.path.join(executable_dir,"{}.exe".format(game_name))): + logger.info("Lanching the demo...") + # Runs the tic-tac-toe executable. + log_run(executable_dir, logger,'{}.exe'.format(game_name)) + else: + logger.error("Game executable does not exist.") + exit() + + +# Check to see if this script is being called directly. +if __name__ == "__main__": + exit(main()) diff --git a/demos/TicTacToe/setup_demo.py b/demos/TicTacToe/setup_demo.py index 7bb4bf95..74744744 100644 --- a/demos/TicTacToe/setup_demo.py +++ b/demos/TicTacToe/setup_demo.py @@ -65,6 +65,12 @@ def main(): build_dir = os.path.join(game_files_dir,"build") executable_dir = os.path.join(build_dir,"bin",game_name,"Debug") + # Checks whether the google-services.json exists in the debug directory. + if not os.path.isfile(os.path.join(ROOT_DIRECTORY,"google_services","google-services.json")): + # Runs the tic-tac-toe executable. + logger.error("google_services/google-services.json is missing.") + exit() + # Creating the cocos2d-x project. log_run(ROOT_DIRECTORY, logger,"cocos new {0} -p com.DemoApp.{0} -l cpp -d .".format(game_name)) @@ -80,14 +86,13 @@ def main(): # Changes the windows project main.cpp to include the new app_delegate header. modify_proj_file(windows_proj_dir) - # Changes directory into the build directory. - log_run(build_dir, logger, 'cmake .. -G "Visual Studio 16 2019" -A Win32') - # Runs cmake with the Visual Studio 2019 as the generator and windows as the target. + log_run(build_dir, logger, 'cmake .. -G "Visual Studio 16 2019" -A Win32') + + # Builds the tic_tac_toe_demo executable. log_run(build_dir, logger,"cmake --build .") - # Runs the tic-tac-toe executable. - log_run(executable_dir, logger,'{}.exe'.format(game_name)) + logger.info("Demo setup succeeded.") # Check to see if this script is being called directly. if __name__ == "__main__": From 5933388f9f722f09e4622e20947fa35754277b3a Mon Sep 17 00:00:00 2001 From: Grant-Postma Date: Tue, 28 Jul 2020 11:19:13 -0400 Subject: [PATCH 3/4] Consistent spacing changes. --- demos/TicTacToe/rebuild_demo.py | 6 +++--- demos/TicTacToe/run_demo.py | 6 +++--- demos/TicTacToe/setup_demo.py | 22 +++++++++++----------- 3 files changed, 17 insertions(+), 17 deletions(-) diff --git a/demos/TicTacToe/rebuild_demo.py b/demos/TicTacToe/rebuild_demo.py index 7c6a6f2c..13c50baa 100644 --- a/demos/TicTacToe/rebuild_demo.py +++ b/demos/TicTacToe/rebuild_demo.py @@ -49,15 +49,15 @@ def main(): # Sets up the logging format and handler. logger = logger_setup() - # Directory paths. + # Directory and file paths. game_name = "tic_tac_toe_demo" - build_dir = os.path.join(ROOT_DIRECTORY,game_name,"build") + build_dir = os.path.join(ROOT_DIRECTORY, game_name, "build") # Checks whether the build directory was created. if os.path.isdir(build_dir): logger.info("Building the demo...") # Builds the tic_tac_toe_demo executable. - log_run(build_dir, logger,"cmake --build .") + log_run(build_dir, logger, "cmake --build .") else: logger.error("Build directory does not exist.") exit() diff --git a/demos/TicTacToe/run_demo.py b/demos/TicTacToe/run_demo.py index 1b0d8982..d93122c7 100644 --- a/demos/TicTacToe/run_demo.py +++ b/demos/TicTacToe/run_demo.py @@ -59,15 +59,15 @@ def main(): exit() # Checks whether the google-services.json exists in the debug directory. - if not os.path.isfile(os.path.join(executable_dir,"google-services.json")): + if not os.path.isfile(os.path.join(executable_dir, "google-services.json")): logger.error("google-services.json file is missing in Debug directory.") exit() # Checks whether the executable exists in the debug directory. - if os.path.isfile(os.path.join(executable_dir,"{}.exe".format(game_name))): + if os.path.isfile(os.path.join(executable_dir, "{}.exe".format(game_name))): logger.info("Lanching the demo...") # Runs the tic-tac-toe executable. - log_run(executable_dir, logger,'{}.exe'.format(game_name)) + log_run(executable_dir, logger, '{}.exe'.format(game_name)) else: logger.error("Game executable does not exist.") exit() diff --git a/demos/TicTacToe/setup_demo.py b/demos/TicTacToe/setup_demo.py index 74744744..b12f0993 100644 --- a/demos/TicTacToe/setup_demo.py +++ b/demos/TicTacToe/setup_demo.py @@ -59,29 +59,29 @@ def main(): game_name = "tic_tac_toe_demo" game_resources_dir = os.path.join(ROOT_DIRECTORY, "game_resources") game_files_dir = os.path.join(ROOT_DIRECTORY, game_name); - windows_proj_dir = os.path.join(game_files_dir,"proj.win32") - mac_proj_dir = os.path.join(game_files_dir,"proj.ios_mac","mac") - linux_proj_dir = os.path.join(game_files_dir,"proj.linux") - build_dir = os.path.join(game_files_dir,"build") - executable_dir = os.path.join(build_dir,"bin",game_name,"Debug") + windows_proj_dir = os.path.join(game_files_dir, "proj.win32") + mac_proj_dir = os.path.join(game_files_dir, "proj.ios_mac","mac") + linux_proj_dir = os.path.join(game_files_dir, "proj.linux") + build_dir = os.path.join(game_files_dir, "build") + executable_dir = os.path.join(build_dir, "bin", game_name, "Debug") # Checks whether the google-services.json exists in the debug directory. - if not os.path.isfile(os.path.join(ROOT_DIRECTORY,"google_services","google-services.json")): + if not os.path.isfile(os.path.join(ROOT_DIRECTORY, "google_services", "google-services.json")): # Runs the tic-tac-toe executable. logger.error("google_services/google-services.json is missing.") exit() # Creating the cocos2d-x project. - log_run(ROOT_DIRECTORY, logger,"cocos new {0} -p com.DemoApp.{0} -l cpp -d .".format(game_name)) + log_run(ROOT_DIRECTORY, logger, "cocos new {0} -p com.DemoApp.{0} -l cpp -d .".format(game_name)) # Removing the default cocos2d-x project files. - log_run(ROOT_DIRECTORY, logger,"rm -r {0}/Classes {0}/Resources {0}/CMakeLists.txt".format(game_files_dir) ) + log_run(ROOT_DIRECTORY, logger, "rm -r {0}/Classes {0}/Resources {0}/CMakeLists.txt".format(game_files_dir)) # Copies the google-services.json file into the correct directory to run the executable. - log_run(ROOT_DIRECTORY, logger,"cp google_services/google-services.json {}".format(os.path.join(game_resources_dir,"build","bin", game_name, "Debug"))) + log_run(ROOT_DIRECTORY, logger, "cp google_services/google-services.json {}".format(os.path.join(game_resources_dir, "build", "bin", game_name, "Debug"))) # Copies the tic-tac-toe game files into the cocos2d-x project files. - log_run(ROOT_DIRECTORY, logger, "cp {} {} -TRv".format(game_resources_dir,game_files_dir)) + log_run(ROOT_DIRECTORY, logger, "cp {} {} -TRv".format(game_resources_dir, game_files_dir)) # Changes the windows project main.cpp to include the new app_delegate header. modify_proj_file(windows_proj_dir) @@ -90,7 +90,7 @@ def main(): log_run(build_dir, logger, 'cmake .. -G "Visual Studio 16 2019" -A Win32') # Builds the tic_tac_toe_demo executable. - log_run(build_dir, logger,"cmake --build .") + log_run(build_dir, logger, "cmake --build .") logger.info("Demo setup succeeded.") From 5a6375a0e6efd468cac667a8afe342a8e037a3ef Mon Sep 17 00:00:00 2001 From: Grant-Postma Date: Wed, 29 Jul 2020 12:56:11 -0400 Subject: [PATCH 4/4] Pylint yapf formatting changes. More specific instructions. --- demos/TicTacToe/rebuild_demo.py | 72 ++++++++-------- demos/TicTacToe/run_demo.py | 99 ++++++++++++---------- demos/TicTacToe/setup_demo.py | 145 ++++++++++++++++++-------------- 3 files changed, 173 insertions(+), 143 deletions(-) diff --git a/demos/TicTacToe/rebuild_demo.py b/demos/TicTacToe/rebuild_demo.py index 13c50baa..f95e77aa 100644 --- a/demos/TicTacToe/rebuild_demo.py +++ b/demos/TicTacToe/rebuild_demo.py @@ -20,49 +20,53 @@ import subprocess import sys + def logger_setup(): - # The root logger of the hierarchy. - logger = logging.getLogger() - logger.setLevel(logging.DEBUG) + # The root logger of the hierarchy. + logger = logging.getLogger() + logger.setLevel(logging.DEBUG) + + # Add a StreamHandler to log to stdout. + stream_handler = logging.StreamHandler(sys.stdout) + stream_handler.setLevel(logging.DEBUG) + formatter = logging.Formatter( + "%(asctime)s - %(name)s - %(levelname)s - %(message)s") + stream_handler.setFormatter(formatter) + logger.addHandler(stream_handler) - # Add a StreamHandler to log to stdout. - stream_handler = logging.StreamHandler(sys.stdout) - stream_handler.setLevel(logging.DEBUG) - formatter = logging.Formatter( - "%(asctime)s - %(name)s - %(levelname)s - %(message)s") - stream_handler.setFormatter(formatter) - logger.addHandler(stream_handler) + return logger - return logger def log_run(dir, logger, cmd): - # Logs the command. - logger.info(cmd) - # Runs the command. - subprocess.call(cmd, cwd=dir, shell=True) + # Logs the command. + logger.info(cmd) + # Runs the command. + subprocess.call(cmd, cwd=dir, shell=True) + def main(): - """The main function.""" - # The run_demo.py script directory. - ROOT_DIRECTORY = os.path.dirname(os.path.abspath(__file__)) - - # Sets up the logging format and handler. - logger = logger_setup() - - # Directory and file paths. - game_name = "tic_tac_toe_demo" - build_dir = os.path.join(ROOT_DIRECTORY, game_name, "build") + """The main function.""" + # The run_demo.py script directory. + ROOT_DIRECTORY = os.path.dirname(os.path.abspath(__file__)) + + # Sets up the logging format and handler. + logger = logger_setup() + + # Directory and file paths. + game_name = "tic_tac_toe_demo" + build_dir = os.path.join(ROOT_DIRECTORY, game_name, "build") - # Checks whether the build directory was created. - if os.path.isdir(build_dir): - logger.info("Building the demo...") - # Builds the tic_tac_toe_demo executable. - log_run(build_dir, logger, "cmake --build .") - else: - logger.error("Build directory does not exist.") - exit() + # Checks whether the build directory was created. + if os.path.isdir(build_dir): + logger.info("Building the demo...") + # Builds the tic_tac_toe_demo executable. + log_run(build_dir, logger, "cmake --build .") + else: + logger.error( + "Build directory expected at {} does not exist.".format(build_dir)) + exit() # Check to see if this script is being called directly. if __name__ == "__main__": - exit(main()) + exit(main()) diff --git a/demos/TicTacToe/run_demo.py b/demos/TicTacToe/run_demo.py index d93122c7..83418644 100644 --- a/demos/TicTacToe/run_demo.py +++ b/demos/TicTacToe/run_demo.py @@ -20,59 +20,68 @@ import subprocess import sys + def logger_setup(): - # The root logger of the hierarchy. - logger = logging.getLogger() - logger.setLevel(logging.DEBUG) + # The root logger of the hierarchy. + logger = logging.getLogger() + logger.setLevel(logging.DEBUG) + + # Add a StreamHandler to log to stdout. + stream_handler = logging.StreamHandler(sys.stdout) + stream_handler.setLevel(logging.DEBUG) + formatter = logging.Formatter( + "%(asctime)s - %(name)s - %(levelname)s - %(message)s") + stream_handler.setFormatter(formatter) + logger.addHandler(stream_handler) - # Add a StreamHandler to log to stdout. - stream_handler = logging.StreamHandler(sys.stdout) - stream_handler.setLevel(logging.DEBUG) - formatter = logging.Formatter( - "%(asctime)s - %(name)s - %(levelname)s - %(message)s") - stream_handler.setFormatter(formatter) - logger.addHandler(stream_handler) + return logger - return logger def log_run(dir, logger, cmd): - # Logs the command. - logger.info(cmd) - # Runs the command. - subprocess.call(cmd, cwd=dir, shell=True) + # Logs the command. + logger.info(cmd) + # Runs the command. + subprocess.call(cmd, cwd=dir, shell=True) + def main(): - """The main function.""" - # The run_demo.py script directory. - ROOT_DIRECTORY = os.path.dirname(os.path.abspath(__file__)) - - # Sets up the logging format and handler. - logger = logger_setup() - - # Directory paths. - game_name = "tic_tac_toe_demo" - executable_dir = os.path.join(ROOT_DIRECTORY, game_name, "build", "bin", game_name, "Debug") - - # Checks whether the demo was set up properly. - if not os.path.isdir(executable_dir): - logger.error("demo setup is incomplete.") - exit() - - # Checks whether the google-services.json exists in the debug directory. - if not os.path.isfile(os.path.join(executable_dir, "google-services.json")): - logger.error("google-services.json file is missing in Debug directory.") - exit() - - # Checks whether the executable exists in the debug directory. - if os.path.isfile(os.path.join(executable_dir, "{}.exe".format(game_name))): - logger.info("Lanching the demo...") - # Runs the tic-tac-toe executable. - log_run(executable_dir, logger, '{}.exe'.format(game_name)) - else: - logger.error("Game executable does not exist.") - exit() + """The main function.""" + # The run_demo.py script directory. + ROOT_DIRECTORY = os.path.dirname(os.path.abspath(__file__)) + + # Sets up the logging format and handler. + logger = logger_setup() + + # Directory paths. + game_name = "tic_tac_toe_demo" + executable_dir = os.path.join(ROOT_DIRECTORY, game_name, "build", "bin", + game_name, "Debug") + + # Checks whether the demo was set up properly. + if not os.path.isdir(executable_dir): + logger.error( + "Demo setup incomplete. Did you run the setup script first?") + exit() + + # Checks whether the google-services.json exists in the debug directory. + if not os.path.isfile(os.path.join(executable_dir, + "google-services.json")): + logger.error( + "google-services.json file is missing in {} directory.".format( + executable_dir)) + exit() + + # Checks whether the executable exists in the debug directory. + if os.path.isfile(os.path.join(executable_dir, + "{}.exe".format(game_name))): + logger.info("Lanching the demo...") + # Runs the tic-tac-toe executable. + log_run(executable_dir, logger, '{}.exe'.format(game_name)) + else: + logger.error("Game executable does not exist.") + exit() # Check to see if this script is being called directly. if __name__ == "__main__": - exit(main()) + exit(main()) diff --git a/demos/TicTacToe/setup_demo.py b/demos/TicTacToe/setup_demo.py index b12f0993..754ddc1e 100644 --- a/demos/TicTacToe/setup_demo.py +++ b/demos/TicTacToe/setup_demo.py @@ -21,79 +21,96 @@ import subprocess import sys + def logger_setup(): - # The root logger of the hierarchy. - logger = logging.getLogger() - logger.setLevel(logging.DEBUG) + # The root logger of the hierarchy. + logger = logging.getLogger() + logger.setLevel(logging.DEBUG) + + # Add a StreamHandler to log to stdout. + stream_handler = logging.StreamHandler(sys.stdout) + stream_handler.setLevel(logging.DEBUG) + formatter = logging.Formatter( + "%(asctime)s - %(name)s - %(levelname)s - %(message)s") + stream_handler.setFormatter(formatter) + logger.addHandler(stream_handler) - # Add a StreamHandler to log to stdout. - stream_handler = logging.StreamHandler(sys.stdout) - stream_handler.setLevel(logging.DEBUG) - formatter = logging.Formatter( - "%(asctime)s - %(name)s - %(levelname)s - %(message)s") - stream_handler.setFormatter(formatter) - logger.addHandler(stream_handler) + return logger - return logger def log_run(dir, logger, cmd): - # Logs the command. - logger.info(cmd) - # Runs the command. - subprocess.call(cmd, cwd=dir, shell=True) + # Logs the command. + logger.info(cmd) + # Runs the command. + subprocess.call(cmd, cwd=dir, shell=True) + def modify_proj_file(dir): - f = fileinput.FileInput(files = [os.path.join(dir,"main.cpp")], inplace = True) - for line in f: - print line.replace("AppDelegate.h", "app_delegate.h"), + f = fileinput.FileInput(files=[os.path.join(dir, "main.cpp")], + inplace=True) + for line in f: + print line.replace("AppDelegate.h", "app_delegate.h"), + def main(): - """The main function.""" - # The setup_demo.py script directory. - ROOT_DIRECTORY = os.path.dirname(os.path.abspath(__file__)) - - # Sets up the logging format and handler. - logger = logger_setup() - - # Directory paths. - game_name = "tic_tac_toe_demo" - game_resources_dir = os.path.join(ROOT_DIRECTORY, "game_resources") - game_files_dir = os.path.join(ROOT_DIRECTORY, game_name); - windows_proj_dir = os.path.join(game_files_dir, "proj.win32") - mac_proj_dir = os.path.join(game_files_dir, "proj.ios_mac","mac") - linux_proj_dir = os.path.join(game_files_dir, "proj.linux") - build_dir = os.path.join(game_files_dir, "build") - executable_dir = os.path.join(build_dir, "bin", game_name, "Debug") - - # Checks whether the google-services.json exists in the debug directory. - if not os.path.isfile(os.path.join(ROOT_DIRECTORY, "google_services", "google-services.json")): - # Runs the tic-tac-toe executable. - logger.error("google_services/google-services.json is missing.") - exit() - - # Creating the cocos2d-x project. - log_run(ROOT_DIRECTORY, logger, "cocos new {0} -p com.DemoApp.{0} -l cpp -d .".format(game_name)) - - # Removing the default cocos2d-x project files. - log_run(ROOT_DIRECTORY, logger, "rm -r {0}/Classes {0}/Resources {0}/CMakeLists.txt".format(game_files_dir)) - - # Copies the google-services.json file into the correct directory to run the executable. - log_run(ROOT_DIRECTORY, logger, "cp google_services/google-services.json {}".format(os.path.join(game_resources_dir, "build", "bin", game_name, "Debug"))) - - # Copies the tic-tac-toe game files into the cocos2d-x project files. - log_run(ROOT_DIRECTORY, logger, "cp {} {} -TRv".format(game_resources_dir, game_files_dir)) - - # Changes the windows project main.cpp to include the new app_delegate header. - modify_proj_file(windows_proj_dir) - - # Runs cmake with the Visual Studio 2019 as the generator and windows as the target. - log_run(build_dir, logger, 'cmake .. -G "Visual Studio 16 2019" -A Win32') - - # Builds the tic_tac_toe_demo executable. - log_run(build_dir, logger, "cmake --build .") - - logger.info("Demo setup succeeded.") + """The main function.""" + # The setup_demo.py script directory. + ROOT_DIRECTORY = os.path.dirname(os.path.abspath(__file__)) + + # Sets up the logging format and handler. + logger = logger_setup() + + # Directory paths. + game_name = "tic_tac_toe_demo" + game_resources_dir = os.path.join(ROOT_DIRECTORY, "game_resources") + game_files_dir = os.path.join(ROOT_DIRECTORY, game_name) + windows_proj_dir = os.path.join(game_files_dir, "proj.win32") + mac_proj_dir = os.path.join(game_files_dir, "proj.ios_mac", "mac") + linux_proj_dir = os.path.join(game_files_dir, "proj.linux") + build_dir = os.path.join(game_files_dir, "build") + executable_dir = os.path.join(build_dir, "bin", game_name, "Debug") + + # Checks whether the google-services.json exists in the debug directory. + if not os.path.isfile( + os.path.join(ROOT_DIRECTORY, "google_services", + "google-services.json")): + # Runs the tic-tac-toe executable. + logger.error("google_services/google-services.json is missing.") + exit() + + # Creating the cocos2d-x project. + log_run(ROOT_DIRECTORY, logger, + "cocos new {0} -p com.DemoApp.{0} -l cpp -d .".format(game_name)) + + # Removing the default cocos2d-x project files. + log_run( + ROOT_DIRECTORY, logger, + "rm -r {0}/Classes {0}/Resources {0}/CMakeLists.txt".format( + game_files_dir)) + + # Copies the google-services.json file into the correct directory to run the executable. + log_run( + ROOT_DIRECTORY, logger, + "cp google_services/google-services.json {}".format( + os.path.join(game_resources_dir, "build", "bin", game_name, + "Debug"))) + + # Copies the tic-tac-toe game files into the cocos2d-x project files. + log_run(ROOT_DIRECTORY, logger, + "cp {} {} -TRv".format(game_resources_dir, game_files_dir)) + + # Changes the windows project main.cpp to include the new app_delegate header. + modify_proj_file(windows_proj_dir) + + # Runs cmake with the Visual Studio 2019 as the generator and windows as the target. + log_run(build_dir, logger, 'cmake .. -G "Visual Studio 16 2019" -A Win32') + + # Builds the tic_tac_toe_demo executable. + log_run(build_dir, logger, "cmake --build .") + + logger.info("Demo setup succeeded.") + # Check to see if this script is being called directly. if __name__ == "__main__": - exit(main()) + exit(main())