[Unity3D]Unity3D游戏开发之Lua与游戏的不解之缘(下)

-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

喜欢我的博客请记住我的名字:秦元培,我的博客地址是blog.csdn.net/qinyuanpei

转载请注明出处,本文作者:秦元培, 本文出处:http://blog.csdn.net/qinyuanpei/article/details/40050225

-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

各位朋友,大家好,我是秦元培,欢迎大家关注我的博客,我的博客地址是blog.csdn.net/qinyuanpei。在前两篇文章中,博主和大家一起学习了Lua在游戏开发领域中应用,今天我们继续来学习Lua语言在游戏开发中的应用,今天我们将视角转换到我们熟悉的Unity平台上来,那么我们为什么要将Lua语言引入Unity平台呢?这是我们今天要思考的第一个问题。传统的单机游戏通常以游戏光盘的形式出售给游戏玩家,玩家在购买游戏后无法获得更多的游戏内容,玩家只能在一张容量有限的游戏光盘里不断地重复寻找着游戏的乐趣。毋庸置疑,这种模式不利于游戏开发方为游戏增加新的内容。可是在互联网技术逐步成熟的今天,玩家在购买一款实体游戏后,通常可以通过购买DLC来体验更加丰富的游戏内容,而游戏制作方则可以通过DLC向玩家传达游戏正传中没有表达出来的内容。我们知道DLC是通常是指游戏的资料片,它是对游戏内容的一种补充。从技术层面上来讲,如果我们采用编译型的语言来做一款游戏,那么我们根本无法实现对游戏内容的扩充,因为我们需要对整个项目进行重新编译然后打包成游戏光盘再出售给玩家。这样无疑会增加游戏制作方的制作成本,而更重要的是玩家不会为了新的游戏内容而再次购买游戏,显然这种方式是不合理的。那么,此时像Lua这样的脚本语言就可以发挥出巨大的作用,因为脚本语言通常不会占用太多资源,或许我们只需要一个游戏脚本就可以利用游戏中现有的场景和人物开辟出新的游戏剧情。所以,经过一番分析,大家可以总结出脚本语言在游戏开发中一个重要的作用就是更新。因为脚本语言通常都是纯文本文件,我们只需要改变某些参数而不必重新编译整个项目,这正是我们希望看到的。

好了,下面我们就来一起学习在Unity3D项目中如何使用Lua语言吧,Unity3D基于Mono虚拟机,所以理论上.NET的类库是可以直接在Unity3D中使用的。可是考虑到Unity3D跨平台的需要,我们选择的工具必须在各个平台获得良好的支持。在前文中提到的LuaInterface理论上是可以在Unity3D中使用的,可是由于IOS不支持反射机制,所以这个类库我们无法直接在Unity3D中使用的。在开源社区中,博主发现了云风团队的阿楠开发的UniLua,云风团队的风云是一个在国内游戏开发领域比较著名的人物,那么我们今天就来选择UniLua来作为我们的一个工具库吧,该项目是一个开源项目,参考了LuaInterface项目,不过在处理反射这个问题上使用了新的方法,所以目前可以完美地支持各个平台。相信大家有了前面两篇文章的基础,现在已经可以从容地面对Lua API了吧。好了,我们,现在来创建一个简单地Unity项目:

第一步是下载UniLua:http://github.com/xebecnan/UniLua。将UniLua引用到项目中有两种方法,一种是将该项目中的UniLua编译成dll然后在Unity项目中使用,一种是将该项目中的UniLua直接复制到Unity 项目中,我们这里使用第二种方法,因为博主比较懒,呵呵。将UniLua的命名空间添加到我们项目中,我们就可以开始动手写程序了。不过这里,博主想说的是Mono可能会导致的一个错误,估计是阿楠在写这个项目的时候使用了.NET4.0以上的版本,而在.NET4.0以上的版本是支持默认参数的构造函数的。可是由于Mono默认使用的是.NET3.5,所以在编译项目的时候就会报错,我们可以通过Project->Assembly-CSharp->Build->General将.NET的目标框架设为4.0,这样就可以解决这个问题了。好了,下面我们开始写代码啦,首先创建一个InvokeScript.cs的脚本:

using UnityEngine;
using System.Collections;
using UniLua;

