• Hallo liebe Userinnen und User,

    nach bereits längeren Planungen und Vorbereitungen sind wir nun von vBulletin auf Xenforo umgestiegen. Die Umstellung musste leider aufgrund der Serverprobleme der letzten Tage notgedrungen vorverlegt werden. Das neue Forum ist soweit voll funktionsfähig, allerdings sind noch nicht alle der gewohnten Funktionen vorhanden. Nach Möglichkeit werden wir sie in den nächsten Wochen nachrüsten. Dafür sollte es nun einige der Probleme lösen, die wir in den letzten Tagen, Wochen und Monaten hatten. Auch der Server ist nun potenter als bei unserem alten Hoster, wodurch wir nun langfristig den Tank mit Bytes vollgetankt haben.

    Anfangs mag die neue Boardsoftware etwas ungewohnt sein, aber man findet sich recht schnell ein. Wir wissen, dass ihr alle Gewohnheitstiere seid, aber gebt dem neuen Board eine Chance.
    Sollte etwas der neuen oder auch gewohnten Funktionen unklar sein, könnt ihr den "Wo issn da der Button zu"-Thread im Feedback nutzen. Bugs meldet ihr bitte im Bugtracker, es wird sicher welche geben die uns noch nicht aufgefallen sind. Ich werde das dann versuchen, halbwegs im Startbeitrag übersichtlich zu halten, was an Arbeit noch aussteht.

    Neu ist, dass die Boardsoftware deutlich besser für Mobiltelefone und diverse Endgeräte geeignet ist und nun auch im mobilen Style alle Funktionen verfügbar sind. Am Desktop findet ihr oben rechts sowohl den Umschalter zwischen hellem und dunklem Style. Am Handy ist der Hell-/Dunkelschalter am Ende der Seite. Damit sollte zukünftig jeder sein Board so konfigurieren können, wie es ihm am liebsten ist.


    Die restlichen Funktionen sollten eigentlich soweit wie gewohnt funktionieren. Einfach mal ein wenig damit spielen oder bei Unklarheiten im Thread nachfragen. Viel Spaß im ngb 2.0.

