Cocos2d-x注册,登录,修改,网络应用

作业要求

  • 实现 输入用户名和密码进行注册、登录,注册、登录后应有信息回显 (显示成功/失败,和服务端返回的信息)
  • 实现 获取用户信息
  • (加分项) 实现 修改个人信息
  • 修改个人信息只是修改“卡组”信息,输入框中直接输入“卡组”的json
  • 这一功能需要通过cookie认证身份,即在登录后需要记录cookie (enableCookies)
  • 使用enableCookies非常简单,因此需要在报告中体现 “思考enableCookies的作用” 才能加分

具体实现

LoginRegisterScene.h


#ifndef __LOGIN_REGISTER_SCENE_H__
#define __LOGIN_REGISTER_SCENE_H__

#include "cocos2d.h"
#include "ui\CocosGUI.h"
#include "network/HttpClient.h"
using namespace cocos2d::network;
using namespace cocos2d::ui;
USING_NS_CC;

class LoginRegisterScene : public cocos2d::Scene {
public:
  static cocos2d::Scene* createScene();

  virtual bool init();

  void loginButtonCallback(Ref *pSender);
  void registerButtonCallback(Ref *pSender);
  void onHttpRequestCompleted(HttpClient *sender, HttpResponse *response);
  void onHttpRequestCompleted1(HttpClient *sender, HttpResponse *response);
  // implement the "static create()" method manually
  CREATE_FUNC(LoginRegisterScene);

  Label *messageBox;
private:
  TextField *usernameInput;
  TextField *passwordInput;
};

#endif // !__LOGIN_REGISTER_SCENE_H__

LoginRegisterScene.cpp

#include "LoginRegisterScene.h"
#include "ui\CocosGUI.h"
#include "network\HttpClient.h"
#include "json\document.h"
#include "Utils.h"

USING_NS_CC;
using namespace cocos2d::network;
using namespace cocos2d::ui;

cocos2d::Scene * LoginRegisterScene::createScene() {
  return LoginRegisterScene::create();
}

bool LoginRegisterScene::init() {
  if (!Scene::init()) {
    return false;
  }

  auto visibleSize = Director::getInstance()->getVisibleSize();
  Vec2 origin = Director::getInstance()->getVisibleOrigin();

  auto loginButton = MenuItemFont::create("Login", CC_CALLBACK_1(LoginRegisterScene::loginButtonCallback, this));
  if (loginButton) {
    float x = origin.x + visibleSize.width / 2;
    float y = origin.y + loginButton->getContentSize().height / 2;
    loginButton->setPosition(Vec2(x, y));
  }

  auto registerButton = MenuItemFont::create("Register", CC_CALLBACK_1(LoginRegisterScene::registerButtonCallback, this));
  if (registerButton) {
    float x = origin.x + visibleSize.width / 2;
    float y = origin.y + registerButton->getContentSize().height / 2 + 100;
    registerButton->setPosition(Vec2(x, y));
  }

  auto backButton = MenuItemFont::create("Back", [] (Ref* pSender) {
    Director::getInstance()->popScene();
  });
  if (backButton) {
    float x = origin.x + visibleSize.width / 2;
    float y = origin.y + visibleSize.height - backButton->getContentSize().height / 2;
    backButton->setPosition(Vec2(x, y));
  }

  auto menu = Menu::create(loginButton, registerButton, backButton, NULL);
  menu->setPosition(Vec2::ZERO);
  this->addChild(menu, 1);

  usernameInput = TextField::create("username", "arial", 24);
  if (usernameInput) {
    float x = origin.x + visibleSize.width / 2;
    float y = origin.y + visibleSize.height - 100.0f;
    usernameInput->setPosition(Vec2(x, y));
    this->addChild(usernameInput, 1);
  }

  passwordInput = TextField::create("password", "arial", 24);
  if (passwordInput) {
    float x = origin.x + visibleSize.width / 2;
    float y = origin.y + visibleSize.height - 130.0f;
    passwordInput->setPosition(Vec2(x, y));
    this->addChild(passwordInput, 1);
  }

  messageBox = Label::create("", "arial", 30);
  if (messageBox) {
    float x = origin.x + visibleSize.width / 2;
    float y = origin.y + visibleSize.height - 200.0f;
    messageBox->setPosition(Vec2(x, y));
    this->addChild(messageBox, 1);
  }

  return true;
}
//登录函数
void LoginRegisterScene::loginButtonCallback(cocos2d::Ref * pSender) {
  // Your code here
    //对应着服务端的username和password,传入json格式的数据
    std::string username = usernameInput->getStringValue();
    std::string password = passwordInput->getStringValue();
    std::string postData = "{\"username\":\"" + username + "\"," + "\"password\":\"" + password + "\"}";

    //用post方式传输,根据ppt里面的提示,用auth
    HttpRequest* request = new HttpRequest();
    request->setUrl("http://127.0.0.1:8000/auth");
    request->setRequestType(HttpRequest::Type::POST);
    request->setResponseCallback(CC_CALLBACK_2(LoginRegisterScene::onHttpRequestCompleted, this));
    request->setRequestData(postData.c_str(), strlen(postData.c_str()));

    //这里就是使用Cookies的地方,只要加这一句就好,可以在报头看到
    //在登录的时候加上cookies就可以,这样服务端就可以记录正在使用的客户
    //作为切换用户的标识
    cocos2d::network::HttpClient::getInstance()->enableCookies(NULL);
    cocos2d::network::HttpClient::getInstance()->send(request);
    request->release();
}

