Absolutely yes, though probably it's better to have an "empty" scene with only one component, whose job is to actually build your game scene.
Even better, you could leverage that empty scene to make a nice loading screen (even just a fixed, full screen SpriteRenderer does wonders)
Anyway, this is what I'm doing for my game.. don't mind some of the weird parts such as using a Task or the MainThreadOperations stuff.. that's just me trying things

Code:
using System.Linq;
using System.Threading.Tasks;
using BrokenGalaxyNeo.Data;
using BrokenGalaxyNeo.Generators;
using BrokenGalaxyNeo.Services;
using BrokenGalaxyNeo.UI;
using Duality;
using Duality.Components;
using Duality.Components.Physics;
using Duality.Components.Renderers;
using Duality.Drawing;
using Duality.Plugins.Companion.Drawing;
using Duality.Plugins.Companion.Math.Graph;
using Duality.Resources;
namespace BrokenGalaxyNeo.Components
{
public class LoadingManager : Component, ICmpUpdatable
{
private delegate void MainThreadOperation(Scene s);
private class CompleteScene
{
public Scene Scene { get; set; }
public MainThreadOperation MainThreadOperations { get; set; }
public void ApplyMTOperations()
{
this.MainThreadOperations(this.Scene);
}
}
public TextRenderer Text { get; set; }
[DontSerialize]
private Task<CompleteScene> _creatorTask;
public void CreateGame(GameConfiguration config)
{
_creatorTask = new Task<CompleteScene>(() =>
{
return PrepareScene(config);
});
_creatorTask.Start();
}
private float CalculateSystemScore(StarSystem system, Player player)
{
float num = system.GetStrategicValueFor(player);
float den = system.Neighbors.Sum(n => n.Owner == null ? 1 : 2);
return (num / den);
}
private CompleteScene PrepareScene(GameConfiguration config)
{
this.Text.Text.SourceText = "Creating map...";
GameServices.Instance.NewGame(config);
this.Text.Text.SourceText = "Seeding galaxy with life...";
foreach (Player player in GameServices.Instance.Players.AllPlayers)
{
GameServices.Instance.Map.Nodes
.Where(n => n.Owner == null)
.OrderByDescending(n => CalculateSystemScore(n, player))
.First()
.SetHomeworld(player);
}
foreach (StarSystem ss in GameServices.Instance.Map.Nodes.Where(n => n.Owner == null))
ss.SetGarrison(new CombatFleet(Player.NotSet, MathF.Rnd.Next(5, 11)));
this.Text.Text.SourceText = "Building scene...";
CompleteScene result = new CompleteScene();
Scene scene = new Scene();
GameObject ssUI = new GameObject("StarSystemMenu");
ssUI.AddComponent<StarSystemMenu>();
scene.AddObject(ssUI);
GameObject lnkUI = new GameObject("LinkMenu");
lnkUI.AddComponent<LinkCreationMenu>();
scene.AddObject(lnkUI);
GameObject gameUI = new GameObject("GameControlMenu");
gameUI.AddComponent<GameControlMenu>();
scene.AddObject(gameUI);
float centerX = GameServices.Instance.Map.Nodes.Average(x => x.Position.X) * Constants.GRAPH_SCALE_FACTOR;
float centerY = GameServices.Instance.Map.Nodes.Average(x => x.Position.Y) * Constants.GRAPH_SCALE_FACTOR;
GameObject camera = new GameObject("Camera");
camera.AddComponent<Transform>();
camera.AddComponent<Camera>();
camera.AddComponent<GameController>();
camera.AddComponent<PlayerController>();
camera.AddComponent<GameOverlayRenderer>();
camera.GetComponent<Transform>().Pos = new Vector3(centerX, centerY, -500);
camera.GetComponent<PlayerController>().StarSystemMenu = ssUI.GetComponent<StarSystemMenu>();
camera.GetComponent<PlayerController>().LinkCreationMenu = lnkUI.GetComponent<LinkCreationMenu>();
scene.AddObject(camera);
// for debug
//camera.AddComponent<ProfileRenderer>().DrawGraphs = false;
foreach (StarSystem ss in GameServices.Instance.Map.Nodes)
scene.AddObject(CreateStarSystemGameObject(ss));
foreach (Link<StarSystem> l in GameServices.Instance.Map.Links)
scene.AddObject(CreateLink(l));
this.Text.Text.SourceText = "Spreading gases...";
Pixmap nebulaPixmap = PixmapGenerator.GenerateNebula(256, config.Seed, .25f, new ColorRgba(35, 40, 75).WithAlpha(.25f));
Pixmap backgroundPixmap = PixmapGenerator.GenerateNebula(512, config.Seed * 2, .5f, new ColorRgba(.1f));
this.Text.Text.SourceText = "Igniting background stars...";
Pixmap starfieldPixmap = PixmapGenerator.GenerateStarfield(1024, config.Seed);
result.MainThreadOperations = (s) =>
{
this.Text.Text.SourceText = "Finishing touches...";
s.AddObject(CreateAOIRenderer(centerX, centerY, config.Width + 10, config.Height + 10));
s.AddObject(CreatePlane("Background", backgroundPixmap, new Vector3(0, 0, 10), 2, .5f));
s.AddObject(CreatePlane("Starfield", starfieldPixmap, new Vector3(0, 0, 5), 1, .25f));
CreatePlane("Nebula", nebulaPixmap, Vector3.Zero, 5, .2f).Parent = camera;
GameObject dragRenderer = new GameObject("DragRenderer");
dragRenderer.AddComponent<DragRenderer>();
scene.AddObject(dragRenderer);
camera.GetComponent<PlayerController>().DragRenderer = dragRenderer.GetComponent<DragRenderer>();
};
result.Scene = scene;
return result;
}
private GameObject CreateStarSystemGameObject(StarSystem system)
{
RigidBody rb = new RigidBody() { IgnoreGravity = true };
rb.ClearShapes();
rb.AddShape(new CircleShapeInfo(Constants.RB_SYSTEM_RADIUS, Vector2.Zero, 1) { IsSensor = true });
GameObject go = new GameObject(system.Name);
go.AddComponent<Transform>();
go.AddComponent<SpriteRenderer>();
go.AddComponent<RigidBody>(rb);
go.AddComponent<StarSystem>(system);
go.GetComponent<Transform>().Pos = new Vector3(system.Position * Constants.GRAPH_SCALE_FACTOR, 0);
go.GetComponent<SpriteRenderer>().Rect = Rect.Align(Alignment.Center, 0, 0, Constants.RB_SYSTEM_RADIUS * 2, Constants.RB_SYSTEM_RADIUS * 2);
go.GetComponent<SpriteRenderer>().CustomMaterial = new BatchInfo(ContentProvider.RequestContent<Material>(@"Data\Graphics\Shaders\StarSystem.Material.res").Res);
return go;
}
private GameObject CreateLink(Link<StarSystem> link)
{
Vector2 linkVector = link.To.Position - link.From.Position;
float linkLength = linkVector.Length * Constants.GRAPH_SCALE_FACTOR;
GameObject go = new GameObject(link.From.Name + "-" + link.To.Name);
go.AddComponent<Transform>();
go.AddComponent<SpriteRenderer>();
go.AddComponent<LinkController>();
go.GetComponent<Transform>().Pos = new Vector3((link.To.Position + link.From.Position) * Constants.GRAPH_SCALE_FACTOR / 2, 0);
go.GetComponent<Transform>().Angle = linkVector.Angle;
go.GetComponent<SpriteRenderer>().Rect = Rect.Align(Alignment.Center, 0, 0, 5, linkLength);
go.GetComponent<SpriteRenderer>().CustomMaterial = new BatchInfo(ContentProvider.RequestContent<Material>(@"Data\Graphics\Shaders\Link.Material.res").Res);
go.GetComponent<SpriteRenderer>().Offset = 1;
go.GetComponent<LinkController>().Link = link;
return go;
}
private GameObject CreateAOIRenderer(float centerX, float centerY, int width, int height)
{
GameObject go = new GameObject("AOIRenderer");
go.AddComponent<Transform>();
go.AddComponent<SpriteRenderer>();
go.AddComponent<AOIRenderer>();
go.GetComponent<Transform>().Pos = new Vector3(centerX, centerY, 1);
go.GetComponent<Transform>().Scale = Constants.GRAPH_SCALE_FACTOR;
go.GetComponent<SpriteRenderer>().Rect = Rect.Align(Alignment.Center, 0, 0, width, height);
go.GetComponent<SpriteRenderer>().SharedMaterial = null;
go.GetComponent<SpriteRenderer>().CustomMaterial = new BatchInfo(
DrawTechnique.Alpha,
Colors.White.WithAlpha(.2f),
new Texture(width, height, TextureSizeMode.NonPowerOfTwo, TextureMagFilter.Nearest, TextureMinFilter.Nearest));
go.GetComponent<SpriteRenderer>().Offset = 1;
return go;
}
private GameObject CreatePlane(string name, Pixmap pixmap, Vector3 position, float scale, float scrollingMult)
{
GameObject go = new GameObject(name);
go.AddComponent<Transform>();
go.AddComponent<PlaneRenderer>();
go.GetComponent<Transform>().Pos = position;
go.GetComponent<Transform>().Scale = scale;
go.GetComponent<PlaneRenderer>().CustomMaterial = new Material(DrawTechnique.Alpha, Colors.White,
new Texture(pixmap, TextureSizeMode.Default,
TextureMagFilter.Linear, TextureMinFilter.LinearMipmapLinear,
TextureWrapMode.Repeat, TextureWrapMode.Repeat,
TexturePixelFormat.Rgba));
go.GetComponent<PlaneRenderer>().Scrolling = PlaneRenderer.ScrollingMode.Both;
go.GetComponent<PlaneRenderer>().ScrollingMultiplier = scrollingMult;
return go;
}
void ICmpUpdatable.OnUpdate()
{
if (_creatorTask != null && _creatorTask.Status == TaskStatus.RanToCompletion)
{
_creatorTask.Result.ApplyMTOperations();
GameServices.Instance.Scene.SetScene(_creatorTask.Result.Scene);
Scene.SwitchTo(_creatorTask.Result.Scene);
}
}
}
}
So basically in that Scene I only have a Camera, a TextRenderer, and that Component;
the actual gameplay Scene is fully built inside it (PrepareScene method).
Hope it helps
