2010-08-04 4 views
7

Ich arbeite daran, eine Version von Asteroiden mit Python und Tkinter zu erstellen. Wenn die linke oder rechte Pfeiltaste gedrückt wird, muss sich das Schiff drehen. Das Schiff ist ein Dreieck auf der Tkinter-Leinwand. Ich habe Probleme mit der Formel, um die Koordinaten für das Dreieck anzupassen. Ich glaube, es hat etwas mit Sünde und Sünde zu tun, obwohl ich mir nicht ganz sicher bin. Bisher habe ich zwei Klassen, eins für das Schiff und das andere für das Spiel. In der Schiffsklasse habe ich Callback-Methoden für die Tastendrücke. Jede Hilfe würde sehr geschätzt werden. Vielen Dank.Wie drehe ich ein Polygon in Python auf einem Tkinter Canvas?

Schiffsklasse

import math 
class Ship: 
    def __init__(self,canvas,x,y,width,height): 
     self.canvas = canvas 
     self.x = x - width/2 
     self.y = y + height/2 
     self.width = width 
     self.height = height 

     self.x0 = self.x 
     self.y0 = self.y 

     self.x1 = self.x0 + self.width/2 
     self.y1 = self.y0-self.height 

     self.x2 = self.x0 + self.width 
     self.y2 = self.y0 

     self.ship = self.canvas.create_polygon((self.x0, self.y0, self.x1, self.y1, self.x2, self.y2), outline="white", width=3) 
    def changeCoords(self): 
     self.canvas.coords(self.ship,self.x0, self.y0, self.x1, self.y1, self.x2, self.y2) 
    def rotateLeft(self, event=None): 
     # Should rotate one degree left. 
     pass 
    def rotateRight(self, event=None): 
     # Should rotate one degree right. 
     self.x0 = self.x0 -1 
     self.y0 = self.y0 - 1 

     self.x1 = self.x1 + 1 
     self.y1 = self.y1 + 1 

     self.x2 = self.x2 - 1 
     self.y2 = self.y2 + 1 
     self.changeCoords() 

Spielklasse

from Tkinter import * 
from ship import * 


class Game: 
    def __init__(self, gameWidth, gameHeight): 
     self.root = Tk() 
     self.gameWidth = gameWidth 
     self.gameHeight = gameHeight 
     self.gameWindow() 

     self.ship = Ship(self.canvas, x=self.gameWidth/2,y=self.gameHeight/2, width=50, height=50) 
     self.root.bind('<Left>', self.ship.rotateLeft) 
     self.root.bind('<Right>', self.ship.rotateRight) 

     self.root.mainloop() 

    def gameWindow(self): 
     self.frame = Frame(self.root) 
     self.frame.pack(fill=BOTH, expand=YES) 

     self.canvas = Canvas(self.frame,width=self.gameWidth, height=self.gameHeight, bg="black", takefocus=1) 
     self.canvas.pack(fill=BOTH, expand=YES)  

asteroids = Game(600,600) 

Antwort

9

Zunächst einmal müssen Sie um ein Zentrum des Dreiecks drehen. Der Schwerpunkt würde wahrscheinlich am besten dafür geeignet sein. Um das herauszufinden, können Sie die Formel C = (1/3*(x0 + x1 + x2), 1/3*(y0 + y1 + y2)) verwenden, da dies der Durchschnitt aller Punkte im Dreieck ist. Dann müssen Sie die Rotation mit diesem Punkt als Mittelpunkt anwenden. Also würde es so etwas wie dieses ...

import math 

