I'm having a problem: When I create a window in OpenGL, using C#, my window starts to lag, and I cannot use the window (I cannot close, minimize, resize, etc.). And when I hover my mouse inside the window, my cursor becomes that blue wheel, meaning it's lagging. How can I fix it?
It's worth saying that I'm using OpenGL and OpenTK to display and use the window however I want.
This is my code for generating the window:
First, this is the “GameLoop” class, everything related to the game itself is derived from this class, it contains some abstract classes that I can override, so it's really useful.
public abstract class GameLoop
{
public GameWindow window;
public Vector2Int windowSize = new Vector2Int(1280, 768);
public void Run()
{
OnInitialize();
WindowManager.CreateWindow(windowSize.x, windowSize.y, "Engine", out window);
OnLoad();
while (WindowManager.IsRunning)
{
OnUpdate();
OnRender();
}
OnCloseWindow();
}
protected abstract void OnInitialize();
protected abstract void OnLoad();
protected abstract void OnUpdate();
protected abstract void OnRender();
protected abstract void OnCloseWindow();
}
class RunGameLoop
{
static void Main()
{
GameLoop loop = new EngineWindow();
loop.Run();
}
}
Secondly, I have this method in another class that is responsible for creating the window itself:
public static void CreateWindow(int width, int height, string title, out GameWindow window)
{
window = new GameWindow(GameWindowSettings.Default, NativeWindowSettings.Default);
Vector2Int res = new Vector2Int(width, height);
//windowSize = res;
IsRunning = true;
window.CenterWindow(Vector2Int.ToVec2i(res));
window.Title = title;
}
And finally, I have the main class, where I can use OpenGL and make my project:
public class EngineWindow : GameLoop
{
protected override void OnInitialize()
{
Debug.WriteLine("On Initialize");
}
protected override void OnLoad()
{
GL.Enable(EnableCap.DepthTest);
GL.Enable(EnableCap.Lighting);
GL.ClearColor(Color.ToColor4(BackColor));
GL.Viewport(0, 0, windowSize.x, windowSize.y);
CreateMesh(cubeMesh);
}
protected override void OnUpdate()
{
}
protected override void OnRender()
{
GL.Clear(ClearBufferMask.ColorBufferBit | ClearBufferMask.DepthBufferBit);
angle += Time.deltaTime;
SetupViewport(sceneCamera);
RenderMesh(cubeMesh);
ControllCamera(sceneCamera);
GL.CullFace(CullFaceMode.Back);
GL.Finish();
window.SwapBuffers();
}
protected override void OnCloseWindow()
{
Debug.WriteLine("Ended");
// Clean up
GL.DeleteProgram(program);
GL.DeleteBuffers(1, ref vbo);
GL.DeleteVertexArrays(1, ref vao);
}
}
But, the issue is that when the window is created, it starts up fine, but becomes extremely laggy and I can't use the window.
What might be the issue, and how can I fix it?
Related
I am trying to use virtual and abstract methods to make my game architecture better.
I'm using C# and Unity for this example.
I use a ShipComponent as a base Class because I want all the child classes to do the same thing.
But sometimes I want a certain ShipComponent to do something else.
The code will make it a lot clearer:
ShipComponent.cs:
public abstract class ShipComponent : MonoBehaviour
{
[HideInInspector] public ShipControl shipControl;
public virtual void Init(ShipControl control)
{
this.shipControl = control;
}
public virtual void IsPlayer()
{
SetListeners();
}
public abstract void IsNotPlayer();
public abstract void ReEnable();
public abstract void SetListeners();
}
One of the many child classes that inherits from ShipComponent:
public class Rudder : ShipComponent
{
[Header("Settings")]
public Transform rudder;
[Header("Debug Info")]
[SerializeField] float rudderSpeed;
[SerializeField][Range(-45, 45)] int setRudderAngle = 0;
[SerializeField][Range(-45f, 45f)] float realRudderAngle = 0f;
public override void Init(ShipControl shipControl)
{
base.Init(shipControl);
rudder = transform.GetChild(0).GetChild(4);
StartCoroutine(SmoothRudderChange());
SetListeners();
}
public override void IsPlayer()
{
base.IsPlayer();
}
public override void IsNotPlayer()
{
PlayerShipControl.OnRudderChange -= SetRudder;
}
public override void ReEnable()
{
StartCoroutine(SmoothRudderChange());
SetListeners();
}
public override void SetListeners()
{
PlayerShipControl.OnRudderChange -= SetRudder;
if (!shipControl.shipWrapper.ship.IsPlayer) return;
PlayerShipControl.OnRudderChange += SetRudder;
}
void OnDisable()
{
PlayerShipControl.OnRudderChange -= SetRudder;
StopAllCoroutines();
}
The main draw back I experience with this, is that I have to copy paste all 5 or 6 methods everytime I create a new ShipComponent class.
It seems messy and theres a lot of repeating code, most of the time the only difference in each ShipComponent is the SetListeners part, and StartCoroutines if any.
Is there a way to dynamically set delegate listeners up?
So I could set them in the base class ShipComponent?
Instead of setting each component individually?
Another script that inherits from ShipComponent for completeness:
public class Guns : ShipComponent
{
IEnumerator mouseAimCycle;
public override void Init(ShipControl shipControl)
{
base.Init(shipControl);
InitCannons();
SetListeners();
}
public override void ReEnable()
{
SetListeners();
}
public override void IsPlayer()
{
base.IsPlayer();
mouseAimCycle = AimCycle();
StartCoroutine(mouseAimCycle);
SetListeners();
}
public override void SetListeners()
{
PlayerShipControl.OnFireGuns -= TryFire;
if (!shipControl.shipWrapper.ship.IsPlayer) return;
PlayerShipControl.OnFireGuns += TryFire;
}
public override void IsNotPlayer()
{
StopCoroutine(mouseAimCycle);
PlayerShipControl.OnFireGuns -= TryFire;
}
void OnDisable()
{
PlayerShipControl.OnFireGuns -= TryFire;
StopAllCoroutines();
}
Calling the ShipComponent virtual and abstract methods:
public class ShipControl : MonoBehaviour
{
// Contains Ship + Cargo + Crew and a ref to this ShipControl
public ShipWrapper shipWrapper { get; private set; }
ShipComponent[] shipComponents;
// Gather all ShipComponents and Initialize them.
public void Start()
{
shipComponents = transform.GetComponents<ShipComponent>();
foreach (ShipComponent comp in shipComponents)
{
comp.Init(this);
}
}
// Call this to check if this is players current ship and set the components accordingly.
public void UpdateIsPlayer()
{
if (!shipWrapper.ship.IsPlayer)
foreach (ShipComponent component in shipComponents)
component.IsNotPlayer();
else
foreach (ShipComponent component in shipComponents)
component.IsPlayer();
}
And PlayerShipControl, which I use for input, broadcasting the input through delegates, and the theory is that only the players currently controlled ship will be listening for this input:
public class PlayerShipControl : MonoBehaviour
{
public static event Action<Transform> SetCamToPlayerShip;
public static event Action SetShipPanelUI;
public static event Action<bool> ToggleAnchorIcon, ToggleFlagIcon, ToggleAutofireIcon, ToggleBoatsIcon;
public static event Action OnFireGuns;
public static event Action<int> OnRudderChange;
public static event Action<int> OnSailStateChange;
public static event Action<bool> OnAllAnchorsCommand;
public static event Action<bool> OnAllBoatsCommand;
bool anchor, flag, autofire, boats;
ShipControl shipControl;
void Update()
{
if (Input.GetKeyUp(KeyCode.W)) // Raise Sails SailState++
{
OnSailStateChange?.Invoke(1);
}
if (Input.GetKeyUp(KeyCode.S)) // Furl Sails SailState--
{
OnSailStateChange?.Invoke(-1);
}
if (Input.GetKey(KeyCode.D))
{
OnRudderChange?.Invoke(1);
}
if (Input.GetKey(KeyCode.A))
{
OnRudderChange?.Invoke(-1);
}
if (Input.GetKeyDown(KeyCode.M))
{
OnRudderChange?.Invoke(0);
}
// Drop All Anchors
if (Input.GetKeyDown(KeyCode.V))
{
anchor = true;
ToggleAnchorIcon?.Invoke(anchor);
OnAllAnchorsCommand?.Invoke(anchor);
}
// Haul All Anchors
if (Input.GetKeyDown(KeyCode.H))
{
anchor = false;
ToggleAnchorIcon?.Invoke(anchor);
OnAllAnchorsCommand?.Invoke(anchor);
}
// Drop All Boats
if (Input.GetKeyDown(KeyCode.B))
{
boats = true;
ToggleBoatsIcon?.Invoke(boats);
OnAllBoatsCommand?.Invoke(boats);
}
// Take In All Boats
if (Input.GetKeyDown(KeyCode.U))
{
OnAllBoatsCommand?.Invoke(false);
// TO DO When all boats are back on deck, boatIcon + boatsBoolFlag should be turned off again.
}
if (Input.GetKeyDown(KeyCode.Space))
{
OnFireGuns?.Invoke();
}
}
}
Its a long string of scripts sometimes though so I have left out all the managers and such.
Ship ship inside shipWrapper.ship is a custom data class that stores the info about the ship, not a Monobehaviour, but it holds a bool called IsPlayer aswell. Nothing else of interest I can think of.
The main draw back I experience with this, is that I have to copy paste all 5 or 6 methods every time I create a new ShipComponent class. It seems messy and there's a lot of repeating code, most of the time the only difference in each ShipComponent is the SetListeners part, and StartCoroutines if any.
In the show example you have more differences between implementations then ones described. Without seeing the full code it is hard to suggest something meaningful.
Few notes on the current code:
In Rudder you don't need to specify IsPlayer because the following:
public override void IsPlayer()
{
base.IsPlayer();
}
does not add anything extra, so you can just skip implementation in the derived class.
Based on provided examples it seems that ReEnable can be defined as virtual in base class with default implementation set to calling SetListeners (the same approach as you have with Init and IsPlayer).
PlayerShipControl.Update possibly can be improved by moving handlers to dictionary. Something along this lines:
public class PlayerShipControl : MonoBehaviour
{
// ...
Dictionary<KeyCode, Action> keyActions = new() // not sure about the type
{
{ KeyCode.W, () => OnSailStateChange?.Invoke(1) },
// ...
{ KeyCode.V, () =>
{
anchor = true;
ToggleAnchorIcon?.Invoke(anchor);
OnAllAnchorsCommand?.Invoke(anchor);
}
},
// ...
};
void Update()
{
foreach (var kvp in keyActions)
{
if (Input.GetKeyUp(kvp.Key))
{
kvp.Value();
break;
}
}
}
}
When you instantiate a new GameWindow, its background color is white, I would like to change it to black for instance.
The problem is further visible if you have a long initialization sequence happening.
The closest I could get is to set clear color in constructor then swap but it ain't perfect.
using System.Drawing;
using OpenTK.Graphics.OpenGL;
using OpenTK.Mathematics;
using OpenTK.Windowing.Common;
using OpenTK.Windowing.Desktop;
internal static class Program
{
private static void Main(string[] args)
{
var gws = new GameWindowSettings();
var nws = new NativeWindowSettings
{
Size = new Vector2i(320, 240)
};
using (var game = new Game(gws, nws))
{
game.Run();
}
}
}
internal class Game : GameWindow
{
public Game(GameWindowSettings gameWindowSettings, NativeWindowSettings nativeWindowSettings)
: base(gameWindowSettings, nativeWindowSettings)
{
// close but still shows a white background at startup for some time
GL.ClearColor(Color.Red);
GL.Clear(ClearBufferMask.ColorBufferBit);
Context.SwapBuffers();
}
protected override void OnLoad()
{
base.OnLoad();
GL.ClearColor(Color.Green);
}
protected override void OnRenderFrame(FrameEventArgs args)
{
base.OnRenderFrame(args);
GL.Clear(ClearBufferMask.ColorBufferBit);
Context.SwapBuffers();
}
protected override void OnResize(ResizeEventArgs e)
{
base.OnResize(e);
GL.Viewport(0, 0, e.Width, e.Height);
}
}
Question:
How to get GameWindow to use another color than white when it's first shown?
I am trying to do a state machine to controll ai behaviour in Unity 3D.
My question is regarding inheritance. Im trying to set up some base logic that handles how and why states shoul be changed. But further down the inheritance line i need different kind of characters to be able to do character speicfic things. But im not able to do this with inheritnance.
Can someone confirm that my thinking is not how its done? then i know to find another solution.
PSEUDO CODE:
// STATE CONTROLLERS CONTROLL THE CHARACETER BY CHOOSING WITCH STATE THEY SHOULD BE IN
abstract class StateController {
StateBase state;
int HitPoints;
int Hunger:
abstract void Update()
{
CheckIfStateShouldChange();
state.UpdateState(this);
}
}
WolfStateController : StateController {
WolfState state;
override void Update()
{
base.Update();
state.Update(this);
}
}
SheepStateController : StateController {
SheepState state;
override void Update()
{
base.Update();
state.Update(this);
}
}
// STATES CONTAINS LOGIC FOR BEHAVIOUR IN A CERTAIN STATE
StateBase {
virtual void UpdateState( StateController controller)
{
// Does things all inheriting classes should do
}
}
WolfState : StateBase {
override void UpdateState( WolfStateController wolfstate)
{
base.UpdateState(WolfStateController wolfstate)
//Does wolf specific things that needs to be done in all WolfStates
}
}
WolfStalkAndHuntState : WolfState {
override void UpdateState( WolfStateController wolfstate)
{
base.UpdateState(WolfStateController wolfState);
//Hunts sheep and attacks on sight
}
}
SheepState : StateBase {
override void UpdateState( SheepStateController sheepState)
{
//Does sheepy things
}
}
SheepReproduceState : SheepState {
override void UpdateState( SheepStateController sheepState)
{
base.UpdateState(SheepStateController sheepState);
// Looks for mate and gets freaky
}
}
I would suggest something like this:
Controller Class:
public class SoliderController : MonoBehaviour
{
[HideInInspector] public sState currentState;
[HideInInspector] public FireState fireState;
[HideInInspector] public IdleState idleState;
[HideInInspector] public ChaseState chaseState;
private void Awake()
{
fireState = new FireState(this);
idleState = new IdleState(this);
chaseState = new ChaseState(this);
}
private void Start ()
{
currentState = idleState;
}
private void Update()
{
currentState.Update();
}
Interface:
public abstract class sState
{
public abstract void Update();
public abstract void ToChaseState();
public abstract void ToIdleState();
public abstract void ToFireState();
}
Example Class
public class IdleState : sState
{
private readonly SoliderController controller;
public IdleState(SoliderController soliderController)
{
controller = soliderController;
}
public override void Update()
{
Patrol();
//Condition to change state
if (*expresion1*)
ToChaseState();
if (*expresion2*)
ToFireState();
}
private void Patrol()
{
//Your Logic for the behvaiour wanted.
}
public override void ToChaseState()
{
controller.currentState = controller.chaseState;
}
public override void ToFireState()
{
controller.currentState = controller.fireState;
}
public override void ToIdleState()
{
Debug.LogWarning("Can't transition to same state");
}
}
This way checking for changes is way easier and also you can impletement state specific behaviours as well. Also, adding a new state goes really easy, you just implement the new Class and ToNewState method in the interface.
Hope it helped.
Hello i have this code:
public abstract class Test : MonoBehaviour
{
public abstract void OnStart();
public abstract void OnUpdate();
private void Start()
{
OnStart();
}
private void Update()
{
if (Input.GetKeyDown(KeyCode.X))
{
Destroy(this);
}
OnUpdate()
}
}
then I have the this:
public class SecondTest : Test
{
public override void OnStart()
{
}
public override void OnUpdate()
{
Writter.Log("Running");
}
}
However whenever I press X, my writter keeps logging, it seems like the instance of "Test" gets destroyed but not my "SecondTest" is there any way to solve this? thank you!
*OP explained the intention is to cause Children to be destroyed when Parent is.
The solution would probably be better handled at a '(Test)Manager' or 'LevelManager'.
You could assign your Children or prefabs to your (Test)Manager manually, or get (Test)Manager to instantiate the child prefab.
GameObject child = Instantiate(prefab);
child.transform.SetParent(gameObject.transform); //set the child's parent to the Manager
Then in your (Test)Manager
private void Update()
{
if (Input.GetKeyDown(KeyCode.X))
{
for(int i=0;i<gameObject.transform.childCount;i++)
Destroy(gameObject.transform.GetChild(i).gameObject);
}
}
This is just a crude suggestion, there are probably better ways to do this such as holding some references to the children in the manager versus parenting.
I'm studying up on the unity containers and have a quick question on how to resolve a class's construction to multiple different implementations of an interface.
Here's my code:
public interface IRenderer
{
void DrawSquare(Square square);
void DrawCircle(Circle circle);
}
public interface IShape
{
void Draw(IRenderer renderer);
}
public class Dx11Renderer : IRenderer
{
public void DrawSquare(Square square)
{
}
public void DrawCircle(Circle circle)
{
}
}
public class GlRenderer : IRenderer
{
public void DrawSquare(Square square)
{
}
public void DrawCircle(Circle circle)
{
}
}
public class Circle : IShape
{
public void Draw(IRenderer renderer) { renderer.DrawCircle(this); }
}
public class Square
{
public void Draw(IRenderer renderer) { renderer.DrawSquare(this); }
}
public class Canvas
{
private readonly IRenderer _renderer;
private List<Circle> _circles = new List<Circle>();
private List<Square> _squares = new List<Square>();
public Canvas(IRenderer renderer)
{
_renderer = renderer;
}
public void Draw()
{
foreach (Circle c in _circles)
{
c.Draw(_renderer);
}
foreach (Square s in _squares)
{
s.Draw(_renderer);
}
}
}
and to register/resolve
// Create the container
var container = new UnityContainer();
// registration
container.RegisterType<IRenderer, GlRenderer>("GL");
container.RegisterType<IRenderer, Dx11Renderer>("DX11");
Canvas canvas = container.Resolve<Canvas>("GL");
This throws a "ResolutionFailedException" so I must be using this incorrectly.
Can someone explain if this is bad practice, or how I can achieve this.
Thanks
UPDATE:
So what I have done is registered Canvas twice with each type of dependencies like so:
// Canvas with an OpenGL Renderer
container.RegisterType<Canvas>("GLCanvas", new InjectionConstructor(new ResolvedParameter<IRenderer>("GL")));
// Canvas with a DirectX Renderer
container.RegisterType<Canvas>("DXCanvas", new InjectionConstructor(new ResolvedParameter<IRenderer>("DX11")));
Canvas canvas = container.Resolve<Canvas>("GLCanvas");
This works well for me!
The problem is that you are resolving Canvas with the name "GL", but you have not registered Canvas in that way. Unity doesn't propagate the name to dependency resolution, so it won't use the name "GL" when resolving IRenderer.
There are several options to solve this already answered: Resolving named dependencies with Unity
Your question is whether this is a bad practice, or how you can achieve the same results. In my experience, trying to register and resolve multiple instances of the same interface usually leads to messy code. One alternative would be to use the Factory pattern to create instances of Canvas.
Do you need to use your container to resolve Canvas? If you don't have a reason not to, you could simply Resolve your IRenderer and new up a Canvas yourself:
new Canvas(container.Resolve<IRenderer>("GL"));
Remember that Unity is just a tool, if it doesn't seem to be capable of doing what you need, you may need a different kind of tool.
There is a way to inject the right renderer in the canvas on startup time. If you know the render method on startup you can register only the right renderer like this:
var container = new UnityContainer();
container.RegisterType<ICanvas, Canvas>();
if (CheckIfItIsDx11)
{
container.RegisterType<IRenderer, Dx11Renderer>();
}
else
{
container.RegisterType<IRenderer, GlRenderer>();
}
when you want to resolve the canvas just use:
var canvas = container.Resolve<ICanvas>();
if you dont know the renderer on startup time there is a way to. Like this:
container.RegisterType<IRenderer, Dx11Renderer>("DX11");
container.RegisterType<IRenderer, GlRenderer>("GL");
var renderer = container.Resolve<IRenderer>("DX11");
var canvas = container.Resolve<ICanvas>(new ParameterOverride("renderer", renderer));
Canvas now has the right renderer injected. The canvas can use the renderer interface like this:
internal interface ICanvas
{
void Draw();
}
public class Canvas : ICanvas
{
private readonly IRenderer _renderer;
private readonly List<Circle> _circles = new List<Circle>();
private readonly List<Square> _squares = new List<Square>();
public Canvas(IRenderer renderer)
{
_renderer = renderer;
}
public void Draw()
{
foreach (var circle in _circles)
{
_renderer.Draw(circle);
}
foreach (var square in _squares)
{
_renderer.Draw(square);
}
}
}
Also the renderer should not be drawing the shape. The shape is responsible for drawing itself. This way you keep your code at the same spot. If you keep adding shapes the renderer file get huge. and you need to search for some shapes if you want to change code. Now everything is in the right place where it should be. The code now should look something like this:
public interface IRenderer
{
void Draw(IShape shape);
}
public interface IShape
{
void Draw(IRenderer renderer);
}
public class Dx11Renderer : IRenderer
{
public void Draw(IShape shape)
{
shape.Draw(this);
}
}
public class GlRenderer : IRenderer
{
public void Draw(IShape shape)
{
shape.Draw(this);
}
}
public class Circle : IShape
{
public void Draw(IRenderer renderer)
{
if (renderer.GetType() == typeof(Dx11Renderer))
{
Console.WriteLine("Draw circle with DX11");
}
if (renderer.GetType() == typeof(GlRenderer))
{
Console.WriteLine("Draw circle with GL");
}
}
}
public class Square : IShape
{
public void Draw(IRenderer renderer)
{
if (renderer.GetType() == typeof(Dx11Renderer))
{
Console.WriteLine("Draw square with DX11");
}
if (renderer.GetType() == typeof(GlRenderer))
{
Console.WriteLine("Draw square with GL");
}
}
}
Hope this will help.