Laden...

Forenbeiträge von RBA285 Ingesamt 68 Beiträge

03.05.2010 - 21:11 Uhr

Hi Forengemeinde,

um mein Verständnis hinsichtlich der Funktionsweise von Generics zu vertiefen,
habe ich versucht, eine eigene (einfache) Dictionary-Class zu definieren, die
im Wesentlichen nur das INumerable-Interface implementieren und einige
Grundmethoden eines Dictionaries (z.B. Add) besitzen soll. Nach einigen Stunden
des Überlegens und Probierens stecke ich bei folgendem Punkt fest:
Der Compiler bemängelt eine fehlende GetEnumerator()-Methode, die
aber vorhanden ist. Ich vermute einen Zusammenhang mit den Generics
TKey und TValue, komme aber nicht darauf, was er nun eigentlich nicht mag.

Lange Rede, kurzer Sinn. Hier ist der komplette Klassen-Code:


    //---------------------------------------------------------------
    public class MeinDictionary<TKey, TValue> : IEnumerable<KeyValuePair<TKey, TValue>>
    //---------------------------------------------------------------
    {
        List<TKey> _keys;
        List<TValue> _values;

        //---------------------------------------------------------------
        public MeinDictionary()
        //---------------------------------------------------------------
        {
            this._keys = new List<TKey>();
            this._values = new List<TValue>();
        }

        //---------------------------------------------------------------
        public void Add( TKey key, TValue value )
        //---------------------------------------------------------------
        {
            this._keys.Add(key);
            this._values.Add(value);
        }

        //---------------------------------------------------------------
        public MeinDictionaryEnum<TKey, TValue> GetEnumerator()
        //---------------------------------------------------------------
        {
            return new MeinDictionaryEnum<TKey, TValue>(this._keys, this._values);
        }
    }

    //---------------------------------------------------------------
    public class MeinDictionaryEnum<TKey, TValue> : IEnumerator<KeyValuePair<TKey, TValue>>
    //---------------------------------------------------------------
    {
        List<TKey> _keys;
        List<TValue> _values;
        int _position;

        //---------------------------------------------------------------
        public MeinDictionaryEnum(List<TKey> keys, List<TValue> values)
        //---------------------------------------------------------------
        {
            this._keys = keys;
            this._values = values;
            this._position = -1;
        }

        //---------------------------------------------------------------
        public bool MoveNext()
        //---------------------------------------------------------------
        {
            this._position++;
            return (this._position < this._keys.Count);
        }

        //---------------------------------------------------------------
        public void Reset()
        //---------------------------------------------------------------
        {
            this._position = -1;
        }

        //---------------------------------------------------------------
        public object Current
        //---------------------------------------------------------------
        {
            get
            {
                try
                {
                    return new KeyValuePair<TKey, TValue>(this._keys[this._position], this._values[this._position]);
                }
                catch (IndexOutOfRangeException)
                {
                    throw new InvalidOperationException();
                }
            }
        }
    }

Wo ist mein Denkfehler?

Google und Forensuche wurden natürlich schon hinreichend gequält - leider
ohne Erfolg. Ebenso habe ich mir die Signatur des Originals angesehen, von
dem ich mir das o.g. in der Klassendefinition abgeguckt habe. Es muss also
irgendwie funktionieren.

Danke,
Robin

02.05.2010 - 20:26 Uhr

Und schon hat man einen Nachkommaanteil vermieden.
Müsste IMHO am schnellsten laufen. Wie gesagt, heut Abend ist testen angesagt 😃

Stimmt, die Lösung ist cool. Trotzdem hat herbivore Recht, decimal ist aus
verschiedenen Gründen besser: Größerer Zahlenraum und schnellere
Implementierung. Decimal ist im Speicher eine Hexzahl, die einen Zähler
über die Nachkommastellen mitführt und nicht erst umständlich wie float und
double umgerechnet werden muss. Zudem kann man bei Deinem Beispiel noch
eine Modulo-Operation einsparen, wenn man einen Hilfsparameter bei der
Zuweisung setzt.

So müsste das vorläufige Optimum aussehen:

static decimal Reverse(decimal n)
        {
            decimal r, x;
            for (r = 0m; n != 0; n /= 10)
            {
                r = 10 * r + (x = n % 10);
                n -= x;
            }

            return r;
        } 

