• Unity3D入门之JavaScript

    2013-10-18 14:57:54
    刚刚接触Unity3D游戏引擎,这里做点学习笔记。下面是我建立的简单场景,左侧的Hierarchy(层次)视图里显示了场景中所有游戏对象,这些基本对象可以从Create下拉菜单里创建。当你点击某个对象,比如立方体Cube时,在...

    刚刚接触Unity3D游戏引擎,这里做点学习笔记。下面是我建立的简单场景,左侧的Hierarchy(层次)视图里显示了场景中所有游戏对象,这些基本对象可以从Create下拉菜单里创建。当你点击某个对象,比如立方体Cube时,在右侧Inspector(监视)中可以看到Cube对象的详细信息,比如它的位置信息、表面材质信息,然后可以在其中修改。下方的Project视图中的Assets(资源)里显示了游戏中所有资源,这里注意与Hierarchy视图里对象的区别,我们的游戏脚本放在Assets里。刚开始学习Unity3D,我会反感那些脚本,总希望不需要写代码就能创建自己的游戏,但后来发现,在Unity3D中不写脚本是不可能的,脚本完全就是一切的逻辑。

    要在Scene(场景)视图里创建物体,可以在左侧的Hierarchy视图里点击Create下拉菜单,选择创建即可,我这里创建了一个平面Plane、两个立方体Cube和MyCube、一个摄像机MainCamera、一个圆柱体Cylinder。在Scene中,按住ALT键,用鼠标就可以旋转整个场景;按住鼠标中键,可以拖动场景视图;用鼠标滚轮可以缩放视图。

    要给场景中的物体上色,比如平面Plane,只需要点击对象Plane,然后在右侧Inspector中做些设置即可。那么如何改变物体表面的颜色了,是直接修改吗?不是,有点图像学基础的都知道,要改变表面颜色,实际要改变的是物体的表面材质,材质中可以包含各种复杂信息。要创建材质,可以在Assets视图中点击右键,选择Create->Material即可,然后在Inspector中修改Main Color属性即可。最后点击Plane对象,在右侧点击Materials里Element0最右边的小圈,选择想要的材质,也可以直接把Assets里的材质拖放到Element0上即可。

    在Create里只能创建一些基本模型,下面学习用JavaScript脚本在场景中创建游戏界面元素,比如按钮、文本框、图片等。我看的书是《Unity3D游戏开发》,最开始讲的就是JavaScript,后面会讲C#作为脚本语言。下面是我自己的一个练习的截图。

    界面有点乱,也懒得改了。最上面的是几个旋转视图的按钮,左边绿色的文字,接着是一幅图片、滑动条。下方是输入框、图片按钮。比较显眼的是3个窗口,窗口里的元素坐标都是相对的。我在代码中都有详细的注释,也不需要做什么说明了。要使用脚本,先在Assets里创建javaScript,打开编辑器复制我的代码。然后点击左侧的Main Camera对象,把脚本文件拖动到右侧中即可。可能会出现编译错误,无法运行,那是因为我没有提供材质、图片。点击Main Camera对象,点击右侧Inspector里的脚本文件,展开它的属性,会看到Image Texture、Button Texture这些变量,凡是在JavaScript里的public修饰的变量就会出现在这里,要给这些变量赋值才可以正常运行。

    我这里需要赋值的是Image Texture、Button Texture、View Texture 0,这三个都是图片,从Assets里拖放三个图片赋给它们即可。下面还有一个My Skin变量,是Unity里的皮肤,比如决定按钮的颜色,可以被很多按钮使用,也是在Assets里直接创建即可。对于Unity3D里的GUI控件,简单的有Label(文本)、Button(按钮)、TextField(文本框)、ToolBar(工具栏)、Slider(滑块)、ScrollView(滚动显示区域)等。

    群组视图(Group View控件):将多个视图放在一个群组中,群组视图里的坐标都是相对的。修改群组视图坐标,里面所有元素坐标都会变化。

    GUILayout:相对与GUI控件,GUILayout控件的创建不需要设定显示区域,不指定具体坐标,可以动态适应窗口。比如绘制一个按钮,如果用GUI控件,需要指定按钮的长度,如果按钮上的文字长度超出了按钮长度,超出部分便无法显示了。如果使用GUILayout,便可以动态自适应。

    帧动画:在加载图片动画时,我使用了Resources.Load()这样的方法,注意需要在Assets里创建Resources目录,然后把动画资源放在其中。

    刚体(Rigidbody):在Unity中可以给对象添加这个属性,比如立方体,添加后的立方体可以和其它物体产生碰撞反应,变成了一个具有物理属性的物体,比如可以自由裸体运动。要添加这个属性,先选择对象,然后在菜单栏里选择Component->Physics->Rigidbody即可。

    复制代码
      1 #pragma strict
      2 
      3 var str1 : String;//外部字符串
      4 var imageTexture : Texture;//外部贴图
      5 var buttonTexture : Texture2D;//按纽图片
      6 var viewTexture0 : Texture2D;
      7 var TranslateSpeed = 20;//模型移动速度
      8 var RotateSpeed = 1000;//模型旋转速度
      9 
     10 private var username : String;//用户名
     11 private var password : String;//密码
     12 
     13 private var imageWidth : int;//图片宽度
     14 private var imageHeight : int;
     15 private var screenWidth : int;//屏幕宽度
     16 private var screenHeight : int;
     17 
     18 private var select : int;//工具栏选择按钮的ID
     19 private var barResource : String[];//工具栏按钮字符串
     20 
     21 var verticalValue : int = 0;//纵向滑动条数值
     22 var horizontalValue : float = 0.0f;//横向滑动条数值
     23 
     24 var scrollPosition : Vector2;//滚动条位置
     25 
     26 var mySkin : GUISkin;//自定义皮肤
     27 
     28 private var choose : boolean = false;//单选控件是否选中
     29 
     30 //默认窗口位置
     31 private var window0 : Rect = Rect(770,100,250,100);
     32 private var window1 : Rect = Rect(600,200,400,300);
     33 
     34 var winArrayList = new ArrayList();//用于存储窗口
     35 
     36 
     37 private var animUp : Object[];//动画数组
     38 private var animDown : Object[];
     39 private var animLeft : Object[];
     40 private var animRight : Object[];
     41 private var map : Texture2D;//地图贴图
     42 private var tex : Object[];//当前人物动画
     43 private var x : int = 400;//人物的x坐标
     44 private var y : int = 400;//人物的y坐标
     45 private var nowFrame : int;//帧序列
     46 private var mFrameCount : int;//帧总数
     47 private var fps : float = 10;//一秒多少帧
     48 private var time : float = 0;//限制帧的时间
     49 
     50 //程序开始函数,变量初始化
     51 function Start () {
     52     screenWidth = Screen.width;
     53     screenHeight = Screen.height;
     54     imageWidth = imageTexture.width;
     55     imageHeight = imageTexture.height;
     56     str1 = "点击click";
     57     username = "";
     58     password = "";
     59     select = 0;
     60     barResource = ["Toolbar1","Toolbar2","Toolbar3"];
     61     scrollPosition[0] = 50;
     62     scrollPosition[1] = 50;
     63     
     64     //添加一个窗口
     65     winArrayList.Add(Rect(winArrayList.Count*100,400,150,100));
     66     
     67     //得到帧动画中的所有图片资源
     68     animUp = Resources.LoadAll("up");
     69     animDown = Resources.LoadAll("down");
     70     animLeft = Resources.LoadAll("left");
     71     animRight = Resources.LoadAll("right");
     72     tex = animUp;
     73 }
     74 
     75 //每一帧都要执行的更新
     76 function Update () {
     77 
     78 }
     79 
     80 //绘制GUI界面组件
     81 function OnGUI()
     82 {
     83     //设置GUI背景颜色
     84     GUI.backgroundColor = Color.red;
     85     //设置一个按钮,规定一个矩形区域
     86     if (GUI.Button(Rect(10,10,70,30), "向左旋转"))
     87     {
     88         //transform为当前绑定模型的变换对象,设置模型旋转
     89         //Time.deltaTime:表示完成最后一帧的时间,单位为秒
     90         transform.Rotate(Vector3.up * Time.deltaTime * (-RotateSpeed));
     91     }
     92     if (GUI.Button(Rect(170,10,70,30), "向右旋转"))
     93     {
     94         transform.Rotate(Vector3.up * Time.deltaTime * RotateSpeed);
     95     }
     96     if (GUI.Button(Rect(90,10,70,30), "向前移动"))
     97     {
     98         transform.Translate(Vector3.forward * Time.deltaTime * TranslateSpeed);
     99     }
    100     if (GUI.Button(Rect(90,50,70,30), "向后移动"))
    101     {
    102         transform.Translate(Vector3.back * Time.deltaTime * TranslateSpeed);
    103     }
    104     if (GUI.Button(Rect(10,50,70,30), "向左移动"))
    105     {
    106         transform.Translate(Vector3.left * Time.deltaTime * TranslateSpeed);
    107     }
    108     if (GUI.Button(Rect(170,50,70,30), "向右移动"))
    109     {
    110         transform.Translate(Vector3.right * Time.deltaTime * TranslateSpeed);
    111     }
    112     
    113     //显示文字信息Label
    114     GUI.color = Color.green;
    115     GUI.Label(Rect(250,10,200,30), "模型的位置" + transform.position);//设置一个文本框
    116     GUI.Label(Rect(250,50,200,30), "模型的旋转" + transform.rotation);
    117     GUI.Label(Rect(450,10,200,30), "屏幕宽度:" + screenWidth);
    118     GUI.Label(Rect(450,50,200,30), "屏幕高度:" + screenHeight);
    119     
    120     //显示图片Label
    121     GUI.color = Color.white;
    122     GUI.Label(Rect(600,10,imageWidth,imageHeight), imageTexture);
    123     
    124     //显示图片按钮Button
    125     GUI.backgroundColor = Color.white;
    126     GUI.Button(Rect(250,90,buttonTexture.width,buttonTexture.height),buttonTexture);
    127     
    128     //显示文本框TextField
    129     GUI.backgroundColor = Color.white;
    130     username = GUI.TextField(Rect(0,90,100,30),username,15);
    131     password = GUI.PasswordField(Rect(120,90,100,30),password,"?"[0],15);
    132     
    133     //显示工具栏Toolbar
    134     select = GUI.Toolbar(Rect(0,140,barResource.Length * 100, 30),select,barResource);
    135     switch(select)
    136     {
    137         case 0:
    138             GUI.Label(Rect(10,180,200,30),"X");
    139             break;
    140         case 1:
    141             GUI.Label(Rect(10,180,200,30),"Y");
    142             break;
    143         case 2:
    144             GUI.Label(Rect(10,180,200,30),"Z");
    145             break;
    146         default:
    147             break;
    148     }
    149     
    150     //显示滑块Slider
    151     verticalValue = GUI.VerticalSlider(Rect(750,10,30,100),verticalValue,99,0);
    152     horizontalValue = GUI.HorizontalSlider(Rect(820,10,100,30),horizontalValue,0.0f,100.0f);
    153     GUI.Label(Rect(780,20,18,100), "纵向进度" + verticalValue);
    154     GUI.Label(Rect(820,30,100,20), "横向进度" + horizontalValue);
    155     
    156     //开始群组视图,将多个组件放在一个群组中,群组中组件坐标都是相对坐标;修改群组坐标,其中所有坐标都会改变
    157     GUI.BeginGroup(new Rect(10,230,200,400));
    158     GUI.DrawTexture(Rect(10,20,viewTexture0.width,viewTexture0.height),viewTexture0);
    159     GUI.Label(Rect(10,70,100,40),"群组视图1");
    160     GUI.Label(Rect(10,100,100,40),"按钮");
    161     GUI.EndGroup();
    162     
    163     //注册窗口
    164     GUI.Window(1001,window0,oneWindow,"第一个窗口");
    165     GUI.Window(1002,window1,twoWindow,"GUILayout");
    166     
    167     //自定义皮肤
    168     GUI.skin = mySkin;
    169     GUI.Button(Rect(300,230,120,30),"自定义皮肤按钮");
    170     GUI.Toggle(Rect(300,270,100,30),choose,"单项选择");
    171     //自定义皮肤风格组件Custom Styles
    172     GUI.Button(Rect(450,230,120,30), "Custom0Button", "Custom0");
    173     GUI.Button(Rect(450,270,120,30), "Custom1Button", "Custom1");
    174     
    175     //遍历每个窗口,并加入视图
    176     var count = winArrayList.Count;
    177     for (var i = 0; i < count; i++)
    178     {
    179         winArrayList[i] = GUILayout.Window(i,winArrayList[i],AddWindow,"窗口ID:"+i);
    180     }
    181     
    182     //绘制帧动画
    183     DrawAnimation(tex, Rect(x,y,32,48));
    184     GUI.BeginGroup(new Rect(400,120,200,400));
    185     //点击按钮移动人物
    186     if (GUILayout.RepeatButton("向上"))
    187     {
    188         y-=2;
    189         tex = animUp;
    190     }
    191     if (GUILayout.RepeatButton("向下"))
    192     {
    193         y+=2;
    194         tex = animDown;
    195     }
    196     if (GUILayout.RepeatButton("向左"))
    197     {
    198         x-=2;
    199         tex = animLeft;
    200     }
    201     if (GUILayout.RepeatButton("向右"))
    202     {
    203         x+=2;
    204         tex = animRight;
    205     }
    206     GUI.EndGroup();
    207 }
    208 
    209 //窗口1
    210 function oneWindow(windowID: int)
    211 {
    212     if (GUI.Button(Rect(10,50,80,30),"普通按钮"))
    213     {
    214         Debug.Log("窗口ID=" + windowID + "按钮被点击");
    215     }
    216     
    217     //GUILayout界面布局
    218     if (GUILayout.Button(str1))
    219     {
    220         str1 += str1;
    221     }
    222 }
    223 
    224 //窗口2 : GUILayout
    225 function twoWindow(windowID : int)
    226 {
    227     //线性布局
    228     GUILayout.BeginHorizontal();
    229     GUILayout.Box("开始水平布局");
    230     GUILayout.Button("按钮");
    231     GUILayout.Label("文本框");
    232     GUILayout.TextField("输入框");
    233     GUILayout.EndHorizontal();
    234     
    235     GUILayout.BeginVertical();
    236     GUILayout.Box("开始垂直布局");
    237     GUILayout.Button("按钮");
    238     GUILayout.TextArea("输入区域");
    239     GUILayout.EndVertical();
    240     
    241     //控件偏移、对齐
    242     GUILayout.BeginArea(Rect(0,150,200,60));//开始一个显示区域
    243     GUILayout.BeginHorizontal();//外层横向布局
    244     
    245     GUILayout.BeginVertical();//嵌套一个纵向布局
    246     GUILayout.Box("Test1");
    247     GUILayout.Space(10);//两个Box控件中间偏移
    248     GUILayout.Box("Test2");
    249     GUILayout.EndVertical();//结束嵌套的纵向布局
    250     
    251     GUILayout.Space(40);//两个纵向布局间偏移
    252     
    253     GUILayout.BeginVertical();//嵌套一个纵向布局
    254     GUILayout.Box("Test3");
    255     GUILayout.FlexibleSpace();//设置对齐
    256     GUILayout.Box("Test4");
    257     GUILayout.EndVertical();//结束嵌套的纵向布局
    258     
    259     GUILayout.EndHorizontal();//结束外层横向布局
    260     GUILayout.EndArea();//结束一个显示区域
    261 }
    262 
    263 //添加新窗口
    264 function AddWindow(windowID : int)
    265 {
    266     if (GUILayout.Button("添加新窗口"))
    267     {
    268         winArrayList.Add(Rect(winArrayList.Count*100,500,80,80));
    269     }
    270     if (GUILayout.Button("关闭当前窗口"))
    271     {
    272         winArrayList.RemoveAt(windowID);
    273     }
    274     GUI.DragWindow(Rect(0,0,Screen.width,Screen.height));
    275 }
    276 
    277 //绘制帧动画
    278 function DrawAnimation(tex : Object[], rect : Rect)
    279 {
    280     //绘制当前帧
    281     GUI.DrawTexture(rect, tex[nowFrame], ScaleMode.StretchToFill, true, 0);
    282     //计算限制帧时间
    283     time += Time.deltaTime;
    284     //超过限制帧则切换图片
    285     if (time >= 1.0/fps)
    286     {
    287         nowFrame++;
    288         time = 0;
    289         if (nowFrame >= tex.Length)
    290         {
    291             nowFrame = 0;
    292         }
    293     }
    294 }
    复制代码

    展开全文
  • Unity3d中的脚本可以与游戏对象链接,变量数值的修改以及实时预览脚本修改后的游戏效果,节省了很多脚本调整和调试的时间,提高了开发效率。 简单的项目和Unity中的大量例子和脚本资源包都是用JS。商业项目基本都用...

    Unity中的JS,也称UnityScript,和基于浏览器的JS有比较大的区别,因为UnityScript是基于Mono的.net 的IL语言规范,CLR运行环境(Mono虚拟机)上设计的语言。

    0.基本概念

    Unity3d中的脚本可以与游戏对象链接,变量数值的修改以及实时预览脚本修改后的游戏效果,节省了很多脚本调整和调试的时间,提高了开发效率。

    简单的项目和Unity中的大量例子和脚本资源包都是用JS。商业项目基本都用C#,因为C#和C/C++交互方便,丰富的数据结构和面向对象的架构利于大型程序的编写,很多强大的第三方插件是用C#开发的,方便工作流程。

    编译过程:

    UnityScript运行环境使用Mono  的.NET Framework。实际上,UnityScript是用Boo实现的,Boo是运行在Mono虚拟机上的一种语言,并且编译成本机代码。JavasScript很多典型的运行环境如String和Math库由Mono提供。你也就知道了为什么UnityScript中方法名要大写了,因为要与Mono中相同。

    Unity中的脚本和传统的解释型(JIT解释)语言不同,都是需要经过编译的,因此速度都一样快。

    这三种语言的代码最后都会被编译执行,而且脚本可以互相访问

    库的调用:

    Unity的脚本基于Mono的.net平台上运行,脚本都可以使用.net库,为xml,数据库,正则表达式提供了良好的解决方案。

    Unity中js想调用mono的.net库,直接import即可。

    import System;

    import System.IO;

    否则,你带指定完整的命名空间来调用函数,如System.IO.File.Open(),而不是File.Open()。

     

    1.基本类型和语句:

    1)数据类型

    数值类型:char,byte,sbyte;short, ushort, int, uint, long, ulong; float,double; decimal.

    布尔值:boolean

    字符串:String,[index]符号

    字符串[0]是字符串取下标为0的字符。

    var s: String = "Whatever_it_may_be";

    s =s.Replace("_"[0], " "[0]); // replace all the underscoreswith spaces

    2)变量声明:

    变量必须先声明[必须](编译缘故,且声明类型有利于减少太多常量,避免内存泄露发生),可以定义类型[可选]:

    var playerName:String;

    函数的参数也要声明类型:

    function Test( playerName:String, baseInfo:Object )

    {

    }

    如果声明时候定义或赋值了类型,那么不能再改变类型,除非声明时候不定义类型。

    var a= "test";

    a =5;// 报错


    var a;

    a ="test";

    a =5;//正确

    变量前面可以加public,protected, private来修饰;不写默认是public的,public的变量可以在Inspector视图中查看和编辑。

    3)数组:

    内建自定义数组(快功能简单):

    var values : int[] = {1,2,3};

    转换到Array数组(需要对数组处理),var arr = new Array(values);

    Array对象数组(慢动态增长排序合并功能):

    var arr = new Array(); arr.Push("good");

    转换到内建数组(需要比较高的性能时候),var bArray : int[] = arr.ToBuiltin(int);

    4)链表和泛型:

    UnityScript可以使用泛型,所以当用到动态大小的数组时,最好用List来替代Array。基本上就没有什么理由要用到Array了,List更快并且功能更多。如果你需要混合类型的数组,你可以用Object List。UnityScript中泛型的语法与C#中接近,除了要加一个额外的“.”符号在“<>”之前。如C#中的"varmyList = new List<int>();"在UnityScript中对应的写法为:"var myList = new List.<int>();"。

    5)运算符和表达式:

    和C一样。

    6)语句:

    每行必须写分号; 比C多了for in 用于遍历对象元素,for(var i:int = 0; i < 10; i++)。

    switch可以使用String变量。


    2.函数

    声明规则:

    function函数名(参数1:参数类型, 参数2:参数类型...):返回值类型

    {

    }

    unityScript中的函数可以视为Function类型对象,可以像变量一样进行赋值比较等操作。

     

    不能写匿名函数。

    Math需要用Mathf。


    3.类(DOM js中没有类):

    在Unity里,一个js文件就是一个类,unity引擎会为js文件自动生成一个类。

    对于UnityScript脚本,Unity编译该文件时会自动的为脚本添加一个与脚本文件名相同的类,并自动地继承于MonoBehaviour。但对于C#或Boo,则需要在脚本中显式的写出类名和继承关系。要创建不继承自MonoBehaviour的类,用C#语言,或者从外部添加js脚本资源(就可以自己直接new对象出来了)。

    //SayHello.js

    #pragma strict // 严格类型检测,尽早生成错误,禁用动态类型,强制用静态类型(强类型)

    function sayHello()

    {

    }

    等价于C#中:

    #pragma strict

    public class SayHello extends MonoBehaviour

    {

      function sayHello()

        {

        }

    }

    但是,你可以在同一个文件中声明多个类,尤其是当你需要使用一些辅助工具类时非常有用,一般这种辅助类没有继承自MonoBehaviour。

    class ButtonState {

      var currentState : int;

      var offset : Vector2;

    }

    如果你在一个文件中声明了MonoBehaviour的子类,但类名与文件名不匹配的话,即使是大小写不一致,你也会碰到麻烦。

    一定要理解,当你在js文件中编写行为脚本是,你实际上在编写一个类:

    a) 类及其对象:文件名就是类名,如果文件名是foo.js,你就可以在其他地方以var x = new foo()的格式进行调用;

    b)类的方法和预定义方法有一些特定的方法是实现系统预先定义的一些事件处理器,如Start、FixedUpdate等。任何事件中,声明的一个函数就是这个文件所代表的类的一个方法。

    c) 类的属性:文件中在函数定义之外编写的代码都在该类的范围之内执行,声明的变量也是该类的成员变量。类中的静态函数、变量本质上是类的方法与属性

    实例:

    /*whenyou drag the behavior onto a gameobject, these values will be visible andeditable

    */

    public name : String;

     

    /*otherscripts which have a reference to this object (e.g. if they're attached to thesame object) can see public functions

    */

    publicage : int;

     

    /*privatemembers are NOT visible to other scripts, even if they have a reference to thisobject

    */

    private favoriteColor : Color;

     

    /*youcan assign a value to bestFriend by dragging a gameObject with an attached copyof the foo behavior to this property. This will give you access to bestFriend'spublic methods and members

    */

    public bestFriend : foo;

     

    /*this function will be called every frame by Unity, so it's actually an eventhandler

    */

    function Update(){

     

     /*transform is a property inherited from thegameObject the behavior is attached to*/

    var t = transform;

     }

     

    function Bar(){

      // this is just a function, if you don't callit yourself, it will never do anything

    }

     

    4.继承

    Unity里需要extends关键字:

    class MyHello extends Hello

    {

    }

    DOM js中用prototype里的bind()方法。

    Unityjs里面还提供了虚拟函数。

     

    类的继承也是不同的。在JavaScript和C#中,方法是隐型并且不可重载,除非方法声明中添加虚拟关键字。不同的是C#只重载那些包含重载关键字override的方法。而JavaScript不需要关键词,只要重载类方法就可以覆盖,其它的都可继承得到。

    //Foo.js

    var foo = "hello, world";

     

    function doEet () {

      // does nothing, intended to be overridden

    }

    将会生成:

    //Foo.js

    import UnityEngine;

    classFoo extends MonoBehaviour {

      public var foo = "hello, world";

     

      public function doEet () {

        // does nothing, intended to be overridden

      }

    }

     

    子类写法:

    //PrintingFoo.js

    class PrintingFoo extends Foo {

       function doEet() {

        print( foo );

      }

    }

    创建虚函数

    classFoo

    {

         virtual function DoSomething ()

         {

             Debug.Log("from baseclass");

         }

    }

    //SubFoo.js

    class SubFoo extends Foo

    {

         virtual function DoSomething()

         {

              Debug.Log("from subclass");

         }

    }

    //Elsewhere

    varfoo : Foo = new SubFoo();

    foo.DoSomething();//printsfrom sub class

    如果你要调用父类的方法,用关键字super。示例如下:

    class SubFoo extends Foo

    {

      virtual function DoSomething()

      {

        super.DoSomething();// 不是虚函数,应该不需要super修饰就可以直接调用。

        Debug.Log("from sub class");

      }

    }

    //Elsewhere

    varfoo : Foo = new SubFoo();

    foo.DoSomething();//prints"from base class" and "from sub class"

    类间通信:Use-a方式(关联关系)比继承耦合度底得多,易于修改维护

    /*Foo.js */

    varbar : Bar;

    function Start(){

      bar = gameObject.GetComponent(Bar);

    }

    function doEet(){

      // do my own thing

      if( bar ){

        bar.doEet();

      }

    }

    /*Bar.js */

      function doEet(){

        // do something special

      }


    5.对象

    Unity中不一定可以用new 创建对象(普通类可以,特殊类不行,各种脚本都一样)。特殊类:用编辑器工程视图右键或者组件Create js 或者C#的类都是继承自MonoBehaviour类,对这种类型的类不能new出来一个对象,原因是Unity会为这种类自动创建对象,并调用被重载的方法。 

    使得用Unity非常有趣的一件事是,它的类采用了非常自由的mixin策略。通常你可以非常快速简单的查到你所需要的类。最通用的一个例子是Transform类,对于你正在处理的一个对象,所有被附加到该对象的相关联的类,都可以简单快速的获取它的属性和方法。

    比如,典型的动作就是你会访问名叫"transform"的变量,它代表与该对象关联的Transform类的实例。如果你需要相关的位置坐标,就访问transform.position(一个 Vector3对象);如果你需要它的GameObject,就访问transform.gameObject;如果你需要它的渲染器,就访问transform.renderer。等等。一般如果你一个对象的主要属性,你就可以快速获取该对象所有其他的属性。

     

    6.js和C#单向通信,不能双向通信,因为编译问题

    js访问C#脚本组件:

    //createa variable to access the C# script

    private var csScript : CSharp1;

    function Awake()

    {

        //Get the CSharp Script

        csScript =this.GetComponent("CSharp1");//Don't forget to place the 'CSharp1'file inside the 'Standard Assets' folder

    }

       

    //rendertext and other GUI elements to the screen

    function OnGUI()

    {

        //render the CSharp1 'message' variable

        GUI.Label(new Rect(10,30,500,20),csScript.message);

    }

    C#访问js脚本组件:

    using UnityEngine;

    using System.Collections;

    public class CSharp2 : MonoBehaviour

    {

        //create a variable to access the JavaScriptscript

        private JS1 jsScript;

        void Awake()

        {

            //Get the JavaScript component

            jsScript = this.GetComponent<JS1>();//Don'tforget to place the 'JS1' file inside the 'Standard Assets' folder

        }

        //render text and other GUI elements to thescreen

        void OnGUI()

        {

            //render the JS1 'message' variable

            GUI.Label(newRect(10,10,300,20),jsScript.message);

        }

    }

     

    7.使用第三方库:

    第三方.NET库如XML-RPC可以以新建资源Asset的方式引入。

     

    8.调试

    可以用print函数,Log()函数或者Debug.Log(),想设置断点,用Debug.Break()函数。

    print() 函数将会生成消息,并输出到状态栏及控制台中,但仅限MonoBehavioour类范围内。

    更好的办法是使用Debug.Log("insert messagehere");,该方法到处都可使用。还可用Debug.LogWarning 和 Debug.LogError生成警告和错误消息。

    Debug.Break(); 可以将游戏暂停在一个精确的点。当一种特定的情条件发生时,如果你想检查对象的状态的时候,这个特性非常有用。

    开发环境运行项目时,编辑界面也是完全实时更新的,你可以查看对象实例的内部状态。


    参考整理自:

    http://www.cnblogs.com/x3d/p/3838619.html

    更多的细节:阅读和编写大量unityScript代码。

    展开全文
  • Unity中脚本是必不可少的。因为他将定义你游戏的各种行为和规则。 这个教程将介绍JavaScript的基本使用。 1.目标 在Unity中,脚本是用来界定用户在游戏中的行为或规则。Unity推荐使用的编程语言是...
    在Unity中脚本是必不可少的。因为他将定义你游戏的各种行为和规则。

    这个教程将介绍JavaScript的基本使用。
    1.目标

    在Unity中,脚本是用来界定用户在游戏中的行为或规则。Unity推荐使用的编程语言是JavaScript,同时也支持C#或Boo。


    2.前提

    本教程的重点是Unity脚本基础,前提是你已经熟悉了Unity的界面。


    3.命名规范
    开始前,先说下Unity的一些规范。
    变量 - 首写为小写字母。变量用来存储游戏状态中的任何信息。
    函数 - 首写为大写字母。函数是一个代码块,在需要的时候可以被重复调用。
    类 - 首写为大写字母。可以被认为是函数的库。

    当阅读范例时注意首写字母,将有助于你更好的理解对象之间的关系。


    4.用户输入
    我们第一个例子是在场景中实现一个简单的移动。
    1)设置场景

    -启动Unity。创建一个用来移动的平面。GameObject->CreateOther->Plane。并且在Inspector面板中设置Position为"0,0,0"。如果当前页面没有Inspector面板,选择Window->Layouts->2by 3。建议熟悉各种布局以便开发需要。

    -创建一个Cube。GameObject->CreateOther->Cube。在Inspector面板中设置Position为"0,1,0"。

    -我们都知道现实世界里物体成像靠的是光反射,那么我们这里也是需要光线的。选择GameObject->CreateOther->PointLight。在Inspector面板中设置坐标为"0,5,0"。

    -保存当前场景。快捷键为Ctrl+s。

    2)新建脚本
    我们打算移动用户的视线,这需要通过控制主相机的位置来实现。
    我们就要写一个脚本,然后把脚本和相机结合起来。


    -创建一个空脚本。Assets->Create->JavaScript并命名为"Move"。重命名快捷键为F2。

    -双击打开脚本Move。默认包含Update()函数。将我们的代码加入这个函数,他将在每一帧执行一次。
    我们需要用transform来改变相机的位置,用到Translate这个函数,他有x,y,z三个参数。我们加入以下代码:
    function Update(){
        transform.Translate(Input.GetAxis("Horizontal"),0,Input.GetAxis("Vertical"));
    }


    Input.GetAxis()函数返回一个从-1到1之间的值,如横轴上左半轴为-1到0,右半轴为0到1。
    如果需要,我们可以通过Edit->ProjectSettings->Input中重定义按键映射。

    3)连接脚本
    脚本写完了,如何让他起作用呢?我们需要把脚本赋予物体才行。

    -点击希望应用脚本的物体对象。这里对我们而言就是相机。从Hierarchy面板中选中它。

    -在菜单中选择Components->Scripts->Move,这样我们便从Inspector面板中看到相机中添加了Move这个组件。(我们也可以用鼠标把脚本拖拽到物体对象上)
    点击运行,我们即可前后左右按键来控制相机移动了。


    注意一个关于DeltaTime的问题。放在Update()函数中的代码是按照帧来执行的。
    如果我们需要物体的移动按照时间秒来执行,我们需要将Input.GetAxis()函数的返回值乘以Time.deltaTime:

    var speed = 5;
    function Update(){
    var x = Input.GetAxis("Horizontal")*Time.deltaTime*speed;
    var y = Input.GetAxis("Vertical")*Time.deltaTime*speed;
    transform.Translate(x, y, 0);
    }
    这样设置之后按下WASD便可以实现上下左右的视角移动了。
    这里的speed为显式变量,可以在Inspector面板中看到。我们可以在使用中随时调整它的值,很方便。


    5.连接变量
    Unity允许在界面上拖拽(drag and drop)的方式赋脚本。快捷方便。这里,我们将涉及连接变量的概念。

    -在场景中添加一个聚光灯。GameObject->CreateOther->SpotLight。Position为"0,5,0",Rotation为"90,0,0"。


    -创建一个JavaScript脚本,命名为"SpotLight"。

    我们想让聚光灯照向主相机。我们可以使用transform.LookAt()这个函数。
    如何使用这个函数呢?我们需要创建一个显式变量。在SporLight脚本中写入如下代码:
    var target : Transform;
    	function Update(){
    	transform.LookAt(target);
    }

    -把脚本赋予聚光灯对象。要么在菜单栏Component中添加,要么鼠标拖放。之后,"target"变量就出现在Inspector面板里了。


    -将Hierarchy面板中的主相机对象拖放到Target变量上。如果我们想让聚光灯照向其他物体,我们也可以将其他物体拖放上去,只要是Transform类型的即可。
    -运行。你可以看到聚光灯一直照向主相机。

    6.访问组件
    一个游戏对象可能有多个脚本或其他组件。它将不可避免的要访问其他组件的函数或变量。Unity中通过GetComponent()函数来实现这个目的。我们现在要实现按下空格键后让聚光灯照向Cube。
    我们考虑一下这个步骤:1.监视空格键被按下。2.空格键按下后聚光灯照向Cube。
    由于SporLight脚本中有target变量,我们只需要为这个变量设定新的值就可以了。


    -创建一个脚本,命名为Switch,添加如下代码:
    var switchToTarget : Transform;
    function Update(){
    	if(Input.GetButtonDown("Jump"))
    		GetComponent(SpotLight).target = switchToTarget;
    }
    注意GetComponent()的参数,它将返回一个参数给Switch脚本,我们就可以用它来访问"target"变量。
    里的GetComponent获取的不是点光源,而是那个名为SpotLight的JS文件。

    -添加Switch脚本到聚光灯对象,并将Cube拖放到Inspector面板中的switchToTarge变量上。


    -运行。按下空格后,聚光灯将照向Cube。

     

    前面我们提到,可以通过写代码的方式指定变量(而不是通过Unity界面),如何做到呢?上面按下空格时告诉聚光灯聚焦到Cube上,我们是在SpotLight脚本中做一个显式的变量,将Cube拖放上去。而在代码中主要有2种方法去实现:
    1.使用对象的名称(name)
    2.使用对象的标签(tag)

    1.对象名称
    可以从Hierarchy面板上看到对象的名称。用GameObject.Find()函数来使这些名称作为参数。因此,我们可以这样写:
    function Update(){
    	if(Input.GetButtonDown("Jump"))
    	{
    		var newTarget = GameObject.Find("Cube").transform;
    		GetComponent(SpotLight).target = newTarget;
    	}
    }
    注意,以上没有出现显式的变量。

    2.对象标签
    对象标签是一个字符串,用来识别一个组件。在Inspector面板中点击Tag按钮查看内建的标签。我们也可以创建自己的标签。GameObject.FindWithTag()函数能通过具体的标签寻找组件并返回一个字符串作为参数。
    function Update(){
    	if(Input.GetButtonDown("Jump"))
    	{
    		var newTarget = GameObject.FindWithTag("fang").transform;
    		GetComponent(SpotLight).target = newTarget;
    	}
    }
    

    7.实例

    我们要在运行时创建(create)对象就要用到Instantiate函数。
    让我们来实现如何在每次按下开火按钮(鼠标左键或Ctrl键)后通过实例化一个新的对象。需要思考以下几点:

    1.哪个物体做我们的实例?
    2.在哪儿实例化?
    关于第一个问题,最好的办法就是显式变量。
    这样我们就可以随时通过拖放来改变我们的实例对象。
    至于在哪儿实例化,我们只要实现当按下开火键时,在用户的当前位置创建一个对象即可。
    实例化函数有3个参数:1.我们要建立的对象。2.对象的位置坐标。3.对象的旋转位置。
    完整的代码如下:

    var newObject : Transform;
    function Update(){
        if(Input.GetButtonDown("Fire1")){
            Instantiate(newObject, transform.position, transform.rotation);
        }
    }
    要记住,transformpositiontransformrotation是附加这个脚本的物体的位置。我们这里假设为主相机。一般情况下,将要被实例化的对象设置为预设(prefab),我们现将Cube设置为预设。
    -首先,让我们创建一个预置。Assets->Create->Prefab。命名为Cube。

    -从Hierarchy面板中选取Cube拖放到Project面板的Cube上。

    -创建一个脚本并命名为Create,并把上面的代码加进去。

    -把这个脚本赋予相机,并将Cube预设赋予脚本变量。

    -运行。移动相机并按下开火键,你能看到新的Cube出现。


    8.调试
    调试是发现和修正你的代码中人为错误的技巧,Unity中提供了Debug类,我们现在看看Debug.Log()函数。
    Log()函数允许用户发送信息到Unity的控制台。这样做的原因可能包括:
    1.在运行时要验证某部分代码是否达成。
    2.报告变量的状态。
    我们现在使用Log()函数,当用户点击开火按钮时,发送一个消息到Unity控制台。
    -打开创建的脚本并在"Instantiate"代码内"if"处添加如下代码:
    Debug.Log("Cube created");
    -运行。点击开火键,我们能看到Unity界面下方显式"Cube created"。


    另外一个有用的功能是用于调试私有变量。这使得当Debug模式被选中时Inspector面板中的变量,但它不能被编辑。为了证明这一点,我们将显式一个私有变量作为Cube实例的计数器。我们在脚本中加入两行内容
    1.添加私有变量cubeCount。
    2.当一个cube实例创建后增加这个变量

    完整代码如下:
    var newObject : Transform;
    private var cubeCount = 0;
    function Update(){
    	if(Input.GetButtonDown("Fire1"))
    	{
    		Instantiate(newObject, transform.position, transform.rotation);
    		Debug.Log("Cube created");
    		cubeCount++;
    		Debug.Log(cubeCount);
    	}
    }


    9.常见脚本类型

    //在这个函数体中的代码每隔固定的间隔执行。它通常在Rigibody中有力的作用的时候被用到。如:
    // Apply a upwards force to the rigibody every frame
    function FixedUpdate(){
    	rigidbody.AddForce(Vector3.up);
    }
    
    
    //这里的代码将被用作初始化。
    Awake(){
    
    }
    
    //这个函数在Update()之前,但在Awake()之后执行。
    //Start()函数和Awake()函数的不同点在于Start()函数仅在脚本启用时候执行(Inspector面板中的复选框被选中)。
    Start(){
    
    }
    
    //当游戏对象的碰撞脚本与另一个游戏对象碰撞时执行这个函数内的代码。
    OnCollisionEnter(){
    
    }
    
    //当鼠标在一个载有GUI元素(GUIElement)或碰撞器(Collider)的游戏对象里按下时执行该函数体内的代码。
    // Loads the level named "SomeLevel" as a response
    // to the user clicking on the object
    function OnMouseDown(){
            Application.LoadLevel("SomeLevel");
    }
    
    //当鼠标悬停在一个GUI元素或碰撞器的对象上时,执行该函数体内的代码。如:
    // Fades the red component of the material to zero
    // while the mouse is over the mesh
    function OnMouseOver(){
            renderer.material.color.r -= 0.1 * Time.deltaTime;
    }


    展开全文
  • unity发布webplayer平台后会输出html和unity3d文件。我们的程序主要被打包在unity3d文件里,而html则是网页的界面显示。 1.Unity发送消息给JS unity想要和js交互,提供了一个函数:Application.ExternalCall();此...

    一.老版方法

    unity发布webplayer平台后会输出html和unity3d文件。我们的程序主要被打包在unity3d文件里,而html则是网页的界面显示。

    1.Unity发送消息给JS

    unity想要和js交互,提供了一个函数:Application.ExternalCall();此函数仅限于webplayer平台下。我们编辑发布的html文件,在里面加入我们的js脚本如下:

    function GetID(id)
    {
       alert("传入id:"+id);	
    }

    在unity里我们在start函数里调用

    Application.ExternalCall("GetID","吴彦祖");

    使用浏览器打开html文件,就会出现如下弹窗:

    2.JS发送消息给unity

    我们在刚才的js函数里添加一句代码:

    	function GetID(id)
    	{
    		alert("传入id:"+id);
    //发送消息给unity 第一个参数:挂在脚本的物体 第二个参数:unity被调用的函数 第三个参数:函数传入的参数
    		u.getUnity().SendMessage("Main Camera","GetIDInfo","JayW")
    	}

    在unity里创建一个函数用来接收处理:

    public void GetIDInfo(string id)
        {
            text.text = id;
        }

    运行效果如下:

    二.新版方法

    最近在使用webgl方面,2018.2.9版本弃用了Application.ExternalCall方法。选择添加一个jslb文件作为中间层。我们搜官方文档可以看到使用方式如下:

    首先创建一个文本,文件格式保持为.jslib。然后我们在里面增加我们要接受c#传来的数据和js要调用的函数。代码如下:

    mergeInto(LibraryManager.library, {
    
      JSLog: function (str) {
      var strs=Pointer_stringify(str);
        Log(strs);
      },
    });

    注意:这里一定要用unity内置函数Pointer_stringify将传进来的str转换成字符串。如果不转换str存储的是inptr数据的内存地址位。传到js就是一堆数字。最后保存文件,将文件放到unity工程下的Plugins文件夹内。

    然后在c#代码块里,我们加上我们要调用的方法:

        [DllImport("__Internal")]
        private static extern void JSLog(string str);//此处传入的类型和调用时候传入的数据类型一定要一致
    
    
    	void Start()
    	{
            JSLog("卧槽你大爷");
        }

    最后使我们打包出来的html文件里,在scrip块内加入被调用函数:

     function Log(str)
    	  {
    	  console.log(str);;
    	  gameInstance.SendMessage('Main Camera','GetStr',String(str));
    	  }

     

     

    展开全文
  • Unity3D是一个跨平台的游戏引擎,它提供了3d游戏的大部分基础功能实现,比如物理碰撞、3d模型显示、光照等功能,简化了使用者开发游戏的过程,更能够节省非常多的成本,unity3d与别的游戏引擎最大的不同是,它的代码...

    Unity3D是一个跨平台的游戏引擎,它提供了3d游戏的大部分基础功能实现,比如物理碰撞、3d模型显示、光照等功能,简化了使用者开发游戏的过程,更能够节省非常多的成本,unity3d与别的游戏引擎最大的不同是,它的代码是跨平台的,也就是说,别的引擎一款游戏要写好几份代码,它上面只需写一份就能在所有系统上运行。

    unity是使用javascript 与c#进行游戏开发的,javascript 和c#都可以作为实现unity3d的脚本语言,但是关于那个脚本语言更适合来开发unity3d呢,js适合个人开发,C#适用于公司开发。U3D官方团队基于数据分析做出结论,U3D团队会把支持的重心转移到C#,也就是说文档和示例以及社区支持的重心都在C#,C#的文档会是最完善的,C#的代码实例会是最详细的,社区内用C#讨论的人数会是最多的。所以,选择C#开发是最适合的。

    对于学习unity3d,首先要掌握c#语言,然后才能按照路线开始正式学习

    1、Unity3D程序开发基础
    1)C#语法基础
    2)OOP(面向对象)
    3)网络通信
    4)内存管理
    从基础讲解C#语言,熟悉字段、属性、接口、委托、事件,掌握C#面向对象编程的核心思想。让学员掌握Unity3d各个方面的知识和基本使用方法,为后面深入的学习打下良好基础。
    2、Unity3D高级阶段
    1)Unity3D物体系统高级部分
    2)Untiy3D动画系统高级部分
    3)常规设计模式
    4)动画,跟随等相关插件学习
    5)第1,3人称项目讲解
    在原来的学习基础上,深入学习Unity3D物体系统、动画系统的高级部分,例如骨骼的绑定,动画角色的创建等。配合游戏案例进行深度讲解,让学生充分了解动画的制作过程。
    3、游戏跨平台发布
    1)IOS版发布
    2)安卓版发布
    3)网页版发布
    4)PC版发布

    展开全文
  • unity3djs和C#混合调用, unity中js脚本与c#脚本互相调用
  • unity中的js与其说是js,不如说是Unity Script。unity中的js是会经过编译的,其性能和本地速度差不多。在官方教材《unity 4.x从入门到精通》中unity称C#,Boo,JS的性能是差不多的。 unity中的js脚本是可以和C#...
  • [Unity3d]unity与html通信

    2019-05-07 00:25:59
    谈谈今天的学习收获,发现了一个好东西,unity与html能够相互通信,意味着我之前学的web开发还能在unity中用得上,哈哈,太happy了!下面简单谈谈通过Unity3D调用HTML网页的脚本...Unity3D浏览器通过执行Applicati...
  • Unity 3d C#和Javascript脚本互相调用 解决方案.
  •  为了更好地理解游戏的软件架构和对象模型,它获得更好的外观仅有一名Unity3D的游戏引擎和编辑器是非常有用的,它的主要原则。 Unity3D 引擎  Unity3D的是一个屡获殊荣的工具,用于创建交互式3D应用程序在多个...
  • 一部分的目录东西太多了 行为控制脚本 鼠标的路线 Unity3D教程:游戏玩家服务器的制作 Unity3D教程:实例化 JS脚本控制逐渐淡出的欢迎界面 Unity3D教程:界面插件NGUI的使用 (2) 脚本控制物体的变换 脚本的运行顺序...
  • Unity3D中一些脚本的方法只能用在JS中,在C#中是无效的,而C#可以与服务器端通讯,JS本身却不行。而且,如果需要用到js调用c#的问题,js会比c#先编译,所以在mac里编译ios的时候会出错,提示为无法找到那个C#类。...
  • 我一直向所有想做游戏的朋友推荐Unity3D,为什么呢?首先是因为专业,Unity3D非常强大,用它创建一个类似MiniGore这样的3D平面射击游戏简直轻而易举,而就连使命召唤这样的大型3d游戏,如果素材得当也不在话下。二是...
  • ThreeJs技术交流(4)——Unity3D与ThreeJS、以及在3D场景中添加视频Unity3D和ThreeJS在3D场景中添加视频基于平面添加视频基于video.js视屏控件添加视频结束语 Unity3D和ThreeJS 最近我正在学习Unity3D,ThreeJS的...
  • 作为一名cocos2d-x开发者,开发2D游戏已经有两年多了,这...cocos的一个“劲敌”unity卷土而来,几乎霸占了整个3D市场,很多开发者都欣然奔向了unity的怀抱。cocos2d-x也从3.3版本之后开始猛加3D功能,如今3D功能也是比
  • Unity3d脚本大全

    2020-07-10 23:31:28
    这是Unity3d的脚本大总结,很多很有用的脚本,包括js以及c#,还有一些操作方法。
  •  在使用unity3d进行游戏开发或者互动项目制作的时候,有3种编辑语言可供使用,不过用的最多的应该是javascript和c#两种语言,相信很多朋友特别是新手都会很纠结于到底该用二者种的哪一个比较好,下面是老外对unity...
1 2 3 4 5 ... 20
收藏数 9,489
精华内容 3,795