JirkaDellOro / EIA2

Modul "Entwicklung Interaktiver Anwendungen II": Material, Aufgaben und Tafelbilder
https://jirkadelloro.github.io/FreeMindViewer/?map=EIA2.mm&path=https://jirkadelloro.github.io/EIA2
5 stars 17 forks source link

Klickposition auf Canvas ermitteln #71

Closed fehren1a closed 6 years ago

fehren1a commented 7 years ago

Hallo zusammen, ich würde bei meiner Abschlussaufgabe gerne die Position auf dem Canvas ermitteln, wo geklickt wird. Habe dabei versucht mit "target" und "clientX" zu arbeiten, jedoch funktioniert das nicht. Ziel ist es, dass das schwarze Panel sich am unteren Spielfeldrand dahin bewegt, wo geklickt wird und somit der Ball dort abprallen kann.

Meine Aufgabe ist hier zu finden: https://github.com/fehren1a/EIA2/blob/master/abschluss_aufgabe/abschluss.html

Link zum Repository: https://github.com/fehren1a/EIA2/tree/master/abschluss_aufgabe

Danke im Voraus schonmal! :)

saenglert commented 7 years ago

Hallo Jonas, das Hauptproblem ist dass du event.target.clientX aufrufst, aber clientX garnicht Teil des targets ist sondern zum event gehört. Korrekt ist also event.clientX. Das wird dich aber auch nicht ganz glückglich machen, denn clientX/Y ist immer relativ zum Ursprung des Browserfenster. Du suchst ja allerdings Koordinaten relativ zum Ursprung des Canvas. Auch da gibts eine Lösung innerhalb des events. Ich weiß nicht, ob du dabei warst, aber im Tutorium haben wir darüber gesprochen.

fehren1a commented 7 years ago

Welchen Typecast benötige ich dann in diesem Fall? Denn für das HTMLCanvasElement gibt es für das event ja nicht die Option clientX, zumindest bei mir wird es nicht angezeigt.

saenglert commented 7 years ago

Ich komme gerade bei deinem Schritt vom Canvas zum Event nicht mit.

Das Canvas hat mit der Eventinformation erstmal nichts zu tun, darum kümmert sich allein das Eventobjekt, welches wiederum wenn es durch einen Klick ausgelöst wird vom Typ MouseEvent ist.

fehren1a commented 7 years ago

Vielen Dank Sascha für die Hilfestellung, das Programm läuft nun so wie ich es mir vorgestellt habe! ;-) Hatte als Parameter in der Funktion kein MouseEvent und habe jetzt mit _event.offsetX gearbeitet.

fehren1a commented 7 years ago

Hätte dennoch eine allgemeine Frage zur Abschlussaufgabe. Was ist mit der Vorgabe "Es ist eine während des Programmverlaufs variable Anzahl von Objekten zu erkennen" bei der Aufgabenstellung gemeint?

Ist dies dann in meinem Fall erfüllt? https://fehren1a.github.io/EIA2/abschluss_aufgabe/abschluss.html

saenglert commented 7 years ago

Wenn ich jetzt kleinlich wäre würde ich ich sagen nein, da du ja fest definiert hast, dass es einen Ball und einen Balken gibt. Du könntest z.B. darüber nachdenken, dass pro 5 Punkte etwa ein zusätzlicher Ball ins Spiel kommt.

Grundsätzlich müsste die Frage aber Herr Dell'Oro beantworten.

JirkaDellOro commented 7 years ago

Das wäre auch meine Antwort gewesen. Es geht darum dynamisch Objekte zu erzeugen, zu zerstören und mit Hilfe der entsprechenden Strukturen zu verwalten.

fehren1a commented 7 years ago

Dynamisch erzeugen würde dann bedeuten, dass ich ein Array habe und darin den Ball beispielsweise verwalte oder?

JirkaDellOro commented 7 years ago

Ja, aber das ergibt natürlich nur Sinn, wenn die Option auf mehrere Bälle existiert.

fehren1a commented 7 years ago

