NetBeans项目

迷宫绘图程序

迷宫绘图程序是一个简单的绘图程序,我们将使用它来设置迷宫并在迷宫中放置物体。在下一个家庭作业中,你将编写一个游戏程序来加载迷宫绘图程序创建的迷宫。

版本1

在第一个版本中,我们将实现一个绘图程序,允许用户绘制迷宫中的墙壁。

迷宫中的墙壁由Wall类表示。

public class Wall {private Line Line;private double snap(double x){长n = Math。舍入(x / 40);返回n * 40.0;} public Wall(双x,双y) {line = new line ();line.setStartX(提前(x));line.setStartY(提前(y));line.setEndX (x);line.setEndY (y);}公共形状getShape(){返回行;}公共无效的setEnd(双x,双y) {line.setEndX(x);line.setEndY (y);}公共无效snapToGrid(双x,双y){双deltaX =数学。abs(x - line.getStartX());double deltaY =数学。abs(y - line.getStartY());if (deltaX > deltaY) {line.setEndX(snap(x));line.setEndY (line.getStartY ());} else {line.setEndX(line.getStartX());line.setEndY(提前(y));}}公共void write(printwwriter out) {out.println(Math.round(line.getStartX()) + " " + Math.round(line.getStartY()) + " " + Math.round(line.getEndX()) + " " + Math.round(line.getEndY()));}}

墙壁本质上是一行,添加了一些额外的方法来支持用鼠标放置墙壁并将墙壁写入文本文件。这个类中的大多数方法都支持用鼠标绘制墙壁。在下一节中,当我讨论绘图程序如何处理鼠标交互时,我们将看到这些方法中的大多数是用来做什么的。

MazePane类

赢博体育程序中最重要的类是MazePane类,它实现了一个允许我们绘制迷宫的自定义组件。

