├── miku.png ├── SAMPLE_FOLDER ├── 35-0.bmp ├── 35-2.bmp ├── 35-3.bmp ├── 35-5.bmp ├── 35-6.bmp ├── 35-8.bmp ├── 35-9.bmp ├── 159-0.bmp ├── 159-1.bmp ├── 159-10.bmp ├── 159-11.bmp ├── 159-12.bmp ├── 159-13.bmp ├── 159-14.bmp ├── 159-2.bmp ├── 159-3.bmp ├── 159-5.bmp ├── 159-6.bmp ├── 159-7.bmp ├── 159-8.bmp ├── 159-9.bmp ├── 35-10.bmp └── 35-11.bmp ├── README.md ├── test_mcpi.py ├── LICENSE └── miku.py /miku.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/3150601355/python_control_mc/HEAD/miku.png -------------------------------------------------------------------------------- /SAMPLE_FOLDER/35-0.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/3150601355/python_control_mc/HEAD/SAMPLE_FOLDER/35-0.bmp -------------------------------------------------------------------------------- /SAMPLE_FOLDER/35-2.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/3150601355/python_control_mc/HEAD/SAMPLE_FOLDER/35-2.bmp -------------------------------------------------------------------------------- /SAMPLE_FOLDER/35-3.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/3150601355/python_control_mc/HEAD/SAMPLE_FOLDER/35-3.bmp -------------------------------------------------------------------------------- /SAMPLE_FOLDER/35-5.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/3150601355/python_control_mc/HEAD/SAMPLE_FOLDER/35-5.bmp -------------------------------------------------------------------------------- /SAMPLE_FOLDER/35-6.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/3150601355/python_control_mc/HEAD/SAMPLE_FOLDER/35-6.bmp -------------------------------------------------------------------------------- /SAMPLE_FOLDER/35-8.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/3150601355/python_control_mc/HEAD/SAMPLE_FOLDER/35-8.bmp -------------------------------------------------------------------------------- /SAMPLE_FOLDER/35-9.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/3150601355/python_control_mc/HEAD/SAMPLE_FOLDER/35-9.bmp -------------------------------------------------------------------------------- /SAMPLE_FOLDER/159-0.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/3150601355/python_control_mc/HEAD/SAMPLE_FOLDER/159-0.bmp -------------------------------------------------------------------------------- /SAMPLE_FOLDER/159-1.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/3150601355/python_control_mc/HEAD/SAMPLE_FOLDER/159-1.bmp -------------------------------------------------------------------------------- /SAMPLE_FOLDER/159-10.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/3150601355/python_control_mc/HEAD/SAMPLE_FOLDER/159-10.bmp -------------------------------------------------------------------------------- /SAMPLE_FOLDER/159-11.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/3150601355/python_control_mc/HEAD/SAMPLE_FOLDER/159-11.bmp -------------------------------------------------------------------------------- /SAMPLE_FOLDER/159-12.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/3150601355/python_control_mc/HEAD/SAMPLE_FOLDER/159-12.bmp -------------------------------------------------------------------------------- /SAMPLE_FOLDER/159-13.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/3150601355/python_control_mc/HEAD/SAMPLE_FOLDER/159-13.bmp -------------------------------------------------------------------------------- /SAMPLE_FOLDER/159-14.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/3150601355/python_control_mc/HEAD/SAMPLE_FOLDER/159-14.bmp -------------------------------------------------------------------------------- /SAMPLE_FOLDER/159-2.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/3150601355/python_control_mc/HEAD/SAMPLE_FOLDER/159-2.bmp -------------------------------------------------------------------------------- /SAMPLE_FOLDER/159-3.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/3150601355/python_control_mc/HEAD/SAMPLE_FOLDER/159-3.bmp -------------------------------------------------------------------------------- /SAMPLE_FOLDER/159-5.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/3150601355/python_control_mc/HEAD/SAMPLE_FOLDER/159-5.bmp -------------------------------------------------------------------------------- /SAMPLE_FOLDER/159-6.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/3150601355/python_control_mc/HEAD/SAMPLE_FOLDER/159-6.bmp -------------------------------------------------------------------------------- /SAMPLE_FOLDER/159-7.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/3150601355/python_control_mc/HEAD/SAMPLE_FOLDER/159-7.bmp -------------------------------------------------------------------------------- /SAMPLE_FOLDER/159-8.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/3150601355/python_control_mc/HEAD/SAMPLE_FOLDER/159-8.bmp -------------------------------------------------------------------------------- /SAMPLE_FOLDER/159-9.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/3150601355/python_control_mc/HEAD/SAMPLE_FOLDER/159-9.bmp -------------------------------------------------------------------------------- /SAMPLE_FOLDER/35-10.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/3150601355/python_control_mc/HEAD/SAMPLE_FOLDER/35-10.bmp -------------------------------------------------------------------------------- /SAMPLE_FOLDER/35-11.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/3150601355/python_control_mc/HEAD/SAMPLE_FOLDER/35-11.bmp -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # python_control_mc 2 | 用python控制mc里的方块 3 | 4 | 这是教程里用的示例代码。视频教程: 5 | https://www.bilibili.com/video/BV1FG4y1X7SQ/ 6 | -------------------------------------------------------------------------------- /test_mcpi.py: -------------------------------------------------------------------------------- 1 | from mcpi.minecraft import Minecraft 2 | import mcpi.block as block 3 | import time 4 | 5 | if __name__ == '__main__': 6 | # 给点时间切换到mc窗口 方便观察 7 | time.sleep(3) 8 | 9 | # 连接到MC 10 | mc = Minecraft.create() 11 | 12 | # 得到角色当前的位置 13 | x, y, z = mc.player.getTilePos() 14 | 15 | for i in range(8): 16 | for j in range(8): 17 | for k in range(8): 18 | mc.setBlock(x+3+j, y+k, z+i, 35, i) 19 | time.sleep(0.01) -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2023 偶尔有点小迷糊 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /miku.py: -------------------------------------------------------------------------------- 1 | import os 2 | import sys 3 | import time 4 | import math 5 | from PIL import Image 6 | 7 | 8 | from mcpi.minecraft import Minecraft 9 | import mcpi.block as block 10 | 11 | ############################ 12 | # 以下变量和每次具体任务有关 13 | 14 | SAMPLE_FOLDER = "SAMPLE_FOLDER" # 用来采样颜色的图片 15 | dictSampleColor = dict() # (r,g,b) as key, int as value 16 | dictColor256ToMaterail = dict() 17 | 18 | # 读取全部图片,生成颜色查找表 19 | def loadColorMap(folderPath): 20 | lstFileName = os.listdir(folderPath) 21 | 22 | for fileName in lstFileName: 23 | fullPath = os.path.join(folderPath, fileName) 24 | if os.path.isfile(fullPath): 25 | _loadFile(fullPath) 26 | 27 | # 对256色中的每一种,指定一个材质 28 | # 256色模式: 共8 bits (R: 3 bits; G: 3 bits; B: 2 bits)。 29 | for r in range(8): 30 | for g in range(8): 31 | for b in range(4): 32 | value = _findNearestByRgb(r, g, b) 33 | key = (r, g, b) 34 | dictColor256ToMaterail.update({key : value}) 35 | 36 | 37 | def _loadFile(fullPath): 38 | im = Image.open(fullPath) 39 | 40 | # 计算key值(r,g,b) 41 | r, g, b = _calAverageRgb(im) 42 | r >>= 5; g >>= 5; b >>=6 43 | 44 | # 文件名中包含id和序号,如 35-2 45 | fileName = fullPath.split(os.sep)[-1][:-4] 46 | 47 | # 改为turtle (35,2)的形式 48 | arr = fileName.split('-') 49 | tt = ( int(arr[0]), int(arr[1]) ) 50 | 51 | #放入词典,样式:{(r, g, b), (材质ID, 子材质序号)} 52 | dictSampleColor.update({(r, g, b): tt}) 53 | 54 | 55 | # (LAB颜色空间) 56 | def _colorDistance(rgb1, rgb2): 57 | R_1,G_1,B_1 = rgb1 58 | R_2,G_2,B_2 = rgb2 59 | rmean = (R_1+R_2)/2 60 | R = R_1-R_2 61 | G = G_1-G_2 62 | B = B_1-B_2 63 | 64 | return math.sqrt((2+rmean/256)*(R**2)+4*(G**2)+(2+(255-rmean)/256)*(B**2)) 65 | 66 | 67 | # 计算平均rgb值 68 | def _calAverageRgb(im): 69 | if im.mode != "RGB": 70 | im = im.convert("RGB") 71 | 72 | pix = im.load() 73 | avgR, avgG, avgB = 0, 0, 0 74 | n = 1 75 | for i in range(im.size[0]): 76 | for j in range(im.size[1]): 77 | r, g, b = pix[i, j] 78 | avgR += r 79 | avgG += g 80 | avgB += b 81 | n += 1 82 | 83 | return (avgR//n, avgG//n, avgB//n) 84 | 85 | 86 | # 获取颜色最接近的方块 87 | def _findNearestByRgb(r, g, b): 88 | minError = 3*255*255 # 初值为最大误差 89 | k = "" 90 | for key in dictSampleColor.keys(): 91 | R, G, B = key 92 | # 计算颜色误差,用平方差的和来表示。其实用HSV色系更好,但是考虑到MC只有16色,还要啥自行车啊 93 | cur_dif = _colorDistance( (r,g,b), (R,G,B) ) 94 | if cur_dif < minError: 95 | minError = cur_dif 96 | k = key 97 | 98 | return dictSampleColor[k] 99 | 100 | 101 | def init(): 102 | global mc, x, y, z 103 | 104 | print('加载颜色样图...') 105 | loadColorMap(SAMPLE_FOLDER) 106 | 107 | print('连接MC...') 108 | mc = Minecraft.create() 109 | x, y, z = mc.player.getTilePos() 110 | 111 | 112 | def drawFrame(img): 113 | imgW, imgH = img.size 114 | mode = img.mode 115 | 116 | zDistance = (imgW * 100) // 256 117 | 118 | for row in range(imgH): 119 | for col in range(imgW): 120 | # img中每个点的颜色分量 121 | r, g, b, alpha = img.getpixel( (col, row) ) 122 | 123 | # 256色模式中,r:g:b = 3:3:2 bits 124 | r >>= 5; g >>= 5; b >>=6 125 | 126 | # 搜索最匹配图片 127 | if alpha == 0 : 128 | # 如果png图片在此位置的透明度是0,画个空气(寂寞) 129 | materialID, subIndex = (block.AIR.id, 0) 130 | else: 131 | materialID, subIndex = dictColor256ToMaterail[ (r, g, b) ] 132 | 133 | 134 | # 平着画,脚下-100的位置,玩家应该站在100+的高度 135 | mc.setBlock(x-col + imgW/2, y-100, z + (imgH/2-row), materialID, subIndex) 136 | # 竖着画,前方30格位置 137 | # mc.setBlock(x+30, y - row + imgH, z + col - imgW/2, materialID, subIndex) 138 | time.sleep(0.05) 139 | 140 | 141 | ########################################################################## 142 | # 入口 143 | if __name__ == '__main__': 144 | print("示例代码,简洁起见,必须使用png格式图片") 145 | time.sleep(5) 146 | init() 147 | 148 | img = Image.open("miku.png") 149 | drawFrame(img) 150 | print("绘制完成,等待mc刷新...") 151 | 152 | 153 | 154 | --------------------------------------------------------------------------------