Skip to content
是封面

如何使用最新最热的MC特性制作原版象棋(下)

CR_019

CR_019

标题有点不一样了?

对,因为中国象棋我们也做出来了,可以看这个视频: https://www.bilibili.com/video/BV1EhFWzJE9G

前情提要

在上一期视频,我们详解了如何拼好模和拼好字,制作了象棋的模型部分和操作界面部分。但是,目前这个对话框我们点击是没有反应的。因此,我们需要给这些字体加上点击事件,使得界面可以操作。如何通过设置点击命令和解析输入结果,正确选中棋子并摆放棋子,就是本期教程讨论的内容了。

Part0:分析操作流程

在正式开始之前,我们需要考虑一下玩家的操作流程是什么样的:
因为没有做走子规则,我们只需要考虑玩家选中棋子和摆棋子。
因此,我们需要维护一个选中状态,然后,根据是否具有选中状态对点击事件进行不同的响应:

  • 当未选中棋子时:
    • 若点击棋盘空格或吃子区空格,不做任何操作;
    • 若点击棋盘上/吃子区棋子所在格,选中该棋子。
  • 若选中棋子:
    • 若点击棋盘上空格,将该棋子移动到该处;
    • 若点击吃子区,将棋子移出棋盘;
    • 若点击自身,取消选择;
    • 若点击己方棋子,切换选择该棋子;
    • 若点击敌方棋子,则吃子(移动棋子并将敌方棋子移出棋盘)。

接下来就按照这个思路,设计棋盘的逻辑系统即可。

关于绑定

这里还有一个问题没有解决,就是如何判断玩家操作的是哪一副棋盘?
实际上,dc引擎自带uid系统,在玩家点击棋盘时,即可将棋盘的uid绑定在玩家的pc_chess_bind计分板上,在寻找实体时即可用这个绑定关系双向寻找。
退出对话框界面时,也会进行一次监听,将玩家和棋盘解绑。

Part1:监听点击操作

字体可以设置click_event,此后玩家点击该字体时就能够执行一条命令。
但由于~~Mojang的小巧思~~为~了~安~全~考~虑~,任何权限大于等于1的指令在此处都会弹出一个二次确认的弹窗,这对玩家的交互体验是灾难性的。因此,我们不得不使用唯一可操作的0权限指令:trigger

关于trigger指令

对于1.13以后甚至1.20时代入坑的数据包开发者可能完全不熟悉这个古早的指令,具体而言,它可以让无权限的玩家也可以通过这条命令有限次数地修改特定计分板的值(计分板需要是trigger准则)。
例如,管理员可以执行scoreboard players enable CR_019 Foo,这样玩家CR_019就可以执行一次trigger foo set 1或者trigger foo add 1来修改一次自己在foo这个计分板上的分数。此后想要再修改,需要再次执行上面的enable指令。
在这里,我们需要让玩家可以随时修改对应积分项的值,因此我们用高频函数对所有玩家enable这个计分板的权限。后面不再赘述。

通过trigger指令,我们可以向计分板传递一个整数。当它变化时,我们即可知道玩家进行了点击操作。

引入概念:点击值

由于后续几乎所有点击事件都使用trigger设置计分板,为方便讲解,我们就将设置的这个值称为点击值
设置点击值即为将这个字符的点击事件设为trigger pc_chess_trigger set <点击值>,在这里的高频函数检测到玩家点击时,即可获取这个值解析它的意义。

data/chess/function/tick.mcfunction:

mcfunction
scoreboard players enable @a pc_chess_trigger

#点击操作
execute as @a at @s if score @s pc_chess_trigger matches 1.. run function chess:dialog/_operation/click
execute as @a at @s if score @s pc_chess_trigger matches ..-1 run function chess:dialog/_operation/option

scoreboard players set @a pc_chess_trigger 0

我们用高频函数检测这个值的变化,然后在click这个函数中处理后续的逻辑。

data/chess/function/dialog/_operation/click.mcfunction

mcfunction
#点击事件
tag @s add pc_chess_player_temp
execute as @e[type=marker,tag=dc_pivot,distance=..10] if score @s dc_uid = @n[type=player,tag=pc_chess_player_temp] pc_chess_bind run function chess:dialog/_operation/click_

tag @s remove pc_chess_player_temp

data/chess/function/dialog/operation/click.mcfunction

mcfunction
#检查状态
execute if data entity @s data.chessboard.select run return run function chess:dialog/_operation/place

execute unless data entity @s data.chessboard.select run return run function chess:dialog/_operation/select

这里我们检查的是棋盘数据是否拥有select标签,如有,则代表该棋盘属于选中状态。在选中状态时,执行放置相关的函数,否则执行选择相关的。

TIP

select的结构如下:

compoundselect:
  • compoundid:表示棋子id,与棋局结构中的键一致;
  • compoundcolor:表示棋子颜色(黑/白)
  • compoundtype:表示选择的棋子在棋盘上还是吃子区
  • intx:棋子的x坐标,若在吃子区则为0;
  • inty:棋子的y坐标,若在吃子区则为0;

Part2:选择操作

  • 当未选中棋子时:
    • 若点击棋盘空格或吃子区空格,不做任何操作;
    • 若点击棋盘上/吃子区棋子所在格,选中该棋子。

data/chess/function/dialog/_operation/select.mcfunction

mcfunction
#选择格子

scoreboard players operation @s pc_chess_position = @n[tag=pc_chess_player_temp] pc_chess_trigger

execute if score @s pc_chess_position matches 1..64 run function chess:dialog/_operation/select/chessboard

execute if score @s pc_chess_position matches 101.. run function chess:dialog/_operation/select/piece

#同步
tag @s add pc_chess_board_temp
tag @a remove pc_chess_player_temp
playsound ui.button.click block @a ~ ~ ~
execute as @a if score @s pc_chess_bind = @n[type=marker,tag=pc_chess_board_temp] dc_uid run function chess:dialog/chessboard/main
function chess:events/sync/execute
tag @s remove pc_chess_board_temp

