FNF源代码指南
CoCo水君
编辑于 2021年12月19日 22:31

1. FNF源代码指南

由Tuxsuper制作(https://gamebanana.com/members/1787500)

(原文地址:https://gamebanana.com/tuts/13798)

由Toast(吐司)翻译

在不直接替换原游戏文件的基础上添加歌曲/Week/人物/舞台/标题/台词

在修改源代码文件后时刻记得按Ctrl+S或者在菜单中保存。

本指南中提到的代码行数并非百分百准确,因为增加或是删除代码都会导致整体的行数发生变化。因此按Ctrl+F直接查找关键词会更加事半功倍。

在对代码进行修改后务必重新编译游戏好令你的修改生效!

【】←内的文字为译者自行附加的说明

目  录

1.1 必读!前置工作/编译

1.2 添加自定义歌曲

1.3 添加自定义人物

1.4 添加自定义Week

1.5 添加自定义舞台

1.6 添加自定义标题Logo/文字/等等

1.7 添加自定义台词

1.8 添加自定义过场

1.9 歌曲进行中的事件

1.10 增加/移除难度

1.11 新week文件夹

1.12 常见问题

1.13 报错定位

1.14 代码速查表


1.1 必读!前置工作/编译:

提醒:在Windows上编译游戏你需要起码6GB的空间,因此在编译前请确保你的盘符内已清理出足够的空间。

一些推荐:使用setup.bat(https://drive.google.com/file/d/1JT3EE7dJk9MKNzr2-YbojiMwJ23Mh4L2/view?usp=sharing)(无法从谷歌云下载的可选择从天翼云下载:https://cloud.189.cn/web/share?code=Bj2u2qURnIN3)来安装必要的一系列文件,如Haxe库,Visual Studio Community以及修正其他的一些错误。但在此之前你的电脑里需要有Haxe 4.1.5(https://haxe.org/download/version/4.1.5/)Git(https://git-scm.com/downloads)GitHub文件(https://github.com/ninjamuffin99/Funkin)!把setup.bat文件放入GitHub的文件夹,与README在同级目录下以取得最佳效果!在安装过程中系统询问你任何问题时尽管按下Y键。除此以外,在代码编辑器方面我比较推荐Visual Code(https://code.visualstudio.com/)

所需的东西:

- Git(必需)(https://git-scm.com/downloads)

- GitHub文件(必需)(https://github.com/ninjamuffin99/Funkin)

- Haxe 4.1.5(必需)(https://haxe.org/download/version/4.1.5/)

     - Haxe 库(必需)

- Visual Studio Community(必需)(https://visualstudio.microsoft.com/)

     - Visual Studio Community组件(必需)

          - MSVC v142 - VS 2019 C++ x64/x86build tools -(最新版本)

          - Windows 10 SDK -(最新版本)

- Visual Code(可选)

     - Visual Code插件(可选)

          - Lime(https://marketplace.visualstudio.com/items?itemName=openfl.lime-vscode-extension)

          - BracketPair Colorizer 2(https://marketplace.visualstudio.com/items?itemName=CoenraadS.bracket-pair-colorizer-2)

          - HXCPPDebugger(https://marketplace.visualstudio.com/items?itemName=vshaxe.hxcpp-debugger)

          - Tabnine(https://marketplace.visualstudio.com/items?itemName=TabNine.tabnine-vscode)

如何获取Github文件:

下载github文件(https://github.com/ninjamuffin99/Funkin)(点击绿色的“Code”按钮,接着选择“Download ZIP”,下载完成后将文件解压,里面所有的文件都是需要的)。

或者你也可以这么下载:

下载并安装git,打开命令提示符,用cd “location”指令将当前目录调整至你想要存放github文件的地方,然后输入git clone https://github.com/ninjamuffin99/Funkin.git并按下回车键。

(注意:以此种方式获取的文件夹默认名称是Funkin,而不是第一种方式中的Funkin-Master,下文中若是提到Funkin-Master文件夹,即是你使用此种方式取得的Funkin文件夹)

示例:

如何获取必需的其余东西:

下载Haxe 4.1.5(https://haxe.org/download/version/4.1.5/)(是的,必须是4.1.5)和Git(https://git-scm.com/downloads),在安装好之后,下载setup.bat(https://drive.google.com/file/d/1JT3EE7dJk9MKNzr2-YbojiMwJ23Mh4L2/view?usp=sharing)(无法从谷歌云下载的可选择从天翼云下载:https://cloud.189.cn/web/share?code=Bj2u2qURnIN3)(顺带一提如果你的浏览器或者杀毒软件弹出提醒说该文件可能会危害你的计算机,请忽略这类提醒。批处理文件会直接运行cmd命令,所以浏览器或杀毒软件会报警告,但我可以向你保证它是安全的。如果你在编辑器里打开这个文件,你可以看它具体运行了哪些命令)并将其粘贴到Funkin-Master文件夹中。之后双击运行它,按照它所说的做,在它要求按Y的时候按Y,在它要求选择IDE的时候选择Visual Code,因为Visual Code就是坠好滴:)

如何高效地写代码/编译:

安装Visual Code(https://code.visualstudio.com/)(它与你在windows上编译游戏需要安装的Visual Studio是两样东西),之后再安装Lime(https://marketplace.visualstudio.com/items?itemName=openfl.lime-vscode-extension)扩展,或者在Visual Code中按下左边工作栏的方形符号来搜索它。接着打开命令提示符,我们要将里面的目录修改为Funkin-Master文件夹所在的位置,复制一下Funkin-Master文件夹的位置,然后在命令提示符中输入这个命令,不需要加引号。

cd “Funkin-Master文件夹的位置”

示例:

然后按顺序输入以下的命令:

haxelib update flixel-tools

haxelib update flixel-templates

flixel configure . -ide vscode

如果你是通过 “Download ZIP”的方式下载了github文件,就要执行这个命令,并遵循所给的提示(如果你一开始用的是git clone的方法,就跳过这一步)。

git clone https://github.com/ninjamuffin99/Funkin.git

现在打开Funkin-Master文件夹内新的Funkin文件夹,应该有一个隐藏的名为.git的文件夹。

如果你在Funkin文件夹里没有看到.git文件夹,那么就点击文件资源管理器左上方的“查看”,勾选“隐藏的项目”。

示例:

(顺带把“文件扩展名”一起勾上对你理解指南可能会有一定的帮助)。

接着,复制.git文件夹并将其粘贴到Funkin-Master文件夹中。一旦粘贴完成,你就可以删除Funkin-Master里面的Funkin文件夹了。

如果你一开始就使用了git clone的方式,请继续往下看(如果你用的是“Download ZIP”的方式,记得要完成上面的步骤后才能往下看):

前面的步骤都完成后,打开Visual Code,点击文件(File)->打开文件夹(Open Folder)或按Ctrl+K+O,打开Funkin Master文件夹。接着从该文件夹或Visual Code内的资源管理器中打开一个haxe文件,看一下底部的工作栏。更改工作栏中的选项,让它与截图中的一致。(你必须得在Visual Code中打开haxe文件,才能出现Windows/Debug选项!)。

然后点击 “文件(File)”->“首选项(Preferences)”->“键盘快捷方式(Keyboard Shortcuts)”或者直接按Ctrl+K+S,搜索“F5”。按下删除键或单击鼠标右键选择“删除键绑定”来删除所有只单独与F5绑定的快捷键。

然后搜索“build task”,将 "Run Build Task(运行生成任务)&#​34;的键绑定改为F5,将 “Configure Default Build Task(配置默认生成任务) ”的键绑定改为Ctrl+Shift+B。

之后退出键盘快捷方式,如果你想编译普通版本,就按Ctrl+Shift+B并搜索lime test windows,如果你想使用haxeflixel的调试菜单,就搜索lime test windows -debug。

现在只需按下F5,Visual Code就会编译游戏并显示错误,总体上提高了工作的效率。

代码会有自动补完,悬停,即时显示错误等功能!

【另一种快速打包的方式:

回到Funkin-Master文件夹下,

务必确认是在这个目录下

鼠标移到空白处,按住Shift键的同时单击鼠标右键,在弹出的右键菜单中选择“在此处打开Powershell窗口”,在新开启的Powershell窗口中输入lime test windows,如果你想使用haxeflixel的调试菜单,就输入lime test windows -debug然后按下回车,游戏便会自动开始打包】


1.2 添加自定义歌曲:

提醒:由于文件读取系统的关系,你需要复制week 1的json文件或是打开json文件并改变里面player1,player2和song的名称,这样它才能从对应的week文件夹或是shared文件夹里读取到正确的数据。如果该json文件里需要读取的人物动画数据不在这首自定义歌曲所对应的新week的文件夹里,会导致游戏崩溃。

在assets/preload/data目录下创建一个新的文件夹,以新歌曲的名字命名(要小写且中间不能有空格)。从其他歌曲的文件夹里把json文件复制一份到你的新文件夹里,或是直接添加你已经做好的json文件。将json文件命名为新歌曲的名字(这里不必小写),然后分别在简单和困难难度的json文件名后加上“-easy”和“-hard”。

接着到assets/songs目录下,再次创建一个新的文件夹,依然以新歌曲的名字命名。把你的音乐文件都添加到这个新文件夹里,伴奏部分命名为Inst,人声部分命名为Voices。

注意开头是大写的i,不是小写的l

(非必需步骤:如果你已经在FreeplayState.hx文件中把新歌曲添加到了某个week中,你可以跳过下面这一步)

如果你想把新歌曲加入到游戏的Freeplay列表中,到assets/preload/data目录下,打开freeplaySonglist.txt文件,随便在哪一行把你新歌曲的名字加进去。

接着把游戏编译一遍,进到你的新歌曲里,按下数字键“7”,你可以在这里对谱面进行修改,再点击“Song”标签,确保歌曲名那栏是你新歌曲的名称,按下Save就可以把assets/preload/data目录下你新歌曲的json文件更新为你修改后的版本。


1.3 添加自定义人物

首先,你需要把新人物的png文件和xml文件放入assets/shared/images目录下。(如果你乐意的话,你也可以在images里另外新建一个文件夹,然后把上述的两个文件放进去)

接着到assets/preload/data目录下找到characterList.txt这个文本文件,将你新人物的名字添加进去(需要小写)。

如果你的人物是player1(即boyfriend位),那么人物名字前面需要加上bf,或者你也可以直接编辑Character.hx里的代码来把你的人物添加进游戏里。

然后来到source文件夹内部,打开Character.hx这个文件,复制其中一个人物由case打头的一连串代码,然后另起一行粘贴上去,我们将基于这个复制的代码文本来完成新人物的代码写作。首先将case后的人物名称改成你新人物的名字(注意依然要小写),然后把frames = Paths.getSparrowAtlas这行代码最后括号里的内容修改为新人物png文件和xml文件所在的位置。

示例:

下一步,将新人物各动作的动画名称与人物xml文件内的对应起来。你需要修改的是括号内第二对单引号里面的内容,例如‘Dad idle dance’这一类。或者你也可以反过来,把人物xml文件里的动画名称修改成代码里已有的内容【个人不太推荐这一种,看代码的时候会比较别扭】

如果新人物在游戏里上下左右的歌唱动画与普通站立时位置偏移较大的话,你可以调整offset值,第一个数值调整的是x坐标,第二个数值调整的是y坐标。【在此推荐github上由studioNOKOI制作的fnfoffsethelper工具(https://github.com/studioNOKOI/fnfoffsethelper),可以十分快捷方便地完成坐标的调整】

接着打开source目录下的另一个文件HealthIcon.hx,为你的新人物添加一行新的代码。

示例:

‘monster-christmas’, <- 这里填的是人物的名字(需小写)。

‘[19,20 ]’, <- 这里填的是assets/preload/images 目录下的iconGrid.png图像内你人物两种血量状态下的头像的位置序号,计数的方式是从0开始从左往右数。

如果你想往iconGrid图像内添加你的人物头像,可以直接在原文件上绘制,注意要对齐位置。或者你也可以用Adobe Animate,把人物的头像复制进iconGrid,然后把png图像导出并覆盖原文件。

现在,把游戏编译一遍,随便进到一首歌里,按下数字键“7”,点击“Song”标签,然后在人物列表里点选你的新人物,按下回车键就可以看到你的人物出现在舞台上了。


1.4 添加自定义Week

打开StoryMenuState.hx文件,在weekData下添加一行代码,里面写入新week的歌曲名,不要忘记在上一行代码后填上一个英文逗号,整段代码中只有最后一行代码后是不需要逗号的。

示例:

接着在weekUnlocked下面添加一个true,这里也别忘记前面要加逗号。

接着在weekCharacters下面按照站在舞台最左边的人物,最右边的人物,中间的人物的顺序添加人物名字,别忘记逗号的事。(如果新week里添加的是新人物,你需要提前先把新人物创建出来)(这里的名字都需要小写)。

接着在weekNames下添加显示在week右上角的关卡描述,再次,别忘了逗号。

下一步,来到assets\preload\images\storymenu目录下,把新week的png图片按序号命名后放入。

示例:

然后,打开MenuCharacter.hx文件,添加你的人物在故事模式菜单页面的线稿动画。

打头的是人物的名字,接着是线稿动画的元件名,第三位的是帧率。

如果你想给自己的人物制作线稿动画,你可以到art/flashFiles目录下,打开campain_menu_UI_assets。你可以在里面创建新人物的动画,然后随同其他角色的线稿动画一并导出sprite表。当然你也可以选择直接在现有的sprite表上绘画,然后手动调整对应的xml文件【比较费时间】。

将导出的新sprite表和xml文件替换掉assets\preload\images的原文件。

如果你需要添加新的girlfriend,你还有些额外的步骤要做。打开PlayState.hx文件,按Ctrl+F查找gfVersion:String = 'gf&#​39;; 然后在下面的switch行内给你的girlfriend添加一个新的case。这个switch的判断依据是舞台的名字,所以你在添加新的girlfriend之前,最好先把舞台给创建了。

不过你也可以让程序根据歌曲名来切换到新的girlfriend,只要在switch段下面加上if的代码。


1.5 添加自定义舞台

首先把舞台的图像添加到assets\shared\images目录下,记住图像的分辨率要与你作为参照的舞台图像一致,也不要添加分辨率过大或过小的图像。下面是一个舞台的分辨率示例:

接着打开Playstate.hx文件,在switch (SONG.song.toLowerCase())下添加一个case,确保你的舞台代码在一对{}之中,不要和别的舞台的混在一起。

示例:

‘cursed’ <- 这里填需要搭载新舞台的歌曲的名称。

curStage = 'minecraft&#​39; <- 这里填舞台的名称,在一些其他的功能中可能会用到。

var bg:FlxSprite <-bg代表你所导入的舞台组件的临时名称,可以随意取,不必和它的PNG图像名称保持一致。

Paths.image(‘minecraft’) <- 这里填写舞台PNG图像的名称。如果你想添加多个舞台组件,可以将{}内从var开始的内容复制多份,然后修改对应的组件名称和PNG图像名称。

‘(-600, -200)’ <- 图像的x坐标与y坐标。如果导入后图像的位置有问题可以修改这两个值。

这部分的代码有许多可以自由调整的地方,我也不可能一一全部说明。详情参见代码速查表。


1.6 添加自定义标题Logo/文字/等等:

打开TitleState.hx文件

Logo - 按下Ctrl+F,搜索logobl,修改它对应的PNG图像名以及xml的动画帧名,或者你也可以选择直接用新的文件替换掉原本的logoBumpin.png和logoBumpin.xml。【当然新文件的名称要与原本的保持一致】

Logo旁边的GF动画 - 按下Ctrl+F,搜索gfDance,修改它对应的PNG图像名以及xml的动画帧名,同样的,你也可以直接替换掉原文件。

Logo弹出前的文字 - 按下Ctrl+F,搜索switch (curBeat),这里的一系列代码是让你能够按一定的节奏/次序令文字显示在游戏画面上。case后的数不能大于16,不然最后的拍子会乱掉。在这里你可以随意更改文字的内容,增加新的文字,删掉原本的文字,加上图片等等。


1.7 添加自定义台词:

来到assets/week6/images目录下,把里面的weeb文件夹复制并粘贴到assets\shared\images目录下,这样可以减少一些不必要的错误。

打开DialogueBox.hx文件,按下Ctrl+F,搜索switch (PlayState.SONG.song.toLowerCase()),其中一个switch case是用来显示对话框的。将senpai的case语句复制下来(senpai的是最简单的),然后在下面粘贴。把case后的名称改为你歌曲的名称。

示例:

你可以改变对话框图片文件所在的位置,或者直接用同名的新文件把旧的覆盖掉(如果你采用后者,会导致week6的对话框也变成新的样式)。

如果你想改变对话时的头像,又不想影响到week6,那就把week6的头像相关的代码全部置于以下代码内:

代码块
JavaScript
自动换行
复制代码
if (PlayState.SONG.song.toLowerCase()=='senpai' || PlayState.SONG.song.toLowerCase()=='roses' || PlayState.SONG.song.toLowerCase()=='thorns')
复制成功

示例:

然后把图内这一大串代码全部复制并粘贴在下面,把歌曲名改为你所需要显示对话的新歌曲名。如果需要修改位于左边的人物头像,你可以在这里编辑:Paths.getSparrowAtlas('weeb/senpaiPortrait&#​39;); 至于它下面的“Senpai Portrait Enter”,你可以把它改成xml里对应的动画名称,或者你也可以反过来,把xml文件里的动画名称修改成代码里已有的内容【依然不太推荐这一种,看代码的时候会比较别扭】

示例:

如果头像显示的位置不对,你可以调整FlxSprite(-20, 40); 里的值。第一个数字代表x坐标,第二个代表y坐标。右边头像调整方式和左边的头像一样。

接下来,打开PlayState.hx文件,来到第150行,那里有一个switch语句用来决定某首歌需要加载哪个对话文件。从week6已有的语句中复制一条并粘贴在下面,然后把歌曲名以及文本读取的路径改成你所需要的。

示例:

接着来到727行,那里有一个switch语句用来决定某首歌是否需要显示对话。把senpai或者thorns的case语句复制一条并粘贴在下面,把歌曲名改为你所需要显示对话的歌曲名。

示例:


1.8 添加自定义过场:

打开PlayState.hx文件,增加一个新的function(详情请参阅底下的代码速查表),在括号里写上?dialogueBox:DialogueBox 。这代表着这个function可以通过变量(doof)来读取到dialogue box的内容。

在{}内创建新的FlxSprite,如果你想添加动画的话请查阅底下的代码速查表。作为例子,我在这里就只添加一个简单的小动画。在创建完后,你还需要添加inCutscene =true; 这样可以在过场结束前屏蔽玩家的按键。

如果你想让HUD图像【你可以搜索.cameras = [camHUD]; 来查看哪些图像属于HUD图像】在过场进行时隐藏的话,就设置camHUD.visible = false; 如果你想要调整过场时镜头的位置,就调整camFollow的x与y的值(x越大镜头越往右,y越大镜头越往下,反之亦然)

(在这里我是播放了动画,但你可以选择在任何你想播放的地方播放,记住上面这些只是我举的例子,你可以使用FlxTimer函数来设定在一段时间后播放动画或是任何你想进行的动作,决定权在你。)

如果你用camFollow改变了镜头的位置,然后你想让镜头瞬间移到那个位置,可以使用FlxG.camera.focusOn(camFollow.getPosition());(你需要在改变camFollow位置后再添加这行代码)。同样,如果要给镜头变焦,你可以这么输入代码:FlxG.camera.zoom = 1.2;  其中1.2为焦距,可自行调整。

接着使用FlxTimer(其实你可以使用任何有onComplete属性的函数)来删除动画图像,如果HUD图像被隐藏了,则使其重新可见,如果镜头被用于场景的缩放,则重置摄像机的焦距。

如果过场结束后不需要发生对话,那么就添加startCountdown函数(用于开启歌曲游玩)。如果你希望在过场结束后进行对话,那么不要添加startCountdown(); 而要使用add(dialogueBox);

如果你不想镜头焦距瞬间变动【指有一个镜头缩放的过程】,那就使用FlxTweens(见代码速查表)。它可以使镜头缓慢缩放到指定的大小,令镜头缩放更为丝滑。

(在这个例子中,镜头缩放的结果与直接用FlxG.camera.zoom = 1.2; 是一样的,但过程会更为流畅,从缩放开始到结束总共用时1.5秒。如果你希望镜头在缩放后恢复到该舞台的默认焦距值,那就把zoom: 1.2改为zoom: defaultCamZoom

一个过场事件的完整示例:

一个比较简单的过场动画就完成了。再次申明这只是一个例子,你完全可以自由发挥,把过场事件改成你所希望的样子。

下面我们来试试弄一个不一样的过场。这一次我打算现在开头加一个会渐隐的黑幕,然后再播放动画。因此我们需要先新建一个FlxSprite,然后用.makeGraphic来创建我们的黑幕图片。

然后用FlxTween设置alpha: 0来使黑幕的透明度渐渐变为100%。你可以自由设置黑幕变透明所需的时间,然后添加一个onComplete function,里面的代码只有当黑幕的透明度变为100%后才会开始执行。

在这个例子中,它把黑幕的alpha值调为了0(即100%的透明度),这个过程从开始到结束需要2.5秒,当它完成时,onComplete函数内的代码会开始运行。我还在tween的上方用代码改变了镜头位置并添加了camera.focusOn行(即时改变镜头位置),因为我希望镜头在tween完成之前就已就位。

一个带注释的过场事件的完整示例:

最后,为了使代码能够运行你所创建的新函数-即过场事件,按下Ctrl+F,搜索schoolIntro(doof); 在最后一个schoolIntro(doof)下面为你的歌曲添加一个新的case,在里面添加你创建的新函数的名字及(doof)。

示例:


1.9 歌曲中途事件:

首先,你需要确定你在歌曲的哪一个时刻触发这个事件。要确认这一点,在调试命令中加入-debug并在游戏打开时按下F2。当你进入到你想要设置中途事件的歌曲时,在屏幕右边会出现beatShit和stepShit。

在代码里,beatShit相当于curBeat,stepShit相当于curStep。如果你想让事件触发的时间点更为精准,可以使用curStep,在这里我使用curBeat作为示例。

接下来播放你的歌曲,直到你想要事件触发的部分,记录此刻的curStep/curBeat,它们需要与你想要事件触发的时间相匹配,然后按照下面的教程进行操作。

打开PlayState.hx文件,按下Ctrl+F,搜索super.beatHit(); 并编写以下的代码。如果你希望在歌曲中只发生一个特定的事件,用你记录的curBeat替换数字。

代码块
JavaScript
自动换行
复制代码
if (curBeat == 数字 && curSong == '歌曲名')
{
 	//事件代码
}
复制成功

示例:

如果你希望在同一首歌曲中触发多个事件,用你记录的第一个curBeat替换“数字1”,用你记录的第二个curBeat替换“数字2”,如果有需要,你可以继续添加新的case。

代码块
JavaScript
自动换行
复制代码
if (curSong == '歌曲名')
{
 	switch (curBeat)
	{
		case 数字1:
			// 事件代码
		case 数字2:
			// 事件代码
    }
}
复制成功

在事件代码中,你可以基于特定的curBeat/curStep播放动画、更改人物图像等,都由你来决定。但记住一点,如果你想播放动画,你可能需要强制它们播放(方法见代码速查表)。

如果你想让敌人改变贴图,你需要先创建两个人物,当curBeat/curStep到触发事件的时间点时,它会改变敌人的贴图。例如,你想让敌人一开始是pico,到某个点时变成mom。只需将下面的代码添加到事件代码中,并将角色名替换为mom。改变BF的贴图也是类似的做法,只需将新人物设为新的Boyfriend。

代码块
JavaScript
自动换行
复制代码
remove(dad);
dad = new Character(100, 100, '角色名');
add(dad);
复制成功

同样,你也可以用这个方法来改变GF的贴图、切换到不同的FlxSprite(如舞台背景)等等。但要确保你在if/switch和类似create()这样的函数之外已经声明了变量。其余都由你自由发挥!

(在上面的例子中:当歌曲是Blammed,curBeat是25时,dad(对手位)的角色就会变成dad,而当curBeat是50时,玩家(BF)就会变成bf-christmas)。

有一个注意点,就是你要确保人物的贴图文件可以被程序读取到。这意味着你所要切换的人物的贴图文件必须在shared或是歌曲所在周的文件夹中。如果贴图文件不在以上的位置,就会导致游戏崩溃!


1.10 增加/移除难度:

打开CoolUtil.hx文件,然后在Array后增加或移除难度。别忘了处理逗号的问题,只有最后一个难度后面是不需要加逗号的。

然后打开FreeplayState.hx文件,按下Ctrl+F,搜索if (curDifficulty。理论上你应该会看到两个2,根据你增加或移除的难度数量把2修改成对应的数字即可。

在下面,你应该能看到一个switch,根据你增加或移除难度的具体情况调整底下case的内容。

接着打开PlayState.hx文件,按下Ctrl+F,搜索if (storyDifficulty == 0)。根据你增加或移除难度的具体情况调整这部分(这里是用来让程序读取歌曲对应难度的json谱面文件)。

(可选/Discord相关)按下Ctrl+F,搜索switch (storyDifficulty),然后根据你调整的难度情况增加或减少对应的case(仿照上面的做法)。

下一步,打开StoryMenuState.hx文件,按下Ctrl+F,搜索var diffic = "&#​34;; 在底下有一个switch,同样仿照上面的做法来增加或移除难度(这里也是用于读取json文件)。

最后,按下Ctrl+F,搜索curDifficulty += change; 在底下会有两个if和一个switch。if的部分同上面那样修改,switch的部分是用来显示难度对应的文字动画,所以你事先需要先修改campaing_menu_assets.png以及对应的xml文件。

如果你还没有添加新的难度文字动画,那就按下Ctrl+F,搜索sprDifficulty.animation.addByPrefix('hard&#​39;, 'HARD&#​39;); 然后在它的下面仿照它的格式为新的文字动画添加代码。

添加完新的文字动画后,再次按下Ctrl+F,搜索curDifficulty += change; 在下面的switch那里根据你修改难度的情况编辑各个难度所对应的动画名,务必仔细检查不要对应出错!同时你也可以在这里调整文字动画的坐标。

最后的最后,别忘了在data文件夹里为你的新难度添加json文件,否则在你进入游戏后选择新难度时会导致游戏崩溃!


1.11 导入新week文件夹:

想要为你的week内容单独建一个可供读取的文件夹,你需要先在assets目录下新建一个文件夹,取一个你喜欢的名字,然后进入到新建的文件夹里,再创建两个子文件夹,一个叫“images“,用来放图片文件,另一个叫”music“,用来放音乐和音效文件。

然后打开LoadingState.hx文件,在大约67行左右的地方,在checkLibrary("week + PlayState.storyWeek); 这行代码之上添加如下的代码:

代码块
JavaScript
自动换行
复制代码
if (PlayState.storyWeek == 7)
	checkLibrary("新week的文件夹名");
else
复制成功

示例:

数字7需要和week的数目相符,在当前0.2.7.1版本中新建周是week7,如果游戏本体更新了week7,新建的week就需要把7变成8。

接着,来到function getNextState这里,在checkLibrary("week + PlayState.storyWeek); 这行代码之上添加如下的代码:

代码块
JavaScript
自动换行
复制代码
if (PlayState.storyWeek == 7)
	Paths.setCurrentLevel("name of the week folder");
else
复制成功

示例:

数字7需要和week的数目相符,在当前0.2.7.1版本中新建周是week7,如果游戏本体更新了week7,新建的week就需要把7变成8。

然后回到Funkin-Master文件夹,打开Project.xml文件,在第59行和第71行找到week6的代码,在后面仿照它添加新week文件夹的读取代码。

示例:

添加完后,在第93行后增加两行新的代码,内容与格式同样仿照week6的,只是把名称改为新week文件夹的名称。

示例:


1.12 常见问题:

当发生错误时,记得首先查看命令提示符,诸如缺少括号、逗号这类的错误会很清晰地显示在上面。

游戏版本过期提示 – 如果你想去除掉游戏版本过期提示信息,打开TitleState.hx文件,按下Ctrl+F,搜索new OutdatedSubState() 然后把它更改成new MainMenuState()

示例:

人物浮在半空/沉到地底 – 打开PlayState.hx文件,按下Ctrl+F,搜索var camPos ,在那附近你会找到敌人镜头位置以及所有人物位置相关的代码。

如果你的新人物是敌人身份,那就仿照其他敌方人物的代码格式,为你的新角色新建一个case,通过增减x与y的值来调整新人物在游戏中的实际位置。

如果你的新人物是BF位的或者你想改变BF的位置,按下Ctrl+F,搜索boyfriend.x或boyfriend.y,然后依据舞台来改变BF的位置。如果你想改变GF的位置也是同样的道理。

减少x的值会使人物往左移动,增加x的值会使人物往右移动。

减少y的值会使人物往上移动,增加y的值会使人物往下移动。

Freeplay页面无法进入 – 用这个文件(https://gist.githubusercontent.com/jbmagination/caf9eb6a7ae8b415e8acd02962f851e1/raw/d76486854a7676a0ce16907dfa82bf804b155388/NGio.hx)替换掉原本的NGio.hx文件。

或者你也可以

打开FreeplayState.hx文件,把NGio.logEvent('Fresh&#​39;); 这一行删掉,记得用Ctrl+F来检索。

Story Mode里缺少最后一首歌 – 打开StoryMenuState.hx文件,按下Ctrl+F,搜索txtTracklist.text.toUpperCase(); 在它上面增加一行txtTracklist.text += "\n&#​34;; 或者也可以在命令提示符里运行haxelib install openfl 9.0.2。

显示Type not found : APIStuff – 在source文件夹内新建一个文本文档,里面输入

代码块
JavaScript
自动换行
复制代码
package;

class APIStuff
{
	public static var API:String = "";
	public static var EncKey:String = "";
}
复制成功

保存后退出,然后把文件的后缀名txt改为hx即可

显示Error: Could not find haxelib "polymod/discord rpc/extension-webm/等等" – 这里【https://cloud.189.cn/web/share?code=Ave6zu6FJRVj(访问码:lcf3)】下载编译所需的所有库,下载后右键选择解压到当前文件夹,然后把解压出来的lib文件夹复制到你的Haxe安装目录下的haxe文件夹内(默认安装路径为对应盘符/HaxeToolkit/haxe)


1.13 报错定位:

这个工具可以帮助你定位代码中出错的具体位置!顺带也方便捣鼓代码的人们互相帮助,所以我十分推荐使用这个工具! Haxe的调试菜单有的时候也挺有用的,但更多时候并不能提供太多的有效信息。

如果你还没有Visual Code(https://code.visualstudio.com/),先把它安装了,然后再安装HXCPP Debugger扩展程序(https://marketplace.visualstudio.com/items?itemName=vshaxe.hxcpp-debugger)

扩展安装完毕后,确保你在Visual Code上打开了含GitHub文件的文件夹(包含readme文件)(你可以在菜单里选择文件-打开文件夹或者直接按Ctrl+K+O在Visual Code中打开一个文件夹),在Visual Code中按F1,搜索HXCPP Debugger: Setup,然后点选它。

示例:

接着打开GitHub文件里的Project.xml文件,在polymod和discord_rpc库后边添加一行代码。

示例:

最后,打开.vscode文件夹,打开launch.json文件(如果你没有.vscode文件夹,那就在Visual Code里按下Ctrl+Shift+D,然后再按下“运行与调试”按钮。)在倒数第二个}后增加一个逗号,然后把下面这一段代码粘贴进去,记得粘贴完后按下Ctrl+S保存。

代码块
JavaScript
自动换行
复制代码
{
	"name": "HXCPP",
	"type": "hxcpp",
	"request": "launch",
	"program": "${workspaceFolder}/export/debug/windows/bin/Funkin.exe"
}
复制成功

示例:

然后点选左边的运行与调试图标,或者按下Ctrl+Shift+D,在新弹出的界面的上方,在方框里选择HXCPP,然后点击左边的绿色三角。

示例:

你需要将游戏至少编译一次。它将在调试模式下打开exe程序,然后复制你所做的导致错误的行为。当错误发生时,它会把游戏停止,显示错误在代码中发生的位置,能定位到代码发生逻辑错误的地方,就更容易找出问题所在了。此外,你还可以使用断点来停止代码,并检查那里发生了什么,为什么有些部分不起作用,这也是超级有用的。

如果你需要向别人寻求代码上的帮助,记得用这个调试器定位到问题发生的具体位置后,截个图发给对方,这能很大程度上节省双方的时间!


1.14 代码速查表:

HaxeFlixel代码速查表:

https://haxeflixel.com/documentation/cheat-sheet/

声明变量:

要声明一个变量,只需写下var 变量名,要注意变量名中间不能有空格。变量就像容器一样,用来存储数字、文本和其他重要的东西。

在Haxe中,你需要用:Type来说明它是哪种类型的变量。

基本类型有:

String - 存储文本,如 "Hello&#​34;。字符串的值需被引号括起来。

Int - 存储整数,不带小数点的数,如123或-123。

Float - 存储浮点数,带有小数点的数,如19.99或-19.99。

Bool - 存储两种状态的值:真(true)或假(false)。

这些只是基本类型,你可以在HaxeFlixel这个游戏引擎中使用多种不同的类型。你可以在这里(https://api.haxeflixel.com/flixel)找到一些你可以使用的类型,譬如sprite(精灵图)。在声明变量的类型时,只需复制类的名称。

如果bg是精灵图

但如果你立刻就想存储你想要的东西,你并不需要重复声明它是哪种类型的变量。

提醒一下,如果这个变量只是给某个特定的歌曲/星期使用的,就不要在相应舞台的if/switch case之外存储它。简而言之,如果你想在代码的多个部分使用这个变量,那就需要在if/switch case之外声明它的类型,并在if/switch case内存储它的值。因为如果你不这样做,它会把播放其他歌曲时不会用到的值一并储存起来,导致浪费资源/时间。

要改变加载在变量中的精灵图,变量本身需要在函数之外声明,以便它们可以被多个函数使用。最常见的是用于舞台的精灵图,你应该在create()函数之外声明变量,同时声明类型,我们并不希望它们被对应的switch case之外的歌曲所使用。

If/Switch case:

If和Switch被用作逻辑条件,只有在满足特定条件的情况下才会运行底下的代码。

以下是条件的列表。

小于:a < b

小于或等于:a <= b

大于:a > b

大于或等于:a >= b

等于 a == b

不等于:a != b

和:&&

或:||

代码块
JavaScript
自动换行
复制代码
if (条件1) 
{
	// 条件1成立时会运行的代码
} 
else if (条件2) 
{
	// 如果条件1不成立且条件2成立时会运行的代码
} 
else 
{
	//如果条件1和条件2皆不成立时会运行的代码
}
复制成功

switch语句用于选择要执行的代码块。它使用一个表达式,并直接进入与该表达式相匹配的代码块。例如,假设表达式是歌曲名称,在case x中,x是歌曲1,在case y中,y是歌曲2。如果你游玩的是歌曲1,只有case歌曲1里面的代码块会运行,如果你玩的是歌曲2也是同样的道理。default代表当所有的case与switch表达式都不匹配时会执行的代码块。

代码块
JavaScript
自动换行
复制代码
switch(表达式) 
{
	case x:
		// 当表达式==x时将会运行
		// 代码块
	case y:
		// 当表达式==y时将会运行
		// 代码块
	default:
		// 所有case与表达式皆不匹配时将会运行
		// 代码块
}
复制成功

switch表达式在部分性能优化上相比使用多个if要好一些,因为它会立即跳转到符合条件的代码块,而不是一个个检查if后才能运行正确的代码块。但相对应的,你无法在switch这里使用if的判断条件,具体写代码的时候你要斟酌一下到底采用哪种方法较为适合。

Function:

Function(函数)可以帮助你组织规划你的代码,避免二次编写相同功能的代码。你可以定义一个函数,然后多次调用该函数。

你可以创建一个函数,把对应功能的代码块放在里面,并在你需要的时候调用它。

代码块
JavaScript
自动换行
复制代码
function 函数名():Void
{
	// 代码块
}
复制成功

想调用函数时只需像这样运行代码:函数名();

要确保你是在其他函数{}之外定义的它,否则你就不能随处调用它。

FlxSprite

new FlxSprite(x, y) 在特定位置创建一个新的精灵图。

仅限Png:

.loadGraphic(Paths.image('文件夹名/png名&#​39;)) 往精灵图里载入/储存一张图片。要注意图片的格式只能是png。如果图片未能成功载入,默认会显示一张16x16的HaxeFlixel logo图。文件夹名不是必需的,如果你不想输入尽管把文件夹名/的部分删掉就好。

.makeGraphic(FlxG.width * 2, FlxG.height * 2, FlxColor.BLACK);创建一张图片。FlxG.width * 2是图片的宽度,FlxG.height * 2是图片的高度,FlxColor.BLACK是图片的颜色。

仅限动画:

.frames = Paths.getSparrowAtlas('文件夹名/精灵图表名&#​39;); 往精灵图里载入/储存一张精灵图表。要注意用这种方式储存的只能是动画。文件夹名不是必需的,如果你不想输入尽管把文件夹名/的部分删掉就好。精灵图标名需要和相应的xml文件匹配。

.animation.addByPrefix('idle&#​39;, 'xml中的动画名称&#​39;, 24, false); 按前缀添加/储存一个动画。这代表它是从xml中读取了特定的动画。“idle”是这个动画的新名字,用于播放它或是执行一些别的操作。“xml中的动画名称”是需要从xml中添加进程序的动画的名称。24是帧率,false是代表无需循环播放【同理true代表需要循环播放】。只要xml里有足够的动画,你想要添加多少到程序中都可以。

非人物:

.animation.play('idle&#​39;); 用于播放被添加的动画。如果你给它起了别的名字,只需把'idle&#​39;修改成你所起的新名字。除此以外你需要考虑就是要在代码中的哪个地方播放这个动画。

人物:

如果该动画是游戏人物的动画,就不能使用.animation.play('idle&#​39;); 取而代之你需要使用.playAnim('idle&#​39;);

就像上面截图中显示的,如果你想强制从头播放一个动画,就用.animation.play('idle&#​39;, true);

如果是人物动画,就用.playAnim('idle&#​39;, true);

FlxSprite的剩余部分:

.antialiasing 控制对象是否要进行抗锯齿处理,抗锯齿处理后图形的边缘会变得平滑,但对计算机性能有一定要求。

.scrollfactor.set(x, y) 控制该对象受镜头移动的影响程度。0 = 不移动(例如背景层),1 = 与前景的移动速度相同。

.active 控制update()是否被自动调用。

.setGraphicSize(Std.int(变量名.width * 0.8)) 按比例调整图片的尺寸,使你能够保持当前的长宽比。这里的0.8代表把图片调整为原先的0.8倍大,你可以把0.8改为你所需要的任意倍数,之后最好再调用一下updateHitbox();

.screenCenter(); 将精灵图放置在屏幕中心的位置。

add(FlxSprite); 将精灵图添加到图层的最上方,所以如果你想改变图层的顺序,只需按顺序添加,后添加的图层会叠加在前一个图层的上面。

remove(FlxSprite); 移除之前添加的精灵图。

FlxTimer

FlxTimer是用来启动计时器的。它可以在计时器计时结束后运行代码,这样你就可以更灵活地对代码进行控制。

.start(5, function(tmr:FlxTimer){}); 启动计时器。5是计时器所需计时的秒数(在这个例子中是5秒)。function(tmr:FlxTimer){}); 是计时器计时完成后执行的,只要像上面的例子里那样把代码块放在{}里面。

FlxTween

用来调整FlxObject,例如FlxSprite。你可以查看这个demo(https://haxeflixel.com/demos/FlxTween/),在里面挑选你需要的tween和ease选项。

例如,这段代码会把BF的精灵图调整为x=500,y=500,旋转40度,不透明度/透明度(alpha)为50%(0.5),精灵图的宽度为500。1是Tween从开始到结束所需的秒数,在这个例子中需要1秒。

然后,它将使用你所选择的ease选项(你可以在上面的demo里挑选你想要的效果)。当Tween完成时,它将运行{}内的代码块,在这个例子中,当Tween完成时,它将把BF的宽度改为250。

FlxTrail

FlxTrail是用来制作轨迹的。你可以在上面的FlxTween的demo中看到具体的效果。

dad处填写的是需要创建轨迹的对象,所以如果你想在BF或另一个FlxSprite上创建轨迹,只要把dad改为对应的名称。null处填写的是用于制作轨迹的图像,可改可不改,如果是null,则默认使用该精灵图的图像。4代表要创建的精灵轨迹图的数量。24代表轨迹更新的频率(0代表每帧都要更新)。0.3代表第一个精灵轨迹图的alpha值。0.069是指下一个精灵轨迹图的alpha 值要降低多少。