[C#] Diverse Fragen

Cyperfriend

Der ohne Avatar

Registriert
14 Juli 2013
Beiträge
1.123
Da hier meist die gleichen Leute reingucken wissen ja die meisten wie sehr ich mit dem Programmieren kämpfe. Also lasst uns bitte nicht an Details hängen bleiben, wie was besser wäre und überhaupt. Ich will erstmal nur den logischen Ablauf an sich hinbekommen.

Ich habe eine kleine Demo, eine Art Prototyp geschrieben, die das Prinzip der textbasierten Browsergames in ein Windows-Programm packt. Ich habe alles kommentiert und die Fragen direkt in den Quellcode gepackt. Wäre super, wenn ihr mir helfen könntet. Wie gesagt: Es geht hier erstmal darum, dass das Programm überhaupt erstmal tut was es soll. Optimieren kann man später.

[src=csharp]
// Startwerte setzen und Variablen deklarieren
int Gold = 100000;
int Silber = 100000;
int Bronze = 100000;
int Stufe = 1;
int Zeit = 0;

private void Form1_Load(object sender, EventArgs e)
{
// Timer für die Ressourcenproduktion aktivieren
timer1.Enabled = true;
// Intervall für die Ressourcenproduktion aktivieren (1 Sekunde)
timer1.Interval = 1000;
}

private void tickRessourcen(object sender, EventArgs e)
{
// Warum wird nur einmal hochgezählt und bei ++ jede Sekunde?
lblGold.Text = "Gold: " + Convert.ToString(Gold + 3);
lblSilber.Text = "Silber: " + Convert.ToString(Silber + 2);
lblBronze.Text = "Bronze: " + Convert.ToString(Bronze++);
}

private void cmdBauen_Click(object sender, EventArgs e)
{
// Prüfen, ob genug Ressourcen vorhanden sind
if (Gold < 5000 || Silber < 3000 || Bronze < 1000)
{
MessageBox.Show("Zu wenug Ressourcen");
}
else
{
// Timer für das Bauprojekt aktivieren
timer2.Enabled = true;
// Intervall für das Bauprojekt aktivieren
timer2.Interval = 500;
// Ressourcen abziehen;
Gold = Gold - 5000;
Silber = Silber - 3000;
Bronze = Bronze - 1000;
// Wie lasse ich den timer zückwärts auf 0 laufen?
lblZeit.Text = "Zeit: ";
}
}

private void tickBauen(object sender, EventArgs e)
{

// Warum wird Stufe erst nach dem zweiten Klick erhöht?
lblStufe.Text = "Stufe: " + Stufe++;
// Timer für das Bauprojekt wieder deaktivieren
timer2.Enabled = false;
}
[/src]

Anhang anzeigen 31217
 

electric.larry

\''; DROP TABLE user; --
Teammitglied

Registriert
13 Dez. 2014
Beiträge
4.549
Ort
Raum 43
[src=csharp]private void tickRessourcen(object sender, EventArgs e)
{
// Warum wird nur einmal hochgezählt und bei ++ jede Sekunde?
lblGold.Text = "Gold: " + Convert.ToString(Gold + 3);
lblSilber.Text = "Silber: " + Convert.ToString(Silber + 2);
lblBronze.Text = "Bronze: " + Convert.ToString(Bronze++);
}[/src]

Weil Bronze++ eine Zuweisung ist, die anderen beiden Operationen aber nicht.

[src=csharp]lblGold.Text = "Gold: " + Convert.ToString(Gold + 3);[/src]

Das hier bedeutet, das Label soll den Wert der Variable Gold + 3 bekommen. Die Variable Gold selbst wird nicht verändert.

[src=csharp]lblBronze.Text = "Bronze: " + Convert.ToString(Bronze++);[/src]

Hier hingegen steht, das Label soll den Wert von Bronze bekommen und die Variable Bronze soll dann um 1 inkrementiert werden. Das wäre also die Kurzform von:

[src=csharp]lblBronze.Text = "Bronze: " + Convert.ToString(Bronze);
Bronze = Bronze + 1;[/src]

Wenn du möchtest, dass Gold und Silber das Selbe machen, wie Bronze, dann müsstest du schreiben:

[src=csharp]lblGold.Text = "Gold: " + Convert.ToString(Gold);
Gold = Gold + 3;

//Oder kürzer in einer Zeile

lblGold.Text = "Gold: " + Convert.ToString(Gold += 3); [/src]

Du musst darauf achten, dass der richtige Wert der Variable in dein Label geschrieben wird. In der Kurzform wird Gold + 3 geschrieben, in der längeren wird Gold geschrieben und erst danach um 3 erhöht.

[src=csharp]// Wie lasse ich den timer zückwärts auf 0 laufen?
lblZeit.Text = "Zeit: ";[/src]

Definiere zB eine Variable mit der Gesamtzeit und ziehe in einem Timer, der einmal pro Sekunde ausgeführt wird, die vergangene Zeit von der Gesamtzeit ab. Disable den Timer erst, wenn vergangene Zeit größer Gesamtzeit ist.

[src=csharp]// Warum wird Stufe erst nach dem zweiten Klick erhöht?
lblStufe.Text = "Stufe: " + Stufe++;[/src]

Selber Grund wie weiter oben schon erwähnt. Dieser Befehl setzt das Label auf den Wert der Variable "Stufe" und inkrementiert sie erst danach.

Willst du, dass die Variable vorher inkrementiert wird und ihr Wert erst danach angezeigt wird, könntest du das so formulieren:

[src=csharp]
lblStufe.Text = "Stufe: " + (++Stufe);[/src]

Als Anfänger würd ich aber vorerst die etwas längere Schreibweise bevorzugen:

[src=csharp]
Stufe += 1; //oder Stufe = Stufe + 1;
lblStufe.Text = "Stufe: " + Stufe;[/src]

Ich sehe oft Code der zwar sehr kompakt aber dadurch schwer leserlich ist. Ich verwende zwar selbst gerne Kurzschreibweisen, aber dort wo es die Lesbarkeit beeinflusst, schreib ich lieber drei Zeilen mehr. Vor Allem wenn man im kommerziellen Umfeld programmiert, geht es darum Zeit zu sparen. Wenn durch ein paar Zeilen mehr Code die Funktion eines Absatzes auf einen Blick ersichtlich wird, dann ist das mMn zu bevorzugen.

Schlechte Idee:

[src=csharp]print ( (getFirstValue(Param1, Param2) + 1) > getSecondValue(Param1, Param2) ? "first higher" : "second higher"); [/src]

Gude Idee:

[src=csharp]value1 = getFirstValue(Param1, Param2);
value1 += 1;
value2 = getSecondValue(Param1, Param2);

print (value1 > value2 ? "first higher" : "second higher or equal"); [/src]
 

BurnerR

Bot #0384479

Registriert
20 Juli 2013
Beiträge
5.507
Wenn durch ein paar Zeilen mehr Code die Funktion eines Absatzes auf einen Blick ersichtlich wird, dann ist das mMn zu bevorzugen.
Das finde ich sogar ganz entscheidend, sobald es über spielereien hinaus geht und man nach 6 Monaten seinen code noch verstehen will oder den von anderen.

[src=csharp]
lblBronze.Text = "Bronze: " + Convert.ToString(Bronze++);
lblStufe.Text = "Stufe: " + (++Stufe);
[/src]
imHo ist man mit solchen Zeilen auf den Weg undefined behavior. Wenn sich eine Variable ändert sollte man das in eine eigene Zeile schreiben.
Jedenfalls in C++. Kann mir aber kaum vorstellen, dass es in C# gross anders ist, guter Stil ist es jedenfalls definitiv nicht.
 

Cyperfriend

Der ohne Avatar

Registriert
14 Juli 2013
Beiträge
1.123
  • Thread Starter Thread Starter
  • #4
@electric.larry: Danke. Die Antwort hat mir echt sehr geholfen und das Projekt ist gewachsen. Ich freue mich, dass du es auch so siehst, dass am Anfang eines Projekt erstmal die Funktion an sich stehen sollte und nicht gleich ein kompakter Code.

Mein Prototyp funktioniert von der Sache her, aber das mit dem Timer will noch nicht so recht. Momentan habe ich mich glaub auch total verant und ich dreh hier auch fast durch, weil ich glaube ganz nahe an der Lösung zu sein. Außerdem verlangt das Programm bei Stufe 3 die 90000 Gold, zieht dann aber doch nur 30000 ab. Irgendwo ist da auch was falsch gelaufen :(
[src=csharp]
// Startwerte setzen und Variablen deklarieren
// Ressourcen allgemein
int Gold = 100000;
int Silber = 100000;
int Bronze = 100000;

// Muss später aus einer Datei gelesen werden
// Aktuelle Informationen zum Haupthaus
int Stufe = 1;
int HH_Zeit = 5000;
int HH_Gold = 30000;
int HH_Silber = 20000;
int HH_Bronze = 10000;

private void Form1_Load(object sender, EventArgs e)
{
// Timer für die Ressourcenproduktion aktivieren
timerRessourcem.Enabled = true;
// Intervall für die Ressourcenproduktion aktivieren (1 Sekunde)
timerRessourcem.Interval = 1000;
// Intervall für die Bauzeit aktivieren (1 Sekunde)
timerHaupthaus.Interval = 1000;

// Muss später aus einer Datei gelesen werden
// Zeigt beim Programmstart die aktuellen Baukosten an.
lblHaupthausGold.Text = "Gold: " + Convert.ToString(HH_Gold);
lblSilber.Text = "Silber: " + Convert.ToString(HH_Silber);
lblBronze.Text = "Bronze: " + Convert.ToString(HH_Bronze);
lblHHZeit.Text = "Zeit: " + Convert.ToString(HH_Zeit);
}

private void tickRessourcen(object sender, EventArgs e)
{
// Ressourcen hinzufügen
lblGold.Text = "Gold: " + Convert.ToString(Gold += 300);
lblSilber.Text = "Silber: " + Convert.ToString(Silber += 200);
lblBronze.Text = "Bronze: " + Convert.ToString(Bronze += 100);
}

private void cmdBauen_Click(object sender, EventArgs e)
{
// Hier muss eine vernünftige Formel rein
// Prüfen, ob genug Ressourcen vorhanden sind
if (Gold < HH_Gold * Stufe || Silber < HH_Silber * Stufe || Bronze < HH_Bronze * Stufe)
{
MessageBox.Show("Zu wenig Ressourcen");
}
else
{
// Timer für das Bauprojekt aktivieren
timerBauen.Enabled = true;
// Intervall für das Bauprojekt aktivieren
HH_Zeit = 5000 * Stufe;
// Button deaktivieren
cmdBauen.Enabled = false;
// Ressourcen für das Bauprojekt abziehen
Gold = Gold - 30000;
Silber = Silber - 20000;
Bronze = Bronze - 10000;

// Bauzeit starten
timerHaupthaus.Enabled = true;
}
}

private void tickBauen(object sender, EventArgs e)
{
// Baustufe um +1 erhöhen
lblStufe.Text = "Stufe: " + (++Stufe);
// Timer für das Bauprojekt deaktivieren
timerBauen.Enabled = false;
// Button aktivieren
cmdBauen.Enabled = true;
// Hier muss eine vernünftige Formel rein
// Berechne die neuen Kosten und Zeit für den Weiterbau
lblHaupthausGold.Text = "Gold: " + Convert.ToString(HH_Gold * Stufe);
lblHaupothausSilber.Text = "Silber: " + Convert.ToString(HH_Silber * Stufe);
lblHaupthausBronze.Text = "Bronze: " + Convert.ToString(HH_Bronze * Stufe);
lblHHZeit.Text = "Zeit: " + Convert.ToString(5000 * Stufe);
}

// Eigentlich soll hier der Timer runtergezählt werden
private void tick_Haupthaus(object sender, EventArgs e)
{
for (HH_Zeit = HH_Zeit * Stufe; HH_Zeit > 0; HH_Zeit--)
{
lblHHZeit.Text = "Zeit: " + Convert.ToString(HH_Zeit--);
}
timerHaupthaus.Enabled = false;
}
[/src]

Anbei noch ein Bild von der GUI, die jetzt leicht anders aussieht.
Anhang anzeigen 31329


Nachtrag:

OK, dass beim Bauen zu wenig Ressourcen abgezogen werden habe ich herausgefunden. Habe den code jetzt geändert, aber das endet auch in einer Katastrophe:
[src=csharp]
// Ressourcen für das Bauprojekt abziehen
Gold = HH_Gold * Stufe;
Silber = HH_Silber * Stufe;
Bronze = HH_Bronze * Stufe;
[/src]
 
Zuletzt bearbeitet:

electric.larry

\''; DROP TABLE user; --
Teammitglied

Registriert
13 Dez. 2014
Beiträge
4.549
Ort
Raum 43
Ich freue mich, dass du es auch so siehst, dass am Anfang eines Projekt erstmal die Funktion an sich stehen sollte und nicht gleich ein kompakter Code.

Seh ich auch so, aber ich bin mir nicht sicher, ob ich mich wirklich verständlich ausgedrückt habe. Schreib lieber gleich von Anfang an zwei Zeilen mehr und behalte die Übersicht, anstatt alles zu verkürzen und dann den Überblick zu verlieren.

Versteh ich das richtig, dass du in der Funktion cmdBauen_Click je nach Speilfortschritt (=Stufe) höhere Kosten für den Bau abziehen möchtest?

Bei der Anzeige des Preises multiplizierst du den Preis mit der Stufe:

[src=csharp]
// Berechne die neuen Kosten und Zeit für den Weiterbau
lblHaupthausGold.Text = "Gold: " + Convert.ToString(HH_Gold * Stufe);
[/src]

Beim Abziehen der Kosten jedoch nicht. Denke das sollte daher lauten

[src=csharp]// Ressourcen für das Bauprojekt abziehen
Gold = Gold - (30000 * Stufe);
Silber = Silber - (20000 * Stufe);
Bronze = Bronze - (10000 * Stufe);[/src]


Bei deinem Timer, der tick_Haupthaus aufruft, hast du einen Denkfehler. Du möchtest ja, dass hier in Sekunden-Schritten runter gezählt wird. Dafür muss der Timer einmal pro Sekunden aufgerufen und dabei HH_Zeit bei jedem Aufruf genau einmal dekrementiert werden. Erst wenn die Zeit abgelaufen ist, sollte der Timer wieder beendet werden.
Du hingegen rufst den Timer nur einmal auf, lasst dann deine for-Schleife laufen, die innerhalb eines Sekundenbruchteils von (HH_Zeit * Stufe) auf 0 runter zählt, und beendest den Timer dann gleich nach der ersten Ausführung der Funktion.

Ausserdem hast du HH_Zeit-- einmal in der for Schleife und dann anschliessend nocheinmal beim Anzeigen "Convert.ToString(HH_Zeit--)". Dadurch wird bei jedem Durchlauf der Schleife HH_Zeit um 2 verkleinert, nicht nur um 1. Erinnere dich, "HH_Zeit--" ist das Selbe wie "HH_Zeit = HH_Zeit - 1", es genügt also das einmal auf zu rufen, nicht zweimal innerhalb eines Schleifendurchlaufs.

Ein Timer, der so funktioniert, koennte in etwa so aussehen:

[src=csharp] //wenn der bau beginnt und der timer starten soll rufst du einmal auf:
timerHaupthaus.Interval = 1000;
timerHaupthaus.Enabled = true;
HH_Zeit_bis_Fertigstellung = HH_Zeit * Stufe; //auch eine globale member variable

//dann wird pro Tick (einmal pro Sekunde) die Funktion aufgerufen
private void tick_Haupthaus(object sender, EventArgs e)
{
HH_Zeit_bis_Fertigstellung -= 1;
lblHHZeit.Text = "Zeit: " + Convert.ToString(HH_Zeit_bis_Fertigstellung);

//erst wenn der timer lange genug gelaufen ist und HH_Zeit_bis_Fertigstellung kleiner oder gleich 0 ist,
//beenden wir die ausfuehrung des timers und tick_Haupthaus wird dann nicht mehr aufgerufen.
if(HH_Zeit_bis_Fertigstellung <= 0)
{
timerHaupthaus.Enabled = false;
return
}

HH_Zeit_bis_Fertigstellung -= 1;
}[/src]
 

Cyperfriend

Der ohne Avatar

Registriert
14 Juli 2013
Beiträge
1.123
  • Thread Starter Thread Starter
  • #6
Erstmal ein rießen Dankeschön.

Habe das Programm umgeschrieben und jetzt funktioniert alles wie es soll.

Mal abgesehen davon, dass der Code sicher nicht optimiert ist: Gibt es funktional irgendwas, dass ich übersehe? Gibt es was zu bemängeln, was einfach unsauber ist? Anbei auch die gepackte exe-Datei

[src=csharp]
// Startwerte setzen und Variablen deklarieren
// Ressourcen allgemein
int Gold = 100000;
int Silber = 100000;
int Bronze = 100000;

// Muss später aus einer Datei gelesen werden
// Aktuelle Informationen zum Haupthaus
int Stufe = 1;
int HH_Zeit = 5;
int HH_Gold = 30000;
int HH_Silber = 20000;
int HH_Bronze = 10000;
int Bau_Fertig;

private void Form1_Load(object sender, EventArgs e)
{
// Timer für die Ressourcenproduktion aktivieren
timerRessourcem.Enabled = true;
// Intervall für die Ressourcenproduktion aktivieren (1 Sekunde)
timerRessourcem.Interval = 1000;
// Intervall für die Bauzeit aktivieren (1 Sekunde)
timerHaupthaus.Interval = 1000;

// Muss später aus einer Datei gelesen werden
// Zeigt beim Programmstart die aktuellen Baukosten an.
lblHaupthausGold.Text = "Gold: " + Convert.ToString(HH_Gold);
lblSilber.Text = "Silber: " + Convert.ToString(HH_Silber);
lblBronze.Text = "Bronze: " + Convert.ToString(HH_Bronze);
lblHHZeit.Text = "Zeit: " + Convert.ToString(HH_Zeit);
}

private void tickRessourcen(object sender, EventArgs e)
{
// Ressourcen hinzufügen
// Hier muss eine vernünftige formel rein
lblGold.Text = "Gold: " + Convert.ToString(Gold += 300 * Stufe);
lblSilber.Text = "Silber: " + Convert.ToString(Silber += 200 * Stufe);
lblBronze.Text = "Bronze: " + Convert.ToString(Bronze += 100 * Stufe);
}

private void cmdBauen_Click(object sender, EventArgs e)
{
// Hier muss eine vernünftige Formel rein
// Prüfen, ob genug Ressourcen vorhanden sind
if (Gold < HH_Gold * Stufe || Silber < HH_Silber * Stufe || Bronze < HH_Bronze * Stufe)
{
MessageBox.Show("Zu wenig Ressourcen");
}
else
{
// Timer für das Bauprojekt aktivieren
timerBauen.Enabled = true;
// Intervall für das Bauprojekt aktivieren
timerBauen.Interval = 1000;
// Button deaktivieren
cmdBauen.Enabled = false;
// Ressourcen für das Bauprojekt abziehen
Gold = Gold - (30000 * Stufe);
Silber = Silber - (20000 * Stufe);
Bronze = Bronze - (10000 * Stufe);

// Bauzeit starten
timerHaupthaus.Enabled = true;
// Bauzeit berechnen
Bau_Fertig = HH_Zeit * Stufe;
}
}

private void tickBauen(object sender, EventArgs e)
{
// Braucht man gar nicht (oder?)
}

// Eigentlich soll hier der Timer runtergezählt werden
private void tick_Haupthaus(object sender, EventArgs e)
{
// Berechnete Bauzeit, davon immer eine Sekunde abziehen bis 0
Bau_Fertig -= 1;
// Den Countdown anzeigen
lblHHZeit.Text = "Zeit: " + Convert.ToString(Bau_Fertig);

if (Bau_Fertig <= 0)
{
// Baustufe um +1 erhöhen
lblStufe.Text = "Stufe: " + (++Stufe);
// Timer für das Bauprojekt deaktivieren
timerBauen.Enabled = false;
// Button aktivieren
cmdBauen.Enabled = true;
// Hier muss eine vernünftige Formel rein
// Berechne die neuen Kosten und Zeit für den Weiterbau
lblHaupthausGold.Text = "Gold: " + Convert.ToString(HH_Gold * Stufe);
lblHaupothausSilber.Text = "Silber: " + Convert.ToString(HH_Silber * Stufe);
lblHaupthausBronze.Text = "Bronze: " + Convert.ToString(HH_Bronze * Stufe);
lblHHZeit.Text = "Zeit: " + Convert.ToString(HH_Zeit * Stufe);
timerHaupthaus.Enabled = false;
return;
}
// Das hier macht keinen Sinn, da sonnst zwei Sekunden abgezogen werden
// Bau_Fertig -= 1;
}
[/src]

Anhang anzeigen 31503
 

electric.larry

\''; DROP TABLE user; --
Teammitglied

Registriert
13 Dez. 2014
Beiträge
4.549
Ort
Raum 43
Schaut schon ganz gut aus :)

Hab eh schon erwähnt, dass ich solche Dinge vermeiden würd:

[src=csharp]lblGold.Text = "Gold: " + Convert.ToString(Gold += 300 * Stufe);[/src]

Solche Abkürzungen sind zwar verlockend, aber ich garantier dir, du wirst dich damit noch ärgern ;) Trenne zumindest Ausgabe und Wertzuweisung und mach Klammern, auch wenn sie nicht zwingend notwendig sind. In etwa so:

