Wer kann bitte helfen? Prüfen, ob noch ein Zug möglich ist

  • GM 8
  • Wer kann bitte helfen? Prüfen, ob noch ein Zug möglich ist

    Morgen, allerseits,
    muss mich noch mal ans Forum wenden, weil ich es nicht hinbekomme, zu prüfen, ob noch ein Zug möglich ist. Ich habe ein Spielfeld von 15*15 Steinen a 40 Pixel. Ein Zug ist dann noch möglich, wenn sich 3 Steine der gleichen Farbe (object) berühren. Alle Objekte in dem Spielfeld sind solid.
    Bis jetzt hab ich folgendes überlegt: Das Spielfeld von unten nach oben prüfen (die Steine fallen nach unten), die Prüfung abbrechen, wenn eine leere Zeile da ist, darüber kann kein Stein sein.
    Während der Prüfung jedes Feld darauf überprüfen: hat der betreffende Stein Nachbarn der gleichen Farbe? Bis jetzt überprüfe ich nur auf einen Nachbarn, aber schon das klappt nicht :-(((

    Mein Code bisher:

    GML-Quellcode

    1. var i,j,o_objekt;
    2. global.zaehler=0;
    3. for (j=580;j>=20;j-=40)
    4. {
    5. for(i=20; i<600; i+=40)
    6. {
    7. if collision_line(0,j,600,j,all,true,true) = noone {exit}; // leere Zeile? Dann Abbruch
    8. o_objekt=position_meeting(i,j,object_index); // hier bekomme ich NICHT den Namen des Objektes geliefert. Was muss stattdessen da stehen??
    9. if o_objekt <> -1 // abhängig von der oberen Zeile: nur prüfen, wenn da überhaupt ein Stein ist - ist wohl auch falsch
    10. {if(position_meeting(i+40,j,o_objekt) || position_meeting(i-40,j,o_objekt) || position_meeting(i,j+40,o_objekt) || position_meeting(i,j-40,o_objekt)) global.zaehler+=1}
    11. } //Wenn Prüfung erfolgreich (=Zug möglich), dann den Zähler erhöhen.
    12. }
    13. } // Mist, hatte alles so schön übersichtlich eingerückt, aber der Editor hat alles wieder zusammengeschoben :-(
    Alles anzeigen


    Wie gesagt, ich hab noch keine Vorstellung, wie ich auf 2 gleiche Nachbarn prüfen soll - aber nicht einmal die Prüfung auf einen Nachbarn haut hin.
    Wer kann hier bitte weiterhelfen? Ich kaue schon seit einer Woche an dem Problem... ;)
    Danke schön schon mal im voraus für evtl. Hilfe,
    Archie
    Signatur? Ich überlege mir noch eine. Die besten sind ja schon alle vergeben... :para:
  • Da gibt es bestimmt mehrere Rangehensweißen, jedoch habe ich das bei meinem Spiel immer über einen globalen Index geregelt.

    Ich weiß nicht so recht ob du sowas Kirby Avalanch mäßiges machst, oder eine Art Vier Gewinnt, deswegen beschreibe ich einfach meinen Lösungsweg meines Kirby Avalanch Klones.

    Zur erklärung:
    Es gibt im grunde zwei Kugelarten, oKugelAktiv und oKugelPassiv. Das Objekt welches diese erstellt heißt oKugelHandler.

    Es wird immer nur eine Instanz von oKugelAktiv erstellt, diese ist die Instanz, welche sich von oben nach unten im Spielfeld bewegt (oder auch seitlich und alles).

    In oKugelHandler, wird zuanfang eine ds_liste erstellt, sowie eine Index Variable. Auf die anderen sachen gehe ich nachher ein
    Create:

    GML-Quellcode

    1. dslKugelFarben = ds_list_create();
    2. dslKugelPassiv = ds_list_create();
    3. iIndex = 0;
    4. event_user(0); // Liste mit Farben füllen + ds_list_shuffle(); zum durchmischen


    Spoiler anzeigen
    So könnte man das event_user(0) Event schreiben:

    GML-Quellcode

    1. // Kugelliste erneuern
    2. repeat (2) {
    3. ds_list_add(dslKugelFarben ,c_red);
    4. ds_list_add(dslKugelFarben ,c_blue);
    5. ds_list_add(dslKugelFarben ,c_green);
    6. ds_list_add(dslKugelFarben ,c_yellow);
    7. ds_list_add(dslKugelFarben ,c_purple);
    8. }
    9. ds_list_shuffle(dslKugelFarben );


    Immer wenn nun eine Kugel erstellt wird, vom Typ oKugelAktiv, so wird ihr erstmal nur die Farbe gegeben.

    GML-Quellcode

    1. // Die Kugeln erstellen
    2. oAktiv1 = instance_create(96,0,oKugelAktiv);
    3. oAktiv1.cFarbe = ds_list_find_value(dslKugelFarben,0);
    4. oAktiv1.oMeister = id; // wichtig!!!
    5. ds_list_delete(dslKugelFarben,0);
    6. // Gebe nach und nach immer die in der Liste forderste Farbe aus, dann lösche diese damit die nächste Farbe vorrücken kann
    7. // Kugelliste leer?
    8. if ds_list_empty(dslKugelFarben)
    9. event_user(0);


    Wenn jetzt, die aktive Kugel mit der Wand (unter sich, nicht seitlich) Kollidiert oder mit einem Stein, soll sie sich in eine passive Kugel verwandeln

    GML-Quellcode

    1. // Aktive Kugel wird passiv
    2. y = floor(y/32)*32; // Position richten
    3. instance_change(oKugelPassiv,true);


    Diese passive Kugel hat nun in ihrem Create Event eine "anmelde Pflicht", sie meldet sich also bei der Instanz von oKugelHandler an. Deswegen ist es auch wichtig instance_change zu benutzten, damit die Variable oMeister, mit der id des Handler nicht verloren geht (wichtig für multiplayer oder gegner, also falls mehr als nur ein Handler sich im Raum befindet). Dieses Anmelden wird nachher noch erläutert und ist wichtig.
    Darauf hin wird der Index der Variable, welcher zur Kettenbestimmung genommen wird, auf -1 gestellt, da wir ja normalerweiße bei 0 Anfangen.
    Dieser Index hat einen großen Vorteil: Auch wenn mehrere Kugel der gleichen Farbe, die sich aber nicht berühren, auf dem Feld sind, können wir diese Kugeln unterscheiden. Es haben nämlich alle Kugeln, gleicher Farbe, die sich berühren, den gleichen Index. Kugeln mit einer anderen Farbe die sich aber berühren, haben einen anderen Index.
    Nachdem wir zu Anfang der Kugel den kleinsten Index gegeben haben (-1), überprüfen wir einfach, ob eine Kugel links, rechts, oben, unten von ihr ist, mit einem größeren Index, aber von der gleichen Farbe. Sollte dies der Fall sein, übernimmt die Kugel einfach den Index, ansonsten kriegt sie einen neuen.

    GML-Quellcode

    1. // Kugel melden
    2. if ds_list_find_index(oMeister.dslKugelPassiv,id) == -1
    3. ds_list_add(oMeister.dslKugelPassiv,id);
    4. // iIndex einstellen
    5. iIndex = -1;
    6. var _obj, _w, _h;
    7. _w = 32;
    8. _h = 32;
    9. _obj = noone;
    10. if place_meeting(x+_w,y,oKugelPassiv) {
    11. _obj = instance_position(x+_w,y,oKugelPassiv);
    12. if _obj != noone {
    13. if _obj.cFarbe == cFarbe && _obj.iIndex != iIndex {
    14. iIndex = max(iIndex, _obj.iIndex);
    15. _obj.iIndex = iIndex;
    16. with (_obj)
    17. event_perform_object(oKugelPassiv,ev_other,ev_user0);
    18. }
    19. }
    20. }
    21. if place_meeting(x,y-_h,oKugelPassiv) {
    22. _obj = instance_position(x,y-_h,oKugelPassiv);
    23. if _obj != noone {
    24. if _obj.cFarbe == cFarbe && _obj.iIndex != iIndex {
    25. iIndex = max(iIndex, _obj.iIndex);
    26. _obj.iIndex = iIndex;
    27. with (_obj)
    28. event_perform_object(oKugelPassiv,ev_other,ev_user0);
    29. }
    30. }
    31. }
    32. if place_meeting(x-_w,y,oKugelPassiv) {
    33. _obj = instance_position(x-_w,y,oKugelPassiv);
    34. if _obj != noone {
    35. if _obj.cFarbe == cFarbe && _obj.iIndex != iIndex {
    36. iIndex = max(iIndex, _obj.iIndex);
    37. _obj.iIndex = iIndex;
    38. with (_obj)
    39. event_perform_object(oKugelPassiv,ev_other,ev_user0);
    40. }
    41. }
    42. }
    43. if place_meeting(x,y+_h,oKugelPassiv) {
    44. _obj = instance_position(x,y+_h,oKugelPassiv);
    45. if _obj != noone {
    46. if _obj.cFarbe == cFarbe && _obj.iIndex != iIndex {
    47. iIndex = max(iIndex, _obj.iIndex);
    48. _obj.iIndex = iIndex;
    49. with (_obj)
    50. event_perform_object(oKugelPassiv,ev_other,ev_user0);
    51. }
    52. }
    53. }
    54. if _obj == noone {
    55. iIndex = oMeister.iIndex;
    56. oMeister.iIndex += 1;
    57. if oMeister.iIndex > 100000
    58. oMeister.iIndex = 0;
    59. }
    Alles anzeigen


    Sollte die Kugel im Laufe des Spiels zerstört werden, so muss man sie auch wieder aus der Liste löschen, wir können ja nicht mit Kugeln im Spielfeld rechnen, die es nicht gibt ;).

    GML-Quellcode

    1. // Kugel abmelden
    2. ds_list_delete(oMeister.dslKugelPassiv,id);


    Und nun, im oKugelHandler Objekt kommt der eigentliche Trick, bei mir ist dies im event_user(2), dies kannst du aber natürlich dahin tuen, wo du es brauchst, nur am besten nicht ins Step Event oder soetwas was ständig aufgerufen wird, sonst sieht es dir deine FPS echt runter.
    Alle (bei mir mit >=4 Ketten eingestellt), Kugeln deren Kette >= 4 ist, werden zerstört. Hier kannst du also nachprüfen, ob 3 Kugeln einer Farbe nebeneinander liegen, indem du es ein wenig modifizierst.

    GML-Quellcode

    1. // Zerstöre alle Kugeln, deren Kette >= 4 ist
    2. var i, j, _temp, _counter;
    3. for (i = 0; i <= iIndex; i += 1) {
    4. _counter = 0;
    5. for (j = 0; j <= ds_list_size(dslKugelPassiv)-1; j += 1) {
    6. _obj = ds_list_find_value(dslKugelPassiv,j);
    7. if _obj.iIndex == i {
    8. _temp[_counter] = _obj;
    9. _counter += 1;
    10. }
    11. }
    12. // Diesen Teil musst du modifizieren, hier wird eingestellt, das alle Kugeln der Kette nun zerstört werden. Wenn du also nur willst das das Spiel jetzt weiter geht, setze hier eine boolean Variable auf true, die du zuvor natürlich auf false eingestellt hast. Einfach ein bisschen rumprobieren.
    13. if _counter > 3 {
    14. for (j = _counter-1; j >= 0; j -= 1)
    15. with (_temp[j])
    16. instance_destroy();
    17. }
    18. }
    Alles anzeigen


    Ich hoffe konnte meine Idee dir näherbringen und dir damit helfen. Bei weiteren Fragen, falls du dieses Verfahren nutzen willst, einfach nachfragen. Ich hoffe ich habe nichts wichtiges aus meinem Code jetzt ausgeschnitten, sollte soweit aber recht funktionstüchtig sein.

    Mfg.,
    Mokuyobi
    木曜日 (Mokuyōbi)
  • Whow, das ist aber viel, was Du da reingesetzt hast - vielen, vielen Dank erst mal für Deine Mühe! Wenn ich den Code so überfliege: im Grunde ähnelt er meinem sehr, es gibt nur 2 Unterschiede: ich habe keine Farblisten, sondern getrennte Objekte für jede Farbe und bei mir heißen sie nicht "aktive" und "passive" Kugeln, sondern halt "normale" und "inverte", was aber wurscht ist. Allerdings mache ich kein 4-gewinnt-Spiel, sondern nur so etwas sehr weit damit Verwandtes.

    Werde mir jetzt mal den ganzen Code, den Du ja zudem noch schön kommentiert hast, runterziehen und dann mal schauen, ob ich den letzten Teil nicht entsprechend meinen Code anpassen kann. Kann allerdings ein bisschen dauern ;)

    Vielen Dank noch mal,
    Archie

    PS: Die erste Frage kommt schon beim Kopieren des Codes. Diese Zeile im letzten Teil von Dir

    GML-Quellcode

    1. _obj = ds_list_find_value(dslKugelPassiv,j);

    speichert die aktuelle Farbe der Kugel. Weisst Du zufällig, was ich statt "ds_list_find_value" schreiben muss, wenn ich keine Liste habe, sondern einzelne Objekte? Mit object_get_name geht es jedenfalls nicht. :(
    Signatur? Ich überlege mir noch eine. Die besten sind ja schon alle vergeben... :para:

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von Archie ()

  • Da hast du anscheinend etwas falsch verstanden ^^.

    GML-Quellcode

    1. // Kugel melden
    2. if ds_list_find_index(oMeister.dslKugelPassiv,id) == -1
    3. ds_list_add(oMeister.dslKugelPassiv,id);


    So wird die Kugel ja angemeldet. Es wird dabei jedoch nur ihre id Übergeben! Weder Farbe, noch index noch sonst etwas.
    Dementsprechend bewirkt diese Codestelle:

    GML-Quellcode

    1. for (j = 0; j <= ds_list_size(dslKugelPassiv)-1; j += 1) {
    2. _obj = ds_list_find_value(dslKugelPassiv,j);
    3. if _obj.iIndex == i {
    4. _temp[_counter] = _obj;
    5. _counter += 1;
    6. }
    7. }


    Das alle passiven Kugeln durchgegangen werden. _obj speichert dabei nur die id der Kugel. Mit hilfe der if Abfrage wird dann auf den iIndex Wert der Instanz zugegriffen (Punktnotation). Die andere Variable in der if Abfrage, i, geht dabei alle möglichen Indexe durch, also von 0 -> iIndex des Objektes oKugelHandler.

    Deswegen steht auch bei bei das die Kugeln eine "anmelde Pflicht" sogesehen haben, damit sie in dieser for Schleife alle durchgegangen werden. So im nachhinen fällt mir ein man hätte auch instance_find nehmen können ^^, dann bräuchte man auch keine Liste der passiven Kugeln machen. Du könntest ja beispielsweiße ein Parent Objekt der Kugeln machen, falls noch nicht vorhanden, und alle instancen davon durchgehen, via instance_find, so kannst du dir die Liste sparen.

    Welche Farben die Kugeln haben ist in diesem Algorithmus eh uninteressant, da er sich rein nur auf die iIndex Variable der Instanzen bezieht, deswegen ist dies auch wichtig, das jede Kugel einen iIndex zugeteilt bekommt, und vorher überprüft wird, ob möglicherweiße eine Kugel in der nähe ist, oben, unten, rechts oder links von ihr, mit der gleiche Farbe, und die Instanz dann jenen iIndex Wert bekommt. Und wenn dann mindestens vier (oder bei dir drei) Kugeln diesen iIndex Wert haben, wird dieses Codesegment ausgeführt:

    GML-Quellcode

    1. // Diesen Teil musst du modifizieren, hier wird eingestellt, das alle Kugeln der Kette nun zerstört werden. Wenn du also nur willst das das Spiel jetzt weiter geht, setze hier eine boolean Variable auf true, die du zuvor natürlich auf false eingestellt hast. Einfach ein bisschen rumprobieren.
    2. if _counter > 3 {
    3. for (j = _counter-1; j >= 0; j -= 1)
    4. with (_temp[j])
    5. instance_destroy();
    6. }


    _temp ist eine lokale Variable die einfach alle id´s speichert bei jedem durchgang, und diese werden dann bis zur Grenze _counter-1 (da die Array nullbasiert ist) alle gelöscht. Da die id gespeichert ist in der Array _temp, lässt sich dies einfach mit with(_temp[j]) durchführen.

    Also um die iIndex Variable kommst du bei meiner Version nicht rum, die Liste der Id´s der Kugeln (dslKugelnPassiv) kannst du dir aber mit instance_find sparen ^^.

    Mfg.,
    Mokuyobi
    木曜日 (Mokuyōbi)
  • Ja, vielen Dank noch mal für die ausführliche Kommentierung und die Mühe, die Du Dir gegeben hast. Hab den ganzen Sonntag dran gesessen, jetzt ist bei mir mehr oder weniger ein Durcheinander eingetreten, also werde ich jetzt meine Sächelchen hier alle zusammensuchen, alles einpacken - und noch mal von vorn beginnen. Irgendwie muss das doch hinzukriegen sein... :D

    Ich werde mal diesen Thread hier als "gelöst" markieren, auch wenn bei mir (noch) nix gelöst ist, aber das dauert halt noch seine Zeit, denke ich. Falls ich je noch eine Rückfrage hätte, kann ich mich ja sicher noch mal an Dich wenden, Mokuyobi, oder....? ;)

    Vielen Dank an alle Helfer,
    Archie
    Signatur? Ich überlege mir noch eine. Die besten sind ja schon alle vergeben... :para:
  • Benutzer online 1

    1 Besucher