this is the interface:
This is the source code:
/**
* @(#)GreedSnake.java
*
*现在还有两个问题没有结局,一个是加速问题,食物会消失,范围
*吃到的食物没有有可能不会加到末端,原因在于吃到食物的一瞬间,必须迅速添加结点,否则,会偏移
*这样一个有些的缺点是每个蛇结点都是一个线程,开销比较大
* @author
* @version 1.00 2019/4/4
*/
package com.view.test;
import java.awt.*;
import javax.swing.*;
import java.awt.event.*;
import java.util.*;
public class GreedSnake extends JFrame {
public GreedSnake() {
MyPanel mp=new MyPanel();
Thread t=new Thread(mp);
t.start();
this.addKeyListener(mp);
this.add(mp);
this.setSize(600,400);
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.setVisible(true);
}
public static void main(String[] args){
GreedSnake gs=new GreedSnake();
}
public void actionPerformed(ActionEvent e)
{
}
}
class MyPanel extends JPanel implements KeyListener,Runnable{
boolean gameOver=false;
Food food=null;
Snake snake=null;
Node node=null;
Thread t=null;
Vector<Node> vn=new Vector<Node>();
Vector<Snake> vs=new Vector<Snake>();
public MyPanel(){
//初始化产生一个食物
food=new Food(60,60);
//初始化产生十个蛇结点,便于调测蛇的移动
snake=new Snake(200,100,3);
Thread t=new Thread(snake);
t.start();
vs.add(snake);
}
public void paint(Graphics g)
{
super.paint(g);
g.fillRect(0,0,600,400);
g.setColor(Color.red);
g.fillOval(food.getX(),food.getY(),20,20);
g.setColor(Color.green);
for(int i=0;i<600/20;i++)
g.drawLine(i*20, 0, i*20, 400);
for(int i=0;i<400/20;i++)
g.drawLine(0, i*20, 600, i*20);
g.setColor(Color.blue);
for(int i=0;i<vs.size();i++)
g.fillOval(vs.get(i).getX(), vs.get(i).getY(), 20, 20);
if(gameOver=GameOver())
{
Font myFont=new Font("仿宋",Font.ITALIC,80);
g.setFont(myFont);
g.setColor(Color.yellow);
g.drawString("游戏结束!", 200, 200);
}
}
public void eatFood(){
System.out.println(food.getX()+""+food.getY());
System.out.println(vs.get(0).getX());
if((vs.get(0).getX()==food.getX())&& (vs.get(0).getY()==food.getY()))
{
int x=(int)(Math.random()*580);
x-=x%20+20;
int y=(int)(Math.random()*380);
y-=y%20+20;
System.out.println("food location"+x+","+y);
food=new Food(x,y);
//根据蛇尾的方向,增加新的蛇结点,每个蛇节点都是一个线程,方向跟随蛇尾方向
switch((vs.get(vs.size()-1)).getDirect())
{
case 1:
snake=new Snake(vs.lastElement().getX(),vs.lastElement().getY()+20,1);
t=new Thread(snake);
t.start();
vs.add(snake);
break;
case 2:
snake=new Snake(vs.lastElement().getX(),vs.lastElement().getY()-20,2);
t=new Thread(snake);
t.start();
vs.add(snake);
break;
case 3:
snake=new Snake(vs.lastElement().getX()+20,vs.lastElement().getY(),3);
t=new Thread(snake);
t.start();
vs.add(snake);
break;
case 4:
snake=new Snake(vs.lastElement().getX()-20,vs.lastElement().getY(),4);
t=new Thread(snake);
t.start();
vs.add(snake);
break;
}
System.out.println("eatfood");
}
}
public void Move()
{
for(int i=0;i<vn.size();i++)
{
for(int j=0;j<vs.size();j++)
{
if(vs.get(j).getX()==vn.get(i).getX() && vs.get(j).getY()==vn.get(i).getY())
{
vs.get(j).setDirect(vn.get(i).getDirect());
}
}
}
//如果所有节点的方向一样,我就把所有转向点去除
for(int i=0;i<vs.size();i++)
{
if(vs.get(i).getDirect()==vs.get(0).getDirect())
{
continue;
}else{
return;
}
}
vn.removeAllElements();
System.out.println("vn.size:"+vn.size());
}
public boolean GameOver()
{
boolean Gameover=false;
for(int i=1;i<vs.size();i++)
{
if(vs.get(i).getX()==vs.get(0).getX() && vs.get(i).getY()==vs.get(0).getY())
{
Gameover=true;
}
}
if(vs.get(0).getX()>600 ||vs.get(0).getX()<0 ||vs.get(0).getY()>400 ||vs.get(0).getY()<0)
{
Gameover=true;
}
return Gameover;
}
public void keyReleased(KeyEvent e)
{
}
public void keyTyped(KeyEvent e){
}
public void keyPressed(KeyEvent e)
{
//按下方向键,设置蛇头方向
//其实头的方向也没有必要设置,只要设置转向点就可以了
//如果有不止一个蛇结点,就有必要在转向时设置转向点
//其实也没有必要,只有一个结点的时候,增加了的转向点在后面的操作中会很快将其删除
if(e.getKeyCode()==KeyEvent.VK_UP)
{
vs.get(0).setDirect(1);
}else if(e.getKeyCode()==KeyEvent.VK_DOWN)
{
vs.get(0).setDirect(2);
}else if(e.getKeyCode()==KeyEvent.VK_LEFT)
{
vs.get(0).setDirect(3);
}
else if(e.getKeyCode()==KeyEvent.VK_RIGHT)
{
vs.get(0).setDirect(4);
}else if(e.getKeyCode()==KeyEvent.VK_A)
{
snake.speed+=20;
}
node=new Node(vs.get(0).getX(),vs.get(0).getY(),vs.get(0).getDirect());
vn.add(node);
}
public void run()
{
while(true)
{
try{
Thread.sleep(200);
}catch(Exception e){
e.printStackTrace();
}
//面板线程只负责重绘,不参与吃和移动,吃和移动是蛇的属性
this.repaint();
eatFood();
Move();
}
}
}
class Snake implements Runnable
{
int x;
int y;
int speed=20;
int direct;//规定:1向上 2向下 3向左 4向右
public Snake(int x,int y,int direct)
{
this.x=x;
this.y=y;
this.direct=direct;
}
public int getX(){
return x;
}
public void setX(int x){
this.x=x;
}
public int getY(){
return y;
}
public void setY(int y){
this.y=y;
}
public int getSpeed(){
return speed;
}
public void setSpeed(int speed){
this.speed=speed;
}
public int getDirect(){
return direct;
}
public void setDirect(int direct){
this.direct=direct;
}
public void run()
{
//蛇之所以能移动的关键在于此线程
while(true){
try{
Thread.sleep(1000);
}catch(Exception e){
e.printStackTrace();
}
switch(direct)
{
case 1:
y-=speed;
break;
case 2:
y+=speed;
break;
case 3:
x-=speed;
break;
case 4:
x+=speed;
break;
}
}
}
}
class Node{
int x;
int y;
int direct;
public Node(int x,int y,int direct){
this.x=x;
this.y=y;
this.direct=direct;
}
public int getX() {
return x;
}
public void setX(int x) {
this.x = x;
}
public int getY() {
return y;
}
public void setY(int y) {
this.y = y;
}
public int getDirect(){
return direct;
}
public void setDirect(int direct){
this.direct=direct;
}
}
class Food{
int x;
int y;
public Food(int x,int y){
this.x=x;
this.y=y;
}
public int getX() {
return x;
}
public void setX(int x) {
this.x = x;
}
public int getY() {
return y;
}
public void setY(int y) {
this.y = y;
}
}