Ein einfaches Schiffchen-Versenken Spiel
Spielregeln: Jeder Spieler erhält ein Spielfeld mit 8 Schiffen an zufällig gewählten Positionen. Die Spieler versuchen, abwechslungsweise mit einem Mausklick die Position der Schiffe des Gegners zu erraten. Damit man die gleiche Zelle nicht mehrmals wählt, wird jeder Versuch mit einem roten Kreuz markiert. Bei einem Treffer wird das Schiff versenkt und verschwindet vom Spielfeld. Wer zuerst alle Gegnerschiffe versenkt hat, gewinnt.
Player 0 |
Player 1 |
Die beiden Spieler verwenden das gleiche Topic /swissgame/battleship. Im Programm legen sie mit player = 0 bzw. player = 1 fest, wer zuerst zum Zug kommt und starten das Spiel. Der Status der Verbindung wird mit der Callbackfunktion onStateChanged(state) überwacht und in der Statuszeile angezeigt. Sobald die beiden Spielpartner verbunden sind (Status READY) kommt der Player 0 zuerst zum Zug (in der Statuszeile erscheint "Make a move!").
In der Callbackfunktion onMousePressed() wird die x- und y-Koordinate des Mausklicks erfasst und als String zum Spielpartner gesendet. Im Callback onMessageReceived() empfängt der Partner diese Koordinaten und meldet zurück, ob sich an dieser Position ein Schiff befindet ("hit") oder nicht ("mis"). Die verbleibende Anzahl Schiffe wird in der Statusbar angezeigt. Dann kommt
#Battleship.py from gamegrid import * from mqttclient import GameClient player = x # set player = 0 or player = 1 myTopic = "/swissgame/battleship" class Ship(Actor): def __init__(self): Actor.__init__(self, "sprites/boat.gif") def onMousePressed(e): global isMyMove if not isMyMove or isOver: return loc = toLocationInGrid(e.getX(), e.getY()) addActor(Actor("sprites/checkred.gif"), loc) client.sendMessage(str(loc.x) + str(loc.y)) # send location setStatusText("Wait!") isMyMove = False def onStateChanged(state): global isMyMove if state == "CONNECTING": setStatusText("Connecting to broker...") elif state == "CONNECTED": setStatusText("Connected. Waiting for partner...") elif state == "READY": if player == 0: setStatusText("Make a move!") isMyMove = True else: setStatusText("Wait for partner's move!") elif state == "DISCONNECTED": setStatusText("Partner disconnected!") isMyMove = False def onMessageReceived(msg): global isMyMove, myHits, partnerHits, isOver if msg == "DISCONNECT": setStatusText("Partner disconnected") isMyMove = False return if msg == "hit": myHits += 1 setStatusText("Hit! Partner's fleet size " + str(nbShip - myHits) + ". Wait!") if myHits == nbShip: setStatusText("Game over, You won!") isOver = True elif msg == "miss": setStatusText("Miss! Partner's fleet size " + str(nbShip - myHits)) else: x = int(msg[0]) y = int(msg[1]) loc = Location(x, y) actor = getOneActorAt(loc, Ship) if actor != None: actor.removeSelf() refresh() client.sendMessage("hit") partnerHits += 1 if partnerHits == nbShip: setStatusText("Game over! Partner won") isOver = True return else: client.sendMessage("miss") setStatusText("You play! Partner's fleet size " + str(nbShip - myHits)) isMyMove = True def onNotifyExit(): client.disconnect() dispose() makeGameGrid(5, 5, 50, Color.red, False, mousePressed = onMousePressed, notifyExit = onNotifyExit) addStatusBar(30) nbShip = 8 for i in range(nbShip): addActor(Ship(), getRandomEmptyLocation()) show() isMyMove = False isOver = False myHits = 0 partnerHits = 0 setTitle("Player #" + str(player)) host = "m2m.eclipse.org" client = GameClient(onStateChanged, onMessageReceived, myTopic) client.connect(host) |
Erklärungen zum Programmcode:
addActor(Actor("sprites/checkred.gif"), loc): Setzt eine Marke in die gewählte Zelle | |
client.sendMessage(str(loc.x) + str(loc.y)): Die Koordinaten des Mausklicks werden als String gesendet (zwei Ziffern zwischen 0 und 4) | |
def onMessageReceived(msg): Callbackfunktion, die aufgerufen wird, wenn eine Message angekommen ist. Empfangen werden entweder die Strings "hit, "miss" oder die Koordinaten der Zelle | |
x = int(msg[0]), y = int(msg[1]: Das erste Zeichen des msg-Strings ist die x- und das zweite Zeichen die y-Koordinate der getroffenen Zelle. Die Strings müssen mit der Funktion int() in Zahlen konvertiert werden | |
actor = getOneActorAt(loc, Ship) : Nur Actrors der Klasse Ship werden berücksichtigt. Falls sich in der gleichen Zelle eine rote Marke befindet, wird None zurückgegeben |