I just took a few hours to do this in .NET making a WinForms game using just a Timer and the built-in System.Graphics namespace. The only thing it does is "spawn" 200 "balls" and draw them on the screen and handles moving all them at the same time. I just wanted to do this to get a rough idea of game loops and taking input wanted to bring it here for critiques. As written on my machine I get about 60 FPS. Some limitations already obvious to me is the entire scene is redrawn each frame. There is no "state" and therefore this is a huge performance hit. I noticed there was a weird flicker when drawing the circles so I implemented a sort of saved image ala double buffer style since setting the double buffer property in the WinForms designer did NOTHING to mitigate the flicker. Critiques wanted. Challenges sought.
All this code can be copied into a single code file if you want to run it yourself. My VS installation default to .Net 4 but nothing specific to the v4 framework is in here.
Let me know what you think!
using System;
using System.Collections;
using System.Collections.Generic;
using System.Drawing;
using System.Windows.Forms;
namespace Managed
{
public partial class Form1 : Form
{
List<Ball> balls = null;
List<Keys> keysPressed = null;
int fps = 0;
DateTime lastFPSUpdate;
Bitmap savedFrame = null;
bool showSaved = false;
Got an interesting problem that isn't obvious. I implemented a line in the circle that but the end goal of that line is to always point at the cursor. I've tied in the mouse location easily enough and can draw a line from the pointer to the center of the circle but I'm having problems figuring how to "clip" the line at the border of the circle. How do I detect where that is? Image is displaying what the code currently does. Also, here is a snippet of code from the Draw method in the circle.
This will give you the dot over the circle that points at the cursor.
Finally draw the line with the new point coordinates instead of the mouse position:
Not really sure what to say on this one as it depends on where you are taking it.
Maybe down the line if your 'game loop' requires some significant cpu time your UI (if you have any?) may become less/un-responsive if this is all happening on the UI thread which I am guessing it is, so perhaps need to consider a thread for the loop. Though this may in itself require alot of invokes to the UI thread since you are drawing objects it has created.
This will give you the dot over the circle that points at the cursor.
Finally draw the line with the new point coordinates instead of the mouse position:
Not really sure what to say on this one as it depends on where you are taking it.
Maybe down the line if your 'game loop' requires some significant cpu time your UI (if you have any?) may become less/un-responsive if this is all happening on the UI thread which I am guessing it is, so perhaps need to consider a thread for the loop. Though this may in itself require alot of invokes to the UI thread since you are drawing objects it has created.
I'm not really going anywhere with this, per se. I just wanted to try, from scratch, to create a program that draws to the screen constantly and takes input that modifies what is drawn, the most basic interpretation of a modern game application, using something I already knew which happens to include C# WinForms. I wanted to present it here hoping to have responses like "hey doing this is dumb do it this way instead" trying to crowdsource some of my education. I am trying to include some multi-threading like you mentioned. Ideally I'd like to get the entire "game loop" on a separate thread. Something interesting I saw is that when I was using my timer-based approached changing the tick number from 15 to 20 cut my FPS in half. Then again, my FPS tracking mechanism may be faulty or not as accurate as it could be.
Okay, some good news. I successfully paralleled the game loop away from the UI thread and am seeing framerates of upwards to 200+. The bad thing is the math for drawing the line that's supposed to point at the cursor is wrong. By wrong it points towards the upper left (0,0 coords) always. Attached is another screen shot. For the screen shot I had the mouse pointer almost directly opposite the point where the line intersects the circle and had the pointer very close to the border of the circle (>50 pixels). Any clues? Also pasted in is the code I've used. If you can spot something that just acts backwards or can be done better I'm open to suggestions!
using System;
using System.Collections;
using System.Collections.Generic;
using System.Drawing;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace Managed
{
public partial class Form1 : Form
{
List<Ball> balls = null;
List<Keys> keysPressed = null;
int fps = 0;
DateTime lastFPSUpdate;
Bitmap savedFrame = null;
bool showSaved = false;
Point mouseLocation;
Task GameTask;
Rectangle window;
this.KeyDown += new KeyEventHandler(Form1_KeyDown);
this.KeyUp += new KeyEventHandler(Form1_KeyUp);
this.MouseMove += new MouseEventHandler(Form1_MouseMove);
doUpdate = new UpdateFPS(ChangeFPS);
drawImage = new UpdateImage(DrawImage);
So, I took the Task library a bit further and used a Parallel.ForEach to parallel-ize the actual drawing of each circle. I noticed the following was actually a performance hit:
The hit is for two reasons. 1) I'm iterating a loop twice and I'm locking on g (the Graphics object) so regardless of how many threads is trying to "draw" g is only accessed once and because of the splitting of the threads the overhead from so much context switching in the Kernel that it's actually slowing me down. I figured I'd give this a shot because given this context it didn't matter what was drawn when since they're all on "top" of each other anyway. I think I'm going to try to do some detection and see if a point is occupied by all the objects to only draw any certain pixel once. This will bottleneck me somewhat but I suspect I could have this application generate several thousand circles and have the same performance of my current cap which seems to be about 200 or so, if done right. So, I'll be trading initial speed for scalability of how much this app can handle.
Note: You may need to adjust some signals because c#'s coordinate system is not the 'standard' one but now the line might not cross the circle. I'm almost certain that you have to flip Y but try it and let us know how it goes
Note: You may need to adjust some signals because c#'s coordinate system is not the 'standard' one but now the line might not cross the circle. I'm almost certain that you have to flip Y but try it and let us know how it goes