[src=csharp]
Gold += (300 * Stufe);
lblGold.Text = "Gold: " + Convert.ToString(Gold);
[/src]

Wenn du mit einem Debugger durch deinen Code wanderst, kannst du auch besser verfolgen was passiert, wenn du komplexere Formeln in mehrere einzelne Zeilen zerlegst.

Für einen nächsten Schritt könntest du dir überlegen wie man das ganze mit nur einem einzigen globalen Timer lösen könnte, der die Spielzeit für alle Objekte im Spiel vorgibt. Oder anders herum ausgedrückt, wie du dynamisch mehrere Häuser ins Spiel bringen könntest ohne für jedes einen eigenen Timer zu verwenden.
 

Cyperfriend

Der ohne Avatar

Registriert
14 Juli 2013
Beiträge
1.123
  • Thread Starter Thread Starter
  • #8
Ja, das steht als nächstes auf meinem Plan - zumindest unter anderem.
 

Cyperfriend

Der ohne Avatar

Registriert
14 Juli 2013
Beiträge
1.123
  • Thread Starter Thread Starter
  • #9
Ich mache jetzt mal hier weiter. Muss ja nicht jedes mal ein neuer Thread sein.

Habe das Programm nochmal neu gemacht und erweitert. Was ich aber nicht hinbekomme:

