第一课 用代码去旅行
连接到Minecraft
在没有运行minecraft的情况下运行一下,以下代码看看会发生什么。
运行minecraft,进入游戏后再试一次。
from mcpi.minecraft import Minecraft
mc = Minecraft.create("robin-pc")
print(mc)
<mcpi.minecraft.Minecraft object at 0x060D4DC0>
认识MC对象
如果上述代码没有报错,接下来就可以使用mc变量了。
mc变量是一个对象类型,对象是一个属性和方法的集合体。
先来看看,这个对象里有些什么。
print(mc.__doc__)
print("mc的属性:", mc.__dict__)
print("mc的属性和方法:", dir(mc))
The main class to interact with a running instance of Minecraft Pi.
mc的属性: {'conn': <mcpi.connection.Connection object at 0x067ED178>, 'camera': <mcpi.minecraft.CmdCamera object at 0x06272F88>, 'entity': <mcpi.minecraft.CmdEntity object at 0x06272F70>, 'player': <mcpi.minecraft.CmdPlayer object at 0x06272EF8>, 'events': <mcpi.minecraft.CmdEvents object at 0x06272FD0>}
mc的属性和方法: ['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'camera', 'conn', 'create', 'entity', 'events', 'getBlock', 'getBlockWithData', 'getBlocks', 'getEntities', 'getEntityTypes', 'getHeight', 'getPlayerEntityId', 'getPlayerEntityIds', 'player', 'postToChat', 'removeEntities', 'removeEntity', 'restoreCheckpoint', 'saveCheckpoint', 'setBlock', 'setBlocks', 'setSign', 'setting', 'spawnEntity']
通过属性和方法的名称,我们可以猜一下分别代表什么。
属性就是对象变量里包含的变量,也可以是一个对象,比如 player 应该是指玩家对象。
方法是对象可以执行的函数,比如 setBlock 应该是将某个位置设置为指定类型的方块。
对象的含义是指具体的某一个事物,即在现实生活中能够看得见摸得着的事物。属性可以认为是构成事物的东西,或事物的某个特征。方法则是事物可以执行的某种行为。比如,人是一个对象,头是他的属性,肤色也可以是他的属性,他能跑、能跳、能说话,这些就是方法。
再来看看 mc.player 对象
print(mc.player.__doc__)
print(mc.player.__dict__)
print(dir(mc.player))
Methods for the host (Raspberry Pi) player
{'conn': <mcpi.connection.Connection object at 0x067ED178>, 'pkg': b'player'}
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'clearEvents', 'conn', 'getDirection', 'getEntities', 'getPitch', 'getPos', 'getRotation', 'getTilePos', 'pkg', 'pollBlockHits', 'pollChatPosts', 'pollProjectileHits', 'removeEntities', 'setDirection', 'setPitch', 'setPos', 'setRotation', 'setTilePos', 'setting']
让玩家飞起来
有了 mc.player 就可以调用他的方法,让玩家做我们指定的事情。
我们这里要让玩家按我们指定的路线去旅行。
也就是说要控制玩家在游戏场景中的位置。
位置单词是 Position。所以我们猜带 Pos 的都是和位置相关的方法。
来看看 getPos 和 getTilePos
print(mc.player.getPos())
print(mc.player.getTilePos())
Vec3(11.894535916349604,9.0,6.112793712914957)
Vec3(11,9,6)
这两个方法都返回了一个三维坐标,只是第一个返回的带小数点(浮点型),第二个没有(整形)。Tile是瓦片的意思,这里应该是指方块。
为了搞清楚这个三维坐标系的含义,我们可以先查查minecraft的百科。
https://minecraft-zh.gamepedia.com/%E5%9D%90%E6%A0%87
坐标系
坐标基于一个由互相垂直且交于一点(即原点)的三条坐标轴形成的网格,即一个空间直角坐标系。
x轴的正方向为东,其坐标反映了玩家距离原点在东(+)西(-)方向上的距离。
z轴的正方向为南,其坐标反映了玩家距离原点在南(+)北(-)方向上的距离。
y轴的正方向为上,其坐标反映了玩家位置的高低程度(从0至255,其中海平面为62),另见海拔高度。
坐标系的单位长度为一个方块长,基于测量方法,每一方块为1立方米。
因此,三条坐标轴形成了右手坐标系(拇指为x轴,食指为y轴,中指为z轴),通过这样可以更为简单地记住各坐标轴。
方块坐标
一个方块的坐标实际上是这个方块的西北下角那一点的坐标,即方块内的坐标向下取整得到的整数坐标。
在游戏中,一个小数坐标通常需要通过向下取整转换成整数坐标,这个整数坐标称为原坐标的方块坐标。
我们现在就让玩家飞起来 100 格瓦片。
要调用方法,首先要搞清楚方法有哪些参数。通常我们应该去查手册。
https://www.stuffaboutcode.com/p/minecraft-api-reference.html
playerpos = mc.player.getTilePos()
print(playerpos)
playerpos.y = playerpos.y + 100
mc.player.setTilePos(playerpos)
print(mc.player.getTilePos())
Vec3(11,9,6)
Vec3(11,109,6)
上边这个程序动作有点快,我们让玩家每10个瓦片先停2秒钟,100个20秒里飞完。
import time
playerpos = mc.player.getTilePos()
print(playerpos)
playerpos.y = playerpos.y + 10
mc.player.setTilePos(playerpos)
time.sleep(2)
playerpos.y = playerpos.y + 10
mc.player.setTilePos(playerpos)
time.sleep(2)
playerpos.y = playerpos.y + 10
mc.player.setTilePos(playerpos)
time.sleep(2)
playerpos.y = playerpos.y + 10
mc.player.setTilePos(playerpos)
time.sleep(2)
playerpos.y = playerpos.y + 10
mc.player.setTilePos(playerpos)
time.sleep(2)
playerpos.y = playerpos.y + 10
mc.player.setTilePos(playerpos)
time.sleep(2)
playerpos.y = playerpos.y + 10
mc.player.setTilePos(playerpos)
time.sleep(2)
playerpos.y = playerpos.y + 10
mc.player.setTilePos(playerpos)
time.sleep(2)
playerpos.y = playerpos.y + 10
mc.player.setTilePos(playerpos)
time.sleep(2)
playerpos.y = playerpos.y + 10
mc.player.setTilePos(playerpos)
time.sleep(2)
print(mc.player.getTilePos())
Vec3(11,9,6)
Vec3(11,62,8)
思考,这个程序有点傻,需要重复敲那么多吗?100次怎么办?
建造东西——垒方块
mc 对象有 getBlock 和 setBlock 方法,分别对应获取和设置指定位置砖块类型的操作。
我们先来看看,我们站在什么东西上面。
playerpos = mc.player.getTilePos()
print(playerpos)
playerpos.y = playerpos.y - 1
blockbelowme = mc.getBlock(playerpos)
print(blockbelowme)
Vec3(11,8,18)
2
接下来将脚下的东西变成黄金。
playerpos = mc.player.getTilePos()
print(playerpos)
playerpos.y = playerpos.y - 1
blockbelowme = mc.getBlock(playerpos)
mc.setBlock(playerpos, 41)
print(mc.getBlock(playerpos))
Vec3(11,8,18)
41
获得玩家的朝向,在玩家前面一格位置地上放一列西瓜
playerdirection = mc.player.getDirection()
print(playerdirection)
playerpos = mc.player.getPos()
print(playerpos)
pos = playerpos + playerdirection
pos.y = pos.y + 1
mc.setBlock(pos, 103)
pos.y = pos.y + 1
mc.setBlock(pos, 103)
pos.y = pos.y + 1
mc.setBlock(pos, 103)
Vec3(0.0,0.0,1.0)
Vec3(11.5,8.0,16.07490546770636)
还可以垒别的方块,这取决于setBlock的类型参数,更多类型参见:https://www.stuffaboutcode.com/p/minecraft-api-reference.html
在这份文档中定义了各种方块ID,但是漏了一部分,遗漏的部分并非不能使用。例如 101 是铁栅栏的ID。
我们可以用 101, 做一组铁栅栏。
这里我们还可以使用 setBlocks,这个函数可以直接建造一个大的长方体
.setBlocks(x0,y0,z0,x1,y1,z1,blockType, blockData)
sets many blocks at a time, filling the gap between 2 sets of x, y, z co-ordinates
playerdirection = mc.player.getDirection()
print(playerdirection)
playerpos = mc.player.getPos()
print(playerpos)
pos = playerpos + playerdirection
pos.y += 1
width = 10
height = 5
length = 0
mc.setBlocks(pos.x, pos.y, pos.z, pos.x + width, pos.y + height, pos.z + length, 101)
Vec3(-0.7765394609815067,0.2537579896646276,0.5767090672253365)
Vec3(14.076302957010665,8.0,15.848499292254203)
更多方块ID,可参见《38363-砖块ID备忘单(网上用).pdf》
使用 setBlock、setBlocks,结合计算形状的算法就可以建造出不同形状的建筑物,以下代码可以建造一个尖塔
#cfrom mcpi.minecraft import Minecraft
#mc = Minecraft.create()
pos = mc.player.getTilePos()
x = pos.x
y = pos.y
z = pos.z
height = 3
blockType = 1
# Spire sides: should be same as height
sideHeight = height
mc.setBlocks(x + 1, y, z + 1, x + 3, y + sideHeight - 1, z + 3, blockType)
# Spire point: should be two times the height
pointHeight = height * 2
mc.setBlocks(x + 2, y, z + 2, x + 2, y + pointHeight - 1, z + 2, blockType)
# Spire base: should be half the height
baseHeight = height / 2
mc.setBlocks(x, y, z, x + 4, y + baseHeight - 1, z + 4, blockType)
我们还可以用什么计算方法做点什么?
随机漫游
我们可以用随机数让玩家在我的世界里随机跳到一个地方
import random
pos = mc.player.getTilePos()
x = pos.x + random.randint(-10, 10)
y = pos.y + random.randint(-10, 10)
z = pos.z + random.randint(-10, 10)
mc.player.setTilePos(x, y, z)
上面这个程序有个问题,玩家可能飞到一个密闭的空间里了,怎么办?
972

被折叠的 条评论
为什么被折叠?



