| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563 |
- require "LuaScripts/Utilities/Network"
- local testScene
- local camera
- local cameraNode
- local yaw = 0
- local pitch = 0
- local drawDebug = 0
- function Start()
- if not engine:IsHeadless() then
- InitConsole()
- InitUI()
- else
- OpenConsoleWindow()
- end
-
- ParseNetworkArguments()
- InitScene()
-
- SubscribeToEvent("Update", "HandleUpdate")
- SubscribeToEvent("KeyDown", "HandleKeyDown")
- SubscribeToEvent("MouseMove", "HandleMouseMove")
- SubscribeToEvent("MouseButtonDown", "HandleMouseButtonDown")
- SubscribeToEvent("MouseButtonUp", "HandleMouseButtonUp")
- SubscribeToEvent("PostRenderUpdate", "HandlePostRenderUpdate")
- SubscribeToEvent("SpawnBox", "HandleSpawnBox")
- SubscribeToEvent("PhysicsCollision", "HandlePhysicsCollision")
-
- network:RegisterRemoteEvent("SpawnBox")
-
- if runServer then
- network:StartServer(serverPort)
- SubscribeToEvent("ClientConnected", "HandleClientConnected")
- -- Disable physics interpolation to ensure clients get sent physically correct transforms
- testScene:GetComponent("PhysicsWorld"):SetInterpolation(false)
- end
-
- if runClient then
- network:Connect(serverAddress, serverPort, testScene)
- end
- end
- function Stop()
- testScene = nil
- camera = nil
- cameraNode = nil
- end
- function InitConsole()
- local uiStyle = cache:GetResource("XMLFile", "UI/DefaultStyle.xml")
- engine:CreateDebugHud()
- debugHud.defaultStyle = uiStyle
- debugHud.mode = DEBUGHUD_SHOW_ALL
- engine:CreateConsole()
- console.defaultStyle = uiStyle
- end
- function InitUI()
- local uiStyle = cache:GetResource("XMLFile", "UI/DefaultStyle.xml")
-
- local newCursor = Cursor:new()
- newCursor.styleAuto = uiStyle
- newCursor.position = IntVector2(graphics:GetWidth()/ 2, graphics:GetHeight() / 2)
- ui.cursor = newCursor
-
- if GetPlatform() == "Android" or GetPlatform() == "iOS" then
- ui.cursor.visible = false
- end
- end
- function InitScene()
- testScene = Scene()
-
- -- Create the camera outside the scene so it is unaffected by scene load/save
- cameraNode = Node()
- camera = cameraNode:CreateComponent("Camera")
- cameraNode.position = Vector3(0, 2, 0)
- if not engine:IsHeadless() then
- renderer:SetViewport(0, Viewport:new(testScene, camera))
-
- -- Add bloom & FXAA effects to the renderpath. Clone the default renderpath so that we don't affect it
- -- local newRenderPathPtr = renderer:GetViewport(0):GetRenderPath():Clone()
- -- local newRenderPath = newRenderPathPtr:Get()
- local newRenderPath = renderer:GetViewport(0):GetRenderPath():Clone()
- newRenderPath:Append(cache:GetResource("XMLFile", "PostProcess/Bloom.xml"))
- newRenderPath:Append(cache:GetResource("XMLFile", "PostProcess/EdgeFilter.xml"))
- newRenderPath:SetEnabled("Bloom", false)
- newRenderPath:SetEnabled("EdgeFilter", false)
- renderer:GetViewport(0):SetRenderPath(newRenderPath)
- audio:SetListener(cameraNode:CreateComponent("SoundListener"))
- end
-
- if runClient then
- return
- end
- local world = testScene:CreateComponent("PhysicsWorld")
- testScene:CreateComponent("Octree")
- testScene:CreateComponent("DebugRenderer")
- local zoneNode = testScene:CreateChild("Zone")
- local zone = zoneNode:CreateComponent("Zone")
- zone.ambientColor = Color(0.15, 0.15, 0.15)
- zone.fogColor = Color(0.5, 0.5, 0.7)
- zone.fogStart = 100.0
- zone.fogEnd = 300.0
- zone.boundingBox = BoundingBox(-1000, 1000)
-
- if true then
- local lightNode = testScene:CreateChild("GlobalLight")
- lightNode.direction = Vector3(0.3, -0.5, 0.425)
-
- local light = lightNode:CreateComponent("Light")
- light.lightType = LIGHT_DIRECTIONAL
- light.castShadows = true
- light.shadowBias = BiasParameters(0.00025, 0.5)
- light.shadowCascade = CascadeParameters(10.0, 50.0, 200.0, 0.0, 0.8)
- light.specularIntensity = 0.5
- end
- if true then
- local objectNode = testScene:CreateChild("Floor")
- objectNode.position = Vector3(0, -0.5, 0)
- objectNode.scale = Vector3(200, 1, 200)
-
- local object = objectNode:CreateComponent("StaticModel")
- object.model = cache:GetResource("Model", "Models/Box.mdl")
- object.material = cache:GetResource("Material", "Materials/StoneTiled.xml")
- object.occluder = true
- local body = objectNode:CreateComponent("RigidBody")
- local shape = objectNode:CreateComponent("CollisionShape")
- shape:SetBox(Vector3(1, 1, 1))
- end
- for i = 1, 50 do
- local objectNode = testScene:CreateChild("Box")
- objectNode.position = Vector3(Random() * 180 - 90, 1, Random() * 180 - 90)
- objectNode:SetScale(2)
- local object = objectNode:CreateComponent("StaticModel")
- object.model = cache:GetResource("Model", "Models/Box.mdl")
- object.material = cache:GetResource("Material", "Materials/Stone.xml")
- object.castShadows = true
- local body = objectNode:CreateComponent("RigidBody")
- local shape = objectNode:CreateComponent("CollisionShape")
- shape:SetBox(Vector3(1, 1, 1))
- end
- for i = 1, 10 do
- local objectNode = testScene:CreateChild("Box")
- objectNode.position = Vector3(Random() * 180 - 90, 10, Random() * 180 - 90)
- objectNode:SetScale(20)
- local object = objectNode:CreateComponent("StaticModel")
- object.model = cache:GetResource("Model", "Models/Box.mdl")
- object.material = cache:GetResource("Material", "Materials/Stone.xml")
- object.castShadows = true
- object.occluder = true
- local body = objectNode:CreateComponent("RigidBody")
- local shape = objectNode:CreateComponent("CollisionShape")
- shape:SetBox(Vector3(1, 1, 1))
- end
-
-
-
- for i = 1, 50 do
- local objectNode = testScene:CreateChild("Mushroom")
- objectNode.position = Vector3(Random() * 180 - 90, 0, Random() * 180 - 90)
- objectNode.rotation = Quaternion(0, Random(360.0), 0)
- objectNode:SetScale(5)
- local object = objectNode:CreateComponent("StaticModel")
- object.model = cache:GetResource("Model", "Models/Mushroom.mdl")
- object.material = cache:GetResource("Material", "Materials/Mushroom.xml")
- object.castShadows = true
- local body = objectNode:CreateComponent("RigidBody")
- local shape = objectNode:CreateComponent("CollisionShape")
- shape:SetTriangleMesh(object:GetModel())
- end
-
- for i = 1, 50 do
- local objectNode = testScene:CreateChild("Jack")
- objectNode:SetPosition(Vector3(Random() * 180 - 90, 0, Random() * 180 - 90))
- objectNode:SetRotation(Quaternion(0, Random() * 360, 0))
- local object = objectNode:CreateComponent("AnimatedModel")
- object.model = cache:GetResource("Model", "Models/Jack.mdl")
- object.material = cache:GetResource("Material", "Materials/Jack.xml")
- object.castShadows = true
-
- -- Create a capsule shape for detecting collisions
- local body = objectNode:CreateComponent("RigidBody")
- body.trigger = true
-
- local shape = objectNode:CreateComponent("CollisionShape")
- shape:SetCapsule(0.7, 1.8, Vector3(0.0, 0.9, 0.0))
- local ctrl = objectNode:CreateComponent("AnimationController")
- ctrl:Play("Models/Jack_Walk.ani", 0, true, 0.0)
- end
- end
- function HandleUpdate(eventType, eventData)
- local timeStep = eventData:GetFloat("TimeStep")
-
- if ui:GetFocusElement() == nil then
- local speedMultiplier = 1.0
- if input:GetKeyDown(KEY_LSHIFT) then
- speedMultiplier = 5.0
- end
- if input:GetKeyDown(KEY_LCTRL) then
- speedMultiplier = 0.1
- end
-
- local speed = timeStep * speedMultiplier
-
- if input:GetKeyDown(KEY_W) then
- cameraNode:Translate(Vector3(0, 0, 10) * speed)
- end
- if input:GetKeyDown(KEY_S) then
- cameraNode:Translate(Vector3(0, 0, -10) * speed)
- end
- if input:GetKeyDown(KEY_A) then
- cameraNode:Translate(Vector3(-10, 0, 0) * speed)
- end
- if input:GetKeyDown(KEY_D) then
- cameraNode:Translate(Vector3(10, 0, 0) * speed)
- end
- end
- end
- function HandleKeyDown(eventType, eventData)
- local key = eventData:GetInt("Key")
- if key == KEY_ESC then
- if ui:GetFocusElement() == nil then
- engine:Exit()
- else
- console:SetVisible(false)
- end
- end
- if key == KEY_F1 then
- console:Toggle()
- end
-
- if ui:GetFocusElement() == nil then
- if key == KEY_1 then
- local quality = renderer:GetTextureQuality()
- quality = quality + 1
- if quality > 2 then
- quality = 0
- end
- renderer:SetTextureQuality(quality)
- end
-
- if key == KEY_2 then
- local quality = renderer:GetMaterialQuality()
- quality = quality + 1
- if quality > 2 then
- quality = 0
- end
- renderer:SetMaterialQuality(quality)
- end
-
- if key == KEY_3 then
- renderer:SetSpecularLighting(not renderer:GetSpecularLighting())
- end
- if key == KEY_4 then
- renderer:SetDrawShadows(not renderer:GetDrawShadows())
- end
- if key == KEY_5 then
- local size = renderer:GetShadowMapSize()
- size = size * 2
- if size > 2048 then
- size = 512
- end
- renderer:SetShadowMapSize(size)
- end
- if key == KEY_6 then
- renderer:SetShadowQuality(renderer:GetShadowQuality() + 1)
- end
- if key == KEY_7 then
- local occlusion = renderer:GetMaxOccluderTriangles() > 0
- occlusion = not occlusion
- if occlusion then
- renderer:SetMaxOccluderTriangles(5000)
- else
- renderer:SetMaxOccluderTriangles(0)
- end
- end
-
- if key == KEY_8 then
- renderer:SetDynamicInstancing(not renderer:GetDynamicInstancing())
- end
- if key == KEY_SPACE then
- drawDebug = drawDebug + 1
- if drawDebug > 2 then
- drawDebug = 0
- end
- end
- if key == KEY_B then
- renderer:GetViewport(0):GetRenderPath():ToggleEnabled("Bloom")
- end
- if key == KEY_F then
- renderer:GetViewport(0):GetRenderPath():ToggleEnabled("EdgeFilter")
- end
- if key == KEY_O then
- camera:SetOrthographic(not camera:IsOrthographic())
- end
- if key == KEY_T then
- debugHud:Toggle(DEBUGHUD_SHOW_PROFILER)
- end
-
-
- if key == KEY_F5 then
- testScene:SaveXML(fileSystem:GetProgramDir() + "Data/Scenes/LuaTestScene.xml")
- end
-
- if key == KEY_F7 then
- testScene:LoadXML(fileSystem:GetProgramDir() + "Data/Scenes/LuaTestScene.xml")
- end
- end
- end
- function HandleMouseMove(eventType, eventData)
- local buttons = eventData:GetInt("Buttons")
- if buttons == MOUSEB_RIGHT then
- local mousedx = eventData:GetInt("DX")
- local mousedy = eventData:GetInt("DY")
- yaw = yaw + (mousedx / 10.0)
- pitch = pitch + (mousedy / 10.0)
- if pitch < -90.0 then
- pitch = -90.0
- end
- if pitch > 90.0 then
- pitch = 90.0
- end
- cameraNode:SetRotation(Quaternion(pitch, yaw, 0))
- end
- end
- function HandleMouseButtonDown(eventType, eventData)
- local button = eventData:GetInt("Button")
- if button == MOUSEB_RIGHT then
- local cursor = ui:GetCursor()
- cursor:SetVisible(false)
- end
-
- -- Test either creating a new physics object or painting a decal (SHIFT down)
- if button == MOUSEB_LEFT and ui:GetElementAt(ui:GetCursorPosition(), true) == nil and ui:GetFocusElement() == nil then
- if not input:GetQualifierDown(QUAL_SHIFT) then
- local eventData = VariantMap()
- eventData:SetVector3("Pos", cameraNode:GetPosition())
- eventData:SetQuaternion("Rot", cameraNode:GetRotation())
- -- If we are the client, send the spawn command as a remote event, else send locally
- if runClient then
- if network:GetServerConnection() ~= nil then
- network:GetServerConnection():SendRemoteEvent("SpawnBox", true, eventData)
- end
- else
- SendEvent("SpawnBox", eventData)
- end
- else
- local pos = ui:GetCursorPosition()
- if ui:GetElementAt(pos, true) == nil and testScene:GetComponent("Octree") ~= nil then
- local cameraRay = camera:GetScreenRay(pos.x / graphics:GetWidth(), pos.y / graphics:GetHeight())
- local result = testScene:GetComponent("Octree"):RaycastSingle(cameraRay, RAY_TRIANGLE, 250.0, DRAWABLE_GEOMETRY)
- if result.drawable ~= nil then
- local rayHitPos = cameraRay.origin + cameraRay.direction * result.distance
- local decal = result.drawable:GetNode():GetComponent("DecalSet")
- if decal == nil then
- decal = result.drawable:GetNode():CreateComponent("DecalSet")
- decal.material = cache:GetResource("Material", "Materials/UrhoDecal.xml")
- -- Increase max. vertices/indices if the target is skinned
- if result.drawable:GetTypeName() == "AnimatedModel" then
- decal.maxVertices = 2048
- decal.maxIndices = 4096
- end
- end
- decal:AddDecal(result.drawable, rayHitPos, cameraNode:GetWorldRotation(), 0.5, 1.0, 1.0, Vector2(0, 0), Vector2(1, 1))
- end
- end
- end
- end
- end
- function HandleSpawnBox(eventType, eventData)
- local position = eventData:GetVector3("Pos")
- local rotation = eventData:GetQuaternion("Rot")
-
- local newNode = testScene:CreateChild("")
- newNode.position = position
- newNode.rotation =rotation
- newNode:SetScale(0.2)
-
- local body = newNode:CreateComponent("RigidBody")
- body.mass = 1.0
- body.friction = 1.0
- body.linearVelocity = rotation * Vector3(0.0, 1.0, 10.0)
- local shape = newNode:CreateComponent("CollisionShape")
- shape:SetBox(Vector3(1, 1, 1))
- local object = newNode:CreateComponent("StaticModel")
- object.model = cache:GetResource("Model", "Models/Box.mdl")
- object.material = cache:GetResource("Material", "Materials/StoneSmall.xml")
- object.castShadows = true
- object.shadowDistance = 150.0
- object.drawDistance = 200.0
- end
- function HandleMouseButtonUp(eventType, eventData)
- if eventData:GetInt("Button") == MOUSEB_RIGHT then
- ui:GetCursor():SetVisible(true)
- end
- end
- function HandlePostRenderUpdate()
- if engine.headless then
- return
- end
-
- -- Draw rendering debug geometry without depth test to see the effect of occlusion
- if drawDebug == 1 then
- renderer:DrawDebugGeometry(true)
- end
- if drawDebug == 2 then
- testScene:GetComponent("PhysicsWorld"):DrawDebugGeometry(true)
- end
-
- local pos = ui.cursorPosition
- if ui:GetElementAt(pos, true) == nil and testScene:GetComponent("Octree") ~= nil then
- local cameraRay = camera:GetScreenRay(pos.x / graphics:GetWidth(), pos.y / graphics:GetHeight())
- local result = testScene:GetComponent("Octree"):RaycastSingle(cameraRay, RAY_TRIANGLE, 250.0, DRAWABLE_GEOMETRY)
- if result.drawable ~= nil then
- local rayHitPos = cameraRay.origin + cameraRay.direction * result.distance
- testScene:GetComponent("DebugRenderer"):AddBoundingBox(BoundingBox(rayHitPos + Vector3(-0.01, -0.01, -0.01), rayHitPos +
- Vector3(0.01, 0.01, 0.01)), Color(1.0, 1.0, 1.0), true)
- end
- end
- end
- function HandleClientConnected(eventType, eventData)
- local connection = eventData:GetPtr("Connection", "Connection")
- connection.scene = testScene -- Begin scene replication to the client
- connection.logStatistics = true
- end
- function HandlePhysicsCollision(eventType, eventData)
- -- Check if either of the nodes has an AnimatedModel component
- local nodeA = eventData:GetPtr("Node", "NodeA")
- local nodeB = eventData:GetPtr("Node", "NodeB")
- if nodeA:HasComponent("AnimatedModel") then
- HandleHit(nodeA)
- elseif nodeB:HasComponent("AnimatedModel") then
- HandleHit(nodeB)
- end
- end
- function HandleHit(node)
- -- Remove the trigger physics shape, and create the ragdoll
- node:RemoveComponent("RigidBody")
- node:RemoveComponent("CollisionShape")
- CreateRagdoll(node:GetComponent("AnimatedModel"))
- end
- function CreateRagdoll(model)
- local root = model:GetNode()
- CreateRagdollBone(root, "Bip01_Pelvis", SHAPE_BOX, Vector3(0.3, 0.2, 0.25), Vector3(0, 0, 0), Quaternion(0, 0, 0))
- CreateRagdollBone(root, "Bip01_Spine1", SHAPE_BOX, Vector3(0.35, 0.2, 0.3), Vector3(0.15, 0, 0), Quaternion(0, 0, 0))
- CreateRagdollBone(root, "Bip01_L_Thigh", SHAPE_CAPSULE, Vector3(0.175, 0.45, 0.175), Vector3(0.25, 0, 0), Quaternion(0, 0, 90))
- CreateRagdollBone(root, "Bip01_R_Thigh", SHAPE_CAPSULE, Vector3(0.175, 0.45, 0.175), Vector3(0.25, 0, 0), Quaternion(0, 0, 90))
- CreateRagdollBone(root, "Bip01_L_Calf", SHAPE_CAPSULE, Vector3(0.15, 0.55, 0.15), Vector3(0.25, 0, 0), Quaternion(0, 0, 90))
- CreateRagdollBone(root, "Bip01_R_Calf", SHAPE_CAPSULE, Vector3(0.15, 0.55, 0.15), Vector3(0.25, 0, 0), Quaternion(0, 0, 90))
- CreateRagdollBone(root, "Bip01_Head", SHAPE_BOX, Vector3(0.2, 0.2, 0.2), Vector3(0.1, 0, 0), Quaternion(0, 0, 0))
- CreateRagdollBone(root, "Bip01_L_UpperArm", SHAPE_CAPSULE, Vector3(0.15, 0.35, 0.15), Vector3(0.1, 0, 0), Quaternion(0, 0, 90))
- CreateRagdollBone(root, "Bip01_R_UpperArm", SHAPE_CAPSULE, Vector3(0.15, 0.35, 0.15), Vector3(0.1, 0, 0), Quaternion(0, 0, 90))
- CreateRagdollBone(root, "Bip01_L_Forearm", SHAPE_CAPSULE, Vector3(0.125, 0.4, 0.125), Vector3(0.2, 0, 0), Quaternion(0, 0, 90))
- CreateRagdollBone(root, "Bip01_R_Forearm", SHAPE_CAPSULE, Vector3(0.125, 0.4, 0.125), Vector3(0.2, 0, 0), Quaternion(0, 0, 90))
-
- CreateRagdollConstraint(root, "Bip01_L_Thigh", "Bip01_Pelvis", CONSTRAINT_CONETWIST, Vector3(0, 0, -1), Vector3(0, 0, 1), Vector2(45, 45), Vector2(0, 0), true)
- CreateRagdollConstraint(root, "Bip01_R_Thigh", "Bip01_Pelvis", CONSTRAINT_CONETWIST, Vector3(0, 0, -1), Vector3(0, 0, 1), Vector2(45, 45), Vector2(0, 0), true)
- CreateRagdollConstraint(root, "Bip01_L_Calf", "Bip01_L_Thigh", CONSTRAINT_HINGE, Vector3(0, 0, -1), Vector3(0, 0, -1), Vector2(90, 0), Vector2(0, 0), true)
- CreateRagdollConstraint(root, "Bip01_R_Calf", "Bip01_R_Thigh", CONSTRAINT_HINGE, Vector3(0, 0, -1), Vector3(0, 0, -1), Vector2(90, 0), Vector2(0, 0), true)
- CreateRagdollConstraint(root, "Bip01_Spine1", "Bip01_Pelvis", CONSTRAINT_HINGE, Vector3(0, 0, 1), Vector3(0, 0, 1), Vector2(45, 0), Vector2(-10, 0), true)
- CreateRagdollConstraint(root, "Bip01_Head", "Bip01_Spine1", CONSTRAINT_CONETWIST, Vector3(1, 0, 0), Vector3(1, 0, 0), Vector2(0, 30), Vector2(0, 0), true)
- CreateRagdollConstraint(root, "Bip01_L_UpperArm", "Bip01_Spine1", CONSTRAINT_CONETWIST, Vector3(0, -1, 0), Vector3(0, 1, 0), Vector2(45, 45), Vector2(0, 0), false)
- CreateRagdollConstraint(root, "Bip01_R_UpperArm", "Bip01_Spine1", CONSTRAINT_CONETWIST, Vector3(0, -1, 0), Vector3(0, 1, 0), Vector2(45, 45), Vector2(0, 0), false)
- CreateRagdollConstraint(root, "Bip01_L_Forearm", "Bip01_L_UpperArm", CONSTRAINT_HINGE, Vector3(0, 0, -1), Vector3(0, 0, -1), Vector2(90, 0), Vector2(0, 0), true)
- CreateRagdollConstraint(root, "Bip01_R_Forearm", "Bip01_R_UpperArm", CONSTRAINT_HINGE, Vector3(0, 0, -1), Vector3(0, 0, -1), Vector2(90, 0), Vector2(0, 0), true)
- -- Disable animation from all bones (both physical and non-physical) to not interfere
- local skel = model:GetSkeleton()
- for i = 1, skel:GetNumBones() do
- skel:GetBone(i-1).animated = false
- end
- end
- function CreateRagdollBone(root, boneName, type, size, position, rotation)
- local boneNode = root:GetChild(boneName, true)
- if boneNode == nil or boneNode:HasComponent("RigidBody") then
- return
- end
- -- In networked operation both client and server detect collisions separately, and create ragdolls on their own
- -- (bones are not synced over network.) To prevent replicated component ID range clashes when the client creates
- -- any components, it is important that the LOCAL creation mode is specified.
- local body = boneNode:CreateComponent("RigidBody", LOCAL)
- body.mass = 1.0
- body.linearDamping = 0.05
- body.angularDamping = 0.85
- body.linearRestThreshold = 1.5
- body.angularRestThreshold = 2.5
- local shape = boneNode:CreateComponent("CollisionShape", LOCAL)
- shape.shapeType = type
- shape.size = size
- shape.position = position
- shape.rotation = rotation
- end
- function CreateRagdollConstraint(root, boneName, parentName, type, axis, parentAxis, highLimit, lowLimit, disableCollision)
- local boneNode = root:GetChild(boneName, true)
- local parentNode = root:GetChild(parentName, true)
- if boneNode == nil or parentNode == nil or boneNode:HasComponent("Constraint") then
- return
- end
- local constraint = boneNode:CreateComponent("Constraint", LOCAL)
- constraint.constraintType = type
- constraint.disableCollision = disableCollision
- -- The connected body must be specified before setting the world position
- constraint.otherBody = parentNode:GetComponent("RigidBody")
- constraint.worldPosition = boneNode.worldPosition
- constraint:SetAxis(axis)
- constraint:SetOtherAxis(parentAxis)
- constraint.highLimit = highLimit
- constraint.lowLimit = lowLimit
- end
|