让你的游戏支持MOD

1 篇文章 0 订阅
1 篇文章 0 订阅

让你的游戏支持MOD!

前言

对于一个游戏的开发者来说,让你的游戏支持mod是一件很酷的事情!但是,有时候我们会难以想象一个游戏到底要如何支持mod。通过自己的一番搜索后,发现网络上现有的游戏mod制作教程要么很零散,要么看不懂,根本无从下手。

本文章针对上诉这些,不仅从一个通俗、简单、易懂的角度来解决问题,而且还擅长举例子说明情况。
(注:本文使用C#与Unity来举例说明)

—作者CSDN小鸦子,转载须注明作者及出处
献给游戏开发者小白

  • 本文章结构:
    ①mod支持低级版本—Json
    ②mod支持中级版本—C# Dll动态库
    ③mod支持高级版本—“简政放权”法

①mod支持低级版本—Json

Q1:什么是Json文件?

在制作游戏中,Json文件是帮助我们存储和读取游戏数据的一种文件格式。比如我们的游戏存档就可以是以一种Json文件的格式储存的。

那么既然是一个文件,那么它一定有属于自己的格式。

Json文件的格式如下:

{
  "Name": "小明",
  "level": 15,
  "armor_id": [1,2,15,261,73],
  "web": [
  { "name":"菜鸟教程" , "url":"www.runoob.com" },
  { "name":"google" , "url":"www.google.com" },
  { "name":"微博" , "url":"www.weibo.com" }
  ]
}

每个Json文件都以" { " (第一行) 开始,以" } " (第十行) 结尾,里面的内容以键值对的方式存储。
所以,每一个Json文件可以看成是一个字典(用键(Key)查找到唯一的值(Value),这样每个Key-Value称为键值对。例如Y = X^2这个函数,每个X且只对应一个Y,每个Key且只对应一个Value,因此Json文件里的Key不允许重复)。
第二行的 "Name"是一个Key,"小明"是一个Value,Key和Value之间要用一个:链接,如果不是最后一个键值对,请每个键值对之间加一个英文的逗号隔开。


Q2 :有了Json文件,游戏如何制作Mod?

假设我们做的游戏是一个刷装备游戏,那么我们需要很多装备的数据,我们有两条路可以走:

  • 全写在游戏代码中,游戏代码就储存着这些数据
  • 全写在Json文件中,游戏代码仅做读取这些Json文件

如果是我,我会选择后者。前者不仅难以维护,而且代码编写起来重复性太高,容易出错或失去耐心。

那么我们将所有武器数据都写在了Json文件当中。它就变成了这样:

{
  "1": ["勇者的剑",10,2,0],
  "2": ["勇者的弓",20,0,1],
  "3": ["骨制斧头",15,1,1]
}

如果你武器Json文件储存在游戏根目录下的Data文件夹内,那么你就可以调用Unity内的函数读取该Json文件。详细参考

那么既然你能够创建这么一个武器Json并读取,那么其他游戏爱好者也可以创建和你类似的Json文件,并放在指定位置(如Mod文件夹内的Weapon文件夹内),然后通过你在Unity内编写代码读取这些数据,就可以达到支持Mod的效果。

  • 遍历Mod文件夹下Weapon中所有文件的路径
  • 然后通过Json读取函数逐一访问这些路径下的Json文件并读取Json数据
  • 为了防止Json数据错误导致程序终止,必须得在游戏开始的时候加以验证Json数据的合法性,并对于不合法的数据应当抛出异常

②mod支持中级版本—C# Dll动态库

Q1:什么是DLL文件?
DLL是一个动态库文件,可以简单理解为代码的动态仓库。如果有C语言基础的应该知道,C语言编译的四大步骤是:预处理、编译、汇编和连接。

当程序通过这四大步骤编译下来成.exe文件后,该.exe文件的功能或者说是函数就已经静态确定了,就比如你定义了一个 int Add(int, int) 函数,在程序编译完成后,你再也无法修改这个Add函数的内容了,即Add函数已经静态确定。除非你将源代码内的Add函数进行修改,然后重新编译,才能使得这个Add函数发生变化,但新生成出来的.exe文件显然就不是之前那个.exe文件了。这就有点像房子盖好了就不能改大小了,如果要改大小那么请将房子拆了再建。

如果我们不想把程序重新编译,又想修改Add函数内容,那该怎么办呢?

  • 方法就是DLL(动态库)的动态链接

我们只需要将Add写进动态库,然后在程序里面调用这个动态库的Add函数,那么当我们修改Add函数的内容时,我们只需要在动态库中修改Add函数即可,不需要把程序本身重新编译一遍。这就好像有一个房子叫Get_Money(收租,这是一个函数名字),前一段时间入住的是People A,而这一段时间入住的是People B,房主只需找到他的房子Get_Money,然后对里面的人进行收租就可以了。如果是采用非DLL编译的方式(也就是静态链接),那么当People A不住了、People B入住的时候,就需要将Get_Money房子拆掉,然后重新建一个Get_Money房子,这显然是很蠢的。


Q2:有DLL文件后,我们应该如何让游戏有更广的mod支持?
我们先来看Json的mod法,这其实局限性很大。当我们的游戏想实现魔法攻击的Mod的时候,常常就会实现不了。因为第一,游戏开发者没有开发魔法攻击,这使得我们只能用普通攻击模拟魔法攻击,但是一维的东西如何去模拟二维甚至是高纬度的东西呢?第二,游戏开发者只规定了金木水火土 这五种魔法攻击,其他的魔法攻击他并没有规定。那么作为游戏爱好者的你就很艹蛋

  • 游戏爱好者:“游戏开发者你好,我想实现一个暗魔法攻击啊?怎么编写Json数据???”
  • 游戏开发者:“额…给我点时间,让我将暗魔法加入游戏…”

这就是Json文件制作mod的劣势,只能在游戏开发者规定范围内开发游戏mod,而游戏开发者想到的东西是有局限性的,无法完美的适配游戏爱好者开发mod的各种条件。

因此,支持DLL开发游戏mod是很有必要的,这起码让你的游戏提高很大的一个档次。

DLL如何解决上述问题呢?非常简单!
(为了让各位能通俗易懂,我决定通过伪代码来进行讲解)

	/*这是玩家类*/
    class Player: MonoBehaviour
    {
        public String Name;  //角色名字
        public List<int> Attributions;  //角色的属性值,包括当前血量、最大血量、各种攻击、各种抗性等等
    };
    /*这是敌人类*/
    class Enemy: MonoBehaviour
    {
		public String Name;  //敌人名字
		public int ID;  //敌人ID信息
		public List<int> Attributions;  //敌人的属性值,包括当前血量、最大血量、各种攻击、各种抗性等等
	};
	/*为了演示,就不继承类了*/

游戏开发者要做的:将玩家对敌人的攻击函数,从静态链接改为动态链接(从静态调用改为动态调用)

using UnityEngine;
using System.Collections;
using Attack;  //引用Attack.dll
class cAttack: MonoBehaviour{
	
	Player player = gameObject.GetComponent("Player");
	Enemy enemy = gameObject.GetComponent("Now_Enemy");
	void attack(Player player, Enemy enemy){
		int hurt_num = player.Attributions[1] - enemy.Attributions[2];
		if(hurt_num > 0){
			enemy.blood -= hurt_num;
		}
		else{
			enemy.blood -= 1;
		}
	}
	private void Update(){
		if(){
			//attack(player,enemy);
			Attack.attack(player, enemy);  //执行Attack.dll内的Create函数
		}
	}
};

游戏Mod开发者需要做的:(例如要实现暗魔法攻击)编写玩家对敌人的攻击函数,然后根据自己写的Json文件数据来判断暗魔法攻击生效的值,然后返回。

	public static void Attack(Player player,Enemy enemy){
		//15为暗魔法攻击力,16为暗魔法防御力
		int hurt_num = player.Attributions[15] - enemy.Attributions[16];
		if(hurt_num > 0){
			enemy.blood -= hurt_num;
		}
		else{
			enemy.blood -= 1;
		}
	}

这样,即使游戏开发者没有想到要开发其他魔法攻击,但是也不影响其他魔法攻击的实现。

  • 针对上面的案例,有人会问,如果Attributions的数组没有15那么长呢?或者15位置上正好和别人做的Mod冲突了呢?

第一问题解决方法:游戏爱好者自行维护一个Json文件,然后从这个Json文件里面读取player和enemy的各类属性值。

	//伪代码,读取Json文件并将其转成字典类型
	Dictionary<string, int> player_Attributions = Json2Dictionary(JsonLoad("mod\\player_Attributions.Json"));
	Dictionary<string, int> enemy_Attributions = Json2Dictionary(JsonLoad("mod\\enemy_Attributions.Json"));
	public static void Attack(Player player,Enemy enemy){
		//15为暗魔法攻击力,16为暗魔法防御力
		int hurt_num = player_Attributions["暗魔法攻击"] - enemy_Attributions["暗魔法防御"];
		if(hurt_num > 0){
			enemy.blood -= hurt_num;
		}
		else{
			enemy.blood -= 1;
		}
	}

第二个问题解决方法:如果15位置上正好和别人做的Mod撞上了,那么这就是Mod冲突,这通常需要在游戏方面进行判断是否产生了Mod冲突。而游戏爱好者的解决办法则是如果发现MOD冲突,那么将15换成其他数字。


③mod支持高级版本—“简政放权”法

当你的游戏本体是以Mod的形式出现的,那你的游戏将会支持更多的Mod。

“简政放权”法的基本思路是:在游戏里开发游戏。

我们在Unity编写游戏代码的时候,通常是将代码写入Unity的九大回调函数当中。如果我们将这些代码写入一个DLL中(将尽量多的功能实现写在DLL,而将基本功能写在游戏内),然后在Unity回调函数中调用这些函数,并传入参数,就可以实现“简政放权”法实现Mod思路。

例如:战场上每过x秒(x由mod制作者定)生成一个敌人,这些敌人的任何东西都可以由mod制作者自行决定。

using UnityEngine;
using System.Collections;
using Create_Enemy;  //引用Create_Enemy.dll
class Enemy_Create : MonoBehaviour{
	
	float time = 0;
	
	private void Update(){
		time += Time.deltaTime;
		//判断是否到达生成敌人的时机
		if(Create_Enemy.canCreate(time)){
			time = 0;
			Create_Enemy.Create();  //执行Create_Enemy.dll内的Create函数
		}
	}
};

因此,Mod制作家们只需要在Create_Enemy.dll中编写好相对应的Create函数后即可,而且每个人制作的Create函数可以各不相同!
C#调用动态链接库DLL


注:编写过程中难免会产生错误,若发现错误可以与题主联系
2024-04-25 小鸦子

  • 25
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值