AP计算机科学A(APcomputer science A)复习备考攻略视频教程
43803 人在学
运用java开发打砖块游戏
前面我们已经讲解了如何运用JAVA设计出贪吃蛇的游戏,那么现在我们接下来讲解第二个经典的游戏,称为打砖块游戏,那么这个游戏是怎么做的呢?其实,我现在讲解也只是讲解它的结构,那么具体怎么修改,还是需要大家去想象设计自己喜欢的游戏。
1.首先我们需要新建一个项目Peng,建立一个主类Peng(File-new-Class,输入类名Peng)。
2.再新建一个类MyPanel,(File-new-Class,输入类名MyPanel)代码如下:
import java.awt.*;
import java.awt.event.*;
public class Peng {
public Peng() {
Frame app = new Frame("打砖块,按空格开始");
//监视关闭窗体事件
app.addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent e) {
System.exit(0);
}
});
app.setLocation(100, 100);
MyPanel drawB = new MyPanel(); //实例化MyPanel对象
app.add(drawB, BorderLayout.CENTER); //在窗体中间显示画版
app.pack();//运行app中的pack方法,动态调整frame的大小,使frame中的组件都可见
app.setVisible(true);
drawB.run(); //运行app中的gameStart方法
}
/**
* @param args the command line arguments
*/
public static void main(String[] args) {
new Peng();
// TODO code application logic here
}
}
3.再新建一个类Pad,(File-new-Class,输入类名Pad)
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Point;
public class Pad {
public Point location;//创建一个Point变量locatoin
public Point size;//创建一个Point变量size
private MyPanel gameP;//创建MyPanel实例,获取MyPanel中的一些变量值
public Pad(MyPanel gp) {
gameP = gp;//将MyPanel对象传给gameP
size = new Point(100, 20);//给size变量赋值
location = new Point((gp.width - size.x) / 2, gp.heigth - size.y);//给location变量赋值
}
public void update() {
if (gameP.padMoveRight) {//如果MyPanel中padMoveRight的值是true
if (location.x + size.x < gameP.width) {//如果没到右边缘
location.x += 10;//向右移
}
}
if (gameP.padMoveLeft) {//如果MyPanel中padMoveLeft的值是true
if (location.x > 0) {//如果没到左边缘
location.x -= 10;//向左移
}
}
}
public void draw(Graphics g) {
g.setColor(Color.BLACK);//设置黑色
g.fillRoundRect(location.x, location.y, size.x, size.y,10,10);//画出档板
}
}
4.再新建一个类Block,(File-new-Class,输入类名Block)
import java.awt.*;
public class Block {
private MyPanel gameP; //定义MyPanel实例gameP,用它来获取MyPanel中的变量值
private Point allocation;//定义Point变量
public Point location[];//定义Point数组变量
public Point size;//定义Point变量
public int num;
public boolean exist[];
public Block(MyPanel gp) {
gameP = gp;
num = 20;
allocation = new Point(4, 5);//定义Point变量
size = new Point(50, 20);//定义Point变量
location = new Point[num];//定义Point数组变量
for (int i = 0; i < allocation.y; i++) {
for (int j = 0; j < allocation.x; j++) {
location[i * allocation.x + j] = new Point((gp.width / allocation.x - size.x) / 2 + j * (gp.width / allocation.x), (i * 2 + 1) * size.y);
System.out.println(location[i * allocation.x + j]);
}
}
exist = new boolean[num]; //
for (int i = 0; i < num; i++) {
exist[i] = true;
}
}
public void update() {
}
public void draw(Graphics g) {
g.setColor(Color.gray);
for (int i = 0; i < num; i++) {
if (exist[i] == true) {//定义一个数组,画出大批量砖块,如果exist是true才画
g.fillRect(location[i].x, location[i].y, size.x, size.y);
}
}
}
}
5.最后建一个类Ball(File-new-Class,输入类名Ball)
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Point;
/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
/**
*
* @author Administrator
*/
public class Ball {
private Point location;//定义Point变量
private int diameter;
private int dx;
private int dy;
private MyPanel gameP;//定义MyPanel实例gameP,用它来获取MyPanel中的变量值
private Block blk;//定义Block实例,用它来获取Block中的变量值
private Pad pd;//定义Pad实例,用它来获取Pad中的变量值
private boolean padCanBounce = false;
public Ball(MyPanel gp, Pad p, Block bk) {//将其他几个类的值传递进来
gameP = gp;//获取MyPanel对象
blk = bk;//获取砖块对象
pd = p;//获取档板对象
diameter = 20;//小球的半径
location = new Point(pd.location.x + (pd.size.x - diameter) / 2, pd.location.y - pd.size.y);
//上面一行,是让小球处在档板的中间正上方.
dx = 5;//每次移动的偏移量
dy = -5;//每次移动的偏移量
}
public void update() {
if (gameP.ballMove) { //如果MyPanel中ballMove变量的值是true
location.x += dx;//小球横坐标增加
location.y += dy;//小球纵坐标增加
wallBounced();//碰到墙的事件
blockBounced();//碰到砖块的事件
padBounced();//碰到档板的事件
} else { //如果MyPanel中ballMove变量的值是false
location.setLocation(pd.location.x + (pd.size.x - diameter) / 2, pd.location.y - pd.size.y);
//让小球回到档板正中间,重新开球
}
}
public void draw(Graphics g) {
g.setColor(Color.blue);//设置蓝色
g.fillOval(location.x, location.y, diameter, diameter);//用蓝色画球
}
public boolean Bounce(Point bk_location, Point bk_size) {//判断小球是否撞到砖
if ((location.x > bk_location.x - diameter) && (location.x < bk_location.x + bk_size.x) && (location.y > bk_location.y - diameter) && (location.y < bk_location.y + bk_size.y)) {
return true;//如果小球撞到砖,返回true
} else {
return false;//如果小球没有撞到砖,返回false
}
//以上是用边界检测法判断小球是不是撞到砖,这是非常重要的知识,参考课本P62
}
public void wallBounced() {//判断碰到墙没
if ((location.x > gameP.width - diameter) || (location.x < 0)) {
dx = -dx;//如果左右到达边界,让左右运动方向变成反向
padCanBounce = true;
}
if (location.y < 0) { //如果达到上边边界
dy = -dy; //让上下运动反向
padCanBounce = true;
}
if (location.y > gameP.heigth) { //如果下面到达边界
gameP.ballMove = false; //小球不能运动,GAME OVER
padCanBounce = true;
}
}
public void blockBounced() { //碰到砖块的反弹处理,课本P63页
Point local1, local2, local3, size1, size2, size3;
for (int i = 0; i < blk.num; i++) {
if(blk.exist[i]==false) continue;
local1 = blk.location[i];
size1 = new Point(blk.size.x * 1 / 10, blk.size.y);
local2 = new Point(blk.location[i].x + blk.size.x * 1 / 10, blk.location[i].y);
size2 = new Point(blk.size.x * 8 / 10, blk.size.y);
local3 = new Point(blk.location[i].x + blk.size.x * 9 / 10, blk.location[i].y);
size3 = new Point(blk.size.x * 1 / 10, blk.size.y);
if (Bounce(local2, size2)) {
dy = -dy;
blk.exist[i] = false;
padCanBounce = true;
} else if (Bounce(local1, size1)) {
if (dx > 0) {
dx = -dx;
} else {
dy = -dy;
}
blk.exist[i] = false;
padCanBounce = true;
} else if (Bounce(local3, size3)) {
if (dx < 0) {
dx = -dx;
} else {
dy = -dy;
}
blk.exist[i] = false;
padCanBounce = true;
}
}
}
public void padBounced() {//碰到档板的事件,课本P65页
Point local1, local2, local3, size1, size2, size3;
local1 = pd.location;
size1 = new Point(pd.size.x * 1 / 7, pd.size.y / 4);
local3 = new Point(pd.location.x + pd.size.x * 6 / 7, pd.location.y);
size3 = new Point(pd.size.x * 1 / 7, pd.size.y / 4);
local2 = new Point(pd.location.x + pd.size.x * 1 / 7, pd.location.y);
size2 = new Point(pd.size.x * 5 / 7, pd.size.y / 4);
if (padCanBounce) {
if (Bounce(local2, size2)) {
dy = -dy;
padCanBounce = false;
} else if (Bounce(local1, size1)) {
padCanBounce = false;
if (dx > 0) {
dx = -dx;
}
dy = -dy;
} else if (Bounce(local3, size3)) {
padCanBounce = false;
if (dx < 0) {
dx = -dx;
}
dy = -dy;
}
}
}
}
保存并运行,按空格键开始,用键盘的左右键控制下方的档板移动,反弹小球去击落上面的砖块,注意不要让小球落到下面去,小球落下去就失败了。
小编结语:其实,对于贪吃蛇和打砖块的游戏代码都是十分简单的,重要的是大家能够理解这个框架,然后根据这个框架来设计更有趣的游戏,那么这节课程就到此结束了。
import java.awt.*;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.image.*;
import java.util.*;
public class MyPanel extends Panel implements Runnable, KeyListener {
public int width;
public int heigth;
private Image im;
private Graphics dbg;
private Thread gamethread;
private static final int FPS = 50;
private Ball myball;
private Pad mypad;
private Block myblock;
public boolean padMoveRight = false;
public boolean padMoveLeft = false;
public boolean ballMove = false;
public boolean gameOver = false;
public boolean reStart = false;
public MyPanel() {
width = 400; //设置窗口宽度
heigth = 400; //设置窗口高度
//setBackground(Color.pink);
setPreferredSize(new Dimension(width, heigth));
mypad = new Pad(this);//实例化Pad对象
myblock = new Block(this); //实例化Block对象
myball = new Ball(this, mypad, myblock); //实例化Ball对象
this.setFocusable(true); //获取光标
this.requestFocus(); //获取输入光标
this.addKeyListener(this); //监听窗口
}
public void gameStart() {
gamethread = new Thread(this); //创建线程
gamethread.start(); //开始线程
}
public void gamePaint() { //在内存中画图
Graphics g;
try {
g = this.getGraphics();
if (g != null && im != null) {
g.drawImage(im, 0, 0, null);
}
g.dispose();
} catch (Exception e) {
}
}
public void gameRender() { //画出一个页面
if (im == null) {
im = createImage(width, heigth);
if (im == null) {
System.out.println("im is null");
} else {
dbg = im.getGraphics();
}
}
dbg.setColor(Color.white); //设置白色为底色
dbg.fillRect(0, 0, width, heigth);//用白色画矩形,擦除窗口
myblock.draw(dbg); //调用Block类的draw方法画砖
myball.draw(dbg); //调用Ball类的draw方法画小球
mypad.draw(dbg);//调用Pad类的draw方法画档板
}
public void gameUpdate() {//运动逻辑更新,判断分析小球和档板的运动
isGameOver(); //判断Game Over没有
if (reStart) { //判断是不是重新开始
reSetGame();//重新开始游戏,恢复变量值
reStart = false;
gameOver = false;
ballMove = false;
}
if (!gameOver) { //如果没有Game Over
mypad.update(); //运行Pad类的Update方法控制Pad的运动
myblock.update();//运行Block类的Update方法控制Block的运动
myball.update();//运行Ball类的Update方法控制Ball的运动
}
}
public void isGameOver() { //判断游戏是否结束
int countBlock = 0;//砖块数量清0
for (int i = 0; i < myblock.num; i++) {
if (myblock.exist[i] == true) {
countBlock++;
}
}
if (countBlock == 0) {
gameOver = true;//如果砖块数量是0,就结束
}
}
public void run() {
long t1,t2,dt,sleepTime;
long period=1000/FPS; //设置延时时间
t1=System.nanoTime();
while (true) {
gameUpdate(); //先执行gameUpdate();
gameRender(); //再执行gameRender();
gamePaint(); //然后执行gameUpdate();
t2= System.nanoTime() ; //下面设置延时
dt=(t2-t1)/1000000L;
sleepTime = period - dt;
if(sleepTime<=0)
sleepTime=2;
try {
Thread.sleep(sleepTime);
} catch (InterruptedException ex) { }
t1 = System.nanoTime();
}
}
public void keyTyped(KeyEvent e) { //键盘输入监视
}
public void keyPressed(KeyEvent e) {//键盘按下监视
int keycode = e.getKeyCode();
if (keycode == KeyEvent.VK_RIGHT) {//键盘按下向右键时
padMoveRight = true;
}
if (keycode == KeyEvent.VK_LEFT) {//键盘按下向左键时
padMoveLeft = true;
}
if (keycode == KeyEvent.VK_SPACE) {//键盘按下空格键时
ballMove = true;
}
if (keycode == KeyEvent.VK_R) {//键盘按下R键时
if (gameOver) {
reStart = true;
}
}
}
public void keyReleased(KeyEvent e) {//键盘放开时
int keycode = e.getKeyCode();
if (keycode == KeyEvent.VK_RIGHT) { //键盘放开向右键时
padMoveRight = false;
}
if (keycode == KeyEvent.VK_LEFT) {//键盘放开向左键时
padMoveLeft = false;
}
}
private void reSetGame() { //重置游戏
mypad = new Pad(this);
myblock = new Block(this);
myball = new Ball(this, mypad, myblock);
}
}