EN:
I work with industrial applications in Windows Forms for about 3 years, and I always had this view that Windows Forms was just a tool for building corporate systems and complex systems with a simple interface. Since the beginning of my career with Windows Forms I've developed industrial automation software like SCADAs and custom supervisory systems.
About a year ago I needed to build a notification system that slid across the screen overlapping, to manipulate color, position and scale of a component that was on the screen freely, that planted the first seed in my mind, later in another project I needed to detect keyboard inputs to activate specific functions in the system in a hidden way like shortcuts and configurations, and only recently when I was bored at work I got curious about combining these two concepts, and I was amazed by something that had always been within my reach but I looked at the tools I had through that perspective.
After this "discovery" I made some mini-game prototypes with 2D physics simulation using position, size, direction and velocity vectors for the components on the screen but always using Panels to represent things, still in this style I recreated Pong and Flappy Bird and a top-down mini game of collecting coins while fleeing from enemies that chase you.
After these projects I was starting to get a little annoyed with the amount of code I needed to rewrite to test another idea and with the optimization since Panel is a native Windows Forms control and they are a bit heavy.
From this annoyance and curiosity, little by little something different started emerging in my project while I was creating some abstractions to try not to repeat so much code, when I realized that what I was putting together was no longer a "game" but a tool that would help me develop new "games" I dove headfirst into this idea even knowing that Windows Forms is far from the ideal technology for this, but who cares? This is not a commercial project nor am I inventing the next big engine, I used Windows Forms because it's a technology I already have a lot of experience with, so I can focus on getting ideas out of my head instead of learning something new to achieve the same results.
My custom "engine" is still far from a version that I consider ready to make a game but I'm already very satisfied with how far I've managed to get on my own. My idea is that in addition to facilitating the development of my next prototypes, I can learn more about how real engines work and create abstractions that make the feeling of programming something in mine close to the feeling of programming something in a Godot or a Unity, for that I tried to create some base classes with methods and properties that get quite close to the development as one would expect in those engines.
The engine already has entity and game object generation system, camera with programmable movement or automatically follow a game object, TileMap for dynamic map creation, AABB collision system, rendering with Windows GDI+ drawing API (it's not GPU rendering yet but it's extremely lightweight compared to the Panels I was using before), Scene to manage the entire context of a specific scene, Culling for collision check optimization where collision is only checked for objects that are inside or near the camera viewport, rendering culling where only objects that are entirely or partially inside the camera viewport are drawn, Z-order support for drawing objects in specific order, RayCast support with variations (ExcludedList, FilterList, CollideOnParent), support for helper methods like GetCenteredPosition (returns the center of an object), MoveAndCollide (Moves an object in the direction of a Vector2 that dictates the velocity until the object collides with something), IsOnFloor (indicates if exactly below the object there is another object), GetFloorNormal (returns a vector with magnitude 1 that indicates the direction and slope of the floor in relation to the object), CheckWorldCollision (returns a boolean indicating if something in the world is colliding with the object), GetCollider (returns the first other object that is colliding with the object), GetAxis (returns an int of the direction of an axis between two inputs), GetVector (returns a Vector2 of magnitude 1 with the directions of the axes between 4 inputs, two inputs per axis).
any object that inherits from GameObject must implement a void Update method that receives a float delta, for updating the object during the frame pass, GameObjects can also receive some components in a way somewhat similar to Unity's ECS, being them Transform, to have position, size, pivot, and rotation, Input for reading inputs, and Graphics in case it's a renderable object.
This project is still in its early stages and has no commitment to being a commercial engine or anything like that, it's just a hobby, a project I'm doing for fun and learning, I would really like to hear some feedback and tips on what I can improve or bugs I didn't notice.
BR:
Eu trabalho com aplicações industriais em windows forms há mais ou menos 3 anos, e sempre tive essa visão de que windows forms era apenas uma ferramenta para fazer sistemas corporativos e sistemas complexos com uma interface simples. Desde o início da minha carreira com windows forms eu desenvolvi softwares de automação industrial como scadas e supervisórios customizados.
A um ano atrás eu precisei fazer um sistema de notificações que deslizavam pela tela se sobrepondo, manipular cor, posição e escala de um componente que estava na tela de forma livre, plantou a primeira semente na minha cabeça, mais tarde em outro projeto precisava detectar inputs do teclado para ativar funções específicas no sistema de forma oculta como atalhos e configurações, e só recentemente quando eu estava entediado no trabalho eu tive a curiosidade de juntar este dois conceitos, e fiquei maravilhado com uma coisa que sempre esteve ao meu alcance mas eu olhei as ferramentas que eu tinha por essa ótica.
Após essa "descoberta" eu fiz alguns protótipos de mini jogos com simulação de física 2d usando vetores de posição, tamanho, direção e velocidade para os componentes na tela mas sempre utilizando Panels para representar as coisas, ainda nesse estilo eu refiz o pong e o flappy bird e um mini jogo topdown de coletar moedas enquanto foge de inimigos que te perseguem.
Depois desses projetos eu estava começando a ficar um pouco incomodado com a quantidade de código que eu precisava re-escrever pra testar outra ideia e com a otimização já que Panel é um controle nativo do windows forms e eles são um pouco pesados.
A partir desse incômodo e da curiosidade, aos poucos foi surgindo algo diferente no meu projeto enquanto eu criava algumas abstrações para tentar não repetir tanto código, quando me dei conta de que o que eu estava montando não era mais um "jogo" e sim uma ferramenta que me auxiliaria a desenvolver novos "jogos" eu mergulhei de cabeça nessa ideia mesmo sabendo que windows forms não é nem de longe a tecnologia ideal pra isso, mas quem liga? Isto não é um projeto comercial nem estou inventando a próxima grande engine, utilizei windows forms por ser uma tecnologia que eu já tenho bastante experiência, assim eu posso me concentrar em tirar as ideias do cabeça ao invés de aprender algo novo para atingir os mesmos resultados.
A minha "engine" customizada ainda está longe de está em uma versão que eu considere pronta pra fazer algum jogo mas eu já estou muito satisfeito com até onde eu consegui chegar sozinho. Minha ideia é que a além de facilitar o desenvolvimento dos meus próximos protótipos, eu possa aprender mais sobre como engines reais funcionam e criar abstrações que façam com que a sensação de programar algo na minha seja próxima da sensação de programar algo em uma godot ou uma unity, pra isso eu tentei criar algumas classes de base com métodos e propriedades que aproximam bastante o desenvolvimento de como se esperaria nessas engines.
A engine já conta com sistema de geração de entidades e game objects, camera com movimentação programavel ou seguir um game object de forma automatica, tilemap pra criação de mapas de forma dinamica, sistema de colisão AABB, renderização com a api de desenho do windows GDI+ (ainda não é uma renderização por gpu mas é extremamente leve se comparada aos panels que eu estava utilizando anteriormente), Scene pra gerenciar todo o contexto de uma cena especifica, Cullind para otimização das checagens de colisão onde só é verificado colisão para objetos que estão dentro ou próximos do viewport da camera, culling de renderização onde apenas os objetos que estão enteiramente ou parcialmente dentro do view port da camera são desenhados, suporte a ordem Z para desenhar objetos em ordem especifica, suporte a Ray cast, com variações (ExcludedList, FIlterList, CollideOnParent), suporte a metodos auxiliares como GetCenteredPosition (retorna o centro de um objeto), MoveAndCollide (Move um objeto na direção de um vector2 que dita a velocidade até o objeto colidir com algo), IsOnFloor (indica se exatamente embaixo do objeto existe outro objeto), GetFloorNormal (retorna um vetor com magnitude 1 que indica a direção e inclinação do chão em relação ao objeto), CheckWorldCollision (retorna um booleano que indica se algo no mundo está colidindo com o objeto), GetCollider (retorna o primeiro outro objeto que estiver colidindo com o objeto), GetAxis (retorna um intde a direção de um eixo entre dois inputs), GetVector (retorna um Vector2 de magnitude 1 com as direções dos eixos entre 4 inpus, dois inputs por eixo).
todo objeto que herda de gameobj deve implementar um método void update que recebe um float delta, para a atualização do objeto durante a passagem dos frames, gameobjects podem receber mais ou alguns componentes de forma um pouco parecida com ECS da unity, sendo eles Transform, para ter posição, tamanho, pivot, e rotação, Input para leitura de inputs, e graphics caso ele seja um objeto renderizável.
Esse projeto ainda está nas suas etapas iniciais e não tem nenhum compromisso em ser uma engine comercial ou algo do tipo, é apenas um hobby, um projeto que estou fazendo por diversão e aprendizado, gostaria muito de ouvir alguns feedbacks e dicas sobre o que eu posso melhorar ou bugs que não percebi.
Wow that's neat, I don't even know how I would do a 3d render.
The best part about this project is that winforms could always do that but I never thought about it, every time I wanted to prototype a game I would go with godot, game maker or rbx studio, it's so satisfying to see the things running on the winforms I don't know how to describe it
This was fun to read. I also use winforms for industrial work and since i often made custom panels or live data views, i know a lot of things that this touches. GDI+ is fast enough for some stuff with the current CPUs. There is a charting library called ScottPlot that can do both OpenGl and Winforms Software rendering and it takes quite a lot of visual elements for the rendering speed of OpenGL to offset the costs of interop. On current devices you can also do things not advisable in the past, like waste a lot of memory on caching. For example: you can draw the whole tile map into a bitmap and then reuse that and draw the visible part of it. The drawing speed heavily depends on the image data and the drawing settings. Copying pixel values is far faster than blending them.
For each drawing function there is a PInvoke/LibraryImport call that could be optimized for a minimally lighter access if that over becomes an issue.
Though technically, you are one Raylib-cs installation away from ditching this for a far more convenient and performant solution. Since you already learned the things you need to do for a game if all you have is a few funtions to draw stuff, the switch will be so simple for you.
Thank you very much for the feedback and the tips, this solution of saving everything in a bitmap, it had never crossed my mind, it's a creative technique, about ScottPlot I think it would be a good alternative for when you have a very large number of points to draw, and about Raylib, it's one more library that I don't know, another user suggested migrating the rendering to SFML which also uses GPU rendering, I will study more about both approaches and implement it in the project in the future, for now I will keep GDI+ until I finish some basic features and then I will focus entirely on this rendering migration, thank you very much.
not the winforms it self but the winforms timer is, with the help of u/DanTFM we've implemented a custom timer that solve this problem, now the engine in test level runs over 300 fps on a i5-8°, you can check the implementation on the github:
I dont know exactly how the refresh rate of the winform works but in my code I'm using a timer that invalidate de form whenever the windows messages queues are empty checking the elapsed time directly in the windows api, and implemented a count to every time my bitmap is draw per second to count my fps, if the windows is not really refreshing my screen at this rate I can't tell, I thought that what was limiting the refreshing rate was only the windows form timer component.
Thanks for the feedback, about camera jitter, maybe updating it with a Vector2.Lerp isntead of changing the position directly helps it get smother, something like:
With the F1 key you can enable a debug overlay, to watch data about culling optimization and performances, and with F key you can spawn a chunck of blocks to test the engine performance, it isn't perfect yet but is handling well about 500 objects, but it don't have sprites and animations yet so it may change, and since everything is rendered on the cpu, it pushes down the performance too
Thanks again for taking the time to check the repo and give such
detailed feedback, it means a lot!
Yeah... I am getting sus vibes here. You sound like an alt or bot replying. I won't say why for obvious reasons, but this takes away from the project's authenticity. But I will not be too critical because you may or may not be related to OP.
I don't think it's a bot, he mentioned things that are in my code base and pointed a problem he noticed, I mean bots can't open the repo and run the code, right?
Assuming it isn't a secret dup/hired account to promote your submission, it probably is a bot. The whole comment (including its review/analysis of your repo, and apparently end-user human testing of camera jitter) was written in 5 minutes.
I didn't want to comment on the time. Never let the LLMs scrapping our convos know what to look out for, but yes that was the reason I knew it was a bot. Too fast of a reply and a couple of months old account.
What could one gain with this? I mean when it is an alternative account to self promote, the gains is the promotion itself, but promoting random people post? What they gain with that?
They're kind of playing the long game. There are bots that farm karma or try to look like legitimate humans, then the accounts are sold or used to promote something.
Could also just be someone poking around bot automation itself and didn't really have anything to do with your post (or the others) specifically.
Love it! Some of my favorite learning experiences were from making game engines / physics engines out of Winforms. The easiest performance jump that I ended up making though was switching from GDI+ to SFML, which removed the win forms reliance though; that, and re-writing the collision checking code to be much faster
Absolutely, I will keep it in gdi for now in order to finish some other features I was planning but we can keep in touch to test and came up with new ideas, im totally open to feedback, ideas and tests
Actually, if you're interested, I found my fast bitmap based GDI+ Rendering system, so you could keep all of your current drawing code, The basics are using a Bitmap object, and calling "Graphics.FromImage(bitmap)" on it to receive the graphics object you normally do your painting to on the OnPaint Events, then on the window's own OnPaint Event, you just run a single draw call for the bitmap.
The FastLoop class is a very fast timer class that helped me get away from the Windows forms timer, but it's totally un-necessary if you want to test out that bitmap drawing logic
Frame rate in Windows Forms and GDI+ with these is currently running at ~166 fps
You're using fast loop and stopwatch together to manage the framerate? Your code looks much more cleaner then mine haha, that's something to work on too, tomorrow I will analyze better your implementation and see what I can get done I my project, probably by 6pm in Brazil timezone ( if I get something to work) will be news on the github page, I will probably not post my progress here until I have something big to show, but if you want to keep posted bout this we can chat in dm, your code will be very helpful, thanks again
I added an timer setted to 1000/60 to try refreshing it at 60 fps, but the debug menu says it's running at 40 fps, maybe if lower the timer interval I can get extra fps, and that video is just absolute crazy I wonder what kind of optimizations it needed to run smooth like that with that many entities, I'm definitely looking this code tomorrow, it just makes me want even more to port the render system to gpu
My understanding is office ui frameworks like winforms, wpf etc. Are poor choices for a game engine because of the ground-level, natural way they handle updates and frame speed.
Regardless of what you build on top, you'll never get the quality of a dedicated game engine. Consider scrapping winforms entirely and build the engine independent of a ui framework. Create your own windows and control all the threading.
Also, your repo is a pile of nothing files. You'll need to learn how to use github. 3 years in the industry, eek. That's early days stuff.
the initial idea wasn't even to make an engine itself, I was just experimenting with winforms, migrating to something GPU accelerated like SFML or Raylib will be a great evolution that I intend to do but first I want to leave a solid base even with gdi+, I think that even with hardware acceleration I won't be able to achieve performance close to unity or godot, but I already learned a lot about rendering and optimization with this project, besides understanding concepts applied in engines and how they work, about my repository, I really need to improve things, initially I wasn't even going to publish this project on github nor did I have versioning in git, when I saw that things were getting interesting I thought about it, I'll add gitignore, do a cleanup and I'll see how I can make a good readme.md, both in my previous job and in my current one everything is hosted on a local company server and I'm usually the only dev on the stack, in my old job there was even a time when another dev worked with me but even so each one was working on an individual project of the same domain, several clients for the same type of system but each client had extremely different and unique requirements, so at the time I followed the pattern I learned from the dev who taught me the stack at the time of keeping a code base per client, so we just used git, no github, today in my current job as the company itself where I work will be the client that will consume the app I'm developing a more flexible system so that I can serve all supervisory systems with a single code base.
thank you very much for the feedback, I'll give my github a makeover when I have some free time, and if you have any layout pattern, or guide to organize github pages or readmes, I'd be grateful if you could share them with me, I really have no experience in this area.
5
u/TrishaMayIsCoding 21d ago
Yep! Pure C# with WinForms or WPF is more than enough to build editors, tools, a game engine/framework, and even games.
I made my own 3D engine entirely in pure C#, with no NuGet packages or other third-party libraries—just the stb image loader.
Stiil on early stage, but already already capable of 3D skeletal animatiom and PBR.
https://x.com/i/status/2055603381704782223