# Kanonenschuß (schiefer Wurf) # see https://en.wikipedia.org/wiki/Projectile_motion # https://de.wikipedia.org/wiki/Wurfparabel#/media/Datei:Wurfparabel_Zusammenfassung_aktualisierung.png # inspired by "Physics for Game Prgrammers, by Grant Palmer, Apress # source code in c: https://github.com/Apress/physics-for-game-programmers/blob/master/Code/C_Code/Chapter03_Newtonian/GravityGame.c import math import random import turtle bildschirm = turtle.Screen() bildschirm.title('Kanone version 3') breite, höhe = 1200, 800 welt_breite = 35_000 welt_höhe = welt_breite/2 bildschirm.setup(breite, höhe) bildschirm.setworldcoordinates(0,0,welt_breite, welt_höhe) # ursprung links unten schreiber = turtle.Turtle() schreiber.penup() schreiber.speed(0) schreiber.goto(breite/2, höhe/2) schreiber.hideturtle() logschreiber = turtle.Turtle() logschreiber.speed(0) logschreiber.penup() gitter = turtle.Turtle() gitter.penup() gitter.hideturtle() kanone = turtle.Turtle() kanone.shape("triangle") kanone.shapesize(2,5) kanone.color("brown") kanone.penup() ball = turtle.Turtle() ball.shape("circle") ball.color("blue") ball.penup() ziel = turtle.Turtle() ziel.shape("square") ziel.color("red","red") ziel.penup() kanone_y = random.uniform(0, welt_höhe/2) # y-position der Kanone in Metern kanone_x = 0 # x-position der Kanone in Metern ziel_y = random.uniform(0, welt_höhe/2) # y-position des Ziels in Metern # x-position des Ziels in Metern. (5 km bis 30 km entfernt) ziel_x = random.uniform(welt_breite/2, welt_breite) dx = kanone_x-ziel_x # delta_x, die Differenz der X-Koordinaten dy = kanone_y-ziel_y # delta_y, die Differenz der Y-Koordinaten distanz = (dx**2+dy**2)**0.5 # pythagoras: a²+b²=c² gravitation = -9.81 # Erdbeschleunigung dt = 0.1 # rechne position für jede Zehntelsekunde ball_x,ball_y = 0, 0 # position vom ball. x=0; y=0 kritische_distanz = 0.5 # wie nahe am Zeil der Ball landen muss game_over = False # turtles an korrekte Position bewegen kanone.goto(kanone_x, kanone_y) ziel.goto(ziel_x, ziel_y) ball.goto(kanone_x, kanone_y) schreiber.goto(welt_breite/7 * 4.5, welt_höhe / 5 * 4) schreiber.pencolor("green") schreiber.write(f"Position der Kanone: x:{kanone_x:5.1f}, y:{kanone_y:5.1f} [m]", align="left", font=("Mono", 12, "normal")) schreiber.goto(schreiber.xcor(), schreiber.ycor()- welt_höhe/10) schreiber.write(f"Position des Ziels: x:{ziel_x:5.1f}, y:{ziel_y:5.1f} [m]", align="left", font=("Mono", 12, "normal")) schreiber.goto(schreiber.xcor(), schreiber.ycor()-welt_höhe/10) schreiber.write(f"Distanz (Luftlinie): {distanz/1_000:8.1f} [km]", align="left", font=("Mono", 12, "normal")) vorschlag_g = 200 vorschlag_w = 33 versuch = 0 logbuch = [] while not game_over: t = 0.0 # Zeitpunkt 0 ball_x = kanone_x # ball zur Kanone zurücksetzen ball_y = kanone_y ball.goto(ball_x,ball_y) ball.pendown() versuch += 1 # Versuch um 1 erhöhen titeltext = f"Versuch: {versuch}" geschwindigkeit = turtle.numinput( title=titeltext, prompt="Abschußgeschwindigkeit in [m/s] >>>", default = vorschlag_g, minval = 0, maxval = 10000000000, ) winkel = turtle.numinput( title=titeltext, prompt = "Abschußwinkel in ° >>>", default = vorschlag_w, minval = 0, maxval = 90, ) kanone.setheading(winkel) # Spieler mag aufhören? if (geschwindigkeit == 0) and (winkel == 0): break # alte Werte als Vorschlag speichern vorschlag_g = geschwindigkeit vorschlag_w = winkel # v0 (Abschußgeschwindigkeit zum Zeitpunkt 0) für x und y ausrechnen winkel_in_radians = math.radians(winkel) vx0 = math.cos(winkel_in_radians) * geschwindigkeit vy0 = math.sin(winkel_in_radians) * geschwindigkeit #print("zeit (sek) | ball x | ball y | Distanz zu Ziel") #print("-----------+-----------+----------|----------------") ball.clear() # alte ballspur löschen while ball_y >= min(kanone_y, ziel_y): # Schleife mit Abbruchbedingung ball_x = kanone_x + vx0 * t # konstante Horziontal-Geschwindigkeit ball_y = kanone_y + vy0 * t + gravitation / 2 * t * t # variable Vertikal-Geschwindigkeit ball.goto(ball_x, ball_y) dx = ball_x-ziel_x # delta_x, die Differenz der X-Koordinaten dy = ball_y-ziel_y # delta_y, die Differenz der Y-Koordinaten distanz = (dx**2+dy**2)**0.5 # pythagoras: a²+b²=c² #print(f" {t:8.1f} | {ball_x:8.1f} | {ball_y:8.1f} | {distanz:8.1f} ") if distanz <= kritische_distanz: schreiber.goto(breite/2, höhe/2) schreiber.write("Treffer!", align="center", font=("System",64,"normal")) game_over = True break if ball_x > welt_breite: break t += dt # nächster Zeitpunkt ball.penup() if ball_x < ziel_x: adjektiv = "kurz" else: adjektiv = "weit" text = f"Versuch #{versuch}: winkel: {winkel} geschw.: {geschwindigkeit} " text += f"Resultat: {distanz:8.1f} Meter zu {adjektiv} geschossen" logbuch.append(text) logschreiber.clear() # alles löschen # schreibe die letzten 20 Einträge vom logbuch von oben nach unten for i in range(-20,0): try: # versuchs... zeile = logbuch[i] # schauen ob es diesen Eintrag gibt except IndexError: # falls nicht... continue # weitermachen mit nächstem i logschreiber.goto(10, welt_höhe/20 * -i) logschreiber.write(zeile, align="left", font=("System",12,"normal")) turtle.exitonclick() print("Danke fürs spielen. Du hattest {versuch} Versuche") # Ende der Schleife