nodezscene.java

来自「java learn PPT java learn PPT java learn」· Java 代码 · 共 356 行

JAVA
356
字号
     import java.awt.*;
     import java.awt.event.*;
     import java.awt.geom.*;
     import java.util.*;

     import magic.gamelet.*;
     import magic.actor2d.*;
     import magic.debug.*;
     import magic.scene.*;
     import magic.graphics.*;

     public class NodezScene extends Scene
     {
          // 装载节点相关信息的ActorGroup2D对象
          private NodeGroup nodeGroup;

          // 容纳实际节点的Vector
          private Vector nodes; 

          // 连接节点的线条的颜色和笔划
          private final Color  CIRCUIT_COLOR  = new Color(255, 50, 50);
          private final Stroke CIRCUIT_STROKE = new BasicStroke(4.0f);

          // 绘制线圈的线条的2-D数组
          // 比如, { 2, 3 }将在索引为2和3的节点间连接一条线
          private int[][] circuits;

          // 上述数组中的线条相互连接的索引对          
          private Line2D[] circuitLines;

          // 用户的选择
          private Node selection1;
          private Node selection2;

          // 根据传入的边界和Applet引用创建一个 NodezScene 对象
          public NodezScene(Rectangle2D r, java.applet.Applet a)
          {
               super(r, r);

               // 为Nodez创建并初始化一个新的 NodezGroup 对象
               nodeGroup = new NodeGroup();
               nodeGroup.init(a);

               // 创建vector并初始化选择
               nodes = new Vector();
               selection1 = null;
               selection2 = null;
          }

          // 通过把它添加到nodez vector去的方法在画面中添加一个节点
          public void add(Actor2D a)
          {
               nodes.add(a);
          }

          // 把传入的级别加载到画面中
          public void loadLevel(int level)
          {
               // 用给定的级别数得到一个静态的NodezLevel结构.
               NodezLevel nodezLevel = NodezLevel.getLevel(level);

               // 返回值为null表明没有级别数据匹配这个级别数
               if(nodezLevel == null)
               {
                    Debugger.reportError(Debugger.FATAL_ERROR, "Invalid level specification",0);
                    return;
               }

               // 从level结构中获得 1)节点的位置和 2) 线圈的索引数组
               Vector2D[] nodePos  = nodezLevel.getNodePos();
               circuits = nodezLevel.getCircuits();

               // 清除Vector和选择
               nodes.clear();
               selection1 = null;
               selection2 = null;

               // 节点将相对窗体的中心放置所以它们会适应不同大小的窗体
               double anchorX = getBounds().getWidth()  * 0.5f;
               double anchorY = getBounds().getHeight() * 0.5f;

               // 给level结构中的每一个位置创建一个 Node
               for(int i = 0; i < nodePos.length; i++)
               {
                    // 用给定的 NodeGroup, 索引和位置创建一个节点
                    Node n = new Node(nodeGroup, i, new Vector2D.Double(anchorX + nodePos[i].getX(),
                                                                        anchorY + nodePos[i].getY()));

                    add(n);
               }

               // 创建索引为[0, nodes.length-1]的数组,并对这个数组进行随机化
               // 这个随机数组将作为节点的目标索引

               int[] indexDest = new int[nodes.size()];
               for(int i = 0; i < indexDest.length; i++)
               {
                    indexDest[i] = i;
               }

               // 不断随机产生并填充目标索引直到有一些节点开始就正确
               do
               {
                    Random r = new Random();
                    for(int i = 0; i < indexDest.length; i++)
                    {
                         int temp = indexDest[i];
                         int rand = r.nextInt(indexDest.length);
                    
                         indexDest[i] = indexDest[rand];
                         indexDest[rand] = temp;
                    }

                    int j = 0;
                    for(Enumeration e = nodes.elements(); e.hasMoreElements(); )
                    {
                         ((Node) e.nextElement()).setCircuitIndexDest(indexDest[j++]);
                    } 
               
               }    while(getNumCorrect() > 0);


               // 填充x,y线条值
               Node node1;
               Node node2;
               circuitLines = new Line2D.Double[circuits.length];
               for(int i = 0; i < circuits.length; i++)
               {
                    // 得到节点0和1等等...
                    node1 = (Node)nodes.get(circuits[i][0]);
                    node2 = (Node)nodes.get(circuits[i][1]);

                    // ...把它们的 x, y 值填充到线条数组中
                    circuitLines[i] = new Line2D.Double(node1.getX(), node1.getY(),
                                                        node2.getX(), node2.getY());
               }
              
          }

          // 从画面中得到NodeGroup
          public NodeGroup getNodeGroup()
          {
               return nodeGroup;
          }

          // 返回当前局中节点的数目
          public int getNumNodes()
          {
               return nodes.size();
          }

          // 返回正确的节点的数目
          public int getNumCorrect()
          {
               int numCorrect = 0;
               for(Enumeration e = nodes.elements(); e.hasMoreElements(); )
               {
                    if(((Node) e.nextElement()).isCorrect())
                    {
                         ++ numCorrect;
                    }
               }
               return numCorrect; 
          }

          // 处理在传入的Node对象上进行的鼠标左击事件    
          private void processLeftClick(Node n)
          {
               // 如果第一个选择没有设置,那么现在设置它 
               if(selection1 == null)
               {
                    selection1 = n;

                    // 确保节点是按照1,2的顺序选择的
                    if(selection2 != null)
                    {
                         selection2.setSelected(false);
                    }
                    n.setSelected(true);

                    // 播放做出选择的声音
                    Gamelet.playSound(Nodez.NODE_SELECTED1, false);
                    return;
               }

               // 否则,选择第二个节点并测试交换               
               else 
               {
                    selection2 = n;
                    selection2.setSelected(true);

                    // 播放做出选择的声音
                    Gamelet.playSound(Nodez.NODE_SELECTED2, false);

                    // 如果同一个节点被选中两次,则取消它的选中状态
                    if(selection1 == selection2)
                    {
                         selection1.setSelected(false);

                         selection1 = null;    
                         selection2 = null;
                    }

                    // 否则,测试节点的交换
                    else if(canSwap(selection1.getCircuitIndex(), selection2.getCircuitIndex()))
                    {
                         // 交换节点
                         Node.swap(selection1, selection2);

                         // 重置选择
                         selection1 = null;

                          // 检测这样做是不是已经解开了难题
                         if(getNumCorrect() == getNumNodes())
                         {
                              Gamelet.playSound(Nodez.GAME_OVER, false);
                         }
                    }

                    // 不应该做交换; 交换选项1的设置到选项2
                    // 这样可以按照这个顺序做匹配
                    else
                    {
                         selection1.setSelected(false);
                         selection1 = selection2;
                    }
               }
          }    // processLeftClick

          // 处理给定节点上的右击事件-- this will toggle the flagged
          // state of the node
          private void processRightClick(Node n)
          {
               n.toggleFlagged();

               // 根据标记的状态播放声音
               if(n.isFlagged())
               {
                    Gamelet.playSound(Nodez.TOGGLE_FLAG_ON, false);
               }
               else
               {
                    Gamelet.playSound(Nodez.TOGGLE_FLAG_OFF, false);
               }
          }

          // 处理给定的点上的鼠标点击事件 (左击或者右击)         
          public void processMouseClick(Point p, int button)
          {
               // 看看哪一个节点包含了所传入的点
               Node n;
               for(Enumeration e = nodes.elements(); e.hasMoreElements(); )
               {
                    n = (Node) e.nextElement();

                    // 只有 "静止"的节点才能被选中
                    if(! n.isMoving())
                    {
                         // 如果节点包含这个点,则在它上面执行动作
                         if(n.contains(p)) 
                         {
                              if(button == MouseEvent.BUTTON1)
                              {
                                   processLeftClick(n);
                              }
                              else if(button == MouseEvent.BUTTON3)
                              {
                                   processRightClick(n);
                              }

                              return;
                         }
                    }
               } 
          }

          // 检测是否游戏终止--如果画面上所有的节点都被正确放置则游戏终止
          public boolean gameOver()
          {
               return (getNumCorrect() == getNumNodes());
          }

          // 判断画面是否已经 "安置好了";也就是说,是否有节点还在移动
          public boolean isSettled()
          {
               for(Enumeration e = nodes.elements(); e.hasMoreElements(); )
               {
                    if(((Node) e.nextElement()).isMoving())
                    {
                         return false;
                    }
               } 

               return true;
          }

          // 判断两个节点是否可以互换; 也就是说,它们是否通过一般的线圈线条连接
          private boolean canSwap(
               int x,   // 第一个节点的索引
               int y    // 第二个节点的索引
               )
          {
               // 不要让一个节点和它自己交换
               if(x == y) 
               {
                    return false;
               }

               // 这个测试理解起来比较麻烦.
               // 如果 x = 2 并且 y = 3, 那么我们将需要找到一个回路
               // 这个回路的第一个值是2或者3并且它的第二个值也是2或者3

               int len = circuits.length;
               for(int i = 0; i < len; i++)
               {
                    if( (circuits[i][0] == x || circuits[i][0] == y) &&
                        (circuits[i][1] == x || circuits[i][1] == y))
                    {
                         return true;
                    }
               }

               return false;
          }

          // 更新节点元素Vector
          public void update()
          {
               for(Enumeration e = nodes.elements(); e.hasMoreElements(); )
               {
                    ((Node) e.nextElement()).update();
               } 
          }

          // 绘制画面        
          public void paint(Graphics2D g2d)
          {
               // 首先绘制节点回路
               g2d.setPaint(CIRCUIT_COLOR);
               g2d.setStroke(CIRCUIT_STROKE);
               for(int i = 0; i < circuitLines.length; i++)
               {
                    g2d.draw(circuitLines[i]);
               }

               // 创建一个透明度为25%的合成
               g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 0.75f));

               // 绘制节点
               for(Enumeration e = nodes.elements(); e.hasMoreElements(); )
               {
                    ((Node) e.nextElement()).paint(g2d);
               } 
          }

     }    // NodezScene

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?