选择操作

到这里,我们就需要根据点击值解析玩家点击的具体坐标。
在对话框拼接的时候,我为每一个棋盘格的坐标指定了单独的trigger值。从左往右,从下往上分配1-64的点击值。
特别地,为了统一性,在翻转视角时,实际上是将对话框的点击值旋转了180度,在安排棋子映射的时候,正好一个倒转x一个倒转y,也很简单。

下方的吃子区,则按照棋子的位置,在棋子的字体上分配101-116,201-216的点击值,用于占位的空字符的点击值则设为100,对这个值不进行响应。

吃子区的棋子很简单,由于每个点击值和具体的棋子一一对应,穷举设置对应的棋子颜色和id即可。

data/chess/function/dialog/_operation/select/piece.mcfunction
mcfunction
#吃子区
#直接遍历

execute if score @s pc_chess_position matches 101 run data modify entity @s data.chessboard.select set value {x:0,y:0,type:"pieces",color:"white",id:"king"}
execute if score @s pc_chess_position matches 102 run data modify entity @s data.chessboard.select set value {x:1,y:0,type:"pieces",color:"white",id:"queen"}
execute if score @s pc_chess_position matches 103 run data modify entity @s data.chessboard.select set value {x:2,y:0,type:"pieces",color:"white",id:"bishop0"}
execute if score @s pc_chess_position matches 104 run data modify entity @s data.chessboard.select set value {x:3,y:0,type:"pieces",color:"white",id:"bishop1"}
execute if score @s pc_chess_position matches 105 run data modify entity @s data.chessboard.select set value {x:4,y:0,type:"pieces",color:"white",id:"knight0"}
execute if score @s pc_chess_position matches 106 run data modify entity @s data.chessboard.select set value {x:5,y:0,type:"pieces",color:"white",id:"knight1"}
execute if score @s pc_chess_position matches 107 run data modify entity @s data.chessboard.select set value {x:6,y:0,type:"pieces",color:"white",id:"rook0"}
execute if score @s pc_chess_position matches 108 run data modify entity @s data.chessboard.select set value {x:7,y:0,type:"pieces",color:"white",id:"rook1"}
execute if score @s pc_chess_position matches 109 run data modify entity @s data.chessboard.select set value {x:8,y:0,type:"pieces",color:"white",id:"pawn0"}
execute if score @s pc_chess_position matches 110 run data modify entity @s data.chessboard.select set value {x:9,y:0,type:"pieces",color:"white",id:"pawn1"}
execute if score @s pc_chess_position matches 111 run data modify entity @s data.chessboard.select set value {x:10,y:0,type:"pieces",color:"white",id:"pawn2"}
execute if score @s pc_chess_position matches 112 run data modify entity @s data.chessboard.select set value {x:11,y:0,type:"pieces",color:"white",id:"pawn3"}
execute if score @s pc_chess_position matches 113 run data modify entity @s data.chessboard.select set value {x:12,y:0,type:"pieces",color:"white",id:"pawn4"}
execute if score @s pc_chess_position matches 114 run data modify entity @s data.chessboard.select set value {x:13,y:0,type:"pieces",color:"white",id:"pawn5"}
execute if score @s pc_chess_position matches 115 run data modify entity @s data.chessboard.select set value {x:14,y:0,type:"pieces",color:"white",id:"pawn6"}
execute if score @s pc_chess_position matches 116 run data modify entity @s data.chessboard.select set value {x:15,y:0,type:"pieces",color:"white",id:"pawn7"}

execute if score @s pc_chess_position matches 201 run data modify entity @s data.chessboard.select set value {x:0,y:1,type:"pieces",color:"black",id:"king"}
execute if score @s pc_chess_position matches 202 run data modify entity @s data.chessboard.select set value {x:1,y:1,type:"pieces",color:"black",id:"queen"}
execute if score @s pc_chess_position matches 203 run data modify entity @s data.chessboard.select set value {x:2,y:1,type:"pieces",color:"black",id:"bishop0"}
execute if score @s pc_chess_position matches 204 run data modify entity @s data.chessboard.select set value {x:3,y:1,type:"pieces",color:"black",id:"bishop1"}
execute if score @s pc_chess_position matches 205 run data modify entity @s data.chessboard.select set value {x:4,y:1,type:"pieces",color:"black",id:"knight0"}
execute if score @s pc_chess_position matches 206 run data modify entity @s data.chessboard.select set value {x:5,y:1,type:"pieces",color:"black",id:"knight1"}
execute if score @s pc_chess_position matches 207 run data modify entity @s data.chessboard.select set value {x:6,y:1,type:"pieces",color:"black",id:"rook0"}
execute if score @s pc_chess_position matches 208 run data modify entity @s data.chessboard.select set value {x:7,y:1,type:"pieces",color:"black",id:"rook1"}
execute if score @s pc_chess_position matches 209 run data modify entity @s data.chessboard.select set value {x:8,y:1,type:"pieces",color:"black",id:"pawn0"}
execute if score @s pc_chess_position matches 210 run data modify entity @s data.chessboard.select set value {x:9,y:1,type:"pieces",color:"black",id:"pawn1"}
execute if score @s pc_chess_position matches 211 run data modify entity @s data.chessboard.select set value {x:10,y:1,type:"pieces",color:"black",id:"pawn2"}
execute if score @s pc_chess_position matches 212 run data modify entity @s data.chessboard.select set value {x:11,y:1,type:"pieces",color:"black",id:"pawn3"}
execute if score @s pc_chess_position matches 213 run data modify entity @s data.chessboard.select set value {x:12,y:1,type:"pieces",color:"black",id:"pawn4"}
execute if score @s pc_chess_position matches 214 run data modify entity @s data.chessboard.select set value {x:13,y:1,type:"pieces",color:"black",id:"pawn5"}
execute if score @s pc_chess_position matches 215 run data modify entity @s data.chessboard.select set value {x:14,y:1,type:"pieces",color:"black",id:"pawn6"}
execute if score @s pc_chess_position matches 216 run data modify entity @s data.chessboard.select set value {x:15,y:1,type:"pieces",color:"black",id:"pawn7"}