//登录的回调函数,主要看返回的状态
void LoginRegisterScene::onHttpRequestCompleted(HttpClient *sender, HttpResponse *response)
{
    if (!response) {
        usernameInput->setString("not 200");
        return;
    }
    auto buffer = response->getResponseData();
    rapidjson::Document doc;
    doc.Parse(buffer->data(),buffer->size());
    if (doc["status"] == true) {
        this->messageBox->setString("Login OK");
    }
    else {
        this->messageBox->setString(std::string("Login Failed\n") + doc["msg"].GetString());
    }
}
//注册函数
void LoginRegisterScene::registerButtonCallback(Ref * pSender) {
  // Your code here
    //和登录函数差不多
    std::string username = usernameInput->getStringValue();
    std::string password = passwordInput->getStringValue();
    std::string postData = "{\"username\":\"" + username + "\"," + "\"password\":\"" + password + "\"}";

    //用Post传输方式,根据PPT里面的提示用users
    HttpRequest* request = new HttpRequest();
    request->setUrl("http://127.0.0.1:8000/users");
    request->setRequestType(HttpRequest::Type::POST);
    request->setResponseCallback(CC_CALLBACK_2(LoginRegisterScene::onHttpRequestCompleted1, this));
    request->setRequestData(postData.c_str(), strlen(postData.c_str()));

    cocos2d::network::HttpClient::getInstance()->send(request);
    request->release();
}
//注册的回调函数,主要显示信息
void LoginRegisterScene::onHttpRequestCompleted1(HttpClient *sender, HttpResponse *response)
{
    auto buffer = response->getResponseData();
    rapidjson::Document doc;
    doc.Parse(buffer->data(), buffer->size());
    if (doc["status"] == true) {
        this->messageBox->setString("Register OK");
    }
    else {
        this->messageBox->setString(std::string("Register Failed\n") + doc["msg"].GetString());
    }
}

UsersInfoScene.h

#pragma once

#ifndef __USER_INFO_SCENE_H__
#define __USER_INFO_SCENE_H__

#include "cocos2d.h"
#include "ui\CocosGUI.h"
#include "network/HttpClient.h"
using namespace cocos2d::network;
USING_NS_CC;
using namespace cocos2d::ui;

class UsersInfoScene : public  cocos2d::Scene{
public:
  static cocos2d::Scene* createScene();

  virtual bool init();

  void getUserButtonCallback(Ref *pSender);
  void onHttpRequestCompleted(HttpClient *sender, HttpResponse *response);
  CREATE_FUNC(UsersInfoScene);

  TextField *limitInput;
  Label *messageBox;
};

#endif // !__USER_INFO_SCENE_H__

UsersInfoScene.cpp

#include "UsersInfoScene.h"
#include "network\HttpClient.h"
#include "json\document.h"
#include "Utils.h"

using namespace cocos2d::network;
using namespace rapidjson;

cocos2d::Scene * UsersInfoScene::createScene() {
  return UsersInfoScene::create();
}

