001 游戏预览和介绍
职业选择
鼠标点击移动 旋转 缩放
药品 装备 任务NPC
状态 装备 技能 存档
002 导入场景资源,搭建场景
3方资源:RPG NGUI StandarAssets
进去关闭自动生成
(问题)模型贴图丢失
改变Shader类型(这么多个,一个个改),然后重新拖地图。原类型Toon/Basic
(问题)地形贴图资源丢失
paint texture移除重新画
重新画的贴图很模糊,法线也不对
(问题)地图是灰色的
Terrain数据文件丢失,重新做吧,已经是官方的初始文档了
第二种可能,照明设置中。开启了雾气
后面发现第3种可能,Unity的优化,让场景在远的变这样,拉近点又恢复好了
(问题)Texture Paint不上去
地表的Texture个还是刷不上去
Unity 3d ,地形上刷不了纹理的原因
(了解)Terrain的Tree选项卡
Tree选项卡就是写入Terrain中,不像直接拖入场景中可以移动
画笔大小要大于树密度,可以体现出随机疏朗,不然后太整齐
003 给场景添加光,设置鼠标指针图片
(了解)默认鼠标
004 给场景添加水面和天空盒子
(了解)天空盒子 skyBox
005 实现镜头缓慢拉近的效果
找不到编辑/照明设置
移到window/渲染/渲染设置(渲染或照明)中‘
006 使用NGUI和白色图片给场景添加渐显效
NGUI toolbar只有文字
unity 2018.4.32f1对应的NGUI版本
NGUI Next-Gen UI v3.12.1 (Jun 29, 2018)
有个情况是我把所有的Assets都新建了个文件夹来保存,之后重新导到根目录,可以了。
Atlas图集
这里是NGUI的Button的图片的添加,图片要加入图集内,需要图集。
打开NGUI/打开/图集编辑器
(问题)新建失败
unity nGUI atlas 将文件保存在项目资源文件夹
(了解)
对比可用的图集,有多了材质,texture两个属性
(可行)新建 == 先复制再修改
对比可用的图集,有生成.mat .png .prefab文件。
所以尝试着复制这三个,再修改。(可行)
保存的位置一般是资源同文件夹
删
点x,再点Delete。删多个点多次x,Delete只需点一次
007 设计开始的界面,开始加载按钮和logo
(按钮)NRPG按钮 == Sprite + 触发器 + UIButton
触发器大小默认为0,要撑起来,跟按钮一样大
(按钮显示隐藏)
对象的添加,有说Tag的是,但觉得浪费。直接public
.SetActive大写
一开始按就显示加载游戏等的按钮,但想动画结束后再显示,开始时加计时器
{
time -= Time.deltaTime;
if (Input.anyKeyDown && time<=0)//因为开头有个动画,time秒后
{
newGameButton.SetActive(true);
loadGameButton.SetActive(true);
pressAnyKey.SetActive(false);
}
}
PlayerPrefs
PlayerPrefs是系统自带的,往里面存键值对
void OnNewGame()//开始游戏
{
PlayerPrefs.SetInt("LoadFrom", 0);
}
void OnLoadGame()//加载游戏
{
PlayerPrefs.SetInt("LoadFrom", 1);
}
(按钮声音)AudioSource没声音
检查
音频文件(文件夹中播放看看)
重启软件
AudioSource叉出去,重新加
还有以下:
ProjectSetting(忘了要看什么,音量不为0?)
游戏Mute(关闭静音)
组件Mute(关闭静音)
组件音量(最大试试)
011 开始角色创建场景,导入模型和UI资源
导入Moedl
导入,加入角色选择的UI到RPG的图集里面(打开图集,选择UI后点击Add/Update)
NGUI按钮点击无效
将UIRoot的相机类型设为UI
NGUI 工具栏拖不出东西,示例场景很多损坏
看是实例场景1,2,7,9,10,12,13,14,15和tutorial都是坏的
(失败)重新导
场景恢复了,但是toolbar还是拖不出东西
(失败)更换NGUI版本
我的unity是2018.4.32f1
不能用的NGUI是NGUI Next-Gen UI v3.12.1
可以用的NGUI是NGUI Next-Gen UI v3.11.2
可以用的NGUI也有点不正常,样式不正常
(解决)过了一会又没了
发现只要我更新了自己生成的RPG资源,就一定出现NGUI的错,也就是两者起冲突了。
然后看着下图,有又是trim,又是replace,就全取消试试,暂时解决问题
一个文件夹一个图集,不要跨文件夹吧、(也许有这个原因)
NGUI放根目录Assets吧(很想跟其他导入的资源放一块)
NGUI的输入框和其他的并存了,PrefabTool也能拖拽
图集必备3文件,只有2个
Prefab mat 缺少png
应该从资料中找一下.png那张图拖进去。或者重新导
删除NGUI后,之前通过NGUI的图集编辑器制作的图集损坏
重新add进texture
(导入出现报错)
Shader error in ‘Transparent/Refractive’: Too many texture interpolators would be used for ForwardBase pass (9 out of max 8), try adding #pragma target 3.0 at line 41
加了确实没报错,不过没用到
Unity shader error: “Too many texture interpolators would be used for ForwardBase pass”
UI和场景的相机
分开的照,合并显示在屏幕上
3点打光
材质 standard
015 控制角色的上一个和下一个的选择
切换角色,要挂在按钮上
我想读文件的,即读取上把文件夹当作组件(但没学过,电脑里的游戏,直接改文件夹中的数据的日子啊 )
public GameObject[] characterPrefabArray;
public int index=0;//看的
private GameObject[] goArray;
// Start is called before the first frame update
void Start()
{
if (characterPrefabArray.Length != 0)
{
//实例 隐藏
goArray = new GameObject[characterPrefabArray.Length];
for (int i = 0; i < characterPrefabArray.Length; i++)
{
goArray[i] = Instantiate(characterPrefabArray[i], transform.position, transform.rotation);
goArray[i].SetActive(false);
goArray[i].transform.parent = transform;
}
goArray[0].SetActive(true);
}
}
public void PreCharacter()
{
goArray[index].SetActive(false);
index = index == 0 ? (characterPrefabArray.Length - 1) : --index;
goArray[index].SetActive(true);
}
public void NextCharacter()
{
goArray[index].SetActive(false);
index = index == characterPrefabArray.Length - 1 ? 0 : ++index;
goArray[index].SetActive(true);
}
016 处理名称的输入和场景的切换
(问题)2D盒状触发器导致的NGUI的输入框(UIInput)不能点击输入
问题描述
上下,选择按钮都可以动,只有输入框不能点击
流程介绍
节A挂一个UIInput的节点,来接收输入框Label;
节点A被脚本引用,用value来取里面的字符串存在PlayerPrefs里面
错误排查
节点A是UIRoot没问题,是输入框根节点有问题(其他场景不会)。
因素:UIRoot、输入框根节点的Depth是0,Label是1,都一样
因素:碰撞器,结果是盒状触发器的问题,要选2D盒状触发器
因素:该案例中submit可以不用写
因素:挂UIInput的节点在运行后,会自动加上UI Input On GUI的脚本
public void LoadScene()
{
PlayerPrefs.SetString("SelectedPlayerName", characterNameInput.value);
PlayerPrefs.SetInt("SelectedPlayerIndex", index);
print(PlayerPrefs.GetInt("SelectedPlayerIndex"));
print(PlayerPrefs.GetString("SelectedPlayerName"));
SceneManager.LoadScene(2);//2是数据,要分离开,但我还没学过
}
(了解) Invalid texture used for cursor - check importer settings or texture creation. Texture must be RGBA32, readable, have alphaIsTransparency enabled and have no mip chain.
我改这就消失了
Invalid texture used for cursor - check importer settings or texture creation. Texture must be RGBA3
(情况)unity保存,还有星号,在没有报错,警告的情况下
(问题)NGUI层黑色,运行后什么都没有
修改NGUI的相机剔除遮罩,选择default 或者 Everything(也是default起作用)
(了解)深度,深度里的会被照进来
018 标签管理
有了下面的文件,Tags.group “Group”,并且敲出Tags后是有提示的(Tags.p 可能就有 Tags.player 的提示)
好处是:写得快,不写错
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Tags : MonoBehaviour
{
public const string group = "Group";
public const string player = "Player";
}
019 实现角色行走的点击效果
void Update()
{
if (Input.GetMouseButtonDown(0))
{
print("点击");
Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);//点生成射线
RaycastHit hit;
bool isCollided = Physics.Raycast(ray, out hit);//是否碰到
if (isCollided && hit.collider.tag==Tags.ground)
{
OnClickEffect(effectPrefab, hit.point);
}
}
}
void OnClickEffect(GameObject effectPrefab, Vector3 position)
{
print("Move");
Instantiate(effectPrefab, position, Quaternion.identity);
}
(问题)空引用
MainCamera的标签
Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition)会报错 空引用
(问题)位置
不是hit.collider.transfrom.position(会跑到世界坐标原点),而是 hit.point
020 控制主角移动的朝向
(问题)鼠标下点,达不到鼠标按着滑动时,玩家一直朝向位置的目的
视频时
鼠标下点,isMoving=true
鼠标上抬,isMoving=false
而鼠标下点到上抬的过程是,鼠标一直按着的时候,这过程isMoving=true
这样做到了下点按着,更新朝向,抬起不更新
上面做的后果是Update实例太多次,按着鼠标时计时
void Update()
{
if (Input.GetMouseButtonDown(0))//鼠标下点
{
notMouseButtonUp = true;
targetPosition = positionByRay2Tag(Input.mousePosition, Tags.ground);
prefabByPosition(effectPrefab, targetPosition);
}
else if (Input.GetMouseButtonUp(0))//鼠标上抬
{
notMouseButtonUp = false;
}
if (notMouseButtonUp)//鼠标按着
{
targetPosition = targetPosition = positionByRay2Tag(Input.mousePosition, Tags.ground);
gameObject.transform.LookAt(targetPosition);
//计时1秒实例
mouseButtonEffectTimer += Time.deltaTime;
if (mouseButtonEffectTimer > mouseButtonEffectTime)
{
mouseButtonEffectTimer = 0f;
prefabByPosition(effectPrefab, targetPosition);
}
}
}
//判断 mouseDownPosition发出的射线是否撞到标签为tag的物体,是的返回hit的位置
Vector3 positionByRay2Tag(Vector3 mouseDownPosition, string tag)
{
Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);//点生成射线
RaycastHit hit;
bool isCollided = Physics.Raycast(ray, out hit);//是否碰到
if (isCollided && hit.collider.tag == Tags.ground)
{
targetPosition = hit.point;
return hit.point;
}
return Vector3.zero;//默认值
}
void prefabByPosition(GameObject prefab, Vector3 position)//在该位置实例预制体
{
Instantiate(prefab, position, Quaternion.identity);
}
021 控制主角的移动
transform.Translate(Time.deltaTime * speed)
void Move()
{
float stopDistanceNearTargetPosition = 0.2f;//可以停下的距离
float distance = Vector3.Distance(transform.position, targetPosition);
if (targetPosition != Vector3.zero && distance > stopDistanceNearTargetPosition)
{
transform.Translate(Vector3.forward * Time.deltaTime * speed);
}
}
角色控制器SimpleMove(speed)
void MoveByCharacterController()
{
float stopDistanceNearTargetPosition = 0.2f;//可以停下的距离
float distance = Vector3.Distance(transform.position, targetPosition);
if (targetPosition != Vector3.zero && distance > stopDistanceNearTargetPosition)
{
characterController.SimpleMove(transform.forward * speed);
}
}
022 控制主角的移动动画的播放
void Update()
{
if (!MoveByMouse._instance.notMouseButtonUp)
{
animation.CrossFade("Sword-Idle");
}
else if (MoveByMouse._instance.notMouseButtonUp)
{
animation.CrossFade("Sword-Run");
}
}
(问题)玩家会出现头朝地跑
y是玩家的y
gameObject.transform.LookAt(new Vector3(targetPosition.x, transform.position.y, targetPosition.z) );
(问题)按着鼠标才出现run
因为是根据鼠标状态,而不是Vetor3.Distance
(了解)LateUpdate
Update设置状态
LateUpdate设置动画
(代码,了解)定义
public enum State
{
Idle,
Walk,
Run
}
枚举变量的public会有下拉项的样式
(代码)设置状态
void MoveByCharacterController()
{
float stopDistanceNearTargetPosition = 0.2f;//可以停下的距离
float distance = Vector3.Distance(transform.position, targetPosition);
if (targetPosition != Vector3.zero && distance > stopDistanceNearTargetPosition)
{
state = State.Run;
characterController.SimpleMove(transform.forward * speed);
}
else
{
state = State.Idle;
}
}
(代码)根据状态设置动画
private new Animation animation;
private State state = State.Idle;
private MoveByMouse player;
// Start is called before the first frame update
void Start()
{
animation = GetComponent<Animation>();
player = GetComponent<MoveByMouse>();
}
// Update is called once per frame
void LateUpdate()
{
if (player.state==State.Idle)
{
animation.CrossFade("Sword-Idle");
}
else if (player.state == State.Run)
{
animation.CrossFade("Sword-Run");
}
}
023 修复bug完善主角的移动控制
(问题)点击后一直向前走,主要在崎岖地形
尤其是y值的过高,导致距离一直处于不到达的状态,该情况下玩家一直forward
(问题) 脚丫悬空
025 使用鼠标滑动控制相机视野的拉近和拉远
代码
public GameObject player;
private Vector3 offset;
//拉近
public float scrollSpeed = 10f;//拉伸速度
public float distance;//实际拉伸
public float minDistance=3.2f;//最大拉伸
public float maxDistance=30f;//最小拉伸
// Use this for initialization
void Start () {
offset = transform.position - player.transform.position;
//offset = new Vector3(0, offset.y, offset.z);//x=0,左右不偏移
}
// Update is called once per frame
void Update () {
transform.position =player.transform.position+ offset;
transform.LookAt(player.transform.position);
offset = ScrollView();
}
Vector3 ScrollView()//相机拉伸
{
distance = offset.magnitude;
distance += scrollSpeed * Input.GetAxis("Mouse ScrollWheel");
if (distance < minDistance)
{
distance = minDistance;
}
else if (distance > maxDistance)
{
distance = maxDistance;
}
offset = offset.normalized * distance;
return offset;
}
(了解)Clamp夹紧
distance = Mathf.Clamp(distance, minDistance, maxDistance);
//代替下面的
if (distance < minDistance)
{
distance = minDistance;
}
else if (distance > maxDistance)
{
distance = maxDistance;
}
027 控制视野的左右旋转
(了解)旋转影响相机的位置,offset发生变化
void RotateView()
{
if (Input.GetMouseButtonDown(1))
{
isRotate = true;
}
if (Input.GetMouseButtonUp(1))
{
isRotate = false;
}
if (isRotate)
{
transform.RotateAround(player.transform.position, Vector3.up, rotateSpeed*Input.GetAxis("Mouse X"));
}
offset = transform.position - player.transform.position;//旋转影响相机的位置,offset发生变化
}
028 控制视野的上下旋转和范围限制
代码
按住鼠标右键旋转,上下角度钳制(10,80)
值的记录要在RotateAround之前
void RotateView()//相机旋转
{
if (Input.GetMouseButtonDown(1))
{
isRotate = true;
}
if (Input.GetMouseButtonUp(1))
{
isRotate = false;
}
if (isRotate)
{
//记录
Vector3 originalPosition = transform.position;
Quaternion originalRotation = transform.rotation;
//赋值
transform.RotateAround(player.transform.position, transform.up, rotateSpeed * Input.GetAxis("Mouse X")); transform.RotateAround(player.transform.position, transform.right, rotateSpeed * Input.GetAxis("Mouse Y"));
transform.RotateAround(player.transform.position, transform.right, rotateSpeed * Input.GetAxis("Mouse Y"));
//限制范围
if (transform.eulerAngles.x < 10 || transform.eulerAngles.x > 80)
{
print ("超范围了");
transform.position = originalPosition;
transform.rotation = originalRotation;
}
}
offset = transform.position - player.transform.position;//旋转影响相机的位置,offset发生变化
}
030 在场景中添加老爷爷这个NPC
(问题)模型的材质丢失,呈粉红色
该材质的类型standard
031 设计任务对话框的背景
(问题,严重)图集信息丢失,造成要重新加上去
丢失一次,尤其有按钮的,加图片很麻烦
发现是复制的场景,原来的没坏,但不清楚现在的为什么坏了
(问题)重影
有关透视
油
(问题)位置不对
场景中看transfrom看是680到150,就可以达到效果
Tween看是700到-1410才能达到想要的位置
032 任务系统-设计任务的内容
(问题)Label在unity字体下不显示
Material材质那里加一次字体,显示黑色字体,又None掉,白色,正常显示
感觉像给NGUI提示,快用字体啊
(问题)多个面板
正常只有1个(我也只有一个),现在是运行后左边有一个不动的,右边那个是Tween Position过来的
(问题)NGUI层出现Terrain的图像
太长照到后面的
调相机的远近
近最小0远最小0.01
(了解)场景中图标太大
(了解)按钮所需的组件
NGUI的按钮 等于 Sprite + UIButton + Play Sound + 2D触发器(看相机是2D还是3D,系统自动切)
(解决)按钮点击不了
触发器大小默认为0,没调
用attackh自动铺张
(了解)GUI图层组件弃用
(问题)NGUI的坐标不一致
场景中人物板从x610到x250
NGUI只显示了1/3,只有x610到x-770效果才一样
看别的视频,unity单位是米,但这里单位是像素
上面的距离是360,1380,也就是1米 == 2像素 ?
(解决)NGUI的按钮不能点击
对比了很多下,删掉新建最方便
(解决)UICamera.hoveredObject==null后点击地面,人物不移动
在unity中使用UICamera.hoveredObject==null后游戏点击地面无反应和鼠标点击穿透UI
private void MouseDownEvent()
{
// if (UICamera.hoveredObject != null) return;
if (UICamera.isOverUI) return;
print("鼠标下按:" + UICamera.hoveredObject);
isMouseButtonPress= true;
targetPosition = GetTargetPosition(Input.mousePosition);
Instantiate(effectPrefab, targetPosition, Quaternion.identity);
}
33 点击NPC弹出任务板
脚本挂NPC,我原想挂任务板,后面也该挂任务板
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Quest : MonoBehaviour
{
public GameObject quest;
private void OnMouseOver()
{
if (Input.GetMouseButtonDown(0))
{
print("点击");
ShowQuest();
}
}
void ShowQuest()
{
quest.GetComponent<TweenPosition>().PlayForward();
}
public void DisableQuest()
{
quest.GetComponent<TweenPosition>().PlayReverse();
}
}
36 鼠标指针管理系统
图片,焦点,软硬件
方法要被调用,不然…
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class GameSettings : MonoBehaviour
{
public Texture2D attackCursor;
public Texture2D lockTargetCursor;
public Texture2D normalCursor;
public Texture2D npcTalkCursor;
public Texture2D pickCursor;
public static GameSettings _instance;
private void Awake()
{
_instance = this;
}
public void SetNormalCursor()
{
Cursor.SetCursor(normalCursor, Vector2.zero, CursorMode.Auto );//图形,焦点
}
public void SetLockTargetCursor()
{
Cursor.SetCursor(lockTargetCursor, Vector2.zero, CursorMode.Auto);//图形,焦点
}
public void SetAttackCursor()
{
Cursor.SetCursor(attackCursor, Vector2.zero, CursorMode.Auto);//图形,焦点
}
public void SetNpcTalkCursor()
{
Cursor.SetCursor(npcTalkCursor, Vector2.zero, CursorMode.Auto);//图形,焦点
}
public void SetPickCursorr()
{
Cursor.SetCursor(pickCursor, Vector2.zero, CursorMode.Auto);//图形,焦点
}
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Npc : MonoBehaviour
{
private void OnMouseEnter()
{
GameSettings._instance.SetLockTargetCursor();
}
private void OnMouseExit()
{
GameSettings._instance.SetNormalCursor();
}
}
(了解)脚本有默认设置
037 开发功能面板
01 玩家点击 Bar上的按钮
02 触发了总节点上的函数去打开面板
public void OnStatusButtonClick()
{
StatusPannel._instance.ShowWindow();
}
public void OnBagButtonClick()
{
BagPannel._instance.ShowWindow();
}
public void OnEquipmentButtonClick()
{
EquipPannel._instance.ShowWindow();
}
public void OnSkillButtonClick()
{
SkillPannel._instance.ShowWindow();
}
public void OnSettingButtonClick()
{
SettingPannel._instance.ShowWindow();
}
03 调用对应的面板的父类方法ShowWindow
public class Pannel : MonoBehaviour
{
[Tooltip("父类Window的字段,不用设置,可调用而已")] public bool isShow = false;
[Tooltip("关闭Pannel的按钮")] public UIButton closeButton;
public void ShowWindow()
{
GetComponent<TweenPosition>().PlayForward();
isShow = true;
}
public void DisableWindow()
{
GetComponent<TweenPosition>().PlayReverse();
isShow = false;
}
}
39-49 背包系统
TextAsset读取.txt
流程图
数据文本
1001,小瓶血药,icon-potion1,Potion,50,0,50,60
1002,大瓶血药,icon-potion2,Potion100,0,70,100
1003,蓝药,icon-potion3,Potion,100,60,80
2001,黄金甲,armor0-icon,Equip,0,50,0,Armor,Swordman,150,200
2002,铜甲,armor1-icon,Equip,0,39,0,Armor,Swordman,100,150
2003,神迹魔法衣,armor2-icon,Equip,0,50,0,Armor,Magician,150,200
2004,破旧魔法衣,armor3-icon,Equip,0,20,0,Armor,Magician,60,100
2005,铜鞋,icon-boot0,Equip,0,0,50,Shoe,Common,60,100
2006,神级红鞋,icon-boot0-01,Equip,0,0,70,Shoe,Common,120,150
2007,帽子,icon-helm,Equip,0,50,0,Headgear,Swordman,100,120
2008,神帽,icon-helm-01,Equip,0,70,0,Headgear,Swordman,120,200
2009,神级魔法帽,icon-helm-02,Equip,0,70,0,Headgear,Magician,120,200
2010,普通魔法帽,icon-helm-03,Equip,0,50,0,Headgear,Magician,100,120
2011,黄金戒指,icon-ring,Equip,0,50,0,Accessory,Common,50,70
2012,铜绿戒指,icon-ring-01,Equip,0,30,0,Accessory,Common,30,50
2013,盾牌,icon-shield,Equip,0,50,0,LeftHand,Common,50,70
2014,神盾,icon-shield1,Equip,0,70,0,LeftHand,Common,70,100
2015,皇族项链,icon-tailman,Equip,0,30,0,Accessory,Common,30,60
2016,火柴棍,rod-icon,Equip,40,0,0,RightHand,Magician,40,80
2017,金属棍,rod-icon02,Equip,60,0,0,RightHand,Magician,60,120
2018,神级魔法棒,rod-icon03,Equip,80,0,0,RightHand,Magician,80,200
2019,御剑,sword0-icon,Equip,40,0,0,RightHand,Swordman,40,60
2020,双手剑,sword0-icon00,Equip,60,0,0,RightHand,Swordman,60,100
2021,白帝圣剑,sword1-icon,Equip,80,0,0,RightHand,Swordman,80,150
2022,华夏第一剑,sword2-icon,Equip,100,0,0,RightHand,Swordman,150,200
(代码)模型类
没有MonoBehaviour,后面子类不能在编辑器内显示
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Item:MonoBehaviour//物品信息类
{
public int id;//000
public new string name;
public string icon_name;
public ItemType itemType;
public int price_sell;
public int price_buy;//5
public DressType dressType;//部位
public ApplyType applyType;//职业
public int attack;
public int defense;
public int speed;
public int hp;
public int mp;
void Start()
{
}
}
public enum ItemType//物品的类型
{
Potion,
Equip,
Mat,
Undefined
}
(代码)TextAsset转化为List
两个方法的作用分别是
1、读TextAsset,写入Dictionary
2、读取Dictionary,返回一个上述模型类的一个对象
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class TextAssetToDictionary: MonoBehaviour
{
[Tooltip("数据文本,英文逗号分割,回车换行")]
public TextAsset textAsset;
[Tooltip("组件不显示,是为了让访问调用")]
public Dictionary<int, Item> dictionary = new Dictionary<int, Item>();
public static TextAssetToDictionary _instance;
void Awake()
{
_instance = this;
dictionary = Read(textAsset);
}
public Dictionary<int, Item> Read(TextAsset textAsset)//读取TextAsset,存储到Dictionary
{
string[] lineArray = textAsset.text.Split('\n');
foreach (string line in lineArray)
{
string[] propertyArray = line.Split(',');//英文逗号
//分流
Item item = new Item();
item.id = int.Parse(propertyArray[0]);
item.name = propertyArray[1];
item.icon_name = propertyArray[2];
//根据类型在具体赋值
switch (propertyArray[3])
{
case "Potion": item.itemType = ItemType.Potion; break;
case "Equip": item.itemType = ItemType.Equip; break;
case "Mat": item.itemType = ItemType.Mat; break;
default: item.itemType = ItemType.Undefined; break;
}
//药品
switch (item.itemType)
{
case ItemType.Potion://药品
{
item.hp = int.Parse(propertyArray[4]);
item.mp = int.Parse(propertyArray[5]);
item.price_sell = int.Parse(propertyArray[6]);
item.price_buy = int.Parse(propertyArray[7]);
}
break;
case ItemType.Equip://装备
{
item.attack = int.Parse(propertyArray[4]);
item.defense = int.Parse(propertyArray[5]);
item.speed = int.Parse(propertyArray[6]);
switch (propertyArray[7])
{
case "Headgear": item.dressType = DressType.Headgear; break;
case "Armor": item.dressType = DressType.Armor; break;
case "LeftHand": item.dressType = DressType.LeftHand; break;
case "RightHand": item.dressType = DressType.RightHand; break;
case "Shoe": item.dressType = DressType.Shoe; break;
case "Accessory": item.dressType = DressType.Accessory; break;
default: break;
}
switch (propertyArray[8])
{
case "Swordman": item.applyType = ApplyType.Swordman; break;
case "Magician": item.applyType = ApplyType.Magician; break;
case "Common": item.applyType = ApplyType.Common; break;
default:break;
}
item.price_sell = int.Parse(propertyArray[9]);
item.price_buy = int.Parse(propertyArray[10]);
}
break;
default:
break;
}
dictionary.Add(item.id, item);
}
return dictionary;
}
public Item GetItemById(int id)
{
dictionary.TryGetValue(id, out Item item);
return item;
}
}
背包
流程图
ItemGroup就是一群,一堆Item的意思,多了数量的属性;
之前想用Bag_Item,但商店里面的也是一样的属性
实例的预制体是ItemGroup,继承于Item,Item的using… Start Update方法不能删除,否则它和子类都不能挂在(还是显示)在编辑器中
(问题)首位多次生成
之前记录的NGUI的有问题,就是拖拽最前面的有时(常常会生成物品)
因为是点击生成物品。拖第一个时形成空位,所以就生成物品在首位
for (int i = 0; i < gridList.Count; i++)
{
string itemName= itemList[itemIndex].GetComponent<UISprite>().spriteName;
string goodName= gridList[i].childCount ==0 ? "" : gridList[i].GetChild(0).GetComponent<UISprite>().spriteName ;
print(goodName+","+itemName);//测试
bool isFind = (itemName==goodName);//新增的sprite名字在格子的子节点中是否能找到相同的
if (isFind)
{
print("相同");
IncreaseGood(i);
break;
}
(代码)取数据,挂在BagPannel下
将字典的每一项item传给ItemGroup
void InitItemPrefabList()//读取文本,派生Item预制体,生成对象
{
dictionary = GetComponent<TextAssetToDictionary>().dictionary;
print("3423"+dictionary.Count);
//遍历字典,填充itemPrefab,加入列表
for (int i = 0; i < dictionary.Count; i++)
{
//看着文本的id来改
Item item =new Item();
if (i > 2)
item = dictionary[2001 + i - 3];//药品
//取值
else
item = dictionary[1001 + i];//装备
GameObject itemPrefab = Instantiate(bag_Item);//生成
itemPrefab.transform.parent = transform;//挂在总节点下,美观
itemPrefab = itemPrefab.GetComponent<Bag_Item>().SetValue(item);//赋值
itemPrefabList.Add(itemPrefab);//加入
}
}
(代码)ItemGroup
根据Item取值和UI显示,隐约觉得继承类可以用,但还没学到
继承Item的话会被Monobehavior排斥,导致无法在编辑器中使用添加。
所以还是将Item当成组件
(做到了),就是基类Item的using, start,update不能省略,不让没法拖到对象上
看到ScriptableObject,介绍单一的(视频是拖出一个,填值),暂时没学到它的价值
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class ItemGroup : Item
{
//比Item额外多的
[Tooltip("信息提示框")] public GameObject tipGo;
[Tooltip("信息提示框的文本")] private UILabel tipLabel;
[Tooltip("数量的文本框")] public UILabel countLabel;
[Tooltip("数量")] public int count = 0;
[Tooltip("信息提示框显示时间")] public float activeTime = 0.2f;
[Tooltip("信息提示框计时器")] public float timer = 0f;
void Start()
{
}
void Update()
{
}
public void DisableTip()//信息框计时隐藏
{
tipGo.SetActive(false);
}
public void ShowTip()//显示提示框文本
{
tipGo.SetActive(true);
string tip = "";
switch (itemType)
{
case ItemType.Potion://药品
{
tip = "名称:" + name;
tip += "\n类型:药品";
tip += "\n效果:Hp+" + hp;
tip += "\n效果:Mp+" + mp;
tip += "\n售价:" +price_sell;
}
break;
case ItemType.Equip://装备
{
string dressTypeStr = "";
switch (dressType)//部位
{
case DressType.Headgear:dressTypeStr = "头部";break;
case DressType.Armor:dressTypeStr = "身体";break;
case DressType.LeftHand:dressTypeStr = "左手";break;
case DressType.RightHand:dressTypeStr = "右手";break;
case DressType.Shoe:dressTypeStr = "脚";break;
case DressType.Accessory:dressTypeStr = "饰品";break;
}
string applyTypeStr = "";
switch (applyType)//职业
{
case ApplyType.Swordman: applyTypeStr = "战士"; break;
case ApplyType.Magician: applyTypeStr = "魔法师"; break;
case ApplyType.Common: applyTypeStr = "通用"; break;
}
//打印
tip = "名称:" + name;
tip += "\n类型:装备";
tip += "\n部位类型:"+ dressTypeStr;
tip += "\n职业类型:"+ applyTypeStr;
tip += "\n攻击:"+ attack;
tip += "\n防御:"+ defense;
tip += "\n速度:"+ speed;
tip += "\n售价:" + price_sell;
}
break;
default:
{
tip = "名称:未命名";
tip += "\n类型:未定义";
}
break;
}
tipLabel.text = tip;
}
public void SetValue(Item item)//父类的数据赋值给子类,因为数据是父类的
{
id=item.id;
name=item.name;
icon_name=item.icon_name;
itemType=item.itemType;
price_sell= item.price_sell;
price_buy= item.price_buy;
dressType= item.dressType;
applyType= item.applyType;
attack= item.attack;
defense= item.defense;
speed = item.speed;
hp= item.hp;
mp= item.mp;
}
}
(代码)拖拽组件
重写了UIDragAndDrop,加在物品上。
格子标签是Grid,物品预制体的标签是Good
using UnityEngine;
public class MyDragDrop : UIDragDropItem
{
[Tooltip("开始拖拽的物体的位置")] private Vector3 startPos = Vector3.zero;
protected override void OnDragDropStart()
{
base.OnDragDropStart();
startPos = base.transform.position;//记录开始位置,为了回滚到原来的位置
}
protected override void OnDragDropRelease(GameObject surface)
{
base.OnDragDropRelease(surface);
print(surface.tag);
if (surface.tag == "Grid")
{
//transform.position = surface.transform.position;//物体放入格子里
transform.parent = surface.transform;
transform.localPosition = Vector3.zero;
}
else if (surface.tag == "Good")
{
//位置交换
transform.position = surface.transform.position;
surface.transform.position = startPos;
}
else//脱到不该脱的位置
{
transform.position = startPos;
}
}
}
(代码)增加物品,挂在BagPannel下
背包的总节点吧,方便做预制体
void CreateNewItem(List<Transform> gridList,List<Item> itemList)//点击生成物品的测试函数,
{
//1 随机添加一个物品
int createNewItemId = itemList[ Random.Range(0, itemList.Count) ].id;//新建的物品的id
//2 有没有相同的
for (int i = 0; i < gridList.Count; i++)//找到图片名相同的grid的索引
{
if (gridList[i].transform.childCount == 0)//循环
{
AddNewItem(i, createNewItemId);//用拿到的id去对应的i实例
break;
}
else if (gridList[i].transform.childCount > 0)
{
int itemGroupId = gridList[i].transform.GetChild(0).GetComponent<ItemGroup>().id;//取得格子里面的物品的id,moonobehavior排斥
if (itemGroupId == createNewItemId)//相同,到对应的i加加
{
AddExistingItem(i);
break;
}
else//循环
{
if (i == gridList.Count - 1)
print("满了");
}
}
}
}
void AddNewItem(int index,int id)//新增
{
Item item= TextAssetToList._instance.GetItemById(id);
GameObject go = Instantiate(itemGroupPrefab);
ItemGroup itemGroup = go.GetComponent<ItemGroup>();
itemGroup.SetValue(item);
go.GetComponent<UISprite>().spriteName = itemGroup.icon_name;
go.transform.parent = gridList[index].transform;
go.transform.localPosition = Vector3.zero;
go.transform.localScale = Vector3.one;
itemGroupList.Add(item);
}
void AddExistingItem(int gridIndex)//旧增
{
Transform t = gridList[gridIndex].transform;//各自位置
int count = int.Parse(t.GetChild(0).GetChild(0).GetComponent<UILabel>().text);//格子下的物品,物品下的Label对象
t.GetChild(0).GetChild(0).GetComponent<UILabel>().text = (++count).ToString();
}
(了解)UI Trigger组件
做鼠标悬浮的显示隐藏
over,out分别拖入显示隐藏信息提示框的方法
(问题)提示框中文不显示
支持中文的字体
(问题)图片过大
go.transform.localScale = Vector3.one;
(问题)The root GameObject of the opened Prefab has been moved out of the Prefab …
现在只靠拖出来改,再拖回去
The root GameObject of the opened Prefab has been moved out of the Prefab …
50-52 状态系统(属性点数的分配、应用、重置修改)
流程图
UI
代码
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Status : Window
{
private int attack ;
private int defense;
private int speed;
private int point;
[Tooltip("数字部分的Label")] public UILabel attackLabel;
[Tooltip("数字部分的Label")] public UILabel defenseLabel;
[Tooltip("数字部分的Label")] public UILabel speedLabel;
[Tooltip("数字部分的Label")] public UILabel pointLabel;
// Start is called before the first frame update
void Start()
{
GetValue();
SetLabel();
}
//点击了相应的加按钮
public void OnAttackClick()
{
bool havePoint = ConsumePoint();
if (!havePoint) return;
attack++;
SetLabel();
}
public void OnDefenseClick()
{
bool havePoint = ConsumePoint();
if (!havePoint) return;
defense++;
SetLabel();
}
public void OnSpeedClick()
{
bool havePoint = ConsumePoint();
if (!havePoint) return;
speed++;
SetLabel();
}
//够钱就扣,返回true;不然还钱,返回false
private bool ConsumePoint()
{
point--;
if (point < 0)
{
point++;
return false;
}
return true;
}
public void ResetValue ()//重置
{
GetValue();
SetLabel();
}
public void SetValue()//应用修改
{
PlayerStatus._instance.attack=attack;
PlayerStatus._instance.defense=defense;
PlayerStatus._instance.speed=speed;
PlayerStatus._instance.point=point;
}
public void GetValue()//到玩家那里获取数据
{
attack = PlayerStatus._instance.attack;
defense = PlayerStatus._instance.defense;
speed = PlayerStatus._instance.speed;
point = PlayerStatus._instance.point;
}
public void SetLabel()//输出到状态板的Label
{
attackLabel.text = attack.ToString();
defenseLabel.text = defense.ToString();
speedLabel.text = speed.ToString();
pointLabel.text = point.ToString();
}
}
问题 组件前面没有可选框
unity–为什么Inspector视图中脚本前面的勾选框没了
将一个父类方法的名字修改后,出现了TweenPosition丢失
背景是将 状态按钮 触发 父节点的方法 去调用 状态栏的父类方法ShowWindow
现尝试将 状态按钮 触发 父节点的方法 去调用 状态栏的父类方法ShowWindow,可以达到效果
所以问题在父节点的方法
53-55 商店系统
56-63 装备系统
视频是通过点击背包里面的装备来穿戴
想到,UI上
01 临时的Bag在左边,装备栏在右边,方便拖拽添加装备
02 界面不够显示两个面板,所以是,显示一个,隐藏一个,通过双击(右键)
需求:
01、打开装备栏点击部位,隐藏装备栏,弹出背包栏,显示玩家职业类型,该部位类型的人装备,再点击装备,实现穿戴或02、者替换,玩家属性的加减
打开背包,弹出背包栏,显示玩家职业类型,该部位类型的人装备,再点击装备,实现穿戴或者替换,玩家属性的加减
03、实现背包里面的数据和显示分离,方便显示可以装备的装备。存储的是
类
想到比Item就多了count属性,Group一群一堆。
框是做预制体用到的UI显示
流程
(重构)拆开数据表和对象表
背景是,在装备栏的部位槽点击进入背包,想背包显示的是该职业该部位属于装备的物品
想到,数据归一档,这个数据可以是所有类型的的物品表,装备类的表,药品类的表,装备老板的商品表,药品老板的商品表。
(代码)原来的
对应的,加减数量也需要更新背包,所以冗余了
void AddNewItem(int index,int id)//新增
{
Item item= TextAssetToList._instance.GetItemById(id);
GameObject go = Instantiate(itemGroupPrefab);
ItemGroup itemGroup = go.GetComponent<ItemGroup>();
itemGroup.SetValue(item);
go.GetComponent<UISprite>().spriteName = itemGroup.icon_name;
go.transform.parent = gridList[index].transform;
go.transform.localPosition = Vector3.zero;
go.transform.localScale = Vector3.one;
itemGroupList.Add(item);
}
(代码)现在的,将显示部分拆出来复用
void AddNewItem(int id)//新增
{
Item item= TextAssetToList._instance.GetItemById(id);
ItemGroup itemGroup = new ItemGroup();
itemGroup.SetValue(item);
itemGroup.count = 1;
itemGroupList.Add(itemGroup);
}
void DisplayItem(List<ItemGroup> itemGroupList)//拿到对应的数据表 itemGroupList,进行实例
{
if (itemGroupObjectList!=null)
{
foreach (GameObject itemGroupObject in itemGroupObjectList)
{
Destroy(itemGroupObject);
}
itemGroupObjectList.Clear();//不clear,list里面有很多Missing的对象
}
重新展览
for (int i = 0; i < itemGroupList.Count; i++)
{
GameObject go = Instantiate(itemGroupPrefab);
ItemGroup itemGroup = go.GetComponent<ItemGroup>();
itemGroup.SetValue(itemGroupList[i]);
itemGroup.countLabel.text = itemGroup.count.ToString();
go.GetComponent<UISprite>().spriteName =itemGroup.icon_name;
go.transform.parent = gridList[i].transform;
go.transform.localPosition = Vector3.zero;
go.transform.localScale = Vector3.one;
itemGroupObjectList.Add(go);
}
}
(问题) 在第一个格子死循环增加第一个随机出来的item
实例的代码在Display方法里面,Display裸露在Update,而不是在鼠标左键条件下。
也没有销毁之前的
void Update()
{
if (Input.GetKeyDown(KeyCode.Space) && _instance.isShow)//在背包打开的情况下点击
{
CreateNewItem(itemList);//克隆对象进背包
DisplayItem(itemGroupList);
}
}
再次Display,没有clear以前的对象列表
void DisplayItem(List<ItemGroup> itemGroupList)//拿到对应的数据表 itemGroupList,进行实例
{
itemGroupObjectList.Clear();
for (int i = 0; i < itemGroupList.Count; i++)
{
GameObject go = Instantiate(itemGroupPrefab);
ItemGroup itemGroup = go.GetComponent<ItemGroup>();
itemGroup.SetValue(itemGroupList[i]);
itemGroup.countLabel.text = itemGroup.count.ToString();
go.GetComponent<UISprite>().spriteName =itemGroup.icon_name;
go.transform.parent = gridList[i].transform;
go.transform.localPosition = Vector3.zero;
go.transform.localScale = Vector3.one;
itemGroupObjectList.Add(go);
}
}
点击装备槽显示对应职业、部位的装备(筛选)
//从装备栏点击进来
public void OnDressTypeClick(DressType dressType)//筛选出 职业类型,Item类型(装备),部位类型的物品
{
List<ItemGroup> equipGroupList = new List<ItemGroup>();
foreach (ItemGroup itemGroup in BagPannel._instance.itemGroupList)
{
if (itemGroup.dressType == dressType &&
itemGroup.applyType == Player._instance.applyType &&
itemGroup.itemType == ItemType.Equip)//找出职业,部位符合的装备
{
equipGroupList.Add(itemGroup);
}
}
BagPannel._instance.DisplayItem(equipGroupList);
this.DisableWindow();
BagPannel._instance.ShowWindow();
}
左键装备,或者替换
public void DressEquipItem(ItemGroup itemGroup)
{
//替换操作
if (itemGroup.itemType != ItemType.Equip ) return;
if (itemGroup.applyType != Player._instance.applyType && itemGroup.applyType != ApplyType.Common) return;
Transform dressTrans = EquipPannel._instance.DressTypeToTransform(itemGroup.dressType);
if (dressTrans.childCount != 0)//替换,多了回滚动作,其他一样
{
//卸下
UnDressEquipItem(dressTrans.GetChild(0).GetComponent<EquipItem>());
}
MinusExistingItem(itemGroup.id);//减减 或者 销毁移除
EquipPannel._instance.DressItemGroup(itemGroup);//装备
}
物品预制体写方法传参id给BagPannel,被双击动作调用
public void OnItemGroupDubleClick()
{
BagPannel._instance.UseItemGroup(id);
}
脱下
public bool UnDressEquipItem(EquipItem equipItem)
{
print("bag脱下");
if (itemGroupList.Contains(equipItem))//有同类
{
AddExistingItem(equipItem.id);
}
if (!itemGroupList.Contains(equipItem))//无同类
{
if (itemGroupObjectList.Count + 1 > gridList.Count)//满了,不能卸下
{
return false;
}
AddNewItem(equipItem.id);
}
return true;
}
}
玩家双击EquipItem,向 装备栏 传递 穿戴类型
public void UndressItemGroup()
{
EquipPannel._instance.UndressItemGroup(dressType);
}
装备栏根据穿戴类型,销毁对应部位上的装备,回滚(加加或新增)装备到背包
public void UndressItemGroup(DressType dressType)
{
//销毁,传id
Transform equipTransform;
switch (dressType)
{
case DressType.Headgear:
equipTransform = headgear;
break;
case DressType.Armor:
equipTransform = anmor;
break;
case DressType.LeftHand:
equipTransform = leftHand;
break;
case DressType.RightHand:
equipTransform = rightHand;
break;
case DressType.Shoe:
equipTransform = shoe;
break;
case DressType.Accessory:
equipTransform = accessory;
break;
default:
throw new System.Exception("脱下装备出错");
}
//销毁回滚
int id = equipTransform.GetChild(0).GetComponent<ItemGroup>().id;
Destroy(equipTransform.GetChild(0).gameObject);
BagPannel._instance.AddExistingItem(id);
}
(问题) InvalidOperationException: Collection was modified; enumeration operation may not execute.
枚举列表时修改了列表
(问题) 文本提示框错误
给本体赋值,而不是给一个接收本体的对象赋值。错误文本框显示的是预制体填的值
ItemGroup itemGroup = go.GetComponent<ItemGroup>();
itemGroup.SetValue(item);
//正确
go.GetComponent<ItemGroup>().SetValue(item);
(现象) 设置字体的字距调整值"Miscrosoft YaHei"
拖个ttf的字体到unity,弹出这个很卡很久