Habe nun versucht, diese Vorgabe zu erfüllen und habe in der main.ts den Ball in ein Array gespeichert. Dabei sind jedoch leider neue Probleme aufgetreten, die ich mir nicht erklären kann:

  1. Sobald der zweite Ball sichtbar ist, d.h. counter == 2, beschleunigen beide Bälle schlagartig, sodass die Geschwindigkeit viel zu hoch ist. Die Geschwindigeit sollte jedoch durch den neu erzeugten Ball nicht erhöht werden und der ursprüngliche Ball soll sich unabhängig davon wie davor weiterbewegen.

  2. Durch den neuen (zweiten) Ball wird über die Punktezahl geschrieben, d.h. beim neuen Ball beginnt die Punktezahl bei 0. Ziel ist es jedoch, dass es nur eine Punktezahl gibt und diese fortgeführt wird, auch wenn der zweite Ball das Panel trifft, bedeutet beispielsweise: Ball1 trifft Panel (--> counter += 1 | Points: 1), Ball2 trifft Panel (--> counter += 1| Points: 2) usw.

  3. Nachdem "Game Over" erscheint, passiert nichts mehr bzw. das Spiel wird nicht mehr zurückgesetzt. Bedeutet, dass kein Panel, keine Punktezahl (resetet) und auch kein einzelner Ball erscheint.

Kann mir hierbei jemand helfen und das Problem lösen?

Link zur Ansicht: https://fehren1a.github.io/EIA2/abschluss_aufgabe/abschluss.html

saenglert commented 7 years ago

Moin moin, ich hab mich da mal etwas durchgewühlt:

            [...]
            else {
                s.update();
                p.draw();
            }
            window.setTimeout(animate, 0.01);
        }//Ende for-Schleife
}//Ende animate

Hier haben wird die Wurzel des Problems der Beschleunigung in deiner main.ts. Der neue Timeout wird so oft gesetzt wie es Bälle gibt. Kein Problem so lange es einer ist, sobald es mehr werden krachts.

Dann wäre da noch die länge deines Timeouts mit 0.01ms. Das ist etwas arg kurz. 20ms und die daraus resultierenden 50 FPS reichen für unsere Zwecke völlig. Ich nehme mal stark an dir ging es dabei hauptsächlich um die Geschwindigkeit des Balls. Um die anzupassen hast die xspeed und yspeed in deiner Ball.ts.

Das Problem mit den überlappenden Highscores ensteht aus der Tatsache heraus, dass jeder deiner Bälle einen eigenen Highscore besitzt, diesen zählt und ausgibt. Diese Funktionalität musst du ins Hauptprogramm verschieben.

Den Spielneustart habe ich auch wieder zum Laufen gebracht und ich war auch etwas verwirrt über das Verhalten von TS/JS an der Stelle. In die Details würde ich an der Stelle jetzt nicht gehen, da wirds etwas zu technisch, aber du kannst dir meinen Pullrequest anschauen und vergleichen, was ich an der Stelle anders mache.

fehren1a commented 7 years ago

Der Spieleablauf funktioniert jetzt soweit und habe nun den counter ins Hauptprogramm verlegt und der zweite Ball hat nun auch das richtige Bewegungsverhalten. Danke schonmal hierfür! :)

Als letzten Schritt möchte ich nun noch mit TypeScript erreichen, dass es ein Menü gibt und ich nur darüber mit Klick auf die entsprechende Option zum Spiel gelange. Für dieses Menü habe ich eine Datei namens gui.tserstellt, welche auch als erstes aufgerufen wird. In dieser werden die jeweiligen Menüpunkte gezeichnet und über eine switch (anzeige) soll geregelt werden, welche Funktionen aufgerufen werden. In case 1wird beispielsweise die init() aufgerufen, welche sich in der Pong.tsbefindet und das eigentliche Spiel bzw. die Spielfunktionalität regelt. Folgende Probleme gilt es zu beheben:

  1. Wie kann ich den Menüpunkten jeweils einen EventListener("click")dranhängen, sodass ich bei Klick auf "Start Game" bzw. "Help" zum gewünschten Ergebnis komme und die cases ausgeführt werden?

  2. Bei der ehemaligen main.ts (Hauptprogramm) hat das Spiel reibungslos funktioniert. Nachdem ich diese nun zu einer Klasse umgebaut habe, jedoch den Inhalt nicht verändert habe, funktioniert das Spiel beim Aufruf der init() nicht mehr, d.h. kein animierter Ball, Panel usw.. Die init() ruft ja wierderum die animate() auf, weshalb eig. etwas passieren sollte.

