Java小游戏——贪吃蛇,包括简单的文件写入读取功能(即英雄榜)
由于服务器问题,分为两部分,此乃上篇
程序包含7个类:Food,Snake,SnakePanel,SnakeFrame,SnameMenu,KeySetDialog和HeroDialog
此类的主要功能是生成食物,得出食物坐标
import java.awt.Color;
import java.awt.Graphics;
import java.util.Random;
public class Food {
privateboolean life=false;//有无食物
private intx;//食物横坐标
private inty;//食物纵坐标
privateRandom random;//随机数
publicFood(){
random=new Random();
this.getFood();//得到食物
}
public voidgetFood(){
if(!life){
//没有食物,得到食物
x=random.nextInt(360)+120;//随机食物横坐标120-480
y=random.nextInt(360)+120;//随机食物横坐标120-480
//以下两个while使食物落在整格内
while(x !=0){
x--;
}
while(y !=0){
y--;
}
life=true;//标明有食物了
}
}
public voiddrawFood(Graphics g){
if(life){
//食物存在,画出
g.setColor(Color.RED);//设置画笔红色
g.fillOval(x, y, 20, 20);//画圆
}
}
//get,set函数,用于类对象对本类数据的访问
publicboolean isLife(){
return life;//返回life的值
}
public voidsetLife(boolean life){
this.life=life;//设置life的值
}
public intgetX(){
return x;//返回当前食物的横坐标
}
public intgetY(){
return y;//返回当前食物的纵坐标
}
}
此类的作用是构造一条蛇,设定蛇的行走,吃食物规则,以及蛇死的检测
在此类设定画蛇的方法和重新开始时重新构造蛇
import java.awt.Color;
import java.awt.Graphics;
import java.util.Arrays;
public class Snake {
public finalstatic int Left=0;//左
public finalstatic int Up=1;//上
public finalstatic int Right=2;//右
public finalstatic int Down=3;//下
publicstatic boolean start=false;//控制开始
publicstatic boolean pause=false;//控制暂停
publicstatic int gameSpeed=800;//蛇行速度
private intscore;
private intlen=2;//长度,初始为2
private intdir=Right;//方向,初始向右
privateboolean life=true;//存活
privateint[] x;//横坐标
privateint[] y;//纵坐标
private Foodfood;//创建食物对象
//构造器
publicSnake(Food food){
x=new int[len];
y=new int[len];
x[0]=160;y[0]=140;//初始化蛇身
x[1]=140;y[1]=140;
this.food=food;//
}
public voidrun(){
//蛇运动
//以倒数第二节的坐标给最后一节的坐标,一节一节给坐标实现蛇的移动
//如3节蛇:x[3]=x[2];x[2]=x[1];x[1]=x[0]
//经此过程,除了蛇头,其他蛇节全往前移动1节
for(int i=len-1;i>0;i--){
x[i]=x[i-1];//从后面起 把前1节坐标给后一节
y[i]=y[i-1];
}
}
public voiddirection(){
//此方法根据蛇运动的方向实现蛇头的移动
//蛇方向向哪边,蛇头向该方向移动1格
switch(dir){
//向左移动1格,x[0]-20;
case Left:x[0]-=20;break;
//上y[0]-
case Up:y[0]-=20;break;
//右x[0]+
case Right:x[0]+=20;break;
//下y[0]+
case Down:y[0]+=20;break;
}
}
publicboolean isDead(){
//蛇死,2种死法,撞墙死、撞自己死
//撞墙死,左上右下墙
if(x[0]<100||y[0]<100||x[0]>480||y[0]>480){
life=false;//蛇撞墙,笨死了
}
//自己撞自己
for(int i=3;i
if(x[0]==x[i]&&y[0]==y[i]){
life=false;//蛇头撞蛇身,2死了
}
}
return !life;//没活就是isDead
}
public voiddrawSnake(Graphics g){
//画出蛇身
for(int i=0;i
if(i==0){
//蛇头
g.setColor(newColor(255,0,255,150));//画笔颜色(蓝色)
}else{
g.setColor(Color.BLUE);//画笔颜色(蓝色)
}
g.fillRect(x[i], y[i], 20, 20);//画矩形
g.setColor(new Color(255,255,255));
g.drawRect(x[i], y[i], 20, 20);
}
}
public voideatFood(){
//蛇吃食物的过程
if(x[0]==food.getX()&&y[0]==food.getY()){
//蛇头坐标与食物坐标相等 即吃到食物
len++;//吃到食物,蛇长+1
x=Arrays.copyOf(x,x.length+1);//横坐标数组长度+1
y=Arrays.copyOf(y,y.length+1);//纵坐标数组长度+1
x[len-1]=-20;//刚吃到的1节放在阴影处
y[len-1]=-20;
food.setLife(false);//食物被吃,没有了
//以下语句判断加分情况和加速情况
if(score<100){
score+=10;//吃1个加10分
Snake.gameSpeed=800;//速度800;
}else if(score<200){
score+=20;//吃1个加20分
Snake.gameSpeed=500;//速度500;
}else if(score<250){
score+=10;//吃1个加10分
Snake.gameSpeed=300;//速度300;
}else if(score<300){
score+=5;//吃1个加5分
Snake.gameSpeed=200;//速度200;
}else if(score<350){
score+=5;//吃1个加5分
Snake.gameSpeed=100;//速度100;
}else{
score+=5;//吃1个加5分
Snake.gameSpeed=50;//速度50;
}
}
}
publicboolean game(){
//蛇吃食物的运动全过程
food.getFood();//先生成食物,引蛇出动
if(!isDead()){//蛇没死就可继续走
run();//根据设定的规则移动蛇身
direction();//根据方向移动蛇头
isDead();//移动后继续判断蛇是否会死
eatFood();//判断有没有食物吃
}
return life;//返回蛇的存亡状态
}
public voidreGame(){
//重新开始游戏
start=false;//游戏没开始
Snake.gameSpeed=800;
score=0;//重置分数
life=true;//蛇重新活过来
dir=Snake.Right;//重新调整方向
len=2;//蛇长还原2
x=Arrays.copyOf(x,len);//还原横坐标长度
y=Arrays.copyOf(y,len);//还原纵坐标
x[0]=160;y[0]=140;//还原初始化蛇身
x[1]=140;y[1]=140;
food.setLife(false);//取消已有食物
food.getFood();;//重新生成食物
}
//getset函数
public intgetDir(){
return dir;//返回当前方向
}
public voidsetDir(int dir){
this.dir=dir;//设置方向
}
publicboolean isLife(){
return life;//返回当前蛇的life
}
public intgetScore(){
return score;//返回得分
}
}
此类为面板类,在此类画蛇,食物以及围墙!在此类添加线程,启动贪吃蛇,监听键盘事件,控制贪吃蛇的方向
判定游戏结束的动作,对比英雄榜,写入英雄榜,
import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.LineNumberReader;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
public class SnakePanel extends JPanel implementsKeyListener,Runnable{
publicstatic int Left_Key=KeyEvent.VK_A;//向左按键,默认为A
publicstatic int Up_Key=KeyEvent.VK_W;//向上按键,默认为W
publicstatic int Right_Key=KeyEvent.VK_D;//向右按键,默认为D
publicstatic int Down_Key=KeyEvent.VK_S;//向右按键,默认为S;
publicstatic double gameTime;//游戏时间
privateSnake snake;//创建蛇对象
private Foodfood;//创建食物对象
private FileheroFile;//英雄榜文件
privateFileWriter heroWriter;//写入
privateFileReader heroReader;//读取
publicSnakePanel(){
food=new Food();
snake=new Snake(food);
this.setBackground(Color.GRAY);//设定背景色
heroFile=new File("hero.dat");//设定英雄榜存储文件
}
public voidpaint(Graphics g){
super.paint(g);
//以下5句代码画出围墙
g.setColor(Color.DARK_GRAY);
g.fillRect(80,80, 420,20);
g.fillRect(80,500, 420,20);
g.fillRect(80,100, 20,400);
g.fillRect(500,80, 20,440);
//画出得分和时间
Font font=new Font("宋体",Font.BOLD,22);//字体
g.setColor(Color.RED);//设置颜色
g.setFont(font);//设置字体
g.drawString("得分:"+snake.getScore(),180,70);
g.drawString("时间:"+gameTime, 300, 70);
//画方格
g.setColor(Color.GREEN);//画笔绿色
for(int i=100;i<=500;i+=20){
//画方格
g.drawLine(100,i,500,i);//画横线
g.drawLine(i,100,i,500);//画竖线
}
snake.drawSnake(g);//画蛇
food.drawFood(g);//画食物
}
//键盘监听事件
@Override
public voidkeyPressed(KeyEvent e) {
// TODO Auto-generated method stub
//键盘按下事件
int key=e.getKeyCode();
if(key==SnakePanel.Left_Key&&snake.getDir()!=Snake.Right){
//当前方向不向右且按下自定的左方向键
snake.setDir(Snake.Left);
}
if(key==SnakePanel.Up_Key&&snake.getDir()!=Snake.Down){
//当前方向不向下且按下自定的上方向键
snake.setDir(Snake.Up);
}
if(key==SnakePanel.Right_Key&&snake.getDir()!=Snake.Left){
//当前方向不向左且按下自定的右方向键
snake.setDir(Snake.Right);
}
if(key==SnakePanel.Down_Key&&snake.getDir()!=Snake.Up){
//当前方向不向上且按下自定的下方向键
snake.setDir(Snake.Down);
}
}
@Override
public voidkeyReleased(KeyEvent e) {
// TODO Auto-generated method stub
}
@Override
public voidkeyTyped(KeyEvent e) {
// TODO Auto-generated method stub
}
//游戏结束的时候匹配英雄榜文件
public intamIHero(){
//每次游戏结束检查自己是否上英雄榜
int places=6;//你的排名,初始化在5名开外,没有上榜
String[] nameHero=newString[5];//用来存放从英雄榜文件读取来的名字文件
int[] scoreHero=newint[5];//用来存放从英雄榜文件读取来的积分
double[] timeHero=newdouble[5];//用来存放从英雄榜文件读取来的时间
try{
heroReader=newFileReader(heroFile);//面向字符输入流
LineNumberReader lnr=newLineNumberReader(heroReader);//
int nameCount=0;//已读取name数据个数
int scoreCount=0;//已读取score数据个数
int timeCount=0;//已读取time数据个数
while(true){
String data=lnr.readLine();//读取数据
if(data==null){
//没有数据了 跳出循环
break;
}else{
//还有数据 读取
if(lnr.getLineNumber()%3==1){
//1行 name
nameHero[nameCount++]=data;
}else if(lnr.getLineNumber()%3==2){
//2行 score
scoreHero[scoreCount++]=Integer.parseInt(data);//转换数据类型
}else{
//3行 time
timeHero[timeCount++]=Double.parseDouble(data);//转换数据类型
}
}
}
lnr.close();//关闭流
heroReader.close();
}catch(IOExceptione){
}//数据读完,对比数据
for(int i=scoreHero.length-1;i>=0;i--){
//先对比积分,从最后1名开始对比
if(snake.getScore()
//积分低,不能上榜
break;//直接跳出循环
}else if(snake.getScore()==scoreHero[i]){
//刚好可能上榜,对比时间
if(gameTime
//时间更少,可以上榜
places=i+1;//击败他,占有他的排名
continue;//进入下一个循环,比对上一排名
}
}else{
//足够上榜
places=i+1;//击败他,占有他的排名
continue;//进入下一个循环,比对上一排名
}
}
//System.out.println(places);
//上榜了就要修改英雄榜文件数据,没有则不做处理
if(places>=6){
//没有上榜
}else{
//上榜了
//把你后面的排名往后挪1位
for(inti=nameHero.length-1;i>places-1;i--){
nameHero[i]=nameHero[i-1];//更改名字排名
scoreHero[i]=scoreHero[i-1];//更改得分排名
timeHero[i]=timeHero[i-1];//更改时间排名
}
//请求输入姓名
StringgetName=JOptionPane.showInputDialog(this,"请输入你的名字");
if(getName==null||getName.equals("")||getName.length()>5){
//没有输入,输入1个空格,输入过长都显示匿名
getName="匿名";//匿名
}
//更新数据
nameHero[places-1]=getName;//更新name
scoreHero[places-1]=snake.getScore();//更新score
timeHero[places-1]=gameTime;//更新time
//把数据写入文件
try{
heroWriter=new FileWriter(heroFile);
for(int i=0;i
heroWriter.write(nameHero[i]+"n");//写入name
heroWriter.write(scoreHero[i]+"n");//写入score
heroWriter.write(timeHero[i]+"n");//写入time
}
heroWriter.close();//关闭流
}catch(IOException e){}
}
return places;//返回你的排名
}
//线程运行
@Override
public voidrun() {
// TODO Auto-generated method stub
while(true){
if(Snake.start&&!Snake.pause){
//游戏已开始且没有暂停 蛇运动
if(!snake.game()){
//snake.game==life=false;
//即蛇以死
String message="是否重新开始游戏?";
int num=amIHero();//对比英雄榜文件,返回排名
if(num>=6){
//没进入排行榜,鼓励一下
message="再接再励!"+message;
}else{
//进入排行榜,恭喜恭喜
message="恭喜,英雄榜第"+num+"名!"+message;
}
//蛇死弹出对话框选择是否重新开始游戏
intregame=JOptionPane.showConfirmDialog(this,message,
"重新开始",JOptionPane.YES_NO_OPTION);
if(regame==0){
//重新开始
snake.reGame();//重新初始化参数
gameTime=0;//时间设置0
repaint();//重画面板
continue;//继续下一个循环
}else{
//选择否,退出游戏
System.exit(0);
break;
}
}
try {
Thread.sleep(Snake.gameSpeed);//线程,睡眠gameSpeed段时间
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
gameTime+=(double)(Snake.gameSpeed)/1000;//得出游戏时间
gameTime= Math.round(10 *gameTime)/10.0;//控制时间格式保留1位小数点
//System.out.println(gameTime);
repaint();//重画面板
}
}
}
}
窗口类,注册键盘监听事件,添加面板类和工具栏
importjavax.swing.JFrame;
public class SnakeFrame extends JFrame{
privateSnakePanel spanel;//SnakePanel对象
privateSnakeMenu smenu;//工具栏
publicSnakeFrame(){
spanel=new SnakePanel();
smenu=new SnakeMenu(this);
this.addKeyListener(spanel);//添加面板键盘监听事件
this.addKeyListener(smenu);//添加工具栏键盘监听事件
new Thread(spanel).start();//启动线程
this.add(spanel);//添加面板
this.setJMenuBar(smenu);//设置工具栏
this.setTitle("贪吃蛇");//设置标题
this.setSize(600,600);//设置窗口大小
this.setVisible(true);//打开窗口
this.setDefaultCloseOperation(EXIT_ON_CLOSE);//窗口注销事件
}
publicstatic void main(String[] args) {
new SnakeFrame();
}
}
//未完待续,更多精彩内容,且看下回分解