用django管理云端数据
配置环境变量
vim .bashrc
在里面添加
export PATH=...:/home/[ 用户名 ]/.local/bin:$PATH
//在外面
source .bashrc
在终端里
django-admin startproject app
//去settings.py里配置一下allowd_hosts;
//测试能否正常运行项目
//去把8080端口打开
python manage.py runserver 0.0.0.0:8080
//创建app
python3 manage.py startapp fps
//更新一下数据库之后,访问admin
python3 manage.py migrate
//创建一个后端管理员账号
//wxx
//123
python3 manage.py createsuperuser
//如果出现了django.db.utils.OperationalError: attempt to write a readonly database的错误
sudo chmod 666 db.sqlite3
把fps中的apps.py中的类要写入settings.py
在settings.py中
...
INSTALLED_APPS = [
'fps.apps.FpsConfig',
...
]
...
编写一个简单的逻辑来验证是否项目正常
在view.py里
from django.http import HttpResponse
def index(request):
return HttpResponse("我的后端页面!!!")
在urls.py里
from django.urls import include, path
from fps.views import index
urlpatterns = [
path('', index, name='index'),
]
在总urls.py里
from django.contrib import admin
from django.urls import path, include
urlpatterns = [
path('admin/', admin.site.urls),
path('fps/', include('fps.urls')),
]
建一个表来存储room的数据
在models.py中
from django.db import models
# Create your models here.
class Room(models.Model):
name = models.CharField(max_length=100, default="Room")
port = models.IntegerField(default=7777)
def __str__(self):
return self.name + '--' + str(self.port)
在终端里
//更新数据库
python3 manage.py makemigrations
python3 manage.py migrate
在admin.py中
//让创建的Room表能在admin页面显示出来
from django.contrib import admin
from fps.models import Room
admin.site.register(Room)
编写查看,创建,删除房间的函数
在view.py里
from django.shortcuts import render
#要用JsonResponse来return
from django.http import HttpResponse, JsonResponse
#将room表引进来
from fps.models import *
def index(request):
return HttpResponse("我的后端页面!!!")
#获取房间列表
def get_room_list(request):
#需要返回的列表
rooms = []
#以端口号排一下序
for room in Room.objects.all().order_by('port'):
rooms.append({
#字典是由零个或多个键值对(key - value pairs)组成的
#列表里面的元素可以是字典元素
'name': room.name,
'port': room.port,
})
return JsonResponse({
'error_message': "success",
'rooms': rooms,
});
def build_room(request):
#遍历已设定好的端口号
for port in [7777, 7778, 7779]:
#如果Room表中现在没有这个房间,代表可以创建
if not Room.objects.filter(port=port).exists():
#可以把创建的变量取出来用于返回
room = Room.objects.create(port=port, name="Room-%d" % port)
return JsonResponse({
'error_message': "success",
'name': room.name,
'port': room.port,
})
#也有可能没有房间了
return JsonResponse({
'error_message': "no port available",
})
#删除房间
def remove_room(request):
#通过http来获取要删的port
port = request.GET.get('port')
Room.objects.filter(port=port).delete()
return JsonResponse({
'error_message': "success",
})
添加路由
在urls.py里
from django.urls import include, path
from fps.views import *
urlpatterns = [
path('', index, name='index'),
path('get_room_list/', get_room_list, name='get_room_list'),
path('build_room', build_room, name='build_room'),
path('remove_room', remove_room, name='remove_room'),
]
用git维护后端代码
在终端里
git config --global user.name "w xx"
git config --global user.email "2394891653@qq.com"
git init
ls -a //会看到.git
ssh-keygen
cd .ssh/
cat id_rsa.pub
//将公钥复制出来,应该是让git能访问服务器的用户
在终端里
git remote add origin git@git.acwing.com:Halfprefc/fps.git
git add .
git commit -m "Initial commit"
git push --set-upstream origin master
实现unity端与后端的连接
创建两个按钮
在networkManagerUI里
public class NetWorkManagerUI : MonoBehaviour
{
[SerializeField]
private Button refresh;
[SerializeField]
private Button build;
[SerializeField]
private Button room1;
[SerializeField]
private Button room2;
// Start is called before the first frame update
void Start()
{
setConfig();
initButton();
RefreshRoomList();
}
private void setConfig()
{
//System.Environment.GetCommandLineArgs()可以返回向程序传入的所有命令行参数
var args = System.Environment.GetCommandLineArgs();
//加一个改ip
for (int i = 0; i < args.Length; i++)
{
if (args[i] == "-ip")
{
string ip = args[i + 1];
var transport = GetComponent<UNetTransport>();
transport.ConnectAddress = ip;
}
}
//两个for循环的顺序不能变
for (int i = 0; i < args.Length; i++)
{
if (args[i] == "-port")
{
//将“-port”的下一个参数转为int
int port = int.Parse(args[i + 1]);
var transport = GetComponent<UNetTransport>();
transport.ConnectPort = transport.ServerListenPort = port;
}
}
for (int i = 0; i < args.Length; i++)
{
if (args[i] == "-launch-as-server")
{
//通过NetworkManager.Singleton可以方便地从任何脚本中访问这个唯一的网络管理实例
NetworkManager.Singleton.StartServer();
DestroyAllButtons();
}
}
}
//编写按钮逻辑
private void initButton()
{
refresh.onClick.AddListener(() =>
{
RefreshRoomList();
});
room1.onClick.AddListener(() =>
{
var transport = GetComponent<UNetTransport>();
transport.ConnectPort = transport.ServerListenPort = 7777;
NetworkManager.Singleton.StartClient();
DestroyAllButtons();
});
room2.onClick.AddListener(() =>
{
var transport = GetComponent<UNetTransport>();
transport.ConnectPort = transport.ServerListenPort = 7778;
NetworkManager.Singleton.StartClient();
DestroyAllButtons();
});
}
//unity发起http请求
private void RefreshRoomList()
{
StartCoroutine(RefreshRoomListRequeset("http://47.109.183.222:8080/fps/get_room_list/"));
}
IEnumerator RefreshRoomListRequeset(string uri)
{
UnityWebRequest uwr = UnityWebRequest.Get(uri);
yield return uwr.SendWebRequest();
if (uwr.result == UnityWebRequest.Result.ConnectionError)
{
Debug.Log("Error While Sending: " + uwr.error);
}
else
{
//Debug.Log("Received: " + uwr.downloadHandler.text);
print(uwr.downloadHandler.text);
}
}
//手动搓一个删除所有按钮的函数
private void DestroyAllButtons() {
Destroy(room1.gameObject);
Destroy(room2.gameObject);
Destroy(refresh.gameObject);
Destroy(build.gameObject);
}
}
将后端的结果解析成unity能识别的数据
需要单独为后端结果的不同变量创建不同的类
(相当于为字典建专门建一个类)
在Room里
//rooms.append({
// 'name': room.name,
// 'port': room.port,
//})
[System.Serializable]
public class Room
{
public string name;
public int port;
}
在GetRoomListResponse里
//return JsonResponse({
// 'error_message': "success",
// 'rooms': rooms,
//});
public class GetRoomListResponse
{
public string error_message;
public Room[] rooms;
}
在NetworkManager里
public class NetWorkManagerUI : MonoBehaviour
{
void Start()
{
...
RefreshRoomList();
}
...
//unity发起http请求
private void RefreshRoomList()
{
StartCoroutine(RefreshRoomListRequeset("http://47.109.183.222:8080/fps/get_room_list/"));
}
IEnumerator RefreshRoomListRequeset(string uri)
{
UnityWebRequest uwr = UnityWebRequest.Get(uri);
yield return uwr.SendWebRequest();
if (uwr.result == UnityWebRequest.Result.ConnectionError)
{
Debug.Log("Error While Sending: " + uwr.error);
}
else
{
//解析返回结果
var resp = JsonUtility.FromJson<GetRoomListResponse>(uwr.downloadHandler.text);
print(resp.error_message);
foreach(var room in resp.rooms)
{
print(room.name + "-" + room.port.ToString());
}
}
}
}
实现刷新房间功能
在NetworkManager里
public class NetWorkManagerUI : MonoBehaviour
{
//创建按钮,实际是对一个预制的GameObject的复制
[SerializeField]
private GameObject roomButtonPrefab;
//把menuUI搞过来是为了方便获取他的位置,按钮的位置是相对于MenuUI的
[SerializeField]
private Canvas menuUI;
...
IEnumerator RefreshRoomListRequeset(string uri)
{
UnityWebRequest uwr = UnityWebRequest.Get(uri);
yield return uwr.SendWebRequest();
//删除前所有按钮
foreach(var room in rooms)
{
room.onClick.RemoveAllListeners();
Destroy(room.gameObject);
}
rooms.Clear();
if (uwr.result == UnityWebRequest.Result.ConnectionError)
{
Debug.Log("Error While Sending: " + uwr.error);
}
else
{
//解析返回结果
var resp = JsonUtility.FromJson<GetRoomListResponse>(uwr.downloadHandler.text);
//print(resp.error_message);
int k = 0;
foreach(var room in resp.rooms)
{
GameObject buttonObj = Instantiate(roomButtonPrefab, menuUI.transform);
//相对于父组件的位置
buttonObj.transform.localPosition = new Vector3(0, 320 - k * 60, 0);
Button button = buttonObj.GetComponent<Button>();
//编辑按钮组件下的文本组件
button.GetComponentInChildren<TextMeshProUGUI>().text = room.name;
button.onClick.AddListener(() =>
{
var transport = GetComponent<UNetTransport>();
transport.ConnectPort = transport.ServerListenPort = room.port;
NetworkManager.Singleton.StartClient();
DestroyAllButtons();
});
rooms.Add(button);
k ++;
}
}
}
//手动搓一个删除所有按钮的函数
private void DestroyAllButtons() {
refresh.onClick.RemoveAllListeners();
build.onClick.RemoveAllListeners();
Destroy(refresh.gameObject);
Destroy(build.gameObject);
foreach(var room in rooms)
{
room.onClick.RemoveAllListeners();
Destroy(room.gameObject);
}
}
}