Script
MainController.cs
using System;
using System.Collections.Generic;
using UnityEngine;
using BestHTTP.WebSocket;
using LitJson;
public clast MainController : MonoBehaviour
{
private int middleX = 0;
private int middleZ = 0;
private int R = 20; // 半径
// GameObject
private Dictionary planetGroup = new Dictionary();
private UnityEngine.Object planetObj;
public Camera mainCamera; // 主摄像机
public GameObject[] flash; // 炮弹结合
public GameObject centerCube; // 中间参照定位方块
public GameObject AnimateRock; // 彩蛋动画陨石
// UI
public GameObject satleText;
public GameObject timeText;
public GameObject roundText;
public GameObject messageBoard;
// 排行榜
public Transform rankListContent; // 列表 Content
private GameObject rankItemPrefab; // 单个 Item Prefab
private List rankItems; // 存放 Item Prefab 实例
// WebSocket
private WebSocket webSocket;
private int round = 1;
private string imageBaseURL = "";
public int roundTime = 300; //默认 300s 一轮
public string url = "";
// Start is called before the first frame update
void Start()
{
this.LoadConfigFile();
this.planetObj = Resources.Load("Planet");
this.timeText.GetComponent().timeSecond = this.roundTime;
this.rankItemPrefab = Resources.Load("RankItem") as GameObject;
this.rankItems = new List();
// Init websocket
webSocket = new WebSocket(new Uri(url));
webSocket.OnOpen = OnOpen;
webSocket.OnMessage = OnMessageReceived;
webSocket.OnError = OnError;
webSocket.OnClosed = OnClosed;
webSocket.Open();
}
void LoadConfigFile()
{
INIParser iniParser = new INIParser();
iniParser.Open(Application.streamingastetsPath + "/asteroid.ini");
this.url = iniParser.ReadValue("connect", "url", "ws://localhost:19999/api/asteroid");
this.R = iniParser.ReadValue("scene", "radius", 20);
this.imageBaseURL = iniParser.ReadValue("connect", "image_url", "http://localhost:19999/api/uploads/");
iniParser.Close();
}
void OnOpen(WebSocket ws)
{
Debug.Log("connecting...");
}
// 接受信息
void OnMessageReceived(WebSocket ws, string msg)
{
JsonData recieveData = JsonMapper.ToObject(msg);
switch (recieveData["Type"].ToString())
{
case "init":
this.satleText.GetComponent().text = recieveData["Data"]["satle"].ToString();
// 初始化队伍星球
JsonData teams = recieveData["Data"]["Team"];
int count = teams.Count;
float singleAngle = 360 / count;
// 刷新排行榜
this.UpdateRankList(teams);
for (int i = 0; i < count; i++)
{
// 星球排列成圆形
Vector3 position = new Vector3(middleX + this.R * Mathf.Sin(i * (singleAngle / 180 * Mathf.PI)), .0f, middleZ + this.R * Mathf.Cos(i * (singleAngle / 180 * Mathf.PI)));
GameObject planet = Instantiate(this.planetObj, position, Quaternion.idensaty) as GameObject;
planet.GetComponent().SetPosition(position);
planet.GetComponent().SetTeamName(teams[i]["Name"].ToString());
planet.GetComponent().SetScoreRank(int.Parse(teams[i]["Score"].ToString()), int.Parse(teams[i]["Rank"].ToString())); // 设置初始分数、排名
// 不显示状态
planet.GetComponent().SetAttack(false);
planet.GetComponent().SetDown(false);
planet.GetComponent().MainCamera = this.mainCamera; // 设置主摄像机
planet.GetComponent().CenterCube = this.centerCube; // 设置中间点方块
//使用队伍 ID 作为索引
this.planetGroup[int.Parse(teams[i]["Id"].ToString())] = planet;
}
// 设置时间、轮数
int time = int.Parse(recieveData["Data"]["Time"].ToString());
timeText.GetComponent().SetTime(time);
this.round = int.Parse(recieveData["Data"]["Round"].ToString());
roundText.GetComponent().text = "第 " + this.round + " 轮";
break;
case "attack":
// 接收到信息,发射炮弹
int from = int.Parse(recieveData["Data"]["From"].ToString());
int to = int.Parse(recieveData["Data"]["To"].ToString());
// 随机选取一种炮弹效果
int flashIndex = UnityEngine.Random.Range(0, this.flash.Length);
// 为了视觉效果,分批发射 5 次,每次间隔 0.1s
NewAttack(this.planetGroup[from], this.planetGroup[to], flashIndex);
StartCoroutine(DelayToInvoke.DelayToInvokeDo(() =>
{
NewAttack(this.planetGroup[from], this.planetGroup[to], flashIndex);
}, 0.2f));
StartCoroutine(DelayToInvoke.DelayToInvokeDo(() =>
{
NewAttack(this.planetGroup[from], this.planetGroup[to], flashIndex);
}, 0.3f));
StartCoroutine(DelayToInvoke.DelayToInvokeDo(() =>
{
NewAttack(this.planetGroup[from], this.planetGroup[to], flashIndex);
}, 0.4f));
StartCoroutine(DelayToInvoke.DelayToInvokeDo(() =>
{
NewAttack(this.planetGroup[from], this.planetGroup[to], flashIndex);
}, 0.5f));
break;
case "rank":
// 设置队伍排行
JsonData teamRanks = recieveData["Data"]["Team"];
// 刷新排行榜
this.UpdateRankList(teamRanks);
for (int i = 0; i < teamRanks.Count; i++)
{
// 星球
this.planetGroup[int.Parse(teamRanks[i]["Id"].ToString())].GetComponent().SetScoreRank(
int.Parse(teamRanks[i]["Score"].ToString()),
int.Parse(teamRanks[i]["Rank"].ToString())
);
}
break;
case "status":
// 设置队伍状态
int teamId = int.Parse(recieveData["Data"]["Id"].ToString());
string status = recieveData["Data"]["Status"].ToString();
SetStatus(teamId, status);
break;
case "round":
// 设置回合数
this.round = int.Parse(recieveData["Data"]["Round"].ToString());
roundText.GetComponent().text = "第 " + this.round + " 轮";
break;
case "time":
// 设置剩余时间
timeText.GetComponent().SetTime(int.Parse(recieveData["Data"]["Time"].ToString()));
break;
case "clear":
teamId = int.Parse(recieveData["Data"]["Id"].ToString());
this.planetGroup[teamId].GetComponent().SetDown(false);
this.planetGroup[teamId].GetComponent().SetAttack(false);
break;
case "clearAll":
// 清空所有队伍状态
foreach (KeyValuePair item in planetGroup)
{
item.Value.GetComponent().SetDown(false);
item.Value.GetComponent().SetAttack(false);
}
break;
// 陨石彩蛋
case "easterEgg":
this.AnimateRock.GetComponent().Play("rock", -1, 0f);
break;
}
}
void OnClosed(WebSocket ws, UInt16 code, string msg)
{
Debug.Log(msg);
}
void OnError(WebSocket ws, Exception ex)
{
Debug.Log(string.Format("Status Code from Server: {0} and Message: {1}", ws.InternalRequest.Response.StatusCode, ws.InternalRequest.Response.Message));
}
// 设置队伍状态
void SetStatus(int TeamID, string Status)
{
// 清空状态
planetGroup[TeamID].GetComponent().SetAttack(false);
planetGroup[TeamID].GetComponent().SetDown(false);
switch (Status)
{
case "down":
planetGroup[TeamID].GetComponent().SetDown(true);
break;
case "attacked":
planetGroup[TeamID].GetComponent().SetAttack(true);
break;
}
}
// 抛物线攻击
void NewAttack(GameObject From, GameObject To, int flashIndex = 0)
{
Vector3[] paths = new Vector3[3];
int speed = 500;
// 炮弹实例
GameObject projectile;
projectile = Instantiate(this.flash[flashIndex], From.GetComponent().position, Quaternion.idensaty) as GameObject;
// 忽略炮弹与炮弹之间的碰撞
Physics.IgnoreLayerCollision(9, 9);
// 忽略发射者与炮弹的碰撞
Physics.IgnoreCollision(From.GetComponent(), projectile.GetComponent());
paths[0] = From.GetComponent().position;
paths[2] = To.GetComponent().position;
paths[1] = new Vector3((paths[2].x + paths[0].x) / 2, 5, (paths[2].z + paths[0].z) / 2);
projectile.GetComponent().AddForce(projectile.transform.forward * speed);
iTween.MoveTo(projectile, iTween.Hash("path", paths, "movetopath", true, "orienttopath", true, "time", 1, "easetype", iTween.EaseType.linear));
// 设置状态为被攻陷
To.GetComponent().SetAttack(true);
}
void UpdateRankList(JsonData teamRanks)
{
Dictionary rankListData = new Dictionary();
// 构造已经排序的列表
for (int i = 0; i < teamRanks.Count; i++)
{
rankListData.Add(int.Parse(teamRanks[i]["Rank"].ToString()), teamRanks[i]);
}
// 创建 rankItem 实例,之后不够的再补
int newItemCount = teamRanks.Count - rankItems.Count;
for (int i = 0; i < newItemCount; i++)
{
GameObject item = Instantiate(rankItemPrefab, rankListContent, false);
rankItems.Add(item);
}
// 刷新排行榜
for (int i = 0; i < teamRanks.Count; i++)
{
RankItem item = rankItems[i].GetComponent();
JsonData data = rankListData[i + 1];
item.SetTeamName(data["Name"].ToString());
item.SetTeamRank(data["Rank"].ToString());
item.SetTeamScore(data["Score"].ToString());
if (rankListData[i + 1]["Image"] != null)
{
string imageURL = rankListData[i + 1]["Image"].ToString();
if (imageURL != "")
{
StartCoroutine(item.SetTeamLogo(imageBaseURL + "/" + imageURL));
}
}
}
}
// Update is called once per frame
void Update()
{
// 更新下一轮
if (this.timeText.GetComponent().timeSecond == 0)
{
this.timeText.GetComponent().timeSecond = this.roundTime;
this.round++;
this.roundText.GetComponent().text = "第 " + this.round.ToString() + " 轮";
}
}
}