贪吃蛇第三弹
要求:创建一个界面,并在界面中画单元格,添加一个线程控制重画,添加键盘方向键来控制蛇的移动
代码:
第一个类
package snake;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.event.KeyEvent;
public class Snake {
// 确定蛇的位置
private int x;
private int y;
// 确定蛇的大小
private static final int width = 25;
private static final int height = 25;
// 实例化方向类
private Direction dir = Direction.D;
// 调用SnakeMain类
private SnakeMain sankeMain;
// 构造带3个参数的方法
public Snake(int x, int y, SnakeMain snakeMain) {
this.x = x;
this.y = y;
this.sankeMain = snakeMain;
}
// 构造带4个参数的方法
public Snake(int x, int y, Direction dir, SnakeMain snakeMain) {
this(x, y, snakeMain);
this.dir = dir;
}
public void draw(Graphics g) {
// 调用画笔
Color c = g.getColor();
g.setColor(Color.BLACK);// 设置画笔颜色
g.setColor(c);
g.fillRect(x, y, width, height);// 画填充了颜色矩形小蛇
}
public void keyPressed(KeyEvent e) {
// 获取键盘上的键入的方向事件
int key = e.getKeyCode();
switch (key) {
case KeyEvent.VK_LEFT: // 键入为左
this.x = x - width; // 相对原位置减一个宽度
break;
case KeyEvent.VK_UP: // 键入为上
this.y = y - height; // 相对原位置减一个高度
break;
case KeyEvent.VK_RIGHT: // 键入为右
this.x = x + width; // 相对原位置加一个宽度
break;
case KeyEvent.VK_DOWN: // 键入为下
this.y = y + height;// 相对原位置加一个高度
break;
}
// 边界控制
if (x <= 0) {
x = 0;
} else if (x > SnakeMain.SNAKE_WIDTH - width) {
x = SnakeMain.SNAKE_WIDTH - width;
}
if (y <= 0) {
y = 0;
} else if (y > SnakeMain.SNAKE_HEIGHT - height) {
y = SnakeMain.SNAKE_HEIGHT - width;
}
}
}
第二个类:
package snake;
public enum Direction {
L,U,R ,D //枚举列出4个方向LEFT,UP,RIGHT,DOEN
}
第三个类
package snake;
import java.awt.Color;
import java.awt.Frame;
import java.awt.Graphics;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
/**
* 项目名称:Snake
* 创建人:YM
* 类描述: 创建一个界面,并在界面中画单元格,添加一个线程控制重画,添加键盘方向键来控制蛇的移动
* 创建时间:2019年1月16日 下午2:59:06
*
*/
public class SnakeMain extends Frame {
static final int SNAKE_WIDTH = 1000; // 定义组件的宽度
static final int SNAKE_HEIGHT = 600; // 定义组件的高度
private static final int squareSize = 25; // 用来确定单元格的大小
Snake s = new Snake(50,50,Direction.D,this);//实例化一个对象,确定蛇的位置
public static void main(String[] args) {
SnakeMain s = new SnakeMain(); // 构建SnakeMai类的一个实例,并命名为s
s.launchFrame(); // 调用实例中的launchFrame()方法
}
private void launchFrame() {
this.setLocation(100, 100); // 确定组件位置
this.setSize(SNAKE_WIDTH, SNAKE_HEIGHT); // 确定组件大小
this.setBackground(Color.WHITE); // 确定组件背景颜色
this.setTitle("我的贪吃蛇"); // 设置窗口的标题
// 添加关闭的处理事件
this.addWindowListener(new WindowAdapter() {
// 添加一个窗口监听
@Override
public void windowClosing(WindowEvent e) {
System.exit(0); // 窗口关闭事件
}
});
// 禁止改变窗的大小
this.setResizable(false);
this.setVisible(true);
//通过调用线程运行启动线程
new Thread(new MyPaintThread()).start();
//通过添加指定的按键侦听器,以接收此组件的按键事件
this.addKeyListener(new MyKeyListener());
}
@Override
public void paint(Graphics g) {
// 调用画笔
Color c = g.getColor();
g.setColor(Color.GRAY); // 设置画笔颜色
g.setColor(c);
int xweight = SNAKE_WIDTH / squareSize;
int xheight = SNAKE_HEIGHT / squareSize;
// 画线
for (int i = 0; i < xweight; i++) {
g.drawLine(i * squareSize, 0, i * squareSize, SNAKE_HEIGHT);
} // 画纵向的线
for (int i = 0; i < xheight; i++) {
g.drawLine(0, i * squareSize, SNAKE_WIDTH, i * squareSize);
} // 画横向的线
s.draw(g); //调用画小蛇的方法
}
private class MyPaintThread implements Runnable{
//通过新建一个MyPaintThread类来实现Runnable接口
//重画线程
@Override
public void run() {
//线程的入口
//每隔50ms重画一次
while(true){
repaint();//会自动调用paint方法
try {
//指定捕获异常的类型
Thread.sleep(50);
} catch (InterruptedException e)
//InterruptedException异常是指当一个当一个正在执行的线程被中断
{
e.printStackTrace();//在命令行中打印异常信息在程序中出错的位置既原因
}
}
}
}
private class MyKeyListener extends KeyAdapter{
// 键盘监听类
@Override
public void keyPressed(KeyEvent e) {
s.keyPressed(e);
}
}
}
从贪吃蛇第三弹中学到的知识点:
1,public enum Direction
Direction是Java.lang.enum的子类,其内部包含方向信息,其枚举出来的量可用于Switch语句
2,线程Thread
java的多线程系统构建在Thread类,方法以及Runnable接口之上,Thread封装了线程的执行,如果不能直接引用一个运行的线程状态,可以通过产生它的线程实例来处理它,也可以通过继承Thread类或者实现Runnable接口创建一个新线程,Thread类定义了几个管理线程的方法如下:
getName():获得线程的名字
getPriority():获得线程的优先级
jsAlive():判断线程是否仍在运行
jion():等待一个线程终止
run():线程入口
sleep():暂停一个线程一段时间
start():通过调用线程的运行方法启动它
Runnable接口抽象了可执行的代码单元,Runnable只是一个接口,它里面只有一个run()方法,没有start()方法,所以即使实现了Runnable接口,也无法启动线程,必须依托其他类,即实现接口后,需要依靠Thread来启动
3,KeyPressed(KeyEvent e)键盘按键函数,函数每按下一次时都会被调用一次,按下的键被保存在存储变量中
KeyReleased(KeyEvent e)在源组件上释放一个键后被调用
KeyTyped(KeyEvent e)在源组件上上按下一个键然后释放该键后被调用
KeyListener是键盘监听器,使用时需要继承KeyAdapter类
KeyAdapter类是KeyListener键盘监听器的适配器,每一个KeyAdapter都对应一个或多个KeyListener
KeyEvent()按键事件可以利用键盘来控制和执行一些动作,或者从键盘获取输入,只要按下,释放一个键或者在组件上敲击,就会触发事keyEvent对象描述事件的特性和对应的值,每个按键事件有一个相关的按键字符
getKeyChar()和按键代码getKeyCode()
按键常量: VK_HOME Home键
VK_CONTROL 控制键
VK_END End键
VK_SHIFT Shift键
VK_PGUP page up键
VK_BACK_SPACE 退格键
VK_PGDN page dowm键
VK_CAPS_LOCK 大小写锁定键
VK_ENTER 回车键
VK_NUM_LOCK 小写键盘锁定键
VK_UP 上箭头
VK_DOEN 下箭头
VK_LEFT 左箭头
VK_RIGHT 右键头
VK_F12 F1-F12
VK_ESCAPE Esc键
VK_9 0-9
VK_TAB Tab键
VK_Z A-Z
4,构造函数:在创建对象时就对其进行初始化,即为对象成员变量赋初值,它与其所在的类具有相同的名称,并且在语法上与方法类似,与运算符NEW一起使用在创建对象语句中,能够把定义对象时的参数传给对象的域,即当创建一个对象时,这个对象就被初始化,可以根据其参数个数的不同或参数类型不同来区分它们。如果写的一个类里面没有构造函数,那么编译器会默认加上一个无参数且方法体为空的构造函数,
构造函数的名称必须与类名相同,包括大小写
构造函数没有返回值,也不能用void修饰,如果在构造函数前添加了返回值类型,将使该钩爪函数变成一个普通的方法
5,this关键字:this关键字代表对象本身,,在程序内部,可以在任何方法内使用this关键字引用当前对象,在构造函数中可以使用this关键字调用本类中的其他构造函数,当有几点要求
1,构造函数调用其它的构造函数,需要将this写在构造函数的第一行
2,构造函数不可递归,防止死循化
6,implements接口
实现接口需要注意的问题:
1,实现一个接口就是要实现该接口的所有方法,抽象类除外
2,接口中所有的方法都是抽象的
3,多个无关类可以实现同一个接口,一个雷可以实现多个无关接口
7,try和catch
Java运行时系统提供默认异常处理,这样做不仅可以允许你修正错误,而且可以防止程序自动终止,要防止和处理运行错误时,需要将监控代码写在try块中,然后在try块后面紧跟一个catch字句,该字句指定了需要捕获的异常类型,如果没有try的话,会出现异常导致程序崩溃
try{
//代码区
}catch(Exceotion e){
//异常处理
}
如果代
码区有错误,会返回所写的异常处理