1) Nur ein Timer verwenden. (Ist das überhaupt möglich, OHNE dass die Übersicht leidet? Immer mit if/else-Schleifen dürfte bei später mehreren Gebäuden sehr unschön sein)
2) Wenn ich durch den Ausbau des Haupthaus Zeit für den Bau anderer Gebäude spare, dann gilt das zwar beim nächsten Bau des Gebäudes. Danach wird aber die Zeit so berechnet, als hätte ich am Haupthaus gar nichts gemacht. Warum?
3) Bei Gebäuden die bereits eine Bauzeit von 0 Sekunden erreicht haben erscheint ein Minuswert. Wie kann ich es erreichen, dass das nicht passiert, OHNE, dass ich bei jedem Gebäude eine if/else-Schleife baue (Werden ja später mehr Gebäude)
4) Welche Codezeilen sollte ich zusammenfassen können? Ich meine nicht, welche fasst man normal zusammen, sondern welche sind EINFACH zusammen zu fassen. Bedenkt, dass ich echt Probleme mit dem so genannten logischen Denken habe und Anfänger bin. Gebt mir eine Chance.
5) Wo habe ich noch was übersehen, wo lauern noch von mir unentdeckte Bugs?

Ich erfrage (noch) keinen Code. Erstmal will ich hilfreiche Tipps. Wie gesagt: Werft nicht mit Fachausdrücken um euch und gebt mir eine Chance. Electric.larry hat das bislang echt gut gemacht und ich habe nicht gleich wieder den Spaß verloren, weil eh alles scheiße programmiert ist. Das Profis das komplett anders machen ist mir klar. Hier geht es aber mmer noch nicht um ein performantes Programm, sondern rein um Verständnis.
Anhang anzeigen 32342
Anhang anzeigen 32344

