13_Ragdolls.cs 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498
  1. //
  2. // Copyright (c) 2008-2015 the Urho3D project.
  3. // Copyright (c) 2015 Xamarin Inc
  4. // Copyright (c) 2016 THUNDERBEAST GAMES LLC
  5. //
  6. // Permission is hereby granted, free of charge, to any person obtaining a copy
  7. // of this software and associated documentation files (the "Software"), to deal
  8. // in the Software without restriction, including without limitation the rights
  9. // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  10. // copies of the Software, and to permit persons to whom the Software is
  11. // furnished to do so, subject to the following conditions:
  12. //
  13. // The above copyright notice and this permission notice shall be included in
  14. // all copies or substantial portions of the Software.
  15. //
  16. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  17. // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  18. // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  19. // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  20. // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  21. // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  22. // THE SOFTWARE.
  23. //
  24. using System.Collections.Generic;
  25. using AtomicEngine;
  26. namespace FeatureExamples
  27. {
  28. public class RagdollSample : Sample
  29. {
  30. Scene scene; // perspective (3d) scene, you know, where the ragdolls are.
  31. Camera camera; // the regular camera
  32. bool drawDebug; // bool to turn on/off debug hud.
  33. // the 2nd scene for the hud "overlay"
  34. Scene hudScene; // the hud scene
  35. Camera hudCamera; // ortho cam for the (pixel perfect) hud
  36. Vector <Sprite2D> filler; // for bargraph display
  37. // more fun features...
  38. List <float> bulletMass; // how heavy the bullet is
  39. List <float> bulletSpeed; // how fast the bullet is
  40. List <float> bulletSize; // how big the bullet is
  41. int massCount, speedCount, sizeCount; // counters
  42. float bulletArc; // shooting inclination
  43. public RagdollSample() : base() { }
  44. public override void Start()
  45. {
  46. massCount = 2;
  47. speedCount = 2;
  48. sizeCount = 2;
  49. bulletMass = new List<float>();
  50. bulletSpeed = new List<float>();
  51. bulletSize = new List<float>();
  52. filler = new Vector <Sprite2D>();
  53. bulletMass.Add(1.0f);
  54. bulletMass.Add(10.0f);
  55. bulletMass.Add(50.0f);
  56. bulletMass.Add(100.0f);
  57. bulletMass.Add(300.0f);
  58. bulletMass.Add(666.0f);
  59. bulletMass.Add(1000.0f);
  60. bulletSpeed.Add(10.0f);
  61. bulletSpeed.Add(22.0f);
  62. bulletSpeed.Add(41.0f);
  63. bulletSpeed.Add(72.0f);
  64. bulletSpeed.Add(116.0f);
  65. bulletSpeed.Add(200.0f);
  66. bulletSpeed.Add(450.0f);
  67. bulletSize.Add(0.25f);
  68. bulletSize.Add(0.5f);
  69. bulletSize.Add(1.25f);
  70. bulletSize.Add(3.25f);
  71. bulletSize.Add(5.25f);
  72. bulletSize.Add(7.25f);
  73. bulletSize.Add(11.25f);
  74. bulletSize.Add(16.25f);
  75. bulletArc = 0.25f;
  76. base.Start();
  77. CreateScene();
  78. CreateHUD(); // add an overlay HUD that tells you settings
  79. SimpleCreateInstructionsWithWasd(
  80. "LMB to spawn physics objects\n" +
  81. "U=Mass, I=Speed, O=Size, R=Restart\n" +
  82. "Space to toggle physics debug geometry\n");
  83. SetupViewport();
  84. SubscribeToEvents();
  85. RestartJacks ();
  86. UpdateSpeedHud (speedCount);
  87. UpdateMassHud (massCount);
  88. UpdateSizeHud (sizeCount);
  89. GetSubsystem<Input>().SetMouseVisible (false);
  90. }
  91. void SubscribeToEvents()
  92. {
  93. SubscribeToEvent<PostRenderUpdateEvent>(e =>
  94. {
  95. // If draw debug mode is enabled, draw viewport debug geometry, which will show eg. drawable bounding boxes and skeleton
  96. // bones. Note that debug geometry has to be separately requested each frame. Disable depth test so that we can see the
  97. // bones properly
  98. if (drawDebug)
  99. GetSubsystem<Renderer>().DrawDebugGeometry(false);
  100. });
  101. }
  102. protected override void Update(float timeStep)
  103. {
  104. base.Update(timeStep);
  105. SimpleMoveCamera3D(timeStep);
  106. var input = GetSubsystem<Input>();
  107. if (input.GetMouseButtonPress(Constants.MOUSEB_LEFT))
  108. SpawnObject();
  109. /* TODO: Scene.SaveXML/Scene.LoadXML
  110. if (input.GetKeyPress(Constants.KEY_F5))
  111. scene.SaveXml(fileSystem.UserDocumentsDir + "/Scenes/Physics.xml");
  112. if (input.GetKeyPress(Constants.KEY_F7))
  113. scene.LoadXml(fileSystem.UserDocumentsDir + "/Scenes/Physics.xml");
  114. */
  115. if (input.GetKeyPress (Constants.KEY_U)) {
  116. massCount++;
  117. if ( massCount > 5 )
  118. massCount = 0;
  119. UpdateMassHud (massCount);
  120. }
  121. if (input.GetKeyPress (Constants.KEY_I)) {
  122. speedCount++;
  123. if ( speedCount> 5 )
  124. speedCount = 0;
  125. UpdateSpeedHud (speedCount);
  126. }
  127. if (input.GetKeyPress (Constants.KEY_O)) {
  128. sizeCount++;
  129. if ( sizeCount > 5 )
  130. sizeCount = 0;
  131. UpdateSizeHud (sizeCount);
  132. }
  133. if (input.GetKeyPress (Constants.KEY_P)) {
  134. if ( bulletArc == 0.0 )
  135. bulletArc = 0.25f;
  136. else if ( bulletArc > 0.0 )
  137. bulletArc = 0.0f;
  138. }
  139. if (input.GetKeyPress (Constants.KEY_R)) {
  140. RestartJacks ();
  141. }
  142. if (input.GetKeyPress(Constants.KEY_SPACE))
  143. drawDebug = !drawDebug;
  144. UpdateFps ();
  145. CleanUpSome ();
  146. }
  147. void UpdateFps ()
  148. {
  149. var eng = GetSubsystem<Engine>();
  150. string mystr = "FPS: " + eng.GetFps ().ToString ();
  151. mystr += "\nUse WASD keys and mouse/touch to move\n"
  152. + "LMB to spawn physics objects\n"
  153. + "U=Mass, I=Speed, O=Size, R=Restart\n"
  154. + "Space to toggle physics debug geometry";
  155. SetInstructions ( mystr );
  156. }
  157. void SetupViewport()
  158. {
  159. var renderer = GetSubsystem<Renderer>();
  160. var cache = GetSubsystem<ResourceCache>();
  161. renderer.SetNumViewports(2); // use 2 viewports, 1 for 3d and 1 for the 2d hud
  162. var viewport2_ = new Viewport(hudScene, hudCamera ); // hud orthographic viewport, scene and camera
  163. var overlayRenderPath = new RenderPath();
  164. overlayRenderPath.Load(cache.GetResource<XMLFile>("PostProcess/FrontPath.xml")); //special renderpath that does not clear
  165. viewport2_.SetRenderPath(overlayRenderPath); // apply to hud viewport, so the background is transparent
  166. renderer.SetViewport(0, new Viewport(scene, camera)); // perspective viewport, scene and camera
  167. renderer.SetViewport(1, viewport2_); // and add in the HUD viewport
  168. }
  169. void CreateScene()
  170. {
  171. var cache = GetSubsystem<ResourceCache>();
  172. scene = new Scene();
  173. // Create octree, use default volume (-1000, -1000, -1000) to (1000, 1000, 1000)
  174. // Create a physics simulation world with default parameters, which will update at 60fps. Like the Octree must
  175. // exist before creating drawable components, the PhysicsWorld must exist before creating physics components.
  176. // Finally, create a DebugRenderer component so that we can draw physics debug geometry
  177. scene.CreateComponent<Octree>();
  178. scene.CreateComponent<PhysicsWorld>();
  179. scene.CreateComponent<DebugRenderer>();
  180. // Create a Zone component for ambient lighting & fog control
  181. Node zoneNode = scene.CreateChild("Zone");
  182. Zone zone = zoneNode.CreateComponent<Zone>();
  183. zone.SetBoundingBox(new BoundingBox(-1000.0f, 1000.0f));
  184. zone.AmbientColor = (new Color(0.15f, 0.15f, 0.15f));
  185. zone.FogColor = new Color(0.5f, 0.5f, 0.7f);
  186. zone.FogStart = 100.0f;
  187. zone.FogEnd = 300.0f;
  188. // Create a directional light to the world. Enable cascaded shadows on it
  189. Node lightNode = scene.CreateChild("DirectionalLight");
  190. lightNode.SetDirection(new Vector3(0.6f, -1.0f, 0.8f));
  191. Light light = lightNode.CreateComponent<Light>();
  192. light.LightType = LightType.LIGHT_DIRECTIONAL;
  193. light.CastShadows = true;
  194. light.ShadowBias = new BiasParameters(0.00025f, 0.5f);
  195. // Set cascade splits at 10, 50 and 200 world units, fade shadows out at 80% of maximum shadow distance
  196. light.ShadowCascade = new CascadeParameters(10.0f, 50.0f, 200.0f, 0.0f, 0.8f);
  197. {
  198. // Create a floor object, 500 x 500 world units. Adjust position so that the ground is at zero Y
  199. Node floorNode = scene.CreateChild("Floor");
  200. floorNode.Position = new Vector3(0.0f, -0.5f, 0.0f);
  201. floorNode.Scale = new Vector3(500.0f, 1.0f, 500.0f);
  202. StaticModel floorObject = floorNode.CreateComponent<StaticModel>();
  203. floorObject.Model = cache.Get<Model>("Models/Box.mdl");
  204. floorObject.SetMaterial(cache.Get<Material>("Materials/StoneTiled.xml"));
  205. // Make the floor physical by adding RigidBody and CollisionShape components
  206. RigidBody body = floorNode.CreateComponent<RigidBody>();
  207. // We will be spawning spherical objects in this sample. The ground also needs non-zero rolling friction so that
  208. // the spheres will eventually come to rest
  209. body.RollingFriction = 0.15f;
  210. CollisionShape shape = floorNode.CreateComponent<CollisionShape>();
  211. // Set a box shape of size 1 x 1 x 1 for collision. The shape will be scaled with the scene node scale, so the
  212. // rendering and physics representation sizes should match (the box model is also 1 x 1 x 1.)
  213. shape.SetBox(Vector3.One, Vector3.Zero, Quaternion.Identity);
  214. }
  215. // Create the camera. Limit far clip distance to match the fog
  216. CameraNode = new Node();
  217. CameraNode.SetName("Camera");
  218. camera = CameraNode.CreateComponent<Camera>();
  219. camera.FarClip = 300.0f;
  220. // Set an initial position for the camera scene node above the plane
  221. CameraNode.Position = new Vector3(0.0f, 3.0f, -20.0f);
  222. }
  223. void RestartJacks()
  224. {
  225. var ll = new Vector <Node>(); //get rid of some old objects
  226. scene.GetChildrenWithName ( ll, "Sphere", true);
  227. for ( int ii=0; ii<ll.Size; ii++ ) {
  228. ll[ii].Remove ();
  229. }
  230. var nn = new Vector <Node>();
  231. scene.GetChildrenWithName ( nn, "Stuffing", true);
  232. for ( int ii=0; ii<nn.Size; ii++ ) {
  233. nn[ii].Remove ();
  234. }
  235. var mm = new Vector <Node>();
  236. scene.GetChildrenWithName ( mm, "Jack", true);
  237. for ( int ii=0; ii<mm.Size; ii++ ) {
  238. mm[ii].Remove ();
  239. }
  240. // Create animated models, you dont know ... jack
  241. var cache = GetSubsystem<ResourceCache>();
  242. for (int z = -1; z <= 1; ++z)
  243. {
  244. for (int x = -4; x <= 4; ++x)
  245. {
  246. Node modelNode = scene.CreateChild("Jack");
  247. modelNode.Position = new Vector3(x * 5.0f, 0.0f, z * 5.0f);
  248. modelNode.Rotation = new Quaternion(0.0f, 180.0f, 0.0f);
  249. AnimatedModel modelObject = modelNode.CreateComponent<AnimatedModel>();
  250. modelObject.Model = cache.Get<Model>("Models/Jack.mdl");
  251. modelObject.SetMaterial(cache.Get<Material>("Materials/Jack.xml"));
  252. modelObject.CastShadows = true;
  253. // Set the model to also update when invisible to avoid staying invisible when the model should come into
  254. // view, but does not as the bounding box is not updated
  255. modelObject.UpdateInvisible = true;
  256. // Create a rigid body and a collision shape. These will act as a trigger for transforming the
  257. // model into a ragdoll when hit by a moving object
  258. RigidBody body = modelNode.CreateComponent<RigidBody>();
  259. // The Trigger mode makes the rigid body only detect collisions, but impart no forces on the
  260. // colliding objects
  261. body.Trigger = true;
  262. CollisionShape shape = modelNode.CreateComponent<CollisionShape>();
  263. // Create the capsule shape with an offset so that it is correctly aligned with the model, which
  264. // has its origin at the feet
  265. shape.SetCapsule(0.7f, 2.0f, new Vector3(0.0f, 1.0f, 0.0f), Quaternion.Identity);
  266. // Create a custom component that reacts to collisions and creates the ragdoll
  267. modelNode.AddComponent(new Ragdoll());
  268. }
  269. }
  270. }
  271. void CreateHUD()
  272. {
  273. float hscal = 0.4f;
  274. //
  275. // create a 2nd viewport and scene for a hud with sprites.
  276. //
  277. hudScene = new Scene();
  278. hudScene.CreateComponent<Octree>();
  279. // Create camera node
  280. var hudCam = hudScene.CreateChild("HudCamera");
  281. // Set camera's position
  282. hudCam.SetPosition(new Vector3(0.0f, 0.0f, -10.0f));
  283. hudCamera = hudCam.CreateComponent<Camera>();
  284. hudCamera.SetOrthographic(true);
  285. var graphics = GetSubsystem<Graphics>();
  286. hudCamera.SetOrthoSize ((float)graphics.GetHeight () * PixelSize ); //PIXEL_SIZE
  287. var cache = GetSubsystem<ResourceCache>();
  288. // add a crosshair in the center of the screen
  289. var sprite = cache.GetResource<Sprite2D>("Textures/NinjaSnowWar/Sight.png");
  290. var targetSprite_ = hudScene.CreateChild("targetSprite");
  291. targetSprite_.SetPosition2D(new Vector2(0,0));
  292. targetSprite_.SetScale2D( new Vector2(0.75f, 0.75f));
  293. var staticSprite = targetSprite_.CreateComponent<StaticSprite2D>();
  294. staticSprite.SetSprite(sprite); // Set sprite
  295. staticSprite.SetBlendMode( AtomicEngine.BlendMode.BLEND_ALPHA ); // Set blend mode
  296. staticSprite.SetAlpha(0.3f);
  297. // borrow the spinning coin from the 2DSprite example to show what the possibilities are
  298. float halfWidth = graphics.Width * 0.5f * PixelSize;
  299. float halfHeight = graphics.Height * 0.5f * PixelSize;
  300. // Get animation set
  301. AnimationSet2D animationSet = cache.Get<AnimationSet2D>("Urho2D/GoldIcon.scml");
  302. if (animationSet == null) return;
  303. var spriteNode2 = hudScene.CreateChild("AnimatedSprite2D");
  304. AnimatedSprite2D animatedSprite = spriteNode2.CreateComponent<AnimatedSprite2D>();
  305. animatedSprite.AnimationSet = animationSet; // Set animation
  306. animatedSprite.SetAnimation("idle", LoopMode2D.LM_DEFAULT);
  307. spriteNode2.SetPosition2D(new Vector2(halfWidth - 0.4f, halfHeight - 0.4f));
  308. // (bullet) mass, speed size feature huds
  309. filler.Push ( cache.GetResource<Sprite2D>("Textures/hudfill1.png") );
  310. filler.Push ( cache.GetResource<Sprite2D>("Textures/hudfill2.png") );
  311. filler.Push ( cache.GetResource<Sprite2D>("Textures/hudfill3.png") );
  312. filler.Push ( cache.GetResource<Sprite2D>("Textures/hudfill4.png") );
  313. filler.Push ( cache.GetResource<Sprite2D>("Textures/hudfill5.png") );
  314. filler.Push ( cache.GetResource<Sprite2D>("Textures/hudfill6.png") );
  315. Sprite2D spritem = cache.GetResource<Sprite2D>("Textures/hudmass.png");
  316. Node hudm = hudScene.CreateChild("hudMass");
  317. hudm.SetScale2D(new Vector2(hscal,hscal));
  318. hudm.SetPosition2D( new Vector2( 0f - (halfWidth/3.0f), halfHeight - 0.4f));
  319. StaticSprite2D hudSpritem = hudm.CreateComponent<StaticSprite2D>();
  320. hudSpritem.SetSprite(spritem);
  321. hudSpritem.SetAlpha(0.9f);
  322. hudSpritem.SetBlendMode(AtomicEngine.BlendMode.BLEND_ALPHA);
  323. hudSpritem.SetOrderInLayer(3);
  324. Node hudfm = hudm.CreateChild("hudMassFill");
  325. hudfm.SetScale2D(new Vector2(1f,1f));
  326. hudfm.SetPosition2D( new Vector2( 0f, 0f));
  327. StaticSprite2D hudSpritefm = hudfm.CreateComponent<StaticSprite2D>();
  328. hudSpritefm.SetSprite(filler[0]);
  329. hudSpritefm.SetAlpha(0.9f);
  330. hudSpritefm.SetBlendMode(AtomicEngine.BlendMode.BLEND_ALPHA);
  331. hudSpritefm.SetOrderInLayer(-3);
  332. Sprite2D sprites = cache.GetResource<Sprite2D>("Textures/hudspeed.png");
  333. Node huds = hudScene.CreateChild("hudSpeed");
  334. huds.SetScale2D(new Vector2(hscal,hscal));
  335. huds.SetPosition2D( new Vector2( 0f, halfHeight - 0.4f));
  336. StaticSprite2D hudSprites = huds.CreateComponent<StaticSprite2D>();
  337. hudSprites.SetSprite(sprites);
  338. hudSprites.SetAlpha(0.9f);
  339. hudSprites.SetBlendMode(AtomicEngine.BlendMode.BLEND_ALPHA);
  340. hudSprites.SetOrderInLayer(3);
  341. Node hudsm = huds.CreateChild("hudSpeedFill");
  342. hudsm.SetScale2D(new Vector2(1f,1f));
  343. hudsm.SetPosition2D( new Vector2( 0f, 0f));
  344. StaticSprite2D hudSpritesm = hudsm.CreateComponent<StaticSprite2D>();
  345. hudSpritesm.SetSprite(filler[0]);
  346. hudSpritesm.SetAlpha(0.9f);
  347. hudSpritesm.SetBlendMode(AtomicEngine.BlendMode.BLEND_ALPHA);
  348. hudSpritesm.SetOrderInLayer(-3);
  349. Sprite2D spritez = cache.GetResource<Sprite2D>("Textures/hudsize.png");
  350. Node hudz = hudScene.CreateChild("hudSize");
  351. hudz.SetScale2D(new Vector2(hscal,hscal));
  352. hudz.SetPosition2D( new Vector2( 0f + (halfWidth/3.0f), halfHeight - 0.4f));
  353. StaticSprite2D hudSpritez = hudz.CreateComponent<StaticSprite2D>();
  354. hudSpritez.SetSprite(spritez);
  355. hudSpritez.SetAlpha(0.9f);
  356. hudSpritez.SetBlendMode(AtomicEngine.BlendMode.BLEND_ALPHA);
  357. hudSpritez.SetOrderInLayer(3);
  358. Node hudzm = hudz.CreateChild("hudSizeFill");
  359. hudzm.SetScale2D(new Vector2(1f,1f));
  360. hudzm.SetPosition2D( new Vector2( 0f, 0f));
  361. StaticSprite2D hudSpritezm = hudzm.CreateComponent<StaticSprite2D>();
  362. hudSpritezm.SetSprite(filler[0]);
  363. hudSpritezm.SetAlpha(0.9f);
  364. hudSpritezm.SetBlendMode(AtomicEngine.BlendMode.BLEND_ALPHA);
  365. hudSpritezm.SetOrderInLayer(-3);
  366. }
  367. void UpdateMassHud ( int value )
  368. {
  369. Node xNode = hudScene.GetChild("hudMass", true);
  370. if (xNode != null) {
  371. Node fillx = xNode.GetChild("hudMassFill");
  372. if (fillx != null) {
  373. StaticSprite2D hudSprite = fillx.GetComponent<StaticSprite2D>();
  374. hudSprite.SetSprite(filler[value]);
  375. }
  376. }
  377. }
  378. void UpdateSpeedHud ( int value )
  379. {
  380. Node xNode = hudScene.GetChild("hudSpeed", true);
  381. if (xNode != null) {
  382. Node fillx = xNode.GetChild("hudSpeedFill");
  383. if (fillx != null) {
  384. StaticSprite2D hudSprite = fillx.GetComponent<StaticSprite2D>();
  385. hudSprite.SetSprite(filler[value]);
  386. }
  387. }
  388. }
  389. void UpdateSizeHud ( int value )
  390. {
  391. Node xNode = hudScene.GetChild("hudSize", true);
  392. if (xNode != null) {
  393. Node fillx = xNode.GetChild("hudSizeFill");
  394. if (fillx != null) {
  395. StaticSprite2D hudSprite = fillx.GetComponent<StaticSprite2D>();
  396. hudSprite.SetSprite(filler[value]);
  397. }
  398. }
  399. }
  400. void SpawnObject()
  401. {
  402. var cache = GetSubsystem<ResourceCache>();
  403. Node boxNode = scene.CreateChild("Sphere");
  404. boxNode.Position = CameraNode.Position;
  405. boxNode.Rotation = CameraNode.Rotation;
  406. boxNode.SetScale(bulletSize[sizeCount]);
  407. StaticModel boxObject = boxNode.CreateComponent<StaticModel>();
  408. boxObject.Model = cache.Get<Model>("Models/Sphere.mdl");
  409. boxObject.SetMaterial(cache.Get<Material>("Materials/StoneSmall.xml"));
  410. boxObject.CastShadows = true;
  411. RigidBody body = boxNode.CreateComponent<RigidBody>();
  412. body.Mass = bulletMass[massCount];
  413. body.RollingFriction = 0.15f;
  414. CollisionShape shape = boxNode.CreateComponent<CollisionShape>();
  415. shape.SetSphere(1.0f, Vector3.Zero, Quaternion.Identity);
  416. float objectVelocity = bulletSpeed[speedCount];
  417. // Set initial velocity for the RigidBody based on camera forward vector. Add also a slight up component
  418. // to overcome gravity better
  419. body.SetLinearVelocity(CameraNode.Rotation * new Vector3(0.0f, bulletArc, 1.0f) * objectVelocity);
  420. }
  421. void CleanUpSome() // destroy the bullets when they get far enough away
  422. {
  423. Node cam = CameraNode; // note - the camera isnt in the scene
  424. if ( cam == null )
  425. return;
  426. var mm = new Vector <Node>();
  427. scene.GetChildrenWithName ( mm, "Sphere", true);
  428. for ( int ii=0; ii<mm.Size; ii++ ) {
  429. float dist = ( mm[ii].GetWorldPosition() - cam.GetWorldPosition() ).Length;
  430. if (dist > 270.0f) {
  431. mm[ii].Remove ();
  432. }
  433. }
  434. }
  435. }
  436. }