自制一个弹球小游戏
先来看一下效果:
这是游戏界面:
这是你歇菜的界面:
1.基础的思路:
废话不多说,进入正题,首先我们创建一个PinBall类,然后把相关的类导入进来,并在里面创建一个init方法,在创建主类调用该方法:
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
public class PinBall {
public void init(){
}
public static void main(String[] args) {
new PinBall().init();
}
}
2.创建需要的相关对象和组件:
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
public class PinBall {
Frame frame =new Frame("弹球游戏");
//桌面宽度和高度
private final int TABLE_WIDTH=300;
private final int TABLE_HEIGHT=400;
//球拍的高度和宽度
private final int RACKET_WIDTH=60;
private final int RACKET_HEIGHT=20;
//小球的大小
private final int BALL_SIZE=16;
//定义变量,记录小球的坐标
private int ballX=120;
private int ballY=20;
//定义变量,记录小球在x和y方向分别移动的速度
private int speedX=2;
private int speedY=1;
//定义变量,记录球拍的坐标
private int racketX=120;
private final int racketY=340;
//定义变量,标识当前游戏是否结束
private boolean isOver=false;
//声明一个定时器
private Timer timer;
//自定义一个类,继承Canvas,充当画布
private class MyCanvas extends Canvas{
@Override
public void paint(Graphics g) {
//绘制内容
if(isOver){
//游戏结束时展示的文字
g.setColor(Color.BLUE);//颜色
g.setFont(new Font("Times",Font.BOLD,30));//字体
g.drawString("游戏结束!",50,200);//坐标
}
else {
//游戏中
//绘制小球
g.setColor(Color.black);
//绘制一个实体圆形
g.fillOval(ballX,ballY,BALL_SIZE,BALL_SIZE);
//绘制球拍,实际就是一个矩形
g.setColor(Color.magenta);
g.fillRect(racketX,racketY,RACKET_WIDTH,RACKET_HEIGHT);
}
}
}
//创建绘画区域
MyCanvas drawArea=new MyCanvas();
public void init(){
}
public static void main(String[] args) {
new PinBall().init();
}
}
3.组装视图和游戏逻辑的控制,也就是init()方法,在主类调用即可
public void init(){
//组装视图,游戏逻辑控制
//完成球拍坐标的变化,使用键盘监听器
KeyListener listener =new KeyAdapter() {
@Override
public void keyPressed(KeyEvent e) {
//获取当下按下的键
int keyCode=e.getKeyCode();
if(keyCode==KeyEvent.VK_LEFT)
{//<-应该向左移动,球拍
if(racketX>0){
racketX-=20;
}
}
if(keyCode==KeyEvent.VK_RIGHT)
{//->应该向右移动,球拍
if(racketX<(TABLE_WIDTH-RACKET_WIDTH)){
racketX+=20;
}
}
}
};
//叉叉的监听器
frame.addWindowListener(new WindowAdapter() {
@Override
public void windowClosing(WindowEvent e) {
System.exit(0);
}
});
//给Frame和drawArea注册监听器
frame.addKeyListener(listener);
drawArea.addKeyListener(listener);
//小球坐标的控制
ActionListener task=new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
//根据边界范围修正速度
if(ballX<=0||ballX>=(TABLE_WIDTH-BALL_SIZE)){
speedX=-speedX ;}
if(ballY<=0||(ballY>racketY-BALL_SIZE&&ballX>racketX&&ballX<racketX+RACKET_WIDTH))
{speedY=-speedY;}
if(ballY>racketY-BALL_SIZE&&(ballX<racketX||ballX>racketX+RACKET_WIDTH)){
//当前小球超出球拍范围,游戏结束
//停止定时器
timer.stop();
//修改游戏是否结束标记
isOver=true;
//重绘界面
drawArea.repaint();
}
//更新小球的坐标,重绘界面
ballX+=speedX;
ballY+=speedY;
//重绘界面
drawArea.repaint();
}
};
//间隔10毫秒,来重绘
timer=new Timer(10,task);
timer.start();
//设置画布大小,就是桌面的大小
drawArea.setPreferredSize(new Dimension(TABLE_WIDTH,TABLE_HEIGHT));
frame.add(drawArea);
//设置frame最佳大小并可视
frame.pack();
frame.setVisible(true);
}
完整代码:
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
public class PinBall {
Frame frame =new Frame("弹球游戏");
//桌面宽度和高度
private final int TABLE_WIDTH=300;
private final int TABLE_HEIGHT=400;
//球拍的高度和宽度
private final int RACKET_WIDTH=60;
private final int RACKET_HEIGHT=20;
//小球的大小
private final int BALL_SIZE=16;
//定义变量,记录小球的坐标
private int ballX=120;
private int ballY=20;
//定义变量,记录小球在x和y方向分别移动的速度
private int speedX=2;
private int speedY=1;
//定义变量,记录球拍的坐标
private int racketX=120;
private final int racketY=340;
//定义变量,标识当前游戏是否结束
private boolean isOver=false;
//声明一个定时器
private Timer timer;
//自定义一个类,继承Canvas,充当画布
private class MyCanvas extends Canvas{
@Override
public void paint(Graphics g) {
//绘制内容
if(isOver){
//游戏结束时展示的文字
g.setColor(Color.BLUE);//颜色
g.setFont(new Font("Times",Font.BOLD,30));//字体
g.drawString("游戏结束!",50,200);//坐标
}
else {
//游戏中
//绘制小球
g.setColor(Color.black);
//绘制一个实体圆形
g.fillOval(ballX,ballY,BALL_SIZE,BALL_SIZE);
//绘制球拍,实际就是一个矩形
g.setColor(Color.magenta);
g.fillRect(racketX,racketY,RACKET_WIDTH,RACKET_HEIGHT);
}
}
}
//创建绘画区域
MyCanvas drawArea=new MyCanvas();
public void init(){
//组装视图,游戏逻辑控制
//完成球拍坐标的变化,使用键盘监听器
KeyListener listener =new KeyAdapter() {
@Override
public void keyPressed(KeyEvent e) {
//获取当下按下的键
int keyCode=e.getKeyCode();
if(keyCode==KeyEvent.VK_LEFT)
{//<-应该向左移动,球拍
if(racketX>0){
racketX-=20;
}
}
if(keyCode==KeyEvent.VK_RIGHT)
{//->应该向右移动,球拍
if(racketX<(TABLE_WIDTH-RACKET_WIDTH)){
racketX+=20;
}
}
}
};
//叉叉的监听器
frame.addWindowListener(new WindowAdapter() {
@Override
public void windowClosing(WindowEvent e) {
System.exit(0);
}
});
//给Frame和drawArea注册监听器
frame.addKeyListener(listener);
drawArea.addKeyListener(listener);
//小球坐标的控制
ActionListener task=new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
//根据边界范围修正速度
if(ballX<=0||ballX>=(TABLE_WIDTH-BALL_SIZE)){
speedX=-speedX ;}
if(ballY<=0||(ballY>racketY-BALL_SIZE&&ballX>racketX&&ballX<racketX+RACKET_WIDTH))
{speedY=-speedY;}
if(ballY>racketY-BALL_SIZE&&(ballX<racketX||ballX>racketX+RACKET_WIDTH)){
//当前小球超出球拍范围,游戏结束
//停止定时器
timer.stop();
//修改游戏是否结束标记
isOver=true;
//重绘界面
drawArea.repaint();
}
//更新小球的坐标,重绘界面
ballX+=speedX;
ballY+=speedY;
//重绘界面
drawArea.repaint();
}
};
//间隔10毫秒,来重绘
timer=new Timer(10,task);
timer.start();
//设置画布大小,就是桌面的大小
drawArea.setPreferredSize(new Dimension(TABLE_WIDTH,TABLE_HEIGHT));
frame.add(drawArea);
//设置frame最佳大小并可视
frame.pack();
frame.setVisible(true);
}
public static void main(String[] args) {
new PinBall().init();
}
}
总结:通过这个我学习到了很多,关于监听器和定时器如何使用,明白在重绘时paint方法是AWT系统负责调用。了解到了,动画效果是在不断绘制变化的图像,因为使用定时器的原因,重绘时间短,导致肉眼无法分辨出。