Stream 套件,讓運行此領域專屬語言的引擎引入參與者模型 (actor model),高效 率管理分散式環境下的各個參與裝置(感應器、Unity 程式)。
‧ 國
立 政 治 大 學
‧
N a tio na
l C h engchi U ni ve rs it y
52
最後,我們透過程式化展演規則,實現了讓實體展演者與虛擬環境的角色或 場景之間互動得以更程式化的支援,我們另外設計了一款輕量級的圖形化編輯器,
提供不具程式設計經驗的 DIPS 腳本撰寫者一個直覺與快速的開發工具,且能夠 輕易擴充或客製化,達到降低使用與學習該語言的門檻之目的。
‧
置,如此一來,導演的描述便可擴充如下:『when(actor body state) { action1 } otherwise {action2}』,本系統便可具更多個演員或多個虛擬角色、場景互動的能 力,語言能力也更強,此外這樣還更一個優點,導演可以組合演員與肢體,再由 演員與肢體的組合來產生對應的狀態與動作,提高導演編寫的自由度,函式庫的 可擴充性也更高。‧
結束,例如我們註冊了一個展演規則為『when(leftHandUp){ noseRaise }』,則該 表演過程中,左手舉起規則便完全綁定鼻子舉起的動作效果,但是一個表演節目‧
DemoDevice 與 DemoBody 兩部分,以提高不同裝置的辨識度。由於本研究旨在虛實環境與DIPS 執行引擎的整合,因此我們保留該實作的 彈性空間給予未來的實作。
通訊資料格式的改善
目前解譯實體裝置送來的感應器資料時,研究計畫中定義的資料格式為
『{"device": {"x" : "...", "y": "...", "z": "..."}} 』,例如收到來自左手的訊號,其資 料內容為『{"LeftHand": {"x":"25.364231", "y":"54.123158", "z":"0.546548"}} 』,
這樣的資料格式在解析 JSON 內容時會遇到無法直接取得裝置名稱的狀況,因為 多數的解析器(parser)實作不會提供存取『key』名稱(此例 key 名稱是 LeftHand) 的方法,本實作目前是透過另外解析資料字串以取出裝置名稱。
多數的 JSON 解析器實作都更個慣例,就是不會把資料存放在 key 中,理 想上的資料格式建議遵守『Micha's Golden Rule』,Mike Dewar [15]提出使用該資 料格式來處理 JSON,可以提高 D3.js 在資料選取上的便利與效率,因此目前的 資料格式建議改成『{"body": "DeviceName", "position": {"x" : "...", "y": "...", "z":
"..."}}』這樣的格式 ( key [field] : value [data] )。
‧
陣列內容為:[ number_of_device, value_of_x, value_of_y, value_of_z ],其中第一 項 number_of_device 為定義好的裝置編號(客製化時通訊各方統一好更哪些裝置,
便可定義出裝置編號),可以整數來編號,其它為座標值,精確度為單精度浮點 數,其長度為 4 位元組,如此則各欄位長度皆為 4 位元組(byte),共 16 位元組,
相較現行格式之最短可能內容:『{"A":{"x":"0.0","y":"0.0","z":"0.0"}}』長度為 37 位元組,(裝置名稱長度不一,因此長度可能更長,且可能性很高,此亦增加解
1 val leftHandUpRule: Rule = when (leftHandUp) { 2 noseRaise
3 } 以及
1 val handsUpRule: Rule = when (leftHandUp and rightHandUp) {
2 noseLay
‧
[1] Hsin Huang, Hsin-Chien Huang, Chun-Feng Liao, Ting-Chun Li, Tzzu-Chieh Tsai, Li-jia Teng, Future Circus: A Performer-Guided Mixed-reality Performance Art, 2015, International Symposium on Wearable Computers
[2] Sorensen, Andrew(2005) , Impromptu : an interactive programming environment for composition and performance. In: Proceedings of the Australasian Computer Music Conference 2009, 2-4 July 2009, Queensland University of Technology, Brisbane.
[3] Ingo Maier Martin Odersky., Deprecating the Observer Pattern with Scala.React, EPFL-REPORT-176887
[4] P. Hudak., Modular domain specific languages and tools., In P. Devanbu and J.
Poulin, editors, Proceeding of the 5th International Conference on Software Reuse (ICSR'98), pages 134-142. IEEE, 1998.
[5] Martin Fowler., Domain specific languages., Addison-Wesley Professional, 2010 [6] H. Conrad Cunningham., A Little Language for Surveys: Constructing an Internal
DSL in Ruby.
[7] Daan Leijen and Erik Meijer, Domain Specific Embedded Compilers, Proceedings of DSL'99: The 2nd Conference on Domain-Specific Languages, Austin, Texas, USA, October 3–6, 1999
[8] Carl Hewitt; Peter Bishop and Richard Steiger., A Universal Modular Actor For-malism for Artificial Intelligence., IJCAI. 1973.
‧
[9] Gul A. Agha, Actors: A Model of Concurrent Computation In Distributed Sys-tems., 1985
[10] Akka Scala Documentation, Release 2.4-SNAPSHOT, Typesafe Inc.
[11] Evan Czaplicki, Elm: Concurrent FRP for Functional GUIs, 2012
[12] Zhanyong Wan, Paul Hudak, Functional Reactive Programming from First Principles, PLDI '00 Proceedings of the ACM SIGPLAN 2000 conference on Programming language design and implementation Pages 242-252
[13] Debasish Ghosh, Anshinsoft , DSL for the Uninitiated, June 1, 2011 [14] Mike Dewar, Getting Start with D3, O'Reilly, 2012
[15] 謝忠和, 全民做遊戲 Unity 3D 跨平台遊戲開發寶典, 2012 [16] DIPS DSL, https://github.com/NCCUCS-PLSM/scala-dsl [17] DIPS Demo, https://github.com/NCCUCS-PLSM/dsl-demo
[18] DIPS Demo Unity Part, https://github.com/NCCUCS-PLSM/dsl-engine-unity [19] Martin Fowler, Work in progress, http://martinfowler.com/dslwip/, 2007.
[20] Reactive Streams, http://www.reactive-streams.org
[21] vFavbric team , Choosing Your Messaging Protocol: AMQP, MQTT, or STOMP, http://blogs.vmware.com/vfabric/2013/02/choosing-your-messaging-protocol-amq p-mqtt-or-stomp.html
[22] Phidgets 1056 user guide, http://www.phidgets.com/docs/1056_User_Guide [23] MIT Scratch extension, http://wiki.scratch.mit.edu/wiki/Scratch_Extension [24] Google Blockly, https://github.com/google/blockly
[25] Arvin Hsieh, [Design Pattern] 觀察者模式 (Observer Pattern) 我也能夠辦報 社, http://www.dotblogs.com.tw/joysdw12/archiver/2013/03/13/96531.aspx
‧ 國
立 政 治 大 學
‧
N a tio na
l C h engchi U ni ve rs it y
59
[26] 邓际锋, 函数式反应型编程(FRP) — 实时互动应用开发的新思路, InfoQ, 2013, http://www.infoq.com/cn/articles/functional-reactive-programming [27] CC 數位學習網, Unity 3D 教學, http://www.cg.com.tw/Unity
‧
- implicit class SyntaxHelper(t: T) - def *(int: Int) = ev times (t, int) - def /(int: Int) = ev divide (t, int)
- def +(t2: T) = ev plus (t, t2) - def foldFun(s: Option[(T, Int)], t: T)
‧
- def or(signal: Signal[Boolean])(implicit evidence: Signal[T] =:= Condition): Condition - def and(signal: Signal[Boolean])(implicit evidence: Signal[T] =:= Condition): Condition
- def _1[U](implicit evidence: Signal[T] =:= Signal[(U, _)]): Signal[U]
‧ 國
立 政 治 大 學
‧
N a tio na
l C h engchi U ni ve rs it y
62
- def x(implicit evidence: Signal[T] =:= Signal[Pos]): Signal[Int]
- def y(implicit evidence: Signal[T] =:= Signal[Pos]): Signal[Int]
- def _2[U](implicit evidence: Signal[T] =:= Signal[(_, U)]): Signal[U]
case class FilterSignal[T](s: Signal[T], f: T => Boolean) extends Signal[T]
case class IntervalSignal[T](s: Signal[T], interval: Duration) extends Signal[T]
case class FoldSignal[T, U](s: Signal[T], start: U, f: (U, T) => U) extends Signal[U]
case class MappedSignal[T, U](s: Signal[T], f: T => U) extends Signal[U]
case class ZippedSignal[U, V](signal1: Signal[U], signal2: Signal[V], initialL: Op-tion[U] = None, initialR: Option[V] = None) extends Signal[(U, V)]
- def withDefaults(left: Option[U] = None, right: Option[V] = None):
ZippedSignal[U, V]
- private def choose[T](c1: Option[T], c2: Option[T])
case class Property[T](query: DeviceQuery, key: String) extends Signal[T]
case class SignalData[T](s: Signal[T], data: T)
case class Or(c1: Condition, c2: Condition) extends Condition case class And(c1: Condition, c2: Condition) extends Condition case class Not(condition: Condition) extends Condition
‧ 國
立 政 治 大 學
‧
N a tio na
l C h engchi U ni ve rs it y
63
附錄二
Syntax.scala 類別與方法結構 object Syntax
- implicit class Ruler(actorRef: ActorRef) - def instruct(rule: Rule)
- object Location
- def inside(location: Location): LocationQuery - def not(query: LocationQuery): LocationQuery - object L
- def apply(s: String)
- implicit def functionToFunctionAction(f: () => Any)
- def zip[T, U](signal1: Signal[T], signal2: Signal[U]): Signal[(T, U)]
- def when(condition: Condition)(action: Action) - def not(condition: Condition)
- def not[T](f: T => Boolean) - def apply(t: T): Boolean
‧
Rule.scala 類別與方法結構 object `package`
trait Rule
- def condition: Condition - def action: Action
- def elseAction: Option[Action]
case class IfRule(condition: Condition, action: Action) extends Rule - def otherwise(elseAction: Action)
case class IfElseRule(condition: Condition, action: Action, elseAct: Action) extends Rule
- override def elseAction case class ActorMessageAction[T](query: De-viceQuery, command: T) extends Action
case class ShowSignalAction[T](query: DeviceQuery, signal: Signal[T]) extends Action
case class FunctionAction(function: () => Any) extends Action case class Show[T](signal: Signal[T])
trait Action
- def and(action2: Action)
case class Then(action1: Action, action2: Action) extends Action case object DeleteRules
‧
Device.scala 類別與方法結構 case class DeviceDescriptor(
case class NamedDeviceQuery(name: String) extends DeviceQuery - def matchesDescriptor(descriptor: DeviceDescriptor)
case class TypeDeviceQuery(typ: String) extends DeviceQuery - def matchesDescriptor(descriptor: DeviceDescriptor)
case class LocationDeviceQuery(query: LocationQuery) extends DeviceQuery - def matchesDescriptor(descriptor: DeviceDescriptor)
case class UUIDDeviceQuery(uuid: String) extends DeviceQuery - def matchesDescriptor(descriptor: DeviceDescriptor)
case class OutputsDeviceQuery(outputs: List[(String, Class[_])]) extends DeviceQuery - def matchesDescriptor(descriptor: DeviceDescriptor)
case class InputsDeviceQuery(inputs: List[(String, Class[_])]) extends DeviceQuery - def matchesDescriptor(descriptor: DeviceDescriptor)
‧ 國
立 政 治 大 學
‧
N a tio na
l C h engchi U ni ve rs it y
66
trait GenericDeviceQuery extends DeviceQuery with Dynamic - def property[T](propertyName: String)
- def is(propertyName: String)
- def selectDynamic[T](propertyName: String) trait DeviceQuery
- def matchesDescriptor(descriptor: DeviceDescriptor): Boolean - def should[T](message: T)
- def shouldShow[T](signal: Signal[T]) object Device - def named(name: String)
- def ofType(type: String) - def inside(location: Location) - def withUUID(uuid: String)
- def thatOutputs(list: List[(String, Class[_])]) - def thatInputs(list: List[(String, Class[_])])
‧
DemoDevice.scala 之類別實作
/**** Define supported physic devices. ****/
‧
‧
‧
‧ 國
立 政 治 大 學
‧
N a tio na
l C h engchi U ni ve rs it y
71
} }
‧ 國
立 政 治 大 學
‧
N a tio na
l C h engchi U ni ve rs it y
72
附錄六
DemoState.scala 之狀態定義實作
/* x-axis state definition of left hand sensor */
val leftHandx: Signal[Float] = leftHand.property[Float]("LeftHandx") val lx: Signal[Float] = leftHandx.atRate(1 second)
val leftHandUp: Condition = lx < (-10).toFloat val leftHandDown: Condition = lx > 10.toFloat
/* x-axis state definition of right hand sensor */
val rightHandx: Signal[Float] = rightHand.property[Float]("RightHandx") val rx: Signal[Float] = rightHandx.atRate(1 second)
val rightHandUp: Condition = rx < (-10).toFloat val rightHandDown: Condition = rx > 10.toFloat
‧ 國
立 政 治 大 學
‧
N a tio na
l C h engchi U ni ve rs it y
73
附錄七
DemoAction.scala 之動作命令實作
val noseRaise: Action = elephant should "noseRaise"
val noseLay: Action = elephant should "noseDown"
val bodyRaise: Action = elephant should "bodyRaise"
val bodyLay: Action = elephant should "bodyDown"
val keepElephantAction: Action = elephant should "keepAction"
‧ 國
立 政 治 大 學
‧
N a tio na
l C h engchi U ni ve rs it y
74
附錄八
DemoEffect.scala 之特效命令實作 val lightOn: Action = light should "on"
val lightOff: Action = light should "off"
val keepLightAction: Action = light should "keepAction"
‧ 國
立 政 治 大 學
‧
N a tio na
l C h engchi U ni ve rs it y
75
附錄九
Engine.scala 腳本執行引擎主程式 object Engine {
def main(args: Array[String]): Unit = { /* loading SDL script */
val filename = getClass.getResource("/DemoDSLScript.scala") val script = Source.fromURL(filename).mkString
/* parse and eval script */
val tb = currentMirror.mkToolBox() tb.eval(tb.parse(script))
} }
‧
EngineDIPSCreator.scala 接收圖形化編輯器介面的執行引擎主程式 object EngineDIPSCreator {
var times = 0 var script = ""
def main(args: Array[String]): Unit = { val serverSock = new ServerSocket(12345)
// listening to socket request from DIPS creator while (true) {
‧ 國
立 政 治 大 學
‧
N a tio na
l C h engchi U ni ve rs it y
77
} }
// Handle request from Scratch
def handleRequest(sockIn: InputStream): Unit = { val buf = new Array[Byte](5000)
val bytes_read = sockIn.read(buf, 0, buf.length)
val header = new String(Arrays.copyOf(buf, bytes_read)) val url = header.substring(header.indexOf("/?rule=")+7, head-er.indexOf("HTTP/1"))
val script = URLDecoder.decode(url, "UTF-8")
val tb = currentMirror.mkToolBox() tb.eval(tb.parse(script))
} }
‧ 國
立 政 治 大 學
‧
N a tio na
l C h engchi U ni ve rs it y
78
附錄十一
展示動作的對應 DSL 腳本
1. 魔術師的左手向上舉起,做出指示大象鼻子舉起來的動作,魔術師的左手放 下,做出指示大象鼻子放下來的動作
1 val leftHandUpRule: Rule = when(leftHandUp){
2 noseRaise 3 } otherwise {
4 keepElephantAction 5 }
6 val leftHandDownRule: Rule = when(leftHandDown){
7 noseLay 8 } otherwise {
9 keepElephantAction 10 }
11 listener.instruct(leftHandUpRule) 12 listener.instruct(leftHandDownRule)
‧ 國
立 政 治 大 學
‧
N a tio na
l C h engchi U ni ve rs it y
79
2. 魔術師的右手向上舉起,做出指示大象身體抬起來的動作,魔術師的右手放 下,做出指示大象身體放下來的動作
1 val rightHandUpRule: Rule = when(rightHandUp){
2 bodyRaise 3 } otherwise {
4 keepElephantAction 5 }
6 val rightHandDownRule: Rule = when(rightHandDown){
7 bodyLay 8 } otherwise {
9 keepElephantAction 10 }
11 listener.instruct(rightHandUpRule) 12 listener.instruct(rightHandDownRule)
‧ 國
立 政 治 大 學
‧
N a tio na
l C h engchi U ni ve rs it y
80
3. 魔術師的雙手舉起,燈亮起來,魔術師的雙手放下,燈暗下來 1 val handsUpRule: Rule = when(leftHandUp and rightHandUp){
2 lightOn 3 } otherwise { 4 keepLightAction 5 }
6 val handsDownRule: Rule = when(leftHandDown and rightHandDown){
7 lightOff 8 } otherwise { 9 keepLightAction 10 }
11 listener.instruct(handsUpRule) 12 listener.instruct(handsDownRule)