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,并勾选触发器选项

玩家要有Collider2DRigidbody2D

关于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的检测方式一样

ladderladderTopcollider的最高点要一致

效果

角色冲刺

关键代码

使用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预制体勾选isOnFirefiredGrass预制体勾选isFired

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

修改火球的脚本

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);
    }

效果

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

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

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

首先开启粒子的碰撞效果

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

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");
    }
}

效果

新物品:箱子

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

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

制作不同的箱子,添加colliderrigidbody

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
    }
}

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

效果

Last modification:October 3rd, 2020 at 09:44 pm