2010-08-04 64 views
7

我正在努力創建一個使用Python和Tkinter的小行星版本。當按下左或右箭頭鍵時,船隻需要旋轉。這艘船是Tkinter帆布上的一個三角形。我無法提出公式來調整三角形的座標。我相信這與罪與cos有關,儘管我並不確定。到目前爲止,我有兩個班,一個是船,另一個是遊戲。在船上我有按鍵的回調方法。任何幫助將不勝感激。謝謝。如何在Tkinter Canvas上的python中旋轉多邊形?

船級

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() 

遊戲類

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) 

回答

9

首先,你需要圍成的三角形的中心旋轉。該質心可能最適合這一點。要找到它,可以使用公式C = (1/3*(x0 + x1 + x2), 1/3*(y0 + y1 + y2)),因爲它是三角形中所有點的平均值。然後,您必須將該點的旋轉作爲中心。所以它會是這樣的......

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() 

我做了一些修改,使遊戲更有點像小行星的控制,順便說一句。 (雖然沒有實施解僱,但我可能已經比我預想的更多了,但我不會去做所有事情,而且,當您嘗試同時使用多個移動鍵時會出現一些問題,但是,這是由於傳統知識沒有事件處理。它不是專爲遊戲的方式,讓你不得不反覆折騰一個公平一點,以獲得與TK/Tkinter的正常工作。)

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) 

順便說一句,你可能想使用屬性來更容易處理點等。

+2

非常感謝您的幫助。你是一個學者和紳士。這正是我所期待的。 – Sam 2010-08-05 00:59:43

+1

你很受歡迎。 – JAB 2010-08-05 13:34:32