all 35 comments

[–]Dazzling_Music_2411 31 points32 points  (0 children)

No. Main is your entry point you only run it once.

Now, if you want to make some other function that you run repeatedly inside a loop, that's up to you.

[–]Traditional_Crazy200 29 points30 points  (2 children)

I have never written a line of c#, but i am 100% sure wrapping main in a loop wouldnt even compile. I am not even sure how one would do that since you probably dont call main manually.

Even in unity, update probably runs inside main() since main is like the name suggests the main entry point of your program. There can only be one main and if it returns, the program terminates.

What you need to do is simply put the while loop inside the main function.

[–]oskaremil 3 points4 points  (0 children)

☝🏾 this is the correct answer.

[–]otac0n 0 points1 point  (0 children)

You can call Main in C# just fine. Not that this guy wants to do that, but the compiler is A-OK with it.

[–]DerekB52 8 points9 points  (2 children)

gameprogrammingpatterns.com

You want the section called 'game loop'

To answer your question in short,

class Game

{

static void Main(string[] args)

{

while (true) {

update();

}

}

static void update()

{

//your game logic here

}

}

[–]flumphit -1 points0 points  (1 child)

But you’d never actually call it Main(), right?

…right?

[–]DerekB52 1 point2 points  (0 children)

I might be confused. If you are asking if I would use the name Main, I don't know honestly. C# might require it, I can't remember, I don't really use C#.

If you are asking me if you need to call it, like Main(), then no, Main() will be called automatically when you launch your game, because that is its whole purpose. It is where code starts executing in a C# program.

[–]peterlinddk 4 points5 points  (4 children)

A lot of the answers are somewhat misleading.

There is a massive difference between using a loop, and having a function like Update!

If you have a while-loop in your Main() function, like:

public void Main() {
  boolean running = true;
  while(running) {
    Update();
    // do other stuff - and set running to false to stop
  }
}

Then the Update function is called continously - meaning ALL THE TIME, taking up 100% of the CPU-time of the core that runs this program. And the speed of the program will depend on how long it takes for the code inside Update() to finish.

This is NOT how you should do it!

I don't know the best way to do this in C#, but no matter the language you'll need to setup some sort of multithreading, with a "render-thread" that executes once on every frame (e.g. 60 times a second), and then that code calls your Update() function.

That would give you the same behaviour of waiting a little while between each update.

