Scorpio-CSharp——第一弹 Space Shooter

  写在前面————

        哈哈, 开始做关于脚本热更新的第一个例子了,鉴于本人还是个没毕业的学生,所以不足之处还希望大家包涵~~~~~~

  注意:

          1.本文章是用Space Shooter(Unity3d官方的小游戏)做的例子

          2.Space Shooter源码和Scorpio-CSharp 的下载链接我会放在文章最后面

          3.如有任何疑问,请加群245199668

  正文

          1.新建项目,把下载好的Space Shooter导入Unity中, 打开Done_Main场景,

           2.下载Scorpio-CSharp,你会得到几个文件:Scorpio,ScorpioDemo,ScorpioExec,ScorpioMaker,ScorpioTest。把Scorpio整个文件夹复制到      Unity3d里(如果还不知道Scorpio-CSharp是什么或者是热更新是什么请点这里这里)。

          3.做一个底层。新建2个脚本,ActionManager和ScriptComponent。ActionManager主要是提供一些方法方便调用,而ScriptComponent是为了过渡C#               脚本,或者也可以说是从C#到Scorpio-CSharp的一个接口。而运行一个Scorpio-CSharp脚本需要压入程序集(PushAssembly)和导入类(import_type)

Singleton:方便全局调用

1 //单例模式
2 public abstract class Singleton<T> where T : class, new()
3 {
4     static T msInstance = null;
5     public static T Instance { get { return msInstance ?? (msInstance = new T()); } }
6 }

ActionManager:

      1.它可以随时随地运行一个热更新脚本,但是该脚本挂载的ScriptComponent是摄像机的,也就是说this.gameObject获得的是摄像机的,OnTriggerEnter之类的函数也是摄像机。

      2.它也可以通过RunScript运行指定物体上的热更新脚本

注意,所有的热更新脚本已通过ActionManager把常用类导入进去了且都放在了Resources文件夹下,通过Resources.Load读取。

 1 #define DEBUG
 2
 3 using UnityEngine;
 4 using System .Collections;
 5 using Scorpio;
 6
 7 public class ActionScriptManager : Singleton<ActionScriptManager>
 8 {
 9     public ActionScriptManager ( )
10     {
11         script = new Script ( );
12         ScriptComponent sc = Camera.main.gameObject.AddComponent<ScriptComponent>();
13         sc .Init ( script );
14         try
15         {
16             SetScript ( script );
17
18             importType = Resources .Load ( "ImportType" ) as TextAsset;
19         }
20         catch ( System .Exception e )
21         {
22             Debug .LogError ( "StackInfo : " + script .GetStackInfo ( ) );
23             Debug .LogError ( e .ToString ( ) );
24         }
25 #if DEBUG
26         stopwatch = new System .Diagnostics .Stopwatch ( );
27 #endif
28     }
29
30     public void SetScript(Script scriptTmp)
31     {
32         if(scriptTmp != null)
33         {
34             scriptTmp .LoadLibrary ( );
35             scriptTmp .PushAssembly ( GetType ( ) .Assembly );
36             //system
37             scriptTmp .PushAssembly ( typeof ( byte ) .Assembly );
38             //UnityEngine
39             scriptTmp .PushAssembly ( typeof ( Object ) .Assembly );
40         }
41     }
42
43     public ScriptObject RunScript ( string scoName )
44     {
45         return RunScript ( script , scoName );
46     }
47
48     public ScriptObject RunScript ( Script scriptTmp, string scoName )
49     {
50         ScriptObject ret;
51
52         if(scriptTmp == null)
53         {
54             Debug .LogError ( scriptTmp + " is null" );
55             return null;
56         }
57
58         textAsset = Resources .Load ( scoName ) as TextAsset;
59         if(textAsset == null)
60         {
61             Debug .LogError ( scoName + " is null" );
62             return null;
63         }
64
65         targetText = importType .text;
66         targetText += textAsset .text;
67
68 #if DEBUG
69         stopwatch .Start ( );
70 #endif
71
72         ret = scriptTmp .LoadString ( targetText );
73
74 #if DEBUG
75         stopwatch .Stop ( );
76         Debug .Log ( scoName + " 运行时间: " + stopwatch .ElapsedMilliseconds .ToString ( ) + "ms" );
77 #endif
78
79         return ret;
80     }
81
82     //脚本源文件
83     TextAsset textAsset;
84     //注册
85     TextAsset importType;
86     //目标字符串
87     string targetText;
88     //热更新脚本
89     Script script;
90 #if DEBUG
91     //计时器
92     System.Diagnostics.Stopwatch stopwatch;
93 #endif
94 }