公共类MazePane扩展窗格{私有数组列表<墙>墙;私墙拖拽;public MazePane() {walls = new ArrayList<Wall>();For (int row = 0;行<= 11;Row ++) {for (int col = 0;<= 16;col++) {Circle Circle = new Circle();圆。setCenterX(col * 40);圆。setCenterY(行* 40);circle.setFill (Color.RED);circle.setRadius (2);this.getChildren阀门()(圆);}}这个。setOnMousePressed(e -> startDrag(e));这一点。setonmousedrag (e ->);这一点。setonmouserreleased (e ->);}公共无效startDrag(MouseEvent e){拖动=新墙(e.getX(), e.getY());walls.add(拖);this.getChildren阀门()(dragging.getShape ());}公共无效dragSegment(MouseEvent e) {draging . setend (e.getX(), e.getY());}公共无效endDrag(MouseEvent e) {drag . snaptogrid (e.getX(), e.getY());拖拽= null;} public void save() {try {PrintWriter out = new PrintWriter(new File("maze.txt"));out.println (walls.size ());for (Wall w: walls) {w.write(out);} out.close ();} catch (Exception ex) {ex. printstacktrace ();}}

MazePane本质上是Wall对象列表的容器,以及用于绘制引导点网格的代码和用于处理放置墙壁的鼠标交互的代码。

MazePane类的构造函数通过构造大量的小Circle对象并将它们添加到窗格中来设置引导点网格。

处理鼠标交互

JavaFX赢博体育程序是GUI赢博体育程序。GUI赢博体育程序中最重要的事情是处理用户事件。当GUI赢博体育程序的用户按下键盘上的一个键、移动鼠标或单击鼠标上的一个按钮时,我们就说用户生成了一个事件。必须对GUI赢博体育程序进行设置,以便在这些事件发生时做出响应。对于自定义窗格尤其如此:我们必须编写自己的赢博体育逻辑,以便自定义窗格在用户事件发生时响应。在这个示例赢博体育程序中,我将展示如何设置一个自定义窗格来响应鼠标事件。在迷宫绘图程序的第二个版本中,我将演示如何添加对键盘事件的支持。

要在迷宫绘图程序中放置墙壁,用户将首先在迷宫窗格的某处单击鼠标左键。鼠标的初始按下将开始鼠标拖动,用户在移动鼠标时按住鼠标按钮。当用户释放鼠标按钮时,鼠标拖动将结束。这些不同的操作,按下鼠标按钮、按住鼠标移动鼠标和释放鼠标,都被认为是不同的用户事件。JavaFX希望我们分别响应这些事件。

要响应JavaFX中的用户事件,需要为相关事件设置一个事件侦听器。要在MazePane类中设置事件侦听器,我们对MazePane构造函数中的setOn方法进行一系列调用。其中每一个都为不同的事件类型设置了不同的侦听器。

这一点。setOnMousePressed(e -> startDrag(e));这一点。setonmousedrag (e ->);这一点。setonmouserreleased (e ->);

在JavaFX中设置事件侦听器的最简单方法是使用lambda表达式。在本例中,我们使用lambda表达式调用MazePane类中的方法来响应每种不同的事件类型。

这些事件处理方法中的每一个都接受一个参数,即javafx.scene.input.MouseEvent类型的对象。MouseEvent对象携带有关用户生成事件时鼠标正在做什么的信息。最重要的是,当用户生成事件时,MouseEvent对象可以告诉我们鼠标在窗格中的位置。

绘制墙段的过程始于鼠标的初始按下。MazePane通过调用这个方法来响应鼠标按下:

公共无效startDrag(MouseEvent e){拖动=新墙(e.getX(), e.getY());walls.add(拖);this.getChildren阀门()(dragging.getShape ());}

此方法创建一个新的Wall对象,该对象的一端连接到最近的网格点,另一端设置为鼠标位置。我们要求Wall对象提供它所包含的Line对象,这样我们就可以将Line添加到子列表中。没有这一步,这条线就画不出来。

当用户拖动鼠标时,我们将设置用户正在拖动的Wall的末端位置。在MazePane类中我们做到了

公共无效dragSegment(MouseEvent e) {drag . setend (e.getX(), e.getY());}

而在长城,我们有

public void setEnd(double x, double y) {line.setEndX(x);line.setEndY (y);}

一旦用户松开鼠标按钮,拖动将结束。释放鼠标按钮会生成一个鼠标释放事件,该事件由MazePane中的这个方法处理:

公共无效endDrag(MouseEvent e) {drag . snaptogrid (e.getX(), e.getY());拖拽= null;}

Wall类中的snapToGrid()方法处理赢博体育程序逻辑的一个重要部分。因为我们希望将迷宫中的墙壁限制在网格点开始和结束,并且我们还希望将墙壁严格限制为水平或垂直,所以我们需要逻辑来执行这些约束。

公共无效snapToGrid(双x,双y){双deltaX =数学。abs(x - line.getStartX());double deltaY =数学。abs(y - line.getStartY());if (deltaX > deltaY) {line.setEndX(snap(x));line.setEndY (line.getStartY ());} else {line.setEndX(line.getStartX());line.setEndY(提前(y));}}

这里的逻辑决定用户绘制的线是更接近水平线还是垂直线,然后强制该线是水平的还是垂直的,其端点与最近的网格点相连。

拯救迷宫

我们的迷宫绘图赢博体育程序的最后一个重要特性是能够将绘图保存到文本文件中。为了支持这个功能,MazePane类有一个save()方法来保存迷宫的内容到一个文本文件:

public void save() {try {PrintWriter out = new PrintWriter(new File("maze.txt"));out.println (walls.size ());for (Wall w: walls) {w.write(out);} out.close ();} catch (Exception ex) {ex. printstacktrace ();}}

Wall类还有一个write()方法,Wall可以使用该方法将自身写入文本文件。

public void write(printwwriter out) {out.println(Math.round(line.getStartX()) + " " + Math.round(line.getStartY()) + " " + Math.round(line.getEndX()) + " " + Math.round(line.getEndY()));}