public class InvokeScript : MonoBehaviour {

	//Lua脚本文件,我们将在C#调用该脚本
	public TextAsset LuaFile;
	//Lua虚拟机
	private ILuaState mLua;

	void Start()
	{
		//初始化Lua虚拟机
		mLua=LuaAPI.NewState();
		//加载Lua标准库
		mLua.L_OpenLibs();
		//引用一个静态地C#库
		mLua.L_RequireF(CSharpLib.CLASSNAME,CSharpLib.InitLib,false); 

		//执行Lua脚本
		mLua.L_DoString(LuaFile.text);
	}

	void OnGUI()
	{
		if(GUILayout.Button("调用Lua脚本",GUILayout.Height(30)))
		{
			InvokeLua();
		}
		if(GUILayout.Button("调用C#脚本",GUILayout.Height(30)))
		{
			InvokeCSharp();
		}
	}

	#region 调用C#脚本
	void InvokeCSharp()
	{
		//获取方法并传入参数
		mLua.GetGlobal("SumAndSub");
		mLua.PushInteger(12);
		mLua.PushInteger(8);
		mLua.PCall(2,4,0);
	}
	#endregion

	#region 调用Lua脚本
	void InvokeLua()
	{
		//获取Lua脚本中的arg1参数
		mLua.GetGlobal("arg1");
		//输出arg1
		Debug.Log("Lua脚本中的变量arg1="+mLua.L_ToString(-1));

		//获取Lua脚本中的arg2参数
		mLua.GetGlobal("arg2");
		//输出arg2
		Debug.Log("Lua脚本中的变量arg2="+mLua.L_ToString(-1));

		//获取Lua脚本中的Printf方法
		mLua.GetGlobal("Printf");
		//调用Lua脚本中的Printf方法
		mLua.PCall(0,0,0);

		//获取Lua脚本中的Sum方法
		mLua.GetGlobal("Sum");
		//传入参数12和25
		mLua.PushInteger(12);
		mLua.PushInteger(25);
		//调用此方法
		mLua.PCall(2,3,0);
		//获取传入的两个参数及求和结果
		int a=mLua.ToInteger(-3);
		int b=mLua.ToInteger(-2);
		int sum=mLua.ToInteger(-1);
		//输出
		Debug.Log("调用Lua脚本中的Sum方法:"+a+"+"+b+"="+sum);
	}
	#endregion

}

在这段脚本中,我们首先初始化了Lua环境,这一点和我们在C++中使用Lua是一样的,因为UniLua在设计API的时候在命名上和LuaAPI保持了高度的一致,如果你对Lua API足够熟悉的话,那么现在这一切对你而言应该会很简单的。接下来,我们通过Require的形式引入了我们编写的一个C#库,它是一个静态库,目的是封装C#方法以便于Lua脚本来调用,这一部分我们稍后会讲到。接下来,我们通过Unity的AssetText加载了一个Lua脚本文件,该脚本的文件的扩展名是.txt,因为我们只需要Lua脚本的内容。在脚本中我们定义了两个方法InvokeLua和InvokeSharp来分别调用Lua脚本和C#脚本。好了,接下来,我们重点来讲Lua调用C#脚本的这部分,因为UniLua在调用函数这块儿和LuaInterface不太一样,所以我们不能再用原来的先注册C#方法然后再像Lua脚本方法一样,不过博主觉得这里的原理是一样的,不过UniLua提供了更好的方法绑定机制,我们来看下面的脚本:

using UnityEngine;
using System.Collections;
using UniLua;

public static class CSharpLib
{
	//当前类文件名称,我们将在Lua脚本中使用这个名称
	public const string CLASSNAME="CSharpLib.cs";

	//C#库初始化
	public static int InitLib(ILuaState lua)
	{
		NameFuncPair[] define=new NameFuncPair[]
		{
			new NameFuncPair("SumAndSub",SumAndSub),
		};
		lua.L_NewLib(define);

		return 1;
	}

	//我们在C#中定义一个求和差的方法
	public static int SumAndSub(ILuaState lua)
	{
		//第一个参数
		int a=lua.L_CheckInteger(1);
		//第二个参数
		int b=lua.L_CheckInteger(2);
		//计算和
		int c=a+b;
		//计算差
		int d=a-b;

		//将参数及计算结果压入栈
		lua.PushInteger(a);
		lua.PushInteger(b);
		lua.PushInteger(c);
		lua.PushInteger(d);

		//有四个返回值, 尽管在C#中不支持返回多个值,可是在Lua中这样是支持的
		return 4;
	}
}

