Was genau bedeutet <identifier> expected?

3 Antworten

Vom Fragesteller als hilfreich ausgezeichnet

Diese Zeile:

spiel.monsterList.setpos(i).(x, y);

birgt mehrere Fehler in sich.

Zum einen versuchst du von einer LinkedList-Instanz eine Methode setpos aufzurufen, die diese Klasse gar nicht besitzt. Zum anderen (und das ist dein aktueller Fehler) rufst du eine Argumentliste auf: (x, y), aber ohne vorhergehendem Methodennamen. Der Compiler weiß daher nicht, an welchen Code-Block er x und y geben sollte.

Hätte deine Klasse monster nun noch eine Methode setpos, hätte ich vermutet, dass dein Code eigentlich ungefähr so aussehen sollte:

spiel.monsterList.get(i).setpos(x, y);

Allerdings würdest du so ja die Position von jedem Monster verändert werden, was wohl auch nicht deine Intention gewesen sein kann. Die Schleife wäre also unsinnig.

Wie dem auch sei, ich möchte folgend auf einige Dinge eingehen, die du ändern solltest.

1) Halte dich an Konventionen. Klassennamen beginnen mit einem Großbuchstaben. So kann man sie leicht von Methoden- und Variablennamen unterscheiden und weiß beim Aufruf von Methoden/Attributen auf den ersten Blick, ob sie statisch sind oder nicht.

// bad practice:
lebewesen lebewesen = new lebewesen();
lebewesen.setzeAnzahlBeine(4); // is setzeAnzahlBeine static or not?

// good practice:
Lebewesen lebewesen = new Lebewesen();
lebewesen.setzeAnzahlBeine(4);

Methodennamen hingegen sollten eine Tätigkeit beschreiben. Eine Methode pos tut das ganz gewiss nicht. Im Namen schneidet sie sich stattdessen sogar noch mit einem Array. Ein Name wie gibPosition wäre aussagekräftiger. Beachte, dass in Java die kamelHoeckerSchreibweise angewandt wird.

2) Mische nicht verschiedene Sprachen in den Bezeichnern (mal Englisch, mal Deutsch). Das macht deinen Quellcode nur schwerer lesbar. Vermeide zudem möglichst Abkürzungen und nichtssagende Namen wie a. Es ist nicht im geringsten ersichtlich, wozu diese Variable dienen soll. Wenn man in der erbenden Klasse (via Autosuggestion in einer IDE) durch die Attribute läuft, fragt man sich schon: Wozu ist die da?

3) Würde es nicht ausreichen, sich nur den zentralen Punkt eines Monsters zu merken, mitsamt seines Radius? Für spätere Überprüfungen (wie Kollisionsabfragen) ist das doch vollkommen ausreichend.

4) Ich halte dein Konzept nicht gut, bei dem du versuchst, dir statische Bindungen aufzubauen und nicht einmal Kapselung einsetzt.

Die einfachste Vorgehensweise wäre, wenn sich die Spielkomponenten selbst zeichnen könnten. Dazu wird jede Komponente, die gezeichnet werden kann, mit einer entsprechenden Methode ausgestattet.

Im folgenden Beispiel würde ich davon ausgehen, dass alle Positionen der Spielkomponenten auf ein Spielbrett (Array) gezeichnet werden. In der game loop werden alle bekannten Komponenten durchlaufen, jede darf sich selbst auf dem Feld eintragen. Das Feld wird danach (bspw. auf der Konsole) ausgegeben.

interface Drawable {
  void draw(Game board);
}
  
abstract class Creature implements Drawable {
  // ...
}
  
class Monster extends Creature {
  @Override
  public void draw(Game board) {
    board.setField(positionX, positionY, '#');
  }

  // ...
}

class Game {
  private char[][] field;

  private List<IDrawable> gameComponents;
    
  // ...

  public void setField(int x, int y, char symbol) {
    field[y][x] = symbol;
  }

  public void draw() {
    // clear board ...
    
    for (IDrawable component : gameComponents) {
      component.draw(this);
    }

    drawBoard();
  }

  // draw board ...
}

Wenn neue Komponenten angelegt werden sollen, dann löse dies entweder in der Game-Klasse oder reiche die Instanz der Game-Klasse weiter, damit sich neue Komponenten bei dieser registrieren können.

Generell geht dies dann in die Richtung des ECS, welches oft für die Spieleentwicklung eingesetzt wird.


cameraflash 
Fragesteller
 23.10.2019, 16:52