[src=csharp]
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;

namespace _4X_Prototyp
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}

// Ressourcen
int resGold;
int resSilber;
int resMineralien;
int resWasser;

// Gebäude
// Haupthaus
int gHaupthausStufe;
int gHaupthausGold;
int gHaupthausSilber;
int gHaupthausZeit;
int gHaupthausBauzeit;

// Goldmine
int gGoldmineStufe;
int gGoldmineGold;
int gGoldmineSilber;
int gGoldmineZeit;
int gGoldmineBauzeit;

// Silbermine
int gSilbermineStufe;
int gSilbermineGold;
int gSilbermineSilber;
int gSilbermineZeit;
int gSilbermineBauzeit;

// Mineralwerk
int gMineralwerkStufe;
int gMineralwerkGold;
int gMineralwerkSilber;
int gMineralwerkZeit;
int gMineralwerkBauzeit;

// Wasserwerk
int gWasserwerkStufe;
int gWasserwerkGold;
int gWasserwerkSilber;
int gWasserwerkZeit;
int gWasserwerkBauzeit;

private void Form1_Load(object sender, EventArgs e)
{
// Spielstand laden
// Ressourcen
resGold = 5000;
resSilber = 5000;
resMineralien = 5000;
resWasser = 5000;

lblGold.Text = "Gold: " + string.Format("{0:#,##0}", resGold);
lblSilber.Text = "Silber: " + string.Format("{0:#,##0}", resSilber);
lblMinerale.Text = "Minerale: " + string.Format("{0:#,##0}", resMineralien);
lblWasser.Text = "Wasser: " + string.Format("{0:#,##0}", resWasser);

// Gebäude
// Haupthaus
gHaupthausStufe = 1;
gHaupthausGold = 500;
gHaupthausSilber = 250;
gHaupthausZeit = 5;

lblHaupthausStufe.Text = "Haupthaus: " + gHaupthausStufe;
lblHaupthausKosten.Text = "Kosten: Gold: " + gHaupthausGold + " - Silber: " + gHaupthausSilber;
lblHaupthausZeit.Text = "Zeit: " + gHaupthausZeit + " Sekunden";

// Goldmine
gGoldmineStufe = 1;
gGoldmineGold = 200;
gGoldmineSilber = 100;
gGoldmineZeit = 10;

lblGoldmineStufe.Text = "Goldmine: " + gGoldmineStufe;
lblGoldmineKosten.Text = "Kosten: Gold: " + gGoldmineGold + " - Silber: " + gGoldmineSilber;
lblGoldmineZeit.Text = "Zeit: " + gGoldmineZeit + " Sekunden";

// Silbermine
gSilbermineStufe = 1;
gSilbermineGold = 100;
gSilbermineSilber = 200;
gSilbermineZeit = 10;

lblSilbermineStufe.Text = "Silbermine: " + gSilbermineStufe;
lblSilbermineKosten.Text = "Kosten: Gold: " + gSilbermineGold + " - Silber: " + gSilbermineSilber;
lblSilbermineZeit.Text = "Zeit: " + gSilbermineZeit + " Sekunden";

// Mineralwerk
gMineralwerkStufe = 1;

// Wasserwerk
gWasserwerkStufe = 1;
}