Ach ja, eines würde mich noch interessieren: Für welche Anwendung
brauchst Du das und warum ist das gar so zeitkritisch?

Robin

02.05.2010 - 13:01 Uhr

Kann den Einwand gut nachvollziehen, an diesem Punkt habe ich auch lange
hin- und herüberlegt. Natürlich kann man das Game auf eine niedrigere
Auflösung designen, allerding hat man dann bei einem hochauflösenden
Monitor nur ein hochgerechnetes, gröberes Bild. Das wollte ich nicht. Ich wollte
die Auflösung voll ausnutzen. Eine weitere Alternative wäre gewesen, für
verschiedene Auflösungen verschiedene Texturen und Fonts zu verwenden.
Das wiederum wäre vom Aufwand nicht vertretbar gewesen.

So habe ich mich letztendlich für 1600+ entschieden. Aber jeder der mag,
darf die Sourcen gerne auf eine niedrigere Auflösung anpassen. Ist halt
undankbare Arbeit, die ganzen Coords runterrechnen und ausprobieren.

Robin

02.05.2010 - 12:06 Uhr

Hi Forengemeinde,

habe mich die letzten Wochen aus persönlicher Neugier mit dem Thema XNA
beschäftigt. Herausgekommen ist ein ganz passabler 2D-Shooter, ein
Remake des Klassikers "Space Invaders". Wer Interesse hat, sowie das
XNA Redistributable 3.1 oder das XNA Gamecenter 3.1 installiert und
einen Monitor ≥ 1600 Pixel in der Horizontalen (ideal: 1920 x 1200) kann
sich das Game hier downloaden und eine Runde spielen:

http://www.scriptinghost.com/SpaceInvaders/
(ca. 30 MB)

Highscores werden zentral auf einen Webserver abgelegt, d.h. die Highscoreliste
ist global gültig. Deshalb wäre auch eine Online-Verbindung gut, ist aber nicht
Voraussetzung um zu spielen.

Über Manöverkritik von den XNA-Profis bin ich natürlich immer dankbar 😃

Bei Interesse gibt es auch die Sourcen, falls die jemand haben will.

Grüße,
Robin

02.05.2010 - 11:35 Uhr

Oha, habe noch einen Käfer in meinem Beispiel entdeckt.

So funktionierts bis hin zu getesteten 78912344551266444765599465312:


private decimal reverseNum(decimal decSource)
        {
            decimal decSource = Convert.ToDecimal(this.textBox1.Text);

            ulong[] n = new ulong[2];
            ulong[] r = new ulong[2];
            ulong r0;
            decimal result;
            decimal tempDec1;
            decimal tempDec2;
            int shiftLeft;
            
            tempDec1 = (decSource / 100000000000000m);
            tempDec1 = (ulong)tempDec1;
            tempDec2 = (decSource - (tempDec1 * 100000000000000m));
            n[0] = (ulong)tempDec1;
            n[1] = (ulong)tempDec2;

            for( int i = 0; i < 2; i++ )
            {
                for (r[i] = 0; n[i] != 0; n[i] /= 10)
                    r[i] = 10 * r[i] + n[i] % 10;
            }

            for (shiftLeft = 0, r0 = r[0]; r0 > 0; r0 /= 10, shiftLeft++);

            result = (decimal)r[1] * (decimal)(Math.Pow(10, shiftLeft)) + (decimal)r[0];
            return( result );
        } 

Persönlich finde ich diese decimal Erweiterung schöner:
z. B. 647m.reverse() => 746m


public static class stringReverse
    {
        private static decimal reverse(this decimal d)
        {
            char[] c = d.ToString().ToCharArray();
            Array.Reverse(c);
            return (Convert.ToDecimal(new string(c)));
        }
    }

Lass mal ein paar tausend Sätze mit beiden Methoden konvertieren und schau Dir
das Zeitverhalten an.

Robin

02.05.2010 - 09:47 Uhr

Mit decimal funktioniert die Formel nicht mehr und dann landet man doch
bei der Stringverarbeitung.

Ich würde die Zahl einfach zerlegen und am Ende wieder zusammenführen:

