unity实现梦日记式效果

【示例代码】(可以直接方便去使用,求一求去看一看吧)

前言

在梦日记及其派生中,有各种效果,这些效果对梦日记玩家来说非常重要,尤其是自行车这一类能快速在主角梦中世界探索的效果,今天,我们就来实现它。

方法

首先,我们就想一个效果,这个效果取名为"天使",它能够让玩家飘,并且移速也会快。效果可以改变主角形象,所以我也建模了一套。

然后,我们要实现的,就是定义效果收集效果切换效果。这三条会依次实现。若其一没实现,效果系统必不完整。

定义效果

第一要定义效果,由于那种可获得的效果最早出自于梦日记。因此,经过我在梦日记及其派生的研究,可以得出,效果在里面相当是物品。

所以,相对应的定义一个item类。经过刚才研究及我实践中,我察觉到这个物品类主要有以下特征,一是有名字二是可以控制使用三是可以控制显示四是有使用效果为了让大家理解,use方法简称使用效果

由于使用效果(方法)可能不同,所以就给use方法设为了纯虚函数,因为我没有为item物品类想好一个默认用到的效果 ,而又给item物品类设为了抽象基类。

csharp 复制代码
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public abstract class item
{
    public string name = "default";
    public bool canUse = true;
    public bool isHide = false;
    public abstract void use();
    public item(string name = "default", bool canUse = true, bool isHide = false)
    {
        this.name = name;
        this.canUse = canUse;
        this.isHide = isHide;
    }
}

接着,我们就根据这个抽象类,我们就能实现各种各样的物品类。

就如继承item类的effectItem类。effectItem类就是效果物品类 ,假定有一个枚举叫effect,用effect效果枚举就可以确定effectItem物品的效果。effectItem就是用来切换效果的 ,因此,我们可以在使用效果里面添加用来切换效果的语句

csharp 复制代码
using System.Collections;
using System.Collections.Generic;
using Unity.VisualScripting;
using UnityEngine;

public class effectItem : item
{
    effect effect;
    you you;
    public override void use()
    {
        trigger.funcs.Add(you.changeEffect(effect));//切换效果
    }
    public effectItem(effect effect, you you)
    {
        this.effect = effect;
        this.name = you.effectName[(int)effect];
        this.canUse = true;
        this.you = you;
    }
}

收集效果

第二要收集效果。主要就是靠z.cs脚本来,因为这个z.cs脚本就是用来执行交互之后的操作的 ,在z.cs中,我们要它既能传送玩家,又能获得效果,就要一个模式来区分。

csharp 复制代码
public enum mode{
    normal,
    tele,
    effect,
    talk
};

根据这个模式,我们可以获得效果。获得效果时我们先要有个物品栏items,之后就将这个效果放进玩家的物品栏去,就能获得效果。但还需要让玩家暂停和npc暂停,再让它切换成normal(普通)模式(符合梦日记原版)。

并且,我们也给它加点花 ,先通过一些特效提示你已经获得该效果后播放点音效 。这样就完成了收集效果

csharp 复制代码
private IEnumerator get(effect e)
{
    if (wait)
    {
        wait = false;
        //示例
        npcMove.npcCanMove = false;
        you.canMove = false;
        //audio
        if (null == GetComponent<AudioSource>())
        {
            gameObject.AddComponent<AudioSource>();
        }
        //play screen
        if (extra)
        {
            screen.GetComponent<Image>().enabled = true;
            GetComponent<AudioSource>().PlayOneShot(screenSound);
            yield return new WaitForSeconds(1f);
            GetComponent<AudioSource>().Stop();
            screen.GetComponent<Image>().enabled = false;
            yield return new WaitForSeconds(1f);
        }
        else
        {
            Instantiate(getHintPrefab, you.transform.position + new Vector3(0, 3, 0), getHintPrefab.transform.rotation);
            GetComponent<AudioSource>().PlayOneShot(keySound);
            yield return new WaitForSeconds(2f);
        }
        GetComponent<AudioSource>().PlayOneShot(getSound);
        getImage.GetComponentInChildren<Text>().text = you.effectName[(int)e];
        getImage.GetComponent<Image>().enabled = true;
        getImage.GetComponentInChildren<Text>().enabled = true;
        //show
        for (int i = 10; i > 0; i--)
        {
            getImage.GetComponent<Image>().color = new Color(1, 1, 1, 1 / (float)i);
            getImage.GetComponentInChildren<Text>().color = new Color(0, 0, 0.785f, 1 / (float)i);
            yield return new WaitForSeconds(0.01f);
        }
        //hide
        yield return new WaitForSeconds(1);
        for (int i = 1; i <= 10; i++)
        {
            getImage.GetComponent<Image>().color = new Color(1, 1, 1, 1 / (float)i);
            getImage.GetComponentInChildren<Text>().color = new Color(0, 0, 0.785f, 1 / (float)i);
            yield return new WaitForSeconds(0.01f);
        }
        getImage.GetComponent<Image>().enabled = false;
        getImage.GetComponentInChildren<Text>().enabled = false;
        //get effect
        you.canMove = true;
        npcMove.npcCanMove = true;
        you.effecthaves[(int)e] = true;
        you.effectNum++;
        you.items.Add(new effectItem(e, you));
        mod = mode.normal;
        wait = true;
    }
    yield return null;
}