private void tickRes(object sender, EventArgs e)
{
// Ressourcen hinzufügen
resGold += (200 * gGoldmineStufe);
resSilber += (150 * gSilbermineStufe);
resMineralien += (100 * gMineralwerkStufe);
resWasser += (50 * gWasserwerkStufe);

lblGold.Text = "Gold: " + string.Format("{0:#,##0}", resGold);
lblSilber.Text = "Silber: " + string.Format("{0:#,##0}", resSilber);
lblMinerale.Text = "Mineral: " + string.Format("{0:#,##0}", resMineralien);
lblWasser.Text = "Wasser: " + string.Format("{0:#,##0}", resWasser);
}

private void cmdHaupthausBauen_Click(object sender, EventArgs e)
{
// Prüfen, ob genug Ressourcen vorhanden sind
if (resGold < (gHaupthausGold) || resSilber < (gHaupthausSilber))
{
MessageBox.Show("Zn wenig Ressourcen");
}
else
{
// Baukosten abziehen
resGold = (resGold - gHaupthausGold);
resSilber = (resSilber - gHaupthausSilber);

// Bauzeit berechnen
gHaupthausBauzeit = gHaupthausZeit;

// Bautimer aktivieren
timerHaupthausBauen.Enabled = true;
}
}

private void tickHaupthausBauen(object sender, EventArgs e)
{
// Verbleibende Bauzeit anzeigen
gHaupthausBauzeit -= 1;

// Verbleibende Bauzeit anzeigen
lblHaupthausZeit.Text = "Restzeit: " + gHaupthausBauzeit + " Sekunden";

if (gHaupthausBauzeit <= 0)
{
// Haupthaus um eine Stufe höher bauen
gHaupthausStufe = ++gHaupthausStufe;
lblHaupthausStufe.Text = "Haupthaus: " + gHaupthausStufe;

// Neue Kosten für Weiterbau berechnen
gHaupthausGold = (500 * gHaupthausStufe);
gHaupthausSilber = (250 * gHaupthausStufe);
lblHaupthausKosten.Text = "Kosten: Gold: " + gHaupthausGold + " - Silber: " + gHaupthausSilber;

// Neue Bauzeit berechnen
gHaupthausZeit = (5 * gHaupthausStufe);
lblHaupthausZeit.Text = "Zeit: " + gHaupthausZeit + " Sekunden";

// Bauzeit der anderen Minen reduzieren
gGoldmineZeit = (gGoldmineZeit - 2);
gSilbermineZeit = (gSilbermineZeit - 2);
gMineralwerkZeit = (gMineralwerkZeit - 2);
gWasserwerkZeit = (gWasserwerkZeit - 2);

lblGoldmineZeit.Text = "Zeit: " + gGoldmineZeit + " Sekunden";
lblSilbermineZeit.Text = "Zeit: " + gSilbermineZeit + " Sekunden";
lblMineralwerkZeit.Text = "Zeit: " + gMineralwerkZeit + " Sekunden";
lblWasserwerkZeit.Text = "Zeit: " + gWasserwerkZeit + " Sekunden";

// Bautimer deaktivieren
timerHaupthausBauen.Enabled = false;
}
}

