MMO 地图传送,UI系统框架设计

地图传送

 创建传送点

建碰撞器触发

//位置归零

建一个传送门cube放到要传送的位置(这个teleporter1是传出的区域

这是从另一张地图传入时的传送门

创建一个脚本TeleporterObject给每个传送cube都绑上脚本

通过脚本,让传送门在编辑器下面还能绘制出来

给每个传送点编号

注意!这里的传送点cube要设置Layer:Teleport:因为角色(层级是Defalut)会触发传送点;而Default之间不能碰撞

把特效挂在传送点上

//把野外场景的传送也加上(并把传送门的id改了

碰撞检测

TelePorterObject:OnTriggerEnter

private void OnTriggerEnter(Collider other)
{PlayerInputController playerInputController=other.GetComponent<PlayerInputController>();//传入的对象是否有玩家控制器if(playerInputController!=null&&playerInputController.isActiveAndEnabled){//得到传送点的IDTeleporterDefine teleDefine = DataManager.Instance.Teleporters[this.ID];if(teleDefine==null){//从角儿控制器取得角色character,第几个传送点Debug.LogErrorFormat("TeleporterObject: Character [{0}] Enter Teleporter [{1}] ,But TeleporterDefine not existed", playerInputController.character.Info.Name, this.ID);return;}Debug.LogFormat("TeleporterObject: Character[{0}] Enter Telepoter [{1}:{2}] ",playerInputController.character.Info.Name, teleDefine.ID,teleDefine.Name); ;if(teleDefine.LinkTo>0){if(DataManager.Instance.Teleporters.ContainsKey(teleDefine.LinkTo))MapService.Instance.SendMapTeleporter(this.ID);else Debug.LogErrorFormat("Teleporter ID:{0} LinkID {1} error!",teleDefine.ID,teleDefine.LinkTo);   }}
}

在MapService中发送进入传送点的信息SendMapTeleporter

SendMapTeleporter

public void SendMapTeleport(int teleporterID)
{Debug.LogFormat("MapTeleporterRequest :teleporterID:{0}", teleporterID);NetMessage message = new NetMessage();message.Request = new NetMessageRequest();message.Request.mapTeleport = new MapTeleportRequest();message.Request.mapTeleport.teleporterId = teleporterID;NetClient.Instance.SendMessage(message);
}

向客户端发送有角色进入传送点的信息

message MapTeleportRequest
{int32 teleporterId = 1;
}

只需要传一个传送点id即可(也可以传地图的id,再传送点的id)

 服务端的协议处理MapService:OnMapTeleport

在MapService()中, 

订阅:

     MessageDistributer<NetConnection<NetSession>>.Instance.Subscribe<MapTeleportRequest>(this.OnMapTeleport);

void OnMapTeleport(NetConnection<NetSession> sender,MapTeleportRequest request)
{//得到客户端进行传送点传送的对象Character character=sender.Session.Character;Log.InfoFormat("OnMapTeleporter: characterID:{0}:{1} TeleporterId:{2}", character.Id, character.Data, request.teleporterId);//没有该传送点if(!DataManager.Instance.Teleporters.ContainsKey(request.teleporterId)){Log.WarningFormat("Source TeleporterID[{0}] not existed", request.teleporterId);return;}TeleporterDefine teleportDefine=DataManager.Instance.Teleporters[request.teleporterId]; if(teleportDefine.LinkTo==0||!DataManager.Instance.Teleporters.ContainsKey(teleportDefine.LinkTo)){Log.WarningFormat("Source TeleporterID [{0}] LinkTo ID [{1}] not existed", request.teleporterId, teleportDefine.LinkTo);}//从客户端传过来的传送点数据表teleportDefine.LinkTo:6 //取的key为6 传送目标点TeleporterDefine teleporterDefine1 = DataManager.Instance.Teleporters[teleportDefine.LinkTo];//角色所在的地图,角色离开处理MapManager.Instance[teleportDefine.MapID].CharacterLeave(character);//把新位置信息填充给角色character.Position=teleporterDefine1.Position;character.Direction=teleporterDefine1.Direction;//角色进入新地图MapManager.Instance[teleporterDefine1.MapID].CharacterEnter(sender,character);
}

//关于传送点配置表TeleporterDefine:

点击这里查看是否有TeleporterDefine配置表生成

扩展编辑器MapTool

在Asset/Editor目录下:

首先把DataManager(角色,传送门,地图之类的信息加载Load

获取当前场景

获取所有传送点

遍历所有的地图,得到地图文件.unity;打开每个场景

获取传送点,检查所有的传送点id在配置表中是否存在

传送点teleportDefine对应的地图id是否正确

把世界坐标转换成逻辑坐标存到配置表中

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.SceneManagement;
using UnityEditor.SceneManagement;
using UnityEditor;
using Common.Data;
public class MapTool : MonoBehaviour
{[MenuItem("Map Tools/Export Teleportters")]//扩展功能:staticpublic static void ExportTeleporters(){DataManager.Instance.Load();Scene current=EditorSceneManager.GetActiveScene();string currentScene=current.name;//把当前场景记录下来,并检查有无保存if(current.isDirty){EditorUtility.DisplayDialog("提示", "请先保存当前场景", "确定");return;}List<TeleporterObject> allTeleporters=new List<TeleporterObject>();foreach(var map in DataManager.Instance.Maps){//根据地图里配置名字生成原始路径string sceneFile = "Assets/Levels/" + map.Value.Resource + ".unity";if(!System.IO.File.Exists(sceneFile)){//判断每一个场景文件是否存在Debug.LogWarningFormat("Scene {0} not existed!", sceneFile);continue;}//打开单个场景EditorSceneManager.OpenScene(sceneFile,OpenSceneMode.Single);//检查所有的传送点TeleporterObject[] teleporters=GameObject.FindObjectsOfType<TeleporterObject>();    foreach(var teleporter in teleporters){Debug.Log("传送点ID" + teleporter.ID);if(!DataManager.Instance.Teleporters.ContainsKey(teleporter.ID)){//检查传送点的id在配置表中是否存在EditorUtility.DisplayDialog("错误", string.Format("地图:{0} 中配置的 Teleporter:[{1}]中不存在", map.Value.Resource, teleporter.ID), "确定");return;}TeleporterDefine def=DataManager.Instance.Teleporters[teleporter.ID];if (def.MapID != map.Value.ID){//地图配的mapID是否正确EditorUtility.DisplayDialog("错误", string.Format("地图:{0} 中的配置的Teleporter:[{1}] MapID:{2} 错误", map.Value.Resource,teleporter.ID,def.MapID), "确定");return;}def.Position=GameObjectTool.WorldToLogicN(teleporter.transform.position);def.Direction=GameObjectTool.WorldToLogicN(teleporter.transform.forward);}}//Save逻辑写在DataMangaer下,运行时是不会受影响的DataManager.Instance.SaveTeleporters();EditorSceneManager.OpenScene("Assets/Levels/" + currentScene + ".unity");EditorUtility.DisplayDialog("提示", "传送点导出完成", "确定");}}

演示:

传送成功;

 传送请求:1号传送点传送到野外的6号点

//从野外传回主城

5号传送点,传LinkTo2号传送点

//但是在野外的相机没有对着角色;在两个场景的切换时,角色会浮空

//Add:可以在场景切换时做一个Loading进度条掩盖

->Map01只有MainPlayerCamera带过来的相机发挥跟随角色的作用//创建角色时相机已经挂上了,删掉野外的一个Camera即可

关于到了新的场景中固定UI没有显示

把UIMainCity做成单例

(在加载新场景时UIMainCity会再创建实例

//可以看到现在加载到另一个场景,显示了UIMainCity和MainPlayerCamera以及UIWorldElementManager等;还有一些在每个场景中必要的GameObject:

//它们都是挂了单例脚本的物体

UI系统框架设计

UI的分类:

UI框架的设计:

补充:断开连接角色处理

 关于在客户端与服务器断开连接,服务器不重启,重启客户端;DisConnected->Connected

登入主城发现客户端界面 有两个角色:因此每次断开连接时,要把数据session全部清理掉

在NetService:Disconnected方法中加上这://作用时清理数据

 在NetSession中做修复Disconnected

删掉角色所有信息

internal void Disconnted()
{if(this.Character!=null)//角色离开UserService.Instance.CharacterLeave(this.Character);    
}

UserService:CharacterCreate

对于用户离开游戏OnGameLeave,里面有RemoveCharacter和map[mapid].CharacterLeave

我们重构这两句

并改成公有的://这样NetSession就可以引用了

演示

没有做断开连接角色处理的服务器页面:

没有角色离开

再进入主城是有上一次客户端数据的残留

进入主城后关掉客户端

已经做角色离开了:CharacterLeave

在启动客户端,进入主城

地图上只有一个角色

 //关于刷新数据

例如小地图的mapImage

//小地图需要在世界场景下加一个BoundingBox;根据当前角色的位置更新在小地图上的位置

需要将每次切换场景时把角色数据都拉一次进来

在UIMinmap.cs中,只有在启动时才加载了小地图

UIMain

UIMainCity更名为UIMain//对应脚本也改掉

把UIMain做成了单例,这样每个场景都能有固定UI(小地图,技能栏;初次出现是在MainCity场景中,后面可以在这个场景下的UIMain节点下做各种UI物体

把initmap改为updatemap

UIMain.cs

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using Models;
using Services;
public class UIMain : MonoSingleton<UIMain>
{public Text avatarName;public Text avatarLevel;protected override void OnStart(){//在启动时候刷新this.UpdateAvatar();}void UpdateAvatar(){//User是单例类,存放用户和角色的各种相关信息//CurrentCharacter存储网络传回来的信息(姓名角色等级..)this.avatarName.text = string.Format("{0}[{1}]", User.Instance.CurrentCharacter.Name, User.Instance.CurrentCharacter.Id);this.avatarLevel.text = User.Instance.CurrentCharacter.Level.ToString();}void Update(){}public void BackToCharSelect(){SceneManager.Instance.LoadScene("CharSelect");UserService.Instance.SendGameLeave();}}

切换地图,要换的小地图数据,在MinimapManager中管理这些数据

同时小地图管理器要知道小地图是哪个,这样就能对不同的小地图进行统一管理

现在的MinimapManager:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using UnityEngine;
using UnityEngine.Analytics;
using Models;
namespace Managers
{class MinimapManager : Singleton<MinimapManager>{public UIMinmap UIminimap;private Collider minimapBoundingBox;public Collider MinimapBoundingBox{get { return minimapBoundingBox; }}public Transform PlayerTransform{get{if (User.Instance.CurrentCharacterObject == null)return null;return User.Instance.CurrentCharacterObject.transform;}}public Sprite LoadCurrentMinimap(){//返回图片所在的路径:图片资源放在了Resources下面//这里用拼接字符串形成了完整路径return Resloader.Load<Sprite>("UI/Minimap/" + User.Instance.CurrentMapData.MiniMap);}public void UpdateMinimap(Collider minimapBoundingBox){//minimapBoundingBox change->告诉小地图:他变了this.minimapBoundingBox=minimapBoundingBox;if (this.UIminimap != null)this.UIminimap.UpdateMap();}}
}

在UIMinmap中引入minimap对象

于是我们就能在MinimapManager管理器中做小地图的更新UpdateMinimap

 public void UpdateMinimap(Collider minimapBoundingBox){//minimapBoundingBox change->告诉小地图:他变了this.minimapBoundingBox=minimapBoundingBox;if (this.minimap != null)this.minimap.UpdateMap();}

在此方法中又调用UIMinimap中更新小地图的方法:UpdateMap

原来的方法中用的minmapBoundingBox在主城中通过public得到的,现在需要更新它

注意!每次切换地图是角色是重新创建的,角色的信息都会被删除,因此我们要把角色清空掉

如果不清空的话,Update里面的就不会更新了;

注意!现在小地图不要需要这一句:

切换场景(地图变化)时调用UpdateMinimap

MinimapManager:UpdateMinimap
public void UpdateMinimap(Collider minimapBoundingBox)
{//minimapBoundingBox change->告诉小地图:他变了this.minimapBoundingBox=minimapBoundingBox;if (this.UIminimap != null)this.UIminimap.UpdateMap();
}

如果每个地图有一个唯一的脚本,地图加载的时候脚本就执行

->在每个场景下创建一个MapRoot,再新建一个地图控制器MapController;

当前地图已经加载了就通知小地图管理器,更新小地图,并传入一个包围盒

MapController
 public Collider minimapBoundingbox;void Start(){MinimapManager.Instance.UpdateMinimap(minimapBoundingbox);}
总结

地图控制器把包围传给-----小地图管理器的UpdateMinimap方法,传给-----小地图UpdateMap方法

MapController:

        MinimapManager.Instance.UpdateMinimap(minimapBoundingbox);

MinimapManager:

                this.UIminimap.UpdateMap();

UIminimap

        this.minmapBoundingBox = MinimapManager.Instance.MinimapBoundingBox;

->UIMain是单例,UIMain下面有UIMinimap:

把每一个场景都做一个MapRoot绑上地图控制器拖上包围盒

启动演示:

//Add可以加一个加速按钮(背包里的滑板车//未做
UIManager

//是Singleton单例

各种弹出ui(如商店,NPC对话,任务栏)的共同事件汇总(框架)

UI元素(已经做好的prefab//被放在Resources/UI下面

展示面板:show

关闭面板:close

//里面做一些实例化或销毁

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System;
public class UIManager : MonoSingleton<UIManager>
{class UIElement{//UI元素public string Resources;//资源路径public bool Cache;public GameObject Instance;}//用来保存定义的UI信息private Dictionary<Type,UIElement>UIResources=new Dictionary<Type, UIElement>();public UIManager(){this.UIResources.Add(typeof(UITest),new UIElement() { Resources="UI/UITest",Cache=true});}~UIManager(){}public T Show<T>(){//声音播放//SoundManager.Instance.PlaySound("ui_open");Type type = typeof(T);if(this.UIResources.ContainsKey(type)){UIElement UIElementinfo=this.UIResources[type];if(UIElementinfo.Instance!=null){//如果这个UI元素有实例了,激活UIElementinfo.Instance.SetActive(true);}else{//从资源中加载prefabUnityEngine.Object prefab=Resources.Load(UIElementinfo.Resources);if(prefab==null){return default(T);  }//实例化UIElementinfo.Instance=(GameObject)GameObject.Instantiate(prefab);  }return UIElementinfo.Instance.GetComponent<T>();}return default(T);}public void Close(Type type){//SoundManager.Instance.PlaySound("ui_close");if(this.UIResources.ContainsKey(type)){UIElement UIElementinfo=this.UIResources[type];if(UIElementinfo.Cache)//如果启用了Cache则不销毁UIElementinfo.Instance.SetActive(false);//?else{GameObject.Destroy(UIElementinfo.Instance);UIElementinfo.Instance = null;}}}
}
UIWindows

委托接受UIWindows对象,和WindowsResult结果对象

委托类型 的OnClose事件

获取类型,结果类型

Close方法:有窗口才关闭

yes/no按钮的事件

using System.Collections;
using System.Collections.Generic;
using UnityEngine;public abstract class UIWindows : MonoBehaviour
{//给所有的UI当父类用public delegate void CloseHandler(UIWindows sender, WindowResult result);public event CloseHandler OnClose;public virtual System.Type Type{//获取类型get{return this.GetType();  }}//内置了一个结果类型public enum WindowResult{None=0,Yes,No,}public void Close(WindowResult result=WindowResult.None){//做UIManager.Close;并且OnClose关闭窗口事件UIManager.Instance.Close(this.Type);if(this.OnClose!=null)this.OnClose(this,result);this.OnClose = null;}public virtual void OnCloseClick(){//用来关闭this.Close();}public virtual void OnYesClick(){//用来确认this.Close(WindowResult.Yes);}private void OnMouseDown(){//一个测试检测鼠标有没有按下Debug.LogFormat(this.name + " Clicked");}
}

写一个关于UIManager为框架,UIWindows的子类:UITest

UITest

先把UI面板做好prefab放在Resources/UI

 UITest脚本:

//继承UIWindows即可

using System.Collections;
using System.Collections.Generic;
using UnityEngine;public class UITest : UIWindows
{
}

在UITest画布下要给按钮绑定事件,可以找到UIWindows的按钮事件

把做好的UITest画布放在

在UIManage中:

要先把UITest加到管理器中,管理器才能使用它:
 

        this.UIResources.Add(typeof(UITest),new UIElement() { Resources="UI/UITest",Cache=true});

//后面若有UIShopCanvas;类似该语句添加

测试新加上来的UITest:

在UIMain中加一个按钮可以打开UITest

在UIMain中加一个测试事件

public void OnClickTest()
{UIManager.Instance.Show<UITest>();
}

把事件绑到这些按钮上

演示:

在OnClickTest中执行一些UITest的方法

public void OnClickTest()
{UITest uitest=UIManager.Instance.Show<UITest>();//可以用uitest调用UItest的方法uitest.SetTitle("新标题");
}
public class UITest : UIWindows
{public Text Title;public void SetTitle(string title){this.Title.text = title;}
}

//注意:UIManager继承的是普通单例,不是mono单例;不需要挂在场景中

Test_OnClose是UIWindows的方法,可以直接获取UITest的信息sender和UI窗口的点击情况

 public void OnClickTest(){UITest uitest = UIManager.Instance.Show<UITest>();//可以用uitest调用UItest的方法uitest.SetTitle("新标题");uitest.OnClose += Test_OnClose;}private void Test_OnClose(UIWindows sender,UIWindows.WindowResult result){//OnClose获取结果;即调用者负责获取调用的结果uitest.OnClose//例如在改名后点击确认按钮,可以获取到改的名字是什么//(sender as UITest).name//在调用前或者后可以任意访问UI的各种值MessageBox.Show("点击了对话框的:" + result, "对话框响应结果", MessageBoxType.Information);}

点击确定和关闭按钮的MessageBox.Show:

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/420741.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

GIT | git提交注释自动添加信息头

GIT | git提交注释自动添加信息头 时间&#xff1a;2024年9月6日10:20:11 文章目录 GIT | git提交注释自动添加信息头1.操作2.commit-msg文件 1.操作 2.commit-msg文件 #!/bin/sh # # An example hook script to check the commit log message. # Called by "git commit&q…

基于SpringBoot+Vue+MySQL的流浪猫狗宠物救助救援网站管理系统

系统展示 用户前台界面 管理员后台界面 系统背景 在当今社会&#xff0c;随着宠物数量的激增及人们关爱动物意识的提升&#xff0c;流浪猫狗问题日益严峻。为解决这一问题&#xff0c;构建一套高效、便捷的流浪猫狗宠物救助救援网站管理系统显得尤为重要。本系统基于SpringBoot…

CSP-CCF★★★201812-2小明放学★★★

目录 一、问题描述 二、解答 &#xff08;1&#xff09;注意&#xff1a; &#xff08;2&#xff09;80分版&#xff1a; &#xff08;3&#xff09;100分版&#xff1a; 三、总结 一、问题描述 二、解答 &#xff08;1&#xff09;注意&#xff1a; 题目的n小于等于10的…

m3u8网页视频文件爬取与视频合成

文章目录 m3u8网页视频文件爬取与视频合成下载m3u8文件下载m3u8文件列表所对应的ts文件下载ffmpeg m3u8网页视频文件爬取与视频合成 我们经常在网络上找到的自己想要的视频素材却无法下载&#xff0c;并且打开控制台一看视频是通过分割成一份份的.ts文件发送过来的。 下载m3u8…

零信任安全:重新思考数字世界的访问

目录 ​编辑 网络安全形势的演变 数字安全的变化 引入零信任安全 零信任的当今意义 了解零信任原则 零信任架构的核心概念 实施微分段 持续验证&#xff1a;积极主动的立场 与传统安全模型的对比 在现代企业中实施零信任 零信任实施基础知识 多重身份验证 (MFA) 的…

c++(继承、模板进阶)

一、模板进阶 1、非类型模板参数 模板参数分类类型形参与非类型形参。 类型形参即&#xff1a;出现在模板参数列表中&#xff0c;跟在class或者typename之类的参数类型名称。 非类型形参&#xff0c;就是用一个常量作为类(函数)模板的一个参数&#xff0c;在类(函数)模板中…

非监督式机器学习:群集

聚类分析是一种非监督式机器学习形式&#xff0c;在此形式下&#xff0c;基于观察值的数据值或特征的相似性&#xff0c;将观察值分组到群集中。 这种就是非监督式机器学习&#xff0c;因为它不使用先前已知的标签值来训练模型。 在聚类分析模型中&#xff0c;标签是群集&#…

帧缓冲 framebuffer

一、基本概念 framebuffer: 帧缓存、帧缓存&#xff08;显示设备&#xff09; Linux内核为显示提供的一套应用程序接口。&#xff08;驱动内核支持&#xff09; 分辨率&#xff1a; 像素点 显示屏&#xff1a;800 * 600&#xff08;横向有800个像素点&#xff0c;纵向有60…

DAY73

作业 pro文件&#xff1a; QT texttospeech 头文件&#xff1a; #ifndef WIDGET_H #define WIDGET_H#include <QWidget> #include <QPushButton> //按钮类 #include <QLabel> //标签类 #include <QLineEdit> //行编译器类 #include…

阿里中间件——diamond

一、前言 最近工作不忙闲来无事&#xff0c;仔细分析了公司整个项目架构&#xff0c;发现用到了很多阿里巴巴集团开源的框架&#xff0c;今天要介绍的是中间件diamond. 二、diamond学习笔记 1、diamond简介 diamond是一个管理持久配置&#xff08;持久配置是指配置数据会持久化…

【Datawhale X 李宏毅苹果书 AI夏令营】《深度学习详解》Task3 打卡

文章目录 前言学习目标一、优化策略二、模型偏差三、优化问题三、过拟合增加训练集给模型一些限制 四、交叉验证五、不匹配总结 前言 本文是【Datawhale X 李宏毅苹果书 AI夏令营】的Task3学习笔记打卡。 学习目标 李宏毅老师对应视频课程&#xff1a;https://www.bilibili.…

QDY421F-16P-25液氨不锈钢液动紧急切断阀

一、产品概述 QDY421F-16P-25液氨不锈钢液动紧急切断阀&#xff0c;采用先进的液动驱动技术&#xff0c;结合高质量的不锈钢材质&#xff0c;专为满足液氨等腐蚀性介质的紧急切断需求而设计。该阀门的工作压力可达16MPa&#xff0c;适用于DN25&#xff08;即25毫米&#xff09;…

系统架构师考试学习笔记第四篇——架构设计实践知识(18)面向服务架构设计理论与实践

本章考点&#xff1a; 第18课时主要学习面向服务架构设计理论与实践。根据考试大纲&#xff0c;本课时知识点会涉及单选题型&#xff08;约占2~5分&#xff09;和案例题&#xff08;25分&#xff09;&#xff0c;本课时内容偏重于方法的掌握和应用&#xff0c;根据以往全国计算…

时序预测|基于小龙虾优化高斯过程GPR数据回归预测Matlab程序COA-GPR 多特征输入单输出 附赠基础GPR

时序预测|基于小龙虾优化高斯过程GPR数据回归预测Matlab程序COA-GPR 多特征输入单输出 附赠基础GPR 文章目录 一、基本原理二、实验结果三、核心代码四、代码获取五、总结 时序预测|基于小龙虾优化高斯过程GPR数据回归预测Matlab程序COA-GPR 多特征输入单输出 附赠基础GPR 一、…

mysql高级sql

文章目录 一&#xff0c;查询1.按关键字排序1.1按关键字排序操作(1)按分数排序查询&#xff08;不加asc默认为升序&#xff09;(2)按分数降序查询&#xff08;DESC&#xff09;(3)使用where进行条件查询(4)使用ORDER BY语句对多个字段排序 1.2使用区间判断查询&#xff08;and/…

如何通过内网穿透实现Pycharm远程服务器编译项目与服务器代码同步

文章目录 前言一、前期准备1. 检查IDE版本是否支持2. 服务器需要开通SSH服务 二、Pycharm本地链接服务器测试1. 配置服务器python解释器 三、使用内网穿透实现异地链接服务器开发1. 服务器安装Cpolar2. 创建远程连接公网地址 四、使用固定TCP地址远程开发 前言 本文主要介绍如…

Unity1 Prefab

修改预设体 进入预设体面板来改 在Hierarchy中可以给预制体添加对象 第一种方法&#xff1a;添加了之后把Hierarchy中的预制体拖到Project中的预制体上 就可以修改原本的预制体 第二种方法&#xff1a;添加了之后在inspector中 点revert 就是重置所有预制体 添加的就没有…

如何远程实时监控员工的电脑屏幕?远程桌面监控的五个可实现方法分享

想象一下&#xff0c;你在办公室喝着咖啡&#xff0c;员工的电脑屏幕却在数百公里之外实时呈现在你的眼前。你可以看到他们在干什么&#xff0c;是埋头工作还是悄悄摸鱼&#xff1f;远程桌面监控让这一切变得触手可及&#xff0c;简直像给了管理者一双“千里眼”&#xff01; 如…

Mysql(二) - 约束, 进阶查询

目录 一.约束 1.not null 2.unique 3.default 4.primary key 5. foreign key 6.check 7. 综合使用 二.进阶查询 1.新增(插入查询的结果) 2.聚合查询 a.聚合函数 b.使用 3.分组查询 4.联合查询 a.内连接 b.外连接 c.自连接 d.子查询 5.合并查询 三.总结 一…

【Unity】简易而又实用的抽卡算法

1.两个数中任选一个&#xff08;抛硬币&#xff09; 基础版本&#xff1a; public int RandomBetweenTwoNumber(int a,int b) {float random Random.Range(0,1f);return radom<0.5f ? a : b ; } 升级版本&#xff08;支持概率调整&#xff09;&#xff1a; /*pa表示“…