棋盘上则稍微复杂一些。需要先根据传入的点击值分解为xy坐标,然后与棋子位置的数据一一比对,确认点击的位置是否有棋子;
如果没有棋子则直接结束,有棋子的话,除了设置选中的棋子id和颜色,还需要记录选择坐标。这里分了三个函数来处理。

棋盘处理函数

data/chess/function/dialog/_operation/select/chessboard.mcfunction:

mcfunction
#在棋盘上
scoreboard players remove @s pc_chess_position 1
#分解横纵坐标
scoreboard players operation $x pc_chess_position = @s pc_chess_position
scoreboard players operation $y pc_chess_position = @s pc_chess_position
scoreboard players operation $x pc_chess_position %= $8 pc_chess_position
scoreboard players operation $y pc_chess_position /= $8 pc_chess_position


#遍历选择
function chess:dialog/_operation/select/chessboard_piece

data/chess/function/dialog/_operation/select/chessboard_piece.mcfunction:

mcfunction
execute store result score $px pc_chess_position run data get entity @s data.chessboard.chess_pieces.white.pawn0.x
execute store result score $py pc_chess_position run data get entity @s data.chessboard.chess_pieces.white.pawn0.y
execute if score $px pc_chess_position = $x pc_chess_position if score $py pc_chess_position = $y pc_chess_position run return run function chess:dialog/_operation/select/chessboard_selected {color:"white",id:"pawn0"}

execute store result score $px pc_chess_position run data get entity @s data.chessboard.chess_pieces.white.pawn1.x
execute store result score $py pc_chess_position run data get entity @s data.chessboard.chess_pieces.white.pawn1.y
execute if score $px pc_chess_position = $x pc_chess_position if score $py pc_chess_position = $y pc_chess_position run return run function chess:dialog/_operation/select/chessboard_selected {color:"white",id:"pawn1"}

execute store result score $px pc_chess_position run data get entity @s data.chessboard.chess_pieces.white.pawn2.x
execute store result score $py pc_chess_position run data get entity @s data.chessboard.chess_pieces.white.pawn2.y
execute if score $px pc_chess_position = $x pc_chess_position if score $py pc_chess_position = $y pc_chess_position run return run function chess:dialog/_operation/select/chessboard_selected {color:"white",id:"pawn2"}

execute store result score $px pc_chess_position run data get entity @s data.chessboard.chess_pieces.white.pawn3.x
execute store result score $py pc_chess_position run data get entity @s data.chessboard.chess_pieces.white.pawn3.y
execute if score $px pc_chess_position = $x pc_chess_position if score $py pc_chess_position = $y pc_chess_position run return run function chess:dialog/_operation/select/chessboard_selected {color:"white",id:"pawn3"}

execute store result score $px pc_chess_position run data get entity @s data.chessboard.chess_pieces.white.pawn4.x
execute store result score $py pc_chess_position run data get entity @s data.chessboard.chess_pieces.white.pawn4.y
execute if score $px pc_chess_position = $x pc_chess_position if score $py pc_chess_position = $y pc_chess_position run return run function chess:dialog/_operation/select/chessboard_selected {color:"white",id:"pawn4"}

execute store result score $px pc_chess_position run data get entity @s data.chessboard.chess_pieces.white.pawn5.x
execute store result score $py pc_chess_position run data get entity @s data.chessboard.chess_pieces.white.pawn5.y
execute if score $px pc_chess_position = $x pc_chess_position if score $py pc_chess_position = $y pc_chess_position run return run function chess:dialog/_operation/select/chessboard_selected {color:"white",id:"pawn5"}

execute store result score $px pc_chess_position run data get entity @s data.chessboard.chess_pieces.white.pawn6.x
execute store result score $py pc_chess_position run data get entity @s data.chessboard.chess_pieces.white.pawn6.y
execute if score $px pc_chess_position = $x pc_chess_position if score $py pc_chess_position = $y pc_chess_position run return run function chess:dialog/_operation/select/chessboard_selected {color:"white",id:"pawn6"}

execute store result score $px pc_chess_position run data get entity @s data.chessboard.chess_pieces.white.pawn7.x
execute store result score $py pc_chess_position run data get entity @s data.chessboard.chess_pieces.white.pawn7.y
execute if score $px pc_chess_position = $x pc_chess_position if score $py pc_chess_position = $y pc_chess_position run return run function chess:dialog/_operation/select/chessboard_selected {color:"white",id:"pawn7"}

execute store result score $px pc_chess_position run data get entity @s data.chessboard.chess_pieces.white.rook0.x
execute store result score $py pc_chess_position run data get entity @s data.chessboard.chess_pieces.white.rook0.y
execute if score $px pc_chess_position = $x pc_chess_position if score $py pc_chess_position = $y pc_chess_position run return run function chess:dialog/_operation/select/chessboard_selected {color:"white",id:"rook0"}

execute store result score $px pc_chess_position run data get entity @s data.chessboard.chess_pieces.white.rook1.x
execute store result score $py pc_chess_position run data get entity @s data.chessboard.chess_pieces.white.rook1.y
execute if score $px pc_chess_position = $x pc_chess_position if score $py pc_chess_position = $y pc_chess_position run return run function chess:dialog/_operation/select/chessboard_selected {color:"white",id:"rook1"}

execute store result score $px pc_chess_position run data get entity @s data.chessboard.chess_pieces.white.knight0.x
execute store result score $py pc_chess_position run data get entity @s data.chessboard.chess_pieces.white.knight0.y
execute if score $px pc_chess_position = $x pc_chess_position if score $py pc_chess_position = $y pc_chess_position run return run function chess:dialog/_operation/select/chessboard_selected {color:"white",id:"knight0"}

