1、帧,如果时间片足够小,就是动画,对于人眼来说,一秒30帧即可看为是动画,拆开就是静态的图片
2、所用工具:键盘监听、定时器Timer
1、步骤
(1)定义数据
(2)画上去
(3)监听事件 —— 键盘监听、事件监听
2、代码
// 导入数据
import javax.swing.*;
import java.net.URL;
/**
* 1、导入图像素材
* 2、添加到图片图标上
*/
public class DataTest {
public static URL headerURL = DataTest.class.getResource("static/header.png"); // logo
public static URL upURL = DataTest.class.getResource("static/up.png"); // 蛇头
public static URL downURL = DataTest.class.getResource("static/down.png"); // 蛇头
public static URL leftURL = DataTest.class.getResource("static/left.png"); // 蛇头
public static URL rightURL = DataTest.class.getResource("static/right.png"); // 蛇头
public static URL bodyURL = DataTest.class.getResource("static/body.png"); // 蛇身
public static URL foodURL = DataTest.class.getResource("static/food.png"); // 食物
public static ImageIcon header = new ImageIcon(headerURL);
public static ImageIcon up = new ImageIcon(upURL);
public static ImageIcon down = new ImageIcon(downURL);
public static ImageIcon left = new ImageIcon(leftURL);
public static ImageIcon right = new ImageIcon(rightURL);
public static ImageIcon body = new ImageIcon(bodyURL);
public static ImageIcon food = new ImageIcon(foodURL);
}
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.util.Random;
/**
* 总体:设置全局变量、构造器、初始化面板、paintComponent绘制面板、keyPressed键盘监听、actionPerformed事件监听
* 继承Jpanel类、 KeyListener, ActionListener接口
*
* 功能:1、设置全局变量:定义蛇的数据结构、食物坐标、成绩、游戏状态(是否开始、是否失败)、定时器
* 2、构造器:调用初始化方法、获得焦点事件、获得键盘监听事件、启动定时器
* 3、初始化面板:蛇(长度、位置、初始方向)、食物随机分布、成绩置为0
* 4、paintComponent绘制面板:清屏、绘制静态面板、画积分、画食物、画小蛇、游戏状态
* 5、keyPressed键盘监听:获得键盘按键、设置提示字符、蛇头换向
* 6、actionPerformed事件监听:检测游戏状态并行动(吃食物长大涨分、移动、转向)、失败判定、开启定时器
*/
public class GamePanelTest extends JPanel implements KeyListener, ActionListener {
// 设置全局变量
int length; //蛇长
// 蛇的坐标
int[] snakeX = new int[600];
int[] snakeY = new int[500];
String direction; // 蛇头方向
//食物坐标(因为随机更换,所以不必设数组来保存上一次的值)
int foodX;
int foodY;
Random random = new Random();
//成绩
int score;
//游戏状态
Boolean isStart; //游戏是否开始
Boolean isFalse; //游戏是否失败
//定时器
Timer timer = new Timer(100,this);
// 构造器
public GamePanelTest(){
init(); //调用初始化方法
this.setFocusable(true); //获得焦点事件
this.addKeyListener(this); //获得键盘监听事件
timer.start(); //启动定时器
}
// 初始化面板
public void init(){
//蛇(长度、位置、初始方向)
length = 3;
snakeX[0] = 100; snakeY[0] = 100;//脑袋位置
snakeX[1] = 75; snakeY[1] = 100;//第一个身体位置
snakeX[2] = 50; snakeY[2] = 100;//第二个身体位置
direction = "right"; // 初始方向向右
//食物随机分布
foodX = 25 + 25*random.nextInt(34); // 850 / 25 = 34
foodY = 75 + 25*random.nextInt(24); // 650 / 25 = 24
//成绩置为0
score = 0;
//游戏状态
isStart = false;
isFalse = false;
}
// paintComponent绘制面板
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g); //清屏
//绘制静态面板
this.setBackground(Color.WHITE);
DataTest.header.paintIcon(this, g, 25, 11); //logo
g.fillRect(25,75,850,650); //游戏界面(黑色)
//画积分
g.setColor(Color.WHITE);
g.setFont(new Font("微软雅黑", Font.BOLD, 16));
g.drawString("长度:" + length, 750, 31);
g.drawString("分数:" + score, 750, 53);
//画食物
DataTest.food.paintIcon(this, g, foodX, foodY);
//画小蛇
//蛇头
if (direction.equals("right"))
DataTest.right.paintIcon(this, g, snakeX[0], snakeY[0]);
else if (direction.equals("left"))
DataTest.left.paintIcon(this, g, snakeX[0], snakeY[0]);
else if (direction.equals("up"))
DataTest.up.paintIcon(this, g, snakeX[0], snakeY[0]);
else if (direction.equals("down"))
DataTest.down.paintIcon(this, g, snakeX[0], snakeY[0]);
//蛇身
for (int i = 1; i < length; i++) {
DataTest.body.paintIcon(this, g, snakeX[i], snakeY[i]);
}
//游戏状态
//是否开始
if (isStart == false){
g.setColor(Color.WHITE);
g.setFont(new Font("微软雅黑", Font.BOLD, 40));
g.drawString("按下空格,开始游戏" , 300, 300);
}
//是否失败
if (isFalse){
g.setColor(Color.RED);
g.setFont(new Font("微软雅黑", Font.BOLD, 40));
g.drawString("游戏失败,按下空格重新开始" , 300, 300);
}
}
// keyPressed键盘监听
@Override
public void keyPressed(KeyEvent e) {
//获得键盘按键
int keycode = e.getKeyCode();
//设置提示字符
if (keycode == KeyEvent.VK_SPACE) {
if (isFalse){
//游戏失败,重新开始
isFalse = false;
init();
}else{
isStart = !isStart; //暂停
}
repaint();
}
//蛇头换向
if (keycode == KeyEvent.VK_UP)
direction = "up";
else if (keycode == KeyEvent.VK_DOWN)
direction = "down";
else if (keycode == KeyEvent.VK_LEFT)
direction = "left";
else if (keycode == KeyEvent.VK_RIGHT)
direction = "right";
}
// actionPerformed事件监听
@Override
public void actionPerformed(ActionEvent e) {
//检测游戏状态并行动(吃食物长大涨分、移动、转向)
if (isStart && isFalse == false){
//吃食物长大涨分
if (snakeX[0]==foodX && snakeY[0]==foodY){
length++; //长度+1
score += 10; //分数+10
// 再次随机生成食物
foodX = 25 + 25*random.nextInt(34); // 850 / 25 = 34
foodY = 75 + 25*random.nextInt(24); // 650 / 25 = 24
}
//移动
for (int i = length-1; i > 0; i--) {
snakeX[i] = snakeX[i-1];
snakeY[i] = snakeY[i-1];
}
//转向
if (direction.equals("right")){
snakeX[0] += 25;
if (snakeX[0] > 850)
snakeX[0] = 25;
}else if (direction.equals("left")){
snakeX[0] -= 25;
if (snakeX[0] < 25)
snakeX[0] = 850;
}else if (direction.equals("up")){
snakeY[0] -= 25;
if (snakeY[0] < 75)
snakeY[0] = 700;
}else if (direction.equals("down")){
snakeY[0] += 25;
if (snakeY[0] > 700)
snakeY[0] = 75;
}
repaint();
}
//失败判定
for (int i = 1; i < length; i++) {
if (snakeX[0]==snakeX[i] && snakeY[0]==snakeY[i])
isFalse = true;
}
//开启定时器
timer.start();
}
// 因继承接口,必须重写的方法
@Override
public void keyTyped(KeyEvent e) {}
@Override
public void keyReleased(KeyEvent e) {}
}
import javax.swing.*;
/**
* 1、创建对象
* 2、设置窗口大小等一系列操作
* 3、将面板添加到框架中
*/
public class StartGameTest extends JFrame {
public static void main(String[] args) {
JFrame frame = new JFrame();
frame.setBounds(10,10,900,780); //设置窗口大小
frame.setResizable(false); //设置窗口大小不可变
frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE); //窗口可关闭
frame.setVisible(true); //设置窗口可见
frame.add(new GamePanelTest()); //添加面板
}
}