大家一定注意到这里有个NameFuncPair类吧,这就是在UniLua中用来将一个C#方法和Lua方法进行绑定的方法,我们首先构造这样一个NameFuncPair数组,然后将其加入到lua_L_NewLib()的参数中,这样相当于是注册了一个库,我觉得应该就是注册了一个方法集合吧。而CLASSNAME是一个表示当前类名称的常量,可以取任意字符,这里我们使用该类的文件名我们将在Lua脚本是用这个值来查找当前类。接下来,我们可以看到博主构造了一个求和差的C#方法,这个方法和Lua API中定义的方法是一致的,即我们需要指定该方法会返回的值得数目。如果我们需要返回一个值,就要把它通过push系列的方法压入栈中。这里我们返回了四个值,大家一定会问好是C#还支持返回多个值啊,其实呢,这是Lua语言提供给我们的一个福利啊,比如我们需要返回一个物体在3D世界里的坐标,通常情况下,我们需要用三个赋值语句才能获取吧,可是你用Lua的话,一行代码就可以搞定啦。好,现在我们回到InvokeScript脚本的Start方法中,大家可以注意到这里有一个L_RequireF()的方法,前面只是轻描淡写地说它引入了一个库,那么现在我们看看它具体做了什么吧,第一个参数表示这个类的名字,指向我们定义好的CLASSNAME,第二个参数是这个类的初始化方法指向InitLib()方法,第三个参数是是否要在全局空间中使用这个库,这里我们选在false。好了,这样,我们就完成了C#脚本的编写。好了,下面我们在项目中创建一个纯文本文件,我们输入如下代码:

local csharplib=require"CSharpLib.cs"
arg1="Unity3D"
arg2="Unreal"
arg3="Coco2dX"

function Printf()
  print("This is the methods invoked in Lua")
end

function Sum(a,b)
  return a,b,a+b
end

function SumAndSub(a,b)
  print(csharplib.SumAndSub(a,b))
end

第一行代码同样是一个require的方法,这是Lua脚本中引用一个库的方法,该方法可以引用Lua的标准库,同样可以引用我们定义的外部库,大家注意到这里的名字和我们之前定义的CLASSNAME是一样的,因为我们就是通过这个名字来查询这个库的,我们在Lua环境中注册了这个库,所以现在才可以引用这个库。在这段脚本中我们定义了几个字符型的变量,两个Lua方法,一个用Lua包装的C#方法。好了,现在我们将这个文本文件指定到InvokeScript的LuaFile字段,我们通过LuaFille的text获取脚本内容,然后通过DoString()方法来执行脚本中的内容,注意这里要先对C#库进行注册,然后再执行脚本中的内容,否则会出现错误。好了,最后,我们来一起看看运行效果吧:

大家可以看到C#调用的Lua脚本中我们获取了脚本中的两个变量arg1、arg2,调用了Lua中定义的两个方法,而最后一个方法,如我们所愿,它返回了四个值,这正是我们所希望的结果。这里顺便说一下啊,在Lua中的print方法和return在Call以后是可以直接在Debug中输出结果的,无需我们再去做Log。好了,今天的内容就是这样啦,希望大家喜欢啊,欢迎大家关注我的博客,在下一篇文章中,博主将带领大家继续Lua到底,请关注博主的下一篇文章《Unity3D游戏开发之Lua与游戏的不解之缘终结篇:UniLua热更新完全解读》,谢谢大家。关于UniLua调用非静态的类和方法,大家可以参考这篇文章:http://www.cnblogs.com/cqgreen/p/3483026.html

每日箴言:合适的人生位置,既不靠近钱,也不靠近权,而是靠近灵魂;真正的幸福,既不是富贵,也不是凡事都对,而是问心无愧。

-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

喜欢我的博客请记住我的名字:秦元培,我的博客地址是blog.csdn.net/qinyuanpei

转载请注明出处,本文作者:秦元培, 本文出处:http://blog.csdn.net/qinyuanpei/article/details/40050225

