Micro Machines Klon - Ruckeln bei 2 Playern?

Hier werden alle anderen GUI-Toolkits sowie Spezial-Toolkits wie Spiele-Engines behandelt.
Antworten
Benutzeravatar
Don Polettone
User
Beiträge: 115
Registriert: Dienstag 23. November 2010, 20:26
Wohnort: Schweiz

Hi,

ich hab ein nerviges Problem. Ich code zurzeit an einem Micro Machines - Klon (ein bisschen SNES like). Hab soweit schon ziemlich was beisammen und im wenn man allein spielt, funktioniert das ganz gut. Ich rendere alles auf einen Buffer 320 x 240 und skaliere das ganze dann hoch. Das Level besteht aus einem Hintergrund Sprite, dem Level Sprite, dem Track Sprite und dann werden noch die Hindernisse geblittet. Es werden immer nur diejenigen Ausschnitte (areas) aus den Surfaces geblittet, die gerade auf dem Bildschirm sind. Demnach befindet sich der Bildausschnitt nicht immer am selben Ort - das Bild "fährt mit". Ich errechne also jedes Frame die topleft Position, wo sich der Bildschirm befindet, und dies anhand der Position des Fahrzeugs. Mit einem Player funktioniert das wunderbar, aber wenn man zu zweit spielt, soll ja der Mittelpunkt zwischen beiden Autos die Mitte des Bildschirms sein, daraus errechne ich dann die topleft Position des Screens. Soweit, so gut und das stimmt soweit auch, aber wenn man zu zweit spielt und beide Autos in dieselbe Richtung fahren mit konstanter Geschwindigkeit, dann ruckelt's irgendwie. Nicht von wegen Performance oder so; ich habe das Gefühl dass es daran liegt, dass der errechnete Mittelwert nun manchmal ein float ist (bei einem Spieler ist's ja einfach immer ein int, da geht's immer auf). Aber auch wenn ich die errechnete Position runde mit round() ruckelt's noch immer, obwohl das Prinzip genau immer dasselbe ist...

evtl. hilft ein wenig Code:

Diese Methode errechnet die topleft pos vom Bildschirm (Game.screenpos):

Code: Alles auswählen

    def screenpos_update(self):

        n = len(self.cars)

        if n == 1:
            car = self.cars[0]
            x = car.rect.centerx - RES[0] / 2
            y = car.rect.centery - RES[1] / 2

        else:
            x_sum = 0
            y_sum = 0

            for car in self.cars:
                x_sum += car.x
                y_sum += car.y

            mid_x = x_sum / n
            x = round(mid_x - self.res[0] / 2)
            
            mid_y = y_sum / n
            y = round(mid_y - self.res[1] / 2)
                
        if x < 0:
            x = 0
        elif x > self.level.rect.width - self.res[0]:
            x = self.level.rect.width - self.res[0]
        if y < 0:
            y = 0
        elif y > self.level.rect.height - self.res[1]:
            y = self.level.rect.height - self.res[1]        

        self.screenpos = (x, y) # topleft
Wenn ich's nun mit 2 Playern starte und ein wenig Gas gebe, dann ruckelt das Auto, das beschleunigt, immer ganz leicht vor und zurück (1 Pixelweise), ganz schnell. Wenn man allein spielt ist das ganze super-smooth. Ich verstehe nicht, warum das eine funktioniert und das andere nicht richtig..? Jemand eine Idee? Wenn mehr Code hilft - gerne!

Danke


Henry
Ich code, also bin ich.
EyDu
User
Beiträge: 4881
Registriert: Donnerstag 20. Juli 2006, 23:06
Wohnort: Berlin

Was passiert denn, wenn du bei zwei Spielern immer den Fokus auf den ersten setzt. Ruckelt dann der zweite?

Außerdem solltest du numpy verwenden um die ganzen Vektoroperationen zu machen. Bei dir steht der ganze Code für x- und y-Achse doppelt.
Das Leben ist wie ein Tennisball.
Benutzeravatar
Don Polettone
User
Beiträge: 115
Registriert: Dienstag 23. November 2010, 20:26
Wohnort: Schweiz

EyDu, ähh.. hey, EyDu,

hmmm... ja voll, das mit dem Fokus stimmt, hab's gerade ausprobiert:

Code: Alles auswählen

def screenpos_update(self):

        n = float(len(self.cars))

        if n in (1, 2):
            car = self.cars[0]
            x = car.rect.centerx - RES[0] / 2
            y = car.rect.centery - RES[1] / 2

        else:
            x_sum = 0
            y_sum = 0

            for car in self.cars:
                x_sum += car.x
                y_sum += car.y

            mid_x = x_sum / n
            x = round(mid_x - self.res[0] / 2)
            
            mid_y = y_sum / n
            y = round(mid_y - self.res[1] / 2)
                
        if x < 0:
            x = 0
        elif x > self.level.rect.width - self.res[0]:
            x = self.level.rect.width - self.res[0]
        if y < 0:
            y = 0
        elif y > self.level.rect.height - self.res[1]:
            y = self.level.rect.height - self.res[1]        

        self.screenpos = (x, y) # topleft
