Seite 1 von 1
PyProcessign key Problem
Verfasst: Samstag 22. September 2018, 14:59
von yoda
Ich versuche gerade dieses Video
https://www.youtube.com/watch?v=cXgA1d_E-jY&t=750s in Python nachzuprogrammieren. Hier der Code:
Code: Alles auswählen
class Vogel:
schwerkraft = 5 # Kraft, die Vogel runterzieht
lift = -10 # Kraft, die Vogel hochzieht
def __init__(self):
self.y = 500 / 2
self.x = 64
self.geschwindigkeit = 0
def hochfliegen(self):
self.geschwindigkeit += Vogel.lift
def show(self):
fill(255)
ellipse(self.x, self.y, 30, 30)
def update(self):
self.geschwindigkeit += Vogel.schwerkraft
self.geschwindigkeit *= 0.9
self.y += self.geschwindigkeit
if self.y > height:
self.y = height
self.geschwindigkeit = 0
if self.y < 0:
self.y = 0
Code: Alles auswählen
from bird import *
vogel = Vogel()
def setup():
size(500, 500)
def draw():
background(51)
vogel.show()
if key == ' ':
vogel.hochfliegen()
vogel.update()
Leider funktioniert es nicht richtig: Sobald ich die Leertaste drücke, klebt der Kreis am oberen Bildschirmende. Witzigerweise kann ich dann Pfeiltaste nach unten drücken und er fällt wieder herunter (obwohl ich das nirgendwo programmiert habe

). Hat jemand eine Idee, woran es liegen könnte?
Re: PyProcessign key Problem
Verfasst: Samstag 22. September 2018, 15:38
von Sirius3
Du schreibst hier was ab, was auf gruselige Weise globale Variablen mit globalem Bildschirmupdates mischt. So wie das hochfliegen Programmiert ist, wird der Vogel innerhalb von Bruchteilen von Sekunden hunderte Pixel nach oben fliegen.
Re: PyProcessign key Problem
Verfasst: Samstag 22. September 2018, 16:19
von yoda
Das Original (was funktioniert) sieht so aus:
Code: Alles auswählen
function Bird() {
this.y = height/2;
this.x = 64;
this.gravity = 0.7;
this.lift = -12;
this.velocity = 0;
this.show = function() {
fill(255);
ellipse(this.x, this.y, 32, 32);
}
this.up = function() {
this.velocity += this.lift;
}
this.update = function() {
this.velocity += this.gravity;
// this.velocity *= 0.9;
this.y += this.velocity;
if (this.y > height) {
this.y = height;
this.velocity = 0;
}
if (this.y < 0) {
this.y = 0;
this.velocity = 0;
}
}
}
Was habe ich übersehen?
Re: PyProcessign key Problem
Verfasst: Samstag 22. September 2018, 16:24
von Sirius3
Das ist Javascript und in einigen Details anders als Deine Python-Übersetzung.
Re: PyProcessign key Problem
Verfasst: Samstag 22. September 2018, 16:35
von yoda
Das ist mir klar, aber es sollte doch genauso funktionieren, oder?
Re: PyProcessign key Problem
Verfasst: Samstag 22. September 2018, 16:46
von __deets__
Ohne deinen gesamten Code zu sehen, der auch die Ereignisbehandlung macht, ist das schwierig nachzuvollziehen. Und deine Gravitation ist >7 mal staerker als im Original. Last but not least ist der gesamte Code (auch schon aus dem Original) fehlerhaft, da man fuer solche Berechnungen ja mit Werten wie zB 9.81 Metern/*SEKUNDE* arbeitet. Man muss also bei zB 60 Frames die Beschleunigung mit der verflossenen Zeit von ~0.016 Sekunden multiplizieren, bevor man sie auf die Geschwindigkeit addiert. Und genauso die Postion mit einem 60stel der Geschwindigkeit veraendern. Am besten misst man in jedem Frame einfach das Delta zum Frame davor, und gibt diese "elapsed" Zeit in die update-Methoden ein.
Re: PyProcessign key Problem
Verfasst: Samstag 22. September 2018, 17:07
von yoda
@__deets__ ich habe meinen gesamten Code oben gepostet. Mich wundert halt immer noch stark, warum ich den Kreis mit Drücken der Runter-Pfeiltaste nach unten bewegen kann.
Die Zahlen im Original funktionieren aber, daran kann es nicht liegen.
Re: PyProcessign key Problem
Verfasst: Samstag 22. September 2018, 18:52
von __deets__
Das ist der gesamte Code? Interessant. Ich habe mit processing mit Python keine Erfahrung. Das da mit globalen Variablen gearbeitet wird, kann ich mir fast nicht vorstellen. Hast du mal einen Tutorial link? Wenn ich danach suche, komme ich auf viele Dinge, die anders aussehen als das, was du da machst.
Re: PyProcessign key Problem
Verfasst: Samstag 22. September 2018, 19:31
von yoda
Das Video ist wie gesagt von hier:
https://www.youtube.com/watch?v=cXgA1d_E-jY&t=750s. Processing-Infos findest du hier
https://py.processing.org. Processing scheint für Python auch nicht sehr verbreitet zu sein. Ich arbeite nur damit, weil es dazu diese Youtube-Videos gibt (also zu der JavaScript-Version), die es für z.B. Pygame so nicht gibt

Re: PyProcessign key Problem
Verfasst: Samstag 22. September 2018, 19:51
von __deets__
Ok, dann ist dein Problem das hier:
https://py.processing.org/reference/key.html
Es wird dich wahrscheinlich nicht besonders beeindrucken wenn ich das sage, aber dieses Vorgehen, dass da eine globale Variable 'key' existiert, und aus der liest du, da wird mir kotzuebel. Das ist wirklich ganz schlecht gemacht. (um das klarzustellen: dafuer kannst du ja nix, aber das spricht in meinen Augen nicht fuer py-processing...)
Wie dem auch sei: lies dir mal genau durch, was da in der Doku steht, und woher es dann kommt, dass du durch das druecken einer anderen Taste den Kreis wieder runterkommen lassen kannst. Es sollte dabei uebrigens auch voellig egal sein, ob das eine Pfeiltaste ist, oder Q oder W oder was auch immer.
Re: PyProcessign key Problem
Verfasst: Sonntag 23. September 2018, 13:06
von ThomasL
Hallo yoda,
freut mich zu lesen, dass du auch ein Fan von Daniel Shiffman "The Coding Train" bist.
Ich hatte ihn Anfang des Jahres entdeckt und war auch begeistert von seinen Videos die er mit Processing erstellt hat.
Da ich aber nur einige Wochen zuvor mit Python angefangen hatte, wollte ich nicht nach Processing (Java) wechseln.
Hatte dann auch einige Tage mit dem Python Modul für Processing experimentiert aber schnell festgestellt, dass das nicht so das wahre ist.
Stimme da voll und ganz __deets__ zu.
Nun, was blieb mir übrig und das ist das was ich dir von Herzen empfehlen kann: Arbeite dich ein wenig in Pygame ein
und programmiere die Challenges von Daniel in Python nach, es ist nicht schwer und ich habe eine Menge dadurch gelernt.
Natürlich hatte ich auch Flappy Bird nachprogrammiert und um dir zu zeigen, wie sowas aussehen kann, hier mal der Code.
Ist schon einige Monate alt, könnte mir vorstellen, eventuell einige Sachen heute anders zu machen. Man beachte bitte auch meine Signatur!
Code: Alles auswählen
import pygame as pg
import random
from pygame.locals import *
import os
BLACK = [0, 0, 0]
WHITE = [255, 255, 255]
RED = [255, 0, 0]
class Bird:
def __init__(self, canvas):
self.canvas = canvas
self.y = self.canvas.height // 2
self.x = 64
self.gravity = 0.5
self.lift = -10
self.velocity = 0
def show(self):
pg.draw.circle(self.canvas.screen, BLACK, [int(self.x), int(self.y)], 10, 0)
def up(self):
self.velocity += self.lift
def update(self):
self.velocity += self.gravity
self.velocity *= 0.9
self.y += self.velocity
if self.y > self.canvas.height:
self.y = self.canvas.height
self.velocity = 0
if self.y < 0:
self.y = 0
self.velocity = 0
self.y = int(self.y)
class Pipe:
def __init__(self, canvas):
self.canvas = canvas
self.top = random.randint(100, self.canvas.height - 200)
self.bottom = self.top + random.randint(100, 150)
self.x = self.canvas.width + 10
self.w = 20
self.speed = 1
self.highlight = False
def hits(self, bird):
if not self.highlight:
if (bird.y <= self.top) or (bird.y >= self.bottom):
if self.x <= bird.x <= self.x + 1:
self.highlight = True
return True
def show(self):
col = BLACK
if self.highlight:
col = RED
pg.draw.rect(self.canvas.screen, col, [self.x, 0, self.w, self.top], 0)
pg.draw.rect(self.canvas.screen, col, [self.x, self.bottom, self.w, self.canvas.height], 0)
def update(self):
self.x -= self.speed
def offscreen(self):
return self.x < 0 - self.w
class Canvas:
def __init__(self, fullhd=False, width=800, height=800, mode=0):
self.fullhd = fullhd
self.width = width
self.height = height
self.mode = mode
os.environ['SDL_VIDEO_CENTERED'] = '1'
pg.init()
self.clock = pg.time.Clock()
if not self.fullhd:
pg.display.set_caption('Flappy Bird')
# icon_img = pg.image.load_extended('.\\icon.png') # if there´s an icon
# pg.display.set_icon(icon_img)
self.screen = pg.display.set_mode([width, height], mode)
self.screen.fill(WHITE)
pg.display.update()
# pg.key.set_repeat(0) # set key repeat rate
def main():
canvas = Canvas() # windowed mode
# canvas = Canvas(fullhd=True, width=1920, height=1080, mode=FULLSCREEN) # fullscreen mode
# mouse_pos = [0, 0] # not used in this game
bird = Bird(canvas)
pipes = [Pipe(canvas)]
frame_count = 0
pause = main_exit = False
while not main_exit:
canvas.clock.tick(60) # set fps rate
for event in pg.event.get():
if event.type == QUIT:
main_exit = pause = True
break
elif event.type == KEYDOWN:
if event.key == K_ESCAPE:
main_exit = pause = True
if event.key == K_UP or event.key == K_w:
bird.up()
# if event.key == K_DOWN or event.key == K_s:
# pass
# if event.key == K_LEFT or event.key == K_a:
# pass
# if event.key == K_RIGHT or event.key == K_d:
# pass
if event.key == K_p:
pause = not pause # pause the action
# elif event.type == KEYUP:
# pass
# elif event.type == MOUSEMOTION:
# mouse_pos = pg.mouse.get_pos()
# button1, button2, button3 = pg.mouse.get_pressed()
# if button1:
# pass
# if button2:
# pass
# if button3:
# pass
# elif event.type == MOUSEBUTTONDOWN:
# if event.button == 3: # right mouse button
# pass
# if event.button == 4: # mouse scroll up
# pass
# if event.button == 5: # mouse scroll down
# pass
# button1, button2, button3 = pg.mouse.get_pressed()
# if button1:
# pass
# if button2:
# pass
# if button3:
# pass
if not pause:
frame_count += 1
canvas.screen.fill(WHITE) # clear surface
for i in range(len(pipes)):
pipes[i].show()
pipes[i].update()
if pipes[i].hits(bird):
print(" HIT")
if pipes[0].offscreen():
pipes = pipes[1:]
bird.update()
bird.show()
if frame_count % 300 == 0:
pipes.append(Pipe(canvas))
pg.display.update()
pg.quit()
if __name__ == '__main__':
main()
Re: PyProcessign key Problem
Verfasst: Sonntag 23. September 2018, 13:14
von __deets__
@ThomasL: ich weiss, dass das alter Code ist. Trotzdem ein paar Anmerkungen:
- es ist ein beliebter Fehler, die Framerate als konstant anzunehmen. Die Doku sagt das recht klar: tick(fps) beschraenkt die Framerate nach *oben*, nicht aber nach unten. Was ja auch logisch ist. Dann aber will man im Grunde *immer* den Rueckgabewert von tick auswerten, um damit das Delta fuer den naechsten Schritt zu bestimmen.
- dieses Delta muss natuerlich dann in allen updates bezueglich Postion etc. verwandt werden.
Re: PyProcessign key Problem
Verfasst: Sonntag 23. September 2018, 14:35
von ThomasL
__deets__ hat geschrieben: Sonntag 23. September 2018, 13:14
- es ist ein beliebter Fehler, die Framerate als konstant anzunehmen. Die Doku sagt das recht klar: tick(fps) beschraenkt die Framerate nach *oben*, nicht aber nach unten. Was ja auch logisch ist. Dann aber will man im Grunde *immer* den Rueckgabewert von tick auswerten, um damit das Delta fuer den naechsten Schritt zu bestimmen.
- dieses Delta muss natuerlich dann in allen updates bezueglich Postion etc. verwandt werden.
no problem, diese Thematik ist sogar sehr wichtig und durchaus komplex.
Ich hatte auch irgendwann mal im Rahmen dieser "Spielereien" diesen Link hier
http://www.pygame.org/wiki/ConstantGameSpeed gebookmarked,
mich dann aber anderen interessanten Dingen wie Perceptrons in pure Python, dann mit Numpy, dann mit Cython, Pandas, Matplotlib, Scikit-Learn, Tensorflow, Keras beschäftigt.
Ist erst ein paar Monate her aber kommt mir vor, als wenn ich das in meiner Kindheit gemacht hätte.
Naja, softwareentwicklungstechnisch gesehen stimmt das ja.
Re: PyProcessign key Problem
Verfasst: Sonntag 23. September 2018, 16:02
von __blackjack__
@ThomasL: Ein paar Anmerkungen zu dem Quelltext:
In der Hauptfunktion ist das ``for i in range(len(sequence)):``-Anti-Pattern. Man kann da direkt, ohne einen Umweg über einen Index über die `Pipe`-Objekte iterieren.
Vom Datentyp her wäre eine `collections.deque` passender für `pipes`.
Klassen die nur aus einer `__init__()` bestehen sind fast nie wirklich Klassen. Denn selbst Klassen die aus einer `__init__()` und einer zusätzlichen Methode bestehen, sind sehr oft einfach nur umständlich geschriebene Funktionen.
Das betrifft `Canvas`. Da werden zudem alle Argumente der `__init__()` an das Objekt gebunden, obwohl später nur zwei davon tatsächlich benötigt werden.
Man kann die ”Klasse” in einem ersten Schritt durch eine Funktion ersetzen, die ein von `collections.namedtuple` abgeleitetes Objekt zurück gibt das die Attribute `screen`, `width`, `height`, und `clock` besitzt. Wobei ich `clock` da auch gleich heraus nehmen würde, denn das gehört eigentlich nicht zu einer Leinwand und könnte problemlos ein lokaler Name in der Hauptfunktion sein.
Im nächsten Schritt kann man dann auch dieses `namedtuple` loswerden, denn das enthält redundante Daten. `screen` ist ein `Surface` und von diesen Objekten kann man die Höhe und Breite abfragen. Es macht wenig Sinn die gleichen Werte extern noch einmal zu speichern.
`Pipe.hits()` hat inkonsistente Rückgabewerte. Statt `True` und `None` sollte die Methode `True` und `False` liefern.
Die verschachtelten ``if``\s kann man alle zusammenfassen.
``bird.y <= self.top or bird.y >= self.bottom`` hätte ich wahrscheinlich eher als ``not self.top <= bird.y < self.bottom`` ausgedrückt.
Das `fullhd`-Argument ist ein bisschen komisch, denn man kann da `True` angeben, aber trotzdem eine Auflösung die nicht Full-HD ist.
Code: Alles auswählen
#!/usr/bin/env python3
import os
import random
from collections import deque
import pygame as pg
from pygame.locals import *
BLACK = [0, 0, 0]
WHITE = [255, 255, 255]
RED = [255, 0, 0]
def create_canvas(fullhd=False, width=800, height=800, mode=0):
os.environ['SDL_VIDEO_CENTERED'] = '1'
pg.init()
if not fullhd:
pg.display.set_caption('Flappy Bird')
screen = pg.display.set_mode([width, height], mode)
screen.fill(WHITE)
pg.display.update()
return screen
class Bird:
GRAVITY = 0.5
LIFT = -10
def __init__(self, canvas):
self.canvas = canvas
self.y = self.canvas.get_height() // 2
self.x = 64
self.velocity = 0
def show(self):
pg.draw.circle(self.canvas, BLACK, [self.x, self.y], 10, 0)
def up(self):
self.velocity += self.LIFT
def update(self):
self.velocity = (self.velocity + self.GRAVITY) * 0.9
self.y = int(self.y + self.velocity)
if self.y > self.canvas.get_height():
self.y = self.canvas.get_height()
self.velocity = 0
if self.y < 0:
self.y = 0
self.velocity = 0
class Pipe:
WIDTH = 20
SPEED = 1
def __init__(self, canvas):
self.canvas = canvas
self.top = random.randint(100, self.canvas.get_height() - 200)
self.bottom = self.top + random.randint(100, 150)
self.x = self.canvas.get_width() + self.WIDTH // 2
self.highlight = False
def hits(self, bird):
if (
not self.highlight
and not self.top <= bird.y < self.bottom
and self.x <= bird.x <= self.x + 1
):
self.highlight = True
return True
return False
def show(self):
color = RED if self.highlight else BLACK
pg.draw.rect(self.canvas, color, [self.x, 0, self.WIDTH, self.top], 0)
pg.draw.rect(
self.canvas,
color,
[self.x, self.bottom, self.WIDTH, self.canvas.get_height()],
0
)
def update(self):
self.x -= self.SPEED
def is_offscreen(self):
return self.x < -self.WIDTH
def main():
canvas = create_canvas() # windowed mode
# canvas = create_canvas(
# fullhd=True, width=1920, height=1080, mode=FULLSCREEN
# ) # fullscreen mode
bird = Bird(canvas)
pipes = deque([Pipe(canvas)])
clock = pg.time.Clock()
frame_count = 0
pause = main_exit = False
while not main_exit:
clock.tick(60) # set fps rate
for event in pg.event.get():
if event.type == QUIT:
main_exit = pause = True
break
elif event.type == KEYDOWN:
if event.key == K_ESCAPE:
main_exit = pause = True
if event.key == K_UP or event.key == K_w:
bird.up()
if event.key == K_p:
pause = not pause # pause the action
if not pause:
frame_count += 1
canvas.fill(WHITE) # clear surface
for pipe in pipes:
pipe.update()
pipe.show()
if pipe.hits(bird):
print(' HIT')
if pipes[0].is_offscreen():
pipes.popleft()
bird.update()
bird.show()
if frame_count % 300 == 0:
pipes.append(Pipe(canvas))
pg.display.update()
pg.quit()
if __name__ == '__main__':
main()
Re: PyProcessign key Problem
Verfasst: Sonntag 23. September 2018, 16:58
von yoda
Vielen Dank für die zahlreichen Antworten

Ich werde mal in Pygame reinschauen, scheint ja auch gut zu gehen.
Re: PyProcessign key Problem
Verfasst: Sonntag 23. September 2018, 17:50
von yoda
@ThomasL: Ich habe zuerst mit Tensorflow angefangen und beschäftige mich momentan reinforcement learning und würde das gerne mit sowas wie Processing bzw. Pygame anwenden. Falls du (oder andere hier) gute Ressourcen parat haben, die in diese Richtung gehen, würde ich mich freuen

Re: PyProcessign key Problem
Verfasst: Sonntag 23. September 2018, 19:11
von ThomasL
__blackjack__ hat geschrieben: Sonntag 23. September 2018, 16:02
@ThomasL: Ein paar Anmerkungen zu dem Quelltext:
Ich wusste das du ein "paar Anmerkungen" für mich hast. <schmunzel> wie gesagt, Code aus meiner Python "Kindheit".
Re: PyProcessign key Problem
Verfasst: Sonntag 23. September 2018, 19:37
von __blackjack__
Macht ja nix von wann der Code ist, und die Anmerkungen sind ja auch für andere die das hier lesen.

Re: PyProcessign key Problem
Verfasst: Sonntag 23. September 2018, 19:51
von ThomasL