2D Spiel Hilfe

  • Einleitung
    Da ich schon immer versucht habe mal ein eigenes kleines 2D Spiel zu programmieren. (auch früher als ich AutoIt noch garnicht kannte)
    Nun wollte ich gucken wie ich so etwas in AutoIt umsetzten kann. Meine erste Idee war es, Bilder zu benutzten und diese auf der GUI Oberfläche zu verschieben. Mein zweiter Gedanke war es, das ich vieleicht eine Funktion erstellen könnte mit der man einfach 2D Objekte erstellen kann, welche aber merken, wenn sie ein anderes Objekt berühren.

    Einführung in das Thema

    Prinzip Objekte/Grundlagen
    _SetPlayingField()
    Zu aller erst gibt man den Spielflächen Rand mit der Funktion _SetPlayingField() an. Denn ein Objekt soll merken wenn es den Rand des Spielfeld berührt. _SetPlayingField(0,0,500,500) setzt die größe des Spiefeldes auf 500*500 pixel und der obere linke punkt des feldes ist (0|0).

    _CreateObject()
    Man erstellt mit der _CreateObject() Funktion 4 eckige Bilder auf einem Spielfeld.
    $testbild=_CreateObject("bild.jpg",100,450,50,50,"test",2) erstellt ein Bild mit dem Aussehen von der Datei bild.jpg an den Koordinaten x=100 und y=450. Was das "test" zu bedeuten hat spielt noch keine Bedeutung. Dafür ist der letzte wert wichtig. 0 ist für Objekte die keine anderen Berühren können, 1 ist für gegenstände die andere Berühren können aber den Rand nicht und 2 heißt sie können andere Objekte und den Rand berühren und das sie sich gegenseitig blocken.

    _ObjectTouch()
    Mit ObjectTouch können wir herausfinden ob ein Object irgend etwas anderes berührt. if _ObjectTouch($testbild)=0 Bei diesem Beispiel sehen wir, das der Wert 0 zurück gegeben wird, wenn das Object ncihts anders berührt und 1, wenn es was anders berührt.

    _ObjectMove()
    Diese Funktion ist sehr wichtig! Damit wird ein Objekt verschoben, hier der Beispiel Code: _MoveObject($testbild,"x",10)
    Das $testbild Object wird auf der X-Achse um 10 nach rechts verschoben, aber nur wenn es nicht daran gehindert wird!
    Fals ein anderes Objekt auf der Strecke liegt passiert garnichts! Wenn dies der fall ist gibt die FUnktion 0 zurück, ansonsten 1.

    _DeleteObject()
    Mit _DeleteObject($testbild) wird das Objekt wieder gelöscht.

    Erweiterte Funktionen
    Nachdem wir die Basis gelernt haben können wir schon einfache 2D Programme schreiben, doch es fehlen noch weitere nützliche Funktionen die einen neue Anwendungsmöglichkeiten erlauben. Eines davon sind die Objektgruppen.

    Objekt Gruppen

    Ihr habt die Möglichkeit eine Array von Objekten zu erstellen, dafür bietet meine UDF noch weitere wichtige Funktionen. Eine Array von Objekten wird hier auch Objekt Gruppe genannt.

    _MoveObjectGroup()
    Dieser Befehl arbeitet genau so wie _MoveObject(), nur das die Array der Objekte mitgegeben wird und alle Objekte in dieser Array verschoben werden. Wichtig ist, das die Array 1Dimensional ist und es keine leeren Elemente gibt.
    Beispiel:
    dim $testbild[2]
    $testbild[0]=_CreateObject("bild.jpg",100,450,50,50,"test",2)
    $testbild[1]=_CreateObject("bildB.jpg",100,400,50,50,"test",2)
    _MoveObjectGroup($testbild,"x",5)

    _ObjectGroupTouch()
    Ich glaube hierzu muss ich nicht mehr viel sagen, es Funktioniert genau so wie _ObjectTouch()

    _DeleteObjectGroup()
    Mit _DeleteObjectGroup() wird die gesamte Objekt Array gelöscht. (Man sollte grundsätzlich Objekt Gruppen mit dieser Funktion löschen!)

    Erweiterte Funktionen für Objekt Gruppen
    _SetObjectGroup()
    Damit wird eine Objekt Gruppe gesetzt, dies ist aber nicht zwingend notwendig, nur wenn man die Funktion _GetObjectGroup() benutzten will.

    _GetObjectGroup()
    Diese Funktion kann sehr nützlich sein, doch es wird die _SetObjectGroup() Funktion vorrausgetzt. Man gibt ein Objekt mit und fals es in einer Objekt Gruppe ist, wird die Array der Objekt Gruppe zurück gegeben, ansonsten der Wert 0.

    Objekt Gruppen in Array
    Vieleicht möchtest du eine Array von Objekt Gruppen machen, dies währe eine 2Dimensionale Array. Doch bei den ObjectGroup-FUnktionen kann man nur 1 Dimensionale Array mitgeben. Darum braucht man hier die Funktion _GetObjectGroupString() und _GetObjectGroupArray().

    _GetObjectGroupString()
    Wandelt die Array einer Objekt Gruppe in einen String, den man gut in einer Array speichern kann.

    _GetObjectGroupArray()
    Damit sich das ganze lohnt wandelt man mit dieser Funktion den String wieder in eine Array um und kann ihn weiter benutzten

    Klassen
    Ganz zu beginn der ANleitung haben wir uns gefragt, wofür das "test" in _CreateObject("bild.jpg",100,450,50,50,"test",2) nützlich sein könnte. Dieses "test" ordnet das Objekt der Klasse "test" zu. Und wann wird das gebraucht?

    _ObjectTouchClass()
    Dies Funktioniert genau so wie _ObjectTouch(), nur das diesmal überprüft wird ob das Objekt ein anders Objekt einer bestimmten Klasse berührt.
    if _ObjectTouchClass($hans,"test")=1 then

    _ObjectGroupTouchClass()
    Dies ist nochmal dasselbe, nur das überprüft wird ob eine Objekt Gruppe eine Klasse berührt.


    Mein Beispiel:
    Damit habe ich dann ein ganz ganz einfaches Jump&Run gemacht.
    Man steuert eine Kreuz und kann nach rechts/links laufen und mit leer auf andere Kisten springen.
    Außerdem gibt es Pilze welche sich die ganze zeit bewegen. Wird man von ihnen berührt, stirbt man. Springt man auf sie drauf, verschwinden sie.
    (So wie bei Super Mario)

    Download:

    Last Update: 13.2.2009

    MfG Oger-Lord

    10 Mal editiert, zuletzt von Oger-Lord (13. Februar 2009 um 17:13)

  • Toll!
    Ersetzt doch Zeile 18 durch

    [autoit]

    global $ich=@scriptdir & "\bilder\ich.jpg"
    $figur=_createObject($ich,100,450,50,50)

    [/autoit]


    und mach so nen roten ball oder so als ich.jpg, sieht besser aus, wieso sollte eine kiste rumhüpfen?!

    Bug entdeckt:
    man kann neu springen, egal wie die Figur eine Kiste berührt, man kommt also eine senkrechte Wand hoch.

    Twitter: @L3viathan2142
    Benutze AutoIt persönlich nicht mehr, da ich keinen Windows-Rechner mehr besitze.

  • Ja, als nächtest müsste ich einbauen das die seite zurück gegeben wird, an der man etwas berührt.
    Und das man Objekte erstellen kann die mit nichts außer dem Spielrand zusammen stoßen können.

    Das ganze Script ist noch ziemlich unfertig, aber dan kann ich ja weiter arbeiten. :)

  • So, ich hab das genze leicht umstruktuiriert. Die _moveObject()Funktion arbeitet jetzt mithilfe der _Objectberuehrt() funktion.
    Außerdem habe ich noch etwas neues mit reingebracht:

    Objekt Arrays
    Durch Objekt Arrays hat man die Möglichkeit andere Formen darzustellen indem man mehrere Objekte kombiniert.
    In meinem Beispiel ist es das Kreuz. Es besteht aus 2 Vierecken und 1 Rechteck. Diese wurden zusammen in einer Array erstellt:

    [autoit]

    dim $figur[3]
    $figur[0]=_createObject($kreuz,200,449,17,17,2)
    $figur[1]=_createObject($kreuz,183,466,51,17,2)
    $figur[2]=_createObject($kreuz,200,483,17,17,2)

    [/autoit]

    Mit den beiden neuen Funktionen
    _MoveObjectGroup() ; und
    _ObjectGroupTouch();
    hat man die Möglichkeit auch die zusammengesetzten Objekte wie normale Objekte zu nutzten.

    Ich denke das sieht man am besten wen man das Beispiel einmal testet.

    MfG Oger-Lord

    Einmal editiert, zuletzt von Oger-Lord (9. Februar 2009 um 16:59)

  • Stimmt, und zwar kann man beim erstellen von Objekten ihnen auch einen Klassennamen zuweisen. Dies wird erst durch die Funktion _ObjectTouchClass() und _ObjectGroupTouchClass() nützlich mit der man überprüfen kann ob ein ein Objekt ein anderes berührt welches sich in einer bestimmten gruppe befindet.

    Außerdem habe ich den Anfangs Post erneuert, in dem nun die einzelnen Funktionsweisen Sachen erklärt werden und ich habe den Funktionen alle einheitliche Namen gegeben und eine Beschreibung hinzugeügt.

    Würde mich über etwas mehr Feedback freuen :)

    MfG Oger-Lord
    (Ab jetzt kommt in die Zip datei immer eine Versions Nummer, hab die schon mehrmals aktualisiert)

  • Wenn es dir zu langsam geht erhöhe doch einfach die Zahlen in Zeile 66 und 71 von -3 und 3 auf -7 und 7.

    Dann ist es schön schnell^^


    Edit: Allerdings sind insgesamt noch ein paar Bugs... Die Kollisionen sind unsauber und manchmal kann man durch kisten durchspringen...

    Aber an sich gefällt mir das Projekt^^

    Einmal editiert, zuletzt von lavido (9. Februar 2009 um 19:10)

  • Ja, wenn man das erste mal gestorben ist kann man durch die Kisten links springen. WIe das kam habe ich keine Ahnung, habe ich aber schon gefixt.
    Zu den Unsauberen Kollisionen: Je größer die Schritte sind die du dich bewegst desto ungenauer wird das ganze. WEnn ich mit 7 pexel Schritten zur Wand gehe bin ich vieleicht schon schnell mit 3 pixeln in der wand. Und da das ja nicht gehen soll wird der Schritt nicht gemacht und du stehst mit 4 Pixeln vor der Wand. Dies wird vorallem beim Springen deutlich, weil man sehr schnell steigt und fällt.

    Hm, ich glaube ich müsste das script noch so umändern das es noch alle möglichkeiten durchprobiert. Bei einem 7ner schritt z.b. noch (6,5,4,3,2,1).

  • So, habe schon wieder weiter gebastelt.

    Ein Überblick über die Funktionen:

    Spoiler anzeigen

    _SetPlayingField()

    _CreateObject()
    _MoveObject()
    _ObjectTouch()
    _DeleteObject()
    _ObjectTouchClass()

    _SetObjectGroup() ;neu
    _MoveObjectGroup()
    _ObjectGroupTouch()
    _ObjectGroupTouchClass()
    _GetObjectGroup() ;neu
    _DeleteObjectGroup()

    Damit habe ich 2 Pilze erstellt, sobald man diese berührt stirbt man, aber wenn man auf sie Draufspringt, verschwinden sie.
    Außerdem habe ich mal leben eingeführt. Sobald man keine Leben mehr hat und dan stirbt ist das Spiel zuende

    Die neuste version gibt es immer im ersten post

    Hier ist nochmal ein Bild:

  • Was meinst du damit? Den Text des ersten posts habe ich noch nicht überarbeitet, aber es gibt die neuste version zum download.

    edit: Hast recht, dumm von mir, hab das falsche archiv gelöscht, jetzt aber :)

    Edit:
    Ich bräuchte noch hilfe, wüsste Jemand wie man folgende Funktion umstellt damit sie schneller durch läuft? Sie wird so oft pro Sekunde gebraucht und ich würde gerne das das ganze Program noch flüssig bleibt wenn es komplizierter wird.

    Hier ist die Funktion

    Spoiler anzeigen
    [autoit]

    ;===============================================================================
    ; Function Name: _ObjectTouch()
    ; Description: Berührt ein Object gerade etwas?
    ; Parameter(s): $number - Das zu überprüfende Object
    ; Requirement(s): A new AutoIt version
    ; Return Value(s): Berührt nichts: 0 Ansonsten: 1
    ; Author(s): Oger-Lord
    ;===============================================================================
    func _ObjectTouch($number,$ausnahmen="",$richtung="",$pixel=0,$art=1)
    $x=$Objekte[$number][1]
    $y=$Objekte[$number][2]
    local $return=0

    if $richtung="x" Then
    $x=$x+$pixel
    endif

    if $richtung="y" Then
    $y=$y+$pixel
    EndIf

    if $Objekte[$number][6]=2 then

    [/autoit] [autoit][/autoit] [autoit]

    if $x<$Objekte[0][1] then
    $x=$Objekte[0][1]
    $return=1
    endif

    if $x>$Objekte[0][3]-$Objekte[$number][3] then
    $x=$Objekte[0][3]-$Objekte[$number][3]
    $return=1
    endif


    if $y<$Objekte[0][2] then
    $y=$Objekte[0][2]
    $return=1
    EndIf

    if $y>$Objekte[0][4]-$Objekte[$number][4] then
    $y= $Objekte[0][4]-$Objekte[$number][4]
    $return=1
    endif

    EndIf

    if $Objekte[$number][6]<>0 then
    for $r=1 to $Objekte[0][0]
    if $r <> $number and $Objekte[$r][0]<>"" and $Objekte[$r][6]<>0 and stringinstr($ausnahmen,$r)=0 Then
    if $x >= $Objekte[$r][1] + $Objekte[$r][3] or $Objekte[$r][1] >= $x + $Objekte[$number][3] or $y >= $Objekte[$r][2] + $Objekte[$r][4] or $Objekte[$r][2] >= $y + $Objekte[$number][4] then
    Else
    $y=$Objekte[$number][2]
    $x=$Objekte[$number][1]
    $return=1
    endif
    endif
    next
    endif

    if $art=1 then
    return $return
    Else
    local $koordinaten[3]
    $koordinaten[0]=$x
    $koordinaten[1]=$y
    $koordinaten[2]=$return
    return $koordinaten
    endif
    endfunc

    [/autoit]

    Einmal editiert, zuletzt von Oger-Lord (10. Februar 2009 um 16:27)

  • ok, hab bis jetzt immer nur mit if gearbeitet, gibt es einen wichtigen unterschied zwischen switch und select?
    Habe jetzt überall select benutzt.

    Btw. wie teste ich am besten wie viel schneller die Funktion durchläuft?

  • Hm, habe gerade gemerkt das man select nicht einfach durch switch ersetzten kann. Bei Switch muss man anscheinend den Wert einer Variable mitgeben, aber wie sieht das ganze mit einer and verküpfungen aus?

  • Select ist eigentlich nur Switch True.
    Manchmal kann man halt Switch nicht verwenden, nur bei sowas:

    [autoit]


    Switch $antwort
    Case 2
    ;sdadasdf
    Case 4
    ;asdfasf
    Case Else
    ;afasf
    EndSwitch

    [/autoit]


    and-verknüpfungen gehen in Switch und Select auch.

    Twitter: @L3viathan2142
    Benutze AutoIt persönlich nicht mehr, da ich keinen Windows-Rechner mehr besitze.

  • Also ist es egal welche variable ich nehme und ich kann imer 1 hinschreiben?

    [autoit]


    switch 1
    case $x>$Objekte[0][3]-$Objekte[$number][3]
    $x=$Objekte[0][3]-$Objekte[$number][3]
    $return=1
    endswitch

    [/autoit]

    Edit:
    Ich hab das ganze eben getestet und ich muss feststellen, das laut den Testergebnissen das IF schneller ist als das Switch. (switch 3,0628 if 2,95880)

    Einmal editiert, zuletzt von Oger-Lord (10. Februar 2009 um 18:24)