void Start()
{
    if ("" == worldName)
    {
        worldName = "nexus";
    }
    if (you.wasd.n == w.front)
    {
        haveFront = false;
        w.front = you.wasd.s;
    }
}

void Update()
{
    if (((you.x + 1) % m.x == w.x && you.y == w.y && you.front == you.wasd.d && (!haveFront || you.wasd.a == w.front) && Input.GetKeyDown("z")) || ((you.x - 1 < 0 ? m.x - 1 : you.x - 1) == w.x && you.y == w.y && you.front == you.wasd.a && (!haveFront || you.wasd.d == w.front) && Input.GetKeyDown("z")) || (you.x == w.x && (you.y + 1) % m.y == w.y && you.front == you.wasd.s && (!haveFront || you.wasd.w == w.front) && Input.GetKeyDown("z")) || (you.x == w.x && (you.y - 1 < 0 ? m.y - 1 : you.y - 1) == w.y && you.front == you.wasd.w && (!haveFront || you.wasd.s == w.front) && Input.GetKeyDown("z")))
    {
        if (mode.tele == mod)
        {
            StartCoroutine(go());
        }
        if (mode.effect == mod && !you.effecthaves[(int)getEffect])
        {
            StartCoroutine(get(getEffect));
        }
    }
}

切换效果

第三要切换效果,以用9键来使用效果的亻列子,我们可以开始检测一下是否有没有得到效果,我在下面用了一个布尔数组来判断是否得到效果,相当于哈希表的作用,查询时间复杂度为O(1),能通过效果转化为有没有拿到的值。

(在我对算法练习的过程中,哈希表因为查询时间复杂度为O(1),所以用这个就能在查询元素的时候把原来算法的时间复杂度更减一层,推荐大家以后能用它就尽量可以去用它。)

csharp 复制代码
if (Input.GetKeyDown("9") && canMove && effecthaves[(int)effect.angel])
{
    StartCoroutine(changeEffect(effect.angel));
}

而我又想因为切换的过程中要有等待,所以用一个协程来实现这个方法。由于在举例,所以这个方法就用changeEffect来表示。

在切换过程中,先还是让玩家暂停和npc暂停,再播放效果切换后的声音(因为符合梦日记)

之后,就要切换效果了,我是这样的,可不必跟着做。
等待 设置玩家当前效果为切换的当前效果 让玩家随机变为一种乱码材质 根据切换后的效果修改玩家属性 继续游戏

csharp 复制代码
public IEnumerator changeEffect(effect effect)
{
    commandIsEnd = false;
    canMove = false;
    npcMove.npcCanMove = false;
    if (effect.none != effect ? null != effectEqiupSound : null != effectCancelEqiupSound)
    {
        GetComponent<AudioSource>().PlayOneShot(effect.none != effect ? effectEqiupSound : effectCancelEqiupSound);
    }
    nowEffect = effect;
    GetComponent<MeshRenderer>().material = screens[change[Random.Range(0, change.Length)]];
    yield return new WaitForSeconds(0.2f);
    isChangeEffect = true;
    canMove = true;
    npcMove.npcCanMove = true;
    commandIsEnd = true;
}

在我测试切换效果的时候,突然发现使用效果后只要你传送到外边,效果就会不见,于是,我就用这个isChangeEffect开关来实现了在传送后切换效果。

这个isChangeEffect开关的作用,我跟大家说吧,当你将这个开关启用为真的时候,就可以切换效果了,之后这个开关会自动关闭,用图理解等于:
线程1 do somethings isChangeEffect = true 线程2 if isChangeEffect else do somethings isChangeEffect = false

这在之后的游戏开发中是一个好用的技巧,只需要动一个开关,就可以执行一段代码,很方便了,需要注意的是,这只在要无限次执行的方法里有用。

最后,我们可以导入示例代码中的所有脚本,通过使用刚才的z.cs组件,及其它的一些代码,我们可以看到:

后言

在刚才的梦日记游戏演示视频中,会有鸟人们来抓附窗子,虽然在梦日记里面只有这一种敌人,但如果被不幸抓到的话,就会被困在随机一个世界的"小黑屋"里,在这里,你只能重新开始探索整个梦世界,这无疑使梦日记变得更令人深刻,在下篇博客中,就来实现这个抓人的功能。

相关推荐
Maybe_ch5 小时前
WinForm-免费,可商用的WinForm UI框架推荐
windows·ui·c#
future14125 小时前
游戏开发日志
学习·游戏开发
火星机器人life5 小时前
(二)Unity3d-ROS联合仿真:运行Unity-Robotics-Hub
unity·游戏引擎·unity3d-ros联合仿真
DaLiangChen7 小时前
ARFoundation系列讲解 - 101 VisionPro 真机调试
unity·ar·mr·苹果vision pro·visonpro·空间智能·arfoundation
AI、少年郎9 小时前
从 C# 到 Python:项目实战第五天的飞跃
开发语言·数据库·c#
Wiktok11 小时前
03-虚幻引擎蓝图类的各父类作用讲解
游戏引擎·虚幻·蓝图
Lazy龙11 小时前
C#之线程Thread
c#
大飞pkz12 小时前
【设计模式&C#】工厂方法模式(相比简单工厂模式更加具有灵活性和扩展性的工厂模式)
开发语言·设计模式·c#·工厂方法模式
浮生带你学Java15 小时前
Spring 中的 Bean 作用域(Scope)有哪些?各自适用于什么场景?
开发语言·jvm·c#