更优雅点的方法,3D to 2D 投影

代码:
import wx
import random
# Formula Reference: http://membres.multimania.fr/amycode.../3dbasics.html
class Star:
    def __init__(self, starfield):
        self.starfield = starfield
        self.reset()
    def color(self):
        r = 1-self.z/self.starfield.max_z
        return (255*r, 255*r, 255*r)
    def project(self):
        sf = self.starfield
        return (self.x*sf.project_z/self.z+sf.offset_x,
                self.y*sf.project_z/self.z+sf.offset_y,)
    def reset(self):
        sf = self.starfield
        rand = random.random
        self.x = (rand()-0.5)*sf.radius
        self.y = (rand()-0.5)*sf.radius
        self.z = (rand()*sf.max_z)
        self.speed = rand()*sf.max_speed
    def move(self):
        self.z -= self.speed
        if self.z <= 0:
            self.reset()
class Starfield(list):
    def __init__(self, size, count=1000):
        self.width, self.height = size
        self.offset_x = self.width/2
        self.offset_y = self.height/2
        self.project_z = 512 # increase this Z offset to see more closer
        self.max_z = 1024
        self.max_speed = 20
        self.radius = max(self.width, self.height)
        list.__init__(self, [Star(self) for i in range(count)])
class AboutFrame(wx.Frame):
    def __init__(self):
        wx.Frame.__init__(self, None, title='for those years, for those people', size=(800, 600))
        self.starfield = Starfield(self.GetClientSize())
        self.Bind(wx.EVT_PAINT, self.OnPaint)        
        self.timer = wx.Timer(self)
        self.Bind(wx.EVT_TIMER, self.OnTimer, self.timer)        
        self.timer.Start(1000/30)#30FPS
        self.Center()
    def Draw(self, dc):
        dc.SetBackground(wx.Brush('black'))
        dc.Clear()
        
        for star in self.starfield:
            dc.SetPen(wx.Pen(star.color()))            
            dc.DrawPoint(*star.project())
            star.move()
            
    def OnTimer(self, evt):
        dc = wx.BufferedDC(wx.ClientDC(self))
        self.Draw(dc)
    def OnPaint(self, evt):
        dc = wx.BufferedPaintDC(self)
        self.Draw(dc)
if __name__ == '__main__':
    app = wx.App(redirect=False)
    AboutFrame().Show()
    app.MainLoop()