execute store result score $px pc_chess_position run data get entity @s data.chessboard.chess_pieces.white.knight1.x
execute store result score $py pc_chess_position run data get entity @s data.chessboard.chess_pieces.white.knight1.y
execute if score $px pc_chess_position = $x pc_chess_position if score $py pc_chess_position = $y pc_chess_position run return run function chess:dialog/_operation/select/chessboard_selected {color:"white",id:"knight1"}

execute store result score $px pc_chess_position run data get entity @s data.chessboard.chess_pieces.white.bishop0.x
execute store result score $py pc_chess_position run data get entity @s data.chessboard.chess_pieces.white.bishop0.y
execute if score $px pc_chess_position = $x pc_chess_position if score $py pc_chess_position = $y pc_chess_position run return run function chess:dialog/_operation/select/chessboard_selected {color:"white",id:"bishop0"}

execute store result score $px pc_chess_position run data get entity @s data.chessboard.chess_pieces.white.bishop1.x
execute store result score $py pc_chess_position run data get entity @s data.chessboard.chess_pieces.white.bishop1.y
execute if score $px pc_chess_position = $x pc_chess_position if score $py pc_chess_position = $y pc_chess_position run return run function chess:dialog/_operation/select/chessboard_selected {color:"white",id:"bishop1"}

execute store result score $px pc_chess_position run data get entity @s data.chessboard.chess_pieces.white.king.x
execute store result score $py pc_chess_position run data get entity @s data.chessboard.chess_pieces.white.king.y
execute if score $px pc_chess_position = $x pc_chess_position if score $py pc_chess_position = $y pc_chess_position run return run function chess:dialog/_operation/select/chessboard_selected {color:"white",id:"king"}

execute store result score $px pc_chess_position run data get entity @s data.chessboard.chess_pieces.white.queen.x
execute store result score $py pc_chess_position run data get entity @s data.chessboard.chess_pieces.white.queen.y
execute if score $px pc_chess_position = $x pc_chess_position if score $py pc_chess_position = $y pc_chess_position run return run function chess:dialog/_operation/select/chessboard_selected {color:"white",id:"queen"}



execute store result score $px pc_chess_position run data get entity @s data.chessboard.chess_pieces.black.pawn0.x
execute store result score $py pc_chess_position run data get entity @s data.chessboard.chess_pieces.black.pawn0.y
execute if score $px pc_chess_position = $x pc_chess_position if score $py pc_chess_position = $y pc_chess_position run return run function chess:dialog/_operation/select/chessboard_selected {color:"black",id:"pawn0"}

execute store result score $px pc_chess_position run data get entity @s data.chessboard.chess_pieces.black.pawn1.x
execute store result score $py pc_chess_position run data get entity @s data.chessboard.chess_pieces.black.pawn1.y
execute if score $px pc_chess_position = $x pc_chess_position if score $py pc_chess_position = $y pc_chess_position run return run function chess:dialog/_operation/select/chessboard_selected {color:"black",id:"pawn1"}

execute store result score $px pc_chess_position run data get entity @s data.chessboard.chess_pieces.black.pawn2.x
execute store result score $py pc_chess_position run data get entity @s data.chessboard.chess_pieces.black.pawn2.y
execute if score $px pc_chess_position = $x pc_chess_position if score $py pc_chess_position = $y pc_chess_position run return run function chess:dialog/_operation/select/chessboard_selected {color:"black",id:"pawn2"}

execute store result score $px pc_chess_position run data get entity @s data.chessboard.chess_pieces.black.pawn3.x
execute store result score $py pc_chess_position run data get entity @s data.chessboard.chess_pieces.black.pawn3.y
execute if score $px pc_chess_position = $x pc_chess_position if score $py pc_chess_position = $y pc_chess_position run return run function chess:dialog/_operation/select/chessboard_selected {color:"black",id:"pawn3"}

execute store result score $px pc_chess_position run data get entity @s data.chessboard.chess_pieces.black.pawn4.x
execute store result score $py pc_chess_position run data get entity @s data.chessboard.chess_pieces.black.pawn4.y
execute if score $px pc_chess_position = $x pc_chess_position if score $py pc_chess_position = $y pc_chess_position run return run function chess:dialog/_operation/select/chessboard_selected {color:"black",id:"pawn4"}

execute store result score $px pc_chess_position run data get entity @s data.chessboard.chess_pieces.black.pawn5.x
execute store result score $py pc_chess_position run data get entity @s data.chessboard.chess_pieces.black.pawn5.y
execute if score $px pc_chess_position = $x pc_chess_position if score $py pc_chess_position = $y pc_chess_position run return run function chess:dialog/_operation/select/chessboard_selected {color:"black",id:"pawn5"}

execute store result score $px pc_chess_position run data get entity @s data.chessboard.chess_pieces.black.pawn6.x
execute store result score $py pc_chess_position run data get entity @s data.chessboard.chess_pieces.black.pawn6.y
execute if score $px pc_chess_position = $x pc_chess_position if score $py pc_chess_position = $y pc_chess_position run return run function chess:dialog/_operation/select/chessboard_selected {color:"black",id:"pawn6"}

execute store result score $px pc_chess_position run data get entity @s data.chessboard.chess_pieces.black.pawn7.x
execute store result score $py pc_chess_position run data get entity @s data.chessboard.chess_pieces.black.pawn7.y
execute if score $px pc_chess_position = $x pc_chess_position if score $py pc_chess_position = $y pc_chess_position run return run function chess:dialog/_operation/select/chessboard_selected {color:"black",id:"pawn7"}

execute store result score $px pc_chess_position run data get entity @s data.chessboard.chess_pieces.black.rook0.x
execute store result score $py pc_chess_position run data get entity @s data.chessboard.chess_pieces.black.rook0.y
execute if score $px pc_chess_position = $x pc_chess_position if score $py pc_chess_position = $y pc_chess_position run return run function chess:dialog/_operation/select/chessboard_selected {color:"black",id:"rook0"}