Uff danke, Problem gelöst! (Ich hätte es dazu schreiben sollen; meine Intention war tatsächlich nur, dass sich die Position jedes Monsters ändern soll ^^')

1+2) Danke, das werde ich noch ändern!

3) Das hört sich ziemlich gut an, aber kannst du mir vielleicht kurz erklären, wie ich diesen Radius einfacher programmiere?

4) Da weiß ich leider nicht, was du meinst. ^^'

Nochmals danke!

0
regex9  23.10.2019, 22:46
@cameraflash

Radius:

Du brauchst eigentlich nur drei Attribute: centerX, centerY, radius. Wenn du die Grenzen brauchst, kannst du sie dynamisch berechnen. Wenn du bspw. die aktuelle Position anhand der linken oberen Ecke erhalten möchtest:

Position getLeftCorner() {
  return new Position(centerX - radius, centerY - radius);
}   

oder die Breite des Rechtecks:

int getWidth() {
  return 2 * radius;
}

Du hast zwar jedesmal Berechnungen vorzunehmen (und an sich könntest du auch Daten wie Breite und Höhe ebenfalls in Attributen speichern), aber brauchst dafür nicht für jeden Punkt der Fläche extra Speicherplatz belegen.

ECS:

Liegt es daran, dass dir Begriffe wie Interfaces, Kapselung, Polymorphie oder statische Instanzen noch nicht bekannt sind? Das sind alles Themen der OOP. Solltest du dich damit noch nicht befasst haben, kannst du ruhig damit beginnen, sofern du dich in der Handhabung von Methoden, Arrays, Kontrollstrukturen und Operatoren bereits sicher fühlst.

Was ich in deinem Snippet im Grunde als negativ betrachte, ist die statische Liste, die du offenbar als globale Variable missbrauchen möchtest. Vorzugsweise solltest du aber strikt logisch zwischen objektgebundenen und objektungebundenen Elementen unterscheiden, Attributzugriffe kapseln (Kapselung) und Sichtbarkeiten viel eher beschränken. Am Ende gestaltest du dein Programm somit wartbarer, besser testbar und erlaubst dem GC zudem eine flexiblere Speicherverwaltung.

Weiter möchte ich dabei allerdings nicht darauf eingehen, denn die OOP-Konzepte werden schon in etlichen anderen Quellen (Büchern, Internetartikeln, etc.) erklärt.

1
cameraflash 
Fragesteller
 26.10.2019, 10:32
@regex9

Danke für deine ausführliche Antwort. Ich werde es mit dem Radius mal versuchen.

Von den meisten Begriffen habe ich tatsächlich noch nicht gehört...

0

Hier liegt der Fehler, wie du schon beschrieben hast: setpos(i).(x, y);

Mit setpos() weiß der Compiler was anzufangen und ruft die Methode auf.

Dann soll der durch dem . mit dem Ergebnis was machen. Hier fehlt der Funktionsname, der die Argumente x und y bekommt.

Richtig sähe das so aus: setpos(i).foo(x, y);

foo ist der fehlende Identifier. Wie er bei dir heißen muss, kann ich nicht wissen.


Wissididom  22.10.2019, 09:19

Ich glaube er wollte

spiel.monsterList.set(i, new monster(x, y));

aufrufen (ist ja eine LinkedList)

1
cameraflash 
Fragesteller
 22.10.2019, 18:21
@Wissididom

new monster() würde doch hier bedeuten, dass ich ein neues Objekt erstelle, oder? Im Prinzip benötige ich aber keine weiteren (Objekte der Klasse) Monster mehr, ich will lediglich die Position jedes (bereits erstellten) Monsters verändern. Wahrscheinlich hätte ich es oben formulieren sollen, aber trotzdem danke für deine Antwort.

0
cameraflash 
Fragesteller
 22.10.2019, 18:14

Ich bin mir nicht sicher, was genau foo hier bedeutet. Ist das eine Variable? ^^'

Den oberen Rest habe ich verstanden. Danke für die schnelle Antwort (auch wenn es noch nicht funktioniert)

1
gogogo  22.10.2019, 19:21
@cameraflash

foo ist ein Name, der gerne in Beschreibungen von Programmiersprachen verwendet wird, um einen Methodennamen zu haben.

Es soll irgendeine Methode damit angegeben werden, so wie setpos(). Nun brauchte ich einen Namen. Der Name ist ein Identifier.

Identifier sind:

  • Klassenname
  • Methodenname
  • Variablenname
1
 public monster(int x, int y)

Du hast vergessen, den Rückgabetyp bzw. "void" anzugeben.

Woher ich das weiß:Hobby – private Programmiererei