-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

时间: 2024-10-26 03:26:51

[Unity3D]Unity3D游戏开发之Lua与游戏的不解之缘(下)的相关文章

Unity3D游戏开发之Lua与游戏的不解之缘终结篇:UniLua热更新完全解读

----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- 喜欢我的博客请记住我的名字:秦元培,我的博客地址是blog.csdn.net/qinyuanpei. 转载请注明出处,本文作者:

[Unity3D]Unity3D游戏开发之Lua与游戏的不解之缘(中)

----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- 喜欢我的博客请记住我的名字:秦元培,我的博客地址是blog.csdn.net/qinyuanpei. 转载请注明出处,本文作者:

Cocos2d-x游戏开发之lua编辑器 subime 搭建,集成cocos2dLuaApi和自有类

Sublime Text http://baike.baidu.com/view/10701920.htm?from_id=8130415&type=syn&fromtitle=Sublime&fr=aladdin 简介 Sublime Text 是一个代码编辑器(Sublime Text 2是收费软件,但可以无限期试用),也是HTML和散文先进的文本编辑器.Sublime Text是由程序员Jon Skinner于2008年1月份所开发出来,它最初被设计为一个具有丰富扩展功能的V

Cocos2d-x游戏开发之lua工程创建

操作系统:OS X 10.85 Cocos2d-x 版本: 2.2.1 使用Cocos2d-x 可以创建lua工程,已经使用cpp创建的工程也可以继承lua进行开发,但是lua并不支持mac工程(因为一些框架的问题). 支持的工程文件如下: 所有使用创建工程create.py language 为cpp的工程,后集成lua及其工具的时候,要注意这一点. 撒 现在进入cocos2d-x 目录之下,通过cd 进入文件目录 进入之后,如果忘记了命令,可以直接运行 create_project.py 如

Cocos2d-x Lua游戏开发之Lua oo 的实现

一些面向对象的语言中提供了类的概念,作为创建对象的模版.在这些 语言里面.对象是类的实例,lua通过table也可以实现类的使用. --建立父类Animal Animal = { size,--动物大小 成员变量声明,不赋值为nil age,--动物年龄 color = "yellow",--动物颜色 sex,--动物性别,这个可以有?? new = function ( self,object ) object = object or {}--判断object是否为空,nil就会创建

Unity3D游戏开发之Lua的技能培训

下面我们开始今天的Unity3D技能培训. 我们学习Unity3D培训目标:让U3D初学者可以更快速的掌握U3D技术,自行制作修改素材,可以独立完成2D.3D小规模游戏及网页游戏开发. 好了,下面我们就来一起学习在Unity3D项目中如何使用Lua语言吧,Unity3D基于Mono虚拟机,所以理论上.NET的类库是可以直接在Unity3D中使用的.可是考虑到Unity3D跨平台的需要,我们选择的工具必须在各个平台获得良好的支持.在前文中提到的LuaInterface理论上是可以在Unity3D中

Cocos2d-x游戏开发之Lua学习笔记

下载链接 什么是Cocos2d-x 一个开源的移动2D游戏框架,MIT许可证下发布. 可以利用C++.Lua及Javascript来进行部署. 跨平台:iOS,Android,Blackberry,Tizen等. 使用Cocos开发的应用 版权声明:本文原创,转载请注明出处:http://blog.csdn.net/zhoumushui

[Unity3D]Unity3D游戏开发之从Unity3D到Eclipse

--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- 喜欢我的博客请记住我的名字:秦元培,我的博客地址是blog.csdn.net/qinyuanpei. 转载请注明出处,本

[Unity3D]Unity3D游戏开发之ACT游戏三连击效果实现综述

各位朋友,大家好,我是秦元培,欢迎大家关注我的博客,我的博客地址是blog.csdn.net/qinyuanpei.在研究了Unity3D Mecanim动画系统的重定向特性后,今天我们继续来探索Mecanim动画系统更多的特性吧.今天博主想和大家分享的是ACT游戏中的三连击效果的实现,由于Unity3D目前存在Animation和Animator两种类型的动画组件,因此本文将分别讲这两种类型的动画组件的三连击效果的实现,其中Animation组件是Unity3.5以下版本所使用的动画组件,An