ScriptComponent:

 1 using UnityEngine;
 2 using Scorpio;
 3
 4 public class ScriptComponent : MonoBehaviour
 5 {
 6     public Script script;
 7     public ScriptTable scriptTable;
 8
 9     public void Init(Script source)
10     {
11         script = source;
12         scriptTable = source .GetGlobalTable ( );
13         scriptTable .SetValue ( "transform" , script .CreateUserdata ( this .transform ) );
14         scriptTable .SetValue ( "gameObject" , script .CreateUserdata ( this .gameObject ) );
15         OnStart ( );
16     }
17
18     void OnStart()
19     {
20         Call ( "Awake" );
21     }
22
23     void Start()
24     {
25         Call ( "Start" );
26     }
27
28     void Update()
29     {
30         Call ( "Update" );
31     }
32
33     void FixedUpdate()
34     {
35         Call ( "FixedUpdate" );
36     }
37
38     void OnGUI ( )
39     {
40         Call ( "OnGUI" );
41     }
42
43     void OnCollisionEnter ( Collision otherCollider )
44     {
45         Call ( "OnCollisionEnter" , otherCollider );
46     }
47
48     void OnCollisionStay ( Collision otherCollider )
49     {
50         Call ( "OnCollisionStay" , otherCollider );
51     }
52
53     void OnCollisionExit ( Collision otherCollider )
54     {
55         Call ( "OnCollisionExit" , otherCollider );
56     }
57
58     void OnTriggerEnter ( Collider otherCollider )
59     {
60         Call ( "OnTriggerEnter" , otherCollider );
61     }
62
63     void OnTriggerStay ( Collider otherCollider )
64     {
65         Call ( "OnTriggerStay" , otherCollider );
66     }
67
68     void OnTriggerExit ( Collider otherCollider )
69     {
70         Call ( "OnTriggerStay" , otherCollider );
71     }
72
73     public void Call(string func, params object[] args)
74     {
75         if(scriptTable != null && scriptTable.HasValue(func))
76         {
77             ( ( ScriptFunction ) scriptTable .GetValue ( func ) ) .call ( args );
78         }
79     }
80 }

ImportType:

 1 //UnityEngine
 2 GameObject = import_type("UnityEngine.GameObject")
 3 Object = import_type("UnityEngine.Object")
 4 Mathf = import_type("UnityEngine.Mathf")
 5 PrimitiveType = import_type("UnityEngine.PrimitiveType")
 6 Resources = import_type("UnityEngine.Resources")
 7 Debug = import_type("UnityEngine.Debug")
 8 Transform = import_type("UnityEngine.Transform")
 9 Vector2 = import_type("UnityEngine.Vector2")
10 Vector3 = import_type("UnityEngine.Vector3")
11 Vector4 = import_type("UnityEngine.Vector4")
12 Application = import_type("UnityEngine.Application")
13 Time = import_type("UnityEngine.Time")
14 Camera = import_type("UnityEngine.Camera")
15 LineRenderer = import_type("UnityEngine.LineRenderer")
16 Screen = import_type("UnityEngine.Screen")
17 SleepTimeout = import_type("UnityEngine.SleepTimeout")
18 Input = import_type("UnityEngine.Input")
19 SpriteRenderer = import_type("UnityEngine.SpriteRenderer")
20 KeyCode = import_type("UnityEngine.KeyCode")
21 Color = import_type("UnityEngine.Color")
22 Random = import_type("UnityEngine.Random")
23 Quaternion = import_type("UnityEngine.Quaternion")
24 Animator = import_type ("UnityEngine.Animator")
25 Renderer = import_type ("UnityEngine.Renderer")
26 Collision = import_type("UnityEngine.Collision")
27 AudioSource = import_type("UnityEngine.AudioSource")
28 Rigidbody = import_type("UnityEngine.Rigidbody")
29 //System
30 byte = import_type("System.byte")
31 int = import_type("System.Int32")
32 float = import_type("System.Single")
33 double = import_type("System.Double")
34 bool = import_type("System.Boolean")
35 string = import_type("System.string")
36
37 List = import_type("System.Collections.Generic.List`1")
38 ListInt = generic_type(List, int)
39 ListGameObject = generic_type(List, GameObject)
40
41 //Owner class
42 ActionScriptManager = import_type("ActionScriptManager")
43 ScriptComponent = import_type("ScriptComponent")
44 Script = import_type("Scorpio.Script")

         4.修改Done_PlayerController成热更新脚本,在Done_GameController脚本的Start函数中加入下面代码,修改类Done_Boundary,加入构造函数。

