双人贪吃蛇(java)
1、双人贪吃蛇
本项目源于【狂神说Java】GUI编程入门到游戏实战,
B站搜UP主:遇见狂神说。即可看见教程
本项目修改为双人贪吃蛇,未采用线程。
本项目仅供学习,侵删。
2、Data数据类
package com.hua.snake;
import javax.swing.*;
import java.net.URL;
//资源路径更改为自己资源的路径
public class Data {
//食物
public static URL foodUrl = Data.class.getResource("/statics/food.png");
public static ImageIcon food = new ImageIcon(foodUrl);
//头部图片
public static URL headerUrl = Data.class.getResource("/statics/header.png");
public static ImageIcon header = new ImageIcon(headerUrl);
//玩家1头部:上下左右
public static URL upUrl1 = Data.class.getResource("/statics/play1/up.png");
public static URL downUrl1 = Data.class.getResource("/statics/play1/down.png");
public static URL leftUrl1 = Data.class.getResource("/statics/play1/left.png");
public static URL rightUrl1 = Data.class.getResource("/statics/play1/right.png");
public static ImageIcon up1 = new ImageIcon(upUrl1);
public static ImageIcon down1 = new ImageIcon(downUrl1);
public static ImageIcon left1 = new ImageIcon(leftUrl1);
public static ImageIcon right1 = new ImageIcon(rightUrl1);
//玩家1身体
public static URL bodyUrl1 = Data.class.getResource("/statics/play1/body.png");
public static ImageIcon body1 = new ImageIcon(bodyUrl1);
//玩家2头部:上下左右
public static URL upUrl2 = Data.class.getResource("/statics/play2/up.png");
public static URL downUrl2 = Data.class.getResource("/statics/play2/down.png");
public static URL leftUrl2 = Data.class.getResource("/statics/play2/left.png");
public static URL rightUrl2 = Data.class.getResource("/statics/play2/right.png");
public static ImageIcon up2 = new ImageIcon(upUrl2);
public static ImageIcon down2 = new ImageIcon(downUrl2);
public static ImageIcon left2 = new ImageIcon(leftUrl2);
public static ImageIcon right2 = new ImageIcon(rightUrl2);
//玩家2身体
public static URL bodyUrl2 = Data.class.getResource("/statics/play2/body.png");
public static ImageIcon body2 = new ImageIcon(bodyUrl2);
}
3、StartGame主方法开启
package com.hua.snake;
import javax.swing.*;
public class StartGame {
public static void main(String[] args) {
//1.新建一个窗口
JFrame frame = new JFrame("Java双人贪吃蛇小游戏");
frame.setBounds(600,10,900,720); // 设置窗口的位置和大小
frame.setResizable(false); //窗口大小不可调整,即固定窗口大小
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); // 设置关闭事件,游戏可以关闭
//2.添加我们自己编写的画布背景
frame.add(new GamePanel());
frame.setVisible(true); //将窗口展示出来
}
}
}
4、Player类
package com.hua.snake;
import javax.swing.*;
public class Player {
//定义蛇的数据结构
int lenth; //蛇的长度
int[] snakeX = new int[600]; //蛇的坐标x
int[] snakeY = new int[500]; //蛇的坐标y
String fx; //蛇的方向 : R:右 L:左 U:上 D:下
ImageIcon up,down,left,right,body; //蛇图像信息
boolean isFail; //判断玩家是否失败
int score; //游戏分数!
//初始化蛇ImageIcon
public void imageSnake1(){
up=Data.up1;
down=Data.down1;
left=Data.left1;
right=Data.right1;
body=Data.body1;
}
public void imageSnake2(){
up=Data.up2;
down=Data.down2;
left=Data.left2;
right=Data.right2;
body=Data.body2;
}
//初始化方法
public void init(String Direction,int snakeHeadx,int snakeHeady) {
fx = Direction; //初始化方向,初始化方向只考虑左或右
lenth = 3;//初始小蛇有三节,包括小脑袋
score = 0; //初始化游戏分数
isFail = false; //初始化玩家游戏结果
//初始化开始的蛇,给蛇定位
if(fx.equals("R")) {
snakeX[0] = snakeHeadx;
snakeY[0] = snakeHeady;
snakeX[1] = snakeHeadx-25;
snakeY[1] = snakeHeady;
snakeX[2] = snakeHeadx-50;
snakeY[2] = snakeHeady;
}else {
snakeX[0] = snakeHeadx;
snakeY[0] = snakeHeady;
snakeX[1] = snakeHeadx+25;
snakeY[1] = snakeHeady;
snakeX[2] = snakeHeadx+50;
snakeY[2] = snakeHeady;
}
}
//小蛇移动
public void snakeMove(Boolean isStart,Boolean isGameOver) {
if (isStart && isGameOver == false) {
//右移:即让后一个移到前一个的位置即可 !
for (int i = lenth - 1; i > 0; i--) { //除了脑袋都往前移:身体移动
snakeX[i] = snakeX[i - 1]; //即第i节(后一节)的位置变为(i-1:前一节)节的位置!
snakeY[i] = snakeY[i - 1];
}
//通过方向控制,头部移动
if (fx.equals("R")) {
snakeX[0] = snakeX[0] + 25;
if (snakeX[0] > 850) snakeX[0] = 25;
} else if (fx.equals("L")) {
snakeX[0] = snakeX[0] - 25;
if (snakeX[0] < 25) snakeX[0] = 850;
} else if (fx.equals("U")) {
snakeY[0] = snakeY[0] - 25;
if (snakeY[0] < 75) snakeY[0] = 650;
} else if (fx.equals("D")) {
snakeY[0] = snakeY[0] + 25;
if (snakeY[0] > 650) snakeY[0] = 75;
}
}
}
}
5、GamePanel游戏面板
package com.hua.snake;
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;
//游戏的面板
public class GamePanel extends JPanel implements KeyListener, ActionListener {
//定义蛇的数据结构
private boolean isStart; //游戏是否开始
private boolean isGameOver; //游戏是否开始
Timer timer = new Timer(100, this); //定时器:第一个参数,就是定时执行时间
//食物
private int foodx;
private int foody;
Random random = new Random();
Player player1 = new Player();
Player player2 = new Player();
//构造方法
public GamePanel() {
this.init();//初始化
player1.init("R", 100, 100); //初始化小蛇定位
player2.init("L", 750, 600);
player1.imageSnake1(); //初始化蛇图像
player2.imageSnake2();
this.setFocusable(true); //获取焦点事件
this.addKeyListener(this); //键盘监听事件
timer.start();
}
//初始化方法
public void init() {
isStart = false; //游戏是否开始
isGameOver = false; //游戏是否开始
//初始化食物数据
foodx = 25 + 25 * random.nextInt(34);//设置随机数范围,避免食物出现在屏幕外
foody = 75 + 25 * random.nextInt(24);
}
/**
* 一开始我们进来我们需要绘制面板
* Alt+ins Overrid 里面有个paintComponent方法用来绘制组件
* 画组件
*
* @param g 游戏中的所有东西,都用这只g画笔来画就够了
*/
public void paintComponent(Graphics g) {
super.paintComponent(g);//清屏
//绘制静态面板
this.setBackground(Color.lightGray); //设置面板的背景色
Data.header.paintIcon(this, g, 25, 11); //绘制头部广告栏
/**
* Paints the icon.
* The top-left corner of the icon is drawn at
* the point (<code>x</code>, <code>y</code>)
* in the coordinate space of the graphics context <code>g</code>.
* If this icon has no image observer,
* this method uses the <code>c</code> component
* as the observer.
*
* @param c the component to be used as the observer
* if this icon has no image observer
* @param g the graphics context
* @param x the X coordinate of the icon's top-left corner
* @param y the Y coordinate of the icon's top-left corner
*/
g.fillRect(25, 75, 850, 600); //绘制游戏区域
//把小蛇画上去paintSnake()
this.paintSnake(g, player1);
this.paintSnake(g, player2);
//画食物
Data.food.paintIcon(this, g, foodx, foody);
g.setColor(Color.BLACK);
g.setFont(new Font("微软雅黑", Font.BOLD, 18));
g.drawString("P1长度 " + player1.lenth, 50, 35);
g.drawString("P1分数 " + player1.score, 50, 50);
g.drawString("P2长度 " + player2.lenth, 750, 35);
g.drawString("P2分数 " + player2.score, 750, 50);
//游戏提示
if (!isStart) {
g.setColor(Color.white);
g.setFont(new Font("微软雅黑", Font.BOLD, 40));
g.drawString("按下空格开始游戏!", 300, 300);
}
//失败判断
if (isGameOver) {
g.setColor(Color.RED);
g.setFont(new Font("微软雅黑", Font.BOLD, 40));
if (player1.isFail) {
g.drawString("玩家1失败, 按下空格重新开始", 200, 300);
} else {
g.drawString("玩家2失败, 按下空格重新开始", 200, 300);
}
g.drawString("玩家1分数为:" + player1.score + ";玩家2分数为:" + player2.score, 150, 350);
}
}
//判断是否失败
public void isFail(Player player1, Player player2) {
//结束判定,头和身体撞到了
for (int i = 1; i < player1.lenth; i++) {
//如果头和身体碰撞,那就说明游戏失败
if (player1.snakeX[i] == player1.snakeX[0] && player1.snakeY[i] == player1.snakeY[0]) {
player1.isFail = true;
isGameOver = true;
}
if (player1.snakeX[i] == player2.snakeX[0] && player1.snakeY[i] == player2.snakeY[0]) {
player2.isFail = true;
isGameOver = true;
}
}
for (int j = 1; j < player2.lenth; j++) {
//如果头和身体碰撞,那就说明游戏失败
if (player2.snakeX[j] == player1.snakeX[0] && player2.snakeY[j] == player1.snakeY[0]) {
player1.isFail = true;
isGameOver = true;
}
if (player2.snakeX[j] == player2.snakeX[0] && player2.snakeY[j] == player2.snakeY[0]) {
player2.isFail = true;
isGameOver = true;
}
}
}
//判定吃到食物
public void eatFood(Player player) {
//吃食物:当蛇的头和食物一样时,算吃到食物!
if (player.snakeX[0] == foodx && player.snakeY[0] == foody) {
//1.长度加一
player.lenth++;
//每吃一个食物,增加积分
player.score = player.score + 10;
//2.重新生成食物
foodx = 25 + 25 * random.nextInt(34);
foody = 75 + 25 * random.nextInt(24);
}
}
//画蛇
public void paintSnake(Graphics g, Player player) {
if (player.fx.equals("R")) { //蛇的头通过方向变量来判断
player.right.paintIcon(this, g, player.snakeX[0], player.snakeY[0]);
} else if (player.fx.equals("L")) {
player.left.paintIcon(this, g, player.snakeX[0], player.snakeY[0]);
} else if (player.fx.equals("U")) {
player.up.paintIcon(this, g, player.snakeX[0], player.snakeY[0]);
} else if (player.fx.equals("D")) {
player.down.paintIcon(this, g, player.snakeX[0], player.snakeY[0]);
}
for (int i = 1; i < player.lenth; i++) {
player.body.paintIcon(this, g, player.snakeX[i], player.snakeY[i]); //蛇的身体长度根据lenth来控制
}
}
@Override
public void keyTyped(KeyEvent e) {
}
//键盘监听事件
@Override
public void keyPressed(KeyEvent e) {
int keyCode = e.getKeyCode(); //获取按下的键盘
if (keyCode == KeyEvent.VK_SPACE) { //如果是空格
if (isGameOver) { //如果游戏失败,从头再来!
init();//初始化
player1.init("R", 100, 100); //初始化小蛇定位
player2.init("L", 750, 600);
} else { //否则,暂停游戏
isStart = !isStart;
}
repaint();
}
//键盘控制走向
if (keyCode == KeyEvent.VK_LEFT) {
player2.fx = "L";
} else if (keyCode == KeyEvent.VK_RIGHT) {
player2.fx = "R";
} else if (keyCode == KeyEvent.VK_UP) {
player2.fx = "U";
} else if (keyCode == KeyEvent.VK_DOWN) {
player2.fx = "D";
}
//键盘控制走向
if (keyCode == KeyEvent.VK_A) {
player1.fx = "L";
} else if (keyCode == KeyEvent.VK_D) {
player1.fx = "R";
} else if (keyCode == KeyEvent.VK_W) {
player1.fx = "U";
} else if (keyCode == KeyEvent.VK_S) {
player1.fx = "D";
}
}
@Override
public void keyReleased(KeyEvent e) {
}
//定时执行的操作
@Override
public void actionPerformed(ActionEvent e) {
//如果游戏处于开始状态,并且没有结束,则小蛇可以移动
player1.snakeMove(isStart, isGameOver);
player2.snakeMove(isStart, isGameOver);
this.eatFood(player1);
this.eatFood(player2);
this.isFail(player1, player2);
this.repaint(); //需要不断的更新页面实现动画
timer.start();//让时间动起来!
}
}
6、游戏截图