-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathterrain.py
89 lines (74 loc) · 2.58 KB
/
terrain.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
# A simple Python port of VoxelSpace by Sebastian Macke
# Autor: Peter Sovietov
import json
import gzip
import tkinter as tk
SCREEN_WIDTH = 320
SCREEN_HEIGHT = 200
BACK_COLOR = (153, 204, 255)
def to_ppm(array, width, height):
return bytes("P6\n%d %d\n255\n" % (width, height), "ascii") + array
def load_data():
with gzip.GzipFile("c1w.json.gz", "rb") as f:
colors = json.loads(f.read().decode())
with gzip.GzipFile("d1.json.gz", "rb") as f:
heights = json.loads(f.read().decode())
return colors, heights
def draw_vline(screen, x, y1, y2, color):
r, g, b = color
y1 = 3 * (max(y1, 0) * SCREEN_WIDTH + x)
y2 = 3 * (min(y2, SCREEN_HEIGHT) * SCREEN_WIDTH + x)
for y in range(y1, y2, 3 * SCREEN_WIDTH):
screen[y] = r
screen[y + 1] = g
screen[y + 2] = b
class Terrain:
def __init__(self, widget):
self.player_x = 0
self.player_y = 0
self.height = 70
self.horizon = 70
self.scale_height = 100
self.distance = 800
self.colors, self.heights = load_data()
self.heights = [SCREEN_HEIGHT - x for x in self.heights]
self.background = bytearray(BACK_COLOR * SCREEN_WIDTH * SCREEN_HEIGHT)
self.screen = self.background[:]
self.ybuffer = [SCREEN_HEIGHT for i in range(SCREEN_WIDTH)]
self.widget = widget
def render(self):
ybuf = self.ybuffer[:]
z = 1
dz = 1
while z < self.distance:
left_x = self.player_x - z
left_y = self.player_y + z
right_x = self.player_x + z
right_y = self.player_y - z
dx = (right_x - left_x) / SCREEN_WIDTH
scale = self.scale_height / z
offs_y = 1024 * (int(left_y) % 1024)
for i in range(SCREEN_WIDTH):
offs = offs_y + int(left_x) % 1024
h = int(self.heights[offs] * scale) + self.horizon
if h < ybuf[i]:
draw_vline(self.screen, i, h, ybuf[i], self.colors[offs])
ybuf[i] = h
left_x += dx
z += dz
dz += 0.02
def update_screen(self):
self.screen[:] = self.background
self.render()
self.player_y += 8
data = to_ppm(self.screen, SCREEN_WIDTH, SCREEN_HEIGHT)
image = tk.PhotoImage(data=data).zoom(2, 2)
self.widget.config(image=image)
self.widget.image = image
Root.after(10, self.update_screen)
Root = tk.Tk()
label = tk.Label()
label.pack()
terrain = Terrain(label)
Root.after(0, terrain.update_screen)
tk.mainloop()