Even though i have some experience in c#, this is my First game in C#. I am trying to set up the minimal skeleton of the game. I heard that Tick Event is a bad approarch for creating the main game loop.
This is the main concept of what I am trying to implement:
Program.cs
//Program.cs calls the Game Form.
Application.Run(new Game());
Game.cs
public partial class Game : Form
{
int TotalFramesCount = 0;
int TotalTimeElapsedInSeconds = 0;
public Game()
{
InitializeComponent();
GameStart();
}
public void GameStart()
{
GameInitialize();
while(true)
{
GameUpdate();
TotalFramesCount++;
CalculateTotalTimeElapsedInSeconds();
//Have a label to display FPS
label1.text = TotalFramesCount/TotalTimeElapsedInSeconds;
}
}
private void GameInitialize()
{
//Initializes variables to create the First frame.
}
private void GameUpdate()
{
// Creates the Next frame by making changes to the Previous frame
// depending on users inputs.
}
private void CalculateTotalTimeElapsedInSeconds()
{
// Calculates total time elapsed since program started
// so that i can calculate the FPS.
}
}
Now, this will not work because the while(true) loop blocks the Game Form from initializing. I found some solutions to this, by using System.Threading.Thread.Sleep(10); or Application.DoEvents();, but I didn't manage to make it work.
To explain why I want to implement this code here is an example of the above code in use:
Lets say I want my game to do the following:
Smoothly move a 100x100 Black colored Square from point (x1,y1) to (x2,y2) and backwards, in a loop and display the FPS in the label1 of the above code. With the above code in mind, I could possibly use TotalTimeElapsedInSeconds variable to set the speed of the movement to be relevant with the Time and not the Frames, as the Frames will differ on each machine.
// Example of fake code that moves a sqare on x axis with 20 pixels per second speed
private void GameUpdate()
{
int speed = 20;
MySquare.X = speed * TotalTimeElapsedInSeconds;
}
The reason i though of using a while(true) loop is that I will get the best FPS I can on each machine.
How could I implement my idea on actual code ? (just the basic skeleton is what i am looking for)
How could I set a max of, lets say 500 FPS to make the code "lighter" to run? instead of trying to produce as many frames as possible which I suspect will needlesly over-use the CPU(?)
Frame rate has nothing to do with smoothness. Even if you accomplish 500 frames/sec the movement will be choppy or worse. The trick is to synchronize with your monitor refresh rate. So for a monitor with 60Hz you need 60 frames/sec no more no less. You can't do that by using a loop in C#. You need DirectX or XNA. These frameworks can synchronize your drawings with the vertical scan of your monitor.
You need to make own thread to that while(true)-loop:
Thread thread = new Thread(new ThreadStart(GameStart));
thread.Priority = ThreadPriority.Lowest;
InitializeComponent();
thread.Start();
Check this blog post to get more coding intuition:
https://praybook2.blogspot.com/2020/04/this-now-advanced-stuff.html
Tough it loop fast. There are many disadvantages by using the threads, consider using some ready built game engine --like Godot; where all these kinds of small problems are fixed beforehand, use threads only when they are needed.
Related
First of all, I know that Application.targetFrameRate exists, and it does a good enough job, but I want something more accurate. For me, it limits the frame rate to around 60.3 when set to 60, and around 204 when set to 200. Btw these are measured in builds (not in the editor) using RTSS 7.2.
So I set out to create my custom frame limiter in Unity using low level timers, but it just doesn't work correctly for some reason. Here's my code:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System.Threading;
using System;
public class FrameLimiter : MonoBehaviour
{
private FrameLimiter m_Instance;
public FrameLimiter Instance { get { return m_Instance; } }
public double FPSLimit = 300.0;
private long lastTime = HighResolutionDateTime.UtcNow.Ticks;
void Awake()
{
m_Instance = this;
}
void OnDestroy()
{
m_Instance = null;
}
void Update()
{
if (FPSLimit == 0.0) return;
lastTime += TimeSpan.FromSeconds(1.0 / FPSLimit).Ticks;
var now = HighResolutionDateTime.UtcNow.Ticks;
if (now >= lastTime)
{
lastTime = now;
return;
}
else
{
SpinWait.SpinUntil(() => { return (HighResolutionDateTime.UtcNow.Ticks >= lastTime); });
}
}
}
Basically this is a singleton that's set to execute before any other script in the script execution order, and it blocks execution until the right time has been reached.
The way it works is it keeps track of the precise time when it last allowed a frame to be rendered (it obtains the current time from a very precise low level timer, here's more detail about that). Then in every call to its Update() function, it adds 1.0 / FPSLimit seconds to it to get the time when the next frame should be rendered, then if the current time is less than this time, it blocks execution until that timestamp has been reached.
SpinWait is basically just an efficient way to block execution without pinning the CPU like an empty while loop would. But just for the record, I did try an empty while loop too, and got the same results, except with much higher CPU usage.
So if you understand how this code is supposed to work, you should see that in theory this should lock the frame rate very precisely, especially given that this timer has a precision better than 1μs (0.001ms) according to Microsoft.
But despite all that, I get about 58.8 FPS when I set this to lock at 60, which I really don't understand. I'm running the build in exclusive full screen mode with V-sync disabled. Btw I'm getting way higher frame rates with no limiting, so the base performance of the game isn't the issue.
Any help would be appreciated!
The problem was weirder than I thought. It seems like this implementation of DateTime rounds the stored time internally to a whole number of milliseconds, so my frame limiter was pacing frames at 17ms instead of 16.6666ms when set to 60 FPS.
The solution was to alter the code for the timer I'm using, and just get the raw value returned by GetSystemTimePreciseAsFileTime() instead of encapsulating it in a DateTime object.
With this change, RTSS shows a perfect 60.0 FPS lock in the build, with occasional dips to 59.9, if the limiter is set to 60.
Here's what it looks like with a frametime graph as well. I was looking around the map at different things to try to excercise the frame limiter's consistency a bit. Safe to say, I made a much better frame limiter than Unity's own :)
If your program works perfectly and the spinwait finishes exactly at the calculated time you get exactly 60fps.
Nothing is perfect so it will take a bit more than the calculated time giving you a lower frame rate.
My 2D platformer game level has treasure chests placed all over the map and when a chest is collected I need to display a message. The messages are contained in a List<string> and they are displayed one by one as the treasures are collected.
These messages are to be displayed in a UI>Text gameObject which is anchored to the top-center of the canvas. I want to display these texts as floating up(fading in/out) when the treasures are collected, by updating the text component of this gameObject. However, the problem arises when two or more treasures are collected before the animation for the previous one could be complete. I can easily concatenate the new messages to the existing ones, but I want the old ones to fade out and new ones to fade in. This can be done by creating multiple UI>Texts, but there are a lot of messages and I do not want to create so many redundant gameobjects. Is there any good workaround for this problem?
The way I handled this in a project of mine was to create a queue of messages to display (as immediacy was not a concern, but being able to only display one at a time was). This sounds very similar to your own problem.
// NotificationItem is just a wrapper around some text and accompanying image
private static List<NotificationItem> notificationQueue = new List<NotificationItem>();
// reference to the on-screen object
public GameObject notification;
// "Hey! I want to display a notification!"
public static void ShowNotification(NotificationItem item) {
notificationQueue.Add(item);
}
// I was using the DO Tween asset here, but the logic can be converted to
// coroutines or straight update cycles
private void Update() {
// If there is no currently displayed notification (ie the notification object is
// not being animated) and there is at least one item to display
if(!DOTween.IsTweening(notification.transform) && notificationQueue.Count > 0) {
// ...get the first one
NotificationItem item = notificationQueue[0];
// ...pop it from the list
notificationQueue.RemoveAt(0);
// ...set the notification object to the details
notification.transform.Find("Title").GetComponent<Text>().text = item.title;
notification.transform.Find("Text").GetComponent<Text>().text = item.text;
notification.transform.Find("Img").GetComponent<Image>().sprite = item.image;
// ...start the animation
// (in my case, the notification animates down from the top of the screen
// waits 2.5 seconds, then animates back up)
notification.transform.DOMoveY(Screen.height - 85, 0.5f, false).SetEase(Ease.InOutQuad).OnComplete(PauseCallback);
}
}
// An admittedly hacky way of getting the notification to do nothing for 2.5 seconds:
// Animate it to where it already is.
private void PauseCallback() {
notification.transform.DOMoveY(Screen.height - 85, 2.5f, false).SetEase(Ease.InOutQuad).OnComplete(ReturnCallback);
}
private void ReturnCallback() {
notification.transform.DOMoveY(Screen.height + 2, 0.5f, false).SetEase(Ease.InOutQuad);
}
The difference between my implementation and yours will be largely in the animation (as well as your Queue lists's type; e.g. you might be able to just use a List<string>). You already have your animation coded, all you need is the queue and a way to determine that your animation is complete.
You will not be generating more objects than the system can handle if you utilize the Flyweight pattern (object pooling). Unity has an Object Pooling tutorial on their site.
I'm doing a chess game with AI in it.
There are some functions that handle the rule of game, like DoMove(), DoSkill().
But for some reasons (most for display cool effects), the function return type is IEnumerator instead of void. So the usage of the function look like this :
yield return StartCoroutine(DoSkill());
Now the problem comes, AI is a heavy work, but I've heard that Unity's Coroutines is not suitable for heavy calculating. When I change functions to IEnumerator, the speed of AI obviously getting very slow.
I'm sure that there isn't any WaitForSeconds(someFloat) will be execute in AI(I use some parameter & if/else to skip it), it just seems like the performance is really poor if I continuously call StartCoroutine again and again.
The possible solution I can think of is write two kind of DoSkill() funtion, one's return type is void , the other is IEnumerator. but it's really not a good way. because I have to maintain lots of similar functions, and it's ugly too.
Any suggestions would be greatly appreciated.
Coroutines are nothing magical - they are a way to have a function keep giving up control mid-execution, and continuing on next time they are pumped. They exist really to allow developers to avoid writing multi-threaded code.
The reason they don't work for heavy calculations is that they are executed in the main thread, so any long running code would effectively kill your frame rate.
They do work where you know you can do a small deterministic pieces of work and defer for next time - such as processing downloaded byte streams, copying data, etc. So if you are running smoothly at 60FPS you know you have 16 ms to do everything in a frame, and heavy calculations might be variable in time and hard to know ahead. If you exceed 16 ms in total (everything including your calculation) the FPS will slow down and the game will appear jerky.
I suggest in your case you run the calculations in a background thread. It's basically:
using UnityEngine;
using System.Threading;
public class ChessAI : MonoBehaviour
{
Thread aiThread;
void StartAI()
{
aiThread = new Thread(new ThreadStart(AIThread));
aiThread.Start();
}
void AIServer()
{
// do stuff here - be careful of accessing data being changed by main thread
}
public void OnApplicationQuit()
{
// It is crucial in the editor that we stop the background thread when we exit play mode
aiThread.Abort();
}
}
Is there any function to freeze all the game or a certain class for a moment?
I'm searching for a Wait function like in Matlab.
Thanks.
EDIT: The wait function stops all the processing for a given time.
A one-line hack would be to call Thread.Sleep(x) in the main Update(), but that'll hang the game for the specified amount of time. The user will think your app has become unresponsive and he might kill it and restart it! It's probably not what you want.
The way I architecture games, each major component has its own Update() (or Tick()) method that is called on each logical update. You can selectively freeze components by simply not calling their Update() for a while. There are things you certainly never want to freeze, like refreshing the screen, responding to user input or sound processing.
Some example code:
// To pause the game for x number of frames, set pauseDelay = to x
int pauseDelay;
public void Update() {
if (pauseDelay > 0) {
--pauseDelay;
}
else {
physics.Update();
ai.Update();
}
input.Update();
sound.Update();
}
If you've based your game on GameComponents you can usually just set the Enabled flag to false which prevents the update logic being executed, this obviously depends on other factors (Object manipulation outside of the classes update logic, update logic being performed in the draw or other method ect..)
public class Car : GameComponent
{
// This logic is only called if the Enabled property is set to true.
public override void Update(GameTime gameTime)
{
base.Update(gameTime);
}
}
If you've not used game component then it would be quite simple to introduce an Enabled flag to your clases and check for that before executing update logic.
If your looking for a very simple way (Andy's seems better, but this is quick way)
In your update Method a class, add at the top:
if (isPaused)
break;
You can use isActive to check is the window is active too.
I want a method in a DrawableGameComponent class to not return until a particular condition is met
Say I have this class (snippet from a DrawableGameComponent class):
public override void Update(GameTime gameTime)
{
if (moving && pixFromLastMove <= distanceToMove)
{
position += velocity;
pixFromLastMove += velocity.Length();
}
else
{
moving = false;
}
if (rotating)
{
rotation += 0.1f;
var cRotation = MathHelper.Clamp(rotation, -MathHelper.PiOver2, angleBeforeRotation + degToRotate);
if (cRotation != rotation)
{
rotation = cRotation;
angleBeforeRotation = rotation;
rotating = false;
}
}
base.Update(gameTime);
}
public void Ahead(int pix)
{
moving = true;
distanceToMove = pix;
pixFromLastMove = 0;
velocity = new Vector2((float) Math.Cos(rotation), (float) Math.Sin(rotation))*5.0f;
//DO NOT RETURN UNTIL THIS ROBOT HAS MOVED TO ITS DESTINATION
}
public void TurnLeft(int deg)
{
rotating = true;
degToRotate = MathHelper.ToRadians(deg);
angleBeforeRotation = rotation;
//DO NOT RETURN UNTIL THIS ROBOT HAS BEEN FULLY ROTATED
}
This class is being drawn (Draw())in the main thread (because this drawablegamecomponent is executing in seperate thread), and also in the main thread I have a list of commands that I want to be executed in order...but currently, since the Ahead method returns just after assigning a value to velocity, the methods will run almost concurrently, which in turn just executes all the animations at the same time.
So what do you think should I do to prevent methods that are commands (Ahead,TurnLeft etc..) from returning before a certain condition is met?
You need to create some kind of state machine for your Update() method. e.g.
public override void Update() {
if (movingRobot) {
OnlyUpdateRobotPosition();
}
else {
DoStuffPerhapsIncludingStartingRobotMove();
}
}
Or am I missing the question?
Ahh, two words: Cooperative multitasking. With the joy of Fibers (or your cooperative multitasking building block of choice) you could (after laying some ground work, such as this to enable fibers in C#) do something like this:
public void Ahead(int pix)
{
moving = true;
distanceToMove = pix;
pixFromLastMove = 0;
velocity = new Vector2((float) Math.Cos(rotation), (float) Math.Sin(rotation))*5.0f;
//DO NOT RETURN UNTIL THIS ROBOT HAS MOVED TO ITS DESTINATION
while(!HasReachedDestination())
{
Yield(); // let another fiber run
}
}
In order to make this work however you need to implement a simple round-robin scheduler. C# isn't really my boat, but what I'd do is to keep it simple and create some sort of base-class that I'd call Cooperative (or something). This class would have a static list of all created fibers as well as the static methods Create() and Yield(). Create() will create a new fiber (or whatever) and Yield() will simply schedule next fiber to execute (round-robin style), in fiber-world that would include a call to SwitchToFiber(). It will also have a virtual method called Start() (or whatever) that is where the fiber will start to run.
To make it more fancy-smancy you could later keep separate lists of fibers that are either runnable or not runnable (i.e. waiting for something to happen). In that case you might be able to simplify the loop in Ahead to:
WaitFor(HasReachedDestination);
But I suggest getting your feet wet with the concept of cooperative multitasking first.
Finally some thoughts on what should be made fibers, typically your main update loop is one fiber, updating and drawing all objects and then calls Yield(). The all game objects would also be fibers (this may not be feasible if you have a lot of game objects). For your game objects you'd do something like:
public override Start()
{
do
{
if(EnemyToTheLeft())
{
TurnLeft(90); // this will call Yield and return when we have finished turning
Shoot();
}
Yield(); // always yield
}while(!dead);
}
I agree with Pop Catalin: it is probably best not to block in those command functions. I think you could improve your game by thinking about the design a bit more. Let me provide some thoughts for you on how you could possibly improve your design.
First, it sounds like the problem you are describing is that you want to send a lot of move commands, in a certain order, to a game component and have it execute those commands in that certain order. As you have noticed, there is a difference in the time it takes the computer to perform the calculations (for the velocity or rotation) and the time it takes the component to actually perform the action (move or rotate).
The problem with blocking during the calculations (Ahead, TurnLeft, etc) is that the update loop that is calling that function cannot update any other components. That may work okay if there is only one component to worry about, but that's not usually the case in most games.
Now for the good part: how do we fix this problem? I think erikkallen has the right idea, but I would take it a bit further. It sounds like the game component is some kind of entity that will be moving around, so why not give it an action queue? A simple implementation would be to just have your calling function call something like:
gameComponent.queueAction( (MethodInvoker)delegate()
{ gameComponent.Ahead(10); });
Your queueAction function might look like this:
public void queueAction(MethodInvoker action)
{
queue.Enqueue(action);
}
At the top of your Update function you could add:
if(noCurrentAction && queue.Count > 0)
{
((MethodInvoker)queue.Dequeue()).Invoke();
noCurrentAction = false;
}
And you'd need to add a line at the end of the Update function like:
if(!moving && !rotating)
noCurrentAction = true;
Now, I definitely wouldn't call this the best solution, but it doesn't take much code to implement it. Of course if you need to move and rotate at the same time you'll have to tweak it a bit. It will also get messier when you add different types of actions.
For a more general solution, I would think about making a base Action class, and deriving specific action classes from it. Then you could just push actions to the queue, and your Update function could call the action's Update function, which would do the work the two sections of your game components Update function is doing now.
These are just some ideas to think about, I hope something here will get you started.
One last thing I wanted to mention was that I don't see you using gameTime variable that is passed to Update. The amount your component moves and rotates may need to be a function of the elapsed time since Update was last called. Meaning that the Update function would move and rotate your game component based on the amount of time that has passed, not just how many times the Update function was called. I'm not very good at explaining it, and it depends on how you'd like your game to function. Here are a couple different posts from Shawn Hargreaves (XNA expert). Also, an XNA Forum post discussing the point I was trying to make.
Although I find your design somewhat odd, best way to accomplish what you want is to use an EventWaitHandle and signal it from another thread.
Say you have an instance of the waithandle on your class
you can call waithadle.WaitOne() in your method, and signal the even from another thread using waithandle.Set() when the condition is met, at which point your method will resume from waiting.