002.03 Tkinter 星空漫遊範例

Jason990420發表於2019-08-30

主題: 002.03 Tkinter星空漫遊範例

建檔日期: 2019/08/30
更新日期: None
語言: Python 3.7.4, tkinter 8.6
系統: Win10 Ver. 10.0.17763

002.03 Tkinter星空漫遊範例

看到書上介紹有關星際大戰的遊戲, 自己也想來寫一個. 第一件事情想到的就是加上一個背景, 而且是動態的星空背景, 順手寫了一個程式, 發上來供大夥參考.

主要內容如下:

1. Tkinter的Canvas畫布及畫圓部件的使用

2. 星空中三維空間的座標轉換為螢幕的二維空間座標

3. 定時器定時觸發, 宇宙飛船前進, 星球位置及大小的改變

輸出畫面

002.03 Tkinter星空漫遊範例

程式程式碼

'''
星際漫遊 - 模擬在星空中前近, 大小星球在螢幕中接近及離去, 可作為遊戲背景
'''
from tkinter import *
from math import sqrt
import random

def cal(point):

    # 計算星空中的座標在螢幕中投影的座標
    delta = point[0] - here
    if delta==0:
        return [-1, -1, 1, 0, 0]
    x = point[1]/delta  # x座標
    y = point[2]/delta  # y座標
    r = point[3]/delta  # 星球半徑
    return [x, y, r]

def display_all(widget, star):

    # 更新星球的位置及大小
    # 遠的星球放在畫布最底層
    star = sorted(star, reverse=False, key=lambda k:k[0]**2+k[1]**2+k[2]**2)
    for i in range(stars):
        star[i][4]=i+1

    for i in range(stars):
        position = cal(star[i])
        x0 = position[0] - position[2] + width/2
        y0 = position[1] - position[2] + height/2
        x1 = position[0] + position[2] + width/2
        y1 = position[1] + position[2] + height/2
        widget.coords(star[i][4], x0, y0, x1, y1)

def process():

    # 每一次更新所有的星球位置及大小
    global here
    here += step
    for i in range(stars):
        while True:

            position = cal(star[i])
            #超出螢幕, 改成新星球, 座標及半徑都更新
            if (0 <= position[0]+width/2  < width and
                0 <= position[1]+height/2 < height and star[i][0]>here):
                break
            else:
                star[i][0] = random.randint(x_far, 2*x_far)+here
                star[i][1] = random.randint(-y_far, y_far)
                star[i][2] = random.randint(-z_far, z_far)
                star[i][3] = random.randint(min_r, max_r)

    display_all(canvas, star)

def threaded():
    # 每0.1秒更新一次
    process()
    root.after(100,threaded)

width = 1536            #螢幕寛度
height = 800            #螢幕高度

step = 1                # 前進速度
min_r = 1               # 最小星球半徑
max_r = 200             # 最大星球半徑
stars = 1000            # 全部星球數量
x_far = 100             # 星空中最大X軸距離
y_far = width/2*x_far   # 星空中最大Y軸距離
z_far = height/2*x_far  # 星空中最大Z軸離離
here = 0                # 目前航天員X軸位置為0, 螢幕在X軸1的位置
x_center = int(width/2) # 螢幕中心X座標
y_center = int(height/2)# 螢幕中心Y座標
star = [[0,0,0,0,0] for i in range(stars)]  # 星球資料[x,y,z,r,部件ID]

root = Tk()
canvas = Canvas(root, width=width, height=height, bg='black')
canvas.pack()

for i in range(stars):  # 建立所有的星球部件

    position = cal(star[i])
    x0 = position[0] - position[2] + width/2
    y0 = position[1] - position[2] + height/2
    x1 = position[0] + position[2] + width/2
    y1 = position[1] + position[2] + height/2

    star[i][4] = canvas.create_oval(x0, y0, x1, y1, fill='white')

# root.bind('<KeyPress>', process)
root.resizable(0, 0)    # 設定視窗為固定大小, 不可改變
threaded()              # 定時起動航天員前進

root.mainloop()
本作品採用《CC 協議》,轉載必須註明作者和本文連結
Jason Yang

相關文章