class Ship: 
    def centroid(self): 
     return 1/3 * (self.x0 + self.x1 + self.x2), 1/3 * (self.y0 + self.y1 + self.y2) 

    def __init__(self, canvas, x, y, width, height, turnspeed, acceleration=1): 
     self._d = {'Up':1, 'Down':-1, 'Left':1, 'Right':-1} 

     self.canvas = canvas 
     self.width = width 
     self.height = height 
     self.speed = 0 
     self.turnspeed = turnspeed 
     self.acceleration = acceleration 

     self.x0, self.y0 = x, y 

     self.bearing = -math.pi/2 

     self.x1 = self.x0 + self.width/2 
     self.y1 = self.y0 - self.height 

     self.x2 = self.x0 + self.width 
     self.y2 = self.y0 

     self.x, self.y = self.centroid() 

     self.ship = self.canvas.create_polygon((self.x0, self.y0, self.x1, self.y1, self.x2, self.y2), outline="white", width=3) 

    def changeCoords(self): 
     self.canvas.coords(self.ship,self.x0, self.y0, self.x1, self.y1, self.x2, self.y2) 

    def rotate(self, event=None): 
     t = self._d[event.keysym] * self.turnspeed * math.pi/180 # the trig functions generally take radians as their arguments rather than degrees; pi/180 radians is equal to 1 degree 

     self.bearing -= t 

     def _rot(x, y): 
      #note: the rotation is done in the opposite fashion from for a right-handed coordinate system due to the left-handedness of computer coordinates 
      x -= self.x 
      y -= self.y 
      _x = x * math.cos(t) + y * math.sin(t) 
      _y = -x * math.sin(t) + y * math.cos(t) 
      return _x + self.x, _y + self.y 

     self.x0, self.y0 = _rot(self.x0, self.y0) 
     self.x1, self.y1 = _rot(self.x1, self.y1) 
     self.x2, self.y2 = _rot(self.x2, self.y2) 
     self.x, self.y = self.centroid() 

     self.changeCoords() 

    def accel(self, event=None): 
     mh = int(self.canvas['height']) 
     mw = int(self.canvas['width']) 
     self.speed += self.acceleration * self._d[event.keysym] 

     self.x0 += self.speed * math.cos(self.bearing) 
     self.x1 += self.speed * math.cos(self.bearing) 
     self.x2 += self.speed * math.cos(self.bearing) 

     self.y0 += self.speed * math.sin(self.bearing) 
     self.y1 += self.speed * math.sin(self.bearing) 
     self.y2 += self.speed * math.sin(self.bearing) 

     self.x, self.y = self.centroid() 

     if self.y < - self.height/2: 
      self.y0 += mh 
      self.y1 += mh 
      self.y2 += mh 
     elif self.y > mh + self.height/2: 
      self.y0 += mh 
      self.y1 += mh 
      self.y2 += mh 

     if self.x < -self.width/2: 
      self.x0 += mw 
      self.x1 += mw 
      self.x2 += mw 
     elif self.x > mw + self.width/2: 
      self.x0 -= mw 
      self.x1 -= mw 
      self.x2 -= mw 

     self.x, self.y = self.centroid() 

     self.changeCoords() 

Ich habe einige Änderungen an den Kontrollen, die das Spiel ein bisschen mehr wie Asteroids machen, nebenbei bemerkt. (Ich habe zwar nicht gefeuert, aber vielleicht habe ich mehr davon gelernt, als ich erwartet hatte, aber ich werde nicht alles tun. Außerdem gibt es ein kleines Problem, wenn Sie versuchen, mehrere Bewegungstasten gleichzeitig zu benutzen, aber das ist aufgrund der Art und Weise Tk ist die Ereignisbehandlung. Es ist nicht für Spiele entwickelt wurde, so dass Sie ein gutes Stück hantieren müßten zu bekommen, dass richtig mit Tk/Tkinter arbeiten.)

from tkinter import * 
from ship import * 

class Game: 
    def __init__(self, gameWidth, gameHeight): 
     self.root = Tk() 
     self.gameWidth = gameWidth 
     self.gameHeight = gameHeight 
     self.gameWindow() 

     self.ship = Ship(self.canvas, x=self.gameWidth/2,y=self.gameHeight/2, width=50, height=50, turnspeed=10, acceleration=5) 
     self.root.bind('<Left>', self.ship.rotate) 
     self.root.bind('<Right>', self.ship.rotate) 
     self.root.bind('<Up>', self.ship.accel) 
     self.root.bind('<Down>', self.ship.accel) 

     self.root.mainloop() 

    def gameWindow(self): 
     self.frame = Frame(self.root) 
     self.frame.pack(fill=BOTH, expand=YES) 

     self.canvas = Canvas(self.frame,width=self.gameWidth, height=self.gameHeight, bg="black", takefocus=1) 
     self.canvas.pack(fill=BOTH, expand=YES)  

asteroids = Game(600,600) 

Als Neben Vielleicht möchten Sie Eigenschaften verwenden, um eine einfachere Handhabung der Punkte und dergleichen zu ermöglichen.

+2

Vielen Dank für die Hilfe. Du bist ein Gelehrter und ein Gentleman. Genau das habe ich gesucht. – Sam

+1

Sie sind herzlich willkommen. – JAB