Ergebnis 1 bis 8 von 8

Thema: Welche Methode zum prüfen einer Kollision von Objekten?

Baum-Darstellung

Vorheriger Beitrag Vorheriger Beitrag   Nächster Beitrag Nächster Beitrag
  1. #2
    Hashs sind schon die richtige Idee, aber ich würde keine Hashs mit einem [x,y] Key verwenden. Besser wäre ein Hash in der Form eines Gitternetzes. Du hast ja vorher die Idee einer Tabelle geäußert, bei der jedes 4x4 Tile einen Tabelleneintrag hat. Du musst aber nicht jedem Tile einen Tabelleneintrag geben. Du kannst die Tabelle auch gröber machen. Stell sie dir wie ein grobmaschiges Netz vor, dass du über die Karte spannst. Es könnte z.B. 64x64 große Gitterfelder haben, oder noch größer, je nachdem wie du zwischen Speicher und Performance ausbalancieren willst. Solch ein Gitternetz hat noch einen weiteren Vorteil: Du kannst nicht nur effizient Kollisionen überprüfen, sondern auch effizient ob ein Event in der Nähe eines anderen ist (goldwert, wenn du sowas wie "Sichtweite, oder Reichweite von Waffen o.ä. einführen willst). Denn dann musst du nicht jedes Nachbarfeld absuchen, sondern nur noch Events die sich innerhalb der benachbarten großen Gitterfelder aufhalten (was bei dünnbesiedelten Maps WESENTLICH weniger Aufwand ist).

    Wie könnte so eine Tabelle aussehen?
    Hier mal der Rohbau für einen 2D-Array:
    Code:
    class Array2D
      include Enumerable
      def initialize rows, cols, content=nil &content_block
        @rows = rows
        @cols = cols
        if content_block then
          @data = Array.new(@rows * @cols, &content_block)
        else
          @data = Array.new(@rows * @cols, content)
        end
      end
    
      def [](row, col)
        @data[row * @cols + col]
      end
    
      def []=(row, col, value)
        @data[row * @cols + col] = value
      end
    
      def each &block
        @data.each &block
      end
    end
    Damit hast du schon mal eine einfache 2D-Array Konstruktion.
    Code:
    tabelle = Array2D.new(10, 10, 0)
    print tabelle[5, 5] #=> 0
    Jetzt kannst du davon eine Subklasse für eine GridMapHash Klasse machen:
    Code:
    class GridMapHash < Array2D
      def initialize mapwidth, mapheight, resolution=64
        super((mapwidth/resolution.to_f).ceil, (mapheight/resolution.to_f).ceil) {Array.new}
        @resolution = resolution
      end
    
      def characters_at x, y
        self[x%@resolution, y % @resolution]
      end
    
      def field_blocked? x, y, char
        characters_at(x, y).any? {|event| event != char && !event.through && event.is_blocking(char, x, y) }
      end
    
      def character_moves(char, fromx, fromy, tox, toy)
        unless (fromx%@resolution) == (tox%@resolution) && (fromy%@resolution)==(toy%@resolution)
          characters_at(fromx, fromy).delete(char)
          characters_at(tox, toy) << char
        end
      end
    end
    Jetzt überschreibst du noch die movement-Methoden der Game_Character Klasse und sagst den Events, dass sie alle Positionsänderungen an diese GridMapHash Instanz melden sollen. DIe Methode is_blocking? musst du noch selbst schreiben. Die sollte prüfen ob das Event dem Char wirklich im Weg steht.

    Edit: Ich hab noch was übersehen. Du verwendest Kollisionsbereiche für deine Events. Das hat natürlich den Nachteil, dass ein Event zwar im Gitterfeld x/y stehen kann, sein Kollisionsbereich aber ins Feld x+1/y hineinragt. Entsprechend musst du die field_blocked? Methode umschreiben, so dass sie auch die umliegenden Felder überprüft, die im Kollisionsradius liegen. Wenn du die Auflösung größer als den größtmöglichen Kollisionsradius wählst, werden immer maximal 3 Gridfelder überprüft werden müssen. Der Aufwand hält sich dann also trotzdem in Grenzen. Es ist nur eben etwas mehr Programmieraufwand das hinzuschreiben.

    Geändert von -KD- (16.03.2011 um 18:02 Uhr)

Berechtigungen

  • Neue Themen erstellen: Nein
  • Themen beantworten: Nein
  • Anhänge hochladen: Nein
  • Beiträge bearbeiten: Nein
  •