D: mutable Keyword
Einige kennen sicher das Keyword mutable aus C++.
In D gibt es kein entsprechendes Äquivalent, const bleibt auch const. Diese Gebenheit nervte mich in letzter Zeit jedoch etwas. Vor allen bei debugging/Log Sachen wäre es mal nützlich, einfach eine mutable Eigenschaft in einer als const Deklarierten Methode zu verwenden.
Für alle die es nicht wissen: eine const deklarierte Methode sieht folgendermaßen aus:
void foo() const {
//some code here}
Das const “sagt” dem Compiler sozusagen, dass diese Methode das Objekt an sich nicht verändert.
Allerdings: wenn eine Eigenschaft eines Objekts verändert wird, ändert sich doch der komplette Zustand des Objekts. Also wozu als mutable deklarieren?
Debugging oder Logging Mitschnitte (oder derartig vergleichbares) verändern nicht wirklich den Zustand, jedenfalls nicht ausschlaggebend. Und für Debugging immer wieder das const auszukommentieren und in der Release wieder hinzuzufügen kann schon nach einer kurzen Weile etwas “nerven”.
Daher habe ich mir eine kleine Struktur geschrieben und einen dazugehörigen Test der die Benutzung demonstriert.
Damit sollte das mutable aus C++ emuliert werden. Eventuell hat ja jemand Interesse daran:
private import std.stdio; private import std.conv; final struct mutable(T) { private: const T _value; void _assign(U)(U val) const { //writeln("private assign: " ~ to!(string)(val)); T * copy = cast(T*) &this._value; *copy = cast(T) val; } public: this(T val) { this._value = val; } this(const ref mutable!(T) val) { this._value = val.value; } mutable!(T) opAssign(U)(U val) const if (std.traits.isIntegral!(U) || std.traits.isSomeString!(U) || is(U == enum)) { this._assign(cast(T) val); return this; } mutable!(T) opAssign(U)(/+const ref +/mutable!(U) val) const { this._assign(val.value); return this; } mutable!(T) opOpAssign(string op, U)(U val) const { switch (op) { case "+": writeln("ADD"); U res = this._value + val; this._assign(res); break; case "-": writeln("SUB"); U res = this._value - val; this._assign(res); break; case "*": writeln("MUL"); U res = this._value * val; this._assign(res); break; case "/": writeln("DIV"); U res = this._value / val; this._assign(res); break; default: break; } return this; } mutable!(U) opBinary(string op, U)(U val) const { //mutable!(U) m; switch (op) { case "+": writeln("Bin. ADD"); U res = this._value + val; //m = res; return mutable!(U)(res); //break; case "-": writeln("Bin. SUB"); U res = this._value - val; //m = res;+ return mutable!(U)(res); //break; case "*": writeln("Bin. MUL"); U res = this._value * val; //writeln(typeid(U)); //m = res; return mutable!(U)(res); //break; case "/": writeln("Bin. DIV"); U res = this._value / val; //m = res; return mutable!(U)(res); //break; default: break; } //return m; assert(0); } bool opEquals(U)(const ref mutable!(U) m) const { if (m is null) return false; if (m is this) return true; return m.value == this._value; } bool opEquals(U)(U m) const { return m == this._value; } @property T value() const { writeln("VALUE: ", this._value); return this._value; } string toString() const { return to!(string)(this._value); } } enum Status { Stopped, Paused, Playing } class B { private: mutable!(ubyte) _id; mutable!(Status) _status; public: void pause() const { this._status = Status.Paused; } void stop() const { this._status = Status.Stopped; } void play() const { this._status = Status.Playing; } Status get_status() const { return this._status.value; } void setup(const ubyte val) const { _id = val; writefln("(=) ID: %d", _id); _id = _id.value + 2; writefln("(+) ID: %d", _id); _id += 2; writefln("(+=) ID: %d", _id); _id -= 32; writefln("(-=) ID: %d", _id); _id *= 2; writefln("(*=) ID: %d", _id); _id = _id + 2; writefln("(!+!) ID: %d", _id); _id = _id - 32; writefln("(!-!) ID: %d", _id); _id = _id * 1.2; writefln("(!*!) ID: %d", _id); writeln(typeid(typeof(_id.value))); _id = _id / 2.0; writefln("(!/!) ID: %d", _id); writeln(typeid(typeof(_id.value))); } } // in der main: B b = new B(); b.setup(128); writeln(b.get_status()); b.play(); writeln(b.get_status()); b.pause(); writeln(b.get_status()); b.play(); writeln(b.get_status()); b.stop(); writeln(b.get_status()); b.play(); writeln(b.get_status());
Nachtrag vom 12.01.2012
Ich habe die obige Struktur nochmal überarbeitet und an den Feinheiten geschliffen. Zudem habe ich nun daraus eine Klasse gemacht (geschah eher nach belieben als aus einem konkretem Grund).
Hier ist der Code:
private import std.stdio; private import std.conv : to; static private import std.traits; final class Mutable(T) { private: const T _value; void _assign(U)(const U val) const { T * copy = cast(T*) &this._value; *copy = cast(T) val; } public: this(const T value) { this._value = value; } this(const ref T value) { this._value = value; } void set_value(U)(U val) { this._assign(val); } @property T value() const { return cast(T) this._value; } alias value this; @disable static Mutable!(T) opAssign(U)(U val) { return null;//new Mutable!(T)(val); } const(Mutable!(T)) opAssign(U)(U val) const { if (is(T == Mutable)) { throw new Exception("Can't assign Mutable to Mutable!"); } this._assign(val); return this; } const(Mutable!(T)) opOpAssign(string op, U)(U val) const { switch (op) { case "+": //writeln("ADD"); U result = this._value + val; this._assign(result); break; case "-": //writeln("SUB"); U result = this._value - val; this._assign(result); break; case "*": //writeln("MUL"); U result = this._value * val; this._assign(result); break; case "/": //writeln("DIV"); U result = this._value / val; this._assign(result); break; default: break; } return this; } Mutable!(U) opBinary(string op, U)(U val) const { switch (op) { case "+": U result = this._value + val; return new Mutable!(U)(result); case "-": U result = this._value - val; return new Mutable!(U)(result); case "*": U result = this._value * val; return new Mutable!(U)(result); case "/": U result = this._value / val; return new Mutable!(U)(result); default: break; } assert(0); } bool opEquals(const T cmp) const { return cmp == this._value; } bool opEquals(const Mutable!(T) cmp) const { return cmp.value == this._value; } override string toString() const { return to!(string)(this._value); } } enum Status { Stopped, Paused, Playing } class B { private: const Mutable!(ubyte) _id; // mit "const" wird sichergestellt, dass _id beim ersten Aufruf initialisiert wird. const Mutable!(Status) _status; public: this() { this._id = new Mutable!(ubyte)(0); this._status = new Mutable!(Status)(Status.Stopped); } void pause() const { this._status = Status.Paused; } void stop() const { this._status = Status.Stopped; } void play() const { this._status = Status.Playing; } Status get_status() const { return this._status.value; } void setup(const ubyte val) const { _id = val; writefln("(=) ID: %d", _id); _id = _id.value + 2; writefln("(+) ID: %d", _id); _id += 2; writefln("(+=) ID: %d", _id); _id -= 32; writefln("(-=) ID: %d", _id); _id *= 2; writefln("(*=) ID: %d", _id); _id = _id + 2; writefln("(!+!) ID: %d", _id); _id = _id - 32; writefln("(!-!) ID: %d", _id); _id = _id * 1.2; writefln("(!*!) ID: %d", _id); writeln(typeid(typeof(_id.value))); writeln(typeid(typeof(_id))); assert(_id == 204); if (_id == 204) { writeln("Korrekt"); } _id = _id / 2.0; writefln("(!/!) ID: %d", _id); writeln(typeid(typeof(_id.value))); writeln(typeid(typeof(_id))); assert(_id == 102); } } void main() { B b = new B(); b.setup(128); writeln(b.get_status()); b.play(); writeln(b.get_status()); b.pause(); writeln(b.get_status()); b.play(); writeln(b.get_status()); b.stop(); writeln(b.get_status()); b.play(); writeln(b.get_status()); }
OpenGL oder SDL?
Die Frage stellt sich mir mehr und mehr.
Ich arbeite derzeit in den letzten Zügen an Dgame 1.6 und möchte danach direkt mit den Arbeiten an Version 1.7 beginnen.
Dort soll die große Änderung der Umstieg von SDL zu OpenGL sein, wobei nach neueren Kenntnisstand eher eine Symbiose zustande käme.
So würde man mittels der SDL das eigentliche Fenster erstellen und würde mit SDL_image weiterhin Bilder laden, diese dann aber, bzw. ihre Pixelsturktur, in eine GL Textur laden. Für etwaige Bildverarbeitung würden dann SDL spezifische Funktionen zu Hilfe genommen werden, wie es jetzt bereits der Fall ist.
OpenGL bzw. dessen Texturen würden für schnelleres und performanteres blitten und etwaige andere Bild Verarbeitungs Maßnahmen zu Hilfe genommen werden, wie etwa Rotation und Zoom.
More »
Sprites, Nachtrag
Vor einiger Zeit verfasste ich ja bereits ein Tutorial zu Sprites und der zugehörigen Klasse.
Mittlerweile weiß ich, dass das ganze wesentlich einfacher bzw. besser ginge, unter anderem mittels des Keywords @property.
More »
Dgame – pygame für die D Programming Language, Preview
Für die bisher im weiten Spektrum der Spieleprogrammierer recht unbekannte Sprache D Programming Language, welche im Grunde eine weiterentwickelte Form von C++ ist und so gut wie alle, wenn nicht alle, Vorzüge aus C++ besitzt, existieren zur Zeit leider noch recht wenige Lib’s und Frameworks. Dabei weist D viel weniger Mängel & Komplexität auf und ist dazu weniger überladen & wesentlich einfacher zu erlernen, laut meiner bescheidenen Meinung jedenfalls. Dazu kommt, dass die meisten Features und Weiterentwicklungen vom neuen aber noch auf sich warten lassenden Standard von C++ (C++0x) bereits implementiert sind und D somit eine Art modernes C++ darstellt.
Darüber hinaus ist die gesamte C Bibliothek fester Bestandteil und somit ist C Kompatibilität absolut gewährleistet.
Allerdings ist D viel zu neu, als das so viele Frameworks wie für C++, welche ja schon seit anno ’79 auf der Welt ist (D seit 2007, Quelle zu C++, Quelle zu D), existieren könnten. Durch das Projekt Derelict existiert allerdings ein Binding für einige C++ Bibliotheken (darunter SDL & OpenGL bspw.) und auch Allegro existiert bereits in D.
Als alter Python und Pygame Fan vermisste ich allerdings die Einfacheit und vorallen die Objekt-orientierte Benutzung einer solchen Lib., denn sowohl die SDL als auch OpenGL sind beinahe (mir fällt im Moment kein Objekt-orientiertes Beispiel ein) komplett funktional, und das liegt nicht an dem D – Binding, denn auch in der offiziellen Dokumentation zur Erklärung von SDL ansich und dessen Funktionsweise finden sich nur Funktionen, keine Klassen.
Die einzige Grafik Bibliothek in C++ die mir daher gefiel war SFML, da sie völlig Objekt-orientiert funktioniert.
SFML gibt es bereits für Python (PySFML) und auch für D existiert ein Binding (DSFML). Allerdings wird, auf Grund der bis dato mangelnden Verbreitung und Neuheit der Sprache, bisher eher zögerlich an DSFML gearbeitet, weswegen die aktuellste Version auf der 1.3′er Version von SFML beruht, wobei SFML für C++ bereits bei der 2′er Version angelangt ist (Quelle).
Deswegen entschied ich mich letzlich für Derelict. Auch dort existiert zwar ein Binding für SFML, doch dieses wird von Derelict (bislang?!) leider nur Funktional angeboten, was den ganzen Effekt zunichte macht.
Also setzte ich mich daran, einen solchen OOP Wrapper auch für D zu schreiben, welcher, wie Pygame, auf der SDL aufbaut.
More »
Sprites
Da bin ich wieder. Leider hat es diesmal etwas länger gedauert, ich war abgelenkt von diversen Projekten, die wohl auch in den nächsten Tagen hier gepostet werden.
Zum einen bin ich aktuell dabei für D eine pygame ähnliche Engine Struktur zu schaffen, da mir der ganze funktionale Code von SDL, statt Objekt Orientiertierung, wie ich es eben von pygame und generell von Python gewohnt bin, mächtig auf den Nerv geht.
Zum anderen haben ein paar Kollegen und ich beschlossen, ein Adventure Spiel zu entwickeln, wahrscheinlich in Python.
Aber in diesem Artikel möchte ich erklären, wie man Sprites auf die dazugehörige Karte zeichnet, so wie angekündigt.
Das mag für den einen ganz einfach klingen, ein Sprite ist ja nur eine Spielerfigur, sprich eine Grafik, also laden und an verschiedene Positionen blitten … oder doch nicht?
More »