[OpenSource] GameUtils
- Beta
- Open Source
Sie verwenden einen veralteten Browser (%browser%) mit Sicherheitsschwachstellen und können nicht alle Funktionen dieser Webseite nutzen.
Hier erfahren Sie, wie einfach Sie Ihren Browser aktualisieren können.
Hier erfahren Sie, wie einfach Sie Ihren Browser aktualisieren können.
Es gibt 152 Antworten in diesem Thema. Der letzte Beitrag () ist von Artentus.
-
-
@Artentus: Warum gibt es eig. kein Punkt?
Naja egal, erstmal vielen Dank das Du dein Code mit uns teilst.
War gerade auf der suche nach fertigen Vetor Klassen etc. und da viel mir dein GameUtils ein.
Ist zwar etwas Overkill da ich doch mit GDI+ zeichen wollte mhhhhhhhh.
Wenn ich da durch steige, würd ich auch dein Renderer nehmen und falls das Mini-Projekt fertig wird, kann ichs dir geben (z. B. könntest Du dies dann als Beispiel (Für 2D) reinstellen) falls dann noch bedarf bestehen sollte.
Edit: Die TestApp ist ja schon dabeiDieser Beitrag wurde bereits 2 mal editiert, zuletzt von „Eistee“ ()
-
Warum gibt es eig. kein Punkt?
Erstmal vielen Dank das Du dein Code mit uns teilst.
War gerade auf der suche nach fertigen Vetor Klassen etc. und da viel mir dein GameUtils ein.
Du solltest mal einen Blick auf MathUtils werfen, da ist alles drin, was man im Umgang mit Vektoren braucht. -
-
-
Hi
Vector und Punkt sind trotzdem voneinander verschieden. Punkte können verschoben werden, Vektoren sind quasi alle Pfeile. Daher benötigt man auch immer einen Aufpunkt, wenn man Vektoren zeichnet (dieser ist häufig auch einfach (0|...|0)).
Die Regeln könnten so aussehen:
Point + Vector = Point
Point - Point = Vector
und einen impliziten Operator für PointN->VectorN könnts dann halt auch geben. Box wäre bspw. ein Point3 und ein Vector3 bzw. ein zweiter Point3, aus dem sich der Vektor erzeugen lässt, die das Volumen aufspannen.
Sauber wär's dann halt mit dieser Unterscheidung in den einzelnen Fällen.
Gruß
~blaze~ -
-
-
Hab jetzt mal die TestApp ausprobiert - immerhin ein Rechteck zu sehen.
Nu wollte ich machen, dass es sich auch bewegt, und finde, die Engine unterstützt einen ühaupt nicht darin.
Also von einer Engine täte ich mindestens erwarten, dass ich mit Tastatur die Richtung und Geschwindigkeit bewegter Objekte beeinflussen kann.
Gerne auch, dass ich Objekte selektieren kann, drehen, oder auch ein Kollisionens-Ereignis bekomme. -
-
Nach langer Zeit gibt hier endlich auch mal wieder ein Update.
Highlight ist die 2D-Physikengine, die auch der Grund war, warum es so lange gedauert hat. Später sollen auch noch Sachen wie Reibung, Seile usw. hinzukommen, aber für den Augenblick belasse ich es erst mal so. Einen Überblick über die aktuelle Funktionalität bekommt ihr in der Testanwendung, die ich speziell für die Physikengine angepasst habe.
Ein dickes Danke geht an @jvbsl: , der mir wirklich enorm dabei geholfen hat, ohne ihn hätte ich es vermutlich nicht geschafft (also liken, abonnieren und favorisieren ).
Weiterhin habe ich auch am Rendersystem weitergearbeitet. Das Geometry-Interface ist nun bis auf die AddArc-Methode, die ich leider immer noch nicht implementieren konnte (hier ist der Thread), fertig. Auch die Vector2-Struktur hat einige neue Funktionen spendiert bekommen. Ein ITextureBrush-Interface ist auch schon vorhanden, das wird aber erst im nächsten Update fertig sein.
Außerdem habe ich auch sonst einige kleinere oder größere Änderungen vorgenommen, und die Stabilität des Gameloops verbessert.
Als nächstes sind jetzt Netzwerk und Input an der Reihe, danach folgt dann UI und vielleicht setzte ich mich auch nochmal an die Physikengine dran (siehe oben). Diese Liste kann natürlich beliebig erweitert werden, je nachdem, was mir oder euch noch so einfällt.
Edit: ach noch was an die Mods: könnte der Thread vielleicht in den Showroom verschoben werden? Da passt der imo besser rein. -
Ah - jetzt habichs erfolgreich auf 2010 runterschrauben - nun kann man ja schon was sehen
Und dann kannman auch den Plan dahinter verstehen, und versuchen zu erklären:
Also Kern eines Spiels ist das GameLoop - Objekt. Da hinein tut der SpieleEntwickler seine SpielObjekte.
Der Gameloop tut nix als vonne SpielObjekte immer.Update()
und.Render(IRenderer renderer)
aufzurufen, also ein SpielObjekt, was sichtbar sein soll, muß IRenderable implementieren, und wenns auch noch beweglich ist, oder sonstwie seinen Status ändert, dann sollte es auch IUpdateable implementieren, damit es eine.Update()
-Funktion hat, mit ders sich dann updatet.
(kann man jetzt diskutieren, ob der GameLoop nicht einfacher 2 Events feuern täte, und ein Spiel-Objekt könnte halt dasGameLoop.Update
-Event abonnieren, wenns sich updaten möchte.)
Ein anners KernKonzept von GameUtils speziell ist nun, dass verschiedene Zeichnungs-Technologien unterstützt werden sollen, etwa GDI und SharpDx. Das erfordert einen enormen Aufwand, nämlich es muß ein allgemeingültiger Werkzeugkasten definiert werden, der ausreichend Mal-Möglichkeiten bereitstellt, um Objekte gescheit darzustellen. Das ist hier definiert:C#-Quellcode
- using System;
- using Artentus.GameUtils.Graphics;
- namespace Artentus.GameUtils {
- public interface IRenderer : IDisposable {
- IFactory Factory { get; }
- void BeginRender();
- void EndRender();
- void DrawLine(Vector2 p1, Vector2 p2, IBrush brush, float strokeWidth);
- void DrawEllipse(Ellipse ellipse, IBrush brush, float strokeWidth);
- void FillEllipse(Ellipse ellipse, IBrush brush);
- void DrawRectangle(Rectangle rect, IBrush brush, float strokeWidth);
- void FillRectangle(Rectangle rect, IBrush brush);
- void DrawText(string text, IFont font, IBrush brush, Rectangle rect, ITextFormat format);
- void DrawText(string text, IFont font, IBrush brush, Vector2 pt);
- void DrawBitmap(IBitmap bmp, Rectangle rect, float opactiy);
- void DrawBitmap(IBitmap bmp, Vector2 pt, float opacity);
- void Clear(Color4 color);
- void DrawGeometry(IGeometry geometry, IBrush brush, float strokeWidth);
- void FillGeometry(IGeometry geometry, IBrush brush);
- void Initialize(System.Windows.Forms.Control surface, RendererPresentation presentationOption);
- void DrawPolygon(Polygon polygon, IBrush brush, float strokeWidth);
- void FillPolygon(Polygon polygon, IBrush brush);
- }
- }
Sieht logisch aus, und einfacher, als es ist, denn die ganzen Typen, die da vorkommen:Ellipse, IBrush, Rectangle, IFont, ITextFormat, Vector2, IBitmap, Color4, IGeometry, Polygon
- die sind weder in Gdi noch in SharpDx bekannt.
Natürlich kennt Gdi Ellipsen, Brushes, Rectangles - aber halt seine eigenen Klassen. Und ebenso SharpDx - das hat auch seine eigenen Klassen dafür.
Also ein Renderer muß eine ganze Infrastruktur an Konvertern schreiben, sodass etwa ein Gdi-Renderer eine Ellipse in eine Gdi-Ellipse konvertiert (gibts bei dene nich, die nehmen Rectangles dafür), und ein SharpRenderer musse in eine Sharp-Ellipse konvertieren, um rendern zu können.
Also die 3-fache Arbeit, als wenn einfach nur eine Gdi-Engine gemacht worden wäre:- Standard-Infrastruktur aus Interfaces und Standard-Klassen coden
- Konverter-Schicht coden, die den standardisierten Kram in Gdi-Objekte übersetzt
- das eigliche Zeichnen mit Gdi
Und es handelt sich um eine echte mehrschichtige Architektur, und zwar an einem sinnvollem Beispiel - sowas ist extrem selten!
Die Mehrschichtigkeit kann man auch als Umsetzung des Strategy-Patterns auffassen, also die untere Schicht kann man austauschen (Sharp-Renderer oder Gdi-Renderer) und die Spiel-Logik in der standardisierten Schicht merkt das nichtmal.
Also der Spiele-Entwickler ist aufgefordert, SpielObjekt-Klassen zu coden, die (nach Bedarf)IUpdateable
undIRenderable
implementieren, und die werden dem Gameloop zugefügt. Dassis der Rahmen, in dem sich für ihn (den Spiele-Entwickler) alles abspielt.
Beim Rendern stehen ihm die oben aufgeführten standardisierten Zeichenmethoden zur Verfügung.
(Dabei frage ich mich grade, obs gut ist, dass IRenderer auch dieFactory
-Property undBegin-/End-Render()
veröffentlicht - das sollte ein Spiel-Objekt doch besser nicht kennen, oder?)
Irritieren tut mich auch beim PhysikManager, dass da auf eine statische Instanz innerhalb der Program-Klasse zugegriffen wird.
Da sollte man doch einen Singleton machen, inne PhysikManager-Klasse angelegt, oder?
Ansonsten ist das mittm PhysikManager sehr fein: Der ist ganz auf der standardisierten Ebene geproggt (hoffe ich jdfs), und bedient dadurch ohne es zu wissen sowohl den Gdi-Renderer als auch den Sharp-Renderer.
Im Kontext des grundsätzlichen Konzepts binnich mitte Interfaces hier im Großen und ganzen versöhnt, also mit Interfaces kann man sowas lösen (wie auch mit Basisklassen, Delegaten oder auch Events).
Nur sowas:hä?
Auch mitIBitmap
habichn Problem - scheinbar ist nicht vorgesehen, Bitmaps auch schräg anzuzeigen. Ich könnte mir eine BasisklasseLocalizable
vorstellen, die 3 Punkte einer Raute angibt. Damit kann man sowohl waagerechte Rechtecke darstellen als auch schiefe, und sogar rautenmäßig verzerrte.
Gdi+-DrawImage(image As System.Drawing.Image, destPoints() As System.Drawing.Point)
etwa zeichnet die Bitmap genau in die durch 3 Punkte aufgespannte Fläche.
vlt. kannman IBitmap komplett rausschmeissen und durch FillRectRectangle ersetzen, wenn man letzterem einen TextureBrush mitgibt. Ich weiß nur nicht, ob GameUtils ein ITextureBrush vorsieht.
Für die GameUtils ist ja uninteressant, dass eine Bitmap hinter diesem Interface stecken soll - denkbar wären ja auch annere rechteckige Objekte wie Rechtecke oder auch Text.
Wie gesagt: dasIBitmap
versteh ich nicht recht: Eiglich könnte esWidth
undHeight
doch auch weglassen, und die Draw-Funktion gliche derFillRectAngle
-Funktion, nur statt desBrushes
übergäbe man dieIBitmap
- ein leeres Interface, von dem nur der Renderer die BildDaten abzurufen weiß. -
Vielen Dank, das nenne ich mal konstruktive Kritik.
Ich werd jetzt einfach mal die einzelnen Punkt abklappern.
ErfinderDesRades schrieb:
Dabei frage ich mich grade, obs gut ist, dass IRenderer auch die Factory-Property und Begin-/End-Render() veröffentlicht - das sollte ein Spiel-Objekt doch besser nicht kennen, oder?
Die Factory hingegen muss unbedingt bekannt sein, über die werden ja die ganzen Sachen wie Brushes, Fonts, Bitmaps usw. erstellt. Ich bin mit dem Factory-System aber eh etwas unzufrieden, da werde ich möglicherweise nochmal was ändern.
ErfinderDesRades schrieb:
Da sollte man doch einen Singleton machen, inne PhysikManager-Klasse angelegt, oder?
ErfinderDesRades schrieb:
Nur sowas:
C/C++-Quelltext
1
2
3
public interface IGameComponent : IDisposable
{
}
hä?
ErfinderDesRades schrieb:
Auch mit IBitmap habichn Problem - scheinbar ist nicht vorgesehen, Bitmaps auch schräg anzuzeigen. -
Artentus schrieb:
Dieses Interface ist dafür da, IRenderables und IUpdateables in ein und der selben Liste halten zu können, damit ich nicht Klassen, die beides implementieren, einmal zur Renderer-Liste und einmal zur Update-Liste hinzufügen muss.
Aber was hälste von solch Add-Methoden:
Die letzte Überladung ist die lustigste, der kannste nur Componenten adden, die beides implementieren -
-
kapier ich nix von - scheinbar sollen gewisse Changes erst verzögert zur Wirkung kommen - k.A., ob das sinnvoll ist.
ich schnall ja schon hierbei ab:
Und ist doch auch sinnlos, falls die Komponente garnet IUpdateable ist.
Also da sehe ich keinen Grund, nicht 2 verschiedene Listen zu verwenden.
Und noch genauer hingeguckt: Diese Synchronisation soll ja glaub verhindern, dass ein Objekt gerendert wird und gleichzeitig geupdated. Das kann aber nur auftreten bei Objekten, die auch beide Interfaces implementieren. Alles annere sollte doch von solch PerformanceFressern verschont bleiben, oder?
Wäre recht einfach zu lösen auch mit meine 3 AddComponent-Überladungen: Nur in der 3. Überladung würden den Componenten Lock-Objekte zugeordnet.. -
Das geht leider nicht anders. Frag mich nicht warum, aber wenn ich den Lock in der If-Abfrage durchführe, dann funktionierts nicht wie gewollt. Ebensowenig funktioniert ein normaler lock-Block.
Wenn Monitor.Enter erfolgreich ausgeführt wird, sollte das aber keinen merklichen Performanceverlust nach sich ziehen. -
k.A., was du meinst - folgendes scheint jdfs. zu gehen:
C#-Quellcode
- private void UpdateLoop() {
- Stopwatch sw = new Stopwatch();
- while(loopRunning) {
- sw.Start();
- for(int i = 0; i < components.Count; i++) {
- var component = components[i] as IUpdateable;
- if(component != null) {
- lock(components.GetLocker(component)) {
- component.Update();
- }
- }
- }
- components.ApplyChanges();
- sw.Stop();
- double targetMilliseconds = 1000.0 / TargetUpdatesPerSecond;
- if(sw.ElapsedMilliseconds < targetMilliseconds)
- Thread.Sleep((int)(targetMilliseconds - sw.ElapsedMilliseconds));
- sw.Reset();
- }
- }
und wenn ich da noch länger drauf gucke, wird daraus:C#-Quellcode
- private void UpdateLoop() {
- Stopwatch sw = new Stopwatch();
- while(loopRunning) {
- sw.Start();
- foreach(var component in components.OfType<IUpdateable>()) {
- lock(components.GetLocker(component)) {
- component.Update();
- }
- }
- components.ApplyChanges();
- sw.Stop();
- double targetMilliseconds = 1000.0 / TargetUpdatesPerSecond;
- if(sw.ElapsedMilliseconds < targetMilliseconds)
- Thread.Sleep((int)(targetMilliseconds - sw.ElapsedMilliseconds));
- sw.Reset();
- }
- }
-
-
ich kann ja nur den GDI-Renderer testen, vlt liegts daran.
Und ob foreach und OfType gegenüber Monitor.Enter noch groß ins Gewicht fallen bliebe erstnoch zu testen.
-
Benutzer online 2
2 Besucher
-
Ähnliche Themen
-
CatchTheBird - - Sonstige Problemstellungen
-
GirlOnFire - - Multimedia- und Spieleprogrammierung