2010-08-04 1 views
7

Я работаю над созданием версии астероидов с использованием Python и Tkinter. Когда нажата клавиша со стрелкой влево или вправо, корабль должен вращаться. Корабль - это треугольник на холсте Ткинтер. У меня возникают проблемы с приложением формулы для корректировки координат для треугольника. Я считаю, что это имеет какое-то отношение к греху и соседу, хотя я не совсем уверен. Пока у меня есть два класса для корабля, а другой для игры. В классе корабля у меня есть методы обратного вызова для нажатия клавиш. Любая помощь будет принята с благодарностью. Благодарю.Как повернуть многоугольник в python на холсте Tkinter?

корабль класса

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

Game Class

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 делает обработку событий. Он был не предназначен для игр, так что вам придется возиться справедливый бит, чтобы получить, что работает должным образом с 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

+1

Вы очень желанны. – JAB

 Смежные вопросы

  • Нет связанных вопросов^_^