【示例代码】(可以直接方便去使用,求一求去看一看吧)
前言
在梦日记及其派生中,有各种效果,这些效果对梦日记玩家来说非常重要,尤其是自行车这一类能快速在主角梦中世界探索的效果,今天,我们就来实现它。
方法
首先,我们就想一个效果,这个效果取名为"天使",它能够让玩家飘,并且移速也会快。效果可以改变主角形象,所以我也建模了一套。

然后,我们要实现的,就是定义效果 ,收集效果 ,切换效果。这三条会依次实现。若其一没实现,效果系统必不完整。
定义效果
第一要定义效果,由于那种可获得的效果最早出自于梦日记。因此,经过我在梦日记及其派生的研究,可以得出,效果在里面相当是物品。
所以,相对应的定义一个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
组件,及其它的一些代码,我们可以看到:

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