bryanedds / nu Goto Github PK
View Code? Open in Web Editor NEWRepository hosting the open-source Nu Game Engine and related projects.
License: MIT License
Repository hosting the open-source Nu Game Engine and related projects.
License: MIT License
Unfortunately, due to the pure functional nature of the engine, a modern CPU is soaked at 60FPS once Nu has around 5000 active entities on screen (not counting rendering). This is due to the sheer overhead of functional transformations necessitated by the engine's design. It should be noted that there are no GC performance issues at this level, either in terms of latency or throughput.
Sadly, to achieve the processing bandwidth needed to support large commercial games, that number about an order of magnitude too small.
It is my conclusion that there are no remaining available optimizations that could put this game engine into a range of supporting the 25,000+ entities needed to support large commercial games.
Therefore, due to the limitations imposed by the design of this engine, Nu cannot support large commercial games.
This issue cannot be resolved with existing technology.
As programs increase in their implementation footprint, it is wise to constrain the ways in which its components interact. To that end, I believe Nu should implement a unidirectionality for its simulant operations.
To achieve this, the World shall have a new field called 'Context' that is an Address of the simulant that is receiving either an event or dispatcher callback. If that simulant attempts to access a property of another simulant higher in the hierarchy (EG - an entity attempts to access its group's Specialization property) or a simulant attempts to access a property of another simulant in an unrelated hierarch (EG - a group attempts to access a group in another screen), a run-time exception will be raised.
Still, the system must permit some circularity; EG, entities should be allowed to access and modify the properties of an entity in the same group.
For efficiency purposes, it should be possible to disable this unidirectionality checking, at least in Release builds.
As a final caveat, an argument could be made to only restrict simulants from modifying other simulant properties rather than also restricting their get-only access.
On page 6 in the guide it says to save your project under ./UserProjects/UserProjects.
This hasn't for worked for me since I VS13 creates a project with the structure Test/Test, so all the references of the dlls will be off.
If I save it to ./UserProjects it works fine ๐
Though the Effect systems currently has emitters that can act a bit like particles, neither its execution model nor its semantics model support what we really need from a particle system.
Whereas the Effect system's semantics is based on Key Frames and Tweens on transient State over time, a Particle system needs to be modeled as a series of Forces on a persistent State over time.
However, note that these particles won't be light-weight like GPU particles, but purely done on the CPU, and in the functional style. This system is more so meant to be powerful and expressive rather than performent.
An efficient GPU particle system is a separate feature.
Unfortunately, I could not get this done in time for v1.0, so leaving this issue here for now.
EDIT: make sure to understand the context provided in this comment before proceeding - #50 (comment)
Unfortunately, one cannot subscribe to when only a specific Participant property changes, but only that a change to that Participant happened in general.
This is inefficient because the a lot of change handlers are going to be hit superfluously.
This presents semantic issues because Observation.noMoreThanOncePerUpdate doesn't discriminate based on the getter for the property it is passed.
The fix is to make change events include the name of the changed property in the event address. This is a difficult fix, and will cause some non-trivial API breakage, all the way down into Prime.
However, there is no other fix or reasonable work around; the problem must be solved correctly.
I have yet to make it such that mounted entities have their world and local properties swapped when mounting. When an entity is mounted in Gaia, its position becomes that of its parent's, which might be confusing and / or inconvenient to users. However, fixing this is a bit of a PITA and has some pitfalls when the mounted entity doesn't exist.
I like how Unity allows layer organization via nodes, so I created a NodeDispatcher. In addition to that, the entity tree view in Gaia should also display entities according to their mount state.
Nowadays, I use 'Double-Cone Design' for all my software as explained here - https://medium.com/@bryanedds/double-cone-design-ddc8e5f23432
While Nu fully leverages the 'data abstraction' aspect of the above approach, it only 2/3 uses of the 'symbolics' aspect.
Unfortunately, at the top level, simulants themselves (as well as their overlays and, less significantly, the asset graph) are represented with more of a 'document model' style, and serialized with XML. Due to the document model-style, top-level types like simulants are not implemented as elegantly and with as little code as they should be. Also, due to the use of XML as the intermediate representation format (rather than symbolic expressions), symbolic manipulation is made much more difficult, if not outright impractical for certain things. Further, the end user of the engine may have to, at certain points, have to deal with XmlDocument objects directly, and that's never a good or simple experience.
nt
Performing an undo of the most recent operation may actually save the editing session.
Is there any plans to support WebGL with FunScript usage?
I attempt to fix the issue by updating SDL a while back, but that made the issue worse.
Perhaps the latest version of SDL will fix the issue. If not, then I presume I'll have to find some way to intervene programmatically with the windows messages themselves.
I'm not sure this is even possible without compilation... but it may become necessary.
The current pretty printer is really weak and works very poorly for script code. Instead, the prettyPrint functions needs to be rewritten so that it can -
Either put all peer symbols on same line, or each on their own newline, and
Only insert newlines when one of symbol depth > 1.
This isn't perfect for script code, but does yield the following improvement -
; Zip two containers by the given zipper function.
[define
zipBy
[zipper ctr ctr2]
[let
[opt [tryUncons ctr]]
[opt2 [tryUncons ctr2]]
[if
[|| [isNone opt] [isNone opt2]]
[toEmpty ctr]
[cons
[zipper [fst! opt] [fst! opt2]]
[zipBy zipper [snd! opt] [snd! opt2]]]]]]
With a special case that allows rule 1 to be violated when indention = 1 -
; Zip two containers by the given zipper function.
[define zipBy [zipper ctr ctr2]
[let
[opt [tryUncons ctr]]
[opt2 [tryUncons ctr2]]
[if
[|| [isNone opt] [isNone opt2]]
[toEmpty ctr]
[cons
[zipper [fst! opt] [fst! opt2]]
[zipBy zipper [snd! opt] [snd! opt2]]]]]]
I think the latter should be good enough for code, at least.
Currently quotes are parsed like sigma', but should be parsed like
sigma. Fix this!
Over the life of Nu, I never recorded sprite rendering as a bottleneck in Nu. But now that I've done the most important CPU optimizations, it sticks out by a large factor!
Fix this, likely by replacing SDL2 with bgfx - https://github.com/bkaradzic/bgfx
Fix this!
The "Documents" folder in Windows is not neccesarily located in the folder given by %userprofile%
. The install script is ineffective in such a case, as the script copies the template zip to "%userprofile%\Documents\Visual Studio 2015\Templates\ProjectTemplates"
Although there no environment variable for this folder AFAIK, switching to a PowerShell script would solve this as [Environment]::GetFolderPath("mydocuments")
does return the correct path (at least on Win10).
Calling these have never felt right... find an intuitive, logical, and consistent parameter order for them,
When an event is intended to Resolve, and thereby 'swallow' an event so that no other handlers receive it, its subscription must happen prior to these other handlers'. However, the Resolving event for mouse and keyboard input for screen transitions perform their subscriptions on an as-needed basis. The solution is to have these subscriptions set up at the start of the program and have the handling result vary depending on whether a screen transition is occurring.
I can start BlazeVector, but as soon as I press Play the game crashes in https://github.com/bryanedds/FPWorks/blob/master/Nu/Nu/Nu/NuMath.fs#L36.
The problem is that it tries to parse
System.Single.Parse "-15.6805";;
When I try
System.Single.Parse "-15,6805";;
(notice the comma) it works.
The problem might be that we are in a locale (Switzerland) that uses dots as a decimal separator.
Currently it's not and becomes hard to debug and can blow the stack in many desirable use cases.
The first pass of implementation is in there, but it never worked. It's extremely confusing to implement, so I'm not sure how to proceed...
In order to specify that a property is not persisted (and doesn't publish its changes), its name is appended with 'Np'. To specify that a property always publishes its changes, its name is appended with 'Ap'. Thus, we end up with properties with names like 'FacetsNp' and 'OnRegisterAp'. This is not only unsightly, but can also be a source of bugs in script code when someone forgets what convention a given property is using.
The ideal solution is to have some way to specify Xtension property attributes other than by naming convention.
Investigate the feasibility of this.
Also do the outstanding P1 todos as that will help GC as well.
It may actually be a pessimization due to it actually increasing cache-misses!
If it doesn't affect performance measurably or is a pessimization, inline the types into World.
One thing that has been bothering me for a while is how groups can't contain groups, and that entities can't contain entities. This design limitation can be solved by combining the the functionality of a group with that of an entity. So, we'll get rid of the Group type and make a special entity dispatcher called GroupDispatcher.
The big change caused by this is that the length of entity addresses is not longer an exact number, but can vary depending on nesting. Fixing all the places the hard-code this will be somewhat error-prone.
This will also, of course, impact user data files.
It is unknown whether each Screen should be created with a default Group entity or not.
Hi, I'm trying to get started with the nu engine:)
I've cloned your repo and openened BlazeVector.sln. I checked that BlazeVector is the startup project.
When I try to build the project I get the following error:
7>Build FAILED.
8>------ Build started: Project: NuEdit, Configuration: Debug Any CPU ------
8> C:\Program Files (x86)\Microsoft SDKs\F#\3.1\Framework\v4.0\fsc.exe -o:obj\Debug\NuEdit.exe -g --debug:full --noframework --define:DEBUG --define:TRACE --doc:bin\Debug\NuEdit.XML --optimize- --tailcalls- --platform:x86 -r:"C:\Program Files (x86)\Reference Assemblies\Microsoft\FSharp\.NETFramework\v4.0\4.3.0.0\FSharp.Core.dll" -r:"C:\Users\joris\Documents\Visual Studio 2013\Projects\FPWorks\Nu\FSharpx.Core\FSharpx.Core.dll" -r:"C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.5\mscorlib.dll" -r:"C:\Users\joris\Documents\Visual Studio 2013\Projects\FPWorks\Nu\Nu\Nu\bin\Debug\Nu.exe" -r:"C:\Users\joris\Documents\Visual Studio 2013\Projects\FPWorks\Nu\Nu\NuEditDesign\bin\Debug\NuEditDesign.exe" -r:"C:\Users\joris\Documents\Visual Studio 2013\Projects\FPWorks\Prime\Prime\Prime\bin\Debug\Prime.exe" -r:"C:\Users\joris\Documents\Visual Studio 2013\Projects\FPWorks\Nu\SDL2#\Release\SDL2#.dll" -r:"C:\Users\joris\Documents\Visual Studio 2013\Projects\FPWorks\SDL2Addendum\SDL2Addendum\SDL2Addendum\bin\Debug\SDL2Addendum.dll" -r:"C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.5\System.Core.dll" -r:"C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.5\System.dll" -r:"C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.5\System.Drawing.dll" -r:"C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.5\System.Numerics.dll" -r:"C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.5\System.Windows.Forms.dll" -r:"C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.5\System.Xml.dll" -r:"C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.5\System.Xml.Serialization.dll" -r:"C:\Users\joris\Documents\Visual Studio 2013\Projects\FPWorks\Nu\TiledSharp\Release\TiledSharp.dll" --target:exe --warn:3 --warnaserror --warnaserror:76 --vserrors --validate-type-providers --LCID:1033 --utf8output --fullpaths --flaterrors --subsystemversion:6.00 --highentropyva+ --sqmsessionguid:cc665991-ad3c-4800-9208-50410f3e6d40 --warnon:1182 "C:\Users\joris\AppData\Local\Temp\.NETFramework,Version=v4.5.AssemblyAttributes.fs" NuEditConstants.fs NuEditReflection.fs Program.fs
8> NuEdit -> C:\Users\joris\Documents\Visual Studio 2013\Projects\FPWorks\Nu\Nu\NuEdit\bin\Debug\NuEdit.exe
8> C:\Users\joris\Documents\Visual Studio 2013\Projects\FPWorks\Nu\Nu\NuEdit\..\..\..\Nu\Nu\NuPipe\bin\Debug\NuPipe.exe C:\Users\joris\Documents\Visual Studio 2013\Projects\FPWorks\Nu\Nu\NuEdit\ C:\Users\joris\Documents\Visual Studio 2013\Projects\FPWorks\Nu\Nu\NuEdit\bin\Debug\
8> 'C:\Users\joris\Documents\Visual' is not recognized as an internal or external command,
8> operable program or batch file.
8>C:\Program Files (x86)\MSBuild\12.0\bin\Microsoft.Common.CurrentVersion.targets(4429,5): error MSB3073: The command "C:\Users\joris\Documents\Visual Studio 2013\Projects\FPWorks\Nu\Nu\NuEdit\..\..\..\Nu\Nu\NuPipe\bin\Debug\NuPipe.exe C:\Users\joris\Documents\Visual Studio 2013\Projects\FPWorks\Nu\Nu\NuEdit\ C:\Users\joris\Documents\Visual Studio 2013\Projects\FPWorks\Nu\Nu\NuEdit\bin\Debug\" exited with code 9009.
8>Done building project "NuEdit.fsproj" -- FAILED.
8>
8>Build FAILED.
9>------ Skipped Build: Project: NuTemplate, Configuration: Debug Any CPU ------
9>Project not selected to build for this solution configuration
========== Build: 5 succeeded, 3 failed, 1 up-to-date, 1 skipped ==========
Do you have any idea how I could fix this?
Thanks!
Current potential performance issues in Nu, in no particular order -
Potential Issue - Event handlers in a dictionary are slower than handlers on the subscribed object a la C#. This means a look up for every publish. However, this is an artifact of a publisher-neutral event system rather than anything related to FP.
Possible Solution - A lot of optimization is already done to avoid publish calls that won't have a useful effect. Beyond these, I have yet to think of further solutions.
Potential Issue - Farseer Physics Engine doesn't scale to 1000s of interacting bodies - Genbox/VelcroPhysics#29
Possible Solution - Presumably Farseer could be replaced with a much faster 2D physics lib, perhaps one written in C or C++. Of course, the question then becomes about the overhead of the required marshalling.
Potential Issue - The string hashing required for each Xtension property look-up is suboptimal.
Possible Solution - Not many practical ones. This issue wouldn't exist if .NET lazy-cached hashes in strings, but there's no reason to believe it ever will. At one point I used an alternative type to string called 'Lun' (later called 'Name') which contained a string and its eagerly-computed hash, but it wasn't very friendly to use. I decided to get rid of it in favor of .NET strings to simplify Nu's API. I'm pretty sure this was the right decision, but I can't prove it one way or another without making large speculative changes to the engine.
Update - Now that F# finally has implicit ctors, reintroducing the Name type shouldn't cause as many changes as it previously would have. This might now be a practical experiment to run.
Potential Issue - LOH threshold is perhaps too small.
Possible Solution - Upgrading to >= .NET 4.8 will allow us to configure it via GCLOHThreshold
- https://docs.microsoft.com/en-us/dotnet/framework/configure-apps/file-schema/runtime/gclohthreshold-element
Update - I've tried increasing LOH, but I cannot observe it having any effect. It's like my attempt is being ignored by the runtime.
Potential Issue - Potentially a lot of events when a subscribed entity transforms -
Nu/Nu/Nu/World/WorldModuleEntity.fs
Lines 177 to 227 in 0b63f40
Possible Solution - Probably nothing great. Could selectively disable a chunk of transform events depending on the application. Not real sure what to do here other than assess that this is part of the cost of doing business declaratively.
Potential Issue - Synchronizing entity properties via World.setEntityPropertyFast
requires a small and likely cache-local dictionary look-up via WorldModuleEntity.EntitySetters
, which is surprisingly fast.
Possible Solution - A faster alternative might be hard-coding a duplicate of the EntitySetters table in a match expression or using a loftier technique such as code generation in the MVU implementation.
Potential Issue - Nu Text rendering might be quite inefficient due to not caching target render buffers. IIRC, render buffers use for text are allocated and deallocated on a one-off basis. I do not see how that could possibly scale well.
Possible Solution - Code it properly. :)
Potential Issue - Only seems to cause a couple small hiccups at the start of programs, but currently .NET GC compaction is not yet parallelized and therefore can cause stalls while it does its thing. This doesn't seem to happen once Nu programs hit their steady state after a couple seconds. Fortunately, according to the .NET team, it appears that parallel compacting is being implemented.
Possible Solution - Wait for parallel compacting GC to ship (.NET 9?). Otherwise, issue GC.Collect between scenes if needed to.
Potential Issue - Bullet Physics out-of-box kinematic character controller does not scale beyond a dozen instances or so.
Possible Solution - Maybe we can roll our own faster kcc somehow?
Potential Issue - Setting physics properties after creating an entity, such as is done by the MMCC initializers, can cause a lot of body recreation inside the physics engines due to the way that RigidBodyFacet's property change handlers work.
Possible Solution - Instead of recreating the physics bodies, create addition body property synchronization messages to make body recreation less often necessary.
'Crayon' in the context of licensing - http://opensource.stackexchange.com/questions/1445/how-can-a-crayon-license-be-a-problem
It was suggested to have two licenses for the repo, one closed license for the assets, and an OSI one for the text / code.
Figure out a way to do this ASAP!
Invsitagate and fix.
Wonder how long this has been broken?
If so, where? If not, can you demonstrate?
We could probably improve the event system's efficiency in a sane way by using contiguous data structures a bit more. EG - store like subscriptions in an array (or UList) rather than a list, and consider using arrays in Addresses rather than lists.
Those two improvements would probably get the event system into an optimal state.
All that's left is the Either type and the following intrinsic functions -
substring update curry compose sort replace slice split
No more than two days of work!
The performance of the Quadtree is one of the engine's potential bottlenecks, and we should play with the notion of 16-trees instead to see if performance improves.
I got a good start on the scripting language implementation, but halted due to not needing it for my current game and limited resources.
Be good to have this really cool dynamic FRP scripting language working one day, tho :)
As said.
Just thinking about a write thread and read running at the same time.
If they both get the original list from validate but the write thread updates ImpList before the read. Then the read thread will see this update and later see it without the update if it reruns and validate calls commit and rebuilds from the logs.
Nu is built to be 100% cross platform, but it has yet to be compiled, deployed, and tested on environments other than Windows due to lack of developer time. Will probably take a solid 3-5 days to get it deployed and tested on all platforms.
Pull requests for individual platforms would also be great!
This will include moving out Nu's event system to Prime, and documenting all public stuffs.
Approx. one week of work.
For now, the workaround is to just use keyboard events.
Two things make event debugging hard in Nu -
The chain monad pollutes the call stack really quickly because it's not tail-recursive.
It's too hard to identify from where an event originates when using the Observation arrow. FIXED
Fix issue 1 by making the chain monad tail-recursive.
Fix issue 2 by finding a good place to add metadata to subscription entries or somewhere.
Currently, World.writeEntity and readEntity employ overlays to achieve their results. There are easily-imagined cases where the usage of overlays is not needed or desirable.
What is needed is some well-factored way to access that functionality in both forms via Nu's public API.
This occurred when implementing the mutant cache optimizations, and needs to be fixed straight away.
Possibly less copy paste? I'm not 100% sure this does what the previous code does since I don't fully understand the whole thing, but decided to take on the task after watching your last vlog as an excercise.
let nameIn<'T> (property : PropertyInfo) =
typeof<'T>.GetProperty (property.Name, BindingFlags.Instance ||| BindingFlags.Public) = property
let getEntityModelPropertyValue (property : PropertyInfo) (entityModel : EntityModel) =
match entityModel with
| Button _ when nameIn property -> property.GetValue (get entityModel EntityModel.button)
| Label _ when nameIn property -> property.GetValue (get entityModel EntityModel.label)
| TextBox _ when nameIn property -> property.GetValue (get entityModel EntityModel.textBox)
| Toggle _ when nameIn property -> property.GetValue (get entityModel EntityModel.toggle)
| Feeler _ when nameIn property -> property.GetValue (get entityModel EntityModel.feeler)
| Block _ when nameIn property -> property.GetValue (get entityModel EntityModel.block)
| Avatar _ when nameIn property -> property.GetValue (get entityModel EntityModel.avatar)
| TileMap _ when nameIn property -> property.GetValue (get entityModel EntityModel.tileMap)
| _ when nameIn<Gui> property -> property.GetValue (get entityModel EntityModel.gui)
| _ -> property.GetValue (get entityModel EntityModel.entity)
I'm not sure if the "nameIn" function is inferring the right type (still lots of unknown for me in fsharp), but if it isn't it could just be set explicitly.
P.S. probably not the best name for that helper function.
Hello
I need to make a game for uni and would like to test the Nu Game Engine.
Now I was wondering why the engine is in the same repo as everything else :)
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.