Pygame Raser

Hier werden alle anderen GUI-Toolkits sowie Spezial-Toolkits wie Spiele-Engines behandelt.
Antworten
robotron
User
Beiträge: 4
Registriert: Samstag 8. Dezember 2012, 13:12

Hier http://www.mikrocontroller.net/attachme ... 3/cars.zip gibt es kleines Progrämmchen in Pygame, welches eine typische Verkehrsituation auf unseren Straßen darstellt.
Interessant wäre es, mehrer Autos zu simulieren, die auch richtig bremsen und Gas geben können. Hat jemand von euch Vorschläge wie das zu bwerkstelligen wäre?
BlackJack

@robotron: Python lernen (am besten inklusive Objektorientierung), sich mit den physikalischen Gegebenheiten von Beschleunigung vertraut machen, und dann mit den entsprechenden Formeln die Geschwindigkeit in Abhängigkeit der Zeit bestimmen.

Und noch ein Lesetipp: PEP 8 -- Style Guide for Python Code.
robotron
User
Beiträge: 4
Registriert: Samstag 8. Dezember 2012, 13:12

Und noch ein Lesetipp: PEP 8 -- Style Guide for Python Code.
Oops, welche Styles sind Dir direkt unangenehm ins Auge gefallen? Ich weiß, dass jeder Programmierer einen bestimmten Stil bevorzugt.
Python lernen (am besten inklusive Objektorientierung
Ich versuchs mal zu modellieren:

Bild
BlackJack

@robotron: Namensschreibweisen und Einrückung zum Beispiel.

Bei der Modellierung fallen die doppelten führenden Unterstriche auf. So etwas wie ``private`` gibt es in Python nicht. Wenn man etwas als Implementierungsdetail kennzeichnen möchte, das von aussen nicht einfach so verwendet werden soll, dann nimmt man dafür konventionell *einen* führenden Unterstrich. Die doppelten veranlassen ein „name mangling” das Namenskollisionen bei Mehrfachvererbung vermeiden soll. Dabei ist Mehrfachvererbung etwas was die meisten Programmierer sowieso vermeiden. Allerhöchstens für „Mixin”-Klassen, was aber auch eher selten vorkommt. Als Folge gibt es auch in der Regel keine trivialen Getter- und Setter-Methoden. Wenn man die hat, dann ist das Attribut sowieso eigentlich öffentlich, also kann man auch direkt darauf zugreifen. Wenn man sich später umentscheidet und ein Attribut nicht mehr als Wert hat, sondern es berechnet, kann man mit `property()` dafür sorgen, dass sich die API nicht verändert.

Benötigt man tatsächlich einen `Fahrer`? Und ist *der* die richtige Stelle um nach der Entfernung zum nächsten Auto zu fragen? Nicht der Fahrer hat die Entfernung sondern eigentlich ja das Auto. Aber das kann die Frage im Grunde auch nicht beantworten ohne alle anderen Autos zu kennen.

Ist übrigens ein ziemlich wüster Englisch/Deutsch-Mix in dem Diagramm.
robotron
User
Beiträge: 4
Registriert: Samstag 8. Dezember 2012, 13:12

Vielen Dank für Deine Ausführungen. Da sind einige nützliche Tipps dabei.
Benötigt man tatsächlich einen `Fahrer`? Und ist *der* die richtige Stelle um nach der Entfernung zum nächsten Auto zu fragen? .
Das mit dem Fahrer ist mir auch erst spontan eingefallen. Aber nach einigem Nachdenken macht es für mich Sinn:
Es können unterschiedliche Fahrer mit bestimmten Fahrweisen in verschiedenen Autos sitzen. Beispielsweise könnte ein junger sportlicher Fahrer in einem Fiat500 mit 50PS sitzen, oder ein älterer Rentner in einem Mercedes mit 300PS. Der Rentner wird ab einem bestimmten Alter nur noch 80 auf der Landstraße fahren, während der jüngere Fahrer mit 120km/h mit überhöhter Geschwindigkeit fährt.
Deshalb macht es meiner Meinung nach Sinn, die Eigenschaften des Autos in der Autoklasse und die Eigenschaften des Fahrers in der Fahrerklasse zu realisieren. Der Fahrer ist sozusagen der Regler. Er sieht, wie weit er vom nächsten Auto entfernt ist und gibt je nach eigenem Temperament Gas oder bremmst. Das Auto wiederum hat bestimmt Eigenschaften wie Höchsgeschwindigkeit oder Beschleunigung.
Nicht der Fahrer hat die Entfernung sondern eigentlich ja das Auto. Aber das kann die Frage im Grunde auch nicht beantworten ohne alle anderen Autos zu kennen.
[/quote]

Der Einfachheit halber würde ich es so modellieren, dass der Fahrer immer nur das nächste Auto vorne sieht. Dann müsste man das nächste Auto nur im Fahrerobject bekannt machen. Es entstünde sozusagen eine verkettet Liste.
BlackJack

@robotron: Wenn der Fahrer die Fahrstrategie enthält, macht die Klasse natürlich Sinn. Dann würde ich aber eventuell die Beziehung umdrehen, also dass das Auto keinen Fahrer kennt, sondern der Fahrer sein Auto. Denn der Fahrer braucht Zugriff auf das Auto. Das Auto aber nicht unbedingt welchen auf den Fahrer. Es würden auch mehr Attribute zum Fahrer wandern können, wie zum Beispiel die Position. Vielleicht könnte man die Namen auch etwas generischer wählen als `Verkehrsteilnehmer` und `Fahrzeug`.

Bei so etwas muss man übrigens auch immer wissen was das Ziel des Programms ist. Das beeinflusst den Abstraktionsgrad und welche Sachen tatsächlich in eigenen Klassen modelliert werden müssen und welche nicht.

Das betrifft zum Beispiel auch ob es Sinn macht die Simulationslogik komplett von der Darstellung zu trennen. Dann hätte ein Fahrzeug/Verkehrsteilehmer zum Beispiel keine Bildschirmposition. Die würde sich dann in der Anzeigeschicht aus der Position in der Simulation berechnen. Und die würde man zum Beispiel in Metern ausdrücken.
robotron
User
Beiträge: 4
Registriert: Samstag 8. Dezember 2012, 13:12

Wenn der Fahrer die Fahrstrategie enthält, macht die Klasse natürlich Sinn. Dann würde ich aber eventuell die Beziehung umdrehen, also dass das Auto keinen Fahrer kennt, sondern der Fahrer sein Auto. Denn der Fahrer braucht Zugriff auf das Auto. Das Auto aber nicht unbedingt welchen auf den Fahrer.
Jetzt wo Du es sagst: Umdrehen würde tatsächlich Sinn machen. Leider habe ich jetzt schon eine erstes "Codeexperiment". Die nächste Zeit kann ich nicht mehr so viel an dem Programm machen, da ja jetzt die Woche schon wieder los geht.
Ich poste hier mal den Code. Die png-Bilder muss man sich aus dem ZIP-File am Anfang dieses Threads ziehen, dann läuft der Code.

Code: Alles auswählen

'''
Created on 09.12.2012

@author: christoph
'''

import pygame, sys
from pygame.locals import *

# the tempplate for this class is found here:
# http://bytemuehle.de/pygame%20Einf%C3%BChrung/
def load_image(name, colorkey=None):
    try:
        image = pygame.image.load(name)
    except pygame.error, message:
        print 'Cannot load image:', name
        raise SystemExit, message
    image = image.convert()
    if colorkey is not None:
        if colorkey is -1:
            colorkey = image.get_at((0,0))
        image.set_colorkey(colorkey, RLEACCEL)
    return image, image.get_rect()

class Driver():
    
    gasPedal=50 # gas pedal in percent ( 0..100% )
    
    def __init__(self,gas):
        self.gasPedal=gas
    def getGasPedal(self):
        return self.gasPedal
    def setItsCar(self,car):
        self.car=car
        
# the tempplate for this class is found here:
# http://bytemuehle.de/pygame%20Einf%C3%BChrung/
class Car(pygame.sprite.Sprite):
    
    speed=0 # speed in km/h
    maxAcceleration=10
    maxSpeed=150 # maximum speed in km/h
        
    def __init__(self,filename,driver,pos=(100,100),maxSpeed=150):
        self.driver=driver
        self.maxSpeed=maxSpeed
        pygame.sprite.Sprite.__init__(self)
        self.image, self.rect  = load_image(filename, -1)
        self.rect.center=pos

        self.screenrect = pygame.display.get_surface().get_rect()

    def update(self):
        acceleration=self.driver.getGasPedal()/25.0
        if self.speed<self.maxSpeed:
            self.speed+=acceleration
        self.rect.move_ip(self.speed/40, 0)


pygame.init() #load pygame modules
size = width, height = 1024, 768 #size of window

screen = pygame.display.set_mode(size) #make window

clock=pygame.time.Clock() #make a clock

raser=Driver(100)
rentner=Driver(50)

all_sprites = pygame.sprite.Group()
all_sprites.add(Car('fiat500.png',raser,(100,100),120))
all_sprites.add(Car('bmw3er.png',rentner,(100,200),200))
all_sprites.add(Car('fiat500.png',rentner,(100,300),120))


flag=True

while 1: #infinite loop

        for event in pygame.event.get(): #if something clicked
                if event.type == pygame.QUIT: #if EXIT clicked
                        sys.exit() #close cleanly
        
        screen.fill((0,0,0))
        all_sprites.update()
        all_sprites.draw(screen)        
        pygame.display.flip() #update the screen
        

        clock.tick(30) #limit framerate to 30 FPS        
      

        
BlackJack

@robotron: PEP8 hat da ja noch keinen Eingang gefunden.

Wenn das Python 2.x ist, dann sollte `Driver` von `object` erben, damit man eine „new style”-Klasse bekommt, bei der auch alles wie in der Dokumentation beschrieben funktioniert. Also zum Beispiel `property()`.

Die Klassenattribute bei beiden Klassen machen keinen Sinn, weil die in der `__init__()` bis aus `maxAccelerazion` und `speed` durch Instanzattribute verdeckt werden. `speed` wird das spätestens nach dem Aufruf der `update()`-Methode.

`Driver` enthält unnötige Getter und Setter. Ausserdem sollten nach der Initialisierung eines Objekts alle seine Attribute existieren und nicht in beliebigen Methoden neue hinzugefügt werden. Das ist sehr undurchsichtig. Nach der `__init__()` sollte dem Leser klar sein woraus sich der Zustand eines Objekts zusammen setzt. Von dem Code würde letztendlich nur noch das hier übrig bleiben:

Code: Alles auswählen

class Driver(object):
    """A driver of a `Car`."""
    def __init__(self, gas_pedal=50, car=None):
        self.gas_pedal = gas_pedal
        self.car = car
`Car.update()` ist fehlerhaft. Es hindert einen nichts daran beim Beschleunigen beim letzten `update()`-Aufruf unter der Maximalgeschwindigkeit, diese zu überschreiten.

Der Rentner fährt zwei Autos gleichzeitig. Kann man so machen, damit verbaut man sich allerdings die Möglichkeit Fahrstrategien mit „Gedächtnis” zu implementieren. Denn dazu müsste jeder Fahrer unabhängig sein.
Antworten