Unity5权威讲解第十四章第十节内容 【在Unity中连接数据库】

14.10 在Unity中连接数据库

应用程序收发数据通常有很多中方法,但其中最快、最常用的方法是连接数据库。虽然此处使用了“直接连接”这个说法,但实际上需要ODBC(Open Database connectivity,开放数据库互联)或者JDBC等中间件才能连接数据库。

如前所述,在Unity中也可以通过ODBC连接数据库,但实际开发中会根据平台不同而有所区别。如图14-116所示,也可通过Web服务器的服务器脚本(Server Side Script)连接到数据库并收发数据。各位熟知的PHP、ASP、JSP等都是服务器端脚本,实际开发中可用JSON、XML、CSV等格式收发数据。

Unity5权威讲解第十四章第十节内容 【在Unity中连接数据库】

 

14.10.1 JSON

JSON(JavaScript Object Notation)是收发数据的一种格式,主要用于轻量级数据。其结构虽然借鉴了Java的语法,但它独立于计算机编程语言或平台。另外,大部分服务器端脚本都支持解析或构建JSON格式的消息体。

JSON支持的数据类型有整数、字符串、布尔型、数组等。

下列示例就是保存游戏玩家信息的JSON消息体。

Unity5权威讲解第十四章第十节内容 【在Unity中连接数据库】

 

JSON格式消息以大括号({})表示开始和结束,然后在大括号内写入要识别的键名和键值。

Unity5权威讲解第十四章第十节内容 【在Unity中连接数据库】

 

其中的键值可根据JSON支持的数据类型决定。

Unity5权威讲解第十四章第十节内容 【在Unity中连接数据库】

 

JSON中,数组的开始和结束均有中括号([])表示。上述示例中,“拥有技能”键保存的键值为数组,包含"掩蔽","透明模式","穿甲弹"这3个字符串类型的值。

JSON支持嵌套子JSON结构体。

{

    "姓名":"狙击手",

    "性别":"男",

    "职业":"狙击手",

    "能力值":{

                "等级":37,

                "生命力":480,

                "活力":270,

                "法力":1200

              },

    "拥有技能":["掩蔽","透明模式","穿甲弹"],

    "分数":2750000,

}

提示:关于JSON的详细内容请参考下列网址http://www.json.org/json-zh.html

 

14.10.2 SimpleJSON

如果想在Unity中使用JSON,需要可以分拆和构建JSON消息的JSON解析器。Unity中可以使用的JSON解析器有SimpleJSON、LitJSON、JSONObject、JsonFX等,本书使用的是SimpleJSON解析器。

SimpleJSON的使用方法较为简单,不需要复杂的C#高级语法。可在下列网站下载SimpleJOSN。

http://wiki.unity3d.com/index.php/SimpleJSON

下载的SimpleJSON.zip文件包括JSON Test文件夹、plugins文件、SimpleJSON.unitypackkage文件夹,只需plugins文件夹中的SimpleJSON.cs文件导入项目视图的Plugins文件夹即可。

 

Unity5权威讲解第十四章第十节内容 【在Unity中连接数据库】

制作新的场景并简单测试JSON。先将本节开头的JOSN示例重命名为user_info.json并保存,放入项目视图的Resources文件夹。

{

"姓名":"狙击手",

"性别":"男",

"职业":"狙击手",

"能力值":

                   {

                            "等级":37

                            ,"生命力":480

                            ,"活力":270

                            ,"法力":1200

                   },

"拥有技能":["掩蔽","透明模式","穿甲弹"],

"分数":2750000,

}

 

using System.Collections;

using System.Collections.Generic;

using UnityEngine;

using SimpleJSON;

 

public class LoadUserInfo : MonoBehaviour

{

 

    public TextAsset jsonData = null;

    public string strJsonData = null;

    // Use this for initialization

    void Start()