private void cmdGoldmineBauen_Click(object sender, EventArgs e)
{
// Prüfen, ob genug Ressourcen vorhanden sind
if (resGold < (gGoldmineGold) || resSilber < (gGoldmineSilber))
{
MessageBox.Show("Zn wenig Ressourcen");
}
else
{
// Baukosten abziehen
resGold = (resGold - gGoldmineGold);
resSilber = (resSilber - gGoldmineSilber);

// Bauzeit berechnen
gGoldmineBauzeit = gGoldmineZeit;

// Bautimer aktivieren
timerGoldmineBauen.Enabled = true;
}
}

private void tickGoldmineBauen(object sender, EventArgs e)
{
// Verbleibende Bauzeit anzeigen
gGoldmineBauzeit -= 1;

// Verbleibende Bauzeit anzeigen
lblGoldmineZeit.Text = "Restzeit: " + gGoldmineBauzeit + " Sekunden";

if (gGoldmineBauzeit <= 0)
{
// Goldmine um eine Stufe höher bauen
gGoldmineStufe = ++gGoldmineStufe;
lblGoldmineStufe.Text = "Goldmine: " + gGoldmineStufe;

// Neue Kosten für Weiterbau berechnen
gGoldmineGold = (500 * gGoldmineStufe);
gGoldmineSilber = (250 * gGoldmineStufe);
lblGoldmineKosten.Text = "Kosten: Gold: " + gGoldmineGold + " - Silber: " + gGoldmineSilber;

// Neue Bauzeit berechnen
gGoldmineZeit = (10 * gGoldmineStufe);
lblGoldmineZeit.Text = "Zeit: " + gGoldmineZeit + " Sekunden";

// Ressourcenproduktion für die Goldmine erhöhen
resGold += (200 * gGoldmineStufe);
lblGold.Text = "Gold: " + string.Format("{0:#,##0}", resGold);

// Bautimer deaktivieren
timerGoldmineBauen.Enabled = false;
}
}
}
}
[/src]
 

KaPiTN

♪♪♫ wild at heart ♪♫♫♪

Registriert
14 Juli 2013
Beiträge
29.138
Für Punkt 1) und 3) gilt, daß Du mehr Funktionen schreiben könntest.

Bei 1) schreibst Du den Code aus Deinen Eventhandlern (Deine tick-Funktionen) in jeweils eine neue Funktion. Dann hättest Du weitere 3 Funktionen, die Du aus einer einzigen tick-Funktion aufrufen könntest.

Bei 3) gilt das gleiche. Du Schreibst Dir eine Funktion, die überprüft, ob beim Abziehen die 0 nach unten überschritten wird. Das ist ja für jede g-Zeit das gleiche. Du rufst die Funktion jeweils mit einer g-Zeit auf und bekommst die neue zurück. Bis max. 0 reduziert.
 
Zuletzt bearbeitet:

Timon3

Team ModMii

Registriert
17 Juli 2013
Beiträge
499
1) Die einfachste Möglichkeit ist, den Code für jedes Gebäude in einzelne Funktionen auszulagern und diese dann von der Timer-Tick-Funktion aus aufzurufen. Dann kannst du einen einzelnen Timer haben, der alles übersichtlich antickt.
(Übrigens, es heißt if/else-Verzweigung, nicht Schleife. 90 Prozent aller Programmierer würden dich für den Ausdruck umbringen :D)

2) Du berechnest die Zeit für die einzelnen Gebäude basierend auf der Stufe der einzelnen Gebäude, dabei wird aber das Haupthaus gar nicht in Betracht gezogen. Schau die beispielsweise mal die Goldmine an:

  • // Neue Bauzeit berechnen
  • gGoldmineZeit = (10 * gGoldmineStufe);
  • lblGoldmineZeit.Text = "Zeit: " + gGoldmineZeit + " Sekunden";

Wenn du die Zeit neu ausrechnest, musst du noch das Haupthaus mit reinnehmen, z. B. indem du bei der Mine (zeit - 2 * haupthausStufe) rechnest.

3) Um es einfach zu machen: Kannst du nicht. Du könntest eine unsigned int (eine Integer-Variable, die keinen negativen Wert annehmen kann und dadurch doppelt so groß in den positiven Bereich werden kann) nehmen, aber das kann dir wieder andere Probleme bringen - also einfach per if/else überprüfen.

Zu 4) und 5) hab ich jetzt nicht sonderlich viel geschaut.

Du solltest dir am Besten jetzt überlegen, wie du weitermachen willst - gerade jetzt ist ein Zeitpunkt, bei dem du das Programm einfach auf objektorientierte Programmierung umstellen kannst und das dabei selbst schön veranschaulicht bekommst. Wenn du daran Interesse hast, kannst du ja nochmal schreiben.
 

electric.larry

\''; DROP TABLE user; --
Teammitglied

Registriert
13 Dez. 2014
Beiträge
4.549
Ort
Raum 43
Auch wenn das Ding jetzt noch ein paar Schöneitsfehler hat, glaube ich, hast du alles gemacht, was man mit dieser Code Basis machen kann. Hier wirst du nicht mehr viel lernen können, was du nicht jetzt schon einigermassen verstanden hast.

Ich würd dir empfehlen, wie @GameChamp98 schon sagt, das Spiel an dieser Stelle einzustampfen und mit einem wirklich objektorientieren Ansatz nocheinmal von Vorne zu beginnen. Also, gleiche Grundidee und Game Logic, aber ein völlig neuer Aufbau deines Codes. Schau dir dafür einmal an, wie man Klassen erstellt und benutzt, wie Listen funktionieren und wie Vererbung und Polymorphie funktionieren.

