一、效果图
二、布局
1.场景布局
创建一个Panel 创建三个cube,Panel地板 两个cube设置一个绿色材质,调整Scale大小让其成为柱子形状,一个cube改名为player设置一个红色材质,当作玩家(用来演示操作的),修改相机位置就可以了。
2.设置面板布局
2.1新建一个空节点名字改为SetKeyPanle,修改属性
2.2在SetKeyPanle下新建一个image,修改名字为root,调整大小,如下图
2.3 在root下 新建Text ,修改名为Title当作标题
2.4在root下新建Scroll View组件修改属性
2.5 选择Scroll View—>Viewport—>Content对象,添加Grid Layout Group组件并修改属性
2.6 在上一步的Content下创建一个按钮改名Item,然后在这个Item下在创建两个Text,修改Item的Button组件属性
两个Text自己修改一下位置就好了,注意两个Text在父物体的孩子子级不要搞错了,第一个Text是前进,第二个是W
弄好后在吧item复制3个,有了Content的Grid Layout Group组件新建的item就不用布局了,他自动给你排列了
三、脚本思路
我们需要一个移动脚本(Player)、按键数据脚本(KeyItem)和设置面板脚本(SetKeyPanle),KeyItem脚本主要用于存储按键信息和触发修改 具体修改功能在SetKeyPanle脚本中
1.KeyItem脚本
3.1.1 获取组件 和 设置初始化按键
using System.Collections;
using System.Collections.Generic;
using UnityEngine.UI;
using UnityEngine;
using System;
public class KeyItem : MonoBehaviour
{
Text key; //按下的按键名称
Button btn; //开启按钮
[SerializeField] KeyCode keyCode;//初始化按键 需要在面板自己选择
void Start()
{
//获取组件
key = transform.GetChild(1).GetComponent<Text>();//这里我用了子物体的孩子子级来获取
btn = GetComponent<Button>();//按钮就获取他自己本身
}
}
将这个脚本赋值给item对象,我们在面板中设置他的初始化按键
3.1.2添加修改key值、修改按钮颜色、更新失败还原按键名称 方法
//修改key值
void SetKeyItemValue()
{
//当前有修改的key值
if (SetKeyPanle.GetIntance().CurrentKeyItem!=null)
{
return;
}
//当前keyitem为空时,就让它等于自己
SetKeyPanle.GetIntance().CurrentKeyItem = this; //这个要从SetKeyPanle脚本获取,是下面要讲的
//当前状态改为true 这样就可以修改按键了
SetKeyPanle.GetIntance().IsSet = true; //可修改 //这个要从SetKeyPanle脚本获取,是下面要讲的
SetBtnColor(new Color32(202, 138, 138, 255));//修改按钮颜色
key.text = "";//修改的时候text值为空
}
//修改按钮颜色
public void SetBtnColor(Color32 color)
{
btn.image.color = color; //修改颜色
}
//更新失败还原按键名称
public void Restore()
{
key.text = keyCode.ToString();
}
3.1.3最终代码
using System.Collections;
using System.Collections.Generic;
using UnityEngine.UI;
using UnityEngine;
using System;
public class KeyItem : MonoBehaviour
{
Text key; //按下的按键名称
Button btn; //开启按钮
[SerializeField] KeyCode keyCode;
public KeyCode KeyCode { get { return keyCode; }
set {
keyCode = value; //修改按键值
key.text = keyCode.ToString(); //修改按键面板要显示的Text值
} }
void Start()
{
key = transform.GetChild(1).GetComponent<Text>();
btn = GetComponent<Button>();
btn.onClick.AddListener(SetKeyItemValue);
}
//修改key值
void SetKeyItemValue()
{
//当前有修改的key值
if (SetKeyPanle.GetIntance().CurrentKeyItem!=null)
{
return;
}
//当前keyitem为空时,就让它等于自己
SetKeyPanle.GetIntance().CurrentKeyItem = this; //这个要从SetKeyPanle脚本获取,是下面要讲的
//当前状态改为true 这样就可以修改按键了
SetKeyPanle.GetIntance().IsSet = true; //可修改 //这个要从SetKeyPanle脚本获取,是下面要讲的
SetBtnColor(new Color32(202, 138, 138, 255));//修改按钮颜色
key.text = "";//修改的时候text值为空
}
//修改按钮颜色
public void SetBtnColor(Color32 color)
{
btn.image.color = color; //修改颜色
}
//更新失败还原按键名称
public void Restore()
{
key.text = keyCode.ToString();
}
}
上面有几个报错的句子先不管,写完SetKeyPanle脚本的对应方法就没错了。
2.SetKeyPanle脚本
这个脚本稍微复杂,因为逻辑处理都在这里。脚本中有详细解释
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System;
//序列化按键节点
[Serializable]
public class KeyItemNode
{
public string keyName;//按键功能名称
public KeyItem keyItem; //按键item
}
public class SetKeyPanle : MonoBehaviour
{
KeyItem currentkeyItem=null; //当前要修改的Item
//封装 用于判定当前是否有修改的按钮 没有为空
public KeyItem CurrentKeyItem { get => currentkeyItem; set => currentkeyItem = value; }
[SerializeField] List<KeyItemNode> keyItemList; //这个需要到面板赋值
Dictionary<string, KeyItem> keyItemDic; //字典存放 键值参数 (玩家移动要用,玩家脚本后面写)
public Dictionary<string, KeyItem> KeyItemDic { get => keyItemDic; set => keyItemDic = value; } //封装可以进行外部调用
[SerializeField] Transform root; //面板节点 用于控制开启关闭面板 是上面创建设置面板UI SetKeyPanle下的root
//单例 这样就可以获取这个脚本的方法进行使用了
static SetKeyPanle intance;
public static SetKeyPanle GetIntance()
{
return intance;
}
void Awake()
{
intance = this; //将自己赋值给intance
}
void Start()
{
keyItemDic = new Dictionary<string, KeyItem>();//初始化字典
//将存储的按键值 添加到字典中
for (int i = 0; i < keyItemList.Count; i++)
{
keyItemDic.Add(keyItemList[i].keyName, keyItemList[i].keyItem);
}
ClosePanel(); //关闭设置面板
}
bool isCurrentOpenState = true; //当前设置面板开启的状态 true 代表开启状态
public bool IsCurrentOpenState { get => isCurrentOpenState; set => isCurrentOpenState = value; } //封装可以进行外部调用
void Update()
{
//按下esc键开启关闭设置面板
if (Input.GetKeyDown(KeyCode.Escape))
{
//判断面板的开启状态
if (isCurrentOpenState)
{
OpenPanel(); //开启面板
}
else
{
//判断当前是修改状态,但是你没有按下按键修改而是直接esc退出时,恢复上一次按键
if (isSet)
{
//关闭后恢复当前修改键值
CurrentKeyItem.Restore();
}
ClosePanel();//关闭面板
}
isCurrentOpenState = !isCurrentOpenState;
}
}
#region 按键修改
bool isSet = false; //是否可以修改
public bool IsSet { get => isSet; set => isSet = value; }
void OnGUI()
{
//可以修改
if (isSet)
{
Event e = Event.current;//获取当前事件
if (e != null && e.isKey && e.keyCode != KeyCode.None)
{
KeyCode currentKey = e.keyCode;
//当前按键等于 ESC 时 恢复上一次按键
if (currentKey==KeyCode.Escape)
{
CurrentKeyItem.Restore();
return;
}
//判断是否按键冲突
if (IsRepeat(currentKey))
{
Debug.Log("按键重复!!");
CurrentKeyItem.Restore(); //还原按键名称
}
else
CurrentKeyItem.KeyCode = currentKey; //不重复 修改按键
CurrentKeyItem.SetBtnColor(new Color32(173, 173, 173, 255)); //还原颜色
IsSet = false;//不是修改状态
CurrentKeyItem = null; //当前没有选择按键item
}
}
}
//是否重复 true 有重复
bool IsRepeat(KeyCode keyCode)
{
//循环查找是否有相同的按键
for (int i = 0; i < keyItemList.Count; i++)
{
if (keyItemList[i].keyItem.KeyCode== keyCode)
{
return true;
}
}
return false;
}
#endregion
#region 开启关闭面板
public void OpenPanel()
{
root.gameObject.SetActive(true);
}
public void ClosePanel()
{
root.gameObject.SetActive(false);
}
#endregion
}
将这个脚本拖到SetKeyPanle的UI上 设置keyItemList值和root对象。如下图 :
3.player移动脚本
using System.Collections;
using System.Collections.Generic;
using UnityEngine.UI;
using UnityEngine;
public class player : MonoBehaviour
{
public Text txt; //这个text是用来显示你按下的按键名称的,你可以随便创建在任何位置,只要赋值给他就好
public float speed = 10f; //定义一个速度
void Start()
{
}
void Update()
{
//没有开启设置面板时 可移动
if (SetKeyPanle.GetIntance().IsCurrentOpenState)
{
//前进
if (Input.GetKey(SetKeyPanle.GetIntance().KeyItemDic["前进"].KeyCode))
{
transform.Translate(Vector3.forward * Time.deltaTime * speed);
txt.text = "按下:" + SetKeyPanle.GetIntance().KeyItemDic["前进"].KeyCode.ToString();
}
//后退
if (Input.GetKey(SetKeyPanle.GetIntance().KeyItemDic["后退"].KeyCode))
{
transform.Translate(Vector3.back * Time.deltaTime * speed);
txt.text = "按下:" + SetKeyPanle.GetIntance().KeyItemDic["后退"].KeyCode.ToString();
}
//向左
if (Input.GetKey(SetKeyPanle.GetIntance().KeyItemDic["向左"].KeyCode))
{
transform.Translate(Vector3.left * Time.deltaTime * speed);
txt.text = "按下:" + SetKeyPanle.GetIntance().KeyItemDic["向左"].KeyCode.ToString();
}
//向右
if (Input.GetKey(SetKeyPanle.GetIntance().KeyItemDic["向右"].KeyCode))
{
transform.Translate(Vector3.right * Time.deltaTime * speed);
txt.text = "按下:" + SetKeyPanle.GetIntance().KeyItemDic["向右"].KeyCode.ToString();
}
}
}
}
将这个脚本拖给player (场景中红色cube)赋值
好的这样我们的自定义按键功能就完成了,赶紧试试吧~~