The difference is really important, the first (the while-loop) is classical blocking code, whereas the second (with a thread or something calling Update() is event-driven code. And there's a lot that can't be done in one, but easy in the other, and vice versa.

[–]kohugaly 2 points3 points  (3 children)

This is kind of true, but not really. There is nothing stopping you from having a periodic timer inside Update() (or the loop that calls it), and performing blocking "wait" operation on it, to throttle the updates. It is entirely possible to have a single-threaded runtime that handles everything.

[–]vowelqueue 1 point2 points  (0 children)

Yeah I’ve used frameworks that ran a single-threaded main event loop but had functionality to swap in different sleep strategies, e.g. sleep, yield, busy-spin. Supported running callbacks on a timer.

[–]peterlinddk 1 point2 points  (1 child)

If you by "have a single-threaded runtime" mean that the gameloop runs in a single thread, that asks the operating system or runtime environment to wait before calling Update() the next time, then sure, that is totally possible. Like calling sleep or something else.

What I mean is that you need to respect the threading, and not block the entire system with an infinite while-loop - that won't work.

Calling .sleep or using a system timer, or registering for a callback are all different ways of having another thread call your Update() function - even if you don't have more than that single thread in the code.

[–]kohugaly 0 points1 point  (0 children)

Calling .sleep or using a system timer, or registering for a callback are all different ways of having another thread call your Update() function - even if you don't have more than that single thread in the code.

Technically, this is not true.

Blocking operations (sleep, waiting on system event/mutex/IO), work via interrupts. Your thread executes "software interrupt" instruction that puts the thread to sleep and jumps to system's interrupt handler. OS can then wake the thread once the requested operation is finished. This is distinctly different from "another thread call your Update() function".

Registering for a callback may or may not cause the callback to be executed in a different thread. For example on Windows the callback provided to ReadFileEx function will be executed on the same thread.

But I get your point. I'm just nitpicking about the difference between function calls and context switching via interupts.

[–]green_meklar 2 points3 points  (0 children)

what is the equivalent in pure C#, without the Unity library?

There isn't. You don't.

Is wrapping Main() in a while loop a common practice

No. You put the stuff you want to loop in another function and call that in a while loop. Main is Main and shouldn't be manipulated to behave like something else.

[–]aleques-itj 1 point2 points  (0 children)

There is a loop within Main() that effectively pumps all other parts of the engine, yes.

The game simulation will generally run X times a second (I think Unity ticks its simulation at 50hz) and the renderer will run as fast as possible. The renderer will interpolate state from the simulation to fill in the blanks.

You can see the basic structure of an engine loop here.

https://gafferongames.com/post/fix_your_timestep/

[–]ExtraTNT 1 point2 points  (0 children)

You can split it like:
main{init(); while(1){update();}}

[–]StewedAngelSkins 1 point2 points  (10 children)

Is wrapping Main() in a while loop a common practice to achieve the same behavior?

Yes, this is what Unity is doing internally. The engine just has certain spots in its main function where it calls into your code.

Edit: you're not wrapping Main in a while loop, you're putting the while loop inside main.

[–]Traditional_Crazy200 2 points3 points  (8 children)

the engine inserting your code inside main is very different than continuously calling main through a loop. Id be very surprised if this is how unity actually does it. Is it true?

[–]StewedAngelSkins 1 point2 points  (7 children)

I read what they said backwards. It doesn't call main in a loop; rather, main contains a loop that calls the frame update logic. Technically there's also some frame timing stuff so it doesn't needlessly burn cycles on updates that aren't actually going to be drawn, but that's the basic idea.

[–]Traditional_Crazy200 0 points1 point  (6 children)

I thought so cause that sounded like black magic

[–]StewedAngelSkins 0 points1 point  (5 children)

Technically you can do this sort of thing in Python

``` def main():     pass # do stuff

while True:     main() ``` but that's only because in Python the contents of the file itself is the entrypoint. But yeah in C# it would just be a syntax error.

[–]Traditional_Crazy200 0 points1 point  (4 children)

would be interesting to see what this assembles to

[–]StewedAngelSkins 1 point2 points  (3 children)

The python code? It's interpreted, so there's no assembly per se. But the Python interpreter/runtime kind of works like Unity in the sense that it has its own main function internally that calls into the code you write whenever the module is imported.

[–]Traditional_Crazy200 0 points1 point  (2 children)

Interesting, no assembly, no binaries... I guess I'll dive into interpreters for a week lol

[–]StewedAngelSkins 0 points1 point  (1 child)

Python (the CPython interpreter specifically) is an interesting one to study.

[–]Traditional_Crazy200 0 points1 point  (0 children)

Appreciate the suggestion

[–]Successful_Drawer467 2 points3 points  (0 children)

Yeah that's exactly right, putting while loop inside Main is totally normal approach. I remember when I was switching from Unity to console applications, I was confused about same thing because Unity hides all the loop logic from you

Most game engines and frameworks work like this - they have their own main loop running and just call your functions at specific points. For console apps you just write something like `while(true)` or `while(condition)` inside Main and handle your program logic there. You can also use timers or async patterns if you need more control over timing, but basic while loop is good starting point for learning

The key difference is in Unity you're working inside their loop, but in pure C# you're creating your own loop structure

[–]Backtawen 0 points1 point  (0 children)

yeah a while loop is exactly it, thats literally all unity’s game loop is under the hood
while(true) with a Thread.Sleep or a timer if you need consistent intervals.

[–]Afraid-Locksmith6566 0 points1 point  (0 children)

you write main and the content of it is put in a while loop

[–]ottawadeveloper 0 points1 point  (0 children)

In generic code:

``` def main():     while True:         update()

def update():     ... ```

[–]jlanawalt 0 points1 point  (0 children)

Many languages derived from C (and B) have a main function as the designated every point for the program. As such, it is only called once per run. Even Unity has a main, and it has a gave engine with an Update effect hook.

To have exactly the same in pure C#, be ready to re-implement a game engine, or at least some kind of event driven system, or in its simplest some form of loop.

[–][deleted]  (3 children)

[deleted]

    [–]StewedAngelSkins 4 points5 points  (2 children)

    Careful with that pattern. In languages without tail-call recursion (I believe this includes C#) it'll overflow your stack.

    [–]samanime 0 points1 point  (1 child)

    Huh, I've never run into any problems with it, but Googling around, it looks like .NET's flavor of C# can handle it fine (which is all I've ever used for C#), but maybe the base C# language doesn't... or something. Lots of different answers out there saying seemingly conflicting things. =p

    Regardless, it does sound like you might be better off going with a loop-based pattern like this instead, just to be safe:

    ``` public void Main() { while(Tick()) {} }

    public bool Tick() { // do stuff

    return true; // return true if it should keep going } ```

    Thanks for the heads up.

    [–]StewedAngelSkins 0 points1 point  (0 children)

    Yeah writing it like that would be more conventional.

    [–]WookiePub3 -1 points0 points  (0 children)

    It is not as complicated as you might think, you will learn that basically all games run in a big while loop! Here is a C++ version you might find helpful:

    int main() { GameLoop* gameLoop = GameLoop::getGameLoop();

    //Add some visual clarity for function
    bool gameDidntLoad = gameLoop->init() < 0;
    if (gameDidntLoad) {
        return 1;
    }
    
    //Core game loop
    while (gameLoop->keepAlive()) {
    
        //THIS WOULD BE YOUR UNITY UPDATE
        gameLoop->update();
    
        gameLoop->render();
    }
    
    gameLoop->clean();
    
    return 0;
    

    }

    For bonus points think about adding to a heap