    {

        //加载Resources文件夹中的JSON文件

        jsonData = Resources.Load<TextAsset>("user_info");

        //将Json文件转化为字符串类型的文件

        strJsonData = jsonData.text;

       // Debug.Log(strJsonData);

 

        //解析JSON文件

        var N = JSON.Parse(strJsonData);

 

        //获取key为姓名的键值

        string user_name = N["姓名"].ToString();

        //从能力值中获取key为等级的键值

        int level = N["能力值"]["等级"].AsInt;

 

        Debug.Log(user_name);

        Debug.Log(level.ToString());

 

        for (int i = 0; i < N["拥有技能"].Count; i++)

        {

            Debug.Log(N["拥有技能"][i].ToString());

        }

 

}

将脚本添加到场景后执行,控制台视图中会出现如图14-118所示的日志信息。

Unity5权威讲解第十四章第十节内容 【在Unity中连接数据库】

 

 

14-118 解析JSON文件的结果

14.10.3 将分数信息保存到数据库

本节将之前坦克爆炸时的累积的分数保存到数据库,然后将其封装为JSON格式的文件并显示到画面。为了便于测试数据保存的内容,各位可以使用我的服务器以使用MySQL数据库。我为每个测试数据库都分配了一个***,这样可以避免各自的数据相互干扰。复制并打开下列网址,输入简单的信息再点击“生成账号”按钮,就会得到一个***。请复制此***。

http://www.unity3d.com/Tankwar/UserRegister.html

 

14-119 为了使用我的MySQL数据库而分配***

Unity5权威讲解第十四章第十节内容 【在Unity中连接数据库】

注意

考虑到运营服务器的成本,我会定期初始化保存的数据,所以此数据库只用于学习。另外,如果数据保存及查询时产生过多的流量,则测试账号的页面会暂时终止。

如脚本14-45所示编写脚本,将其命名为DataMgr,用于数据库中保存和查询数据。

using System.Collections;

using System.Collections.Generic;

using UnityEngine;

 

public class DataMgr : MonoBehaviour

{

    public static DataMgr instance = null;

 

    //为了使用MySQL数据库而分配的***

    private const string seqNo = "3201411232";

    //保存分数的PHP地址

    private string urlSave = "http://www.Unity3dStudy.com/Tankwar/save_score.php";

 

    void Awkae()

    {

        instance = this;

    }

    public IEnumerator SaveScore(string user_name, int killCount)

    {

        WWWForm form = new WWWForm();

        //设置要传递的参数

        form.AddField("user_name", user_name);

        form.AddField("kill_count", killCount);

        form.AddField("seq_no", seqNo);

 

        //调用URL

        var www = new WWW(urlSave, form);

        //等待完成

        yield return www;

        if (string.IsNullOrEmpty(www.error))

        {

            Debug.Log(www.text);

        }

        else

        {

            Debug.Log("Error" + www.error);

        }

    }

}

 

使用seqNo变量保存从图14-119额页面中获取的***,避免与其他读者的数据弄混。

    //为了使用MySQL数据库而分配的***

    private const string seqNo = "3201411232";

使用save_score.php将分数保存到数据库,php页面的源码如脚本14-46所示

<?php

//连接数据库

$connect = mysql_connect("localhost","用户名","密码");

//查看是否连接成功

if($connect==0)

{

?>SORRY SOCRE SERVER CONNECTION ERROR<?

}else

{

}

 

//设置要使用的数据库

mysql_select_db("数据库名称",$connect);

//以POST方式传递的参数保存到变量

$user_name = $_POST["user_name"];

$kill_count = $_POST["kill_count"];

$seq_no = $_POST["seq_no"];

//生成SQL查询语句

$sql = "INSERT INTO tb_score(user_name,kill_count,seq_no)";

$sql.="\n values("'.$user_name.'",".$kill_count.",".$seq_no.")";

$sql.="\n ON DUPLICATE KEY UPDATE kill_count = kill_count +1";

 

//执行SQL查询语句

$result = mysql_query($sql,$connect);

//返回查询语句的执行结果

if($result)

{

echo("YOUR SCORE SAVED.");

}else

{

 echo("eroor");

}

//断开与数据库的连接

mysql_close($connect);

?>

 

DataMgr脚本制作完成后,将其添加到场景中的GameManager游戏对象。

Unity5权威讲解第十四章第十节内容 【在Unity中连接数据库】

 

如脚本14-47所示,将DataMgr脚本中定义的“向数据库保存数据”的函数添加到TankDamage脚本的IncKillCount函数。

void InKillCount()

    {

        ++killCount;

        if (texttKillCount != null)

            texttKillCount.text = killCount.ToString();

 

        Debug.Log(killCount);

        if(DataMgr.instance!=null)

        StartCoroutine(DataMgr.instance.SaveScore(gameObject.name, 1));

 

    }

         // Update is called once per frame