execute store result score $px pc_chess_position run data get entity @s data.chessboard.chess_pieces.black.rook1.x
execute store result score $py pc_chess_position run data get entity @s data.chessboard.chess_pieces.black.rook1.y
execute if score $px pc_chess_position = $x pc_chess_position if score $py pc_chess_position = $y pc_chess_position run return run function chess:dialog/_operation/select/chessboard_selected {color:"black",id:"rook1"}

execute store result score $px pc_chess_position run data get entity @s data.chessboard.chess_pieces.black.knight0.x
execute store result score $py pc_chess_position run data get entity @s data.chessboard.chess_pieces.black.knight0.y
execute if score $px pc_chess_position = $x pc_chess_position if score $py pc_chess_position = $y pc_chess_position run return run function chess:dialog/_operation/select/chessboard_selected {color:"black",id:"knight0"}

execute store result score $px pc_chess_position run data get entity @s data.chessboard.chess_pieces.black.knight1.x
execute store result score $py pc_chess_position run data get entity @s data.chessboard.chess_pieces.black.knight1.y
execute if score $px pc_chess_position = $x pc_chess_position if score $py pc_chess_position = $y pc_chess_position run return run function chess:dialog/_operation/select/chessboard_selected {color:"black",id:"knight1"}

execute store result score $px pc_chess_position run data get entity @s data.chessboard.chess_pieces.black.bishop0.x
execute store result score $py pc_chess_position run data get entity @s data.chessboard.chess_pieces.black.bishop0.y
execute if score $px pc_chess_position = $x pc_chess_position if score $py pc_chess_position = $y pc_chess_position run return run function chess:dialog/_operation/select/chessboard_selected {color:"black",id:"bishop0"}

execute store result score $px pc_chess_position run data get entity @s data.chessboard.chess_pieces.black.bishop1.x
execute store result score $py pc_chess_position run data get entity @s data.chessboard.chess_pieces.black.bishop1.y
execute if score $px pc_chess_position = $x pc_chess_position if score $py pc_chess_position = $y pc_chess_position run return run function chess:dialog/_operation/select/chessboard_selected {color:"black",id:"bishop1"}

execute store result score $px pc_chess_position run data get entity @s data.chessboard.chess_pieces.black.king.x
execute store result score $py pc_chess_position run data get entity @s data.chessboard.chess_pieces.black.king.y
execute if score $px pc_chess_position = $x pc_chess_position if score $py pc_chess_position = $y pc_chess_position run return run function chess:dialog/_operation/select/chessboard_selected {color:"black",id:"king"}

execute store result score $px pc_chess_position run data get entity @s data.chessboard.chess_pieces.black.queen.x
execute store result score $py pc_chess_position run data get entity @s data.chessboard.chess_pieces.black.queen.y
execute if score $px pc_chess_position = $x pc_chess_position if score $py pc_chess_position = $y pc_chess_position run return run function chess:dialog/_operation/select/chessboard_selected {color:"black",id:"queen"}

data/chess/function/dialog/_operation/select/chessboard_selected.mcfunction:

mcfunction
$data modify entity @s data.chessboard.select set value {x:-1,y:-1,type:"chessboard",color:"$(color)",id:"$(id)"}

execute store result entity @s data.chessboard.select.x int 1 run scoreboard players get $x pc_chess_position
execute store result entity @s data.chessboard.select.y int 1 run scoreboard players get $y pc_chess_position

scoreboard players set @s pc_chess_switch 1

同步操作

最后我们需要将选框渲染到玩家的对话框上,实际上只需要执行一次同步操作即可,选框的渲染会在刷新对话框时自动完成。后续放置棋子时棋子位置的同步也是同理,这里使用统一的处理:

mcfunction
#同步
tag @s add pc_chess_board_temp
tag @a remove pc_chess_player_temp
playsound ui.button.click block @a ~ ~ ~
execute as @a if score @s pc_chess_bind = @n[type=marker,tag=pc_chess_board_temp] dc_uid run function chess:dialog/chessboard/main
function chess:events/sync/execute
tag @s remove pc_chess_board_temp

对玩家刷新显示一次对话框,对模型同步刷新一次模型,这样就可以把模型存储的数据同步到显示上了。

Part3:放置操作

  • 若选中棋子:
    • 若点击棋盘上空格,将该棋子移动到该处;
    • 若点击吃子区,将棋子移出棋盘;
    • 若点击自身,取消选择;
    • 若点击己方棋子,切换选择该棋子;
    • 若点击敌方棋子,则吃子(移动棋子并将敌方棋子移出棋盘)。

放置棋子的部分稍微复杂一些,但总体还是分为两个大类:点击棋盘上格子或吃子区。依然使用点击值进行第一次条件判断:

data/chess/function/dialog/_operation/place.mcfunction:

mcfunction
#放置棋子

scoreboard players operation @s pc_chess_position = @n[tag=pc_chess_player_temp] pc_chess_trigger

#在棋盘上
execute if score @s pc_chess_position matches 1..64 run function chess:dialog/_operation/place/chessboard
#在棋盘外
execute if score @s pc_chess_position matches 100.. run function chess:dialog/_operation/place/piece

#同步
tag @s add pc_chess_board_temp
tag @a remove pc_chess_player_temp
playsound block.decorated_pot.place block @a ~ ~ ~
execute as @a if score @s pc_chess_bind = @n[type=marker,tag=pc_chess_board_temp] dc_uid run function chess:dialog/chessboard/main
function chess:events/sync/execute
tag @s remove pc_chess_board_temp

第一次条件判断

吃子区的逻辑很简单,如果选中的棋子本来就在吃子区,取消选择即可;如果在棋盘上,则移出棋盘(将xy设置为-1)。

data/chess/function/dialog/_operation/place/piece.mcfunction:

