Page 1 of 2 12 LastLast
Results 1 to 10 of 11
  1. #1
    Join Date
    Jun 2004
    Location
    The Netherlands
    Posts
    153

    Make R&D DemoFrameWork event based?

    I had a question about the DemoFrameWork setup. Why doesn't IDemo just have an (static) Initialize method which has the GameManager as variable and let have the GameManager events for Start, Awake, etc.

    The implementation of which methods you want to use in your Demo are something that belongs to the Demo you make and maybe you dont need all methods in your Demo implementation. This way you prevent empty method calls (which normally are skipped at JIT compilation though). But you also dont need to remember in your GameManager which methods to include of your Demo instance cause you have that in the Initialization method of Demo itself where you have knowledge of those things.

    Also nice to know when a Method in CIL (old MSIL) size is less then 32 bytes the JIT compiler will make it inline (thus no method call). Reminded that when Lee and Jason had it about this part of the code:
    Code:
    if (Input.GetKeyDown("escape"))
         UnLockCursor();
    versus
    Code:
    if (Input.GetKeyDown("escape"))
         Screen.lockCursor = false;
    Last edited by Project-A; 02-15-2011 at 09:38 AM.
    Bug? That's not a bug, that's a feature.
    LinkedIn - Twitter (dutch) - Work (dutch)

  2. #2
    Join Date
    Jun 2004
    Location
    The Netherlands
    Posts
    153
    Wrote part of as example, this way you can add/remove demo's by changing just 1 line of code:

    Code:
    using System;
    using System.Collections.Generic;
    using _DemoFramework.Demos;
    using _Scripts;
    using UnityEngine;
    
    public class GameManager : MonoBehaviour, IGameManager
    {
        #region Fields
    
        private List<IDemo> _loadedDemos;
    
        #endregion
    
        #region Constructors
    
        public GameManager()
            : base()
        {
            _loadedDemos = new List<IDemo>();
            _loadedDemos.Add(new Demo1());
    
            Initialize();
        }
    
        #endregion
    
        #region Events and Delegates
    
        public event EventHandler BehaviourStart;
        public event EventHandler BehaviourUpdate;
    
        #endregion
    
        #region Methods
    
        private void Initialize()
        {
            _loadedDemos.ForEach(demo => demo.Initialize(this));
        }
    
        private void Start()
        {
            if (BehaviourStart != null)
                BehaviourStart(this, EventArgs.Empty);
        }
    
        private void Update()
        {
            if (BehaviourUpdate != null)
                BehaviourUpdate(this, EventArgs.Empty);
        }
    
        #endregion
    }
    Code:
    using System;
    using _Scripts;
    
    namespace _DemoFramework.Demos
    {
        public class Demo1 : IDemo
        {
            #region Constructors
    
            public void Initialize(IGameManager manager)
            {
                manager.BehaviourStart += new EventHandler(OnStart);
            }
    
            #endregion
    
            #region Methods
    
            private void OnStart(object sender, EventArgs e)
            {
                // Handle start stuff
            }
    
            #endregion
        }
    }
    Last edited by Project-A; 02-15-2011 at 10:59 AM.
    Bug? That's not a bug, that's a feature.
    LinkedIn - Twitter (dutch) - Work (dutch)

  3. #3
    Join Date
    Jun 2004
    Location
    The Netherlands
    Posts
    153
    Not sure if I am allowed to post all this code, if so admin can remove it. Nice feature dependency option for features in Demo:
    Code:
    using System;
    
    namespace _DemoFramework
    {
        [AttributeUsage(AttributeTargets.Class, AllowMultiple=true)]
        public class FeatureDependencyAttribute : Attribute
        {
            public FeatureDependencyAttribute(Type type)
            {
                Type = type;
            }
    
            public Type Type { get; set; }
        }
    }
    and the new demo:
    Code:
        [FeatureDependency(typeof(MouseLock))]
        public class Demo1 : IDemo
        {...}
    updated MouseLock
    Code:
      public class MouseLock : IFeature
        {
            public void Initialize(IGameManager manager)
            {
                manager.BehaviourUpdate += new EventHandler(OnUpdate);
            }
    
            static void OnUpdate(object sender, EventArgs e)
            {
                HandleMouseCursorLocking();
            }
            ...
    and the new GameManager:
    Code:
    using System;
    using System.Collections.Generic;
    using _DemoFramework.Demos;
    using _Scripts;
    using UnityEngine;
    using _DemoFramework;
    
    public class GameManager : MonoBehaviour, IGameManager
    {
        #region Fields
    
        private List<Type> _loadedFeaturesTypes;
        private List<IDemo> _loadedDemos;
        private List<IFeature> _loadedFeatures;
    
        #endregion
    
        #region Constructors
    
        public GameManager()
            : base()
        {
            _loadedFeaturesTypes = new List<Type>();
            _loadedFeatures = new List<IFeature>();
            _loadedDemos = new List<IDemo>();
            _loadedDemos.Add(new Demo1());
    
            Initialize();
        }
    
        #endregion
    
        #region Events and Delegates
    
        public event EventHandler BehaviourStart;
        public event EventHandler BehaviourUpdate;
    
        #endregion
    
        #region Methods
    
        private void Initialize()
        {
            _loadedDemos.ForEach(demo =>
                {
                    demo.Initialize(this);
                    var dependencies = (FeatureDependencyAttribute[])demo.GetType().GetCustomAttributes(typeof(FeatureDependencyAttribute), false);
                    foreach (var dependency in dependencies)
                    {
                        if (!_loadedFeaturesTypes.Contains(dependency.Type))
                            _loadedFeaturesTypes.Add(dependency.Type);
                    }
                });
    
            foreach (var featureType in _loadedFeaturesTypes)
            {
                IFeature feature = (IFeature)Activator.CreateInstance(featureType));
                feature.Initialize(this);
                _loadedFeatures.Add(feature);
            }
        }
    
        private void Start()
        {
            if (BehaviourStart != null)
                BehaviourStart(this, EventArgs.Empty);
        }
    
        private void Update()
        {
            if (BehaviourUpdate != null)
                BehaviourStart(this, EventArgs.Empty);
        }
    
        #endregion
    }
    Bug? That's not a bug, that's a feature.
    LinkedIn - Twitter (dutch) - Work (dutch)

  4. #4
    Join Date
    Nov 2009
    Location
    Dallas, Texas
    Posts
    170
    Since you're doing events outside the context of the realtime component of the game, it's probably fine. It is also possible that C# on Mono is optimized by Unity so this may be moot, however, when working with XNA for games, we had serious performance/memory issues with custom events and garbage collection in C#/.NET. Yes, I know Unity and XNA both use events as part of the game loop, however, these are optimized for this purpose. Custom events have several layers of overhead and tend to be sloppy with memory as opposed to a simple static method call. In all the managed engines we've worked with we tend to roll our own event system if we really need one. I would say, generally speaking, it's usually a best practice to avoid custom events, if possible in .NET. Additionally, use memory pools where you can to avoid unecessary garbage collects during game play. Finally, reflection is usually off limits in game code. I know you would fail a code review if you provided a solution that included reflection. Now, I say all this in terms of C#/.NET, which may work differently than C#/Mono. Unity may have optimizations for this, however, I would probably stick with the static method call approach.

    If you grew up with .NET in the traditional business application sense, I think a lot of the coding choices made in game clients might make you cringe because there are cleaner ways to solve the problem, architecturally. However, in the game client, architecture is second to performance so things like static methods, which are usually frowned on in business app dev, are favored in game client code because the levels of indirection required to make a static method call are 0. I think you'll see that client game code tends to not be as abstract and "sexy" in terms of architecture for performance reasons.
    Last edited by jjguzzardo; 02-15-2011 at 11:54 AM.

  5. #5
    Join Date
    Jun 2004
    Location
    The Netherlands
    Posts
    153
    I understand, I wasn't by far going for fast code but for fast Demo / Feature testing with minimal setting up stuff where I am able to quickly switch between stuff and have to type as less possible to test / implement a feature. But you are right I have a huge mindshift to go with LOB development and game development, but will fall in place soon enough. Got ildasm open and playing around with it already

    Also handling GC is also an underestimated part of .NET, like the GC.SuppressFinalize is not known by so many developers or how structs vs classes work with GC.

    Update:
    Seems method call generates a callvirt instruction where static is just a call, also there is some checking above a method call (if its in the class of in a base class). Problem is thought that MSIL is not fully optimized code, so really wonding what it generates after JIT.
    Last edited by Project-A; 02-15-2011 at 12:14 PM.
    Bug? That's not a bug, that's a feature.
    LinkedIn - Twitter (dutch) - Work (dutch)

  6. #6
    Join Date
    Mar 2004
    Location
    Anacortes, WA
    Posts
    4,168
    Quote Originally Posted by jjguzzardo View Post
    Since you're doing events outside the context of the realtime component of the game, it's probably fine. It is also possible that C# on Mono is optimized by Unity so this may be moot, however, when working with XNA for games, we had serious performance/memory issues with custom events and garbage collection in C#/.NET. Yes, I know Unity and XNA both use events as part of the game loop, however, these are optimized for this purpose. Custom events have several layers of overhead and tend to be sloppy with memory as opposed to a simple static method call. In all the managed engines we've worked with we tend to roll our own event system if we really need one. I would say, generally speaking, it's usually a best practice to avoid custom events, if possible in .NET. Additionally, use memory pools where you can to avoid unecessary garbage collects during game play. Finally, reflection is usually off limits in game code. I know you would fail a code review if you provided a solution that included reflection. Now, I say all this in terms of C#/.NET, which may work differently than C#/Mono. Unity may have optimizations for this, however, I would probably stick with the static method call approach.

    If you grew up with .NET in the traditional business application sense, I think a lot of the coding choices made in game clients might make you cringe because there are cleaner ways to solve the problem, architecturally. However, in the game client, architecture is second to performance so things like static methods, which are usually frowned on in business app dev, are favored in game client code because the levels of indirection required to make a static method call are 0. I think you'll see that client game code tends to not be as abstract and "sexy" in terms of architecture for performance reasons.
    It seems that he was only using reflection at startup, which shouldn't be an issue at all. Also, delegates have the same performance implications as a virtual method according to: http://en.wikipedia.org/wiki/Delegat...T)#Performance

    Now sure, that's greater than the performance overhead of a static method; but it doesn't seem that bad to me.
    Need any help? Feel free to PM me - or send an email directly to nelson@3dbuzz.com!

  7. #7
    Join Date
    Jul 2002
    Location
    In space
    Posts
    5,428
    Moved to the Programming Questions forum.

  8. #8
    Join Date
    Nov 2009
    Location
    Dallas, Texas
    Posts
    170
    Yes, startup code is probably ok for reflection and it's only a demo so i'm not trying to be difficult, just offering up some issues I've run into when doing this kind of thing on a production game. We don't have to be quite as uptight about the way we do things when we're doing it for fun. Also, we've had 16 year industry vets look at the garbage collection issue in managed games using XNA and it always results in ways to totally avoid it using memory pools. We even had to roll our own event system because .NETs are just too sloppy. GC is not underestimated in any of the game studios i've worked for, especially when you need to squeeze every amount of performance out of a game. Maybe for non game software GC is ok, but not for games. I've not seen one production game where memory pools weren't used to prevent garbage collection from happening. In fact in game engine code, the over head of a C++ virtual method calls is too much which is why you dont see lots of OO in the actual game engine code itself. In terms of the actual game logic, it may or may not matter and especially in managed code it probably doesn't matter because every function call is a virtual call anyway

    I also want to reiterate that .NET is different than Unity Mono and it's possible there are optimizations for this kind of thing. However, I wouldn't assume that GC or .NET events are ok just because their in the language. I would probably want to understand how these are implemented so I can understand the performance ramifications if there are any that matter.

  9. #9
    Join Date
    Jun 2004
    Location
    The Netherlands
    Posts
    153
    Like you mentioned, I do have business industry way of thinking and have to get rid of that at some points, but while this is code is somewhat slower the drawback is that little that it justitfies the design for myself. I just wanna try stuff out myself and make own decisions in ways of going forward to the end goal hoping to learn more then just simply rewriting all I see on the video.
    I expect nothing more then some sort of memory management, for example to pool objects which are necessary for allocating in gametime and reuse ones that are not used anymore instead of letting them go in gabarge and reallocating a new one. Besides that its also just being smart with handling allocating objects. Allocating stuff in inialization also seems a good way to speed things up, like this XNA example I found on a blog:

    This allocates 4 matrices, with a total of 66 floats on the stack for each call.
    Code:
    public Matrix GetBodyMatrix()
    {
        return Matrix.CreateRotationZ(rotation) * Matrix.CreateTranslation(position.X, position.Y, 0);
    }
    
    public Vector2 GetWorldPosition(Vector2 localPosition)
    {
        return Vector2.Transform(localPosition, GetBodyMatrix());
    }
    While this code initializes way slower, at runtime there is no stack allocation anymore, and you down the 66 floats to 0 per call. And this runs 10-15% faster.
    Code:
    private Vector2 _worldPositionTemp = Vector2.Zero;
    private Matrix _bodyMatrixTemp = Matrix.Identity;
    private Matrix _rotationMatrixTemp = Matrix.Identity;
    private Matrix _translationMatrixTemp = Matrix.Identity;
    
    public void GetBodyMatrix(out Matrix bodyMatrix)
    {
        Matrix.CreateTranslation(position.X, position.Y, 0, out _translationMatrixTemp);
        Matrix.CreateRotationZ(rotation, out _rotationMatrixTemp);
        Matrix.Multiply(ref _rotationMatrixTemp, ref _translationMatrixTemp, out bodyMatrix);
    }
    
    public Vector2 GetWorldPosition(Vector2 localPosition)
    {
        GetBodyMatrix(out _bodyMatrixTemp);
        Vector2.Transform(ref localPosition, ref _bodyMatrixTemp, out _worldPositionTemp);
        return _worldPositionTemp;
    }
    Quote Originally Posted by jjguzzardo View Post
    I also want to reiterate that .NET is different than Unity Mono and it's possible there are optimizations for this kind of thing. However, I wouldn't assume that GC or .NET events are ok just because their in the language. I would probably want to understand how these are implemented so I can understand the performance ramifications if there are any that matter.
    I am going over the Unity3D forums and q&a system and as far as I can see it just uses the .NET Framework runtime or Mono runtime. I cant find anywhere if Unity3D is using Mono also for windows machines. Besides that there is no special things Unity does with the code. Just just takes the CIL generated by Visual Studio or MonoDevelop. There seem to be some overhead on using Javascript or Boo cause that requires extra libraries to be included in the dll's, I guess the whole DLR thing. Unity makes no optimalizations or any sort to the CIL generated.

    In the end I will just go and learn my way around, hoping that things now and then go horribly wrong as those are the points you normally learn the most
    Last edited by Project-A; 02-16-2011 at 05:14 AM.
    Bug? That's not a bug, that's a feature.
    LinkedIn - Twitter (dutch) - Work (dutch)

  10. #10
    Join Date
    Nov 2009
    Location
    Dallas, Texas
    Posts
    170
    Yes, startup code is probably ok for reflection and it's only a demo so i'm not trying to be difficult, just offering up some issues I've run into when doing this kind of thing on a production game.
    Actually, I think business app dev experience is really useful and many game devs could learn something from the industry if they're willing to listen. It is very true that each industry is solving different kinds of problems so things that are important for one industry are not as important for another. In business app dev, memory is cheap and performance is important to a point. In games memory is a sacred resource that should never be wasted and making proper use of every CPU cycle can make or break you in some cases. Also games care more about fun, which is very subjective and requires different development processes than a business application where less subjective functional requirements drive development.

    When I was in the business world I was told to work on a system and then I would work with the client to generate a set of functional requirements for my team to work from. In games you're told something like, "it would be really coold to have ambient creatures running around the world to make the game world seem more alive.". That's it. No spec, just a simple sentence and then you have to try and make some kind of data-driven, ambient animation system so that designers can make the world come to life. If the fun factor isn't there then your work is thrown out or tweaked until the "fun" meter is at 100, which totally depends on a designers whim. This is the only reason I made the suggestions I did. It's mostly from a best practice point of view not a "this-is-the-right-way" point of view. In fact, if everyone always followed best practices we wouldn't have best practices in the first place .

    At some point, someone has to be a pioneer and discover new and better ways of doing things so I hope my suggestions weren't taken as the "right" way to do something. The only "right" way to do anything is the way that works . One nice thing about not having games industry experience is that there will be lots of outside-the-box thinking. I'm really looking forward to seeing all the cool ideas people come up with .
    Last edited by jjguzzardo; 02-19-2011 at 05:24 PM.

Page 1 of 2 12 LastLast

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •