学习java很久了,很少完完全全的自己编写一个有难度点的程序。又正好赶上一门课程任务,所以前段时间自己决定用java写一个小游戏,既可以当设计作品又可以练习巩固所学。
这个游戏具体规则如下:
1. 在窗体中央有一座塔,塔的左边或右边会有梯子,但左右不能同时有梯子。
2. 小球初始在最下面的梯子上,按下左键或右键小球向上跳跃。
3. 小球向上跳跃一次,则所有梯子下降一个单位,上方将出现一个方向随机的梯子。
4. 若小球的上方梯子在塔的左方就应该按下左键,若小球的上方梯子在塔的右方就应该按下右键。
5. 若按错方向键,则游戏结束。
6. 小球走过的梯子经过短时间就会断裂消失。
7. 若小球所站的梯子断裂,则游戏结束。
8. 小球走过一个梯子,分数加1。
下面贴上游戏的主流程图(主要是课程要求):
游戏开始后的流程图:
好了,下面给上代码:
import java.awt.Canvas;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import javax.swing.*;
public class Climb extends JFrame implements KeyListener, ActionListener{
private draw d;
private Timer timer;
private char key;
private int score,bestscore;
private JLabel lscore,lbestscore;
public Climb()
{
super("登塔:是男人就上100层!");
this.setBounds(300, 200, 600, 550);
this.setLayout(null);
this.setDefaultCloseOperation(EXIT_ON_CLOSE);
JPanel right=new JPanel();
right.setLayout(null);
right.setBackground(Color.gray);
right.setBounds(400, 0, 200, 550);
this.lscore=new JLabel("当前得分:");
this.lbestscore=new JLabel("最高得分:");
lscore.setBounds(0, 100, 100, 50);
lbestscore.setBounds(0, 200, 100, 50);
right.add(lscore);
right.add(lbestscore);
this.add(right); //加入右边的面板,容纳记录分数的标签和开始按钮
JPanel left=new JPanel();
left.setBackground(Color.lightGray);
left.setBounds(0, 0, 400, 550);
this.addKeyListener(this);
this.setFocusable(true);
this.d=new draw(Color.darkGray);
left.add(this.d);
this.add(left); //加入左边面板,这块面板里加入了一块画布,画布上绘制梯子和球
this.setVisible(true);
timer=new Timer(400, this); //新建一个定时器,每过一定时间触发事件调用actionPeformed
}
public void keyPressed(KeyEvent e) {
}
public void keyReleased(KeyEvent e) {
if(e.getKeyCode()==KeyEvent.VK_SPACE)
{
}
if(e.getKeyCode()==KeyEvent.VK_LEFT)
{
timer.restart(); //及时按下键,则计时器重新开始
this.key=0;
this.score++;
d.move(this.key); //根据按下的键决定小球位置
this.printscore(Integer.toString(score));
this.printbestscore(Integer.toString(bestscore));
}
if(e.getKeyCode()==KeyEvent.VK_RIGHT)
{
timer.restart(); //及时按下键,则计时器重新开始
this.key=1;
this.score++;
d.move(this.key); //根据按下的键决定小球位置
this.printscore(Integer.toString(score));
this.printbestscore(Integer.toString(bestscore));
}
if(key!=d.LorR[3]) //按键错误则游戏结束
{
this.over();
}
}
public void keyTyped(KeyEvent e) {
}
public void actionPerformed(ActionEvent ev) { //若一定时间没按键,则触发事件,调用此函数,将会调用over()函数结束本次游戏
timer.stop();
this.d.broken=1;
this.d.repaint();
this.over();
}
public void printscore(String s)
{
this.lscore.setText("当前得分:"+s);
} //输出当前得分
public void printbestscore(String s)
{
this.lbestscore.setText("最高得分:"+s);
} //输出最高得分
public void init()
{
timer.stop();
for(int i=0;i<5;i++)
{
this.d.LorR[i]=(int)(2*Math.random());
} //为5个初始梯子随机生成代表左右的参数
this.d.lr=this.d.LorR[3];
this.d.repaint();
}
public void over() //游戏结束后调用进行清场并初始化下一次游戏
{
JOptionPane.showMessageDialog(this,"Game Over");
if(this.score>this.bestscore)
{
bestscore=score;
}
this.score=0; //更新最大分数,同时将本次分数清零
this.init();
}
public static void main(String[] args) {
Climb m=new Climb();
m.init();
}
}
class draw extends Canvas
{
private Color color;
protected int lr=0,broken=1;
protected int LorR[]=new int[5]; //表示第i个梯子实在左边还是右边。0左 1右
public draw(Color color)
{
this.color=color;
this.setBounds(0, 0, 400, 550);
}
public void paint(Graphics g)
{
g.setColor(this.color);
g.fillRect(150, 0, 100, 550); //在画布里画出矩形,同时填充这个矩形,充当塔身
for(int i=0;i<5;i++)
{
if((this.LorR[i]==0&&i!=3&&i!=4)||(this.LorR[i]==0&&this.broken==0))
{
g.fillRect(50, 80*(i+1)+i*20, 100, 20);
}
if((this.LorR[i]==1&&i!=3&&i!=4)||(this.LorR[i]==1&&this.broken==0))
{
g.fillRect(250, 80*(i+1)+i*20, 100, 20);
}
} //for循环根据参数画出5个梯子
if(lr==0) {
g.fillOval(75, 330, 50, 50);
}
if(lr==1)
{
g.fillOval(275, 330, 50, 50);
} //根据按下左键还是右键,画出小球位置
if(broken==1) //如果断裂标志为1
{
if(this.LorR[3]==0)
{
g.fillRect(50, 380, 40, 20);
g.fillRect(110, 380, 40, 20);
}
if(this.LorR[3]==1)
{
g.fillRect(250, 380, 40, 20);
g.fillRect(310, 380, 40, 20);
}
if(this.LorR[4]==0)
{
g.fillRect(50, 480, 40, 20);
g.fillRect(110, 480, 40, 20);
}
if(this.LorR[4]==1)
{
g.fillRect(250, 480, 40, 20);
g.fillRect(310, 480, 40, 20);
}
this.broken=0;
} //在梯子的位置画两个小梯子,看起来像断裂的效果
}
public void move(int s)
{
for(int i=4;i>0;i--)
{
this.LorR[i]=this.LorR[i-1];
}
this.LorR[0]=(int)(2*Math.random());
this.lr=s;
this.repaint();
}
//梯子刷新函数,将下面的梯子左右参数改为它上面梯子的左右参数。依次类推,最上面的梯子还是随机生成方向。这样梯子看起来想在向下运动。
}
运行后是这样子的:
由于自己编程经验欠缺,设计思路有些混乱,代码结构可能也不完美。但是还是实现了功能。这次完全的自身实战(每用过别人一行代码)完成后,发现有些事自己亲自动手了还是没有想象中难(信心小增强)。特地在此记录一下。
记录一下遇到的主要困难吧:
1. 开始窗口总是接受不到键盘事件。
原因:窗口失去了焦点,这需要设置窗口成焦点。
2. 开始在画布上画图但运行后每效果。
解决:在继承了画布的类的构造函数加了设置大小的代码就ok了,而且这个大小设置的和左边面板一样,这样画布就是完全覆盖了面板。
当然,游戏还是有很多的不足,最大的问题就是画面太low,要是有兴趣给这个游戏贴图(背景、塔身、梯子、人)的朋友贴好了还请发我一份。贴好图后可玩性还是可以的,移植到手机端可玩性更高。
最后说一下:这是我自己一个人写的程序,源码也都给出了,转载的还请注明。