1、代码:
package org.ligson.jogl.test; import java.awt.BorderLayout; import java.awt.event.KeyEvent; import java.awt.event.KeyListener; import java.awt.event.WindowAdapter; import java.awt.event.WindowEvent; import java.util.ArrayList; import java.util.List; import java.util.Random; import javax.media.opengl.GL; import javax.media.opengl.GLAutoDrawable; import javax.media.opengl.GLCanvas; import javax.media.opengl.GLCapabilities; import javax.media.opengl.GLEventListener; import javax.swing.JFrame; import org.ligson.jogl.test.SnakeDemo.Dir; /* * 事物只有一个 */ public class SnakeDemo extends JFrame implements GLEventListener, Runnable, KeyListener { //产生食物随机坐标 Random random = new Random(); //枚举方向 enum Dir { UP(1), DOWN(2), LEFT(3), RIGHT(4); final int d; private Dir(int d) { this.d = d; } public int getDir() { return this.d; } } //速度 float speed = 10.0f; //长度 int len = 5; // gl库的handler,相当于画笔 GL gl; // 画布 GLCanvas canvas; // 指定了一套OpenGL的功能:渲染内容必须支持,如色彩深度,以及立体是否已启用。 GLCapabilities capabilities; Thread thread = new Thread(this); //蛇集合 List<Snake> snakes = new ArrayList<Snake>(); //食物集合 List<Food> foods = new ArrayList<Food>(); public SnakeDemo() { super("Demo4"); this.setSize(500, 500); //屏幕中心 this.setLocationRelativeTo(null); this.setResizable(false); capabilities = new GLCapabilities(); canvas = new GLCanvas(capabilities); canvas.addGLEventListener(this); this.addKeyListener(this); this.addWindowListener(new WindowAdapter() { public void windowClosing(WindowEvent e) { System.exit(0); } }); this.add(canvas, BorderLayout.CENTER); thread.start(); } @Override public void run() { while (true) { try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } canvas.display(); //检查撞击 checkHit(); } } @Override public void display(GLAutoDrawable drawable) { gl.glClear(GL.GL_COLOR_BUFFER_BIT); gl.glClear(GL.GL_DEPTH_BUFFER_BIT); gl.glEnable(GL.GL_DEPTH_TEST); gl.glColor3f(1.0f, 0.0f, 0.0f); painSnakes(); painFoods(); gl.glFlush(); } @Override public void displayChanged(GLAutoDrawable drawable, boolean arg1, boolean arg2) { } @Override public void init(GLAutoDrawable drawable) { gl = drawable.getGL(); gl.glClearColor(0.3f, 0.3f, 0.3f, 1.0f); gl.glShadeModel(GL.GL_FLAT); gl.glFrontFace(GL.GL_CW); //初始化蛇 for (int i = 0; i < len; i++) { Snake snake = new Snake(10.0f, 10.0f, 0.0f, i * 10.0f, Dir.UP); snakes.add(snake); } //初始化食物 Food food = new Food(10.0f, 10.0f, random.nextInt(250), random.nextInt(250)); foods.add(food); } @Override public void reshape(GLAutoDrawable drawable, int x, int y, int w, int h) { if (h == 0) { h = 1; } int windowWidth; int windowHeight; gl.glViewport(0, 0, w, h); gl.glMatrixMode(GL.GL_PROJECTION); gl.glLoadIdentity(); if (w <= h) { windowWidth = 250; windowHeight = 250 * h / w; } else { windowWidth = 250 * w / h; windowHeight = 250; } //重新定义世界坐标系,以窗口中心为(0,0,0) gl.glOrtho(0 - windowWidth, windowWidth, 0 - windowHeight, windowHeight, 250.0f, -250.0f); gl.glMatrixMode(GL.GL_MODELVIEW); gl.glLoadIdentity(); } public static void main(String[] args) { SnakeDemo demo = new SnakeDemo(); demo.setVisible(true); } @Override public void keyTyped(KeyEvent e) { } @Override public void keyPressed(KeyEvent e) { int key = e.getKeyCode(); switch (key) { case KeyEvent.VK_UP: //防止向相反方向走 if (snakes.get(0).getDir() != Dir.DOWN) { snakes.get(0).setDir(Dir.UP); } break; case KeyEvent.VK_DOWN: if (snakes.get(0).getDir() != Dir.UP) { snakes.get(0).setDir(Dir.DOWN); } break; case KeyEvent.VK_LEFT: if (snakes.get(0).getDir() != Dir.RIGHT) { snakes.get(0).setDir(Dir.LEFT); } break; case KeyEvent.VK_RIGHT: if (snakes.get(0).getDir() != Dir.LEFT) { snakes.get(0).setDir(Dir.RIGHT); } break; case KeyEvent.VK_EQUALS: len++; break; case KeyEvent.VK_MINUS: len--; if (len < 1) { len = 1; } break; default: break; } } @Override public void keyReleased(KeyEvent e) { } private void painSnakes() { int abs = len - snakes.size(); if (abs > 0) { for (int i = 0; i < abs; i++) { Snake lastSnake = snakes.get(snakes.size() - 1); Snake newSnake = new Snake(10.0f, 10.0f, lastSnake.getX() + 10, lastSnake.getY() + 10, lastSnake.getDir()); snakes.add(newSnake); } } else if (abs < 0) { for (int i = 0; i < -abs; i++) { snakes.remove(snakes.size() - 1); } } for (int i = snakes.size() - 1; i >= 1; i--) { Snake tmpSnake = snakes.get(i); Snake prevSnake = snakes.get(i - 1); tmpSnake.setX(prevSnake.getX()); tmpSnake.setY(prevSnake.getY()); tmpSnake.setDir(prevSnake.getDir()); } Snake snake = snakes.get(0); int h = getContentPane().getHeight(); int w = getContentPane().getWidth(); switch (snake.getDir().getDir()) { case 1: if ((snake.getY() + speed - 10.0f) > (h / 2.0)) { snake.setY(-250.0f); } else { snake.setY(snake.getY() + speed); } break; case 2: if ((snake.getY() + speed + snake.getHeight()) < -(h / 2.0)) { snake.setY(250.0f); } else { snake.setY(snake.getY() - speed); } break; case 3: if ((snake.getX() + speed + snake.getWidth()) < -(w / 2.0)) { snake.setX(250.0f); } else { snake.setX(snake.getX() - speed); } break; case 4: if ((snake.getX() + speed - 10.0f) > (w / 2.0)) { snake.setX(-250.0f); } else { snake.setX(snake.getX() + speed); } break; } snakes.set(0, snake); for (Snake snake2 : snakes) { snake2.pain(gl); } } private void painFoods() { if (foods.size() == 0) { Food food = new Food(10.0f, 10.0f, random.nextInt(250), random.nextInt(250)); foods.add(food); } for (Food food : foods) { food.pain(gl); } } private void checkHit() { for (Snake snake : snakes) { for (Food food : foods) { if (Math.abs(snake.getX() - food.getX()) < 10.0f && Math.abs(snake.getY() - food.getY()) < 10.0f) { len++; foods.remove(food); break; } } } } } class Food { private float width = 10.0f; private float height = 10.0f; private float x = 0.0f; private float y = 0.0f; public Food(float width, float height, float x, float y) { super(); this.width = width; this.height = height; this.x = x; this.y = y; } public float getWidth() { return width; } public void setWidth(float width) { this.width = width; } public float getHeight() { return height; } public void setHeight(float height) { this.height = height; } public float getX() { return x; } public void setX(float x) { this.x = x; } public float getY() { return y; } public void setY(float y) { this.y = y; } public void pain(GL gl) { gl.glBegin(GL.GL_QUADS); gl.glVertex3f(this.x, this.y, 0.0f); gl.glVertex3f(this.x, this.y + height, 0.0f); gl.glVertex3f(this.x + width, this.y + height, 0.0f); gl.glVertex3f(this.x + width, this.y, 0.0f); gl.glEnd(); } } class Snake { private float width = 10.0f; private float height = 10.0f; private float x = 0.0f; private float y = 0.0f; private Dir dir = Dir.UP; private Random random = new Random(); public Snake(float width, float height, float x, float y, Dir dir) { super(); this.width = width; this.height = height; this.x = x; this.y = y; this.dir = dir; } public float getWidth() { return width; } public void setWidth(float width) { this.width = width; } public float getHeight() { return height; } public void setHeight(float height) { this.height = height; } public float getX() { return x; } public void setX(float x) { this.x = x; } public float getY() { return y; } public void setY(float y) { this.y = y; } public Dir getDir() { return dir; } public void setDir(Dir dir) { this.dir = dir; } public float[] getPoints() { return null; } public void pain(GL gl) { gl.glColor3f(random.nextFloat(), random.nextFloat(), random.nextFloat()); gl.glBegin(GL.GL_QUADS); gl.glVertex3f(this.x, this.y, 0.0f); gl.glVertex3f(this.x, this.y + height, 0.0f); gl.glVertex3f(this.x + width, this.y + height, 0.0f); gl.glVertex3f(this.x + width, this.y, 0.0f); gl.glEnd(); } public String toString() { return "X:" + this.x + ";Y:" + this.y; } }
2、jogl需要的库