1-- Urho2D physics sample. 2-- This sample demonstrates: 3-- - Creating both static and moving 2D physics objects to a scene 4-- - Displaying physics debug geometry 5 6require "LuaScripts/Utilities/Sample" 7 8function Start() 9 -- Execute the common startup for samples 10 SampleStart() 11 12 -- Create the scene content 13 CreateScene() 14 15 -- Create the UI content 16 CreateInstructions() 17 18 -- Setup the viewport for displaying the scene 19 SetupViewport() 20 21 -- Set the mouse mode to use in the sample 22 SampleInitMouseMode(MM_FREE) 23 24 -- Hook up to the frame update events 25 SubscribeToEvents() 26end 27 28function CreateScene() 29 scene_ = Scene() 30 31 -- Create the Octree component to the scene. This is required before adding any drawable components, or else nothing will 32 -- show up. The default octree volume will be from (-1000, -1000, -1000) to (1000, 1000, 1000) in world coordinates it 33 -- is also legal to place objects outside the volume but their visibility can then not be checked in a hierarchically 34 -- optimizing manner 35 scene_:CreateComponent("Octree") 36 scene_:CreateComponent("DebugRenderer") 37 38 -- Create a scene node for the camera, which we will move around 39 -- The camera will use default settings (1000 far clip distance, 45 degrees FOV, set aspect ratio automatically) 40 cameraNode = scene_:CreateChild("Camera") 41 -- Set an initial position for the camera scene node above the plane 42 cameraNode.position = Vector3(0.0, 0.0, -10.0) 43 local camera = cameraNode:CreateComponent("Camera") 44 camera.orthographic = true 45 camera.orthoSize = graphics.height * PIXEL_SIZE 46 camera.zoom = 1.2 * Min(graphics.width / 1280, graphics.height / 800) -- Set zoom according to user's resolution to ensure full visibility (initial zoom (1.2) is set for full visibility at 1280x800 resolution) 47 48 -- Create 2D physics world component 49 scene_:CreateComponent("PhysicsWorld2D") 50 51 local boxSprite = cache:GetResource("Sprite2D", "Urho2D/Box.png") 52 local ballSprite = cache:GetResource("Sprite2D", "Urho2D/Ball.png") 53 54 -- Create ground. 55 local groundNode = scene_:CreateChild("Ground") 56 groundNode.position = Vector3(0.0, -3.0, 0.0) 57 groundNode.scale = Vector3(200.0, 1.0, 0.0) 58 59 -- Create 2D rigid body for gound 60 local groundBody = groundNode:CreateComponent("RigidBody2D") 61 62 local groundSprite = groundNode:CreateComponent("StaticSprite2D") 63 groundSprite.sprite = boxSprite 64 65 -- Create box collider for ground 66 local groundShape = groundNode:CreateComponent("CollisionBox2D") 67 -- Set box size 68 groundShape.size = Vector2(0.32, 0.32) 69 -- Set friction 70 groundShape.friction = 0.5 71 72 local NUM_OBJECTS = 100 73 for i = 1, NUM_OBJECTS do 74 local node = scene_:CreateChild("RigidBody") 75 node.position = Vector3(Random(-0.1, 0.1), 5.0 + i * 0.4, 0.0) 76 77 -- Create rigid body 78 local body = node:CreateComponent("RigidBody2D") 79 body.bodyType = BT_DYNAMIC 80 81 local staticSprite = node:CreateComponent("StaticSprite2D") 82 local shape = nil 83 if i % 2 == 0 then 84 staticSprite.sprite = boxSprite 85 -- Create box 86 shape = node:CreateComponent("CollisionBox2D") 87 -- Set size 88 shape.size = Vector2(0.32, 0.32) 89 else 90 staticSprite.sprite = ballSprite 91 -- Create circle 92 shape = node:CreateComponent("CollisionCircle2D") 93 -- Set radius 94 shape.radius = 0.16 95 end 96 -- Set density 97 shape.density = 1.0 98 -- Set friction 99 shape.friction = 0.5 100 -- Set restitution 101 shape.restitution = 0.1 102 end 103end 104 105function CreateInstructions() 106 -- Construct new Text object, set string to display and font to use 107 local instructionText = ui.root:CreateChild("Text") 108 instructionText:SetText("Use WASD keys and mouse to move, Use PageUp PageDown to zoom.") 109 instructionText:SetFont(cache:GetResource("Font", "Fonts/Anonymous Pro.ttf"), 15) 110 111 -- Position the text relative to the screen center 112 instructionText.horizontalAlignment = HA_CENTER 113 instructionText.verticalAlignment = VA_CENTER 114 instructionText:SetPosition(0, ui.root.height / 4) 115end 116 117function SetupViewport() 118 -- Set up a viewport to the Renderer subsystem so that the 3D scene can be seen. We need to define the scene and the camera 119 -- at minimum. Additionally we could configure the viewport screen size and the rendering path (eg. forward / deferred) to 120 -- use, but now we just use full screen and default render path configured in the engine command line options 121 local viewport = Viewport:new(scene_, cameraNode:GetComponent("Camera")) 122 renderer:SetViewport(0, viewport) 123end 124 125function MoveCamera(timeStep) 126 -- Do not move if the UI has a focused element (the console) 127 if ui.focusElement ~= nil then 128 return 129 end 130 131 -- Movement speed as world units per second 132 local MOVE_SPEED = 4.0 133 134 -- Read WASD keys and move the camera scene node to the corresponding direction if they are pressed 135 if input:GetKeyDown(KEY_W) then 136 cameraNode:Translate(Vector3(0.0, 1.0, 0.0) * MOVE_SPEED * timeStep) 137 end 138 if input:GetKeyDown(KEY_S) then 139 cameraNode:Translate(Vector3(0.0, -1.0, 0.0) * MOVE_SPEED * timeStep) 140 end 141 if input:GetKeyDown(KEY_A) then 142 cameraNode:Translate(Vector3(-1.0, 0.0, 0.0) * MOVE_SPEED * timeStep) 143 end 144 if input:GetKeyDown(KEY_D) then 145 cameraNode:Translate(Vector3(1.0, 0.0, 0.0) * MOVE_SPEED * timeStep) 146 end 147 148 if input:GetKeyDown(KEY_PAGEUP) then 149 local camera = cameraNode:GetComponent("Camera") 150 camera.zoom = camera.zoom * 1.01 151 end 152 153 if input:GetKeyDown(KEY_PAGEDOWN) then 154 local camera = cameraNode:GetComponent("Camera") 155 camera.zoom = camera.zoom * 0.99 156 end 157end 158 159function SubscribeToEvents() 160 -- Subscribe HandleUpdate() function for processing update events 161 SubscribeToEvent("Update", "HandleUpdate") 162 163 -- Unsubscribe the SceneUpdate event from base class to prevent camera pitch and yaw in 2D sample 164 UnsubscribeFromEvent("SceneUpdate") 165end 166 167function HandleUpdate(eventType, eventData) 168 -- Take the frame time step, which is stored as a float 169 local timeStep = eventData["TimeStep"]:GetFloat() 170 171 -- Move the camera, scale movement with time step 172 MoveCamera(timeStep) 173end 174 175-- Create XML patch instructions for screen joystick layout specific to this sample app 176function GetScreenJoystickPatchString() 177 return 178 "<patch>" .. 179 " <remove sel=\"/element/element[./attribute[@name='Name' and @value='Button0']]/attribute[@name='Is Visible']\" />" .. 180 " <replace sel=\"/element/element[./attribute[@name='Name' and @value='Button0']]/element[./attribute[@name='Name' and @value='Label']]/attribute[@name='Text']/@value\">Zoom In</replace>" .. 181 " <add sel=\"/element/element[./attribute[@name='Name' and @value='Button0']]\">" .. 182 " <element type=\"Text\">" .. 183 " <attribute name=\"Name\" value=\"KeyBinding\" />" .. 184 " <attribute name=\"Text\" value=\"PAGEUP\" />" .. 185 " </element>" .. 186 " </add>" .. 187 " <remove sel=\"/element/element[./attribute[@name='Name' and @value='Button1']]/attribute[@name='Is Visible']\" />" .. 188 " <replace sel=\"/element/element[./attribute[@name='Name' and @value='Button1']]/element[./attribute[@name='Name' and @value='Label']]/attribute[@name='Text']/@value\">Zoom Out</replace>" .. 189 " <add sel=\"/element/element[./attribute[@name='Name' and @value='Button1']]\">" .. 190 " <element type=\"Text\">" .. 191 " <attribute name=\"Name\" value=\"KeyBinding\" />" .. 192 " <attribute name=\"Text\" value=\"PAGEDOWN\" />" .. 193 " </element>" .. 194 " </add>" .. 195 "</patch>" 196end 197