半成品 贪吃蛇项目
看看图片
视频链接20_【尚学堂】贪吃蛇游戏项目_游戏关卡的设置_哔哩哔哩_bilibili,他里面有章身体的没有讲到,所以我就学不下了。
还是讲讲代码吧
gamewine代码
package game;
import java.awt.*;
import java.util.ArrayList;
import java.util.List;
import javax.swing.JFrame;
import javax.swing.SwingUtilities;
import javax.swing.Timer;
import obj.bodyobj;
import obj.foodobj;
import obj.head;
import utils.gameutils;
public class gamewin extends JFrame {
Image offscreenImage = null;
// 蛇头对象
head headObj = new head(gameutils.rightimg, 30, 560, this);
public List<bodyobj> bodyobjs=new ArrayList();
//食物
public foodobj foodobj=new foodobj().getFoodobj();
private void launch() {
this.setVisible(true);
this.setSize(600, 600);
this.setLocationRelativeTo(null);
this.setTitle("我是一条贪吃蛇");
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
// 设置重绘的定时器
Timer timer = new Timer(250, e -> repaint());
timer.start();
}
@Override
public void update(Graphics g) {
// 初始化离屏图像
if (offscreenImage == null) {
offscreenImage = createImage(600, 600);
}
Graphics gOffscreen = offscreenImage.getGraphics();
paint(gOffscreen);
g.drawImage(offscreenImage, 0, 0, this);
}
@Override
public void paint(Graphics g) {
// super.paint(g);
// 绘制背景
g.setColor(Color.GRAY);
g.fillRect(0, 0, 600, 600);
// 绘制网格线
g.setColor(Color.BLACK);
for (int i = 0; i < 20; i++) {
g.drawLine(i*30,0,i*30,600);
}
for (int i = 0; i < 20; i++) {
g.drawLine(0,i*30,600,i*30);
}
// 绘制蛇头
headObj.paintself(g);
foodobj.paintself(g);
}
public static void main(String[] args) {
gamewin game = new gamewin();
game.launch();
;
}
}
上述代码是实现窗口等绘制,
注意点
这里的双缓存不能像往常一样了,以前的话这里线条会重叠,导致粗细不同,用了
public void update(Graphics g) {
// 初始化离屏图像
if (offscreenImage == null) {
offscreenImage = createImage(600, 600);
}
Graphics gOffscreen = offscreenImage.getGraphics();
paint(gOffscreen);
g.drawImage(offscreenImage, 0, 0, this);
}
可以实现以前线条的去除,这里的update也是自动触发的
重绘定时
// 设置重绘的定时器
Timer timer = new Timer(250, e -> repaint());
timer.start();
snake head .java类
package obj;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import game.gamewin;
import utils.gameutils;
public class head extends gameobj{
//方向是上下左右
private String direction="right";
public head(Image img, int x, int y, gamewin frame) {
super(img, x, y,frame);
this.frame.addKeyListener(new KeyAdapter() {
@Override
public void keyPressed(KeyEvent e) {
// TODO Auto-generated method stub
changedirction(e); }
}
);
// TODO Auto-generated constructor stub
}
public void changedirction(KeyEvent e) {
switch (e.getKeyCode()) {
case KeyEvent.VK_A:
if (!"right".equals(direction)) {
direction="left";
img=gameutils.leftimg;
}
break;
case KeyEvent.VK_W:
if (!"down".equals(direction)) {
direction="up";
img=gameutils.upimg;
}
break;
case KeyEvent.VK_S:
if (!"up".equals(direction)) {
direction="down";
img=gameutils.downimg;
}
break;
case KeyEvent.VK_D:
if (!"left".equals(direction)) {
direction="right";
img=gameutils.rightimg;
}
break;
default:
break;
}
}
public String getDirection() {
return direction;
}
//蛇头移动
public void move() {
switch (direction){
case "up": {
y-=height;
break;
}
case "down":
y+=height;
break;
case "left":
x-=width;
break;
case "right":
x+=width;
break;
default:
break;
}
}
@Override
public void paintself(Graphics g) {
// TODO Auto-generated method stub
super.paintself(g);
foodobj food=this.frame.foodobj;
//用xy条件判断蛇头与食物是否重合
if (this.x==food.x && this.y==food.y) {
//将新的随机生成的foodobj对象给窗口的foodobj
this.frame.foodobj=food.getFoodobj();
}
move();
//越界处理
if (x<0) {
x=570;
}
else if (x>570) {
x=0;
}
else if (y<30) {
y=570;
}
else if (y>570) {
y=30;
}
}
}
我们这里对蛇的上下左右控制
这里有监控,按压
public head(Image img, int x, int y, gamewin frame) {
super(img, x, y,frame);
this.frame.addKeyListener(new KeyAdapter() {
@Override
public void keyPressed(KeyEvent e) {
// TODO Auto-generated method stub
changedirction(e); }
}
对不同的方向实现不同的蛇头图片
public void changedirction(KeyEvent e) {
switch (e.getKeyCode()) {
case KeyEvent.VK_A:
if (!"right".equals(direction)) {
direction="left";
img=gameutils.leftimg;
}
break;
case KeyEvent.VK_W:
if (!"down".equals(direction)) {
direction="up";
img=gameutils.upimg;
}
break;
case KeyEvent.VK_S:
if (!"up".equals(direction)) {
direction="down";
img=gameutils.downimg;
}
break;
case KeyEvent.VK_D:
if (!"left".equals(direction)) {
direction="right";
img=gameutils.rightimg;
}
break;
default:
break;
}
}
而像
if (!"up".equals(direction)) {
direction="down";
img=gameutils.downimg;
是为了保证蛇不会往反方向移动,然后又将其移动
public String getDirection() {
return direction;
}
//蛇头移动
public void move() {
switch (direction){
case "up": {
y-=height;
break;
}
case "down":
y+=height;
break;
case "left":
x-=width;
break;
case "right":
x+=width;
break;
default:
break;
}
}
因为我们这个实现的越界后继续循环使用的样子,所以
public void paintself(Graphics g) {
// TODO Auto-generated method stub
super.paintself(g);
foodobj food=this.frame.foodobj;
//用xy条件判断蛇头与食物是否重合
if (this.x==food.x && this.y==food.y) {
//将新的随机生成的foodobj对象给窗口的foodobj
this.frame.foodobj=food.getFoodobj();
}
move();
//越界处理
if (x<0) {
x=570;
}
else if (x>570) {
x=0;
}
else if (y<30) {
y=570;
}
else if (y>570) {
y=30;
}
x,y坐标的改变
公共属性
package utils;
import java.awt.*;
public class gameutils {
//蛇头。蛇身
public static Image upimg=Toolkit.getDefaultToolkit().getImage("D:\\programing\\javaide\\snak\\picture\\head.png");
public static Image downimg=Toolkit.getDefaultToolkit().getImage("D:\\programing\\javaide\\snak\\picture\\down.png");
public static Image leftimg=Toolkit.getDefaultToolkit().getImage("D:\\programing\\javaide\\snak\\picture\\left.png");
public static Image rightimg=Toolkit.getDefaultToolkit().getImage("D:\\programing\\javaide\\snak\\picture\\right.png");
public static Image bodyimg=Toolkit.getDefaultToolkit().getImage("D:\\programing\\javaide\\snak\\picture\\body.png");
public static Image food=Toolkit.getDefaultToolkit().getImage("D:\\programing\\javaide\\snak\\picture\\food.png");
public static Image bg=Toolkit.getDefaultToolkit().getImage("D:\\programing\\javaide\\snak\\picture\\background.png");
public void drawword(Graphics g,String string,Color color,int size,int x,int y ) {
g.setColor(color);
g.setFont(new Font("仿宋",Font.BOLD,size));
g.drawString(string, x, y);
}
}
对一些能够通用的就放到一起
结语
这个残缺的代码就写好了
与以前对比
java讲究的是对象化,把每个物体看作对象,如大鱼吃小鱼,我方鱼,敌方鱼,大鱼,小鱼,这都是不同的对象。不过又可以定义一个公共的对象,,让这些小对象继承,如
public class fish {
//定义图片
Image img;
//定义坐标
int x;
int y;
int width;
int height;
//移动速度
int speed;
//方向定义
int dir=1;
//类型
int type;
//分值
int count;
//距离,用于检测自身
//距离,用于碰撞检测
public Rectangle getrec () {
return new Rectangle(x,y,width,height);//就相当于是返回一个对象
}
public void paintself(Graphics g ) {
g.drawImage(img,x,y,null);//背景面
}}
这里定义了一个公共鱼类,它也是有公共属性,
class ennamy_l extends fish{
敌方鱼继承,我方鱼继承,或override其属性。在我们的贪吃蛇小游戏项目中,我们有蛇头,蛇身,食物,这三个obj,那么对于一些公共方法,属性的实现我们就可以在这个公共方法中实现了
package obj;
import java.awt.*;
import game.gamewin;
import utils.gameutils;
public class gameobj {
//图片
Image img;
int x;
int y;
//物体的宽高
int width=30;
int height=30;
//
//窗口类的引用
gamewin frame;
public Image getImg() {
return img;
}
public int getWidth() {
return width;
}
public int getHeight() {
return height;
}
public gamewin getFrame() {
return frame;
}
public void setImg(Image img) {
this.img = img;
}
public void setWidth(int width) {
this.width = width;
}
public void setHeight(int height) {
this.height = height;
}
public void setFrame(gamewin frame) {
this.frame = frame;
}
public gameobj() {
// TODO Auto-generated constructor stub
}
public gameobj(Image img, int x, int y, int width, int height, gamewin frame) {
this.img = img;
this.x = x;
this.y = y;
this.width = width;
this.height = height;
this.frame = frame;
}
public gameobj(Image img, int x, int y,gamewin frame) {
this.img = img;
this.x = x;
this.y = y;
this.frame = frame;
}
//绘制自身的方法
public void paintself(Graphics g) {
// g.drawImage(img, x, y,null);
g.drawImage(img, x, y, width, height, null);
// TODO Auto-generated method stub
}
public void foodobj() {
}
}
这里用了多个构造方法以此来适应后期不同的需求,并且注意
this.frame = frame;这是我们以前方法中没有的。gamewin frame目的是指向gamewin这个代码页面,所以在我们head构造器中就没必要重复定义x,y,this.x=x这样的
public head(Image img, int x, int y, gamewin frame) {
super(img, x, y,frame);
在
head headObj = new head(gameutils.rightimg, 30, 560, this);
时,这个this就是值frame了。那么在head中也能使用frame.x或y了
对判断食物时
@Override
public void paintself(Graphics g) {
// TODO Auto-generated method stub
super.paintself(g);
foodobj food=this.frame.foodobj;
//用xy条件判断蛇头与食物是否重合有个替换
总之、
有this的用途,用逻辑switch,有多个构造方法的用途