2.6
This commit is contained in:
109
docs/mcguide/28-电脑网络游戏/课程3:编写Bukkit插件/3-进阶内容/1-箱子GUI的实现.md
Normal file
109
docs/mcguide/28-电脑网络游戏/课程3:编写Bukkit插件/3-进阶内容/1-箱子GUI的实现.md
Normal file
@@ -0,0 +1,109 @@
|
||||
---
|
||||
front:
|
||||
hard: 进阶
|
||||
time: 20分钟
|
||||
---
|
||||
|
||||
# Bukkit类与箱子GUI的实现
|
||||
|
||||
服务器里经常会利用箱子的GUI做“按钮菜单”功能. 有些服务器可能利用`ChestCommand`插件做出了各种花样的菜单.
|
||||
如何写一个插件来实现这样的箱子GUI呢?
|
||||
|
||||
# Bukkit类
|
||||
|
||||
我们早在事件监听注册监听器时就已经见过`Bukkit`类了.
|
||||
|
||||
```java
|
||||
Bukkit.getPluginManager().registerEvents(this,this);
|
||||
```
|
||||
|
||||
`Bukkit`类是服务器的单例. 我们可以通过它操作服务器.
|
||||
例如, 你可以用`Bukkit.banIP("某个IP")`来封禁某个IP号. 更多的用法可以在JavaDoc上查到.
|
||||
|
||||
你也可以利用`Server`对象操作服务器, 二者几乎没有差别(`Bukkit`类内部就是操作`Server`对象).
|
||||
插件主类提供`getServer()`方法, 返回值就是一个`Server`对象.
|
||||
|
||||
# Inventory的使用
|
||||
|
||||
箱子GUI本质是一个Inventory界面. 首先我们需要创建一个Inventory对象出来.
|
||||
但我们不必直接`new Inventory(...)`, 这是因为查阅JavaDocs可以得知,Inventory是一个接口,无法直接实例化。
|
||||
但是`Bukkit`类给我们提供了创建`Inventory`对象的方法:
|
||||
|
||||
```java
|
||||
Inventory inv = Bukkit.createInventory(player, 6*9, "URARA!");
|
||||
//第一项是主人, 在这里可以设打开界面的玩家Player对象(还记得Inventory和箱子或玩家背包等一一对应吗)
|
||||
//第二项必须是 9n (n是1≤n≤6的正整数)
|
||||
//第三项是标题
|
||||
ItemStack item_bk = new ItemStack(Material.DIAMOND);
|
||||
|
||||
//在四周设置钻石边框
|
||||
//这里用这样脑残的写法是为了告诉你一个大概的意思
|
||||
//我相信你实际写的时候不会这么简单粗暴解决问题的, 应该会用上循环解决, 对吧
|
||||
inv.setItem(0,item_bk);
|
||||
inv.setItem(1,item_bk);
|
||||
inv.setItem(2,item_bk);
|
||||
inv.setItem(3,item_bk);
|
||||
inv.setItem(4,item_bk);
|
||||
inv.setItem(5,item_bk);
|
||||
inv.setItem(6,item_bk);
|
||||
inv.setItem(7,item_bk);
|
||||
inv.setItem(8,item_bk);
|
||||
inv.setItem(9,item_bk);
|
||||
inv.setItem(17,item_bk);
|
||||
inv.setItem(18,item_bk);
|
||||
inv.setItem(26,item_bk);
|
||||
inv.setItem(27,item_bk);
|
||||
inv.setItem(35,item_bk);
|
||||
inv.setItem(36,item_bk);
|
||||
inv.setItem(44,item_bk);
|
||||
inv.setItem(45,item_bk);
|
||||
inv.setItem(46,item_bk);
|
||||
inv.setItem(47,item_bk);
|
||||
inv.setItem(48,item_bk);
|
||||
inv.setItem(49,item_bk);
|
||||
inv.setItem(50,item_bk);
|
||||
inv.setItem(51,item_bk);
|
||||
inv.setItem(52,item_bk);
|
||||
inv.setItem(53,item_bk);
|
||||
|
||||
ItemStack item_button1 = new ItemStack(Material.GOLD);
|
||||
ItemStack item_button2 = new ItemStack(Material.ANVIL);
|
||||
inv.setItem(22,item_button1);
|
||||
inv.setItem(31,item_button2);
|
||||
|
||||
//然后可以给玩家打开这个Inventory(注意, 我们还没做限制, 这个时候玩家可以自由的在这个GUI里拿东西出来)
|
||||
p.openInventory(inv);
|
||||
```
|
||||
|
||||
然后我们监听`InventoryClickEvent`实现功能和限制:
|
||||
```java
|
||||
@EventHandler
|
||||
public void onInventoryClick(InventoryClickEvent e){
|
||||
//从这里可以看出来, 标题不是随意设置的, 我们经常用标题作为区分GUI的标志
|
||||
if(e.getWhoClicked().getOpenInventory().getTitle().equals("URARA!")){
|
||||
e.setCancelled(true); //这样玩家就没办法拿出来物品了
|
||||
|
||||
//getRawSlot获得玩家点击的格子编号
|
||||
//但是玩家点击GUI之外不是格子的地方也会触发InventoryClickEvent, 需要做处理!
|
||||
if(e.getRawSlot()<0 || e.getRawSlot()>e.getInventory().getSize() || e.getInventory()==null)
|
||||
return;
|
||||
|
||||
//自从Mojang把HIM删掉以后, 能触发InventoryClickEvent的只有Player了
|
||||
//目前来说可以直接把它强转成Player
|
||||
Player p = (Player)e.getWhoClicked();
|
||||
|
||||
if(e.getRawSlot()==22){
|
||||
p.sendMessage("你点击了金锭!");
|
||||
p.closeInventory();
|
||||
} else {
|
||||
p.sendMessage("你没有点击金锭!");
|
||||
p.closeInventory();
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
基于这个思路, 你可以做出一个有功能的箱子GUI了!
|
||||
|
||||
> 思考: 如果遇到了某些能够修改箱子GUI的标题的插件(比如帮助加前缀)
|
||||
> 能不能利用 InventoryHolder 来区分GUI呢?
|
||||
|
||||
Reference in New Issue
Block a user