         void Update () {

 

        if (Input.GetKeyDown(KeyCode.I))

            InKillCount();

         }

 

重新构建2个游戏可执行文件并运行,在不同游戏窗口中互相攻击,可以在控制台视图中看到诸如YOUR SCORE SAVED.的日志和执行的SQL查询语句,说明数据已经正常保存到数据库(此处使用键盘的I键为分数增加的模拟操作)。

 

Unity5权威讲解第十四章第十节内容 【在Unity中连接数据库】

14.10.4 从数据库获取排名信息

下面从数据获取保存的排名信息。从数据中查询数据,构建为JSON格式的消息并返回,然后在Unity中解析JSON消息以获取数据。我制作的PHP脚本源码如脚14-48所示。

<?php

//连接数据库

$connect = mysql_connect("localhost","用户名","密码");

//查看是否连接成功

if($connect==0)

{

?>SORRY SOCRE SERVER CONNECTION ERROR<?

}else

{

}

 

//设置要使用的数据库

mysql_select_db("数据库名称",$connect);

//以POST方式传递的参数保存到变量

$seq_no = $_POST["seq_no"];

//生成SQL查询语句

$sql = "SELECT ";

$sql.="\n @rownum:[email protected]+1 as ranking";

$sql.="\n   ,A.user_name as user_name";

$sql.="\n   ,A.kill_count as kill_count";

$sql.="\n FROM tb_score as A, (SELECT @rownum := 0) R ";

$sql.="\n where A.seq_no ='".$seq_no."'";

$sql.="\n ODDER BY kill_count DESC";

//执行SQL查询语句

$result = mysql_query($sql,$connect);

 

//保存JSON的数组

$rows = array();

$return = array();

//从开始到最终记录始终输出查询结果值

while($row = mysql_fetch_arrya($result))

{

$rows["ranking"] = $row["ranking"];//获取排名

$rows["user_name"] = $row["user_name"];//获取用户名

$rows["kill_count"] = $row["kill_count"];//获取分数

 

//向数组添加记录值以生成JSON数据

array_push($return ,$rows);

 

}

header("Content-type:application/json");

//生成JSON文件

echo json_encode($return);

 

//断开与数据库的连接

mysql_close($connect);

?>

向DataMgr脚本添加入脚本14-49所示代码,解析JSON格式的消息并获取、显示排名信息数据。

using System.Collections;

using System.Collections.Generic;

using UnityEngine;

 

using SimpleJSON;

public class DataMgr : MonoBehaviour

{

    public static DataMgr instance = null;

 

    //为了使用MySQL数据库而分配的***

    private const string seqNo = "3201411232";

    //保存分数的PHP地址

    private string urlSave = "http://www.Unity3dStudy.com/Tankwar/save_score.php";

 

    //可以获取排名信息的PHP地址

    private string urlScoreList = "http://www.Unity3dStudy.com/Tankwar/get_score_list.php";

    void Awake()

    {

        instance = this;

    }

    public IEnumerator SaveScore(string user_name, int killCount)

    {

        WWWForm form = new WWWForm();

        //设置要传递的参数

        form.AddField("user_name", user_name);

        form.AddField("kill_count", killCount);

        form.AddField("seq_no", seqNo);

 

        //调用URL

        var www = new WWW(urlSave, form);

        //等待完成

        yield return www;

        if (string.IsNullOrEmpty(www.error))

        {

            Debug.Log(www.text);

        }

        else

        {

            Debug.Log("Error" + www.error);

        }

 

        StartCoroutine(this.GetScoreList());

    }

 

    public IEnumerator GetScoreList()

    {

        WWWForm form = new WWWForm();

        //设置要传递的参数

        form.AddField("seq_no", seqNo);

 

        //调用URL

        var www = new WWW(urlScoreList, form);

        //等待完成

        yield return www;

        if (string.IsNullOrEmpty(www.error))

        {

            Debug.Log(www.text);

            //调用显示分数的函数

            DispScoreList(www.text);

        }

        else

        {

            Debug.Log("Error" + www.error);

        }

    }

 

    //解析JSON文件并显示分数的函数

    void DispScoreList(string strJsonData)

    {

        //解析JSON文件

        var N = JSON.Parse(strJsonData);

        //根据JSON对象数组大小循环

        for (int i = 0; i < N.Count; i++)

        {

            int ranking = N[i]["ranking"].AsInt;

            string userName = N[i]["user_name"].ToString();

            int killCount = N[i]["kill_count"].AsInt;

            //将结果值显示到控制台视图

            Debug.Log(ranking.ToString() + userName + killCount.ToString());

        }

 

    }

}

本示例中,排名信息以JSON格式传递,脚本需要使用SimpleJSON,所以在DataMgr脚本的开始部分添加了using SimpleJSON以声明相应的命名空间。

将分数保存到数据库后,脚本访问了get_score_list.php以获取排名信息。Get_score_list.php中生成的JSON格式的消息如下所示。

[

{"ranking":"1","user_name":"Zack","kill_count":"17"},

{"ranking":"2","user_name":"Penzer",kill_count":"9"}

]

运行游戏,操作坦克互相攻击,可在控制台视图中看到从数据库获取的结果值,如图所示。

 

Unity5权威讲解第十四章第十节内容 【在Unity中连接数据库】

本博文参考:Unity5权威讲解,【韩】李在贤 著 孔雪玲 译,ISBN 978-7-115-43636-8