private decimal reverseNum(decimal decSource)
        {
            long[] n = new long[2];
            long[] r = new long[2];
            long r0;
            decimal result;
            int shiftLeft;

            n[0] = (long)(decSource / 1000000000);
            n[1] = (long)(decSource - (n[0] * 1000000000));

            for( int i = 0; i < 2; i++ )
            {
                for (r[i] = 0; n[i] != 0; n[i] /= 10)
                    r[i] = 10 * r[i] + n[i] % 10;
            }

            for (shiftLeft = 0, r0 = r[0]; r0 > 0; r0 /= 10, shiftLeft++) ;

            result = (decimal)(r[1] * Math.Pow(10, shiftLeft) + r[0]);

            return( result );
        }

Wenn man die Arrays dynamisch gestaltet und aussenrum noch
eine Schleife spendiert, lassen sich in der Theorie beliebig große Zahlenräume
"reversen".

Wobei die Frage die ist, ob es tatsächlich langsamer ist, wenn man z.B.
die Stringklasse durch ein static erweitert und einfach einen pointer rückwärts
laufen lässt, der eine Kopie des Strings anfertigt.

Robin

25.04.2010 - 01:28 Uhr

Hallo, für ein Spiel programmiere ich einen TCP Server und Client

Läuft nun endlich so wie alles soll. Der Server empfängt und sendet auch Daten an
den zuvor verbundenen Client. Der Sendet und empfängt ebenfalls Strings.

Soweit sogut.

Nun möchte ich ja nicht nur 1 Server und 1 Client haben.

Ich dachte daran den Server 4 x zu starten damit sich dann max. 4 Clients
connecten können.

Andersrum gefragt: Was willst Du bezwecken? Normalerweise läuft das so,
dass Du einen Server startest, auf dem sich dann n Clients connecten.
Der eine Server koordiniert dann die Kommunikation der n Clients.
Beispiel-Source hier: http://www.codeproject.com/KB/IP/BasicTcpServer.aspx

Für die Speicherung der Positionsdaten gibt es ebenfalls tonnenweise
Möglichkeiten. Wenn es nur X/Y ist, würde ich zu einem Array greifen.
Braucht es mehr Info, eine List oder ein eigenes Objekt.

Robin

24.04.2010 - 19:36 Uhr

Versuche es mal damit:

<?xml version="1.0" encoding="iso-8859-1"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

<xsl:decimal-format name="de" decimal-separator="," grouping-separator="."/>

<xsl:template match="/">
 <html>
 <head>
 </head>
 <body>
 <xsl:apply-templates />
 </body>
 </html>
</xsl:template>


<xsl:template match="Player">
<td>
    <xsl:for-each select="ExpMutation">
    <xsl:value-of select="format-number(.,'#.##0','de')" />
    </xsl:for-each>
</td>
</xsl:template>

</xsl:stylesheet>

Farbe, Table-Formatierungen usw. musst Du natürlich noch wie benötigt
einbauen.

Robin

22.04.2010 - 08:22 Uhr

Hallo Forengemeinde,

folgende Situation: Bei einem Game werden gewisse Texturen zur
Laufzeit geändert und sollen bei jedem neuen Level neu über einen
separaten(!) Contentmanager geladen werden.

Das klappt auch ausgezeichnet mit folgendem Code, der bei jedem Game-Level
aufgerufen wird:

 shieldContent.Unload();

            for (int i = 0; i < 3; i++)
            {
                this.shieldTexture[i] = shieldContent.Load<Texture2D>("shield" + (i + 1).ToString());
                this.shieldColorArray[i] = TextureTo2DArray(this.shieldTexture[i]);
            }

Den Contentmanager, der nur dafür da ist, diese speziellen Texturen zu
verwalten, wird im Konstruktor wie folgt initialisiert:

this.shieldContent = new ContentManager(this.Services, "Content");

Auch das funktioniert ohne Probleme. Was mich stört ist, dass ich mit dem
IServiceProvider-Interface, welches beim Erzeugen des Contentmanagers
mit angegeben muss nichts anfangen kann. D.h. ich weiß nicht wofür dieses
Interface in diesem Kontext gut sein soll. Die Fachliteratur schweigt sich aus, im
Internet findet man ab und an den Tipp, das Interface selbst zu implementieren
und nicht das aus dem Game zu nehmen. Die oben angebene Lösung mit
dem "this.Services" funktioniert ohne Probleme. Die Frage ist, ob das auch
"sauber" ist.

