接下来的几篇博客,想记录一下通过学习坦克大战项目来循序渐进的学习Java基础。主要是为了巩固基础知识,当然学习编程重要的还是多敲,问题通常是在敲代码的过程中发现的,积累也是在敲代码中寻求的经验。这个坦克大战项目是利用Java图形界面来做的,比较简陋。但是,在不断的往里面加功能的时候,可以学到很多知识,最重要的还是体会Java的面向对象编程思想。下面介绍几个用的上的Demo,最后是坦克大战的1.0版本。

Demo1:回顾事件处理机制

/*
* 功能:事件处理机制(ActionListener的应用)
*/
package com.fanghua1;
import java.awt.*;
import javax.swing.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.*; public class Demo1_1 extends JFrame implements ActionListener {
// 定义一个panel
MyP mp = null;
JButton jb1 = null;
JButton jb2 = null; public static void main(String[] args) {
// TODO Auto-generated method stub
Demo1_1 be = new Demo1_1();
} public Demo1_1() {
mp = new MyP();
jb1 = new JButton("黑色");
jb2 = new JButton("红色"); this.add(jb1, BorderLayout.NORTH);
mp.setBackground(Color.black);
this.add(mp);// 中间是默认的,不用加参数
this.add(jb2, BorderLayout.SOUTH); // 注册监听(this 代表Demo9_4)(每创建一个对象就有一个this)
//jb1、jb2都是事件源对象
jb1.addActionListener(this);
// 指定Action命令
jb1.setActionCommand("aa");
jb2.addActionListener(this);
jb2.setActionCommand("bb"); jb1.addActionListener(new Cat());
jb2.addActionListener(new Cat()); this.setSize(200, 150);
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.setVisible(true);
} @Override
// 对事件处理的方法,actionPerformed函数
//ActionEvent e 是事件对象
public void actionPerformed(ActionEvent e) {
// TODO Auto-generated method stub
// System.out.println("OK");//用来测试监听有没有实现,看控制台
// 判断那个按钮被点击
if (e.getActionCommand().equals("aa")) {
System.out.println("你点击的是黑色");
mp.setBackground(Color.black);
} else if (e.getActionCommand().equals("bb")) {
System.out.println("你点击的是红色");
mp.setBackground(Color.red);
} else {
System.out.println("不知道");
}
} class MyP extends JPanel { public void Paint(Graphics g) {
super.paint(g);
g.fillRect(0, 0, 30, 30); }
}
}
//一个事件源并不是只有一个事件监听者,他可以有多个事件监听者
class Cat implements ActionListener{ @Override
public void actionPerformed(ActionEvent e) {
if(e.getActionCommand().equals("aa")){
System.out.println("我监听到了黑色");
}else if(e.getActionCommand().equals("bb")){
System.out.println("我监听到了红色");
}else{
System.out.println("Nothing");
} } }

Demo2:加深对事件处理机制的理解