Benötige daher dringend Hilfe, um auch dies noch gelöst zu bekommen.

Link zum Repo: https://github.com/fehren1a/EIA2/tree/master/abschluss_aufgabe

JirkaDellOro commented 7 years ago
  1. Hier kommen mir zwei Alternativen in den Sinn

    • die Buttons als HTML-Elemente per CSS über den Canvas legen und wie üblich mit einem Listener versehen, oder
    • einen Listener auf dem Canvas platzieren und dann die Zeigerposition mit den Textpositionen vergleichen
  2. Ich kann leider keine Klasse in main.ts erkennen...

fehren1a commented 7 years ago

Okay, wären denk ich leichtere Optionen. Also mit der main.ts meinte ich, dass man diese nicht mehr berücksichtigen braucht und ich stattdessen die Pong.ts habe.

JirkaDellOro commented 7 years ago

Hmmm.... und wo wird jetzt ein Pong-Objekt instanziert?

fehren1a commented 7 years ago

In der gui.ts wird das getan. Bin gerade noch an einer zweiten Version, werde diese gleich noch hochladen.

fehren1a commented 7 years ago

Habe nun dieses Problem behoben und bin das Problem mit einem Click auf den Canvas umgangen, was aber in diesem Falle ausreicht. Da ich bei einer Punktezahl von 1 (counter == 1) einen zusätzlichen Ball in das Array reinpushe würde mich interessieren, wie ich diesen wieder gelöscht bekomme im Falle von GameOver. Muss ich hier in der if (s.gameOver) mit .pop arbeiten?

Link zur Ansicht: https://fehren1a.github.io/EIA2/semesteraufgabe/abschluss.html

Link zum Repository: https://github.com/fehren1a/EIA2/tree/master/semesteraufgabe

JirkaDellOro commented 7 years ago

Ja, mit .pop wird das letzte Element des Arrays herausgenommen. Vielleicht ist es aber viel einfacher und geschickter, einfach ein neues, leeres Array zuzuweisen. Das alte wird dann automatisch komplett aus dem Speicher gelöscht.

fehren1a commented 7 years ago

Komme leider immer noch nicht ganz dahinter, wie ich das einbauen soll. Angenommen das leere Array heißt Collector{}. Dann habe ich ja in der animate() eine if(s.gameOver){}. Würde das dann bedeuten, dass ich in der if-Bedingung Collector.push(ball) schreibe und in deren else amount = 0? Und wird das Spiel dann auch wieder richtig geladen mit einem Ball oder fehlt da noch irgendwas?

JirkaDellOro commented 7 years ago

Um da helfen zu können, müsste ich erst die gegenwärtige Struktur verstehen und akzeptieren. Da kommen zunächst Fragen bzw. Korrekturnotwendigkeiten auf

fehren1a commented 7 years ago

Das werde ich noch umändern, damit es aussagekräftiger wird. GameOver hatte ich ursprünglich in der Ballklasse deklariert, weil ich hier auch gesagt habe, dass sich der Zusatnd zu true ändert, wenn der Ball das Spielfeld unten verlässt. Also damit hätte jeder Ball ein individuelles gameOver.

JirkaDellOro commented 7 years ago

Wenn der Ball das Spielfeld verlässt, erscheint es mir intuitiver, wenn er einfach aus der Berechnung heraus genommen, also gelöscht wird. Sind keine Bälle mehr im Spielfeld, das Ball-Array also leer, dann ist das Spiel vorbei.

fehren1a commented 7 years ago

Danke, ich werde es probieren umzusetzen.

fehren1a commented 7 years ago

Problem mit dem Ball ist gelöst

JirkaDellOro commented 7 years ago

Wunderbar!