Also, wofür ist dieses Interface in diesem Kontext gut und kann ich unbedenklich
das aus dem Game (this.Services) verwenden?

Vielen Dank,
Robin

18.04.2010 - 11:16 Uhr

Nehm die Bewegung noch mit gameTime.Milliseconds mal.

gameTime war der goldene Hinweis!

Habe im Gamekonstruktur folgende Zeilen hinzugefügt:


this.IsFixedTimeStep = true;
TargetElapsedTime = new TimeSpan(10000000L / 500L);

Schon flutscht der Ball, wie er sollte. Ist hier auch gut dokumentiert:
Game.TargetElapsedTime Property

Wenn man doch nur immer wüsste, wonach man suchen muss. 😁

Vielen Dank nochmal,
Robin

18.04.2010 - 09:37 Uhr

Danke für den Tipp. Die Verlagerung nach Update hat geschwindigkeit-
technisch leider nichts gebracht. Den this.IsFixedTimeStep-Parameter
habe ich ebenfalls auf "false" gesetzt, leider ohne Erfolg.

Es könnte ja auch möglich sein, dass die "Langsamkeit" so normal ist,
ich wundere mich nur, da ich das einfach deutlich schneller erwartet habe.

Robin

18.04.2010 - 09:11 Uhr

Hallo Forengemeinde,

folgende kleine Methode lässt eine Ball-Textur im Fenster eines XNA Win-Games
kreuz- und quer "bouncen":


        //-------------------------------------------
        private void drawBall()
        //-------------------------------------------        {
            ball.Position.X += ball.DirectionX * ball.Speed;
            ball.Position.Y += ball.DirectionY * ball.Speed;

            if (ball.Position.X + ball.DirectionX * ball.Speed >= graphics.PreferredBackBufferWidth || ball.Position.X <= 0)
                ball.DirectionX = -ball.DirectionX;

            if (ball.Position.Y + ball.DirectionY * ball.Speed >= graphics.PreferredBackBufferHeight || ball.Position.Y <= 0)
                ball.DirectionY = -ball.DirectionY;

            spriteBatch.Draw(ballTexture, ball.Position, Color.White);          
        }

Die Klasse "Ball" selbst hält nur die aktuellen Koordinaten und die
"Geschwindigkeit", d.h. um wieviele Pixel X und Y sich der Ball pro Draw-
Zyklus bewegt. Die Textur wird nicht skaliert. Die drawBall()-Methode wird
im Draw-Block des Games aufgerufen.

Frage: Wenn die Schrittweite pro Draw-Vorgang nur ein Pixel ist, schleicht der
Ball geradezu über den Bildschirm. Meine Erwartungshaltung war die,
dass das mit XNA irgendwie deutlich schneller funktioniert. Natürlich kann
man das über die Schrittweite (="Speed") steuern, aber irgendwann wird das dann
ruckelig.

Lässt sich das einfach ändern oder habe ich was grundsätzliches übersehen?

Vielen Dank,
Robin

17.04.2010 - 12:55 Uhr

Hi,

das Thema interessiert mich auch. Ich habe es von der MS-Produktstrategie bisher
so verstanden, dass DirectX bei C# nur noch über das XNA-Framework als
Wrapper laufen soll.

Was ich bisher von XNA gesehen habe, gefällt mir ganz gut.
Hier gibts auch ein gutes Tutorial: http://www.riemers.net/

Robin

16.04.2010 - 17:50 Uhr

Große Erleuchtung. Bin nach gut 30 Minuten intensiven Nachdenkens und
Probierens selbst drauf gekommen. So passt alles in ein
LINQ-Statement und man kann noch zusätzliche DB-Felder mitgeben:

//-----------------------------------------------------------------------------------------------------------------
        private void butLos_Click(object sender, EventArgs e)
        //-----------------------------------------------------------------------------------------------------------------
        {
            KontaktDBDataContext _meineDBConnect = new KontaktDBDataContext();

            var ergebnis = from records in _meineDBConnect.Personen
                           group new { Name = records.Name, EMail = records.Email } by records.Firma into resultset
                           select resultset;

            this.txtErgebnis.Text = "";

            foreach (var myGroup in ergebnis)
            {
                this.txtErgebnis.Text += "Firma: " + myGroup.Key.ToString() + "(" + myGroup.Count().ToString() + ")\r\n";

                foreach (var record in myGroup)
                {
                    this.txtErgebnis.Text += record.Name.ToString() + "\r\n";
                }
                this.txtErgebnis.Text += "\r\n\r\n";
            }
        }