Klingt jetzt am Anfang vielleicht ein wenig kompliziert, aber ich verspreche dir, nachdem du Vererbung und Polymorphismus begreifst, wirst du ein komplett neues Verständnis vom Programmieren in einer objektorientierten Sprache haben. Diese Konzepte sind auch kein C#-Spezialwissen, sondern begegnen dir in den meisten verbreiteten Hochsprachen.

Schau dir einmal dieses Beispiel im MSDN an, ich denke dann verstehst du was ich meine.

Der Grundaufbau, so würde ich es zumindest angehen, wäre so:

In deiner Form1 hast du weitherin alle GUI Elemente sowie einen Timer. Ausserdem hast du eine Liste in der alle Spielelemente (Häuser, Minen, Werke) gespeichert sind. In deinem Timer Event durchläufst du jedes mal die gesamte Liste der Spielelemente und rufst die Methode (= Funktion) onGameTimerTick() von jedem der Elemente auf. Diese Funktion gehört zu jedem der Häuser/Minen und macht im Prinzip das, was z. B. deine tickHaupthausBauen Funktion tut. Nur ist diese Funktion dann nicht mehr in der Form1, sondern schön dort wo sie hin gehört, in der Klasse des jeweiligen Hauses.

Für deine Gebäude und Minen machst du dir eine eigene Klasse. Eine Grundklasse "Spielelement" und davon leitest du jeweils eine Klasse die das jeweilige Gebäude näher definiert, ab. Jede dieser Klassen implementiert die Funktion onGameTimerTick().
Wenn dein Programm dann läuft, musst du nicht mehr für jedes Spielobjekt eine eigene Timer Funktion schreiben, sondern sobald du ein neues Spielelement erstellst, hängst du es in deine Liste von Spielelementen. Bei jedem Timer Tick, wird die Liste durchlaufen und der Tick Event des jeweiligen Objekts aufgerufen.

Das Beispiel im MSDN ist wahrscheinlich ein guter Ausgangspunkt für dein Game. Was dort die draw() Funktion ist, ist deine onTimerTick() Event. Die Klasse Shape ist dein Spielelement und Circle bzw. Rectangle sind deine unterschiedlichen Gebäude.
 

KaPiTN

♪♪♫ wild at heart ♪♫♫♪

Registriert
14 Juli 2013
Beiträge
29.138
Objektorientierte Programmierung ist überbewertet an dieser Stelle absolut nicht zielführend und völliger Overkill.
Daß man Methoden/Funktionen benutzen kann, um Funktionalität mehrfach zu verwenden, darauf kommen Programmierer auch ohne OOP.
Der TS möchte Hilfe bei der Lösung seiner Probleme.
Da braucht er keine Hinweise auf die Theorie. Vor allem nicht , wenn diese in der Praxis oft eh nur ansatzweise umgesetzt wird. Verwendet man Klassen, so programmiert man vermeintlich schon OOP. Dabei ist das nur meist nur eine Struktur für Klassen.

Funktionalität in Funktionen zusammenfassen ist völlig zielorientiert. Eine Windows-Form-Anwnendung benötigt keine weiteren Klassen

Lieber TS. Der Beitrag ist Meta OT Überließ ihn einfach bitte. sry
 
Zuletzt bearbeitet:

electric.larry

\''; DROP TABLE user; --
Teammitglied

Registriert
13 Dez. 2014
Beiträge
4.549
Ort
Raum 43
@KaPiTN: Du sagst also, jemandem der eine objektorientierte Sprache wie C# lernen will, Objektorientierte Programmierung ans Herz zu legen, sei Overkill?

Du hast völlig recht, bei einer Anwendung mit 50 Zeilen Code ist das ein unnötiger Aufwand. Ich finde aber, sein Beispiel mit den Häusern ist perfekt dafür geeignet, dieses komplexe Thema auf spielerische Art zu lernen.
 

BurnerR

Bot #0384479

Registriert
20 Juli 2013
Beiträge
5.507
Die Frage lässt sich nicht abschließend beantworten. Der TE möchte gern ergebnisorientiert arbeiten, was insbesondere in Hinblick auf Motivation klug und verständlich ist, andererseits ist programmieren bei etwas umfangreicheren Projekten eine Qual wenn man sich auf "Spaghetticode" beschränkt oder sich dann erst die entsprechenden Möglichkeiten aneignet.

Gibts nicht ein ergebnisorientiertes C# Buch, wo man über mehrere Kapitel ein Spiel programmiert?
 

Larius

OutOfOrder

Registriert
12 Juli 2013
Beiträge
5.792
Geben tut es bestimmt irgendwelche Werke, mir fallen nur adhoc keinerlei vernünftige ein.

Aber um die Metadiskussion mal kurz aufzugreifen: So unrecht hat Electric.Larry und GameChamp98 nicht. Man könnte durchaus jetzt beginnen, den bereits bestehenden Code in objektorientierte Logik auszulagern. Es macht auch durchaus Sinn, da man so neue Spieleelemente gut implementieren kann. Stichwörter wie Building Queue & Building Requirements fallen mir da spontan ein, sprich man hat eine Liste wo man dann verschiedene Gebäude "in Bau" geben kann. Die werden dann nacheinander einfach abgearbeitet, sprich für das erste Gebäude rennt dann der Timer bis er auf 0 ist, dann wird es aus der Liste entfernt und das nächste Gebäude wird gebaut. Oder man hat eine Liste, wo alle bereits gebauten Gebäude drinnen stehen, und überprüft dann einfach "Oh, hab ich eigentlich schon eine Schmiede das ich daraus meine Waffenschmiede bauen kann"?

Ich würde schon sagen das man mit Objektorientiertheit dann noch mehr Features dazubasteln kann und man sich dann später auch leichter tut.
 
Oben