2010-08-04 227 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