bool UsersInfoScene::init() {
  if (!Scene::init()) return false;

  auto visibleSize = Director::getInstance()->getVisibleSize();
  Vec2 origin = Director::getInstance()->getVisibleOrigin();

  auto getUserButton = MenuItemFont::create("Get User", CC_CALLBACK_1(UsersInfoScene::getUserButtonCallback, this));
  if (getUserButton) {
    float x = origin.x + visibleSize.width / 2;
    float y = origin.y + getUserButton->getContentSize().height / 2;
    getUserButton->setPosition(Vec2(x, y));
  }

  auto backButton = MenuItemFont::create("Back", [](Ref* pSender) {
    Director::getInstance()->popScene();
  });
  if (backButton) {
    float x = origin.x + visibleSize.width / 2;
    float y = origin.y + visibleSize.height - backButton->getContentSize().height / 2;
    backButton->setPosition(Vec2(x, y));
  }

  auto menu = Menu::create(getUserButton, backButton, NULL);
  menu->setPosition(Vec2::ZERO);
  this->addChild(menu, 1);

  limitInput = TextField::create("limit", "arial", 24);
  if (limitInput) {
    float x = origin.x + visibleSize.width / 2;
    float y = origin.y + visibleSize.height - 100.0f;
    limitInput->setPosition(Vec2(x, y));
    this->addChild(limitInput, 1);
  }

  messageBox = Label::create("", "arial", 30);
  if (messageBox) {
    float x = origin.x + visibleSize.width / 2;
    float y = origin.y + visibleSize.height / 2;
    messageBox->setPosition(Vec2(x, y));
    this->addChild(messageBox, 1);
  }

  return true;
}
//得到用户信息的函数
void UsersInfoScene::getUserButtonCallback(Ref * pSender) {
  // Your code here

    std::string num = limitInput->getStringValue();
    //根据PPT里面的提示,用users?limit=,传输方式用GET
    HttpRequest* request = new HttpRequest();
    request->setUrl("http://127.0.0.1:8000/users?limit=" + num);
    request->setRequestType(HttpRequest::Type::GET);

    request->setResponseCallback(CC_CALLBACK_2(UsersInfoScene::onHttpRequestCompleted, this));

    cocos2d::network::HttpClient::getInstance()->send(request);
    request->release();
}

//得到信息的回调函数,稍微有点复杂
void UsersInfoScene::onHttpRequestCompleted(HttpClient *sender, HttpResponse *response) 
{
    if (!response) {
        return;
    }
    auto buffer = response->getResponseData();
    rapidjson::Document doc;
    doc.Parse(buffer->data(), buffer->size());
    //首先是要用rapidjson解释库解析一下,得到doc这个数据结构
    if (doc["status"] == true) {
        std::string result;//为了将结果放入result中
        for (int i = 0; i < doc["data"].Size(); i++) {//使用方式类似于vector,
            result += "Username : ";
            result += doc["data"][i]["username"].GetString();
            result += "\nDeck : \n";
            for (int j = 0; j < doc["data"][i]["deck"].Size(); j++) {
                for (auto& m : doc["data"][i]["deck"][j].GetObjectW()) {//C++11标准的遍历
                    result == "\n";
                    //这边调一下缩进,似乎和\n放在一起不起作用,所以直接拿出来了
                    result += "  ";
                    result += m.name.GetString();
                    result += ":";
                    //这边按照教程应该是直接m.value.GetInt但是会出乱码,所以将int再转成string再放到result里面
                    int a = m.value.GetInt();
                    CCString* ns = CCString::createWithFormat("%d", a);
                    std::string s = ns->_string;
                    result += s;
                    CCLOG("m.value.GetInt = %d", m.value.GetInt());
                    result += "\n";
                }
                result += " ---\n";
            }
            result += "---\n";
        }
        this->messageBox->setString(result);
    }
    else {
        this->messageBox->setString(std::string("Info Failed\n") + doc["msg"].GetString());
    }
}

ModifyUserScene.h

#pragma once

#ifndef __MODIFY_USER_SCENE_H__
#define __MODIFY_USER_SCENE_H__

#include "cocos2d.h"
#include "ui\CocosGUI.h"
//必须要加这个库,以及引用名字空间,否则虽然没有红线,但是无法运行
#include "network\HttpClient.h"
using namespace cocos2d::network;
using namespace cocos2d::ui;
USING_NS_CC;

class ModifyUserScene : public cocos2d::Scene {
public:
  static cocos2d::Scene* createScene();

  virtual bool init();

  void putDeckButtonCallback(Ref *pSender);
  //为了点击回调
  void onHttpRequestCompleted(HttpClient *sender, HttpResponse *response);
  // implement the "static create()" method manually
  CREATE_FUNC(ModifyUserScene);

