
import java.awt.*; |
import java.awt.event.*; |
import javax.swing.*; |
import java.util.*; |
//============================================= |
//Main Class |
//============================================= |
public class GreedSnake implements KeyListener |
{ |
JFrame mainFrame; |
Canvas paintCanvas; |
JLabel label得分;//计分牌 |
SnakeModel snakeModel=null;// 蛇 |
public static final int canvasWidth=200; |
public static final int canvasHeight=300; |
public static final int nodeWidth=10; |
public static final int nodeHeight=10; |
//---------------------------------------------------------------------- |
//GreedSnake():初始化游戏界面 |
//---------------------------------------------------------------------- |
public GreedSnake() |
{ |
//设置界面元素 |
mainFrame=new JFrame("贪吃蛇"); |
Container cp=mainFrame.getContentPane(); |
label得分=new JLabel("得分:"); |
cp.add(label得分,BorderLayout.NORTH); |
paintCanvas=new Canvas(); |
paintCanvas.setSize(canvasWidth+1,canvasHeight+1); |
paintCanvas.addKeyListener(this); |
cp.add(paintCanvas,BorderLayout.CENTER); |
JPanel panelButtom=new JPanel(); |
panelButtom.setLayout(new BorderLayout()); |
JLabel labelHelp;// 帮助信息 |
labelHelp=new JLabel("上下加速;",JLabel.CENTER); |
panelButtom.add(labelHelp,BorderLayout.NORTH); |
labelHelp=new JLabel("确认,R,S开始;",JLabel.CENTER); |
panelButtom.add(labelHelp,BorderLayout.CENTER); |
labelHelp=new JLabel("空格或者P暂停,卢奇",JLabel.CENTER); |
panelButtom.add(labelHelp,BorderLayout.SOUTH); |
cp.add(panelButtom,BorderLayout.SOUTH); |
mainFrame.addKeyListener(this); |
mainFrame.pack(); |
mainFrame.setResizable(false); |
mainFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); |
mainFrame.setVisible(true); |
begin(); |
} |
//---------------------------------------------------------------------- |
//keyPressed():按键检测 |
//---------------------------------------------------------------------- |
public void keyPressed(KeyEvent e) |
{ |
int keyCode=e.getKeyCode(); |
if(snakeModel.running) switch(keyCode) |
{ |
case KeyEvent.VK_UP: |
snakeModel.changeDirection(SnakeModel.UP); |
break; |
case KeyEvent.VK_DOWN: |
snakeModel.changeDirection(SnakeModel.DOWN); |
break; |
case KeyEvent.VK_LEFT: |
snakeModel.changeDirection(SnakeModel.LEFT); |
break; |
case KeyEvent.VK_RIGHT: |
snakeModel.changeDirection(SnakeModel.RIGHT); |
break; |
case KeyEvent.VK_ADD: |
case KeyEvent.VK_PAGE_UP: |
snakeModel.speedUp();// 加速 |
break; |
case KeyEvent.VK_SUBTRACT: |
case KeyEvent.VK_PAGE_DOWN: |
snakeModel.speedDown();// 减速 |
break; |
case KeyEvent.VK_SPACE: |
case KeyEvent.VK_P: |
snakeModel.changePauseState();// 暂停或继续 |
break; |
default: |
} |
//重新开始 |
if(keyCode==KeyEvent.VK_R || keyCode==KeyEvent.VK_S |
|| keyCode==KeyEvent.VK_ENTER) |
{ |
snakeModel.running=false; |
begin(); |
} |
} |
//---------------------------------------------------------------------- |
//keyReleased():空函数 |
//---------------------------------------------------------------------- |
public void keyReleased(KeyEvent e) |
{ |
} |
//---------------------------------------------------------------------- |
//keyTyped():空函数 |
//---------------------------------------------------------------------- |
public void keyTyped(KeyEvent e) |
{ |
} |
//---------------------------------------------------------------------- |
//repaint():绘制游戏界面(包括蛇和食物) |
//---------------------------------------------------------------------- |
void repaint() |
{ |
Graphics g=paintCanvas.getGraphics(); |
//draw background |
g.setColor(Color.YELLOW); |
g.fillRect(0,0,canvasWidth,canvasHeight); |
//draw the snake |
g.setColor(Color.BLUE); |
LinkedList na=snakeModel.nodeArray; |
Iterator it=na.iterator(); |
while(it.hasNext()) |
{ |
Node n=(Node)it.next(); |
drawNode(g,n); |
} |
// draw the food |
g.setColor(Color.RED); |
Node n=snakeModel.food; |
drawNode(g,n); |
update得分(); |
} |
//---------------------------------------------------------------------- |
//drawNode():绘画某一结点(蛇身或食物) |
//---------------------------------------------------------------------- |
private void drawNode(Graphics g,Node n) |
{ |
g.fillRect(n.x*nodeWidth,n.y*nodeHeight,nodeWidth-1,nodeHeight-1); |
} |
//---------------------------------------------------------------------- |
//update得分():改变计分牌 |
//---------------------------------------------------------------------- |
public void update得分() |
{ |
String s="得分: "+snakeModel.得分; |
label得分.setText(s); |
} |
//---------------------------------------------------------------------- |
//begin():游戏开始,放置贪吃蛇 |
//---------------------------------------------------------------------- |
void begin() |
{ |
if(snakeModel==null||!snakeModel.running) |
{ |
snakeModel=new SnakeModel(this,canvasWidth/nodeWidth, |
this.canvasHeight/nodeHeight); |
(new Thread(snakeModel)).start(); |
} |
} |
//---------------------------------------------------------------------- |
//main():主函数 |
//---------------------------------------------------------------------- |
public static void main(String[] args) |
{ |
GreedSnake gs=new GreedSnake(); |
} |
} |
/************************************************************************** |
*要点分析: |
*1)数据结构:matrix[][]用来存储地图上面的信息,如果什么也没有设置为false, |
* 如果有食物或蛇,设置为true;nodeArray,一个LinkedList,用来保存蛇的每 |
* 一节;food用来保存食物的位置;而Node类是保存每个位置的信息。 |
*2)重要函数: |
* changeDirection(int newDirection) ,用来改变蛇前进的方向,而且只是 |
* 保存头部的前进方向,因为其他的前进方向已经用位置来指明了。 其中newDirection |
* 必须和原来的direction不是相反方向,所以相反方向的值用了同样的奇偶性。在测试 |
* 的时候使用了direction%2!=newDirection%2 进行判断。 |
* moveOn(),用来更新蛇的位置,对于当前方向,把头部位置进行相应改变。如果越界, |
* 结束;否则,检测是否遇到食物(加头部)或身体(结束);如果什么都没有,加上头部, |
* 去掉尾部。由于用了LinkedList数据结构,省去了相当多的麻烦。 |
*************************************************************************/ |
|
//---------------------------------------------------------------------- |
//Node:结点类 |
//---------------------------------------------------------------------- |
class Node |
{ |
int x; |
int y; |
Node(int x,int y) |
{ |
this.x=x; |
this.y=y; |
} |
} |
//---------------------------------------------------------------------- |
//SnakeModel:贪吃蛇模型 |
//---------------------------------------------------------------------- |
class SnakeModel implements Runnable |
{ |
GreedSnake gs; |
boolean[][] matrix;// 界面数据保存在数组里 |
LinkedList nodeArray=new LinkedList(); |
Node food; |
int maxX;//最大宽度 |
int maxY;//最大长度 |
int direction=2;//方向 |
boolean running=false; |
int timeInterval=200;// 间隔时间(速度) |
double speedChangeRate=0.75;// 速度改变程度 |
boolean paused=false;// 游戏状态 |
int 得分=0; |
int countMove=0; |
// UP和DOWN是偶数,RIGHT和LEFT是奇数 |
public static final int UP=2; |
public static final int DOWN=4; |
public static final int LEFT=1; |
public static final int RIGHT=3; |
//---------------------------------------------------------------------- |
//GreedModel():初始化界面 |
//---------------------------------------------------------------------- |
public SnakeModel(GreedSnake gs,int maxX,int maxY) |
{ |
this.gs=gs; |
this.maxX=maxX; |
this.maxY=maxY; |
matrix=new boolean[maxX][]; |
for(int i=0;i<maxX;++i) |
{ |
matrix[i]=new boolean[maxY]; |
Arrays.fill(matrix[i],false);// 没有蛇和食物的地区置false |
} |
//初始化贪吃蛇 |
int initArrayLength=maxX>20 ? 10 : maxX/2; |
for(int i=0;i<initArrayLength;++i) |
{ |
int x=maxX/2+i; |
int y=maxY/2; |
nodeArray.addLast(new Node(x,y)); |
matrix[x][y]=true;// 蛇身处置true |
} |
food=createFood(); |
matrix[food.x][food.y]=true;// 食物处置true |
} |
//---------------------------------------------------------------------- |
//changeDirection():改变运动方向 |
//---------------------------------------------------------------------- |
public void changeDirection(int newDirection) |
{ |
if(direction%2!=newDirection%2)// 避免冲突 |
{ |
direction=newDirection; |
} |
} |
//---------------------------------------------------------------------- |
//moveOn():贪吃蛇运动函数 |
//---------------------------------------------------------------------- |
public boolean moveOn() |
{ |
Node n=(Node)nodeArray.getFirst(); |
int x=n.x; |
int y=n.y; |
switch(direction) |
{ |
case UP: |
y--; |
break; |
case DOWN: |
y++; |
break; |
case LEFT: |
x--; |
break; |
case RIGHT: |
x++; |
break; |
} |
if((0<=x&&x<maxX)&&(0<=y&&y<maxY)) |
{ |
if(matrix[x][y])// 吃到食物或者撞到身体 |
{ |
if(x==food.x&&y==food.y)// 吃到食物 |
{ |
nodeArray.addFirst(food);// 在头部加上一结点 |
//计分规则与移动长度和速度有关 |
int 得分Get=(10000-200*countMove)/timeInterval; |
得分+=得分Get>0 ? 得分Get : 10; |
countMove=0; |
food=createFood(); |
matrix[food.x][food.y]=true; |
return true; |
} |
else return false;// 撞到身体 |
} |
else//什么都没有碰到 |
{ |
nodeArray.addFirst(new Node(x,y));// 加上头部 |
matrix[x][y]=true; |
n=(Node)nodeArray.removeLast();// 去掉尾部 |
matrix[n.x][n.y]=false; |
countMove++; |
return true; |
} |
} |
return false;//越界(撞到墙壁) |
} |
//---------------------------------------------------------------------- |
//run():贪吃蛇运动线程 |
//---------------------------------------------------------------------- |
public void run() |
{ |
running=true; |
while(running) |
{ |
try |
{ |
Thread.sleep(timeInterval); |
}catch(Exception e) |
{ |
break; |
} |
if(!paused) |
{ |
if(moveOn())// 未结束 |
{ |
gs.repaint(); |
} |
else//游戏结束 |
{ |
JOptionPane.showMessageDialog(null,"你傻逼啊这么简单都会死", |
"傻逼",JOptionPane.INFORMATION_MESSAGE); |
break; |
} |
} |
} |
running=false; |
} |
//---------------------------------------------------------------------- |
//createFood():生成食物及放置地点 |
//---------------------------------------------------------------------- |
private Node createFood() |
{ |
int x=0; |
int y=0; |
do |
{ |
Random r=new Random(); |
x=r.nextInt(maxX); |
y=r.nextInt(maxY); |
}while(matrix[x][y]); |
return new Node(x,y); |
} |
//---------------------------------------------------------------------- |
//speedUp():加快蛇运动速度 |
//---------------------------------------------------------------------- |
public void speedUp() |
{ |
timeInterval*=speedChangeRate; |
} |
//---------------------------------------------------------------------- |
//speedDown():放慢蛇运动速度 |
//---------------------------------------------------------------------- |
public void speedDown() |
{ |
timeInterval/=speedChangeRate; |
} |
//---------------------------------------------------------------------- |
//changePauseState(): 改变游戏状态(暂停或继续) |
//---------------------------------------------------------------------- |
public void changePauseState() |
{ |
paused=!paused; |
} |
} |




初级程序员
by: BBOY小潮 发表于:2017-04-10 21:38:45 顶(0) | 踩(0) 回复
666
回复评论