forked from CoderDojoTC/python-minecraft
-
Notifications
You must be signed in to change notification settings - Fork 1
/
sleepyoz_analogclock.py
executable file
·128 lines (107 loc) · 4.66 KB
/
sleepyoz_analogclock.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
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
#!/usr/bin/env python
"""
Draw an analogue clock into Minecraft.
Use PIL to prepare the bitmaps, then update Minecraft.
SleepyOz: tfptfp(at)gmail.com
2013-02-13
"""
# mcpipy.com retrieved from URL below, written by SleepyOz
# http://www.raspberrypi.org/phpBB3/viewtopic.php?f=32&t=33427
import math
import mcpi.block as block
import mcpi.minecraft as minecraft
from PIL import Image # Remember to "sudo apt-get install python-imaging" to make PIL available.
from PIL import ImageDraw
import time
import server
# Not very good colour names, because they are inverting when displayed.
colour_black = 1
colour_dark = 32
colour_medium = 64
colour_light = 128
colour_white = 192
def clockhand(angle, length):
"""
Calculate the end point for the given vector.
Angle 0 is 12 o'clock, 90 is 3 o'clock.
Based around (32,32) as origin, (0,0) in top left.
"""
radian_angle = math.pi * angle / 180.0
x = 32 + length * math.cos(radian_angle)
y = 32 + length * math.sin(radian_angle)
return [(32,32),(x,y)]
def draw_clock():
"""
Draw an analogue clock face.
In an attempt to improve appearance, the clock is drawn at a higher
resolution then scaled down with anti-aliasing.
"""
now = time.localtime()
bitmap = Image.new("L", (65,65), color=colour_black) # Work with oversized images, and reduce before displaying.
draw = ImageDraw.Draw(bitmap) # An object to draw into.
# Multiple outer rings so something survives the resolution reduction later.
draw.ellipse((1,1,64,64), outline=colour_white) # Face.
draw.ellipse((2,2,63,63), outline=colour_white) # Face.
draw.ellipse((3,3,62,62), outline=colour_white) # Face.
draw.ellipse((4,4,61,61), outline=colour_white) # Face.
# TODO: We could draw numbers or chevrons on the clock face.
# The hands are drawn by converting the time to degrees.
# Note that all the hands move every second, althought the change might be too small to see.
# The hour hand only moves every minute and even that is not visible.
draw.line(clockhand(now.tm_hour * 30 + now.tm_min / 2, 20), fill=colour_white, width=4) # Hour hand.
draw.line(clockhand(now.tm_min * 6 + now.tm_sec / 10, 22), fill=colour_white, width=3) # Minute hand.
draw.line(clockhand(now.tm_sec * 6, 25), fill=colour_white, width=2) # Second hand.
bitmap.thumbnail((32,32), Image.ANTIALIAS) # Reduce resolution to suit the view distance.
return bitmap
class buffer:
"""
Double-buffer a voxel block for Minecraft.
To improve performance, only changes are actually sent to Minecraft.
"""
anchor_position = minecraft.Vec3(0,0,0)
offscreen = None
onscreen = None
def __init__(self, anchor_position):
"""
Set everything up to render the voxels into the world
at the given position.
"""
self.anchor_position = anchor_position
self.onscreen = Image.new("L", (32,32), color=0)
def render(self):
"""
Get a picture of the clock.
"""
self.offscreen = draw_clock()
def flip(self, client):
"""
Put the off-screen buffer onto the screen.
Only send the differences.
Remember the new screen for use during the next flip.
"""
if self.offscreen:
width,height = self.offscreen.size
draw = ImageDraw.Draw(self.onscreen) # So we can remember what we did for next time.
for x in range(0, width - 1):
for z in range(0, height - 1):
dot = self.offscreen.getpixel((x,z))
if self.onscreen.getpixel((x,z)) != dot:
# Change detected.
draw.point((x,z), fill=dot)
# Pick display items that suit the antialiasing.
display = block.SNOW_BLOCK # Very white.
if (dot >= colour_dark+16) and (dot < colour_medium + 16):
display = block.WOOL # Light grey.
elif (dot >= colour_medium + 16) and (dot < colour_light + 16):
display = block.STONE # Medium grey.
elif (dot >= colour_light + 16):
display = block.OBSIDIAN # Blackish.
client.setBlock(self.anchor_position.x + x, self.anchor_position.y, self.anchor_position.z + z, display)
client=minecraft.Minecraft.create(server.address) # Connect to Minecraft.
place=client.player.getPos() # Start near the player.
place.y += 0 # At the level of the player's feet.
bitmapper = buffer(place)
while True:
bitmapper.render()
bitmapper.flip(client)
time.sleep(.1) # Rest a while before drawing again.