  Label *messageBox;
  TextField *deckInput;
};

#endif

ModifyUserScene.cpp

#include "ModifyUserScene.h"
#include "Utils.h"
#include "network\HttpClient.h"
#include "json\document.h"

using namespace cocos2d::network;

cocos2d::Scene * ModifyUserScene::createScene() {
  return ModifyUserScene::create();
}

bool ModifyUserScene::init() {
  if (!Scene::init()) return false;

  auto visibleSize = Director::getInstance()->getVisibleSize();
  Vec2 origin = Director::getInstance()->getVisibleOrigin();

  auto postDeckButton = MenuItemFont::create("Post Deck", CC_CALLBACK_1(ModifyUserScene::putDeckButtonCallback, this));
  if (postDeckButton) {
    float x = origin.x + visibleSize.width / 2;
    float y = origin.y + postDeckButton->getContentSize().height / 2;
    postDeckButton->setPosition(Vec2(x, y));
  }

  auto backButton = MenuItemFont::create("Back", [](Ref* pSender) {
    Director::getInstance()->popScene();
  });
  if (backButton) {
    float x = origin.x + visibleSize.width / 2;
    float y = origin.y + visibleSize.height - backButton->getContentSize().height / 2;
    backButton->setPosition(Vec2(x, y));
  }

  auto menu = Menu::create(postDeckButton, backButton, NULL);
  menu->setPosition(Vec2::ZERO);
  this->addChild(menu, 1);

  deckInput = TextField::create("Deck json here", "arial", 24);
  if (deckInput) {
    float x = origin.x + visibleSize.width / 2;
    float y = origin.y + visibleSize.height - 100.0f;
    deckInput->setPosition(Vec2(x, y));
    this->addChild(deckInput, 1);
  }

  messageBox = Label::create("", "arial", 30);
  if (messageBox) {
    float x = origin.x + visibleSize.width / 2;
    float y = origin.y + visibleSize.height / 2;
    messageBox->setPosition(Vec2(x, y));
    this->addChild(messageBox, 1);
  }

  return true;
}

//改变卡组的函数
void ModifyUserScene::putDeckButtonCallback(Ref * pSender) {
  // Your code here
    //和之前的注册登录类似
    std::string deck = deckInput->getStringValue();
    std::string postData = "{\"deck\":" + deck + "}";

    //根据PPT的内容,用put方式,users
    HttpRequest* request = new HttpRequest();
    request->setUrl("http://127.0.0.1:8000/users");
    request->setRequestType(HttpRequest::Type::PUT);

    request->setResponseCallback(CC_CALLBACK_2(ModifyUserScene::onHttpRequestCompleted, this));
    request->setRequestData(postData.c_str(), strlen(postData .c_str()));
    cocos2d::network::HttpClient::getInstance()->send(request);
    request->release();
}
//改变卡组的回调函数,主要显示信息
void ModifyUserScene::onHttpRequestCompleted(HttpClient *sender, HttpResponse *response) {
    auto buffer = response->getResponseData();
    rapidjson::Document doc;
    doc.Parse(buffer->data(), buffer->size());
    if (doc["status"] == true) {
        this->messageBox->setString("PUT OK");
    }
    else {
        this->messageBox->setString(std::string("PUT Failed\n") + doc["msg"].GetString());
    }
}

常见问题

在头文件加入void onHttpRequestCompleted1(HttpClient *sender, HttpResponse *response)报错问题

这个问题,在写的时候,visual studio 2018,不会加红线,所以看不出来报错,但是运行的时候就会出错,需要加头文件以及用对应的名字空间。#include "network/HttpClient.h"
using namespace cocos2d::network;

怎么使用Cookies的问题

我大概看了一下往届是怎么用Cookies的,他们有一个Global.cppGlobal.h文件,用来根据传入的报头,生成一个值,然后在登录的时候传入这个值,这样在修改的时候,将这个值传入报头用来标识,等到我们这届直接在void LoginRegisterScene::loginButtonCallback(cocos2d::Ref * pSender)这个函数里面加上cocos2d::network::HttpClient::getInstance()->enableCookies(NULL);即可,直接自动生成,而不用手动添加了。

解析Json文件得到键值对两个值的方法

具体的详细的教程

主要是利用迭代器,得到name和value的值
这里写图片描述

视频以及资源

代码以及视频演示

猜你喜欢

转载自blog.csdn.net/yaoxh6/article/details/80784527