
* File: ErsBlocksGame.java
* User: 张丽琼
* Date: May 11, 2009
* Describe: 俄罗斯方块的Java实现
*/
package src
import javax.swing.*
import java.awt.*
import java.awt.event.*
/**
* 游戏主类,继承自JFrame类,负责游戏的全局控制。
* 内含
* 1, 一个GameCanvas画布类的实例引用,
* 2, 一个保存当前活动块(ErsBlock)实例的引用,
* 3, 一个保存当前控制面板(ControlPanel)实例的引用
*/
public class ErsBlocksGame extends JFrame {
/**
* 每填满一行计多少分(每填满一行计100分)
*/
public final static int PER_LINE_SCORE = 100
/**
* 积多少分以后能升级(积满100*20分以后升一级)
*/
public final static int PER_LEVEL_SCORE = PER_LINE_SCORE * 20
/**
* 最大级数是10级
*/
public final static int MAX_LEVEL = 10
/**
* 默认级数是5
*/
public final static int DEFAULT_LEVEL = 5
private GameCanvas canvas//画布类
private ErsBlock block//块类
private boolean playing = false
private ControlPanel ctrlPanel//控制面板类
/**
* javax.swing.JMenuBar菜单栏的实现。将JMenu对象添加到菜单栏以构造菜单。
*当用户选择JMenu对象时,就会显示其关联的JPopupMenu,允许用户选择其上的某一个JMenuItem。
*/
private JMenuBar bar = new JMenuBar()
/**
* javax.swing.JMenu菜单的该实现是一个包含 JMenuItem 的d出窗口,
* 用户选择 JMenuBar 上的项时会显示该 JMenuItem。除 JMenuItem 之外,
* JMenu 还可以包含 JSeparator。
*/
private JMenu
mGame = new JMenu("Game"),
mControl = new JMenu("Control"),
mWindowStyle = new JMenu("WindowStyle"),
mInfo = new JMenu("Information")
/**
* javax.swing.JMenuItem菜单中的项的实现。菜单项本质上是位于列表中的按钮。
* 当用户选择“按钮”时,则执行与菜单项关联的 *** 作。JPopupMenu 中包含的 JMenuItem 正好执行该功能。
*/
private JMenuItem
miNewGame = new JMenuItem("New Game"),
miSetBlockColor = new JMenuItem("Set Block Color ..."),
miSetBackColor = new JMenuItem("Set Background Color ..."),
miTurnHarder = new JMenuItem("Turn up the level"),
miTurnEasier = new JMenuItem("Turn down the level"),
miExit = new JMenuItem("Eixt"),
miPlay = new JMenuItem("Play"),
miPause = new JMenuItem("Pause"),
miResume = new JMenuItem("Resume"),
miStop = new JMenuItem("Stop"),
miAuthor = new JMenuItem("Author : zlq87229@163.com"),
miSourceInfo = new JMenuItem("You can get the source code / document by email")
/**
* javax.swing.JCheckBoxMenuItem可以被选定或取消选定的菜单项。
* 如果被选定,菜单项的旁边通常会出现一个复选标记。如果未被选定或被取消选定,
* 菜单项的旁边就没有复选标记。像常规菜单项一样,复选框菜单项可以有与之关联的文本或图标,
* 或者二者兼而有之。
*/
private JCheckBoxMenuItem
miAsWindows = new JCheckBoxMenuItem("Windows"),
miAsMotif = new JCheckBoxMenuItem("Motif"),
miAsMetal = new JCheckBoxMenuItem("Metal", true)//true默认是显示的这个Metal
/**
* 主游戏类的构造函数
* @param title String,窗口标题
*/
public ErsBlocksGame(String title) {
super(title)
//setSize(315, 392)//设置组件窗口的尺寸大小。
setSize(315,392)
/**
* java.awt.Toolkit此类是所有 Abstract Window Toolkit 实际实现的抽象超类。
* Toolkit 的子类被用于将各种组件绑定到特定本机工具包实现。
*/
Dimension scrSize = Toolkit.getDefaultToolkit().getScreenSize()// 获取屏幕的大小。
/**
* java.awt.Component.setLocation将组件移到新位置。
* java.awt.Component.getSize 以 Dimension 对象的形式返回组件的大小。
* 这里是设置游戏窗口在屏幕上位置。
*/
setLocation((scrSize.width - getSize().width) / 2,
(scrSize.height - getSize().height) / 2)
createMenu()//此方法在下面定义
/**
* Container javax.swing.JFrame.getContentPane() 返回此窗体的 contentPane 对象
*/
Container container = getContentPane()
container.setLayout(new BorderLayout(6,0))
canvas = new GameCanvas(20,12)
ctrlPanel = new ControlPanel(this)
container.add(canvas, BorderLayout.CENTER)//窗口的而局
container.add(ctrlPanel, BorderLayout.EAST)
/**
* void java.awt.Window.addWindowListener(WindowListener l)
* 添加指定的窗口侦听器,以从此窗口接收窗口事件。
*/
addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent we) {
stopGame()//这个方法是自定义的,在下面有。
System.exit(0)
}
})
/**
* void java.awt.Component.addComponentListener(ComponentListener l)
* 添加指定的组件侦听器,以接收发自此组件的组件事件。
*/
addComponentListener(new ComponentAdapter() {
public void componentResized(ComponentEvent ce) {
canvas.fanning()//此方法在GameCanvas类中定义
}
})
//show()//此方法在JDK1.5过时了,采用下面这个方法。
setVisible(true)
canvas.fanning()
}//主游戏类的构造函数到这里写完了
/**
* 让游戏“复位”
*/
public void reset() {
ctrlPanel.reset()
canvas.reset()
}
/**
* 判断游戏是否还在进行
* @return boolean, true-还在运行,false-已经停止
*/
public boolean isPlaying() {
return playing
}
/**
* 得到当前活动的块
* @return ErsBlock, 当前活动块的引用
*/
public ErsBlock getCurBlock() {
return block
}
/**
* 得到当前画布
* @return GameCanvas, 当前画布的引用
*/
public GameCanvas getCanvas() {
return canvas
}
/**
* 开始游戏
*/
public void playGame() {
play()//此方法是自己定义的,在下面
ctrlPanel.setPlayButtonEnable(false)//游戏开始以后禁用“play”按钮。
/**
* void javax.swing.JMenuItem.setEnabled(boolean b)启用或禁用菜单项。
* 在游戏开始以后这个菜单项就不能用了,设置为false.
*/
miPlay.setEnabled(false)
ctrlPanel.requestFocus()// 请求此 Component 获取输入焦点。
}
/**
* 游戏暂停
*/
public void pauseGame() {
if (block != null) block.pauseMove()
ctrlPanel.setPauseButtonLabel(false)
miPause.setEnabled(false)
miResume.setEnabled(true)
}
/**
* 让暂停中的游戏继续
*/
public void resumeGame() {
if (block != null) block.resumeMove()
ctrlPanel.setPauseButtonLabel(true)
miPause.setEnabled(true)
miResume.setEnabled(false)
ctrlPanel.requestFocus()
}
/**
* 用户停止游戏
*/
public void stopGame() {
playing = false
if (block != null) block.stopMove()
miPlay.setEnabled(true)
miPause.setEnabled(true)
miResume.setEnabled(false)
ctrlPanel.setPlayButtonEnable(true)
ctrlPanel.setPauseButtonLabel(true)
}
/**
* 得到当前游戏者设置的游戏难度
* @return int, 游戏难度1-MAX_LEVEL
*/
public int getLevel() {
return ctrlPanel.getLevel()
}
/**
* 让用户设置游戏难度
* @param level int, 游戏难度1-MAX_LEVEL
*/
public void setLevel(int level) {
if (level <11 &&level >0) ctrlPanel.setLevel(level)
}
/**
* 得到游戏积分
* @return int, 积分。
*/
public int getScore() {
if (canvas != null) return canvas.getScore()
return 0
}
/**
* 得到自上次升级以来的游戏积分,升级以后,此积分清零
* @return int, 积分。
*/
public int getScoreForLevelUpdate() {
if (canvas != null) return canvas.getScoreForLevelUpdate()
return 0
}
/**
* 当分数累计到一定的数量时,升一次级
* @return boolean, ture-update successufl, false-update fail
*/
public boolean levelUpdate() {
int curLevel = getLevel()
if (curLevel <MAX_LEVEL) {
setLevel(curLevel + 1)
canvas.resetScoreForLevelUpdate()
return true
}
return false
}
/**
* 游戏开始
*/
private void play() {
reset()
playing = true
Thread thread = new Thread(new Game())
thread.start()
}
/**
* 报告游戏结束了
*/
private void reportGameOver() {
JOptionPane.showMessageDialog(this, "Game Over!")
}
/**
* 建立并设置窗口菜单
*/
private void createMenu() {
bar.add(mGame)
bar.add(mControl)
bar.add(mWindowStyle)
bar.add(mInfo)
mGame.add(miNewGame)
mGame.addSeparator()
mGame.add(miSetBlockColor)
mGame.add(miSetBackColor)
mGame.addSeparator()
mGame.add(miTurnHarder)
mGame.add(miTurnEasier)
mGame.addSeparator()
mGame.add(miExit)
mControl.add(miPlay)
mControl.add(miPause)
mControl.add(miResume)
mControl.add(miStop)
mWindowStyle.add(miAsWindows)
mWindowStyle.add(miAsMotif)
mWindowStyle.add(miAsMetal)
mInfo.add(miAuthor)
mInfo.add(miSourceInfo)
setJMenuBar(bar)
miPause.setAccelerator(
KeyStroke.getKeyStroke(KeyEvent.VK_P, KeyEvent.CTRL_MASK))
miResume.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, 0))
miNewGame.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent ae) {
stopGame()
reset()
setLevel(DEFAULT_LEVEL)
}
})
miSetBlockColor.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent ae) {
Color newFrontColor =
JColorChooser.showDialog(ErsBlocksGame.this,
"Set color for block", canvas.getBlockColor())
if (newFrontColor != null)
canvas.setBlockColor(newFrontColor)
}
})
miSetBackColor.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent ae) {
Color newBackColor =
JColorChooser.showDialog(ErsBlocksGame.this,
"Set color for block", canvas.getBackgroundColor())
if (newBackColor != null)
canvas.setBackgroundColor(newBackColor)
}
})
miTurnHarder.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent ae) {
int curLevel = getLevel()
if (curLevel <MAX_LEVEL) setLevel(curLevel + 1)
}
})
miTurnEasier.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent ae) {
int curLevel = getLevel()
if (curLevel >1) setLevel(curLevel - 1)
}
})
miExit.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent ae) {
System.exit(0)
}
})
miPlay.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent ae) {
playGame()
}
})
miPause.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent ae) {
pauseGame()
}
})
miResume.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent ae) {
resumeGame()
}
})
miStop.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent ae) {
stopGame()
}
})
miAsWindows.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent ae) {
String plaf = "com.sun.java.swing.plaf.windows.WindowsLookAndFeel"
setWindowStyle(plaf)
canvas.fanning()
ctrlPanel.fanning()
miAsWindows.setState(true)
miAsMetal.setState(false)
miAsMotif.setState(false)
}
})
miAsMotif.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent ae) {
String plaf = "com.sun.java.swing.plaf.motif.MotifLookAndFeel"
setWindowStyle(plaf)
canvas.fanning()
ctrlPanel.fanning()
miAsWindows.setState(false)
miAsMetal.setState(false)
miAsMotif.setState(true)
}
})
miAsMetal.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent ae) {
String plaf = "javax.swing.plaf.metal.MetalLookAndFeel"
setWindowStyle(plaf)
canvas.fanning()
ctrlPanel.fanning()
miAsWindows.setState(false)
miAsMetal.setState(true)
miAsMotif.setState(false)
}
})
}
/**
* 根据字串设置窗口外观
* @param plaf String, 窗口外观的描述
*/
private void setWindowStyle(String plaf) {
try {
UIManager.setLookAndFeel(plaf)
SwingUtilities.updateComponentTreeUI(this)
} catch (Exception e) {
}
}
/**
* 一轮游戏过程,实现了Runnable接口
* 一轮游戏是一个大循环,在这个循环中,每隔100毫秒,
* 检查游戏中的当前块是否已经到底了,如果没有,
* 就继续等待。如果到底了,就看有没有全填满的行,
* 如果有就删除它,并为游戏者加分,同时随机产生一个
* 新的当前块,让它自动下落。
* 当新产生一个块时,先检查画布最顶上的一行是否已经
* 被占了,如果是,可以判断Game Over了。
*/
private class Game implements Runnable {
public void run() {
int col = (int) (Math.random() * (canvas.getCols() - 3)),
style = ErsBlock.STYLES[(int) (Math.random() * 7)][(int) (Math.random() * 4)]
while (playing) {
if (block != null) {//第一次循环时,block为空
if (block.isAlive()) {
try {
Thread.currentThread().sleep(100)
} catch (InterruptedException ie) {
ie.printStackTrace()
}
continue
}
}
checkFullLine() //检查是否有全填满的行
if (isGameOver()) { //检查游戏是否应该结束了
miPlay.setEnabled(true)
miPause.setEnabled(true)
miResume.setEnabled(false)
ctrlPanel.setPlayButtonEnable(true)
ctrlPanel.setPauseButtonLabel(true)
reportGameOver()
return
}
block = new ErsBlock(style, -1, col, getLevel(), canvas)
block.start()
col = (int) (Math.random() * (canvas.getCols() - 3))
style = ErsBlock.STYLES[(int) (Math.random() * 7)][(int) (Math.random() * 4)]
ctrlPanel.setTipStyle(style)
}
}
/**
* 检查画布中是否有全填满的行,如果有就删除之
*/
public void checkFullLine() {
for (int i = 0i <canvas.getRows()i++) {
int row = -1
boolean fullLineColorBox = true
for (int j = 0j <canvas.getCols()j++) {
if (!canvas.getBox(i, j).isColorBox()) {
fullLineColorBox = false
break
}
}
if (fullLineColorBox) {
row = i--
canvas.removeLine(row)
}
}
}
/**
* 根据最顶行是否被占,判断游戏是否已经结束了。
* @return boolean, true-游戏结束了,false-游戏未结束
*/
private boolean isGameOver() {
for (int i = 0i <canvas.getCols()i++) {
ErsBox box = canvas.getBox(0, i)
if (box.isColorBox()) return true
}
return false
}
}
}
考虑到美观与功能,所以用到的用到的组件有colorbox,paintbox,panel.panitbox1放在panel上面。线条的颜色可以随时改变。所以增加了其灵活性。
var
x,y:integer
begin
x := 50
y := Height div 2
paintbox1.Canvas.Pen.Color := colorbox1.Selected
paintbox1.Canvas.Brush.Color:=colorbox1.Selected
paintbox1.Canvas.MoveTo(x,y)
paintbox1.Canvas.LineTo(x + 90, y)
end
欢迎分享,转载请注明来源:内存溢出
微信扫一扫
支付宝扫一扫
评论列表(0条)