- Java锁的逻辑(结合对象头和ObjectMonitor)
- 还在用饼状图?来瞧瞧这些炫酷的百分比可视化新图形(附代码实现)⛵
- 自动注册实体类到EntityFrameworkCore上下文,并适配ABP及ABPVNext
- 基于Sklearn机器学习代码实战
相信阅读过上期文章,动手能力强的朋友们已经自己跑出来界面了。所以这期我要讲的是交互部分,也就是对于鼠标点击事件的响应,包括计时计数对点击事件以及一些状态量的影响.
回忆下第一期介绍的扫雷规则和操作,游戏从开局到结束可能会涉及到哪些情况呢?我认为比较重要的就是明确什么情况下游戏已经结束,结束代表的是胜利还是失败。对此我定义了一个游戏状态量,他有位置、胜利和失败三种可选值,如下:
// 游戏状态相关 [1:获胜, 0:未知, -1:失败]
public static byte WIN = 1;
public static byte UNSURE = 0;
public static byte LOSS = -1;
public static byte STATE = UNSURE;
很显然游戏只要还未结束,就应该保持在未知状态。那么哪些情况会影响到状态量的取值,就需要我们逐个分析了.
根据规则,当我们把除地雷以外的所有格子均点开后便取得胜利,所以右键点击并不会对游戏状态造成影响。那我们仅需在每次左键点击处理中进行格子数统计,符合要求就修改游戏状态为胜利,点击到地雷便修改为失败。另外每次点击都需要更新相关格子的显示,所以这两项任务可以放在一起进行,做法如下:
// 更新点击过的数据
mineSweeper.clickCell(row, column);
执行完后就对游戏状态进行判断,如果没有点击到地雷,执行 STATE == UNSURE 部分:
if (STATE == UNSURE) {
// 统计非雷格子已点开数目
int count = 0;
for (int i = 0; i < GAME.height; ++i) {
for (int j = 0; j < GAME.width; ++j) {
if (map[i][j] > BOUND) {
Button btn = (Button) buttons.get(i * GAME.width + j);
count += 1;
int value = map[i][j] - 100;
if (value != BLANK) {
// 消除空白填充
btn.setPadding(new Insets(0.0));
// 设置粗体和字体颜色
btn.setFont(Font.font("Arial", FontWeight.BOLD, GAME.numSize));
btn.setTextFill(NUMS[value - 1]);
btn.setText(value + "");
}
btn.setStyle("-fx-border-color: #737373; -fx-opacity: 1; -fx-background-color: #ffffff");
btn.setDisable(true);
}
}
}
// 判断全部非雷格子是否全部点开
if (count + GAME.bomb == GAME.width * GAME.height) {
STATE = WIN;
}
}
否则执行 STATE == LOSS 部分:
if (STATE == LOSS) {
// 游戏失败, 显示所有地雷位置
for (int i = 0; i < GAME.height; ++i) {
for (int j = 0; j < GAME.width; ++j) {
if (map[i][j] == BOMB) {
Button btn = (Button) buttons.get(i * GAME.width + j);
btn.setStyle("-fx-background-color:#ffffff; -fx-background-size: contain; -fx-background-image: url(" + UNEXPLODED_IMG + ")");
}
}
}
button.setStyle("-fx-background-color:#ffffff; -fx-background-size: contain; -fx-background-image: url(" + EXPLODED_IMG + ")");
}
看上去似乎所有任务都完成了,真的是这样吗?别忘了还有计时功能,时间超出指定范围也可以认为是游戏失败。上期说过计时计数这块有自定义控件,这期它依旧不是主角 ,但是我会大致说明下它的工作方式。如果你还记得游戏界面那两个黑框框是GridPane布局的话,显示出的 数字 就是其中的控件外观。我使用的是三位数,也就是说每个布局中都含有三个数字自定义控件,根据数值不同排列组合表示不同整数.
首先来讲计时,这里JavaFX提供的有时间轴类,直接拿来用非常方便。我们可以设置事件触发的间隔,对应到扫雷里自然是每秒触发一次。事件中要做的就是判断游戏状态和是否超时,下面给出代码以供参考.
涉及到的量:
// 时间计数和超时范围
public static int TIMER = 0;
public static int OVERTIME = 999;
// 计时器
public static Timeline TIMELINE = null;
计时事件:
TIMELINE = new Timeline(
new KeyFrame(Duration.seconds(1), event -> {
TIMER += 1;
// 超时自动判负
if (TIMER >= OVERTIME) {
STATE = LOSS;
}
// 游戏胜负已确定
if (STATE != UNSURE) {
String path = WIN_IMG;
TIMELINE.stop();
if (STATE == LOSS) {
path = LOSS_IMG;
} else {
// 自定义模式不计入成绩
if (GAME != GameEnum.CUSTOM) {
Platform.runLater(() -> showDialog());
}
}
reset.setStyle("-fx-background-size: contain; -fx-background-image: url(" + path + ")");
}
ledTime[0].switchSkin(TIMER / 100);
ledTime[1].switchSkin(TIMER % 100 / 10);
ledTime[2].switchSkin(TIMER % 10);
})
);
接下来是计数功能,数字显示原理同上,主要是交互。这个数字表示的是游戏中剩余可用标记数 REST_FLAG ,它的值通过左右键点击改变。它的改变规则具体如下:
- 该数值初始大小等于地雷数目。
- 右键点击未知格子时,如果先前没有标记,那么值减去1,标记旗帜;如果已有旗帜标记,值不变,替换为问号标记;如果已有问号标记,值加上1,去除格子上的标记。
- 左键点击有标记的格子时,不管是哪种标记,值统统加上1,去除标记。
接下来需要考虑如何监听 REST_FLAG 值的变化,通过查阅资料,我找到了一种方案 ReadOnlyIntegerWrapper 。该类提供了一个方便的类来定义只读属性。它创建两个同步的属性。一个属性是只读的,可以传递给外部用户。另一个属性是可读写的,只能在内部使用。最重要的是可以对它设置监听器,在值发生变化时执行一些操作,实现如下:
// 创建具有可观察特性的整数变量
rest = new ReadOnlyIntegerWrapper(REST_FLAG);
// 添加监听器, 在变量值变化时执行相应的操作, 下同
ChangeListener<? super Number> restListener = (observable, oldValue, newValue) -> {
// 在变量值变化时执行相应的操作
ledMark[0].switchSkin(REST_FLAG / 100);
ledMark[1].switchSkin(REST_FLAG % 100 / 10);
ledMark[2].switchSkin(REST_FLAG % 10);
};
// 将监听器绑定到rest属性
rest.addListener(restListener);
这些工作完成后,我们再来考虑一个有关计时的问题。什么时机开始计时较为合适呢?是进入游戏界面,还是第一次点击格子?我认为后者更符合要求。当然这个全看个人设计,如果采用后者的方案的话,也需要设置对应的值来监听,比如下面这种:
// 游戏是否开局, 即格子是否被点击过 [1:是, 0:否]
public static int YES = 1;
public static int NO = 0;
public static int CLICKED = NO;
然后把上边提到的监听事件与之结合:
clicked = new ReadOnlyIntegerWrapper(CLICKED);
ChangeListener<? super Number> clickListener = (observable, oldValue, newValue) -> {
// 已经被点击, 开始计时
TIMER = 0;
// TODO 这里放入计时监听事件
TIMELINE.setCycleCount(Animation.INDEFINITE);
TIMELINE.play();
};
clicked.addListener(clickListener);
值发生变化后需要手动调用set方法触发监听:
// 判断游戏是否开局
if (CLICKED == NO) {
CLICKED = YES;
clicked.set(CLICKED);
}
// 触发监听, 修改剩余地雷数显示
rest.set(REST_FLAG);
截止到这里,有关游戏部分就只剩下排行榜功能未介绍了。至于鸽了好几期都没说的自定义控件,因为我觉得它的实现并不重要,了解它的作用一样能理解前边的内容,所以就放在最后一期再说吧.
——————————————我———是———分———割———线————————————— 。
我居然更到第三期了哎,一周之内呀!太勤快了吧!不行,最多再更两期,我要报仇雪恨般地拖更,拖拖拖拖拖拖拖一拖到明年,大好时光怎么能天天用来码文呢?我要打电动去啦,阿伟也拦不住,我说的! 。
最后此篇关于基于JavaFX的扫雷游戏实现(三)——交互逻辑的文章就讲到这里了,如果你想了解更多关于基于JavaFX的扫雷游戏实现(三)——交互逻辑的内容请搜索CFSDN的文章或继续浏览相关文章,希望大家以后支持我的博客! 。
在 python 交互中,有没有办法在每次输入命令后自动从 python 文件执行方法? 例如:如果我有一个打印文件信息的方法,但我不想不断调用该方法,我怎样才能让它在 python 交互中的每个命令
当你使用Edge等浏览器或系统软件播放媒体时,Windows控制中心就会出现相应的媒体信息以及控制播放的功能,如图。 SMTC (SystemMedia
我在主菜单上使用标准的剪切,复制,粘贴操作。它们具有快捷键Ctrl-X,Ctrl-C和Ctrl-V。 当我打开模态表单时FindFilesForm.ShowModal,然后所有快捷方式都可以从表单中使
这是我想要实现的目标:打开一个 shell(korn 或 bash,没关系),从那个 shell,我想打开一个 ssh 连接(ssh user@host)。在某些时候,可能会提示我输入密码,或者可能会
我正在测试在C / C++程序中嵌入Python,但是我缺乏理解。 测试程序很简单: 初始化解释器; 从启动Timer的文件中执行python脚本(每0.1秒增加一个变量); 等待5秒(C++); 从
我正在尝试用java创建Excel文件。现在,我正在使用 Apache POI 库创建文件并将其保存到本地驱动器。有没有办法启动 Excel 并填充数据而不将其保存到硬盘驱动器? 最佳答案 考虑 Do
我有一个黑盒函数,它接受大约 10 个整数输入。该函数返回一个 pandas 数据框,我想捕获输出窗口(通过使用 bbwidget.children)并显示在布局中的其他地方。到目前为止,交互/交互似
我正在体验新的 QQuickWidget。我如何在 QQuickWidget 和 C++ 之间进行交互? C++ QQuickWidget *view = new QQuickWidget(); vi
我正在尝试设置一个使用 TWAIN 的 C# 应用程序 example from code project 除了我需要将 Form 转换为 IMessageFilter 和调用 IMessageFil
我想在使用 redis 的 python 中编写应用程序。我用谷歌搜索,但找不到我的问题的任何结果。通常,我这样做: import redis rs = redis.Redis('localhost'
最近做一个小项目,网页中嵌入google maps,输入经纬度坐标可以定位地图位置并加注标记,点击标记获取远端摄像头数据并在视频窗口实现播放。在实际操作过程中,由于经纬度数据和视频登录的用户名密码数
我需要在这里澄清一些事情: 我有一个网站,每次在浏览器中重新加载网站时都会更新两个变量的值。这个页面显然是一个 HTML 页面,但变量是由 javascript 函数更新的。此页面在我的服务器上运行。
我注意到,auto忽略双条件。这是一个简化的示例: Parameter A B : Prop. Parameter A_iff_B : A B. Theorem foo1: A -> B. Proo
使用 interactive使用多个小部件相当简单,例如: interactive(foo, w1=widget1, w2=widget2, ...) 但是,我想使用 VBox 和 HBox 的组合以
我们提供类似于 imagemagick 的浏览器页面 JavaScript,可帮助人们将图像转换为不同大小和格式。但是,它需要网页交互。 是否可以让人们自动进行这种交互——无需将图像发送到我们的服务器
大家好,我正在尝试制作一个具有大量动画和效果的交互式 UI。 但我不知道是否: 核心图形可以支持用户交互(触摸、拖动等) 核心图形支持对象旋转 核心图形可以以任何方式与 UIKit 和核心动画交互 谢
这是获取维基百科上一篇关于高盛的文章的介绍的链接。 http://en.wikipedia.org/w/api.php?action=query&prop=extracts&titles=Goldma
我正在尝试编写一个 AppleScript 来查询 iCal 并在任何日历中查找给定日期的所有事件。 我首先编写了一个简单的脚本,它对给定日历中的每个事件执行一些简单的操作: tell applica
我在我的 hudson 服务器上使用 jira 插件。将代码提交到 svn 时,我的提交注释包含在我的 jira 问题中,但有什么办法可以将注释归因于执行提交的实际人员,而不是让一个全局 jira 用
我正在播放一段视频来装饰我的用户界面。我隐藏了 AV 播放器控件,但用户仍然可以控制视频。例如,他们可以使用滑动手势快进或快退。 这让我特别惊讶,因为 AVPlayerView 上面有一个覆盖 Vie
我是一名优秀的程序员,十分优秀!