# 控制 ridig body 來實作簡易版開關門
###### tags: `Omniverse`
## 功能
1. 鍵盤控制 Controller 在場景內移動
2. 碰撞偵測 : trigger
> 持續增添新功能中。 [name=megan ( Omniverse 菜雞仔 )]
## 實作步驟
1. 開啟環境 : `Omniverse > Create > LAUNCH`
2. 新增場景
* 創建物理場景 : `Create > Physics > Physics Scene`
* 創建地面 : `Create > Physics > Ground Plane`
4. 新增可控制角色
* 創建角色 : `Create > Shape > Capsule`
* 套用 Rigid Body : `Property > Add > Physics > Rigid Body with Colliders Preset`
5. 新增門與牆壁
* 創建門 :
* `Asset Store(beta) > Search:door`
* download 順眼的門 : Simple_Wood_Door (輸入 sketchfab 密碼)
* 創建牆壁*3 : `Create > Shape > Cube`
### 碰撞偵測
1. 在需要有物理阻擋的物件(牆壁*3、門)上賦予碰撞功能 : `Property > Add > Physics > Collider`
2. 開關門事件
* 新建碰撞觸發器 :
* `Create > Cube`
* rename `door_trigger`
* 放在門口處(若是被 Capsule 碰到則觸發開門,沒有碰到時表示關門狀態)

* 隱藏(但仍可以偵測碰撞) : `property > Visual > Purpose : guide`
* 新增Trigger :
`property > Add > Physics > collider`
`property > Add > Trigger`
* 建立 Trigger 腳本
```python=
import sys
from pxr import Usd, UsdGeom, Gf, Vt, UsdUtils
def main():
print("fafa")
if not hasattr(sys, 'argv'):
sys.argv = ['']
if len(sys.argv) ==6:
stageId = int(sys.argv[1])
triggerPath = sys.argv[2]
otherPath = sys.argv[3]
eventName = sys.argv[4]
scriptFileName = sys.argv[5]
print("Executed script: " + scriptFileName)
print("Event name: " + eventName)
cache = UsdUtils.StageCache.Get()
stage = cache.Find(Usd.StageCache.Id.FromLongInt(stageId))
if stage:
otherPrim = stage.GetPrimAtPath("/World/Simple_Wood_Door")
cube_prim = UsdGeom.Mesh.Get(stage, otherPrim.GetPath())
if eventName == "LeaveEvent": #colse door
xform = UsdGeom.Xformable(cube_prim)
xform.ClearXformOpOrder()
transform = xform.AddTransformOp()
mat = Gf.Matrix4d()
mat.SetTranslateOnly(Gf.Vec3d(0,0,0))
mat.SetRotateOnly(Gf.Rotation(Gf.Vec3d(0, 1, 0), 0))
transform.Set(mat)
else: # open door
xform = UsdGeom.Xformable(cube_prim)
xform.ClearXformOpOrder()
transform = xform.AddTransformOp()
mat = Gf.Matrix4d()
mat.SetTranslateOnly(Gf.Vec3d(0,0,0))
mat.SetRotateOnly(Gf.Rotation(Gf.Vec3d(0, 1, 0), 120))
transform.Set(mat)
pass
main()
```
* 將腳本路徑宣告在`door_trigger > property > Physic > Trigger > On Enter Script & On Leave Script`

### Keyboard 事件
1. W A S D 控制 Capsule 前後左右移動
2. 於 Script Editor 內執行腳本
3. code :
```python=
import carb.imgui
import carb.windowing
import carb.input
import omni.appwindow
import omni
from pxr import UsdGeom, Gf
import omni.usd
#get capsule original position
stage = omni.usd.get_context().get_stage()
door_prim = stage.GetPrimAtPath("/World/Capsule")
local_transform = omni.usd.get_local_transform_SRT(door_prim)
translate = local_transform[3]
_x = translate[0]
_y = translate[1]
_z = translate[2]
appwindow = omni.appwindow.get_default_app_window()
keyboard = appwindow.get_keyboard()
def on_input(e):
xform = UsdGeom.Xformable(door_prim)
xform.ClearXformOpOrder()
transform = xform.AddTransformOp()
mat = Gf.Matrix4d()
global _x
global _y
global _z
if e.input == carb.input.KeyboardInput.W:
#forward z--
_z = _z -10
mat.SetTranslateOnly(Gf.Vec3d(_x,_y,_z))
transform.Set(mat)
if e.input == carb.input.KeyboardInput.A:
#left x--
_x = _x -10
mat.SetTranslateOnly(Gf.Vec3d(_x,_y,_z))
transform.Set(mat)
if e.input == carb.input.KeyboardInput.S:
#back z++
_z = _z +10
mat.SetTranslateOnly(Gf.Vec3d(_x,_y,_z))
transform.Set(mat)
if e.input == carb.input.KeyboardInput.D:
#right x++
_x = _x +10
mat.SetTranslateOnly(Gf.Vec3d(_x,_y,_z))
transform.Set(mat)
return True
input = carb.input.acquire_input_interface()
keyboard_sub_id = input.subscribe_to_keyboard_events(keyboard, on_input)
```
4. 參考來源
* [取得當前位置](https://forums.developer.nvidia.com/t/get-position-of-a-prim-object/224198)
## 影片 demo
網址 : https://www.youtube.com/watch?v=esIZ5J_E22k