World, Scene, and UI Creation in Code (C#)

 

Creating Scenes and GUI Forms in Code (eg. C#)

You can create new scene classes and GUI form classes in code such as by adding and modifying the following classes in the Visual Studio world project (such as Isles of War/Isles of War.csproj) and then compiling them and (re)starting the toolset, such as by pressing F5 in Visual Studio after making your changes. For example, you could modify the BaseScene.cs to be like shown below, to add a UI panel that shows when the scene starts and which has a button which, when pressed, will add a vehicle to the scene at the camera's current position.  In this case, it will create an instance of a vehicle prefab.  That prefab will then be saved to a .v3dx XML file after its added to the scene via the button (due to the use of World.Database.GetOrCreate() method), if you save the world before exiting the toolset (such as via Ctrl-Shift-S or File > Save World or saving when prompted when exiting the toolset).

Modify BaseScene.cs  (found at, for example, Isles of War/Scenes/BaseScene.cs) like follows:


using System;
using System.Collections.Generic;
using System.Runtime.Serialization;
using Microsoft.Xna.Framework;
using Visual3D;
using Visual3D.Demo;
using Visual3D.Demo.Avatars;
using Visual3D.UI;
using Visual3D.Demo.UI;
 
namespace IslesofWar
{
[DataContract] //Required to ensure instanced of this class can be saved. Apply [DataMember] to any field or property that should be saved.
public class BaseScene : BaseDemoScene
{
public BaseScene()
{
MusicTrackName = "Wild_Tracks_60Sec_Edit.mp3";
MusicTrackVolume = 0.6f;
Settings.AmbientLight.BaseScale *= 1.10f; //10% increase in ambient (indirect, night and day) lighting / screen brightness
Settings.CameraSpeed *= 1.10f; //faster movement of camera (when not controlling an avatar, and when editing scene)
}
protected override void OnContentLoaded()
{
  base.OnContentLoaded();
 
//any configuration, entity creation and scripting below will occur every time the scene starts 
//(before this, the OnConstructPrototype() will occur if first time scene is created or else it will load from the .scene.v3dx saved scene definition file, and then OnStarted() will occur, then OnContentLoaded())
TimeOfDay.AutoUpdateTimeScalar = 1.00f; //day-night cycle completes at 100% speed, in 24 game/simulation hours
TimeOfDay.LightScalar = 1.10f; //increase overall brightness (direct, eg. sunlight and indirect/ambient eg. at night)
TimeOfDay.HourOfDay = 12; //reset current time to noon (mid-day) for sun / sky of the dynamic day-night cycle
//scripted logic that should occur every time the scene starts should go here.
}
 
//you can override OnPause() and OnResume() if needed, but scripting (in Ability, Action, etc. derived classes), Music, etc. will be paused automatically when game/simulation is paused (such as via pressing P or Pause or Ctrl-P or Escape).
protected override void OnDeactivated()
{
   base.OnDeactivated();
//any cleanup can go here (or in OnDispose() which is usually called after this), however, OnDeactivated() and then OnDisposed() will be automatically called for the scene, its entities, entity scripts/abilities/components, etc. when a scene is exited/unloaded.
}
}
 
public class VehicleScene : BaseScene
{
public const int CurrentUIClassVersion = 1;
 
[DataMember]
protected int SavedUIVersion = 0;
 
 
protected override void OnConstructPrototype()
{
base.OnConstructPrototype();
 
//one time scene setup logic, such as adding entities or GUI forms to the scene, can go here.
//Usually logic here will only occur the first time a scene is created, before its first saved (eg. via Ctrl-S in Scene Editor) to a .scene.v3dx XML file.
//It is suggested to do this logic instead in the OnConstructPrototype() method of an entity (such as in a class derived from ModelEntity, SceneEntity, Area, or (Full)SceneArea) instead of in the scene class. Or, you can check whether a component already exists before creating it here or replace an existing one, such as by using methods like Set*() instead of Add*(). Or, you can create a saved field like UIWasCreated example below 
 
if(SavedUIVersion < CurrentUIClassVersion)
{
SavedUIVersion = CurrentUIClassVersion;
GUI.ShowForm<VehicleManagerUI>();
}
 
}
[DataContract]
public class VehicleManagerUI : GuiForm
{
protected static float Padding = 10;
protected static ScreenSize ButtonSize = new ScreenSize(150, 30);
 
public VehicleManagerUI()
{
}
 
 
protected override void BuildGui()
{
TopSheet.ThemeFileName = SkinIDs.Fantasy;
 
base.BuildGui();
 
var buttonSize = new ScreenSize(150, 30);
 
var panel = AddPanel("Vehicle Manager", new ScreenPoint{ X = 10, Y = -10}, 
new ScreenSize(buttonSize.Width+Padding, buttonSize.Height+Padding), 
PanelFlags.Moveable | PanelFlags.UnfadeOnHover | PanelFlags.NoTitleBar, 
AnchorPoint.BottomLeft);
 
panel.AddButton("Create Vehicle", new ScreenPoint(Padding, Padding), buttonSize, CreateVehicleButton_Clicked);
}
 
protected virtual void CreateVehicleButton_Clicked(object control, GuiEventArgs e)
{
var vehicle = CreateFromPrefab<DesertPatrolVehicle>();
var position = World.MainCamera.WorldPosition;
position.Y = float.NaN; //ensures starts at terrain/ground altitude (or, can use Scene.Spatial.AddChild(obj, pos, true) overload)
World.Scene.AddChild(vehicle.VisualObject);
vehicle.IsSaved = false; //temporary vehicle, not saved with scene, created via button only
}
 
public TPrefab CreateFromPrefab<TPrefab>()
where TPrefab : new()
{
return CreateFromPrefab<TPrefab>(NameID.Null);
}
public TPrefab CreateFromPrefab<TPrefab>(NameID prefabID)
where TPrefab : new()
{
TPrefab prefab;
if(prefabID.IsNullOrEmpty)
prefabID = typeof(TPrefab); //get a consistent ID based on the class name
World.Database.GetOrCreateItem(prefabID, out prefab);
var entity = prefab.CreateInstance(InstancingMode.Instanced);
 
return entity;
}
}
}

Modify the WorldApp.cs file (found at, for example, Isles of War/World/WorldApp.cs) like follows:

using System;
using Visual3D;
using Visual3D.Demo;
using Visual3D.Demo.Scenes;
using Visual3D.Scenes;

namespace IslesofWar
{
public class WorldApp : BaseDemoWorld 
{
protected override void AddScenes()
{
//Registered the VehicleScene class, which will be shown by default as a scene named "Vehicle Sim"
//you could also just call Scenes.Add(typeof(VehicleScene)) if you want a default scene name of "Vehicle Scene"
Scenes.Add(new SceneInfo("Vehicle Sim", typeof(VehicleScene)));

//If you want multiple scenes (eg. scenarios or missions) using the same scene class, you can add them here by ensuring they have different scene names when registered. You can also modify the above line to set the scene
//Scenes.Add(new SceneInfo("Vehicle Mission 2", typeof(VehicleScene));

//Alternatively, you could just go to File (Visual3D icon) > Save Scene as Copy when editing the "Vehicle Sim" scene, to create another scene which uses the same class (and which starts out with all the same settings and content, initially, too).

//Registering of BaseScene was commented out below so that you don't show a scene for your base scene class/template which is often just supposed to be an empty scene
//Scenes.Add(typeof(BaseScene)); 
 
//You can remove or comment out the below line if you don't want to use the default Main Menu scene 
Scenes.Add(new SceneInfo(typeof(Visual3D.Demo.Scenes.MainMenu)));
//NOTE: The Main Menu scene shows a list of all scenes a user can choose to run. Main Menu is shown on startup if its configured to be the startup scene, which is edited by going to Short Cuts > World Manifest and changing Startup Scene (or Toolset Startup Scene) in Object Editor.
}

protected override IPrototypeLoader CreatePrototypeLoader()
{
return new AssetLibraryPlugin();
}
}
}