diff --git a/FishGame/bin/com/mypro/base/graphics/Bitmap.class b/FishGame/bin/com/mypro/base/graphics/Bitmap.class deleted file mode 100644 index 77b0b90..0000000 Binary files a/FishGame/bin/com/mypro/base/graphics/Bitmap.class and /dev/null differ diff --git a/FishGame/bin/com/mypro/base/graphics/Canvas.class b/FishGame/bin/com/mypro/base/graphics/Canvas.class deleted file mode 100644 index 9c8af2b..0000000 Binary files a/FishGame/bin/com/mypro/base/graphics/Canvas.class and /dev/null differ diff --git a/FishGame/bin/com/mypro/base/graphics/Matrix.class b/FishGame/bin/com/mypro/base/graphics/Matrix.class deleted file mode 100644 index cf1e9fd..0000000 Binary files a/FishGame/bin/com/mypro/base/graphics/Matrix.class and /dev/null differ diff --git a/FishGame/bin/com/mypro/base/graphics/Paint.class b/FishGame/bin/com/mypro/base/graphics/Paint.class deleted file mode 100644 index 9a24c50..0000000 Binary files a/FishGame/bin/com/mypro/base/graphics/Paint.class and /dev/null differ diff --git a/FishGame/bin/com/mypro/base/tools/Log.class b/FishGame/bin/com/mypro/base/tools/Log.class deleted file mode 100644 index 6113e42..0000000 Binary files a/FishGame/bin/com/mypro/base/tools/Log.class and /dev/null differ diff --git a/FishGame/bin/com/mypro/basecomponet/AwtMainComponet$1.class b/FishGame/bin/com/mypro/basecomponet/AwtMainComponet$1.class deleted file mode 100644 index 7d9426d..0000000 Binary files a/FishGame/bin/com/mypro/basecomponet/AwtMainComponet$1.class and /dev/null differ diff --git a/FishGame/bin/com/mypro/basecomponet/AwtMainComponet$2.class b/FishGame/bin/com/mypro/basecomponet/AwtMainComponet$2.class deleted file mode 100644 index 06e9f4e..0000000 Binary files a/FishGame/bin/com/mypro/basecomponet/AwtMainComponet$2.class and /dev/null differ diff --git a/FishGame/bin/com/mypro/basecomponet/AwtMainComponet$3.class b/FishGame/bin/com/mypro/basecomponet/AwtMainComponet$3.class deleted file mode 100644 index 7bcbbf3..0000000 Binary files a/FishGame/bin/com/mypro/basecomponet/AwtMainComponet$3.class and /dev/null differ diff --git a/FishGame/bin/com/mypro/basecomponet/AwtMainComponet.class b/FishGame/bin/com/mypro/basecomponet/AwtMainComponet.class deleted file mode 100644 index b694684..0000000 Binary files a/FishGame/bin/com/mypro/basecomponet/AwtMainComponet.class and /dev/null differ diff --git a/FishGame/bin/com/mypro/basecomponet/JMatrix.class b/FishGame/bin/com/mypro/basecomponet/JMatrix.class deleted file mode 100644 index 562dbd0..0000000 Binary files a/FishGame/bin/com/mypro/basecomponet/JMatrix.class and /dev/null differ diff --git a/FishGame/bin/com/mypro/constant/Constant.class b/FishGame/bin/com/mypro/constant/Constant.class deleted file mode 100644 index cc226c7..0000000 Binary files a/FishGame/bin/com/mypro/constant/Constant.class and /dev/null differ diff --git a/FishGame/bin/com/mypro/mainsurface/MainSurface$JCanvas$JPaint.class b/FishGame/bin/com/mypro/mainsurface/MainSurface$JCanvas$JPaint.class deleted file mode 100644 index 4d42b5a..0000000 Binary files a/FishGame/bin/com/mypro/mainsurface/MainSurface$JCanvas$JPaint.class and /dev/null differ diff --git a/FishGame/bin/com/mypro/mainsurface/MainSurface$JCanvas.class b/FishGame/bin/com/mypro/mainsurface/MainSurface$JCanvas.class deleted file mode 100644 index cafdce3..0000000 Binary files a/FishGame/bin/com/mypro/mainsurface/MainSurface$JCanvas.class and /dev/null differ diff --git a/FishGame/bin/com/mypro/mainsurface/MainSurface$OnDrawThread.class b/FishGame/bin/com/mypro/mainsurface/MainSurface$OnDrawThread.class deleted file mode 100644 index cac5adf..0000000 Binary files a/FishGame/bin/com/mypro/mainsurface/MainSurface$OnDrawThread.class and /dev/null differ diff --git a/FishGame/bin/com/mypro/mainsurface/MainSurface.class b/FishGame/bin/com/mypro/mainsurface/MainSurface.class deleted file mode 100644 index f59ae3d..0000000 Binary files a/FishGame/bin/com/mypro/mainsurface/MainSurface.class and /dev/null differ diff --git a/FishGame/bin/com/mypro/manager/CannonManager$1.class b/FishGame/bin/com/mypro/manager/CannonManager$1.class deleted file mode 100644 index 37634ff..0000000 Binary files a/FishGame/bin/com/mypro/manager/CannonManager$1.class and /dev/null differ diff --git a/FishGame/bin/com/mypro/manager/CannonManager.class b/FishGame/bin/com/mypro/manager/CannonManager.class deleted file mode 100644 index 2a3e18e..0000000 Binary files a/FishGame/bin/com/mypro/manager/CannonManager.class and /dev/null differ diff --git a/FishGame/bin/com/mypro/manager/CatchFishManager$1.class b/FishGame/bin/com/mypro/manager/CatchFishManager$1.class deleted file mode 100644 index aa28dd8..0000000 Binary files a/FishGame/bin/com/mypro/manager/CatchFishManager$1.class and /dev/null differ diff --git a/FishGame/bin/com/mypro/manager/CatchFishManager$2.class b/FishGame/bin/com/mypro/manager/CatchFishManager$2.class deleted file mode 100644 index 2fa501e..0000000 Binary files a/FishGame/bin/com/mypro/manager/CatchFishManager$2.class and /dev/null differ diff --git a/FishGame/bin/com/mypro/manager/CatchFishManager.class b/FishGame/bin/com/mypro/manager/CatchFishManager.class deleted file mode 100644 index f53df02..0000000 Binary files a/FishGame/bin/com/mypro/manager/CatchFishManager.class and /dev/null differ diff --git a/FishGame/bin/com/mypro/manager/FishManager.class b/FishGame/bin/com/mypro/manager/FishManager.class deleted file mode 100644 index a0daeb9..0000000 Binary files a/FishGame/bin/com/mypro/manager/FishManager.class and /dev/null differ diff --git a/FishGame/bin/com/mypro/manager/GameInitManager.class b/FishGame/bin/com/mypro/manager/GameInitManager.class deleted file mode 100644 index 472f941..0000000 Binary files a/FishGame/bin/com/mypro/manager/GameInitManager.class and /dev/null differ diff --git a/FishGame/bin/com/mypro/manager/GamePartInfo.class b/FishGame/bin/com/mypro/manager/GamePartInfo.class deleted file mode 100644 index 8147b3e..0000000 Binary files a/FishGame/bin/com/mypro/manager/GamePartInfo.class and /dev/null differ diff --git a/FishGame/bin/com/mypro/manager/GamePartManager$1.class b/FishGame/bin/com/mypro/manager/GamePartManager$1.class deleted file mode 100644 index 87b4125..0000000 Binary files a/FishGame/bin/com/mypro/manager/GamePartManager$1.class and /dev/null differ diff --git a/FishGame/bin/com/mypro/manager/GamePartManager.class b/FishGame/bin/com/mypro/manager/GamePartManager.class deleted file mode 100644 index b6c87d0..0000000 Binary files a/FishGame/bin/com/mypro/manager/GamePartManager.class and /dev/null differ diff --git a/FishGame/bin/com/mypro/manager/HeadFish.class b/FishGame/bin/com/mypro/manager/HeadFish.class deleted file mode 100644 index 29b4ce3..0000000 Binary files a/FishGame/bin/com/mypro/manager/HeadFish.class and /dev/null differ diff --git a/FishGame/bin/com/mypro/manager/ImageConfig$ActConfig.class b/FishGame/bin/com/mypro/manager/ImageConfig$ActConfig.class deleted file mode 100644 index a2679b7..0000000 Binary files a/FishGame/bin/com/mypro/manager/ImageConfig$ActConfig.class and /dev/null differ diff --git a/FishGame/bin/com/mypro/manager/ImageConfig.class b/FishGame/bin/com/mypro/manager/ImageConfig.class deleted file mode 100644 index ee72d52..0000000 Binary files a/FishGame/bin/com/mypro/manager/ImageConfig.class and /dev/null differ diff --git a/FishGame/bin/com/mypro/manager/ImageManager.class b/FishGame/bin/com/mypro/manager/ImageManager.class deleted file mode 100644 index 7f0e173..0000000 Binary files a/FishGame/bin/com/mypro/manager/ImageManager.class and /dev/null differ diff --git a/FishGame/bin/com/mypro/manager/LayoutInfo.class b/FishGame/bin/com/mypro/manager/LayoutInfo.class deleted file mode 100644 index 6d56d7e..0000000 Binary files a/FishGame/bin/com/mypro/manager/LayoutInfo.class and /dev/null differ diff --git a/FishGame/bin/com/mypro/manager/LayoutManager$1.class b/FishGame/bin/com/mypro/manager/LayoutManager$1.class deleted file mode 100644 index 96f5f1b..0000000 Binary files a/FishGame/bin/com/mypro/manager/LayoutManager$1.class and /dev/null differ diff --git a/FishGame/bin/com/mypro/manager/LayoutManager.class b/FishGame/bin/com/mypro/manager/LayoutManager.class deleted file mode 100644 index 3219bbe..0000000 Binary files a/FishGame/bin/com/mypro/manager/LayoutManager.class and /dev/null differ diff --git a/FishGame/bin/com/mypro/manager/PathManager.class b/FishGame/bin/com/mypro/manager/PathManager.class deleted file mode 100644 index 6ef0348..0000000 Binary files a/FishGame/bin/com/mypro/manager/PathManager.class and /dev/null differ diff --git a/FishGame/bin/com/mypro/manager/ScoreManager$1.class b/FishGame/bin/com/mypro/manager/ScoreManager$1.class deleted file mode 100644 index 6f13bc2..0000000 Binary files a/FishGame/bin/com/mypro/manager/ScoreManager$1.class and /dev/null differ diff --git a/FishGame/bin/com/mypro/manager/ScoreManager$2.class b/FishGame/bin/com/mypro/manager/ScoreManager$2.class deleted file mode 100644 index 03f8f79..0000000 Binary files a/FishGame/bin/com/mypro/manager/ScoreManager$2.class and /dev/null differ diff --git a/FishGame/bin/com/mypro/manager/ScoreManager$3.class b/FishGame/bin/com/mypro/manager/ScoreManager$3.class deleted file mode 100644 index 61dd6db..0000000 Binary files a/FishGame/bin/com/mypro/manager/ScoreManager$3.class and /dev/null differ diff --git a/FishGame/bin/com/mypro/manager/ScoreManager.class b/FishGame/bin/com/mypro/manager/ScoreManager.class deleted file mode 100644 index 94408a0..0000000 Binary files a/FishGame/bin/com/mypro/manager/ScoreManager.class and /dev/null differ diff --git a/FishGame/bin/com/mypro/manager/ShoalManager$1.class b/FishGame/bin/com/mypro/manager/ShoalManager$1.class deleted file mode 100644 index da512d0..0000000 Binary files a/FishGame/bin/com/mypro/manager/ShoalManager$1.class and /dev/null differ diff --git a/FishGame/bin/com/mypro/manager/ShoalManager$2.class b/FishGame/bin/com/mypro/manager/ShoalManager$2.class deleted file mode 100644 index 519f080..0000000 Binary files a/FishGame/bin/com/mypro/manager/ShoalManager$2.class and /dev/null differ diff --git a/FishGame/bin/com/mypro/manager/ShoalManager.class b/FishGame/bin/com/mypro/manager/ShoalManager.class deleted file mode 100644 index 9e9283b..0000000 Binary files a/FishGame/bin/com/mypro/manager/ShoalManager.class and /dev/null differ diff --git a/FishGame/bin/com/mypro/manager/XmlManager.class b/FishGame/bin/com/mypro/manager/XmlManager.class deleted file mode 100644 index 1b9c1a5..0000000 Binary files a/FishGame/bin/com/mypro/manager/XmlManager.class and /dev/null differ diff --git a/FishGame/bin/com/mypro/model/Ammo.class b/FishGame/bin/com/mypro/model/Ammo.class deleted file mode 100644 index 4975212..0000000 Binary files a/FishGame/bin/com/mypro/model/Ammo.class and /dev/null differ diff --git a/FishGame/bin/com/mypro/model/BackGround.class b/FishGame/bin/com/mypro/model/BackGround.class deleted file mode 100644 index ea76bb6..0000000 Binary files a/FishGame/bin/com/mypro/model/BackGround.class and /dev/null differ diff --git a/FishGame/bin/com/mypro/model/DrawableAdapter.class b/FishGame/bin/com/mypro/model/DrawableAdapter.class deleted file mode 100644 index ecd3e58..0000000 Binary files a/FishGame/bin/com/mypro/model/DrawableAdapter.class and /dev/null differ diff --git a/FishGame/bin/com/mypro/model/FishGold.class b/FishGame/bin/com/mypro/model/FishGold.class deleted file mode 100644 index ee9b46c..0000000 Binary files a/FishGame/bin/com/mypro/model/FishGold.class and /dev/null differ diff --git a/FishGame/bin/com/mypro/model/FishInfo.class b/FishGame/bin/com/mypro/model/FishInfo.class deleted file mode 100644 index 1085b36..0000000 Binary files a/FishGame/bin/com/mypro/model/FishInfo.class and /dev/null differ diff --git a/FishGame/bin/com/mypro/model/FishingNet.class b/FishGame/bin/com/mypro/model/FishingNet.class deleted file mode 100644 index e81a727..0000000 Binary files a/FishGame/bin/com/mypro/model/FishingNet.class and /dev/null differ diff --git a/FishGame/bin/com/mypro/model/GamingInfo.class b/FishGame/bin/com/mypro/model/GamingInfo.class deleted file mode 100644 index 830f835..0000000 Binary files a/FishGame/bin/com/mypro/model/GamingInfo.class and /dev/null differ diff --git a/FishGame/bin/com/mypro/model/HighPoint.class b/FishGame/bin/com/mypro/model/HighPoint.class deleted file mode 100644 index aaebc19..0000000 Binary files a/FishGame/bin/com/mypro/model/HighPoint.class and /dev/null differ diff --git a/FishGame/bin/com/mypro/model/HundredPoint.class b/FishGame/bin/com/mypro/model/HundredPoint.class deleted file mode 100644 index fe326f3..0000000 Binary files a/FishGame/bin/com/mypro/model/HundredPoint.class and /dev/null differ diff --git a/FishGame/bin/com/mypro/model/componets/Bottom.class b/FishGame/bin/com/mypro/model/componets/Bottom.class deleted file mode 100644 index 10f6755..0000000 Binary files a/FishGame/bin/com/mypro/model/componets/Bottom.class and /dev/null differ diff --git a/FishGame/bin/com/mypro/model/componets/BottomGold.class b/FishGame/bin/com/mypro/model/componets/BottomGold.class deleted file mode 100644 index 750c110..0000000 Binary files a/FishGame/bin/com/mypro/model/componets/BottomGold.class and /dev/null differ diff --git a/FishGame/bin/com/mypro/model/componets/BottomTime.class b/FishGame/bin/com/mypro/model/componets/BottomTime.class deleted file mode 100644 index e8703f0..0000000 Binary files a/FishGame/bin/com/mypro/model/componets/BottomTime.class and /dev/null differ diff --git a/FishGame/bin/com/mypro/model/componets/ButtonAdapter.class b/FishGame/bin/com/mypro/model/componets/ButtonAdapter.class deleted file mode 100644 index 4a8869a..0000000 Binary files a/FishGame/bin/com/mypro/model/componets/ButtonAdapter.class and /dev/null differ diff --git a/FishGame/bin/com/mypro/model/componets/Cannon$1.class b/FishGame/bin/com/mypro/model/componets/Cannon$1.class deleted file mode 100644 index a491439..0000000 Binary files a/FishGame/bin/com/mypro/model/componets/Cannon$1.class and /dev/null differ diff --git a/FishGame/bin/com/mypro/model/componets/Cannon.class b/FishGame/bin/com/mypro/model/componets/Cannon.class deleted file mode 100644 index 5e7cadf..0000000 Binary files a/FishGame/bin/com/mypro/model/componets/Cannon.class and /dev/null differ diff --git a/FishGame/bin/com/mypro/model/componets/Componet.class b/FishGame/bin/com/mypro/model/componets/Componet.class deleted file mode 100644 index a1fb181..0000000 Binary files a/FishGame/bin/com/mypro/model/componets/Componet.class and /dev/null differ diff --git a/FishGame/bin/com/mypro/model/componets/DownCannonButtonListener.class b/FishGame/bin/com/mypro/model/componets/DownCannonButtonListener.class deleted file mode 100644 index ae8c871..0000000 Binary files a/FishGame/bin/com/mypro/model/componets/DownCannonButtonListener.class and /dev/null differ diff --git a/FishGame/bin/com/mypro/model/componets/UpCannonButtonListener.class b/FishGame/bin/com/mypro/model/componets/UpCannonButtonListener.class deleted file mode 100644 index 1ca38df..0000000 Binary files a/FishGame/bin/com/mypro/model/componets/UpCannonButtonListener.class and /dev/null differ diff --git a/FishGame/bin/com/mypro/model/fish/Fish$1.class b/FishGame/bin/com/mypro/model/fish/Fish$1.class deleted file mode 100644 index 8354262..0000000 Binary files a/FishGame/bin/com/mypro/model/fish/Fish$1.class and /dev/null differ diff --git a/FishGame/bin/com/mypro/model/fish/Fish.class b/FishGame/bin/com/mypro/model/fish/Fish.class deleted file mode 100644 index d1827a7..0000000 Binary files a/FishGame/bin/com/mypro/model/fish/Fish.class and /dev/null differ diff --git a/FishGame/bin/com/mypro/model/interfaces/Button.class b/FishGame/bin/com/mypro/model/interfaces/Button.class deleted file mode 100644 index 1b8d768..0000000 Binary files a/FishGame/bin/com/mypro/model/interfaces/Button.class and /dev/null differ diff --git a/FishGame/bin/com/mypro/model/interfaces/Drawable.class b/FishGame/bin/com/mypro/model/interfaces/Drawable.class deleted file mode 100644 index d572e8d..0000000 Binary files a/FishGame/bin/com/mypro/model/interfaces/Drawable.class and /dev/null differ diff --git a/FishGame/bin/com/mypro/model/interfaces/OnClickListener.class b/FishGame/bin/com/mypro/model/interfaces/OnClickListener.class deleted file mode 100644 index d41d0ce..0000000 Binary files a/FishGame/bin/com/mypro/model/interfaces/OnClickListener.class and /dev/null differ diff --git a/FishGame/bin/com/mypro/threads/FishRunThread$1.class b/FishGame/bin/com/mypro/threads/FishRunThread$1.class deleted file mode 100644 index 07178f5..0000000 Binary files a/FishGame/bin/com/mypro/threads/FishRunThread$1.class and /dev/null differ diff --git a/FishGame/bin/com/mypro/threads/FishRunThread.class b/FishGame/bin/com/mypro/threads/FishRunThread.class deleted file mode 100644 index d9562f9..0000000 Binary files a/FishGame/bin/com/mypro/threads/FishRunThread.class and /dev/null differ diff --git a/FishGame/bin/com/mypro/threads/PicActThread.class b/FishGame/bin/com/mypro/threads/PicActThread.class deleted file mode 100644 index 2f7f9d0..0000000 Binary files a/FishGame/bin/com/mypro/threads/PicActThread.class and /dev/null differ diff --git a/FishGame/bin/com/mypro/threads/ShotThread$1.class b/FishGame/bin/com/mypro/threads/ShotThread$1.class deleted file mode 100644 index deeb060..0000000 Binary files a/FishGame/bin/com/mypro/threads/ShotThread$1.class and /dev/null differ diff --git a/FishGame/bin/com/mypro/threads/ShotThread.class b/FishGame/bin/com/mypro/threads/ShotThread.class deleted file mode 100644 index 0662904..0000000 Binary files a/FishGame/bin/com/mypro/threads/ShotThread.class and /dev/null differ diff --git a/FishGame/bin/com/mypro/tools/CircleRectangleIntersect.class b/FishGame/bin/com/mypro/tools/CircleRectangleIntersect.class deleted file mode 100644 index 3ce72c4..0000000 Binary files a/FishGame/bin/com/mypro/tools/CircleRectangleIntersect.class and /dev/null differ diff --git a/FishGame/bin/com/mypro/tools/LogTools.class b/FishGame/bin/com/mypro/tools/LogTools.class deleted file mode 100644 index 5be8377..0000000 Binary files a/FishGame/bin/com/mypro/tools/LogTools.class and /dev/null differ diff --git a/FishGame/bin/com/mypro/tools/Tool.class b/FishGame/bin/com/mypro/tools/Tool.class deleted file mode 100644 index 20519ed..0000000 Binary files a/FishGame/bin/com/mypro/tools/Tool.class and /dev/null differ diff --git a/Tetris/bin/tetris/Cell.class b/Tetris/bin/tetris/Cell.class new file mode 100644 index 0000000..190972a Binary files /dev/null and b/Tetris/bin/tetris/Cell.class differ diff --git a/Tetris/bin/tetris/GameConfig.class b/Tetris/bin/tetris/GameConfig.class new file mode 100644 index 0000000..77a9471 Binary files /dev/null and b/Tetris/bin/tetris/GameConfig.class differ diff --git a/Tetris/bin/tetris/GameManager.class b/Tetris/bin/tetris/GameManager.class new file mode 100644 index 0000000..b319e30 Binary files /dev/null and b/Tetris/bin/tetris/GameManager.class differ diff --git a/Tetris/bin/tetris/GameOverPanel$1.class b/Tetris/bin/tetris/GameOverPanel$1.class new file mode 100644 index 0000000..9422a86 Binary files /dev/null and b/Tetris/bin/tetris/GameOverPanel$1.class differ diff --git a/Tetris/bin/tetris/GameOverPanel$2.class b/Tetris/bin/tetris/GameOverPanel$2.class new file mode 100644 index 0000000..6d28814 Binary files /dev/null and b/Tetris/bin/tetris/GameOverPanel$2.class differ diff --git a/Tetris/bin/tetris/GameOverPanel$3.class b/Tetris/bin/tetris/GameOverPanel$3.class new file mode 100644 index 0000000..20a7a99 Binary files /dev/null and b/Tetris/bin/tetris/GameOverPanel$3.class differ diff --git a/Tetris/bin/tetris/GameOverPanel.class b/Tetris/bin/tetris/GameOverPanel.class new file mode 100644 index 0000000..9e77c01 Binary files /dev/null and b/Tetris/bin/tetris/GameOverPanel.class differ diff --git a/Tetris/bin/tetris/GameState.class b/Tetris/bin/tetris/GameState.class new file mode 100644 index 0000000..7be0d6a Binary files /dev/null and b/Tetris/bin/tetris/GameState.class differ diff --git a/Tetris/bin/tetris/MenuPanel$1.class b/Tetris/bin/tetris/MenuPanel$1.class new file mode 100644 index 0000000..0b0e1c2 Binary files /dev/null and b/Tetris/bin/tetris/MenuPanel$1.class differ diff --git a/Tetris/bin/tetris/MenuPanel$2.class b/Tetris/bin/tetris/MenuPanel$2.class new file mode 100644 index 0000000..7a91d69 Binary files /dev/null and b/Tetris/bin/tetris/MenuPanel$2.class differ diff --git a/Tetris/bin/tetris/MenuPanel$3.class b/Tetris/bin/tetris/MenuPanel$3.class new file mode 100644 index 0000000..7730fd5 Binary files /dev/null and b/Tetris/bin/tetris/MenuPanel$3.class differ diff --git a/Tetris/bin/tetris/MenuPanel$4.class b/Tetris/bin/tetris/MenuPanel$4.class new file mode 100644 index 0000000..1a9e772 Binary files /dev/null and b/Tetris/bin/tetris/MenuPanel$4.class differ diff --git a/Tetris/bin/tetris/MenuPanel.class b/Tetris/bin/tetris/MenuPanel.class new file mode 100644 index 0000000..a190232 Binary files /dev/null and b/Tetris/bin/tetris/MenuPanel.class differ diff --git a/Tetris/bin/tetris/SettingsPanel$1.class b/Tetris/bin/tetris/SettingsPanel$1.class new file mode 100644 index 0000000..283ef53 Binary files /dev/null and b/Tetris/bin/tetris/SettingsPanel$1.class differ diff --git a/Tetris/bin/tetris/SettingsPanel$2.class b/Tetris/bin/tetris/SettingsPanel$2.class new file mode 100644 index 0000000..0d8e5ef Binary files /dev/null and b/Tetris/bin/tetris/SettingsPanel$2.class differ diff --git a/Tetris/bin/tetris/SettingsPanel$3.class b/Tetris/bin/tetris/SettingsPanel$3.class new file mode 100644 index 0000000..f6f195f Binary files /dev/null and b/Tetris/bin/tetris/SettingsPanel$3.class differ diff --git a/Tetris/bin/tetris/SettingsPanel$4.class b/Tetris/bin/tetris/SettingsPanel$4.class new file mode 100644 index 0000000..38244b9 Binary files /dev/null and b/Tetris/bin/tetris/SettingsPanel$4.class differ diff --git a/Tetris/bin/tetris/SettingsPanel$5.class b/Tetris/bin/tetris/SettingsPanel$5.class new file mode 100644 index 0000000..ba4fd82 Binary files /dev/null and b/Tetris/bin/tetris/SettingsPanel$5.class differ diff --git a/Tetris/bin/tetris/SettingsPanel$6.class b/Tetris/bin/tetris/SettingsPanel$6.class new file mode 100644 index 0000000..a986268 Binary files /dev/null and b/Tetris/bin/tetris/SettingsPanel$6.class differ diff --git a/Tetris/bin/tetris/SettingsPanel.class b/Tetris/bin/tetris/SettingsPanel.class new file mode 100644 index 0000000..bd92539 Binary files /dev/null and b/Tetris/bin/tetris/SettingsPanel.class differ diff --git a/Tetris/bin/tetris/TetrisFrame$1.class b/Tetris/bin/tetris/TetrisFrame$1.class new file mode 100644 index 0000000..85edb2f Binary files /dev/null and b/Tetris/bin/tetris/TetrisFrame$1.class differ diff --git a/Tetris/bin/tetris/TetrisFrame.class b/Tetris/bin/tetris/TetrisFrame.class new file mode 100644 index 0000000..420818a Binary files /dev/null and b/Tetris/bin/tetris/TetrisFrame.class differ diff --git a/Tetris/bin/tetris/TetrisPane$1.class b/Tetris/bin/tetris/TetrisPane$1.class new file mode 100644 index 0000000..207fd8f Binary files /dev/null and b/Tetris/bin/tetris/TetrisPane$1.class differ diff --git a/Tetris/bin/tetris/TetrisPane$2.class b/Tetris/bin/tetris/TetrisPane$2.class new file mode 100644 index 0000000..8e9f285 Binary files /dev/null and b/Tetris/bin/tetris/TetrisPane$2.class differ diff --git a/Tetris/bin/tetris/TetrisPane$DropExecution.class b/Tetris/bin/tetris/TetrisPane$DropExecution.class new file mode 100644 index 0000000..2190d71 Binary files /dev/null and b/Tetris/bin/tetris/TetrisPane$DropExecution.class differ diff --git a/Tetris/bin/tetris/TetrisPane$IShaped.class b/Tetris/bin/tetris/TetrisPane$IShaped.class new file mode 100644 index 0000000..4d5a2e4 Binary files /dev/null and b/Tetris/bin/tetris/TetrisPane$IShaped.class differ diff --git a/Tetris/bin/tetris/TetrisPane$JShaped.class b/Tetris/bin/tetris/TetrisPane$JShaped.class new file mode 100644 index 0000000..0d26fa5 Binary files /dev/null and b/Tetris/bin/tetris/TetrisPane$JShaped.class differ diff --git a/Tetris/bin/tetris/TetrisPane$KeyControl.class b/Tetris/bin/tetris/TetrisPane$KeyControl.class new file mode 100644 index 0000000..8863316 Binary files /dev/null and b/Tetris/bin/tetris/TetrisPane$KeyControl.class differ diff --git a/Tetris/bin/tetris/TetrisPane$LShaped.class b/Tetris/bin/tetris/TetrisPane$LShaped.class new file mode 100644 index 0000000..8f0a633 Binary files /dev/null and b/Tetris/bin/tetris/TetrisPane$LShaped.class differ diff --git a/Tetris/bin/tetris/TetrisPane$OShaped.class b/Tetris/bin/tetris/TetrisPane$OShaped.class new file mode 100644 index 0000000..fc4d11a Binary files /dev/null and b/Tetris/bin/tetris/TetrisPane$OShaped.class differ diff --git a/Tetris/bin/tetris/TetrisPane$SShaped.class b/Tetris/bin/tetris/TetrisPane$SShaped.class new file mode 100644 index 0000000..60046eb Binary files /dev/null and b/Tetris/bin/tetris/TetrisPane$SShaped.class differ diff --git a/Tetris/bin/tetris/TetrisPane$TShaped.class b/Tetris/bin/tetris/TetrisPane$TShaped.class new file mode 100644 index 0000000..ef0d1e4 Binary files /dev/null and b/Tetris/bin/tetris/TetrisPane$TShaped.class differ diff --git a/Tetris/bin/tetris/TetrisPane$ZShaped.class b/Tetris/bin/tetris/TetrisPane$ZShaped.class new file mode 100644 index 0000000..b5ecd3d Binary files /dev/null and b/Tetris/bin/tetris/TetrisPane$ZShaped.class differ diff --git a/Tetris/bin/tetris/TetrisPane.class b/Tetris/bin/tetris/TetrisPane.class new file mode 100644 index 0000000..7ade5d3 Binary files /dev/null and b/Tetris/bin/tetris/TetrisPane.class differ diff --git a/Tetris/bin/tetris/Tetromino.class b/Tetris/bin/tetris/Tetromino.class new file mode 100644 index 0000000..30cf6b3 Binary files /dev/null and b/Tetris/bin/tetris/Tetromino.class differ diff --git a/Tetris/src/tetris/Cell.java b/Tetris/src/tetris/Cell.java index da74660..9f0f9bd 100644 --- a/Tetris/src/tetris/Cell.java +++ b/Tetris/src/tetris/Cell.java @@ -4,13 +4,13 @@ import java.awt.Graphics; /** - * 网格类 + * Cell class for Tetris game * @author Leslie Leung */ public class Cell { - public static final int CELL_SIZE = 25; //一个网格的大小 + public static final int CELL_SIZE = 25; - /* 格子的所有颜色 */ + /* Color constants for cells */ public static final int COLOR_CYAN = 0; public static final int COLOR_BLUE = 1; public static final int COLOR_GREEN = 2; @@ -19,18 +19,18 @@ public class Cell { public static final int COLOR_RED = 5; public static final int COLOR_PINK = 6; - private int color; //格子的颜色 - private int x; //横坐标 - private int y; //纵坐标 + private int color; + private int x; + private int y; /** - * 构造方法 - * @param x 横坐标 - * @param y 纵坐标 - * @param style 格子的样式,通过颜色来指定 + * Constructor + * @param x X coordinate + * @param y Y coordinate + * @param style Style/color of the cell */ public Cell(int x, int y, int style) { - /* 根据传进来的样式决定格子的颜色 */ + /* Set color based on style */ switch(style) { case 0: color = COLOR_CYAN; break; case 1: color = COLOR_BLUE; break; @@ -46,40 +46,48 @@ public Cell(int x, int y, int style) { } /** - * 设置该格子的横坐标 - * @param newX 新的横坐标 + * Set X coordinate + * @param newX New X coordinate */ public void setX(int newX) { x = newX; } /** - * 设置该格子的纵坐标 - * @param newY 新的纵坐标 + * Set Y coordinate + * @param newY New Y coordinate */ public void setY(int newY) { y = newY; } /** - * 获取该Cell的横坐标 - * @return 横坐标 + * Get X coordinate + * @return X coordinate */ public int getX() { return x; } /** - * 获取该Cell的纵坐标 - * @return 纵坐标 + * Get Y coordinate + * @return Y coordinate */ public int getY() { return y; } + + /** + * Get color + * @return Color + */ + public int getColor() { + return color; + } /** - * 绘图方法 - * @param g Graphics引用 + * Paint the cell + * @param g Graphics object */ public void paintCell(Graphics g) { switch(color) { @@ -106,4 +114,4 @@ public void paintCell(Graphics g) { break; } } -} +} \ No newline at end of file diff --git a/Tetris/src/tetris/GameConfig.java b/Tetris/src/tetris/GameConfig.java new file mode 100644 index 0000000..2486515 --- /dev/null +++ b/Tetris/src/tetris/GameConfig.java @@ -0,0 +1,124 @@ +package tetris; + +import java.io.Serializable; + +public class GameConfig implements Serializable { + private static final long serialVersionUID = 1L; + + public static final int DIFFICULTY_EASY = 0; + public static final int DIFFICULTY_MEDIUM = 1; + public static final int DIFFICULTY_HARD = 2; + + public static final int LANGUAGE_CHINESE = 0; + public static final int LANGUAGE_ENGLISH = 1; + + public static final int RESOLUTION_SMALL = 0; + public static final int RESOLUTION_MEDIUM = 1; + public static final int RESOLUTION_LARGE = 2; + + private int difficulty; + private int language; + private int resolution; + private int cellSize; + + public GameConfig() { + this.difficulty = DIFFICULTY_MEDIUM; + this.language = LANGUAGE_CHINESE; + this.resolution = RESOLUTION_MEDIUM; + this.cellSize = 25; + } + + public int getDifficulty() { + return difficulty; + } + + public void setDifficulty(int difficulty) { + this.difficulty = difficulty; + } + + public int getLanguage() { + return language; + } + + public void setLanguage(int language) { + this.language = language; + } + + public int getResolution() { + return resolution; + } + + public void setResolution(int resolution) { + this.resolution = resolution; + switch(resolution) { + case RESOLUTION_SMALL: + cellSize = 20; + break; + case RESOLUTION_MEDIUM: + cellSize = 25; + break; + case RESOLUTION_LARGE: + cellSize = 30; + break; + } + } + + public int getCellSize() { + return cellSize; + } + + public int getSpeedMultiplier() { + switch(difficulty) { + case DIFFICULTY_EASY: + return 2; + case DIFFICULTY_MEDIUM: + return 1; + case DIFFICULTY_HARD: + return 0; + default: + return 1; + } + } + + public String getDifficultyText() { + switch(language) { + case LANGUAGE_CHINESE: + switch(difficulty) { + case DIFFICULTY_EASY: return "绠鍗"; + case DIFFICULTY_MEDIUM: return "涓瓑"; + case DIFFICULTY_HARD: return "鍥伴毦"; + default: return "涓瓑"; + } + case LANGUAGE_ENGLISH: + switch(difficulty) { + case DIFFICULTY_EASY: return "Easy"; + case DIFFICULTY_MEDIUM: return "Medium"; + case DIFFICULTY_HARD: return "Hard"; + default: return "Medium"; + } + default: + return "涓瓑"; + } + } + + public String getResolutionText() { + switch(language) { + case LANGUAGE_CHINESE: + switch(resolution) { + case RESOLUTION_SMALL: return "灏"; + case RESOLUTION_MEDIUM: return "涓"; + case RESOLUTION_LARGE: return "澶"; + default: return "涓"; + } + case LANGUAGE_ENGLISH: + switch(resolution) { + case RESOLUTION_SMALL: return "Small"; + case RESOLUTION_MEDIUM: return "Medium"; + case RESOLUTION_LARGE: return "Large"; + default: return "Medium"; + } + default: + return "涓"; + } + } +} \ No newline at end of file diff --git a/Tetris/src/tetris/GameManager.java b/Tetris/src/tetris/GameManager.java new file mode 100644 index 0000000..f2db32d --- /dev/null +++ b/Tetris/src/tetris/GameManager.java @@ -0,0 +1,144 @@ +package tetris; + +import javax.swing.JFrame; +import javax.swing.JPanel; + +public class GameManager { + private static GameManager instance; + + private JFrame mainFrame; + private GameConfig config; + private GameState state; + + public static final int SCENE_MENU = 0; + public static final int SCENE_GAME = 1; + public static final int SCENE_SETTINGS = 2; + public static final int SCENE_GAME_OVER = 3; + + private int currentScene; + + private MenuPanel menuPanel; + private TetrisPane gamePanel; + private SettingsPanel settingsPanel; + private GameOverPanel gameOverPanel; + + private GameManager() { + config = new GameConfig(); + state = new GameState(); + currentScene = SCENE_MENU; + } + + public static GameManager getInstance() { + if (instance == null) { + instance = new GameManager(); + } + return instance; + } + + public void setMainFrame(JFrame frame) { + this.mainFrame = frame; + } + + public GameConfig getConfig() { + return config; + } + + public GameState getState() { + return state; + } + + public JFrame getMainFrame() { + return mainFrame; + } + + public int getCurrentScene() { + return currentScene; + } + + public void setScene(int sceneType) { + if (mainFrame == null) { + return; + } + + JPanel currentPanel = getCurrentPanel(); + if (currentPanel != null) { + mainFrame.remove(currentPanel); + } + + JPanel newPanel = getPanelForScene(sceneType); + if (newPanel != null) { + mainFrame.add(newPanel); + mainFrame.revalidate(); + mainFrame.repaint(); + newPanel.requestFocusInWindow(); + } + + currentScene = sceneType; + } + + private JPanel getCurrentPanel() { + switch (currentScene) { + case SCENE_MENU: + return menuPanel; + case SCENE_GAME: + return gamePanel; + case SCENE_SETTINGS: + return settingsPanel; + case SCENE_GAME_OVER: + return gameOverPanel; + default: + return null; + } + } + + private JPanel getPanelForScene(int sceneType) { + switch (sceneType) { + case SCENE_MENU: + if (menuPanel == null) { + menuPanel = new MenuPanel(); + } + return menuPanel; + + case SCENE_GAME: + if (gamePanel == null) { + gamePanel = new TetrisPane(); + } + gamePanel.resetGame(); + state.reset(); + state.startGame(); + return gamePanel; + + case SCENE_SETTINGS: + if (settingsPanel == null) { + settingsPanel = new SettingsPanel(); + } + return settingsPanel; + + case SCENE_GAME_OVER: + if (gameOverPanel == null) { + gameOverPanel = new GameOverPanel(); + } + return gameOverPanel; + + default: + return null; + } + } + + public void startNewGame() { + setScene(SCENE_GAME); + } + + public void showMenu() { + setScene(SCENE_MENU); + } + + public void showSettings() { + setScene(SCENE_SETTINGS); + } + + public void showGameOver() { + state.endGame(); + setScene(SCENE_GAME_OVER); + } +} \ No newline at end of file diff --git a/Tetris/src/tetris/GameOverPanel.java b/Tetris/src/tetris/GameOverPanel.java new file mode 100644 index 0000000..0a66c48 --- /dev/null +++ b/Tetris/src/tetris/GameOverPanel.java @@ -0,0 +1,203 @@ +package tetris; + +import java.awt.BorderLayout; +import java.awt.Color; +import java.awt.Dimension; +import java.awt.Font; +import java.awt.GridBagConstraints; +import java.awt.GridBagLayout; +import java.awt.Insets; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import javax.swing.BorderFactory; +import javax.swing.JButton; +import javax.swing.JLabel; +import javax.swing.JPanel; +import javax.swing.SwingConstants; + +public class GameOverPanel extends JPanel { + private static final long serialVersionUID = 1L; + + private GameManager gameManager; + private GameConfig config; + private GameState state; + + private JLabel titleLabel; + private JLabel scoreLabel; + private JLabel levelLabel; + private JLabel linesLabel; + private JLabel timeLabel; + private JButton restartButton; + private JButton menuButton; + + private static final Color BACKGROUND_COLOR = new Color(30, 30, 50); + private static final Color TITLE_COLOR = new Color(255, 100, 100); + private static final Color LABEL_COLOR = Color.WHITE; + private static final Color VALUE_COLOR = new Color(100, 200, 255); + private static final Color BUTTON_COLOR = new Color(70, 130, 180); + private static final Color BUTTON_HOVER_COLOR = new Color(100, 160, 210); + private static final Color PANEL_COLOR = new Color(40, 40, 70); + + public GameOverPanel() { + gameManager = GameManager.getInstance(); + config = gameManager.getConfig(); + state = gameManager.getState(); + + setBackground(BACKGROUND_COLOR); + setLayout(new BorderLayout()); + + initComponents(); + setupLayout(); + } + + private void initComponents() { + titleLabel = new JLabel(getGameOverText()); + titleLabel.setFont(new Font("Arial", Font.BOLD, 48)); + titleLabel.setForeground(TITLE_COLOR); + titleLabel.setHorizontalAlignment(SwingConstants.CENTER); + + scoreLabel = new JLabel(getScoreText() + ": 0"); + scoreLabel.setFont(new Font("Arial", Font.PLAIN, 20)); + scoreLabel.setForeground(LABEL_COLOR); + + levelLabel = new JLabel(getLevelText() + ": 1"); + levelLabel.setFont(new Font("Arial", Font.PLAIN, 20)); + levelLabel.setForeground(LABEL_COLOR); + + linesLabel = new JLabel(getLinesText() + ": 0"); + linesLabel.setFont(new Font("Arial", Font.PLAIN, 20)); + linesLabel.setForeground(LABEL_COLOR); + + timeLabel = new JLabel(getTimeText() + ": 00:00"); + timeLabel.setFont(new Font("Arial", Font.PLAIN, 20)); + timeLabel.setForeground(LABEL_COLOR); + + restartButton = createStyledButton(getRestartText()); + restartButton.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + gameManager.startNewGame(); + } + }); + + menuButton = createStyledButton(getMenuText()); + menuButton.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + gameManager.showMenu(); + } + }); + } + + private void setupLayout() { + JPanel titlePanel = new JPanel(); + titlePanel.setBackground(BACKGROUND_COLOR); + titlePanel.setBorder(BorderFactory.createEmptyBorder(30, 0, 20, 0)); + titlePanel.add(titleLabel); + add(titlePanel, BorderLayout.NORTH); + + JPanel statsPanel = new JPanel(); + statsPanel.setBackground(PANEL_COLOR); + statsPanel.setBorder(BorderFactory.createEmptyBorder(20, 40, 20, 40)); + statsPanel.setLayout(new GridBagLayout()); + + GridBagConstraints gbc = new GridBagConstraints(); + gbc.insets = new Insets(15, 15, 15, 15); + gbc.anchor = GridBagConstraints.WEST; + gbc.gridx = 0; + gbc.gridy = 0; + + statsPanel.add(scoreLabel, gbc); + + gbc.gridy = 1; + statsPanel.add(levelLabel, gbc); + + gbc.gridy = 2; + statsPanel.add(linesLabel, gbc); + + gbc.gridy = 3; + statsPanel.add(timeLabel, gbc); + + JPanel centerPanel = new JPanel(); + centerPanel.setBackground(BACKGROUND_COLOR); + centerPanel.add(statsPanel); + add(centerPanel, BorderLayout.CENTER); + + JPanel buttonPanel = new JPanel(); + buttonPanel.setBackground(BACKGROUND_COLOR); + buttonPanel.setBorder(BorderFactory.createEmptyBorder(20, 20, 40, 20)); + + buttonPanel.add(restartButton); + buttonPanel.add(menuButton); + + add(buttonPanel, BorderLayout.SOUTH); + } + + private JButton createStyledButton(String text) { + JButton button = new JButton(text); + button.setFont(new Font("Arial", Font.BOLD, 18)); + button.setForeground(Color.WHITE); + button.setBackground(BUTTON_COLOR); + button.setFocusPainted(false); + button.setBorderPainted(false); + button.setOpaque(true); + button.setPreferredSize(new Dimension(150, 50)); + + button.addMouseListener(new java.awt.event.MouseAdapter() { + @Override + public void mouseEntered(java.awt.event.MouseEvent evt) { + button.setBackground(BUTTON_HOVER_COLOR); + } + + @Override + public void mouseExited(java.awt.event.MouseEvent evt) { + button.setBackground(BUTTON_COLOR); + } + }); + + return button; + } + + public void updateStats() { + scoreLabel.setText(getScoreText() + ": " + state.getScore()); + levelLabel.setText(getLevelText() + ": " + state.getLevel()); + linesLabel.setText(getLinesText() + ": " + state.getLines()); + timeLabel.setText(getTimeText() + ": " + state.getFormattedTime()); + } + + @Override + public void setVisible(boolean visible) { + super.setVisible(visible); + if (visible) { + updateStats(); + } + } + + private String getGameOverText() { + return config.getLanguage() == GameConfig.LANGUAGE_CHINESE ? "娓告垙缁撴潫" : "Game Over"; + } + + private String getScoreText() { + return config.getLanguage() == GameConfig.LANGUAGE_CHINESE ? "鍒嗘暟" : "Score"; + } + + private String getLevelText() { + return config.getLanguage() == GameConfig.LANGUAGE_CHINESE ? "绛夌骇" : "Level"; + } + + private String getLinesText() { + return config.getLanguage() == GameConfig.LANGUAGE_CHINESE ? "娑堥櫎琛屾暟" : "Lines Cleared"; + } + + private String getTimeText() { + return config.getLanguage() == GameConfig.LANGUAGE_CHINESE ? "娓告垙鏃堕棿" : "Time"; + } + + private String getRestartText() { + return config.getLanguage() == GameConfig.LANGUAGE_CHINESE ? "閲嶆柊寮濮" : "Restart"; + } + + private String getMenuText() { + return config.getLanguage() == GameConfig.LANGUAGE_CHINESE ? "杩斿洖涓昏彍鍗" : "Main Menu"; + } +} \ No newline at end of file diff --git a/Tetris/src/tetris/GameState.java b/Tetris/src/tetris/GameState.java new file mode 100644 index 0000000..d05c646 --- /dev/null +++ b/Tetris/src/tetris/GameState.java @@ -0,0 +1,121 @@ +package tetris; + +public class GameState { + private int score; + private int level; + private int lines; + private int tetrominoCount; + private long startTime; + private long elapsedTime; + private boolean isPlaying; + private boolean isPaused; + + public GameState() { + reset(); + } + + public void reset() { + this.score = 0; + this.level = 1; + this.lines = 0; + this.tetrominoCount = 0; + this.startTime = 0; + this.elapsedTime = 0; + this.isPlaying = false; + this.isPaused = false; + } + + public void startGame() { + this.startTime = System.currentTimeMillis(); + this.isPlaying = true; + this.isPaused = false; + } + + public void pauseGame() { + if (isPlaying && !isPaused) { + elapsedTime += System.currentTimeMillis() - startTime; + isPaused = true; + } + } + + public void resumeGame() { + if (isPlaying && isPaused) { + startTime = System.currentTimeMillis(); + isPaused = false; + } + } + + public void endGame() { + if (isPlaying) { + elapsedTime += System.currentTimeMillis() - startTime; + isPlaying = false; + } + } + + public void addLines(int lines) { + this.lines += lines; + this.tetrominoCount++; + + switch (lines) { + case 1: + score += 100 * level; + break; + case 2: + score += 300 * level; + break; + case 3: + score += 500 * level; + break; + case 4: + score += 800 * level; + break; + } + + updateLevel(); + } + + private void updateLevel() { + int newLevel = (lines / 10) + 1; + if (newLevel != level) { + level = newLevel; + } + } + + public int getScore() { + return score; + } + + public int getLevel() { + return level; + } + + public int getLines() { + return lines; + } + + public int getTetrominoCount() { + return tetrominoCount; + } + + public long getElapsedTime() { + if (isPlaying && !isPaused) { + return elapsedTime + (System.currentTimeMillis() - startTime); + } + return elapsedTime; + } + + public boolean isPlaying() { + return isPlaying; + } + + public boolean isPaused() { + return isPaused; + } + + public String getFormattedTime() { + long totalSeconds = getElapsedTime() / 1000; + long minutes = totalSeconds / 60; + long seconds = totalSeconds % 60; + return String.format("%02d:%02d", minutes, seconds); + } +} \ No newline at end of file diff --git a/Tetris/src/tetris/MenuPanel.java b/Tetris/src/tetris/MenuPanel.java new file mode 100644 index 0000000..4134be3 --- /dev/null +++ b/Tetris/src/tetris/MenuPanel.java @@ -0,0 +1,167 @@ +package tetris; + +import java.awt.BorderLayout; +import java.awt.Color; +import java.awt.Dimension; +import java.awt.Font; +import java.awt.Graphics; +import java.awt.GridBagConstraints; +import java.awt.GridBagLayout; +import java.awt.Insets; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import javax.swing.JButton; +import javax.swing.JLabel; +import javax.swing.JPanel; + +public class MenuPanel extends JPanel { + private static final long serialVersionUID = 1L; + + private GameManager gameManager; + private GameConfig config; + + private JLabel titleLabel; + private JButton startButton; + private JButton settingsButton; + private JButton exitButton; + + private static final Color BACKGROUND_COLOR = new Color(30, 30, 50); + private static final Color TITLE_COLOR = new Color(100, 200, 255); + private static final Color BUTTON_COLOR = new Color(70, 130, 180); + private static final Color BUTTON_HOVER_COLOR = new Color(100, 160, 210); + private static final Color BUTTON_TEXT_COLOR = Color.WHITE; + + public MenuPanel() { + gameManager = GameManager.getInstance(); + config = gameManager.getConfig(); + + setBackground(BACKGROUND_COLOR); + setLayout(new BorderLayout()); + + initComponents(); + setupLayout(); + } + + private void initComponents() { + titleLabel = new JLabel("TETRIS"); + titleLabel.setFont(new Font("Arial", Font.BOLD, 72)); + titleLabel.setForeground(TITLE_COLOR); + titleLabel.setHorizontalAlignment(JLabel.CENTER); + + startButton = createStyledButton(getStartText()); + startButton.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + gameManager.startNewGame(); + } + }); + + settingsButton = createStyledButton(getSettingsText()); + settingsButton.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + gameManager.showSettings(); + } + }); + + exitButton = createStyledButton(getExitText()); + exitButton.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + System.exit(0); + } + }); + } + + private void setupLayout() { + JPanel centerPanel = new JPanel(); + centerPanel.setBackground(BACKGROUND_COLOR); + centerPanel.setLayout(new GridBagLayout()); + + GridBagConstraints gbc = new GridBagConstraints(); + gbc.gridx = 0; + gbc.gridy = 0; + gbc.insets = new Insets(20, 0, 40, 0); + gbc.anchor = GridBagConstraints.CENTER; + centerPanel.add(titleLabel, gbc); + + gbc.gridy = 1; + gbc.insets = new Insets(10, 0, 10, 0); + gbc.fill = GridBagConstraints.HORIZONTAL; + centerPanel.add(startButton, gbc); + + gbc.gridy = 2; + centerPanel.add(settingsButton, gbc); + + gbc.gridy = 3; + centerPanel.add(exitButton, gbc); + + add(centerPanel, BorderLayout.CENTER); + + JPanel infoPanel = new JPanel(); + infoPanel.setBackground(BACKGROUND_COLOR); + JLabel infoLabel = new JLabel(getControlsText()); + infoLabel.setForeground(Color.LIGHT_GRAY); + infoLabel.setFont(new Font("Arial", Font.PLAIN, 12)); + infoPanel.add(infoLabel); + add(infoPanel, BorderLayout.SOUTH); + } + + private JButton createStyledButton(String text) { + JButton button = new JButton(text); + button.setFont(new Font("Arial", Font.BOLD, 18)); + button.setForeground(BUTTON_TEXT_COLOR); + button.setBackground(BUTTON_COLOR); + button.setFocusPainted(false); + button.setBorderPainted(false); + button.setOpaque(true); + button.setPreferredSize(new Dimension(200, 50)); + + button.addMouseListener(new java.awt.event.MouseAdapter() { + @Override + public void mouseEntered(java.awt.event.MouseEvent evt) { + button.setBackground(BUTTON_HOVER_COLOR); + } + + @Override + public void mouseExited(java.awt.event.MouseEvent evt) { + button.setBackground(BUTTON_COLOR); + } + }); + + return button; + } + + private String getStartText() { + return config.getLanguage() == GameConfig.LANGUAGE_CHINESE ? "寮濮嬫父鎴" : "Start Game"; + } + + private String getSettingsText() { + return config.getLanguage() == GameConfig.LANGUAGE_CHINESE ? "璁剧疆" : "Settings"; + } + + private String getExitText() { + return config.getLanguage() == GameConfig.LANGUAGE_CHINESE ? "閫鍑" : "Exit"; + } + + private String getControlsText() { + if (config.getLanguage() == GameConfig.LANGUAGE_CHINESE) { + return "鎺у埗: 鏂瑰悜閿Щ鍔 | A閫嗘椂閽堟棆杞 | D椤烘椂閽堟棆杞 | 绌烘牸纭檷"; + } else { + return "Controls: Arrow keys move | A rotate CCW | D rotate CW | Space hard drop"; + } + } + + @Override + protected void paintComponent(Graphics g) { + super.paintComponent(g); + + g.setColor(new Color(50, 50, 80, 30)); + for (int i = 0; i < 20; i++) { + int x = (int) (Math.random() * getWidth()); + int y = (int) (Math.random() * getHeight()); + int size = 20 + (int) (Math.random() * 40); + g.fillRect(x, y, size, size); + } + } +} \ No newline at end of file diff --git a/Tetris/src/tetris/SettingsPanel.java b/Tetris/src/tetris/SettingsPanel.java new file mode 100644 index 0000000..a86a6e4 --- /dev/null +++ b/Tetris/src/tetris/SettingsPanel.java @@ -0,0 +1,295 @@ +package tetris; + +import java.awt.BorderLayout; +import java.awt.Color; +import java.awt.Dimension; +import java.awt.Font; +import java.awt.GridBagConstraints; +import java.awt.GridBagLayout; +import java.awt.Insets; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.util.Hashtable; +import javax.swing.BorderFactory; +import javax.swing.JButton; +import javax.swing.JComboBox; +import javax.swing.JLabel; +import javax.swing.JPanel; +import javax.swing.JSlider; +import javax.swing.event.ChangeEvent; +import javax.swing.event.ChangeListener; + +public class SettingsPanel extends JPanel { + private static final long serialVersionUID = 1L; + + private GameManager gameManager; + private GameConfig config; + + private JLabel titleLabel; + private JLabel difficultyLabel; + private JComboBox difficultyCombo; + private JLabel resolutionLabel; + private JComboBox resolutionCombo; + private JLabel languageLabel; + private JComboBox languageCombo; + private JButton backButton; + private JButton applyButton; + + private static final Color BACKGROUND_COLOR = new Color(30, 30, 50); + private static final Color TITLE_COLOR = new Color(100, 200, 255); + private static final Color LABEL_COLOR = Color.WHITE; + private static final Color BUTTON_COLOR = new Color(70, 130, 180); + private static final Color BUTTON_HOVER_COLOR = new Color(100, 160, 210); + private static final Color PANEL_COLOR = new Color(40, 40, 70); + + private int tempDifficulty; + private int tempResolution; + private int tempLanguage; + + public SettingsPanel() { + gameManager = GameManager.getInstance(); + config = gameManager.getConfig(); + + tempDifficulty = config.getDifficulty(); + tempResolution = config.getResolution(); + tempLanguage = config.getLanguage(); + + setBackground(BACKGROUND_COLOR); + setLayout(new BorderLayout()); + + initComponents(); + setupLayout(); + } + + private void initComponents() { + titleLabel = new JLabel(getSettingsTitleText()); + titleLabel.setFont(new Font("Arial", Font.BOLD, 36)); + titleLabel.setForeground(TITLE_COLOR); + titleLabel.setHorizontalAlignment(JLabel.CENTER); + + difficultyLabel = new JLabel(getDifficultyText() + ":"); + difficultyLabel.setFont(new Font("Arial", Font.PLAIN, 16)); + difficultyLabel.setForeground(LABEL_COLOR); + + String[] difficultyOptions = getDifficultyOptions(); + difficultyCombo = new JComboBox<>(difficultyOptions); + difficultyCombo.setSelectedIndex(tempDifficulty); + difficultyCombo.setFont(new Font("Arial", Font.PLAIN, 14)); + difficultyCombo.setPreferredSize(new Dimension(150, 30)); + difficultyCombo.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + tempDifficulty = difficultyCombo.getSelectedIndex(); + } + }); + + resolutionLabel = new JLabel(getResolutionText() + ":"); + resolutionLabel.setFont(new Font("Arial", Font.PLAIN, 16)); + resolutionLabel.setForeground(LABEL_COLOR); + + String[] resolutionOptions = getResolutionOptions(); + resolutionCombo = new JComboBox<>(resolutionOptions); + resolutionCombo.setSelectedIndex(tempResolution); + resolutionCombo.setFont(new Font("Arial", Font.PLAIN, 14)); + resolutionCombo.setPreferredSize(new Dimension(150, 30)); + resolutionCombo.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + tempResolution = resolutionCombo.getSelectedIndex(); + } + }); + + languageLabel = new JLabel(getLanguageText() + ":"); + languageLabel.setFont(new Font("Arial", Font.PLAIN, 16)); + languageLabel.setForeground(LABEL_COLOR); + + String[] languageOptions = getLanguageOptions(); + languageCombo = new JComboBox<>(languageOptions); + languageCombo.setSelectedIndex(tempLanguage); + languageCombo.setFont(new Font("Arial", Font.PLAIN, 14)); + languageCombo.setPreferredSize(new Dimension(150, 30)); + languageCombo.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + tempLanguage = languageCombo.getSelectedIndex(); + updateLanguageTexts(); + } + }); + + backButton = createStyledButton(getBackText()); + backButton.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + gameManager.showMenu(); + } + }); + + applyButton = createStyledButton(getApplyText()); + applyButton.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + applySettings(); + gameManager.showMenu(); + } + }); + } + + private void setupLayout() { + JPanel titlePanel = new JPanel(); + titlePanel.setBackground(BACKGROUND_COLOR); + titlePanel.add(titleLabel); + add(titlePanel, BorderLayout.NORTH); + + JPanel settingsPanel = new JPanel(); + settingsPanel.setBackground(PANEL_COLOR); + settingsPanel.setBorder(BorderFactory.createEmptyBorder(20, 20, 20, 20)); + settingsPanel.setLayout(new GridBagLayout()); + + GridBagConstraints gbc = new GridBagConstraints(); + gbc.insets = new Insets(15, 15, 15, 15); + gbc.anchor = GridBagConstraints.WEST; + + gbc.gridx = 0; + gbc.gridy = 0; + settingsPanel.add(difficultyLabel, gbc); + + gbc.gridx = 1; + settingsPanel.add(difficultyCombo, gbc); + + gbc.gridx = 0; + gbc.gridy = 1; + settingsPanel.add(resolutionLabel, gbc); + + gbc.gridx = 1; + settingsPanel.add(resolutionCombo, gbc); + + gbc.gridx = 0; + gbc.gridy = 2; + settingsPanel.add(languageLabel, gbc); + + gbc.gridx = 1; + settingsPanel.add(languageCombo, gbc); + + JPanel centerPanel = new JPanel(); + centerPanel.setBackground(BACKGROUND_COLOR); + centerPanel.add(settingsPanel); + add(centerPanel, BorderLayout.CENTER); + + JPanel buttonPanel = new JPanel(); + buttonPanel.setBackground(BACKGROUND_COLOR); + buttonPanel.setBorder(BorderFactory.createEmptyBorder(20, 20, 20, 20)); + + buttonPanel.add(backButton); + buttonPanel.add(applyButton); + + add(buttonPanel, BorderLayout.SOUTH); + } + + private JButton createStyledButton(String text) { + JButton button = new JButton(text); + button.setFont(new Font("Arial", Font.BOLD, 16)); + button.setForeground(Color.WHITE); + button.setBackground(BUTTON_COLOR); + button.setFocusPainted(false); + button.setBorderPainted(false); + button.setOpaque(true); + button.setPreferredSize(new Dimension(120, 40)); + + button.addMouseListener(new java.awt.event.MouseAdapter() { + @Override + public void mouseEntered(java.awt.event.MouseEvent evt) { + button.setBackground(BUTTON_HOVER_COLOR); + } + + @Override + public void mouseExited(java.awt.event.MouseEvent evt) { + button.setBackground(BUTTON_COLOR); + } + }); + + return button; + } + + private void applySettings() { + config.setDifficulty(tempDifficulty); + config.setResolution(tempResolution); + config.setLanguage(tempLanguage); + + javax.swing.JFrame frame = gameManager.getMainFrame(); + if (frame != null && frame instanceof TetrisFrame) { + ((TetrisFrame) frame).updateWindowSize(); + } + } + + private void updateLanguageTexts() { + titleLabel.setText(getSettingsTitleText()); + difficultyLabel.setText(getDifficultyText() + ":"); + resolutionLabel.setText(getResolutionText() + ":"); + languageLabel.setText(getLanguageText() + ":"); + backButton.setText(getBackText()); + applyButton.setText(getApplyText()); + + updateComboBoxModels(); + } + + private void updateComboBoxModels() { + String[] difficultyOptions = getDifficultyOptions(); + int selectedDifficulty = difficultyCombo.getSelectedIndex(); + difficultyCombo.setModel(new javax.swing.DefaultComboBoxModel<>(difficultyOptions)); + difficultyCombo.setSelectedIndex(selectedDifficulty); + + String[] resolutionOptions = getResolutionOptions(); + int selectedResolution = resolutionCombo.getSelectedIndex(); + resolutionCombo.setModel(new javax.swing.DefaultComboBoxModel<>(resolutionOptions)); + resolutionCombo.setSelectedIndex(selectedResolution); + + String[] languageOptions = getLanguageOptions(); + int selectedLanguage = languageCombo.getSelectedIndex(); + languageCombo.setModel(new javax.swing.DefaultComboBoxModel<>(languageOptions)); + languageCombo.setSelectedIndex(selectedLanguage); + } + + private String getSettingsTitleText() { + return tempLanguage == GameConfig.LANGUAGE_CHINESE ? "璁剧疆" : "Settings"; + } + + private String getDifficultyText() { + return tempLanguage == GameConfig.LANGUAGE_CHINESE ? "闅惧害" : "Difficulty"; + } + + private String getResolutionText() { + return tempLanguage == GameConfig.LANGUAGE_CHINESE ? "鍒嗚鲸鐜" : "Resolution"; + } + + private String getLanguageText() { + return tempLanguage == GameConfig.LANGUAGE_CHINESE ? "璇█" : "Language"; + } + + private String getBackText() { + return tempLanguage == GameConfig.LANGUAGE_CHINESE ? "杩斿洖" : "Back"; + } + + private String getApplyText() { + return tempLanguage == GameConfig.LANGUAGE_CHINESE ? "搴旂敤" : "Apply"; + } + + private String[] getDifficultyOptions() { + if (tempLanguage == GameConfig.LANGUAGE_CHINESE) { + return new String[]{"绠鍗", "涓瓑", "鍥伴毦"}; + } else { + return new String[]{"Easy", "Medium", "Hard"}; + } + } + + private String[] getResolutionOptions() { + if (tempLanguage == GameConfig.LANGUAGE_CHINESE) { + return new String[]{"灏", "涓", "澶"}; + } else { + return new String[]{"Small", "Medium", "Large"}; + } + } + + private String[] getLanguageOptions() { + return new String[]{"涓枃", "English"}; + } +} \ No newline at end of file diff --git a/Tetris/src/tetris/TetrisFrame.java b/Tetris/src/tetris/TetrisFrame.java index 38c1a6b..5a4a027 100644 --- a/Tetris/src/tetris/TetrisFrame.java +++ b/Tetris/src/tetris/TetrisFrame.java @@ -1,42 +1,56 @@ package tetris; -import java.awt.FlowLayout; +import java.awt.BorderLayout; import javax.swing.JFrame; -import javax.swing.JLabel; /** - * 框架类 + * 涓荤獥鍙g被 * @author Leslie Leung */ public class TetrisFrame extends JFrame { - private TetrisPane tp; //俄罗斯方块主游戏场景类 - private JLabel mention; //游戏的提示信息 + private static final long serialVersionUID = 1L; + + private GameManager gameManager; /** - * 构造方法 + * 鏋勯犲嚱鏁 */ public TetrisFrame() { - setSize(550, 600); //设置窗体大小 + setTitle("Tetris"); setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); - setLocationRelativeTo(null); //设置窗体于屏幕中央 - setTitle("Tetris"); //设置标题为Tetris - setResizable(false); //不允许窗体缩放 - setLayout(new FlowLayout()); //设置布局管理器 - - tp = new TetrisPane(); //新建场景类对象 - mention = new JLabel("按A键逆时针转,按D顺时针转,按方向键控制向左、向右和向下的运动,按空格键硬下落"); + setLocationRelativeTo(null); + setResizable(false); + setLayout(new BorderLayout()); - add(mention); //把标签添加到主框架中 - add(tp); //把游戏主场景面板添加到主框架中 + gameManager = GameManager.getInstance(); + gameManager.setMainFrame(this); - /* 注册键盘事件 */ - addKeyListener(tp.getInnerInstanceOfKeyControl()); - tp.addKeyListener(tp.getInnerInstanceOfKeyControl()); + configureWindowSize(); + gameManager.setScene(GameManager.SCENE_MENU); setVisible(true); } + private void configureWindowSize() { + GameConfig config = gameManager.getConfig(); + int cellSize = config.getCellSize(); + int width = cellSize * TetrisPane.COLUMNS + 200; + int height = cellSize * TetrisPane.ROWS + 100; + + setSize(width, height); + setLocationRelativeTo(null); + } + + public void updateWindowSize() { + configureWindowSize(); + } + public static void main(String[] args) { - new TetrisFrame(); + javax.swing.SwingUtilities.invokeLater(new Runnable() { + @Override + public void run() { + new TetrisFrame(); + } + }); } } diff --git a/Tetris/src/tetris/TetrisPane.java b/Tetris/src/tetris/TetrisPane.java index b13449e..7f3d743 100644 --- a/Tetris/src/tetris/TetrisPane.java +++ b/Tetris/src/tetris/TetrisPane.java @@ -1,26 +1,34 @@ package tetris; +import java.awt.BorderLayout; import java.awt.Color; import java.awt.Dimension; +import java.awt.Font; +import java.awt.GradientPaint; import java.awt.Graphics; +import java.awt.Graphics2D; +import java.awt.RenderingHints; import java.awt.event.KeyAdapter; import java.awt.event.KeyEvent; import java.util.Arrays; import java.util.Random; import java.util.Timer; import java.util.TimerTask; +import javax.swing.BorderFactory; +import javax.swing.JLabel; import javax.swing.JOptionPane; import javax.swing.JPanel; +import javax.swing.SwingConstants; +import javax.swing.border.Border; /** - * 俄罗斯方块游戏场景类 + * 淇勭綏鏂柟鍧楁父鎴忛潰鏉 * @author Leslie Leung */ public class TetrisPane extends JPanel { - public static final int ROWS = 20; //整个场景的行数 - public static final int COLUMNS = 16; //整个场景的列数 + public static final int ROWS = 20; + public static final int COLUMNS = 16; - /* 表示7种不同的四格方块 */ public static final int I_SHAPED = 0; public static final int S_SHAPED = 1; public static final int T_SHAPED = 2; @@ -29,221 +37,557 @@ public class TetrisPane extends JPanel { public static final int O_SHAPED = 5; public static final int J_SHAPED = 6; - public static final int KIND = 7; //表示四格方块有7个种类 - public static final int INIT_SPEED = 1000; //表示下落的初始速度 + public static final int KIND = 7; + public static final int INIT_SPEED = 1000; - private static int randomNum = 0; //表示已生成的俄罗斯方块的数目 + private static int randomNum = 0; + + private GameManager gameManager; + private GameConfig config; + private GameState state; private Random random; - private Tetromino currentTetromino; //表示当前的四格方块 - private Cell[][] wall; //表示墙,null表示方块内没对象 - private Timer autoDrop; //实现自动下落的计时器 - private KeyControl keyListener; //表示键盘事件监控变量 + private Tetromino currentTetromino; + private Cell[][] wall; + private Timer autoDrop; + private KeyControl keyListener; + private Timer updateTimer; + + private JPanel infoPanel; + private JLabel scoreLabel; + private JLabel levelLabel; + private JLabel linesLabel; + private JLabel timeLabel; + private JLabel nextPieceLabel; + private JLabel controlsLabel; + + private static final Color BACKGROUND_COLOR = new Color(20, 20, 40); + private static final Color GRID_COLOR = new Color(40, 40, 70); + private static final Color INFO_PANEL_COLOR = new Color(30, 30, 60); + private static final Color LABEL_COLOR = new Color(100, 200, 255); + private static final Color VALUE_COLOR = Color.WHITE; /** - * 构造方法 + * 鏋勯犲嚱鏁 */ public TetrisPane() { - setPreferredSize(new Dimension(COLUMNS * Cell.CELL_SIZE, ROWS * Cell.CELL_SIZE)); + gameManager = GameManager.getInstance(); + config = gameManager.getConfig(); + state = gameManager.getState(); + + setBackground(BACKGROUND_COLOR); + setLayout(new BorderLayout()); random = new Random(); wall = new Cell[ROWS][COLUMNS]; autoDrop = new Timer(); keyListener = new KeyControl(); + initInfoPanel(); + setupLayout(); + + setFocusable(true); + addKeyListener(keyListener); + } + + private void initInfoPanel() { + infoPanel = new JPanel(); + infoPanel.setBackground(INFO_PANEL_COLOR); + infoPanel.setPreferredSize(new Dimension(180, 0)); + infoPanel.setLayout(null); + infoPanel.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10)); + + int y = 20; + int labelHeight = 40; + int gap = 15; + + scoreLabel = createInfoLabel(getScoreText(), "0", y); + y += labelHeight + gap; + + levelLabel = createInfoLabel(getLevelText(), "1", y); + y += labelHeight + gap; + + linesLabel = createInfoLabel(getLinesText(), "0", y); + y += labelHeight + gap; + + timeLabel = createInfoLabel(getTimeText(), "00:00", y); + y += labelHeight + gap; + + nextPieceLabel = createInfoLabel(getNextText(), "", y); + nextPieceLabel.setVerticalAlignment(SwingConstants.TOP); + y += labelHeight + gap + 100; + + controlsLabel = createInfoLabel(getControlsTitleText(), "", y); + controlsLabel.setFont(new Font("Arial", Font.BOLD, 14)); + y += labelHeight; + + JLabel[] controlLabels = createControlLabels(); + for (JLabel label : controlLabels) { + label.setBounds(20, y, 140, 25); + label.setForeground(Color.LIGHT_GRAY); + infoPanel.add(label); + y += 25; + } + + infoPanel.add(scoreLabel); + infoPanel.add(levelLabel); + infoPanel.add(linesLabel); + infoPanel.add(timeLabel); + infoPanel.add(nextPieceLabel); + infoPanel.add(controlsLabel); + } + + private JLabel createInfoLabel(String text, String value, int y) { + JLabel label = new JLabel("" + text + "
" + value + ""); + label.setBounds(20, y, 140, 50); + label.setForeground(LABEL_COLOR); + label.setFont(new Font("Arial", Font.BOLD, 14)); + label.setVerticalAlignment(SwingConstants.CENTER); + return label; + } + + private JLabel[] createControlLabels() { + if (config.getLanguage() == GameConfig.LANGUAGE_CHINESE) { + return new JLabel[] { + new JLabel("鈫 鈫 宸﹀彸绉诲姩"), + new JLabel("鈫 涓嬬Щ"), + new JLabel("A 閫嗘椂閽堟棆杞"), + new JLabel("D 椤烘椂閽堟棆杞"), + new JLabel("绌烘牸 纭檷"), + new JLabel("P 鏆傚仠") + }; + } else { + return new JLabel[] { + new JLabel("鈫 鈫 Move Left/Right"), + new JLabel("鈫 Move Down"), + new JLabel("A Rotate CCW"), + new JLabel("D Rotate CW"), + new JLabel("Space Hard Drop"), + new JLabel("P Pause") + }; + } + } + + private void setupLayout() { + JPanel gameArea = new JPanel() { + private static final long serialVersionUID = 1L; + + @Override + protected void paintComponent(Graphics g) { + super.paintComponent(g); + paintGameArea(g); + } + }; + gameArea.setBackground(BACKGROUND_COLOR); + gameArea.setPreferredSize(new Dimension( + COLUMNS * Cell.CELL_SIZE + 20, + ROWS * Cell.CELL_SIZE + 20 + )); + + add(gameArea, BorderLayout.CENTER); + add(infoPanel, BorderLayout.EAST); + } + + @Override + protected void paintComponent(Graphics g) { + super.paintComponent(g); + paintGameArea(g); + } + + private void paintGameArea(Graphics g) { + Graphics2D g2d = (Graphics2D) g; + g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); + + int cellSize = Cell.CELL_SIZE; + int offsetX = 10; + int offsetY = 10; + + g2d.setColor(new Color(50, 50, 80)); + g2d.fillRect(offsetX - 2, offsetY - 2, COLUMNS * cellSize + 4, ROWS * cellSize + 4); + + g2d.setColor(GRID_COLOR); + for (int i = 0; i < ROWS; i++) { + for (int j = 0; j < COLUMNS; j++) { + g2d.fillRect( + offsetX + j * cellSize + 1, + offsetY + i * cellSize + 1, + cellSize - 2, + cellSize - 2 + ); + } + } + + g2d.setColor(new Color(30, 30, 50)); + for (int i = 0; i <= ROWS; i++) { + g2d.drawLine( + offsetX, + offsetY + i * cellSize, + offsetX + COLUMNS * cellSize, + offsetY + i * cellSize + ); + } + for (int j = 0; j <= COLUMNS; j++) { + g2d.drawLine( + offsetX + j * cellSize, + offsetY, + offsetX + j * cellSize, + offsetY + ROWS * cellSize + ); + } + + for (int i = 0; i < ROWS; i++) { + for (int j = 0; j < COLUMNS; j++) { + if (wall[i][j] != null) { + paintCell(g2d, wall[i][j], offsetX, offsetY); + } + } + } + + if (currentTetromino != null) { + for (Cell cell : getCurrentCells()) { + paintCell(g2d, cell, offsetX, offsetY); + } + + paintGhostPiece(g2d, offsetX, offsetY); + } + + if (state.isPaused()) { + g2d.setColor(new Color(0, 0, 0, 150)); + g2d.fillRect(offsetX, offsetY, COLUMNS * cellSize, ROWS * cellSize); + + g2d.setColor(Color.WHITE); + g2d.setFont(new Font("Arial", Font.BOLD, 36)); + String pauseText = config.getLanguage() == GameConfig.LANGUAGE_CHINESE ? "鏆傚仠" : "PAUSED"; + int textWidth = g2d.getFontMetrics().stringWidth(pauseText); + g2d.drawString( + pauseText, + offsetX + (COLUMNS * cellSize - textWidth) / 2, + offsetY + ROWS * cellSize / 2 + ); + } + } + + private void paintCell(Graphics2D g2d, Cell cell, int offsetX, int offsetY) { + int cellSize = Cell.CELL_SIZE; + int x = offsetX + cell.getX() * cellSize; + int y = offsetY + cell.getY() * cellSize; + + Color baseColor = getCellColor(cell); + + GradientPaint gradient = new GradientPaint( + x, y, baseColor.brighter(), + x + cellSize, y + cellSize, baseColor.darker() + ); + g2d.setPaint(gradient); + g2d.fillRect(x + 2, y + 2, cellSize - 4, cellSize - 4); + + g2d.setColor(baseColor.brighter()); + g2d.fillRect(x + 2, y + 2, cellSize - 4, 3); + g2d.fillRect(x + 2, y + 2, 3, cellSize - 4); + + g2d.setColor(baseColor.darker().darker()); + g2d.fillRect(x + 2, y + cellSize - 5, cellSize - 4, 3); + g2d.fillRect(x + cellSize - 5, y + 2, 3, cellSize - 4); + } + + private void paintGhostPiece(Graphics2D g2d, int offsetX, int offsetY) { + if (currentTetromino == null) return; + + int cellSize = Cell.CELL_SIZE; + Cell[] ghostCells = calculateGhostPosition(); + + for (Cell cell : ghostCells) { + int x = offsetX + cell.getX() * cellSize; + int y = offsetY + cell.getY() * cellSize; + + Color baseColor = getCellColor(cell); + g2d.setColor(new Color( + baseColor.getRed() / 2, + baseColor.getGreen() / 2, + baseColor.getBlue() / 2, + 100 + )); + + g2d.drawRect(x + 2, y + 2, cellSize - 4, cellSize - 4); + } + } + + private Cell[] calculateGhostPosition() { + if (currentTetromino == null) return new Cell[0]; + + Cell[] cells = getCurrentCells(); + Cell[] ghostCells = new Cell[cells.length]; + + for (int i = 0; i < cells.length; i++) { + ghostCells[i] = new Cell(cells[i].getX(), cells[i].getY(), getCellColorIndex(cells[i])); + } + + while (!isGhostReachBottom(ghostCells)) { + for (Cell cell : ghostCells) { + cell.setY(cell.getY() + 1); + } + } + + return ghostCells; + } + + private boolean isGhostReachBottom(Cell[] cells) { + for (Cell cell : cells) { + int y = cell.getY() + 1; + if (y >= ROWS || (y >= 0 && cell.getX() >= 0 && cell.getX() < COLUMNS && wall[y][cell.getX()] != null)) { + return true; + } + } + return false; + } + + private Color getCellColor(Cell cell) { + switch (cell.getColor()) { + case Cell.COLOR_CYAN: return Color.CYAN; + case Cell.COLOR_BLUE: return Color.BLUE; + case Cell.COLOR_GREEN: return Color.GREEN; + case Cell.COLOR_YELLOW: return Color.YELLOW; + case Cell.COLOR_ORANGE: return Color.ORANGE; + case Cell.COLOR_RED: return Color.RED; + case Cell.COLOR_PINK: return Color.PINK; + default: return Color.GRAY; + } + } + + private int getCellColorIndex(Cell cell) { + switch (cell.getColor()) { + case Cell.COLOR_CYAN: return 0; + case Cell.COLOR_BLUE: return 1; + case Cell.COLOR_GREEN: return 2; + case Cell.COLOR_YELLOW: return 3; + case Cell.COLOR_ORANGE: return 4; + case Cell.COLOR_RED: return 5; + case Cell.COLOR_PINK: return 6; + default: return 0; + } + } + + public void resetGame() { + randomNum = 0; + random = new Random(); + wall = new Cell[ROWS][COLUMNS]; + + if (autoDrop != null) { + autoDrop.cancel(); + } + autoDrop = new Timer(); + + if (updateTimer != null) { + updateTimer.cancel(); + } + randomOne(); - autoDrop.schedule(new DropExecution(), (long)interval(), (long)interval()); + updateTimer = new Timer(); + updateTimer.scheduleAtFixedRate(new TimerTask() { + @Override + public void run() { + updateUI(); + } + }, 0, 1000); + + autoDrop.schedule(new DropExecution(), (long) interval(), (long) interval()); + + updateInfoLabels(); + requestFocusInWindow(); + } + + private void updateInfoLabels() { + if (scoreLabel != null) { + scoreLabel.setText("" + getScoreText() + "
" + state.getScore() + ""); + } + if (levelLabel != null) { + levelLabel.setText("" + getLevelText() + "
" + state.getLevel() + ""); + } + if (linesLabel != null) { + linesLabel.setText("" + getLinesText() + "
" + state.getLines() + ""); + } + if (timeLabel != null) { + timeLabel.setText("" + getTimeText() + "
" + state.getFormattedTime() + ""); + } + } + + @Override + public void updateUI() { + super.updateUI(); + updateInfoLabels(); + repaint(); } - /** - * 随机生成一个四格方块 - */ public void randomOne() { Tetromino tetromino = null; - /* 随机生成7种四格方块的其中一种 */ - switch(random.nextInt(KIND)) { + switch (random.nextInt(KIND)) { case I_SHAPED: tetromino = new IShaped(); break; case S_SHAPED: tetromino = new SShaped(); - break; + break; case T_SHAPED: tetromino = new TShaped(); - break; + break; case Z_SHAPED: tetromino = new ZShaped(); - break; + break; case L_SHAPED: tetromino = new LShaped(); - break; + break; case O_SHAPED: tetromino = new OShaped(); - break; + break; case J_SHAPED: tetromino = new JShaped(); - break; + break; } - currentTetromino = tetromino; //当前的四格方块为生成的四格方块 - randomNum ++; + currentTetromino = tetromino; + randomNum++; } - /** - * 判断玩家是否输了 - * @return true,输了;false,没输 - */ public boolean isGameOver() { - int x, y; //当前俄罗斯方块格子的横坐标和纵坐标 - for(int i = 0; i < getCurrentCells().length; i ++) { + int x, y; + for (int i = 0; i < getCurrentCells().length; i++) { x = getCurrentCells()[i].getX(); y = getCurrentCells()[i].getY(); - if(isContain(x, y)) {//看其刚生成的位置是否已存在方块对象,存在的话,表示输了 + if (isContain(x, y)) { return true; } } - return false; } - /** - * 每生成一个俄罗斯方块,通过改变TimerTask的时间间隔来加快下落速度 - * @return 时间间隔 - */ public double interval() { - return INIT_SPEED * Math.pow((double)39 / 38, 0 - randomNum); + int level = state.getLevel(); + int difficultyMultiplier = config.getSpeedMultiplier(); + return INIT_SPEED * Math.pow((double) 39 / 38, 0 - (randomNum + level * 5)) * (1 + difficultyMultiplier * 0.5); } - /** - * 返回KeyControl类的实例 - * @return KeyControl类实例 - */ public KeyControl getInnerInstanceOfKeyControl() { return keyListener; } - /** - * 内部类,用于实现俄罗斯方块的自动下落 - * @author Leslie Leung - */ private class DropExecution extends TimerTask { @Override public void run() { - // TODO Auto-generated method stub + if (state.isPaused()) { + return; + } - if(isGameOver()) {//如果输了 - JOptionPane.showMessageDialog(null, "你输了"); + if (isGameOver()) { autoDrop.cancel(); - removeKeyListener(keyListener); + if (updateTimer != null) { + updateTimer.cancel(); + } + gameManager.showGameOver(); return; } - if(!isReachBottomEdge()) { + if (!isReachBottomEdge()) { currentTetromino.softDrop(); } else { - landIntoWall(); //把俄罗斯方块添加到墙上 - removeRows(); //如满行,删除行 - randomOne(); //马上新建一个俄罗斯方块 + landIntoWall(); + removeRows(); + randomOne(); autoDrop.cancel(); autoDrop = new Timer(); - autoDrop.schedule(new DropExecution(), (long)interval(), (long)interval()); + autoDrop.schedule(new DropExecution(), (long) interval(), (long) interval()); } repaint(); } } - /** - * 把俄罗斯方块添加到墙上 - */ public void landIntoWall() { - int x, y; //定义俄罗斯方块不能移动后的横坐标和纵坐标 + int x, y; - for(int i = 0; i < getCurrentCells().length; i ++) { + for (int i = 0; i < getCurrentCells().length; i++) { x = getCurrentCells()[i].getX(); y = getCurrentCells()[i].getY(); - wall[y][x] = getCurrentCells()[i]; //添加到墙上 + wall[y][x] = getCurrentCells()[i]; } } - /** - * 内部类,用于实现键盘的事件控制 - * @author Leslie Leung - */ private class KeyControl extends KeyAdapter { @Override public void keyPressed(KeyEvent e) { - switch(e.getKeyCode()) { - case KeyEvent.VK_LEFT: //往左移动 - - if(!isReachLeftEdge()) {//当俄罗斯方块没到达左边界时,往左移动 + if (state.isPaused() && e.getKeyCode() != KeyEvent.VK_P) { + return; + } + + switch (e.getKeyCode()) { + case KeyEvent.VK_LEFT: + if (!isReachLeftEdge()) { currentTetromino.moveLeft(); repaint(); } break; - case KeyEvent.VK_RIGHT: //往右移动 - - if(!isReachRightEdge()) {//当俄罗斯方块没到达右边界时,往右移动 + case KeyEvent.VK_RIGHT: + if (!isReachRightEdge()) { currentTetromino.moveRight(); repaint(); } break; - case KeyEvent.VK_DOWN: //向下移动 - - if(!isReachBottomEdge()) {//当俄罗斯方块没到达下边界时,往下移动 + case KeyEvent.VK_DOWN: + if (!isReachBottomEdge()) { currentTetromino.softDrop(); repaint(); } - break; - case KeyEvent.VK_SPACE: //硬下落 - - hardDrop(); //硬下落 - landIntoWall(); //添加到墙中 - removeRows(); //如满行,删除行 + case KeyEvent.VK_SPACE: + hardDrop(); + landIntoWall(); + removeRows(); randomOne(); autoDrop.cancel(); autoDrop = new Timer(); - autoDrop.schedule(new DropExecution(), (long)interval(), (long)interval()); + autoDrop.schedule(new DropExecution(), (long) interval(), (long) interval()); repaint(); break; - case KeyEvent.VK_D: //顺时针转 - - if(!clockwiseRotateIsOutOfBounds() && !(currentTetromino instanceof OShaped)) {//俄罗斯方块没越界且其不为O形时,旋转 + case KeyEvent.VK_D: + if (!clockwiseRotateIsOutOfBounds() && !(currentTetromino instanceof OShaped)) { currentTetromino.clockwiseRotate(getAxis(), getRotateCells()); repaint(); } break; - case KeyEvent.VK_A: //逆时针转 - - if(!anticlockwiseRotateIsOutOfBounds() && !(currentTetromino instanceof OShaped)) {//俄罗斯方块没越界且其不为O形时,旋转 + case KeyEvent.VK_A: + if (!anticlockwiseRotateIsOutOfBounds() && !(currentTetromino instanceof OShaped)) { currentTetromino.anticlockwiseRotate(getAxis(), getRotateCells()); repaint(); } break; + + case KeyEvent.VK_P: + togglePause(); + break; } } } - /** - * 内部类,I形的四格方块,继承了Tetromino类 - * @author Leslie Leung - */ + private void togglePause() { + if (state.isPaused()) { + state.resumeGame(); + } else { + state.pauseGame(); + } + repaint(); + } + private class IShaped extends Tetromino { - /** - * 构造方法 - */ public IShaped() { cells = new Cell[4]; @@ -252,7 +596,6 @@ public IShaped() { cells[2] = new Cell(5, 0, Cell.COLOR_CYAN); cells[3] = new Cell(6, 0, Cell.COLOR_CYAN); - /* 设置旋转轴和要旋转的格子 */ setAxis(); setRotateCells(); @@ -260,14 +603,7 @@ public IShaped() { } } - /** - * 内部类,S形的四格方块,继承了Tetromino类 - * @author Leslie Leung - */ private class SShaped extends Tetromino { - /** - * 构造方法 - */ public SShaped() { cells = new Cell[4]; @@ -276,7 +612,6 @@ public SShaped() { cells[2] = new Cell(3, 1, Cell.COLOR_BLUE); cells[3] = new Cell(4, 1, Cell.COLOR_BLUE); - /* 设置旋转轴和要旋转的格子 */ setAxis(); setRotateCells(); @@ -284,14 +619,7 @@ public SShaped() { } } - /** - * 内部类,T形的四格方块,继承了Tetromino类 - * @author Leslie Leung - */ private class TShaped extends Tetromino { - /** - * 构造方法 - */ public TShaped() { cells = new Cell[4]; @@ -300,7 +628,6 @@ public TShaped() { cells[2] = new Cell(5, 0, Cell.COLOR_GREEN); cells[3] = new Cell(4, 1, Cell.COLOR_GREEN); - /* 设置旋转轴和要旋转的格子 */ setAxis(); setRotateCells(); @@ -308,14 +635,7 @@ public TShaped() { } } - /** - * 内部类,Z形的四格方块,继承了Tetromino类 - * @author Leslie Leung - */ private class ZShaped extends Tetromino { - /** - * 构造方法 - */ public ZShaped() { cells = new Cell[4]; @@ -324,7 +644,6 @@ public ZShaped() { cells[0] = new Cell(4, 1, Cell.COLOR_ORANGE); cells[3] = new Cell(5, 1, Cell.COLOR_ORANGE); - /* 设置旋转轴和要旋转的格子 */ setAxis(); setRotateCells(); @@ -332,14 +651,7 @@ public ZShaped() { } } - /** - * 内部类,L形的四格方块,继承了Tetromino类 - * @author Leslie Leung - */ private class LShaped extends Tetromino { - /** - * 构造方法 - */ public LShaped() { cells = new Cell[4]; @@ -348,7 +660,6 @@ public LShaped() { cells[2] = new Cell(5, 0, Cell.COLOR_PINK); cells[3] = new Cell(3, 1, Cell.COLOR_PINK); - /* 设置旋转轴和要旋转的格子 */ setAxis(); setRotateCells(); @@ -356,14 +667,7 @@ public LShaped() { } } - /** - * 内部类,O形的四格方块,继承了Tetromino类 - * @author Leslie Leung - */ private class OShaped extends Tetromino { - /** - * 构造方法 - */ public OShaped() { cells = new Cell[4]; @@ -372,7 +676,6 @@ public OShaped() { cells[2] = new Cell(4, 1, Cell.COLOR_RED); cells[3] = new Cell(5, 1, Cell.COLOR_RED); - /* 设置旋转轴和要旋转的格子 */ setAxis(); setRotateCells(); @@ -380,14 +683,7 @@ public OShaped() { } } - /** - * 内部类,J形的四格方块,继承了Tetromino类 - * @author Leslie Leung - */ private class JShaped extends Tetromino { - /** - * 构造方法 - */ public JShaped() { cells = new Cell[4]; @@ -396,7 +692,6 @@ public JShaped() { cells[2] = new Cell(5, 0, Cell.COLOR_YELLOW); cells[3] = new Cell(5, 1, Cell.COLOR_YELLOW); - /* 设置旋转轴和要旋转的格子 */ setAxis(); setRotateCells(); @@ -404,130 +699,120 @@ public JShaped() { } } - /** - * 删除若干行 - */ public void removeRows() { - for(int i = 0; i < getCurrentCells().length; i ++) { - removeRow(getCurrentCells()[i].getY()); + int removedCount = 0; + for (int i = 0; i < ROWS; i++) { + if (removeSingleRow(i)) { + removedCount++; + i--; + } + } + + if (removedCount > 0) { + state.addLines(removedCount); + updateInfoLabels(); } } - /** - * 获取旋转轴 - * @return 旋转轴 - */ + private boolean removeSingleRow(int rowIndex) { + for (int j = 0; j < COLUMNS; j++) { + if (wall[rowIndex][j] == null) { + return false; + } + } + + for (int k = rowIndex; k >= 1; k--) { + System.arraycopy(wall[k - 1], 0, wall[k], 0, COLUMNS); + + for (int m = 0; m < COLUMNS; m++) { + if (wall[k][m] != null) { + wall[k][m].setY(wall[k][m].getY() + 1); + } + } + } + Arrays.fill(wall[0], null); + return true; + } + public Cell getAxis() { return currentTetromino.getAxis(); } - /** - * 获取需要旋转的格子 - * @return 需要旋转的格子 - */ public Cell[] getRotateCells() { return currentTetromino.getRotateCells(); } - /** - * 获取当前俄罗斯方块的所有格子 - * @return 当前俄罗斯方块的所有格子 - */ public Cell[] getCurrentCells() { return currentTetromino.getCells(); } - /** - * 判断俄罗斯方块是否到达底部(包括是否到达面板底部和下一位置是否有方块) - * @return true,到达;false,没到达 - */ public boolean isReachBottomEdge() { - int oldY, newY, oldX; //定义格子旧的纵坐标、新的纵坐标和旧的横坐标 + int oldY, newY, oldX; - for(int i = 0; i < getCurrentCells().length; i ++) { + for (int i = 0; i < getCurrentCells().length; i++) { oldY = getCurrentCells()[i].getY(); newY = oldY + 1; oldX = getCurrentCells()[i].getX(); - if(oldY == ROWS - 1) {//到达面板底部 + if (oldY == ROWS - 1) { return true; } - if(isContain(oldX, newY)) {//下一位置有方块 + if (isContain(oldX, newY)) { return true; } } return false; } - /** - * 判断俄罗斯方块是否到达左边界(包括是否超出面板左边界和下一位置是否出现与其他方块碰撞) - * @return true,已到达;false,没到达 - */ public boolean isReachLeftEdge() { - int oldX, newX, oldY; //定义格子旧的横坐标、新的横坐标和旧的纵坐标 + int oldX, newX, oldY; - for(int i = 0; i < getCurrentCells().length; i ++) { + for (int i = 0; i < getCurrentCells().length; i++) { oldX = getCurrentCells()[i].getX(); newX = oldX - 1; oldY = getCurrentCells()[i].getY(); - if(oldX == 0 || isContain(newX, oldY)) {//到达左边界 - return true; - } - - if(isContain(newX, oldY)) {//下一位置有方块 + if (oldX == 0 || isContain(newX, oldY)) { return true; } } return false; } - /** - * 判断俄罗斯方块是否到达右边界(包括是否超出面板右边界和下一位置是否出现与其他方块碰撞) - * @return true,已到达;false,没到达 - */ public boolean isReachRightEdge() { - int oldX, newX, oldY; //定义格子旧的横坐标、新的横坐标和旧的纵坐标 + int oldX, newX, oldY; - for(int i = 0; i < getCurrentCells().length; i ++) { + for (int i = 0; i < getCurrentCells().length; i++) { oldX = getCurrentCells()[i].getX(); newX = oldX + 1; oldY = getCurrentCells()[i].getY(); - if(oldX == COLUMNS - 1 || isContain(newX, oldY)) {//到达右边界 - return true; - } - - if(isContain(newX, oldY)) {//下一位置有方块 + if (oldX == COLUMNS - 1 || isContain(newX, oldY)) { return true; } } return false; } - /** - * 判断俄罗斯方块顺时针转后是否超出边界(包括是否超出面板边界和下一位置是否有方块) - * @return true,超出边界;false,没超边界 - */ public boolean clockwiseRotateIsOutOfBounds() { - int oldX; //rotateCell的横坐标 - int oldY; //rotateCell的纵坐标 - int newX; //rotateCell旋转后的横坐标 - int newY; //rotateCell旋转后的纵坐标 + int oldX; + int oldY; + int newX; + int newY; - for(int i = 0; i < 3; i ++) { + for (int i = 0; i < 3; i++) { oldX = getRotateCells()[i].getX(); oldY = getRotateCells()[i].getY(); - newX = getAxis().getX() - oldY + getAxis().getY(); //新横坐标计算算法 - newY = getAxis().getY() + oldX - getAxis().getX(); //新纵坐标计算算法 + newX = getAxis().getX() - oldY + getAxis().getY(); + newY = getAxis().getY() + oldX - getAxis().getX(); - if(newX < 0 || newY < 0 || newX > COLUMNS - 1 || newY > ROWS - 1) {//如果越界,返回true + if (newX < 0 || newY < 0 || newX > COLUMNS - 1 || newY > ROWS - 1) { return true; } - if(isContain(newX, newY)) {//如果越界,返回true + if (isContain(newX, newY)) { return true; } } @@ -535,28 +820,24 @@ public boolean clockwiseRotateIsOutOfBounds() { return false; } - /** - * 判断俄罗斯方块逆时针转后是否超出边界(包括是否超出面板边界和下一位置是否有方块) - * @return true,超出边界;false,没超边界 - */ public boolean anticlockwiseRotateIsOutOfBounds() { - int oldX; //rotateCell的横坐标 - int oldY; //rotateCell的纵坐标 - int newX; //rotateCell旋转后的横坐标 - int newY; //rotateCell旋转后的纵坐标 + int oldX; + int oldY; + int newX; + int newY; - for(int i = 0; i < 3; i ++) { + for (int i = 0; i < 3; i++) { oldX = getRotateCells()[i].getX(); oldY = getRotateCells()[i].getY(); - newX = getAxis().getX() - getAxis().getY() + oldY; //新横坐标计算算法 - newY = getAxis().getY() + getAxis().getX() - oldX; //新纵坐标计算算法 + newX = getAxis().getX() - getAxis().getY() + oldY; + newY = getAxis().getY() + getAxis().getX() - oldX; - if(newX < 0 || newY < 0 || newX > COLUMNS - 1 || newY > ROWS - 1) {//如果越界,返回true + if (newX < 0 || newY < 0 || newX > COLUMNS - 1 || newY > ROWS - 1) { return true; } - if(isContain(newX, newY)) {//如果越界,返回true + if (isContain(newX, newY)) { return true; } } @@ -564,79 +845,40 @@ public boolean anticlockwiseRotateIsOutOfBounds() { return false; } - /** - * 判断某个格子是否存在方块对象 - * @param x 横坐标 - * @param y 纵坐标 - * @return true,存在对象;false,不存在对象 - */ public boolean isContain(int x, int y) { - if(wall[y][x] == null) { + if (y < 0 || y >= ROWS || x < 0 || x >= COLUMNS) { return false; - } else { - return true; } + return wall[y][x] != null; } - /** - * 实现俄罗斯方块的硬下落 - */ public void hardDrop() { - while(!isReachBottomEdge()) { + while (!isReachBottomEdge()) { currentTetromino.softDrop(); } } - /** - * 消除单行 - * @param i 行的下标 - */ - public void removeRow(int i) { - int oldY, newY; - - for(int j = 0; j < COLUMNS; j ++) { - if(wall[i][j] == null) {//如果其中一个方块没有填满,return - return; - } - } - - /* 消除行并把该行上面的方块往下移 */ - for(int k = i; k >= 1; k --){ - System.arraycopy(wall[k - 1], 0, wall[k], 0, COLUMNS); - - for(int m = 0; m < COLUMNS; m ++) { - if(wall[k][m] != null) {//对于不是空的对象,要重设其纵坐标 - oldY = wall[k][m].getY(); - newY = oldY + 1; - wall[k][m].setY(newY); - } - } - - } - Arrays.fill(wall[0], null); + private String getScoreText() { + return config.getLanguage() == GameConfig.LANGUAGE_CHINESE ? "鍒嗘暟" : "Score"; } - @Override - public void paint(Graphics g) { - g.setColor(Color.BLACK); - g.fillRect(0, 0, getBounds().width, getBounds().height); - - /* 画墙 */ - for(int i = 0; i < ROWS; i ++) { - for(int j = 0; j < COLUMNS; j ++) { - if(wall[i][j] == null) {//某点的方块为空时 - g.setColor(Color.WHITE); - g.fillRect(j * Cell.CELL_SIZE + 1, i * Cell.CELL_SIZE + 1, Cell.CELL_SIZE - 2, Cell.CELL_SIZE - 2); - } else {//当方块不为空时 - wall[i][j].paintCell(g); - } - } - } - - /* 画当前俄罗斯方块 */ - for(int i = 0; i < getCurrentCells().length; i ++) { - getCurrentCells()[i].paintCell(g); - } - + private String getLevelText() { + return config.getLanguage() == GameConfig.LANGUAGE_CHINESE ? "绛夌骇" : "Level"; + } + + private String getLinesText() { + return config.getLanguage() == GameConfig.LANGUAGE_CHINESE ? "娑堥櫎琛屾暟" : "Lines"; + } + + private String getTimeText() { + return config.getLanguage() == GameConfig.LANGUAGE_CHINESE ? "鏃堕棿" : "Time"; + } + + private String getNextText() { + return config.getLanguage() == GameConfig.LANGUAGE_CHINESE ? "涓嬩竴涓" : "Next"; + } + + private String getControlsTitleText() { + return config.getLanguage() == GameConfig.LANGUAGE_CHINESE ? "鎿嶄綔璇存槑" : "Controls"; } -} +} \ No newline at end of file diff --git a/Tetris/src/tetris/Tetromino.java b/Tetris/src/tetris/Tetromino.java index 422a5fd..fbb133a 100644 --- a/Tetris/src/tetris/Tetromino.java +++ b/Tetris/src/tetris/Tetromino.java @@ -1,68 +1,67 @@ package tetris; /** - * 四格方块类 + * Tetromino class for Tetris game * @author Leslie Leung */ public class Tetromino { - protected Cell[] cells; //用对象数组cells存储四格方块 - protected Cell axis; //旋转轴 - protected Cell[] rotateCells; //需要旋转的格子集合 + protected Cell[] cells; + protected Cell axis; + protected Cell[] rotateCells; /** - * 实现四格方块逆时针转的算法 - * @param axis 旋转轴,以cells中下标为0的Cell为旋转轴 - * @param rotateCells 要旋转的格子的集合 + * Rotate the tetromino counterclockwise + * @param axis The axis cell to rotate around + * @param rotateCells The cells to rotate */ protected void anticlockwiseRotate(Cell axis, Cell[] rotateCells) { - int oldX; //用以表示传进来的rotateCell的横坐标 - int oldY; //用以表示传进来的rotateCell的纵坐标 - int newX; //用以表示传进来的rotateCell旋转后的横坐标 - int newY; //用以表示传进来的rotateCell旋转后的纵坐标 + int oldX; + int oldY; + int newX; + int newY; for(int i = 0; i < 3; i ++) { oldX = rotateCells[i].getX(); oldY = rotateCells[i].getY(); - newX = axis.getX() - axis.getY() + oldY; //新横坐标计算算法 - newY = axis.getY() + axis.getX() - oldX; //新纵坐标计算算法 + newX = axis.getX() - axis.getY() + oldY; + newY = axis.getY() + axis.getX() - oldX; - rotateCells[i].setX(newX); //重新设置目标格子的横坐标 - rotateCells[i].setY(newY); //重新设置目标格子的纵坐标 + rotateCells[i].setX(newX); + rotateCells[i].setY(newY); } } /** - * 实现四格方块顺时针转的算法 - * @param axis 旋转轴,以cells中下标为0的Cell为旋转轴 - * @param rotateCells 要旋转的格子的集合 + * Rotate the tetromino clockwise + * @param axis The axis cell to rotate around + * @param rotateCells The cells to rotate */ protected void clockwiseRotate(Cell axis, Cell[] rotateCells) { - int oldX; //用以表示传进来的rotateCell的横坐标 - int oldY; //用以表示传进来的rotateCell的纵坐标 - int newX; //用以表示传进来的rotateCell旋转后的横坐标 - int newY; //用以表示传进来的rotateCell旋转后的纵坐标 + int oldX; + int oldY; + int newX; + int newY; for(int i = 0; i < 3; i ++) { oldX = rotateCells[i].getX(); oldY = rotateCells[i].getY(); - newX = axis.getX() - oldY + axis.getY(); //新横坐标计算算法 - newY = axis.getY() + oldX - axis.getX(); //新纵坐标计算算法 + newX = axis.getX() - oldY + axis.getY(); + newY = axis.getY() + oldX - axis.getX(); - rotateCells[i].setX(newX); //重新设置目标格子的横坐标 - rotateCells[i].setY(newY); //重新设置目标格子的纵坐标 + rotateCells[i].setX(newX); + rotateCells[i].setY(newY); } } /** - * 实现四格方块的自动下落 + * Move the tetromino down */ protected void softDrop() { - int oldY; //某个格子下落前的纵坐标 - int newY; //某个格子下落后的纵坐标 + int oldY; + int newY; - /* 所有格子下移 */ for(int i = 0; i < cells.length; i ++) { oldY = cells[i].getY(); newY = oldY + 1; @@ -72,13 +71,12 @@ protected void softDrop() { } /** - * 实现四格方块左移的算法 + * Move the tetromino left */ protected void moveLeft() { - int oldX; //某个格子左移前的横坐标 - int newX; //某个格子左移后的横坐标 + int oldX; + int newX; - /* 所有格子左移 */ for(int i = 0; i < cells.length; i ++) { oldX = cells[i].getX(); newX = oldX - 1; @@ -88,13 +86,12 @@ protected void moveLeft() { } /** - * 实现四格方块右移的算法 + * Move the tetromino right */ protected void moveRight() { - int oldX; //某个格子右移前的横坐标 - int newX; //某个格子右移后的横坐标 + int oldX; + int newX; - /* 所有格子右移 */ for(int i = 0; i < cells.length; i ++) { oldX = cells[i].getX(); newX = oldX + 1; @@ -104,40 +101,40 @@ protected void moveRight() { } /** - * 返回四格方块的格子的集合 - * @return Cell的集合 + * Get the cells of the tetromino + * @return Array of cells */ protected Cell[] getCells() { return cells; } /** - * 获取旋转轴 - * @return 旋转轴 + * Get the axis cell + * @return Axis cell */ protected Cell getAxis() { return axis; } /** - * 获取需要旋转的目标格子的集合 - * @return 目标格子的集合 + * Get the cells that need to be rotated + * @return Array of cells to rotate */ protected Cell[] getRotateCells() { return rotateCells; } /** - * 把cells[0]设置为旋转轴 + * Set the axis cell (cells[0]) */ protected void setAxis() { axis = cells[0]; } /** - * 新建长度为3的数组并把cells[1]、cells[2]、cells[3]添加到rotateCells中 + * Set the rotate cells (cells[1], cells[2], cells[3]) */ protected void setRotateCells() { rotateCells = new Cell[]{cells[1], cells[2], cells[3]}; } -} +} \ No newline at end of file diff --git a/Worm/bin/worm/Cell.class b/Worm/bin/worm/Cell.class new file mode 100644 index 0000000..88dcc37 Binary files /dev/null and b/Worm/bin/worm/Cell.class differ diff --git a/Worm/bin/worm/Worm.class b/Worm/bin/worm/Worm.class new file mode 100644 index 0000000..531350a Binary files /dev/null and b/Worm/bin/worm/Worm.class differ diff --git a/Worm/bin/worm/WormFrame.class b/Worm/bin/worm/WormFrame.class new file mode 100644 index 0000000..5d58384 Binary files /dev/null and b/Worm/bin/worm/WormFrame.class differ diff --git a/Worm/bin/worm/WormStage$KeyControl.class b/Worm/bin/worm/WormStage$KeyControl.class new file mode 100644 index 0000000..cd52387 Binary files /dev/null and b/Worm/bin/worm/WormStage$KeyControl.class differ diff --git a/Worm/bin/worm/WormStage$Move.class b/Worm/bin/worm/WormStage$Move.class new file mode 100644 index 0000000..fa8b8d5 Binary files /dev/null and b/Worm/bin/worm/WormStage$Move.class differ diff --git a/Worm/bin/worm/WormStage.class b/Worm/bin/worm/WormStage.class new file mode 100644 index 0000000..0bd6495 Binary files /dev/null and b/Worm/bin/worm/WormStage.class differ