Unity笔记(1001-1003)

    科技2022-07-12  113

    10月1日

    npc对话

    参考https://blog.csdn.net/weixin_43673589/article/details/106559650

    对象层级

    将Canvas设为世界空间以绑定在npc身上

    给npc添加脚本

    using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEngine.UI; public class NPC : MonoBehaviour { public GameObject dialog; public GameObject tip; public Text text; public float showTime = 2; private float showTimer; private bool isShow = false; private bool isEnter = false; void Start () { tip.SetActive (false); dialog.SetActive (false); showTimer = -1; } void Update () { if (isEnter) { if (Input.GetKeyDown (KeyCode.E)) { Showdialog (); } } if (isShow) { showTimer -= Time.deltaTime; if (showTimer < 0) { dialog.SetActive (false); isShow = false; } } } private void OnTriggerEnter2D (Collider2D other) { if (other.tag == "Player") { tip.SetActive (true); isEnter = true; } } private void OnTriggerExit2D (Collider2D other) { if (other.tag == "Player") { isEnter=false; tip.SetActive (false); } } public void Showdialog () { text.text = "你好!"; isShow = true; showTimer = showTime; dialog.SetActive (true); tip.SetActive (false); } }

    npc要添加Collider2D,并勾选触发器选项

    玩家要有Collider2D和Rigidbody2D

    关于Collider2D的碰撞https://blog.csdn.net/youxijishu/article/details/104259317

    效果

    爬梯子

    制作一个平台以及一个梯子

    给梯子添加collider,并在顶端的位置再添加一个带有collider的对象

    增加的代码

    using System.Collections; using System.Collections.Generic; using UnityEngine; public class Player : MonoBehaviour { public Transform ladderCheck; //梯子 public Transform ladderTopCheck; public LayerMask ladder; public LayerMask ladderTop; public bool isLadder, isLadderTop; void Update () { if (isLadder) { if (!isLadderTop) { if (Input.GetKey (KeyCode.W)) { rb.velocity = new Vector2 (rb.velocity.x, 1); } } if (Input.GetKey (KeyCode.S)) { if (isGround) { platform.GetComponent<Collider2D> ().enabled = false; } rb.velocity = new Vector2 (rb.velocity.x, -1); } } } private void FixedUpdate () { isLadderTop = Physics2D.OverlapCircle (ladderTopCheck.position, 0.1f, ladderTop); //判断是否在梯子顶端 } private void OnTriggerEnter2D (Collider2D other) { if (other.tag == "Ladder") { isLadder = true; transform.GetComponent<Rigidbody2D> ().gravityScale = 0; if (!isLadderTop) { platform.GetComponent<Collider2D> ().enabled = false; } } } private void OnTriggerExit2D (Collider2D other) { if (other.tag == "Ladder") { isLadder = false; transform.GetComponent<Rigidbody2D> ().gravityScale = 1; platform.GetComponent<Collider2D> ().enabled = true; } } }

    ladderTop的检测方式和ground的检测方式一样

    ladder和ladderTop的collider的最高点要一致

    效果

    角色冲刺

    关键代码

    使用MovePosition函数移动到指定位置

    if (Input.GetKey(KeyCode.LeftShift)) { Vector2 velocity = new Vector2(horizontalMove, 0)*sprintDistance; rb.MovePosition(rb.position + velocity * Time.fixedDeltaTime); }

    效果

    释放火球

    准备一张火球的图片,制作成prefab

    玩家脚本添加

    using System.Collections; using System.Collections.Generic; using UnityEngine; public class Player : MonoBehaviour { public int playerDirection; //玩家面对方向 public int playerType; //玩家元素 void Update () { if(Input.GetMouseButtonDown(0)){ skillRelease(); } if(Input.GetKeyDown(KeyCode.D)){ playerDirection=1; //向右 } if(Input.GetKeyDown(KeyCode.A)){ playerDirection=-1; //向右 } } //技能释放 private void skillRelease () { switch (playerType) { case 1: GameObject objPrefab = (GameObject) Resources.Load ("Prefabs/playerFireBall"); objPrefab.transform.GetComponent<playerFireBall>().moveDirection=playerDirection; Instantiate (objPrefab, transform.position, transform.rotation); break; case 2: break; case 3: break; } } }

    火球脚本

    using System.Collections; using System.Collections.Generic; using UnityEngine; public class playerFireBall : MonoBehaviour { // Start is called before the first frame update public float moveSpeed; public float maxMoveDistance; //最大移动距离 private float moveDistance; //移动距离 public int moveDirection; //移动方向 private Vector3 startPosition; //起始位置 void Start() { startPosition=transform.position; } void Update() { transform.Translate(Vector3.right*moveDirection *moveSpeed * Time.deltaTime); moveDistance=Mathf.Abs((transform.position-startPosition).x); if(moveDistance>=maxMoveDistance){ Destroy(gameObject); } } }

    效果

    火焰与草丛互动

    制作三种不同状态的草丛prefab,设定同一个taggrass,并添加collider

    将它们都添加同一个Object.cs脚本

    using System.Collections; using System.Collections.Generic; using UnityEngine; public class Object : MonoBehaviour { public bool isOnFire; public bool isFired; public int objType; private float fireTimer; public float fireTime; private float growTimer; //生长时间 public float growTime; void Start () { } void Update () { if (isOnFire) { //正在燃烧 if (fireTimer < fireTime) { fireTimer += Time.deltaTime; } else { GameObject firedGrassPb=(GameObject) Resources.Load ("Prefabs/firedGrass"); firedGrassPb.transform.GetComponent<Object>().isFired=true; Instantiate(firedGrassPb,transform.position,transform.rotation); Destroy (gameObject); } } if (isFired) { //烧完了 if (growTimer < growTime) { growTimer += Time.deltaTime; } else { GameObject grassPb=(GameObject) Resources.Load ("Prefabs/grass"); Instantiate(grassPb,transform.position,transform.rotation); Destroy (gameObject); } } } }

    fireGrass预制体勾选isOnFire,firedGrass预制体勾选isFired

    fireTime,GrowTime分别表示烧完,生长所需时间

    修改火球的脚本

    playerFireBall.cs

    private void OnTriggerEnter2D (Collider2D other) { if (other.tag == "grass") { if (!other.transform.GetComponent<Object> ().isOnFire && !other.transform.GetComponent<Object> ().isFired) { Destroy (gameObject); GameObject fireGrassPb = (GameObject) Resources.Load ("Prefabs/fireGrass"); fireGrassPb.transform.GetComponent<Object> ().isOnFire = true; Instantiate (fireGrassPb, other.transform.position, other.transform.rotation); Destroy (other.gameObject); } } }

    效果

    10月2日

    元素交互

    水与火

    照葫芦画瓢,做一个放水球的功能,新建名为playerSkill.cs的脚本,并把之前playerFireBall.cs中的内容复制过去,然后给水球和火球都绑定playerSkill脚本

    假设潮湿的草遇到火元素会烘干,然后有蒸发的特效,燃烧的草遇到水则会被扑灭

    简单制作一个蒸发的粒子特效

    首先新建一个water材质球,然后修改Shader,选择水滴的图片

    然后新建steam粒子,将water作为材质,并适当修改粒子的属性

    再制作潮湿和烘干的草丛预制体

    被扑灭草丛

    修改playerSkill.cs

    using System.Collections; using System.Collections.Generic; using UnityEngine; public class playerSkill : MonoBehaviour { private enum skillTypes { fire, water, wind } public int skillType; //技能类型 public float moveSpeed; //移动速度 public float maxMoveDistance; //最大移动距离 private float moveDistance; //移动距离 public int moveDirection; //移动方向 private Vector3 startPosition; //起始位置 void Start () { startPosition = transform.position; //其实位置 } void Update () { //移动超过一定距离销毁 transform.Translate (Vector3.right * moveDirection * moveSpeed * Time.deltaTime); moveDistance = Mathf.Abs ((transform.position - startPosition).x); if (moveDistance >= maxMoveDistance) { Destroy (gameObject); } } private void OnTriggerEnter2D (Collider2D other) { //元素与物品交互(碰撞) if (other.tag == "grass") { Object grass = other.transform.GetComponent<Object> (); switch (skillType) { //火技能 case (int) skillTypes.fire: //草丛没有燃烧 没有烧尽 没有潮湿 没有被扑灭 if (!grass.isOnFire && !grass.isFired && !grass.isOnWater&&!grass.isOutfire) { Destroy (gameObject); GameObject fireGrassPb = (GameObject) Resources.Load ("Prefabs/fireGrass"); Instantiate (fireGrassPb, other.transform.position, other.transform.rotation); Destroy (other.gameObject); } //潮湿的草丛 if (grass.isOnWater) { Destroy (gameObject); GameObject waterGrassPb = (GameObject) Resources.Load ("Prefabs/dryingGrass"); Instantiate (waterGrassPb, other.transform.position, other.transform.rotation); Destroy (other.gameObject); GameObject steam = (GameObject) Resources.Load ("Prefabs/steam"); Instantiate (steam); } break; //水技能 case (int) skillTypes.water: //草丛没有燃烧 没有烧尽 没有被扑灭 if (!grass.isOnFire && !grass.isFired&&!grass.isOutfire) { Destroy (gameObject); GameObject waterGrassPb = (GameObject) Resources.Load ("Prefabs/waterGrass"); Instantiate (waterGrassPb, other.transform.position, other.transform.rotation); Destroy (other.gameObject); } //草丛正在燃烧 if (grass.isOnFire) { } break; } } } }

    Object.cs

    using System.Collections; using System.Collections.Generic; using UnityEngine; public class Object : MonoBehaviour { public bool isOnFire; public bool isFired; //烧尽 public bool isOnWater; public bool isDrying; //烘干 public int objType; private float fireTimer; public float fireTime; private float growTimer; //生长时间 public float growTime; public float dryTime; //烘干时间 private float dryTimer; void Start () { } void Update () { if (isOnFire) { //正在燃烧 if (fireTimer < fireTime) { fireTimer += Time.deltaTime; } else { GameObject firedGrassPb=(GameObject) Resources.Load ("Prefabs/firedGrass"); Instantiate(firedGrassPb,transform.position,transform.rotation); Destroy (gameObject); } } if (isFired) { //烧完了 if (growTimer < growTime) { growTimer += Time.deltaTime; } else { GameObject grassPb=(GameObject) Resources.Load ("Prefabs/grass"); Instantiate(grassPb,transform.position,transform.rotation); Destroy (gameObject); } } if(isDrying){ if (dryTimer<dryTime) { dryTimer += Time.deltaTime; } else { GameObject grassPb=(GameObject) Resources.Load ("Prefabs/grass"); Instantiate(grassPb,transform.position,transform.rotation); Destroy (gameObject); } } } }

    效果

    火与风

    风有概率吹出草丛里的道具

    制作风技能

    制作加血道具

    为了方便给Object添加isNormal属性,表示正常状态

    prob表示发生某事件概率

    给grass预制件勾选上

    playerSkill脚本

    case (int) skillTypes.wind: if (grass.isNormal) { Destroy (gameObject); //概率吹出道具 int prob = Random.Range (0, 100); if (prob < other.transform.GetComponent<Object> ().prob) { GameObject hearteGrassPb = (GameObject) Resources.Load ("Prefabs/heart"); Instantiate (hearteGrassPb, other.transform.position, other.transform.rotation); } Destroy (other.gameObject); }

    效果

    风吹向燃烧的草丛会引发爆炸

    制作爆炸预制件(同蒸发效果)

    使主角与爆炸粒子碰撞会掉血

    首先开启粒子的碰撞效果

    然后在player的OnParticleCollision方法中写碰撞粒子后的事件

    public Transform hearts; //血条 void Start () { hearts = GameObject.Find ("hearts").transform; bloodNum = hearts.GetComponent<hearts> ().bloodNum; } private void OnParticleCollision (GameObject other) { if (other.tag == "explode") { changeBlood (-1); } } private void OnTriggerEnter2D (Collider2D other) { if(other.tag=="heart"){ changeBlood(1); Destroy(other.gameObject); } } private void changeBlood (int type) { //1是加血 -1是减血 if (type == 1) { if (bloodNum < maxBloodtNum) { bloodNum += 1; hearts.GetComponent<hearts> ().changeBlood(type); } } else if (type == -1) { if (bloodNum > 0) { bloodNum -= 1; hearts.GetComponent<hearts> ().changeBlood(type); } } }

    heart.cs

    using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEngine.UI; public class hearts : MonoBehaviour { public Transform heart0; public Transform heart1; public Transform heart2; public List<Transform> heartList; public int maxBloodNum; public int bloodNum; void Start () { heartList = new List<Transform> (); heartList.Add (heart0); heartList.Add (heart1); heartList.Add (heart2); if (bloodNum != maxBloodNum) { for (int i = 0; i < maxBloodNum - bloodNum; i++) { heartList[maxBloodNum-i-1].GetChild (1).GetComponent<Image> ().enabled = false; } } } void Update () { } public void changeBlood (int type) { if (type == 1) { if (bloodNum < maxBloodNum) { heartList[bloodNum].GetChild (1).GetComponent<Image> ().enabled = true; bloodNum += 1; } } else if (type == -1) { if (bloodNum > 0) { bloodNum -= 1; heartList[bloodNum].GetChild (1).GetComponent<Image> ().enabled = false; } } } }

    效果

    10月3日

    主角攻击(击剑)

    准备一张剑的图片,添加collider,勾选触发器

    添加一个剑平移(击剑)的简单动画

    绑定在角色身上

    player

    public GameObject sword; //武器 剑 void Start () { sword = GameObject.Find ("sword"); } void Update () { //普通攻击 if (Input.GetMouseButtonDown (0)) { sword.transform.GetComponent<Animation>().Play ("swordAttack"); } }

    效果

    新物品:箱子

    箱子与元素的交互 部分遵循与草丛的交互规则

    普通箱子不可打破,潮湿箱子可以被打破

    制作不同的箱子,添加collider和rigidbody

    给Object添加

    private void OnTriggerStay2D (Collider2D other) { if (objType == (int) objTypes.woodenBox) { //潮湿的箱子可打破 if(isOnWater){ if (other.tag == "sword") { if (other.transform.GetComponent<Animation> ().IsPlaying ("swordAttack")) { Destroy (gameObject); } } } } }

    效果

    相机跟随

    给相机添加CameraFollow.cs脚本

    using System.Collections; using System.Collections.Generic; using UnityEngine; public class CameraFollow : MonoBehaviour { public Transform player; //设定一个角色能看到的最远值 public float Ahead; //设置一个摄像机要移动到的点 public Vector3 targetPos; //设置一个缓动速度插值 public float smooth; void Start () { } void Update () { targetPos = new Vector3 (player.position.x, gameObject.transform.position.y, gameObject.transform.position.z); if (player.position.x > 0f) { targetPos = new Vector3 (player.position.x + Ahead, gameObject.transform.position.y, gameObject.transform.position.z); } else { targetPos = new Vector3 (player.position.x - Ahead, gameObject.transform.position.y, gameObject.transform.position.z); } transform.position = Vector3.Lerp (transform.position, targetPos, smooth * Time.deltaTime); } }

    切换角色时改变相机的player

    注意要传入Instantiate后的对象而不是prefab对象

    Player.cs

    if (Input.GetKeyDown (KeyCode.Alpha1)) { GameObject objPrefab = (GameObject) Resources.Load ("Prefabs/playerCat"); GameObject player= Instantiate (objPrefab, transform.position, transform.rotation); changePlayerCamera (player); DestroyImmediate (gameObject); } private void changePlayerCamera (GameObject player) { GameObject camera = GameObject.Find ("MainCamera"); camera.GetComponent<CameraFollow> ().player = player.transform; }

    效果

    视差效果

    https://www.bilibili.com/video/BV1Zx411X72x?from=search&seid=14704518843659195740

    随便制作两个背景

    BackgroundParallax.cs

    using System.Collections; using System.Collections.Generic; using UnityEngine; public class BackgroundParallax : MonoBehaviour { public new Camera camera; //摄像机对象 public Transform[] backgrounds; //不同层次的背景 public float[] parallaxScales; //每个层次的视差比例(即背景与摄影机的移动量的比例) public float smoothTime; //看做是速度的倒数就好~ private Vector3 lastCameraPosition; //上一次相机的位置,用于计算滚动量 private Vector3 velocity; //速度向量,Vector3.SmoothDamp用到的变量 void Start () { lastCameraPosition = camera.transform.position; //初始化lastCameraPosition velocity = Vector3.zero; //初始化velocity } void Update () { //遍历每个层次的背景 for (int i = 0, count = backgrounds.Length; i < count; i++) { Vector3 parallax = (lastCameraPosition - camera.transform.position) * parallaxScales[i]; //计算滚动量(滚动距离=摄像机移动距离*视差比例) parallax.z = 0f; //设置z轴滚动量为0,防止背景前后移动 Vector3 target = backgrounds[i].position + parallax; //目标坐标=当前背景坐标+滚动量 backgrounds[i].position = Vector3.SmoothDamp (backgrounds[i].position, target, ref velocity, smoothTime); //用Vector3.SmoothDamp将背景平滑移动 } lastCameraPosition = camera.transform.position; //更新lastCameraPosition } }

    将该脚本绑定到摄像机上,调整参数

    效果

    Processed: 0.014, SQL: 8