AtomicMain.cs 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182
  1. using System.Collections.Generic;
  2. using AtomicEngine;
  3. internal static class Cache
  4. {
  5. private static readonly ResourceCache _cache = AtomicNET.GetSubsystem<ResourceCache>();
  6. public static T Get<T>(string path) where T : Resource
  7. {
  8. return _cache.Get<T>(path);
  9. }
  10. }
  11. public class AtomicMain : AppDelegate
  12. {
  13. private static Scene _scene;
  14. private static Terrain _terrain;
  15. private Viewport _viewport;
  16. private Camera _camera;
  17. private Vehicle _vehicle;
  18. private Clouds _clouds;
  19. public override void Start()
  20. {
  21. // We setup our scene, main camera and viewport
  22. _viewport = GetSubsystem<Renderer>().GetViewport(0);
  23. _scene = new Scene();
  24. _scene.CreateComponent<Octree>().SetSize(new BoundingBox(1,100), 3);
  25. _viewport.Scene = _scene;
  26. _camera = _scene.CreateChild("Camera").CreateComponent<Camera>();
  27. _camera.Node.Position = new Vector3(50, 10, -1);
  28. _camera.Orthographic = true;
  29. _camera.OrthoSize = 26;
  30. _viewport.Camera = _camera;
  31. // We create a sound source for the music and the music
  32. SoundSource musicSource = _scene.CreateComponent<SoundSource>();
  33. Sound music = Cache.Get<Sound>("music/Happy_Bee.ogg");
  34. music.SetLooped(true);
  35. musicSource.Play(music);
  36. musicSource.SetSoundType("Music");
  37. // We don't need a sound listener for the above, but we add one for the sounds and adjust the music gain
  38. Audio audioSystem = GetSubsystem<Audio>();
  39. audioSystem.SetListener(_camera.Node.CreateComponent<SoundListener>());
  40. audioSystem.SetMasterGain("Music", 0.3f);
  41. // We create a background node which is a child of the camera so it won't move relative to it
  42. Node bg = _camera.Node.CreateChild("Background");
  43. StaticSprite2D bgspr = bg.CreateComponent<StaticSprite2D>();
  44. bgspr.SetSprite(Cache.Get<Sprite2D>("scenarios/grasslands/bg.png"));
  45. bg.SetPosition(new Vector3(0,0,100));
  46. bg.SetScale2D(Vector2.One*5.2f);
  47. // We add a physics world so we can simulate physics, and enable CCD
  48. PhysicsWorld2D pw = _scene.CreateComponent<PhysicsWorld2D>();
  49. pw.SetContinuousPhysics(true);
  50. // We create a terrain, vehicle and cloud system
  51. _terrain = new Terrain(_scene);
  52. _vehicle = CreateVehicle(new Vector2(50,10));
  53. _clouds = new Clouds(50, 5, 40, 16, 40);
  54. // We subscribe to the PostUpdateEvent
  55. SubscribeToEvent<PostUpdateEvent>(PostUpdate);
  56. // If we're building a debug release, we draw debug data
  57. #if DEBUG
  58. DebugRenderer dbr = _scene.CreateComponent<DebugRenderer>();
  59. pw.SetDrawCenterOfMass(true); pw.SetDrawJoint(true); pw.SetDrawPair(true); pw.SetDrawShape(true);
  60. SubscribeToEvent<PostRenderUpdateEvent>(e => {_scene.GetComponent<PhysicsWorld2D>().DrawDebugGeometry(dbr,false);});
  61. #endif
  62. }
  63. // This function is called after all nodes positions were updated for the current frame (UpdateEvent)
  64. void PostUpdate(PostUpdateEvent eventData)
  65. {
  66. // We lerp the camera so it follows the vehicle smoothly
  67. _camera.Node.SetPosition(
  68. new Vector3(LerpVector2(_camera.Node.Position2D, _vehicle.Node.Position2D+Vector2.UnitX*10, 5*eventData.TimeStep)) +
  69. Vector3.Back*10);
  70. // We tick the cloud system
  71. _clouds.Tick(eventData.TimeStep, _vehicle.Node.Position.X);
  72. }
  73. #region Static Utils
  74. // Convenience function to create node with sprite and rigidbody (optional)
  75. static Vehicle CreateVehicle(Vector2 position)
  76. {
  77. Node vehicleNode = CreateSpriteNode(Cache.Get<Sprite2D>("characters/truck/vehicle.png"), 1.4f);
  78. // We create the vehicle and the chassis (CreateChassis returns the Vehicle for convenience)
  79. Vehicle vehicle = vehicleNode.CreateComponent<Vehicle>().CreateChassis(
  80. new Vector2(-0.1f, 0.4f), 1.4f, 5,
  81. new Vector3(-2f, -1, 1), Cache.Get<ParticleEffect2D>("particles/smoke.pex"),
  82. Cache.Get<Sound>("sounds/engine_sound_crop.wav"), Cache.Get<Sound>("sounds/tires_squal_loop.wav"),
  83. new [] {Cache.Get<Sound>("sounds/susp_1.wav"), Cache.Get<Sound>("sounds/susp_3.wav")},
  84. 300, 50, 5, 500);
  85. // We create the wheels
  86. Sprite2D wspr = Cache.Get<Sprite2D>("characters/truck/wheel.png");
  87. Node w1 = vehicle.CreateWheel(
  88. wspr, new Vector2(1.5f,-1.5f), 1.25f, 4, 0.4f, Cache.Get<ParticleEffect2D>("particles/dust.pex"), 2.6f);
  89. Node w2 = vehicle.CreateWheel(
  90. wspr, new Vector2(-1.8f,-1.5f), 1.25f, 4, 0.4f, Cache.Get<ParticleEffect2D>("particles/dust.pex"), 2.6f);
  91. // We create the head
  92. Node head = vehicle.CreateHead(
  93. Cache.Get<Sprite2D>("characters/truck/head.png"), new Vector3(-1,2.7f,-1), 1f, new Vector2(-1,1.8f));
  94. // We position the vehicle
  95. foreach (Node node in new []{vehicleNode, w1, w2, head})
  96. node.Translate2D(position);
  97. return vehicle;
  98. }
  99. // Create a node with a sprite and optionally set scale and add a RigidBody2D component
  100. public static Node CreateSpriteNode(Sprite2D sprite, Node parent, float scale = 1f, bool addRigidBody = true)
  101. {
  102. Node n = parent.CreateChild();
  103. n.SetScale2D(Vector2.One*scale);
  104. n.CreateComponent<StaticSprite2D>().SetSprite(sprite);
  105. if (addRigidBody) n.CreateComponent<RigidBody2D>().SetBodyType(BodyType2D.BT_DYNAMIC);
  106. return n;
  107. }
  108. // Convenience overload
  109. public static Node CreateSpriteNode(Sprite2D sprite, float scale = 1f, bool addRigidBody = true)
  110. {
  111. return CreateSpriteNode(sprite, _scene, scale, addRigidBody);
  112. }
  113. // Convenience function to add a collider to a given node
  114. public static T AddCollider<T>(Node node, float fric = 1, float dens = 1, float elas = 0) where T: CollisionShape2D
  115. {
  116. CollisionShape2D s = node.CreateComponent<T>();
  117. s.SetFriction(fric);
  118. s.SetDensity(dens);
  119. s.SetRestitution(elas);
  120. return (T)s;
  121. }
  122. // This returns the surface point closest to wheel's center
  123. public static Vector3 GetSurfacePointClosestToPoint(Node wheel)
  124. {
  125. // We sample various points near the wheel position
  126. List<Vector2> points = new List<Vector2>();
  127. for (float xOffset = -1; xOffset < 1; xOffset+=0.02f)
  128. {
  129. float y = _terrain.SampleSurface(wheel.Position.X + xOffset);
  130. points.Add(new Vector2(wheel.Position.X + xOffset, y));
  131. }
  132. // We get the closest one
  133. float lastDist = float.MaxValue;
  134. Vector2 closestPoint = Vector2.Zero;
  135. foreach (Vector2 point in points)
  136. {
  137. float pointDist = Vector2.Distance(wheel.Position2D, point);
  138. if (pointDist < lastDist)
  139. {
  140. closestPoint = point;
  141. lastDist = pointDist;
  142. }
  143. }
  144. return new Vector3(closestPoint.X, closestPoint.Y, 2);
  145. }
  146. public static Vector2 LerpVector2(Vector2 vecA, Vector2 vecB, float t)
  147. {
  148. Vector2 ipo;
  149. ipo.X = vecA.X + t * (vecB.X - vecA.X);
  150. ipo.Y = vecA.Y + t * (vecB.Y - vecA.Y);
  151. return ipo;
  152. }
  153. #endregion
  154. }