mcfunction
#如果本来就在吃子区,直接取消选择
execute if data entity @s {data:{chessboard:{select:{type:"pieces"}}}} run return run data remove entity @s data.chessboard.select

#如果在棋盘上,将其移出棋盘
execute unless data entity @s {data:{chessboard:{select:{type:"pieces"}}}} run function chess:dialog/_operation/place/piece_place with entity @s data.chessboard.select

data/chess/function/dialog/_operation/place/piece_place.mcfunction

mcfunction
#移出棋子
$data modify entity @s data.chessboard.chess_pieces.$(color).$(id) set value {x:-1,y:-1}

data remove entity @s data.chessboard.select

棋盘点击的逻辑和选择类似,依然是先解析坐标,然后判断位置上的棋子。判断棋子的部分有一些变化:

  • 首先是新增了自身检查,直接检查select的xy坐标即可;
  • 然后根据选中棋子的颜色判断敌我关系,分别处理:

最后,如果没有匹配到棋子,则为空格,移动并清除选择。

data/chess/function/dialog/_operation/place/chessboard.mcfunction:

mcfunction
#在棋盘上
scoreboard players remove @s pc_chess_position 1
#分解横纵坐标
scoreboard players operation $x pc_chess_position = @s pc_chess_position
scoreboard players operation $y pc_chess_position = @s pc_chess_position
scoreboard players operation $x pc_chess_position %= $8 pc_chess_position
scoreboard players operation $y pc_chess_position /= $8 pc_chess_position

#判断是否是自身
execute store result score $px pc_chess_position run data get entity @s data.chessboard.select.x
execute store result score $py pc_chess_position run data get entity @s data.chessboard.select.y
execute unless data entity @s {data:{chessboard:{select:{type:"pieces"}}}} if score $px pc_chess_position = $x pc_chess_position if score $py pc_chess_position = $y pc_chess_position run return run data remove entity @s data.chessboard.select


#判断是否是其他棋子的位置
scoreboard players set @s pc_chess_switch 0
execute if data entity @s {data:{chessboard:{select:{color:"white"}}}} run function chess:dialog/_operation/place/chessboard_piece_white
execute if data entity @s {data:{chessboard:{select:{color:"black"}}}} run function chess:dialog/_operation/place/chessboard_piece_black

#如果不是切换选择,将选定的棋子移动,并清除选择状态
execute unless score @s pc_chess_switch matches 1 run function chess:dialog/_operation/place/chessboard_place with entity @s data.chessboard.select

切换选择和吃子

这一部分以白方为例,黑方的对应处理即可:

data/chess/function/dialog/_operation/place/chessboard_piece_white.mcfunction:
mcfunction
#己方棋子,切换选择
execute store result score $px pc_chess_position run data get entity @s data.chessboard.chess_pieces.white.pawn0.x
execute store result score $py pc_chess_position run data get entity @s data.chessboard.chess_pieces.white.pawn0.y
execute if score $px pc_chess_position = $x pc_chess_position if score $py pc_chess_position = $y pc_chess_position run return run function chess:dialog/_operation/select/chessboard_selected {color:"white",id:"pawn0"}

execute store result score $px pc_chess_position run data get entity @s data.chessboard.chess_pieces.white.pawn1.x
execute store result score $py pc_chess_position run data get entity @s data.chessboard.chess_pieces.white.pawn1.y
execute if score $px pc_chess_position = $x pc_chess_position if score $py pc_chess_position = $y pc_chess_position run return run function chess:dialog/_operation/select/chessboard_selected {color:"white",id:"pawn1"}

execute store result score $px pc_chess_position run data get entity @s data.chessboard.chess_pieces.white.pawn2.x
execute store result score $py pc_chess_position run data get entity @s data.chessboard.chess_pieces.white.pawn2.y
execute if score $px pc_chess_position = $x pc_chess_position if score $py pc_chess_position = $y pc_chess_position run return run function chess:dialog/_operation/select/chessboard_selected {color:"white",id:"pawn2"}

execute store result score $px pc_chess_position run data get entity @s data.chessboard.chess_pieces.white.pawn3.x
execute store result score $py pc_chess_position run data get entity @s data.chessboard.chess_pieces.white.pawn3.y
execute if score $px pc_chess_position = $x pc_chess_position if score $py pc_chess_position = $y pc_chess_position run return run function chess:dialog/_operation/select/chessboard_selected {color:"white",id:"pawn3"}

execute store result score $px pc_chess_position run data get entity @s data.chessboard.chess_pieces.white.pawn4.x
execute store result score $py pc_chess_position run data get entity @s data.chessboard.chess_pieces.white.pawn4.y
execute if score $px pc_chess_position = $x pc_chess_position if score $py pc_chess_position = $y pc_chess_position run return run function chess:dialog/_operation/select/chessboard_selected {color:"white",id:"pawn4"}

execute store result score $px pc_chess_position run data get entity @s data.chessboard.chess_pieces.white.pawn5.x
execute store result score $py pc_chess_position run data get entity @s data.chessboard.chess_pieces.white.pawn5.y
execute if score $px pc_chess_position = $x pc_chess_position if score $py pc_chess_position = $y pc_chess_position run return run function chess:dialog/_operation/select/chessboard_selected {color:"white",id:"pawn5"}

execute store result score $px pc_chess_position run data get entity @s data.chessboard.chess_pieces.white.pawn6.x
execute store result score $py pc_chess_position run data get entity @s data.chessboard.chess_pieces.white.pawn6.y
execute if score $px pc_chess_position = $x pc_chess_position if score $py pc_chess_position = $y pc_chess_position run return run function chess:dialog/_operation/select/chessboard_selected {color:"white",id:"pawn6"}

execute store result score $px pc_chess_position run data get entity @s data.chessboard.chess_pieces.white.pawn7.x
execute store result score $py pc_chess_position run data get entity @s data.chessboard.chess_pieces.white.pawn7.y
execute if score $px pc_chess_position = $x pc_chess_position if score $py pc_chess_position = $y pc_chess_position run return run function chess:dialog/_operation/select/chessboard_selected {color:"white",id:"pawn7"}

