2D游戏开发模块梳理
Snap Seting 控制一次移动的步长,按住control 在移动工具中,一般设置为物体的长宽,批量复制
地形设计(Terrain)笔刷
shift + mouse是降低
四种灯光直射光E.G
火堆 使用Lightmapping 贴图节约 性能添加Lighting选项,将场景和灯光都选择为static
选择所有灯光Mode改为bakedShadow Type选择 Hard 或者柔和的
粒子系统火焰
导航系统添加导航系统对地形包括灯光所有选择为static
对象设置为不可到达(添加障碍物)Inspector面板取消勾选对象的 Navigation static(取消障碍物)烘培完成蓝色是可行走区域
添加玩家为角色添加 Navi mesh agent给玩家添加导航脚本
void Update() { //使用射线检测 if (Input.GetMouseButton(0)) { Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);//屏幕坐标转换成射线 RaycastHit hit; //保持碰撞信息 if(Physics.Raycast(ray, out hit)) { Debug.Log(hit.point); agent.SetDestination(hit.point);//导航 }//射线检测 } }控制相机跟随(视野问题) public class FollowTarget : MonoBehaviour{ public Transform playertransform; private Vector3 offset; // Start is called before the first frame update void Start() { offset = transform.position - playertransform.position;//设置相机跟随距离 } // Update is called once per frame void Update() { transform.position = playertransform.position + offset;//相机跟随 }}
把角色在检视窗口赋值给playertransfrom 注意:点击后 人物移动的速度 符合牛顿定律(第1 第2)
TileMap画板使用(2D)Hirarchy创建然后创建调色板,拖入Sprite图鼠标点击单元图,进行粉刷
切割精灵图制作瓦片集 选择精灵图集,设置type = multipe类型选择切割方式,Apply,然后拖入调色板 ,灵活配图Edit按下是对调色板中的瓦片进行操作,抬起是对scene(上方)进行操作
渲染顺序实现ruby在盒子下方时脑袋挡住盒子,在盒子上方(后面)被挡住腿,远近的实现
细节设置盒子的Pivot
刚体 尽量使用刚体控制移动,不然移动脚本可能造成接触物体发生抖动2D记得冻结Y轴旋转,不然碰撞后发生 侧旋 场景碰撞器为Tilemap添加tilemap collider 2D更改Tile图片的的碰撞类型为None ,河流 石头 是sprite
再更改Rigidbody2d 为static
敌人 伤害区域ctrl + k f 格式化代码 在chactrar 文件夹里设置敌人的 Pivot 为脚部调整collider的大小为脚部
敌人的移动控制脚本 先创建Animator Controller ,挂载到GO上再创建Animation,编辑精灵图的动画导入精灵图集的单帧动作动画,调整间隔和顺序编辑动画之间的间隔状态机连线,添加条件在脚本中,设置相应参数使用混合树
玩家 玩家控制脚本 private Vector2 lookDirection = new Vector2(1,0);//Ruby朝向向量void Update(){ //玩家输入监听 float horizontal = Input.GetAxis("Horizontal"); float vertical = Input.GetAxis("Vertical"); Vector2 move = new Vector2(horizontal,vertical); if (!Mathf.Approximately(move.x,0)||!Mathf.Approximately(move.y,0)) { //lookDirection.Set(move.x,move.y); lookDirection = move; lookDirection.Normalize(); if (!walkAudioSource.isPlaying) { walkAudioSource.clip = walkSound; walkAudioSource.Play(); } } else { walkAudioSource.Stop(); } //动画的控制 animator.SetFloat("Look X",lookDirection.x);//Look X ,Look Y混合树参数 animator.SetFloat("Look Y",lookDirection.y); animator.SetFloat("Speed",move.magnitude); //移动 Vector2 position = transform.position; //Ruby的目标位置 position += speed * move * Time.deltaTime; //transform.position = position; //Ruby移动到目标位置 rigidbody2d.MovePosition(position); } 子弹脚本发射 #Ruby脚本中 动态创建子弹对象 GameObject projectileObject = Instantiate(projectilePrefab, rigidbody2d.position+Vector2.up*0.5f,Quaternion.identity);//克隆方法 Projectile projectile= projectileObject.GetComponent();//获取子弹脚本组件 projectile.Launch(lookDirection,300);//调用子弹脚本创建一个子弹 animator.SetTrigger("Launch"); //按键绑定 if (Input.GetKeyDown(KeyCode.H)) { Launch(); } #Bullet脚本中 public void Launch(Vector2 direction,float force) //子弹发射方法(Ruby调用) { rigidbody2d.AddForce(direction*force);//自身刚体调用自己的施加力的方式 } private void OnCollisionEnter2D(Collision2D collision) { //Debug.Log("当前子弹碰撞到的游戏物体是:"+collision.gameObject); EnemyController enemyController = collision.gameObject. GetComponent(); if (enemyController!=null) { enemyController.Fix(); } Destroy(gameObject);//子弹销毁 } private void Update() { if (transform.position.magnitude>100) //子弹不触碰,长距离销毁 transform.position.magnitude 距离向量的模长 { Destroy(gameObject); } } 添加子弹交互动画 通过层级系统 筛选碰撞单元添加层级
粒子系统给对象添加粒子系统更改参数上传特效图片,选择Start Frame区间,下拉列表,随机在两个之间
血条使用MASK 制作血条
using System.Collections;using System.Collections.Generic;using UnityEngine;using UnityEngine.UI;public class UIHealthBar : MonoBehaviour{ public Image mask; private float originalSize; public static UIHealthBar instance { get; private set; }//单例模式,可全局访问 public bool hasTask; //public bool ifCompleteTask; public int fixedNum; private void Awake() //单例模式的实例化 { instance = this; } // Start is called before the first frame update void Start() { originalSize = mask.rectTransform.rect.width; } // Update is called once per frame void Update() { } /// /// 血条UI填充显示 /// /// 填充百分比 public void SetValue(float fillPercent) { mask.rectTransform.SetSizeWithCurrentAnchors(RectTransform. Axis.Horizontal,originalSize*fillPercent); }} 射线检测 NPC对话系统 if (Input.GetKeyDown(KeyCode.T)) { RaycastHit2D hit = Physics2D.Raycast(rigidbody2d.position+Vector2.up*0.2f,//添加V2.up原因是角色初始锚点在脚部,设置后射线初始位置在胸口 lookDirection,1.5f,LayerMask.GetMask("NPC")); //存储触碰物体的信息 if (hit.collider!=null) { NPCDialog npcDialog = hit.collider.GetComponent();//获取NPC身上控制对话的脚本 if (npcDialog!=null) { npcDialog.DisplayDialog(); } } }在对话框脚本中使用计时器,确定对话消失时间
void Update() { if (timerDisplay>=0) { timerDisplay -= Time.deltaTime; if (timerDisplay timerDisplay = displayTime; dialogBox.SetActive(true);//激活对话框 UIHealthBar.instance.hasTask = true; if (UIHealthBar.instance.fixedNum>=5) { //已经完成任务,需要修改对话框内容 dialogText.text = "哦,伟大的Ruby,谢谢你,你真的太棒了!"; if (!hasPlayed) { audioSource.PlayOneShot(completeTaskclip); hasPlayed = true; } } }对话框画板 设置为世界模式血条 和 玩家信息画布应该是Overlay模式Canvas子对象如果填充Canvas,在锚点视图,点ctrl,选择右下角全充满子对象选择Image导入对话框背景图
背景音乐与音效 AudioClip(音频剪辑资源)播放条件需要一个Audio Source需要一个对象有Audio Listener(一般为相机)
AudioSource组件 public void PlaySound(AudioClip audioClip)//播放音效 { audioSource.PlayOneShot(audioClip);//PlayOneShot表示只播放一次 } if (!Mathf.Approximately(move.x,0)||!Mathf.Approximately(move.y,0))//Approximately()判断浮点数是否近似相等 { //lookDirection.Set(move.x,move.y); lookDirection = move; lookDirection.Normalize(); if (!walkAudioSource.isPlaying) //移动音效 { walkAudioSource.clip = walkSound; walkAudioSource.Play(); } } else { walkAudioSource.Stop(); } 人物落地音效实现 干扰:上半身碰撞地形/地面行走 Jump_Time是人物一次起跳后在空中停留的时间引入计时器,玩家起跳后开始计时Clock_Time +=Time.deltaTime接触地形后,判断Clock_Time与Jump_Time关系,测试,选取最小阈值【e.g.起跳上地形上,接触时间可能比较小】Clock_Time大于最小阈值判断为落地播放 private AudioClip landClip;landClip = Resources.Load("Gris/Audioclips/Land");//落地音效AudioSource.PlayClipAtPoint(landClip,transform.position);