Etwas gewöhnungsbedürftig der LINQ-Syntax. =)
Hätte mich doch gewundert, wenn man die DB zweimal nerven muss.

Robin

16.04.2010 - 16:44 Uhr

Ausgangssituation: Eine einfache SQL-Server DB Tabelle namens "Personen"
mit den char-Feldern "Firma" und "Name" im Verhältnis 1:n (eine Firma, n Namen).

Aufgabenstellung: Nach Firma gruppieren, die Firma als Überschrift mit Anzahl
gefundener Personen anzeigen und die Personen direkt unterhalb der Firma
einzeln auflisten. Dies Firma pro Firma, siehe beil. Screenshot.

Hier der funktionierende Code:

//-----------------------------------------------------------------------------------------------------------------
        private void butLos_Click(object sender, EventArgs e)
        //-----------------------------------------------------------------------------------------------------------------
        {
            KontaktDBDataContext _meineDBConnect = new KontaktDBDataContext();

            var ergebnis = from records in _meineDBConnect.Personen
                           group records.Firma by records.Firma into resultset
                           select resultset;

            this.txtErgebnis.Text = "";

            foreach (var myGroup in ergebnis)
            {
                this.txtErgebnis.Text += "Firma: " + myGroup.Key.ToString() + "(" + myGroup.Count().ToString() + ")\r\n";

                var ergebnis1 = from records in _meineDBConnect.Personen
                                where records.Firma == myGroup.Key.ToString()
                                select records;

                foreach (var record in ergebnis1)
                {
                    this.txtErgebnis.Text += record.Name.ToString() + "\r\n";
                }
                this.txtErgebnis.Text += "\r\n\r\n";
            }
        }

Frage: Ist diese Lösung mit zwei "selects" so elegant oder geht das besser?
Ich komme aus der SQL-Ecke und bin mit dem Syntax und den Möglichkeiten
von LINQ noch nicht so vertraut.

Vielen Dank!
Robin

11.04.2010 - 23:11 Uhr

Und zwar hab ich eine Listbox die dynamisch während der Laufzeit geladen werden.
Nun füge ich jedem Item ein Eventhandler für die Click Funktionen hinzu.

Allerdings habe ich hier kein Sender Object da alles von einer Library vorgegeben ist.

Der Weg über das Event wäre beispielhaft so:

        private void listBox1_SelectedIndexChanged(object sender, EventArgs e)
        {
            MessageBox.Show(((ListBox)sender).SelectedIndex.ToString());
        }

Wenn das über eine selbstgestrickte Lib läuft, sollte der direkte Zugriff
auf das Listbox-Item so klappen:

MessageBox.Show(this.listbox1.SelectedIndex.ToString());

Ich verstehe noch nicht ganz, wie Du ein individuelles Click-Event auf ein einzelnes
Element bekommst. Die Events feuert doch immer das Control, nicht das Item.

So etwas wie Funktionen zu Laufzeit habe ich schon irgendwo gelesen, nennt
sich Parser bzw. Evaluator, ist aber m.E. für den gedachten Einsatzzweck
ziemlicher overkill.

Robin

11.04.2010 - 10:31 Uhr

Wow, eine hilfreiche Antwort binnen einer Minute! Klasse Forum. Vielen Dank!

Robin

11.04.2010 - 10:24 Uhr

Hallo Forengemeinde,

ich beiße mich gerade durch die Themen Delegates, Events & Co.

Dabei ist mir folgendes aufgefallen: In den Büchern wird die gültige
Syntax für das Hinzufügen eines Event-Delegates wie folgt
beschrieben (Beispiel):

this._tempTimer.Tick += new EventHandler(tempTimer_Tick);

Allerdings ist mir aufgefallen, dass auch diese Zuweisung problemlos
funktioniert und akzeptiert wird:

this._tempTimer.Tick += tempTimer_Tick;

Gibt es einen funktionalen Unterschied zwischen beiden Methoden?
Innerhalb meines Programmes konnte ich keinerlei Unterschiede am
Laufverhalten erkennen, beides funktioniert.

Vielen Dank,
Robin