1 ScriptComponent sc = GameObject.FindGameObjectWithTag("Player").AddComponent<ScriptComponent>();
2 Script s = new Script();
3 sc .Init ( s );
4 ActionScriptManager .Instance .SetScript ( s );
5 ActionScriptManager .Instance .RunScript ( s , "PlayerController" );

Done_PlayerController.txt:

 1 var speed = 10;
 2 var tilt = 5;
 3 var boundary = Done_Boundary(-6, 6, -4, 8);
 4 var shot;
 5 var shotSpawn;
 6 var fireRate = 0.25;
 7 var nextFire = 0;
 8 function Update ()
 9 {
10     shot = Resources.Load("Done_Bolt");
11     shotSpawn = transform.FindChild("Shot Spawn");
12     if (Input.GetButton("Fire1") && Time.time > nextFire)
13     {
14         nextFire = Time.time + fireRate;
15         GameObject.Instantiate(shot, shotSpawn.position, shotSpawn.rotation);
16         gameObject.GetComponent(typeof(AudioSource)).Play ();
17     }
18 }
19 function FixedUpdate()
20 {
21     var moveHorizontal = Input.GetAxis ("Horizontal");
22     var moveVertical = Input.GetAxis ("Vertical");
23     var movement = Vector3 (moveHorizontal, 0.0, moveVertical);
24     gameObject.GetComponent(typeof (Rigidbody)).velocity = Vector3.op_Multiply(movement, speed);
25     gameObject.GetComponent(typeof(Rigidbody)).position = Vector3
26     (
27         Mathf.Clamp (gameObject.GetComponent(typeof(Rigidbody)).position.x, boundary.xMin, boundary.xMax),
28         0.0,
29         Mathf.Clamp (gameObject.GetComponent(typeof(Rigidbody)).position.z, boundary.zMin, boundary.zMax)
30     );
31     gameObject.GetComponent(typeof (Rigidbody)).rotation
32         = Quaternion.Euler(0, 0, gameObject.GetComponent(typeof (Rigidbody)).velocity.x * -tilt);
33 }

今天就先到这里了。。。

————————————————————————————————华丽的分割线———————————————————————————————————————————————

  注意:

    1.假如在热更新脚本里使用系统或者unity的类,需先把程序集压入到Script里面(俩个类在同意程序集只用压一次), 然后再热更新脚本前头声明该类来自那个程序集(每个类都必须声明)。

如果说是自己写的类直接import_type和scriptTmp .PushAssembly ( GetType ( ) .Assembly );

例如(GameObject和Object在同一程序集里):

    scriptTmp .PushAssembly ( typeof ( Object ) .Assembly );

    GameObject = import_type("UnityEngine.GameObject")

    Object = import_type("UnityEngine.Object")

    2.Scorpio-CSharp脚本类似js脚本,声明全部用var

    3.默认数字为double和long,0为long,0.0为double

    4.没有new关键字,类初始化可以直接GameObject(),不需要new

    5.可以GetComponent(typeof(AudioSource)),不能GetComponent<AudioSource>()

    6.没有重写+=,-=,/=,*=操作符,可以通过Vector3.op_Multiply(乘),Vector3.op_Addition(加)实现

    7.热更新脚本没有继承mono使用创建和摧毁前得加上GameObject(GameObject.Destroy)

  链接:

    Space Shooter:     http://pan.baidu.com/s/1geuEEkF

    Scorpio-CSharp: https://github.com/qingfeng346/Scorpio-CSharp#showcase

   更多例子请看ScorpioDemo。

时间: 2024-10-11 05:09:31

Scorpio-CSharp——第一弹 Space Shooter的相关文章

codechef 营养题 第一弹

第一弾が始まる! 定期更新しない! 来源:http://wenku.baidu.com/link?url=XOJLwfgMsZp_9nhAK15591XFRgZl7f7_x7wtZ5_3T2peHh5XXoERDanUcdxw08SmRj1a5VY1o7jpW1xYv_V1kuYao1Pg4yKdfG4MfNsNAEa codechef problems 第一弹 一.Authentication Failed原题题面Several days ago Chef decided to registe

javascript之【贪吃蛇系列】第一弹:简单的贪吃蛇实现

