"Removed the SupportedPlatformsImpl classes and replaced them with a new SupportedPlatforms attribute on the assembly level. Removed a few class constructors which could cause problems when loading a game. Made ResetElapsedTime in the game class reset to 0 instead of TimeSpan.MinValue. Removed the restriction in the InputDeviceFactory for which InputDevices are supported. Added a Logger for Metro which works with the current Logger implementation. Changed that when a platform is recognized that is higher than Windows 8, it gets treated like Windows 8, not like Windows 7. Due to the SupportedPlatforms change, the assembly loader is now faster in finding out which assemblies contains addIns. For not Metro system, it's also added that a warning gets written if an AddIn references a different ANX version than that of the running assembly. OpenGL and DirectX have been updated to the newest versions. XAudio system uses now the same SharpDX version as all the other systems. ParameterBuffer for WindowsMetro gets now correctly created by considering the size constraints for constant buffers. Fixed an erroneous finalizer in the xaudio system. Made the metro projects convert to Windows 8.1, as Windows 8.0 is not supported by the newer SharpDX versions. It's now also necessary to use at least Visual Studio 2013 to build the Metro versions. Made the samples work again on Windows." "Fixed the creation of the swap chain for windows metro and removed the dependency of the Metro Rendersystem onto the Metro Platformsytem. All occurrences of WindowHandles have been replaced with a custom WindowHandle type which should work out of the box in most cases, but does still represent a breaking change to XNA. The ProjectConverter for Metro was adjusted so that with just changing the way the application is initialized, most projects that worked with ANX before should now work under win rt. The sample SimpleNoContent does now work out of the box for win rt, after a project conversion. The application name for win rt apps is now a guid, the display name stayed the same though. That's to be more compliant with the way win rt apps are normally created. The default namespace and namespace of the classes for the Sample "SimpleNoContent" is renamed from "SimpleModernUI" to "SimpleNoContent". With the new way win rt apps are initialized for ANX, it's necessary to first create the WindowsGameHost for WinRT with a handler how to create the game instance and give that to the CoreApplication object to run it. Also took care of a few annoying bugs when working with win rt and ANX where no InputDevices could be created on the first frame (Issue #1164 ) and that it wasn't possible to use the localfolder of the application on the first update and all the other stuff for which an instance of the Application class was necessary."
614 lines
17 KiB
C#
614 lines
17 KiB
C#
#region Using Statements
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using ANX.Framework.Content;
|
|
using ANX.Framework.Graphics;
|
|
using ANX.Framework.NonXNA;
|
|
using ANX.Framework.NonXNA.Development;
|
|
using ANX.Framework.NonXNA.PlatformSystem;
|
|
using ANX.Framework.NonXNA.SoundSystem;
|
|
|
|
#endregion // Using Statements
|
|
|
|
// This file is part of the ANX.Framework created by the
|
|
// "ANX.Framework developer group" and released under the Ms-PL license.
|
|
// For details see: http://anxframework.codeplex.com/license
|
|
|
|
#region Patch-Log
|
|
/*
|
|
|
|
* 12/03/2012 #13365 clcrutch
|
|
|
|
*/
|
|
#endregion
|
|
|
|
namespace ANX.Framework
|
|
{
|
|
[PercentageComplete(60)]
|
|
[TestState(TestStateAttribute.TestState.Untested)]
|
|
[Developer("Glatzemann")]
|
|
public class Game : IDisposable
|
|
{
|
|
#region Private Members
|
|
private IGraphicsDeviceManager graphicsDeviceManager;
|
|
private IGraphicsDeviceService graphicsDeviceService;
|
|
private GameServiceContainer gameServices;
|
|
|
|
protected bool firstUpdateDone;
|
|
protected bool firstDrawDone;
|
|
private bool drawingSlow;
|
|
private bool inRun;
|
|
private bool isInitialized;
|
|
|
|
private GameHost host;
|
|
private bool ShouldExit;
|
|
|
|
private GameTimer gameTimer;
|
|
private TimeSpan gameTimeAccu;
|
|
private GameTime gameTime;
|
|
private TimeSpan totalGameTime;
|
|
private long updatesSinceRunningSlowly1;
|
|
private long updatesSinceRunningSlowly2;
|
|
private bool suppressDraw;
|
|
|
|
private GameTime gameUpdateTime;
|
|
|
|
private ContentManager content;
|
|
|
|
private List<IGameComponent> drawableGameComponents;
|
|
|
|
#endregion
|
|
|
|
#region Events
|
|
public event EventHandler<EventArgs> Activated;
|
|
public event EventHandler<EventArgs> Deactivated;
|
|
public event EventHandler<EventArgs> Disposed;
|
|
public event EventHandler<EventArgs> Exiting;
|
|
|
|
#endregion
|
|
|
|
public Game()
|
|
{
|
|
Logger.Info("created a new Game-Class");
|
|
|
|
this.gameServices = new GameServiceContainer();
|
|
this.gameTime = new GameTime();
|
|
|
|
try
|
|
{
|
|
AddInSystemFactory.Instance.Initialize();
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
Logger.Error("Error while initializing AddInSystem: " + ex);
|
|
throw new AddInLoadingException("Error while initializing AddInSystem.", ex);
|
|
}
|
|
|
|
AddSystemCreator<IInputSystemCreator>();
|
|
AddSystemCreator<ISoundSystemCreator>();
|
|
AddSystemCreator<IRenderSystemCreator>();
|
|
|
|
FrameworkDispatcher.Update();
|
|
|
|
CreateGameHost();
|
|
|
|
Logger.Info("creating ContentManager");
|
|
this.content = new ContentManager(this.gameServices);
|
|
|
|
Logger.Info("creating GameTimer");
|
|
this.gameTimer = new GameTimer();
|
|
this.IsFixedTimeStep = true;
|
|
this.gameUpdateTime = new GameTime();
|
|
this.InactiveSleepTime = TimeSpan.FromMilliseconds(20.0);
|
|
this.TargetElapsedTime = TimeSpan.FromTicks(TimeSpan.TicksPerSecond / 60L); // default is 1/60s
|
|
|
|
//TODO: implement draw- and update-order handling of GameComponents
|
|
this.Components = new GameComponentCollection();
|
|
this.Components.ComponentAdded += components_ComponentAdded;
|
|
this.Components.ComponentRemoved += components_ComponentRemoved;
|
|
this.drawableGameComponents = new List<IGameComponent>();
|
|
|
|
Logger.Info("finished initializing new Game class");
|
|
|
|
this.IsActive = true;
|
|
}
|
|
|
|
#region CreateGameHost
|
|
private void CreateGameHost()
|
|
{
|
|
Logger.Info("creating GameHost");
|
|
host = PlatformSystem.Instance.CreateGameHost(this);
|
|
|
|
host.Activated += HostActivated;
|
|
host.Deactivated += HostDeactivated;
|
|
host.Suspend += HostSuspend;
|
|
host.Resume += HostResume;
|
|
host.Idle += HostIdle;
|
|
host.Exiting += HostExiting;
|
|
}
|
|
#endregion
|
|
|
|
#region AddSystemCreator
|
|
private T AddSystemCreator<T>() where T : class, ICreator
|
|
{
|
|
T creator = AddInSystemFactory.Instance.GetDefaultCreator<T>();
|
|
if (creator != null)
|
|
this.gameServices.AddService(typeof(T), creator);
|
|
|
|
return creator;
|
|
}
|
|
#endregion
|
|
|
|
protected virtual void Initialize()
|
|
{
|
|
if (!this.isInitialized)
|
|
{
|
|
foreach (GameComponent component in this.Components)
|
|
{
|
|
component.Initialize();
|
|
}
|
|
|
|
this.isInitialized = true;
|
|
|
|
this.LoadContent();
|
|
}
|
|
}
|
|
|
|
protected virtual void Update(GameTime gameTime)
|
|
{
|
|
foreach (IUpdateable updateable in this.Components)
|
|
{
|
|
if (updateable.Enabled)
|
|
{
|
|
updateable.Update(gameTime);
|
|
}
|
|
}
|
|
|
|
FrameworkDispatcher.Update();
|
|
}
|
|
|
|
protected virtual void Draw(GameTime gameTime)
|
|
{
|
|
foreach (IDrawable drawable in this.drawableGameComponents)
|
|
{
|
|
if (drawable.Visible)
|
|
{
|
|
drawable.Draw(gameTime);
|
|
}
|
|
}
|
|
}
|
|
|
|
protected virtual void LoadContent()
|
|
{
|
|
|
|
}
|
|
|
|
protected virtual void UnloadContent()
|
|
{
|
|
|
|
}
|
|
|
|
protected virtual void BeginRun()
|
|
{
|
|
|
|
}
|
|
|
|
protected virtual void EndRun()
|
|
{
|
|
|
|
}
|
|
|
|
public void RunOneFrame()
|
|
{
|
|
throw new NotImplementedException();
|
|
}
|
|
|
|
public void SuppressDraw()
|
|
{
|
|
this.suppressDraw = true;
|
|
}
|
|
|
|
public void ResetElapsedTime()
|
|
{
|
|
//TODO Check if it works right
|
|
gameTimeAccu = TimeSpan.Zero;
|
|
}
|
|
|
|
protected virtual bool BeginDraw()
|
|
{
|
|
if ((this.graphicsDeviceManager != null) && !this.graphicsDeviceManager.BeginDraw())
|
|
{
|
|
return false;
|
|
}
|
|
//Logger.BeginLogEvent(LoggingEvent.Draw, "");
|
|
return true;
|
|
}
|
|
|
|
protected virtual void EndDraw()
|
|
{
|
|
if (this.graphicsDeviceManager != null)
|
|
{
|
|
this.graphicsDeviceManager.EndDraw();
|
|
}
|
|
}
|
|
|
|
public void Exit()
|
|
{
|
|
this.ShouldExit = true;
|
|
this.host.Exit();
|
|
}
|
|
|
|
public void Run()
|
|
{
|
|
this.RunGame();
|
|
}
|
|
|
|
public void Tick()
|
|
{
|
|
if (this.ShouldExit)
|
|
{
|
|
return;
|
|
}
|
|
|
|
// Throttle speed when the game is not active
|
|
if (!this.IsActive)
|
|
{
|
|
ThreadHelper.Sleep(InactiveSleepTime);
|
|
}
|
|
|
|
gameTimer.Update();
|
|
|
|
//Do an additional update cycle at the beginning to be compatible with XNA.
|
|
if (!firstUpdateDone)
|
|
{
|
|
this.Update(this.gameTime);
|
|
this.firstUpdateDone = true;
|
|
}
|
|
|
|
bool skipDraw = IsFixedTimeStep ? DoFixedTimeStep(gameTimer.Elapsed) : DoTimeStep(gameTimer.Elapsed);
|
|
this.suppressDraw = false;
|
|
if (skipDraw == false)
|
|
{
|
|
DrawFrame();
|
|
}
|
|
|
|
}
|
|
|
|
private bool DoFixedTimeStep(TimeSpan time)
|
|
{
|
|
bool skipDraw = false;
|
|
|
|
if (Math.Abs(time.Ticks - this.TargetElapsedTime.Ticks) < this.TargetElapsedTime.Ticks >> 6)
|
|
{
|
|
time = this.TargetElapsedTime;
|
|
}
|
|
|
|
this.gameTimeAccu += time;
|
|
long updateCount = this.gameTimeAccu.Ticks / this.TargetElapsedTime.Ticks;
|
|
|
|
if (updateCount <= 0)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
if (updateCount > 1)
|
|
{
|
|
this.updatesSinceRunningSlowly2 = this.updatesSinceRunningSlowly1;
|
|
this.updatesSinceRunningSlowly1 = 0;
|
|
}
|
|
else
|
|
{
|
|
this.updatesSinceRunningSlowly1++;
|
|
this.updatesSinceRunningSlowly2++;
|
|
}
|
|
|
|
this.drawingSlow = (this.updatesSinceRunningSlowly2 < 20);
|
|
|
|
while (updateCount > 0)
|
|
{
|
|
if (this.ShouldExit)
|
|
{
|
|
break;
|
|
}
|
|
|
|
updateCount -= 1L;
|
|
|
|
this.gameTime.ElapsedGameTime = this.TargetElapsedTime;
|
|
this.gameTime.TotalGameTime = this.totalGameTime;
|
|
this.gameTime.IsRunningSlowly = this.drawingSlow;
|
|
this.Update(this.gameTime);
|
|
skipDraw &= this.suppressDraw;
|
|
this.suppressDraw = false;
|
|
|
|
this.gameTimeAccu -= this.TargetElapsedTime;
|
|
this.totalGameTime += this.TargetElapsedTime;
|
|
}
|
|
|
|
return skipDraw;
|
|
}
|
|
|
|
private bool DoTimeStep(TimeSpan time)
|
|
{
|
|
this.gameTime.ElapsedGameTime = time;
|
|
this.gameTime.TotalGameTime = this.totalGameTime;
|
|
this.gameTime.IsRunningSlowly = false;
|
|
|
|
this.Update(this.gameTime);
|
|
|
|
this.totalGameTime += time;
|
|
|
|
return suppressDraw;
|
|
}
|
|
|
|
private void RunGame()
|
|
{
|
|
this.graphicsDeviceManager = this.Services.GetService(typeof(IGraphicsDeviceManager)) as IGraphicsDeviceManager;
|
|
if (this.graphicsDeviceManager != null)
|
|
this.graphicsDeviceManager.CreateDevice();
|
|
|
|
this.Initialize();
|
|
this.inRun = true;
|
|
this.BeginRun();
|
|
this.gameTime.ElapsedGameTime = TimeSpan.Zero;
|
|
this.gameTime.TotalGameTime = this.totalGameTime;
|
|
this.gameTime.IsRunningSlowly = false;
|
|
|
|
this.host.Run();
|
|
|
|
this.EndRun();
|
|
}
|
|
|
|
private void DrawFrame()
|
|
{
|
|
if (!this.ShouldExit)
|
|
{
|
|
if (this.firstUpdateDone)
|
|
{
|
|
if (!this.Window.IsMinimized)
|
|
{
|
|
if (this.BeginDraw())
|
|
{
|
|
this.Draw(this.gameTime);
|
|
this.EndDraw();
|
|
|
|
if (!this.firstDrawDone)
|
|
{
|
|
this.firstDrawDone = true;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
#region Public Properties
|
|
public GameServiceContainer Services
|
|
{
|
|
get
|
|
{
|
|
return this.gameServices;
|
|
}
|
|
}
|
|
|
|
public ContentManager Content
|
|
{
|
|
get
|
|
{
|
|
return this.content;
|
|
}
|
|
set
|
|
{
|
|
this.content = value;
|
|
}
|
|
}
|
|
|
|
public GraphicsDevice GraphicsDevice
|
|
{
|
|
get
|
|
{
|
|
//TODO: GraphicsDevice property is heavily used. Maybe it is better to hook an event to the services container and
|
|
// cache the reference to the GraphicsDeviceService to prevent accessing the dictionary of the services container
|
|
|
|
IGraphicsDeviceService graphicsDeviceService = this.graphicsDeviceService;
|
|
if (graphicsDeviceService == null)
|
|
{
|
|
this.graphicsDeviceService = graphicsDeviceService = this.Services.GetService(typeof(IGraphicsDeviceService)) as IGraphicsDeviceService;
|
|
|
|
//TODO: exception if null
|
|
}
|
|
|
|
return graphicsDeviceService.GraphicsDevice;
|
|
}
|
|
}
|
|
|
|
public GameWindow Window
|
|
{
|
|
get
|
|
{
|
|
return (host != null) ? host.Window : null;
|
|
}
|
|
}
|
|
|
|
public bool IsFixedTimeStep
|
|
{
|
|
get;
|
|
set;
|
|
}
|
|
|
|
public TimeSpan TargetElapsedTime
|
|
{
|
|
get;
|
|
set;
|
|
}
|
|
|
|
public TimeSpan InactiveSleepTime
|
|
{
|
|
get;
|
|
set;
|
|
}
|
|
|
|
public bool IsActive
|
|
{
|
|
get;
|
|
internal set;
|
|
}
|
|
|
|
public bool IsMouseVisible
|
|
{
|
|
get;
|
|
set;
|
|
}
|
|
|
|
public LaunchParameters LaunchParameters
|
|
{
|
|
get
|
|
{
|
|
throw new NotImplementedException();
|
|
}
|
|
}
|
|
|
|
public GameComponentCollection Components
|
|
{
|
|
get;
|
|
private set;
|
|
}
|
|
|
|
#endregion
|
|
|
|
internal bool IsActiveIgnoringGuide
|
|
{
|
|
get
|
|
{
|
|
throw new NotImplementedException();
|
|
}
|
|
}
|
|
|
|
public void Dispose()
|
|
{
|
|
Dispose(true);
|
|
GC.SuppressFinalize(this);
|
|
}
|
|
|
|
protected virtual void Dispose(bool disposing)
|
|
{
|
|
if (disposing)
|
|
{
|
|
this.Components.ComponentAdded -= components_ComponentAdded;
|
|
this.Components.ComponentRemoved -= components_ComponentRemoved;
|
|
|
|
IDisposable disposable;
|
|
var array = new IGameComponent[Components.Count];
|
|
Components.CopyTo(array, 0);
|
|
for (int i = 0; i < array.Length; i++)
|
|
{
|
|
disposable = (IDisposable)array[i];
|
|
if (disposable != null)
|
|
disposable.Dispose();
|
|
}
|
|
|
|
disposable = (IDisposable)graphicsDeviceManager;
|
|
if (disposable != null)
|
|
disposable.Dispose();
|
|
|
|
if (Disposed != null)
|
|
Disposed(this, EventArgs.Empty);
|
|
}
|
|
}
|
|
|
|
protected virtual bool ShowMissingRequirementMessage(Exception exception)
|
|
{
|
|
throw new NotImplementedException();
|
|
}
|
|
|
|
#region Event Handling
|
|
protected virtual void OnActivated(Object sender, EventArgs args)
|
|
{
|
|
RaiseIfNotNull(this.Activated, sender, args);
|
|
}
|
|
|
|
protected virtual void OnDeactivated(Object sender, EventArgs args)
|
|
{
|
|
RaiseIfNotNull(this.Deactivated, sender, args);
|
|
}
|
|
|
|
protected virtual void OnExiting(Object sender, EventArgs args)
|
|
{
|
|
RaiseIfNotNull(this.Exiting, sender, args);
|
|
}
|
|
|
|
private void RaiseIfNotNull(EventHandler<EventArgs> eventDelegate, Object sender, EventArgs args)
|
|
{
|
|
if (eventDelegate != null)
|
|
{
|
|
eventDelegate(sender, args);
|
|
}
|
|
}
|
|
|
|
private void components_ComponentRemoved(object sender, GameComponentCollectionEventArgs e)
|
|
{
|
|
if (e.GameComponent is IDrawable)
|
|
{
|
|
drawableGameComponents.Remove(e.GameComponent);
|
|
}
|
|
}
|
|
|
|
private void components_ComponentAdded(object sender, GameComponentCollectionEventArgs e)
|
|
{
|
|
if (e.GameComponent is IDrawable)
|
|
{
|
|
drawableGameComponents.Add(e.GameComponent);
|
|
}
|
|
|
|
if (isInitialized)
|
|
{
|
|
e.GameComponent.Initialize();
|
|
}
|
|
}
|
|
|
|
private void HostActivated(object sender, EventArgs e)
|
|
{
|
|
if (!IsActive)
|
|
{
|
|
this.IsActive = true;
|
|
this.OnActivated(this, EventArgs.Empty);
|
|
}
|
|
}
|
|
|
|
private void HostDeactivated(object sender, EventArgs e)
|
|
{
|
|
if (IsActive)
|
|
{
|
|
this.IsActive = false;
|
|
this.OnDeactivated(this, EventArgs.Empty);
|
|
}
|
|
}
|
|
|
|
private void HostExiting(object sender, EventArgs e)
|
|
{
|
|
ShouldExit = true;
|
|
|
|
//TODO: implement
|
|
//this.OnExiting(this, EventArgs.Empty);
|
|
}
|
|
|
|
private void HostIdle(object sender, EventArgs e)
|
|
{
|
|
this.Tick();
|
|
}
|
|
|
|
private void HostResume(object sender, EventArgs e)
|
|
{
|
|
//TODO: implement
|
|
//this.clock.Resume();
|
|
}
|
|
|
|
private void HostSuspend(object sender, EventArgs e)
|
|
{
|
|
//TODO: implement
|
|
//this.clock.Suspend();
|
|
}
|
|
|
|
#endregion
|
|
}
|
|
}
|