execute store result score $px pc_chess_position run data get entity @s data.chessboard.chess_pieces.white.rook0.x
execute store result score $py pc_chess_position run data get entity @s data.chessboard.chess_pieces.white.rook0.y
execute if score $px pc_chess_position = $x pc_chess_position if score $py pc_chess_position = $y pc_chess_position run return run function chess:dialog/_operation/select/chessboard_selected {color:"white",id:"rook0"}

execute store result score $px pc_chess_position run data get entity @s data.chessboard.chess_pieces.white.rook1.x
execute store result score $py pc_chess_position run data get entity @s data.chessboard.chess_pieces.white.rook1.y
execute if score $px pc_chess_position = $x pc_chess_position if score $py pc_chess_position = $y pc_chess_position run return run function chess:dialog/_operation/select/chessboard_selected {color:"white",id:"rook1"}

execute store result score $px pc_chess_position run data get entity @s data.chessboard.chess_pieces.white.knight0.x
execute store result score $py pc_chess_position run data get entity @s data.chessboard.chess_pieces.white.knight0.y
execute if score $px pc_chess_position = $x pc_chess_position if score $py pc_chess_position = $y pc_chess_position run return run function chess:dialog/_operation/select/chessboard_selected {color:"white",id:"knight0"}

execute store result score $px pc_chess_position run data get entity @s data.chessboard.chess_pieces.white.knight1.x
execute store result score $py pc_chess_position run data get entity @s data.chessboard.chess_pieces.white.knight1.y
execute if score $px pc_chess_position = $x pc_chess_position if score $py pc_chess_position = $y pc_chess_position run return run function chess:dialog/_operation/select/chessboard_selected {color:"white",id:"knight1"}

execute store result score $px pc_chess_position run data get entity @s data.chessboard.chess_pieces.white.bishop0.x
execute store result score $py pc_chess_position run data get entity @s data.chessboard.chess_pieces.white.bishop0.y
execute if score $px pc_chess_position = $x pc_chess_position if score $py pc_chess_position = $y pc_chess_position run return run function chess:dialog/_operation/select/chessboard_selected {color:"white",id:"bishop0"}

execute store result score $px pc_chess_position run data get entity @s data.chessboard.chess_pieces.white.bishop1.x
execute store result score $py pc_chess_position run data get entity @s data.chessboard.chess_pieces.white.bishop1.y
execute if score $px pc_chess_position = $x pc_chess_position if score $py pc_chess_position = $y pc_chess_position run return run function chess:dialog/_operation/select/chessboard_selected {color:"white",id:"bishop1"}

execute store result score $px pc_chess_position run data get entity @s data.chessboard.chess_pieces.white.king.x
execute store result score $py pc_chess_position run data get entity @s data.chessboard.chess_pieces.white.king.y
execute if score $px pc_chess_position = $x pc_chess_position if score $py pc_chess_position = $y pc_chess_position run return run function chess:dialog/_operation/select/chessboard_selected {color:"white",id:"king"}

execute store result score $px pc_chess_position run data get entity @s data.chessboard.chess_pieces.white.queen.x
execute store result score $py pc_chess_position run data get entity @s data.chessboard.chess_pieces.white.queen.y
execute if score $px pc_chess_position = $x pc_chess_position if score $py pc_chess_position = $y pc_chess_position run return run function chess:dialog/_operation/select/chessboard_selected {color:"white",id:"queen"}


#敌方棋子,吃子
execute store result score $px pc_chess_position run data get entity @s data.chessboard.chess_pieces.black.pawn0.x
execute store result score $py pc_chess_position run data get entity @s data.chessboard.chess_pieces.black.pawn0.y
execute if score $px pc_chess_position = $x pc_chess_position if score $py pc_chess_position = $y pc_chess_position run return run function chess:dialog/_operation/place/capture {color:"black",id:"pawn0"}

execute store result score $px pc_chess_position run data get entity @s data.chessboard.chess_pieces.black.pawn1.x
execute store result score $py pc_chess_position run data get entity @s data.chessboard.chess_pieces.black.pawn1.y
execute if score $px pc_chess_position = $x pc_chess_position if score $py pc_chess_position = $y pc_chess_position run return run function chess:dialog/_operation/place/capture {color:"black",id:"pawn1"}

execute store result score $px pc_chess_position run data get entity @s data.chessboard.chess_pieces.black.pawn2.x
execute store result score $py pc_chess_position run data get entity @s data.chessboard.chess_pieces.black.pawn2.y
execute if score $px pc_chess_position = $x pc_chess_position if score $py pc_chess_position = $y pc_chess_position run return run function chess:dialog/_operation/place/capture {color:"black",id:"pawn2"}

execute store result score $px pc_chess_position run data get entity @s data.chessboard.chess_pieces.black.pawn3.x
execute store result score $py pc_chess_position run data get entity @s data.chessboard.chess_pieces.black.pawn3.y
execute if score $px pc_chess_position = $x pc_chess_position if score $py pc_chess_position = $y pc_chess_position run return run function chess:dialog/_operation/place/capture {color:"black",id:"pawn3"}

execute store result score $px pc_chess_position run data get entity @s data.chessboard.chess_pieces.black.pawn4.x
execute store result score $py pc_chess_position run data get entity @s data.chessboard.chess_pieces.black.pawn4.y
execute if score $px pc_chess_position = $x pc_chess_position if score $py pc_chess_position = $y pc_chess_position run return run function chess:dialog/_operation/place/capture {color:"black",id:"pawn4"}

execute store result score $px pc_chess_position run data get entity @s data.chessboard.chess_pieces.black.pawn5.x
execute store result score $py pc_chess_position run data get entity @s data.chessboard.chess_pieces.black.pawn5.y
execute if score $px pc_chess_position = $x pc_chess_position if score $py pc_chess_position = $y pc_chess_position run return run function chess:dialog/_operation/place/capture {color:"black",id:"pawn5"}