参考博客:http://blog.csdn.net/sunxing007/article/details/4187038 以上博客是参考,毕竟第一次做,真让自己盲人摸象做不出来. 不过我在其上做了一些改进,界面等效果看起来更好一些. 下图是在Chrome上运行的效果,但是火狐和IE会不兼容,onkeydown事件不能正确调用 这里用了一张图把贪吃蛇制作过程的思想画了出来,画的有点简陋: 下面就是把代码发上来,上边有详细的解释: <html> <head> <title>

FluentData 学习 第一弹

地址: http://fluentdata.codeplex.com/ 前世: FluentData 我们公司用的一个增删改查的里面的持久层.之前还不知道 这个持久层叫FluentData.  某天看见群里 说 某视频网站里面 居然在讲这个开发框架,还收费.我搜了一下.fluentdata有源代码. 这个13年有过记载.不过我是新手.什么也需要 学习一下.  和 室友说了一下微型orm ,他们 呢  用的  微型orm是 Dapper .可以去了解一下. 废话真多,完毕. FluentData

C#Light 和 uLua的对比第一弹

初始化 做一样的初始化,其实是没办法对等的 C#Light的Env 不等于Lua的LuaState C#Light的执行有完全的执行堆栈,完整的作用域,lua都没有 C#Light有完整的class 函数,继承特征,lua都没有 C#Light可以用VS做编辑器,lua? 为了保持平等对抗,三个测试先做一遍,再依次执行 测试1 ,简单的一次创建给个名字并销毁,测试300次 测试2,调用Debug.Log打印,执行300次 测试3,一次性在脚本里多调用一些方法,创建10个物体再销毁 测试一结果:

The Internet Communications Engine (Ice) 跨平台异构通讯方案 第一弹-ICE简介

.net中的通讯方案很多,从.net Remoting,MSMQ,Webservice,WSE,WCF等等,他们都有一个特点,易用,但是都不能跨语种异构,如果你服务端要用java开发,客户端用C#开发,或者其它语言譬如C++, Python,PHP, Ruby, Objective-C,等等,那么.net提供的解决方案将不再有效.现在,隆重推出跨平台异构方案ICE.ICE官网:http://www.zeroc.com/ice.html 简介:The Internet Communications

MongoDB第一弹

下载: MongoDB下载地址: http://www.mongodb.org/ 我下载的是windows32的MSI. 安装: next就可以. 新建: 新建data文件夹,在data里面再建db和log两个子目录. 启动: 进入cmd,到当前MongoDB的bin目录下面,启动 "mongd"!(不是mongo),修改db路径. 然后打开浏览器输入localhost:27017,会出现: 最后在cmd中启动mongo.exe,出现: 基本操作: insert: find: upda

Ubuntu闪电入门第一弹

目录: 一.设置主机名 1.临时修改主机名 2.永久修改主机名 二.设置网络 1.配置静态IP地址 2.配置DNS服务器解析 3.修改DNS本地解析 三.软件包管理 1.dpkg管理软件包 2.apt管理软件包 四.运行级别 五.文件传输工具lrszs 1.发送文件sz 2.接收文件rz 六.磁盘管理 1.磁盘分区 2.磁盘分区格式化 3.挂载磁盘分区 一.设置主机名 1.临时修改主机名(重启系统后失效) $ sudo hostname ikki $ hostname ikki 2.永久修改主机

C# 二进制替换第一弹 byte 数组替换

Unity 3D本地发布WebPlayer版时遇到提示:"Failed to download data file"(如上图),遇到这个问题就是指Web服务器并没有支持这种*.unity3d文件类型.需要做的是在Web服务器中添加MIME类型: 1.IIS 7 及以上版本: 在功能视图的IIS选项卡中: 双击打开MIME,选择"添加": .unity3d application/octet-stream 2.IIS6版本: 右击计算机名,选择属性,找到MIME类型,

你好,博客园!!第一弹~局域网下的简易聊天室,socket与多线程简结

发觉博客园里面关于这些基本知识点的详细内容真是应有尽有,所以这里的随笔就不再重复了,就积累一下简单的用法-- 1.Socket 最近学网络编程,也就是Socket,套接字,一个用来建立链接传输数据的工具. 数据传输发生在"客户端"与"服务端"之间,下面是一种建立连接传输数据的简单方法: (1)客户端 1 try{ 2 //服务端ip 3 String ip = "127.0.0.1"; 4 //服务器端口 5 int port = 5000; 6