/*
* 加深对事件处理机制的理解
* 通过上下左右键,来控制小球的位置
*/
package com.fanghua1;
import java.awt.*;
import javax.swing.*;
import java.awt.event.*; public class Demo1_2 extends JFrame { // 定义
PaintO jp = null; // 构造函数中初始化
public Demo1_2() {
jp = new PaintO(); this.add(jp); this.addKeyListener(jp); this.setSize(400, 300);
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.setVisible(true);
} public static void main(String[] args) {
// TODO Auto-generated method stub
new Demo1_2();
} } // 定义自己的面板
class PaintO extends JPanel implements java.awt.event.KeyListener {
int x = 10;
int y = 10; public void paint(Graphics g) {
super.paint(g);
g.fillOval(x, y, 40, 40);
} @Override
// 键的一个值被输出
public void keyTyped(KeyEvent e) {
// TODO Auto-generated method stub } @Override
// 键被按下
public void keyPressed(KeyEvent e) {
// TODO Auto-generated method stub
// System.out.print("按下"+(char)e.getKeyCode()); if (e.getKeyCode() == KeyEvent.VK_DOWN) {
// x=x;这样就不用写了
y++; // y+=5;提速 // 调用repaint()函数,来重绘界面
this.repaint(); } else if (e.getKeyCode() == KeyEvent.VK_UP) {
y--;
this.repaint();
} else if (e.getKeyCode() == KeyEvent.VK_LEFT) {
x--;
this.repaint();
} else if (e.getKeyCode() == KeyEvent.VK_RIGHT) {
x++;
this.repaint();
} } @Override
// 键被释放
public void keyReleased(KeyEvent e) {
// TODO Auto-generated method stub } }
//功能:事件处理机制 演示1.2
package com.fanghua1;
import java.awt.*;
import javax.swing.*; import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.WindowEvent;
import java.awt.event.WindowListener; public class Demo1_3 extends JFrame { Mypanl1_3 mp1 = null; public static void main(String[] args) {
// TODO Auto-generated method stub
new Demo1_3();
} public Demo1_3() { // 这里经常忘记
mp1 = new Mypanl1_3(); this.add(mp1); // 注册监听
this.addKeyListener(mp1);
this.addMouseListener(mp1);
this.addWindowListener(mp1);
this.addMouseMotionListener(mp1);
// this.addActionListener(mp1); // 按钮用这个,this.addActionListener(mp1); this.setSize(300, 400);
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.setVisible(true); }
} // 这个经常用,java.awt.event.MouseMotionListener 鼠标移动和拖拽
class Mypanl1_3 extends JPanel implements java.awt.event.MouseMotionListener,
KeyListener, MouseListener, WindowListener { public void paint(Graphics g) {
super.paint(g);
} @Override
public void windowOpened(WindowEvent e) {
// TODO Auto-generated method stub
System.out.print("开启窗口被调用" + e.getClass());
} @Override
public void windowClosing(WindowEvent e) {
// TODO Auto-generated method stub } @Override
public void windowClosed(WindowEvent e) {
// TODO Auto-generated method stub
System.out.println("窗口关闭了"); } @Override
public void windowIconified(WindowEvent e) {
// TODO Auto-generated method stub } @Override
public void windowDeiconified(WindowEvent e) {
// TODO Auto-generated method stub } @Override
// 窗口激活
public void windowActivated(WindowEvent e) {
// TODO Auto-generated method stub
System.out.println("窗口激活");
} @Override
// 窗口不激活
public void windowDeactivated(WindowEvent e) {
// TODO Auto-generated method stub
System.out.println("窗口不激活"); } @Override
// 1.鼠标点击
public void mouseClicked(MouseEvent e) {
// TODO Auto-generated method stub
System.out
.println("当前鼠标点击的横坐标是" + e.getX() + "当前鼠标点击de纵坐标是" + e.getY());
} @Override
// 2.鼠标按压,没松开
public void mousePressed(MouseEvent e) {
// TODO Auto-generated method stub
System.out.println("鼠标按压,没松开"); } @Override
// 3.鼠标松开
public void mouseReleased(MouseEvent e) {
// TODO Auto-generated method stub
System.out.println("鼠标松开"); } @Override
// 4.鼠标移动到MyPanel
public void mouseEntered(MouseEvent e) {
// TODO Auto-generated method stub
System.out.println("鼠标移动到面板"); } @Override
// 5.鼠标离开
public void mouseExited(MouseEvent e) {
// TODO Auto-generated method stub
System.out.println("鼠标离开"); } @Override
// 1.键输入 (与 keyPressed的不同是,外围一圈的键都不会有反应)
public void keyTyped(KeyEvent e) {
// TODO Auto-generated method stub } @Override
// 2.键按下(我测试过了:
// 字母和少数键没反应,其他键盘最外一圈F1-F12,Delete等控制台之类都有反应)
public void keyPressed(KeyEvent e) {
// TODO Auto-generated method stub
// 注意:这里切换到美式键盘下演示。我在搜狗输入法下演示了,结果总出不来
System.out.println(e.getKeyChar() + "键按下");
} @Override
// 键松开
public void keyReleased(KeyEvent e) {
// TODO Auto-generated method stub } @Override
// 重要:鼠标拖拽
public void mouseDragged(MouseEvent e) {
// TODO Auto-generated method stub
System.out.println("鼠标拖拽了"); } @Override
// 重要:鼠标移动
public void mouseMoved(MouseEvent e) {
// TODO Auto-generated method stub
// System.out.println("鼠标移动了");
System.out.println("当前移动移动横坐标是" + e.getX() + "当前移动纵坐标是" + e.getY());
}
}

Demo3:进程与线程

/* 功能:进程与线程练习
* Java中一个类要当作线程来使用,方法有两种:
* 1.继承Thread类,并重写run函数
* 2.实现Runnable接口,并重写run函数
* 在这里就可以看出继承(类)和实现(类)的区别了
*/
package com.fanghua1; public class Demo1_4 extends Thread {
public static void main(String[] args) {
// TODO Auto-generated method stub
Demo1_4 de = new Demo1_4();
// 启动run函数
de.start();
} int times = 0; @Override
public void run() {
// TODO Auto-generated method stub
// 在控制台,每隔一秒输出一句“HeLLo Word”
while (true) {
// 每隔一秒=休眠一秒
try {
Thread.sleep(1000);// 1000表示1000毫秒
// sleep 会让该线程进入到Blocked(阻塞)状态,并释放资源
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
times++;
System.out.println("HeLLo Word" + times);
if (times == 10) {
// 退出程序
break;
}
}
}
}
/* 功能:加深理解多线程
* 编写程序,该程序可以接收一个整数n
* 创建一个线程计算从1+......+n 并输出结果
* 创建另一个线程每隔一秒在控制台输出“我是另一个线程,我输出第n个HeLLo”
* 两个工作要同时进行
* 注意:如果说没有任何要求的情况下来开发线程,最好用接口来实现,给别人继承的空间
*之后会具体说继承和实现的区别
*/ package com.fanghua1; public class Demo1_6 { public static void main(String[] args) {
// TODO Auto-generated method stub
new Thread(new Bird(10)).start();
new Thread(new Pig(10)).start(); }
} // 计算需求
class Bird implements Runnable { int n = 0;
int res = 0;
int times = 0;
public Bird(int n) {
this.n = n;
} @Override
public void run() {
// TODO Auto-generated method stub
// 每隔1秒算一次
while (true) {
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
res += (++times);
System.out.print("当前结果是" + res);
if (times == n) {
System.out.print("最后结果是" + res);
break;
}
}
} } // 输出需求
class Pig implements Runnable {
int n = 0;
int times = 0; public Pig(int n) {
this.n = n;
} public void run() {
// TODO Auto-generated method stub
while (true) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println("我是另一个线程,我输出第" + times + "个HeLLo");
times++;
if (times == n) {
break;
}
}
}
}

坦克大战(1.0版本)

/*
* 功能:画出坦克
* 学习:图形界面
*/
package com.fanghua1;
import java.awt.*;
import javax.swing.*; public class MyTankGame1_1 extends JFrame { Mypanel mp=null;
public static void main(String[] args) {
// TODO Auto-generated method stub
new MyTankGame1_1();
} // 构造函数
public MyTankGame1_1() {
mp=new Mypanel();
this.add(mp); this.setSize(600,500);
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.setVisible(true); }
} // 我的面板,不要在JFram上面画坦克,会很乱
class Mypanel extends JPanel{ //定义一个我的坦克
Hero hero=null;
//在构造函数里给坦克意义初始位置
public Mypanel(){
hero=new Hero(10,10);
}
//重写paint函数
public void paint(Graphics g){
//一定要调用
super.paint(g);
//设置背景颜色
g.fillRect(0, 0, 600, 500);
//调用绘画坦克
this.drawTank(hero.getX(), hero.getY(), g, 0, 1); }
//画出坦克的函数
public void drawTank(int x,int y,Graphics g,int direct,int type){
//坦克类型
switch(type){
case 0:
g.setColor(Color.green);
break;
case 1:
g.setColor(Color.yellow);
break;
}
//判断方向
switch(direct){
//向上
case 0:
//画出坦克函数(已封装)
//画出左边的矩形
g.fill3DRect(x,y, 5, 30,false);
g.fill3DRect(x+15, y, 5,30,false);
//画出中间矩形
g.fill3DRect(x+5, y+5, 10, 20,false);
//画出圆形
g.fillOval(x+5, y+10, 10, 10);
//画出线
g.drawLine(x+10,y+15, x+10, y);
break;
} }
} // 坦克类(自己和敌人的坦克的父类)
class Tank {
// x表示坦克的横坐标,y代表坦克的纵坐标
int x = 0;
public int getX() {
return x;
} public void setX(int x) {
this.x = x;
} public int getY() {
return y;
} public void setY(int y) {
this.y = y;
} int y = 0; // 构造函数
public Tank(int x, int y) {
this.x = x;
this.y = y; } } // 我的坦克
class Hero extends Tank {
// 因为坦克里面没有定义无参构造函数
// 会报错:Implicit super constructor Tank() is undefined for default
// constructor. Must define an explicit constructor
// 解决1.在Tank类里面定义无参构造函数。
// 2用父类的构造函数,来初始化子类的成员变量。如下:
public Hero(int x, int y) {
super(x, y);
}
} /*
* public void paint(Graphics g){
*一定要调用
*super.paint(g);
*g.fillRect(0, 0, 600, 500);q
*画出坦克函数(未封装)
*画出左边的矩形
*g.fill3DRect(hero.getX(),hero.getY(), 5, 30,false);
*g.fill3DRect(hero.getX()+15, hero.getY(), 5,30,false);
*画出中间矩形
*g.fill3DRect(hero.getX()+5, hero.getY()+5, 10, 20,false);
*画出圆形
*g.fillOval(hero.getX()+5, hero.getY()+10, 10, 10);
*画出线
*g.drawLine(hero.getX()+10,hero.getY()+15, hero.getX()+10, hero.getY());
*}
*/

坦克大战(1.0.1版本)

/*
* 功能:坦克可移动
* 学习:事件处理机制
*/
package com.fanghua1;
import java.awt.*;
import java.awt.event.KeyEvent; import javax.swing.*; public class MyTankGame1_2 extends JFrame { Mypanel1_2 mp = null; public static void main(String[] args) {
// TODO Auto-generated method stub
new MyTankGame1_2();
} // 构造函数
public MyTankGame1_2() {
mp = new Mypanel1_2();
this.add(mp);
// 注册监听
this.addKeyListener(mp); this.setSize(600, 500);
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.setVisible(true); }
} // 我的面板,不要在JFram上面画坦克,会很乱
class Mypanel1_2 extends JPanel implements java.awt.event.KeyListener { // 定义一个我的坦克
Hero1_2 hero = null; // 在构造函数里给坦克意义初始位置
public Mypanel1_2() {
hero = new Hero1_2(10, 10);
} // 重写paint函数
public void paint(Graphics g) {
// 一定要调用
super.paint(g);
// 设置背景颜色
g.fillRect(0, 0, 600, 500);
// 调用绘画坦克
this.drawTank(hero.getX(), hero.getY(), g, 0, 1); } // 画出坦克的函数
public void drawTank(int x, int y, Graphics g, int direct, int type) {
// 坦克类型
switch (type) {
case 0:
g.setColor(Color.green);
break;
case 1:
g.setColor(Color.yellow);
break;
}
// 判断方向
switch (direct) {
// 向上
case 0:
// 画出坦克函数(已封装)
// 画出左边的矩形
g.fill3DRect(x, y, 5, 30, false);
g.fill3DRect(x + 15, y, 5, 30, false);
// 画出中间矩形
g.fill3DRect(x + 5, y + 5, 10, 20, false);
// 画出圆形
g.fillOval(x + 5, y + 10, 10, 10);
// 画出线
g.drawLine(x + 10, y + 15, x + 10, y);
break;
} } @Override
public void keyTyped(KeyEvent e) {
// TODO Auto-generated method stub } @Override
public void keyPressed(KeyEvent e) {
// TODO Auto-generated method stub
// e.getKeyCode() ==KeyEvent.VK_W 这句话我试了好久,都不能实现
// 原因:我在测试的时候,输入法是搜狗输入法,应该切换到美式键盘或者英文状态下!!!!!
if (e.getKeyCode() == KeyEvent.VK_UP || e.getKeyCode() == KeyEvent.VK_W) {
// 这里有三处不好的地方:
// 1.方向(比如this.hero.y--;)写死了,以后想改变移动速度,这里实现起来麻烦。更正(将“速度”在坦克类里封装成函数)
// 2.重绘(this.repaint();)不用每个都写一遍,在for循环之外,一个就可以了
// 3.方向设置最好按照顺时针或者逆时针,依次。我这个上下左右,容易乱
this.hero.moveUp();// 之前版本:this.hero.y--;
// this.repaint();
// 设置我的坦克的方向
this.hero.setDirect(0);
} else if (e.getKeyCode() == KeyEvent.VK_DOWN
|| e.getKeyCode() == KeyEvent.VK_S) {
this.hero.moveDown();// 之前版本: this.hero.y++;
// this.repaint();
this.hero.setDirect(2);
} else if (e.getKeyCode() == KeyEvent.VK_LEFT
|| e.getKeyCode() == KeyEvent.VK_A) {
this.hero.moveLeft();// 之前版本:this.hero.x--;
// this.repaint();
this.hero.setDirect(3);
} else if (e.getKeyCode() == KeyEvent.VK_RIGHT
|| e.getKeyCode() == KeyEvent.VK_D) {
// this.repaint();
this.hero.setDirect(1);
this.hero.moveRight();// 之前版本:this.hero.x++;
}
this.repaint();
} @Override
public void keyReleased(KeyEvent e) {
// TODO Auto-generated method stub }
} // 坦克类 (自己和敌人坦克的父类)
class Tank1_2 {
// 坦克的坐标:x横坐标,y纵坐标
int x = 0;
int y = 0; // 坦克方向:0表示上,1表示右,2表示下,3表示左
int direct = 0; // 坦克的速度(默认为1,如果将来想给自己和敌人的坦克设置速度,set一下就可以了)
int speed = 1; public int getSpeed() {
return speed;
} public void setSpeed(int speed) {
this.speed = speed;
} public int getDirect() {
return direct;
} public void setDirect(int direct) {
this.direct = direct;
} public int getX() {
return x;
} public void setX(int x) {
this.x = x;
} public int getY() {
return y;
} public void setY(int y) {
this.y = y;
} // 构造函数
public Tank1_2(int x, int y) {
this.x = x;
this.y = y; } } // 我的坦克
class Hero1_2 extends Tank1_2 {
// 因为坦克里面没有定义无参构造函数
// 会报错:Implicit super constructor Tank() is undefined for default
// constructor. Must define an explicit constructor
// 解决:
// 1.在Tank类里面定义无参构造函数。
// 2.用父类的构造函数,来初始化子类的成员变量。如下:
public Hero1_2(int x, int y) {
super(x, y);
} // 坦克向上移动
public void moveUp() {
y -= speed;
} // 坦克向右移动
public void moveRight() {
x += speed;
} // 坦克向下移动
public void moveDown() {
y += speed;
} // 坦克向左移动
public void moveLeft() {
x -= speed;
}
}

Java坦克大战(一)-LMLPHP

接下来几天我会连续更新几篇博客,介绍该坦克大战的渐进完善过程,和中间需要初学者掌握的基础知识,有很多代码实例,也会渐进的增加坦克大战里面的元素和功能。

PS:这个好久之前的了,现在看着有些想看小时候的日记,自我感觉很好玩。

05-04 00:30