Wieso wusstest Du das? Was kann ich gegen tun? numpy hab ich schon öfters gehört... wird wohl Zeit, sich das anzuschauen. Ich bin etwas library-faul und erfinde immer gerne etwas das Rad neu... na ja. Ja ja ich weiss - ich arbeite dran :D
Ich code, also bin ich.
BlackJack

Zu `numpy` würde ich nicht raten sondern zu `Rect`\s von `pygame`. Die haben so eine praktische `union()`- beziehungsweise `unionall()`-Methode und kennen ihren eigenen Mittelpunkt:

Code: Alles auswählen

In [280]: r1 = pygame.rect.Rect((0, 0), (2, 2))

In [281]: r2 = pygame.rect.Rect((10, 10), (2, 2))

In [282]: r1.union(r2)
Out[282]: <rect(0, 0, 12, 12)>

In [283]: r1.union(r2).center
Out[283]: (6, 6)
Benutzeravatar
Don Polettone
User
Beiträge: 115
Registriert: Dienstag 23. November 2010, 20:26
Wohnort: Schweiz

Hey BlackJack,

mit Rects "arbeite" ich seit einiger Zeit, das habe ich mittlerweile eingesehen. Aber ja, die union Funktion kannte ich nicht, danke.

Gleich :shock: ob's damit funzt! Kann's mir zwar nicht vortsllen - ist ja eigentlich auch dasselbe?
Ich code, also bin ich.
Benutzeravatar
Don Polettone
User
Beiträge: 115
Registriert: Dienstag 23. November 2010, 20:26
Wohnort: Schweiz

hey ist ja voll der Burner... es ruckelt nicht mehr, danke! Ihr seid Killer, Leute!

Code: Alles auswählen

    def screenpos_update(self):

        n = len(self.cars)

        if n == 1:
            car = self.cars[0]
            x = car.rect.centerx - RES[0] / 2
            y = car.rect.centery - RES[1] / 2

        elif n == 2:
            car1 = self.cars[0]
            car2 = self.cars[1]
            united_rect = car1.rect.union(car2.rect)
            x = united_rect.centerx - RES[0] / 2
            y = united_rect.centery - RES[1] / 2       

        self.screenpos = (x, y) # topleft
und viel kürzer ist auch. krass.

merci


Henry
Ich code, also bin ich.
BlackJack

@Henry Jones Jr.: Das geht noch kürzer wenn Du die Fälle nicht einzeln behandelst. `unionall()` funktioniert auch mit einer leeren Liste als Argument. Und statt der oberen linken Ecke könnte man auch ein `Rect` in Screengrösse zum Positionieren benutzen. Folgender Code setzt den Mittelpunkt dieses Rechtecks auf den Mittelpunkt der Autos, solange mindestens ein Auto existiert:

Code: Alles auswählen

    def screenpos_update(self):
        assert self.cars, 'no cars to follow'
        self.screen_rect.center = self.cars[0].unionall(self.cars).center
Die Frage hier, wie wohl auch beim alten Code ist, was passiert wenn die Autos so weit auseinander liegen, dass nicht mehr alle auf den sichtbaren Ausschnitt passen. Im schlechtesten Fall sieht man dann keines der Autos.
Benutzeravatar
Don Polettone
User
Beiträge: 115
Registriert: Dienstag 23. November 2010, 20:26
Wohnort: Schweiz

Hi Blackjack,

yep, hatte das gestern auch noch mit unionall() ausgebaut; aber hatte es noch immer unterteilt auf 1 bzw. mehrere Spieler.

Hast aber völlig Recht - dies wäre wohl die eleganteste Lösung. Bzgl. des "zu-weit-auseinanderliegens" der Autos: Es ist beabsichtigt, dass, wenn nicht mehr alle Autos auf den Screen passen, dann das hinterste Auto "rausfliegt"; die anderen Spieler können weiterzocken, bis nur noch einer da ist. Dann bekommt dieser einen Punkt. Daraufhin werden alle Autos wieder beim letzten erreichten Checkpoint gespawned und der Krieg kann weitergehen :-)

noch bzgl. assert: Ich "kenne" dies zwar, verstehe aber nicht, wieso Du unten noch einen string mitgibst..?

Was genau macht das? Ich könnte das Ganze auch ohne assert schreiben, nicht? Ist ja egal, wenn nur ein Auto in der Liste ist und car1 dann eine Liste bekommt mit sich selbst drin für die unionall() Funktion?

es grüsst und dankt:


Henry
Ich code, also bin ich.
Benutzeravatar
Don Polettone
User
Beiträge: 115
Registriert: Dienstag 23. November 2010, 20:26
Wohnort: Schweiz

alles klar - der String definiert die Ausgabe, wenn's eben nicht passt mit der assertion :-)

Sorry, keine weiteren Fragen :mrgreen:

Danke, hat SEHR geholfen dieser Thread!
Ich code, also bin ich.
Antworten