execute store result score $px pc_chess_position run data get entity @s data.chessboard.chess_pieces.black.pawn6.x
execute store result score $py pc_chess_position run data get entity @s data.chessboard.chess_pieces.black.pawn6.y
execute if score $px pc_chess_position = $x pc_chess_position if score $py pc_chess_position = $y pc_chess_position run return run function chess:dialog/_operation/place/capture {color:"black",id:"pawn6"}

execute store result score $px pc_chess_position run data get entity @s data.chessboard.chess_pieces.black.pawn7.x
execute store result score $py pc_chess_position run data get entity @s data.chessboard.chess_pieces.black.pawn7.y
execute if score $px pc_chess_position = $x pc_chess_position if score $py pc_chess_position = $y pc_chess_position run return run function chess:dialog/_operation/place/capture {color:"black",id:"pawn7"}

execute store result score $px pc_chess_position run data get entity @s data.chessboard.chess_pieces.black.rook0.x
execute store result score $py pc_chess_position run data get entity @s data.chessboard.chess_pieces.black.rook0.y
execute if score $px pc_chess_position = $x pc_chess_position if score $py pc_chess_position = $y pc_chess_position run return run function chess:dialog/_operation/place/capture {color:"black",id:"rook0"}

execute store result score $px pc_chess_position run data get entity @s data.chessboard.chess_pieces.black.rook1.x
execute store result score $py pc_chess_position run data get entity @s data.chessboard.chess_pieces.black.rook1.y
execute if score $px pc_chess_position = $x pc_chess_position if score $py pc_chess_position = $y pc_chess_position run return run function chess:dialog/_operation/place/capture {color:"black",id:"rook1"}

execute store result score $px pc_chess_position run data get entity @s data.chessboard.chess_pieces.black.knight0.x
execute store result score $py pc_chess_position run data get entity @s data.chessboard.chess_pieces.black.knight0.y
execute if score $px pc_chess_position = $x pc_chess_position if score $py pc_chess_position = $y pc_chess_position run return run function chess:dialog/_operation/place/capture {color:"black",id:"knight0"}

execute store result score $px pc_chess_position run data get entity @s data.chessboard.chess_pieces.black.knight1.x
execute store result score $py pc_chess_position run data get entity @s data.chessboard.chess_pieces.black.knight1.y
execute if score $px pc_chess_position = $x pc_chess_position if score $py pc_chess_position = $y pc_chess_position run return run function chess:dialog/_operation/place/capture {color:"black",id:"knight1"}

execute store result score $px pc_chess_position run data get entity @s data.chessboard.chess_pieces.black.bishop0.x
execute store result score $py pc_chess_position run data get entity @s data.chessboard.chess_pieces.black.bishop0.y
execute if score $px pc_chess_position = $x pc_chess_position if score $py pc_chess_position = $y pc_chess_position run return run function chess:dialog/_operation/place/capture {color:"black",id:"bishop0"}

execute store result score $px pc_chess_position run data get entity @s data.chessboard.chess_pieces.black.bishop1.x
execute store result score $py pc_chess_position run data get entity @s data.chessboard.chess_pieces.black.bishop1.y
execute if score $px pc_chess_position = $x pc_chess_position if score $py pc_chess_position = $y pc_chess_position run return run function chess:dialog/_operation/place/capture {color:"black",id:"bishop1"}

execute store result score $px pc_chess_position run data get entity @s data.chessboard.chess_pieces.black.king.x
execute store result score $py pc_chess_position run data get entity @s data.chessboard.chess_pieces.black.king.y
execute if score $px pc_chess_position = $x pc_chess_position if score $py pc_chess_position = $y pc_chess_position run return run function chess:dialog/_operation/place/capture {color:"black",id:"king"}

execute store result score $px pc_chess_position run data get entity @s data.chessboard.chess_pieces.black.queen.x
execute store result score $py pc_chess_position run data get entity @s data.chessboard.chess_pieces.black.queen.y
execute if score $px pc_chess_position = $x pc_chess_position if score $py pc_chess_position = $y pc_chess_position run return run function chess:dialog/_operation/place/capture {color:"black",id:"queen"}

这一步是遍历数据列表,检查格子上是否是对应的棋子;
如果是己方棋子,调用select模块的函数切换选择;
如果是敌方棋子,则触发吃子,将对应颜色和棋子id传入capture函数:

data/xiangqi/function/dialog/_operation/place/capture.mcfunction:

mcfunction
#吃子:将棋子移出棋盘

$data modify entity @s data.chessboard.chess_pieces.$(color).$(id) set value {x:-1,y:-1}

吃子这一步只移出了敌方棋子,因为移动选定棋子的部分和点击空位的移动一起在最后处理了。

同步

移动棋子后,照例需要同步一下,这一部分在选中部分已经提过,流程完全一致。

PartEX:切换视角与预设布局

到这里,我们就完成了象棋摆件的全部流程:选中棋子和吃子。当然,你还会发现在下面有三个按钮:切换视角、清空棋盘、恢复开局。

这部分相对简单,在此带过一下:

切换视角会触发-2的点击值,会修改玩家的视角参数并刷新对话框,对话框渲染函数会根据这个参数设置棋盘点击值和棋子渲染坐标处理算法;

退出对话框会触发-1的点击值,会将玩家和棋盘解绑。

设置预设布局的两个按钮我没有设置点击值而是直接绑定了函数,正好给一个二次确认的机会。实现也很简单,就是强制修改每一个棋子的位置,然后同步一次模型。

结语

以上就是数据包象棋的全部解析了。本作的特色主要还是在第一部分的显示上,使用了物品模型映射和字体的拼合特性,用比较有限的模型和纹理数量制作了很丰富的可能。

Powered by Vitepress and Github Pages