JAVA-制作小游戏期末实训
源码
import game.frame.Frame;public class App {public static void main(String[] args) {System.out.println("starting......");new Frame();}
}
package game.controller;import game.model.Enemy;public class EnemyController implements Runnable{private Enemy enemy;public EnemyController(Enemy enemy) {this.enemy = enemy;}@Overridepublic void run() {while (true) {try {if (enemy.getStatus() == 1 || enemy.getStatus() == -1) {enemy.setStatus(-2); // 站立状态修改成左跑}if (enemy.getX() <= -100) {enemy.setStatus(2);}if (enemy.getX() >= 300) {enemy.setStatus(-2);}Thread.sleep(50);} catch (InterruptedException e){e.printStackTrace();}}}
}
package game.frame;
import game.model.BackGround;
import game.model.Enemy;
import game.model.Person;
import javax.swing.JFrame;
import java.awt.*;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.image.BufferedImage;
import java.util.Date;
import java.util.List;public class Frame extends JFrame implements Runnable, KeyListener {private Person person; // 添加人物private Date startDate = new Date(); // 游戏开始时间private BackGround nowBackGround; // 当前场景public Frame() {setTitle("game"); // 窗体标题setSize(720, 480); // 窗体大小// 居中显示Toolkit toolkit = Toolkit.getDefaultToolkit(); // 获取屏幕工具包int width = (int)toolkit.getScreenSize().getWidth(); // 获取屏幕宽度int hight = (int)toolkit.getScreenSize().getHeight(); // 获取屏幕高度int x = (width - 720) / 2;int y = (hight - 480) / 2;this.setLocation(x, y);// 初始化场景nowBackGround = new BackGround(1);setVisible(true); // 设置可见setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); // 程序随窗体关闭而关闭// 监听键盘this.addKeyListener(this);// 多线程Thread thread = new Thread(this);thread.start();// 创建人物person = new Person(0, 250, nowBackGround);}// 多线程任务@Overridepublic void run() {while (true) {try {this.person.applyGravity();this.repaint(); // 循环重新绘画窗口Thread.sleep(50); // 线程休息50毫秒} catch (InterruptedException e) {e.printStackTrace();}}}@Overridepublic void paint(Graphics g) {// 创建图片对象BufferedImage image = new BufferedImage(720, 480, BufferedImage.TYPE_3BYTE_BGR);// 获取图像画笔Graphics graphics = image.getGraphics();// 图像画笔绘画图像graphics.drawImage(nowBackGround.getShowImage(), 0, 0, this);// 添加时间long dif = new Date().getTime() - startDate.getTime();// 绘画时间graphics.drawString("时间 " + (dif/1000/60) + " : " + (dif/1000%60), 600, 60);// 绘画击杀数graphics.drawString("击杀数: " + person.getKillNum(), 600, 80);// 绘画敌人List<Enemy> allEnemy = nowBackGround.getAllEnemy();for (Enemy enemy : allEnemy) {graphics.drawImage(enemy.getShowImage(), enemy.getX(), enemy.getY(), this);}// 绘画人物graphics.drawImage(person.getShowImage(), person.getX(), person.getY(), this);// 窗体画笔会话图像g.drawImage(image, 0, 0, this);// 是否进入下一场景if (nowBackGround.isPass(person) && nowBackGround.hasNext()) {nowBackGround = nowBackGround.next();person.setX(0);person.setBackGround(nowBackGround); // 重新设置场景}}@Override // 键入某个键时调用public void keyTyped(KeyEvent e) {//TODO}@Override // 按下某个键时调用public void keyPressed(KeyEvent e) {int keyCode = e.getKeyCode();if (keyCode == 68) { // 按下D时右跑this.person.rightRun();}if (keyCode == 65) { // 按下A时左跑this.person.leftRun();}if (keyCode == 75) { // 按下K时跳跃this.person.jump();}if (keyCode == 74) { // 按下J时攻击this.person.attack();}if (keyCode == 76) { // 按下L时闪现this.person.flash();}// 当按下A或D键且人物处于跳跃状态时,设置方向改变请求为trueif (person.getStatus() == 3 || person.getStatus() == -3) {if (keyCode == 68) {person.setJumpDirectionChangeRequested(true);person.setJumpMoveDirection(1);} else if (keyCode == 65) {person.setJumpDirectionChangeRequested(true);person.setJumpMoveDirection(-1);}}}@Override // 释放某个键时调用public void keyReleased(KeyEvent e) {int keyCode = e.getKeyCode();if (keyCode == 68) { // 释放D时停止右跑this.person.stopRightRun();}if (keyCode == 65) { // 释放A时停止左跑this.person.stopLeftRun();}}
}
package game.model;import java.awt.image.BufferedImage;
import java.util.ArrayList;
import java.util.List;import game.util.StaticValue;public class BackGround {private BufferedImage showImage = null; // 显示的场景图片private int sort; // 序号private int nextSort; // 下一个场景序号private List<Enemy> allEnemy = new ArrayList<>(); // 敌人public BackGround(int sort) {this.sort = sort;create();}public void create() { // 根据sort选择场景if (this.sort == 1) {this.showImage = StaticValue.bg01;this.allEnemy.add(new Enemy(400, 110, this));this.allEnemy.add(new Enemy(200, 110, this));this.nextSort = 2;} else if (this.sort == 2) {this.showImage = StaticValue.bg02;this.nextSort = 3;this.allEnemy.add(new Enemy(400, 100, this));this.allEnemy.add(new Enemy(200, 100, this));} else if (this.sort == 3) {this.showImage = StaticValue.bg03;this.nextSort = 4;this.allEnemy.add(new Enemy(400, 100, this));this.allEnemy.add(new Enemy(200, 100, this));this.allEnemy.add(new Enemy(600, 100, this));}else if (this.sort == 4) {this.showImage = StaticValue.bg04;this.nextSort = 1;this.allEnemy.add(new Enemy(400, 100, this));this.allEnemy.add(new Enemy(200, 100, this));this.allEnemy.add(new Enemy(600, 100, this));this.allEnemy.add(new Enemy(300, 100, this));}}public boolean hasNext() { // 是否有另一个场景return nextSort != 0;}public BackGround next() { // 创建下一个场景return new BackGround(nextSort);}public boolean isPass(Person person) { // 是否可以通过if (person.getX() >= 650) {return true;}return false;}public BufferedImage getShowImage() {return showImage;}public void setShowImage(BufferedImage showImage) {this.showImage = showImage;}public List<Enemy> getAllEnemy() {return allEnemy;}
}
package game.model;
import game.controller.EnemyController;
import game.util.StaticValue;
public class Enemy extends Person{private Thread controllerThread;public Enemy(int x, int y, BackGround backGround) {super(x, y, backGround);this.status = -1; // 设置状态为左站立controllerThread = new Thread(new EnemyController(this));controllerThread.start();}// 设置敌人图片@Overrideprotected void setImageList() {leftStandImages = StaticValue.leftEnemyImgs.subList(14, 19);rightStandImages = StaticValue.rightEnemyImgs.subList(14, 19);leftRunImages = StaticValue.leftEnemyImgs.subList(0, 6);rightRunImages = StaticValue.rightEnemyImgs.subList(0, 6);leftJumpImages = StaticValue.leftEnemyImgs.subList(4, 5);rightJumpImages = StaticValue.rightEnemyImgs.subList(4, 5);leftAttackImages = StaticValue.leftEnemyImgs.subList(6, 14);rightAttackImages = StaticValue.rightEnemyImgs.subList(6, 14);}public void dead() { // 死掉this.backGround.getAllEnemy().remove(this);Person.killNum++;}
}
package game.model;import game.util.StaticValue;
import java.awt.image.BufferedImage;
import java.util.List;public class Person implements Runnable{protected int x; // 坐标xprotected int y; // 坐标yprotected BufferedImage showImage; // 人物显示图片protected Thread t; // 线程protected double moving = 0; // 移动帧数protected int status = 1; // 人物状态 默认右站立protected int jumpForce = 0; // 跳跃力protected int jumpMoveDirection = 0; // 跳跃移动方向 0垂直 -1向左 1向右protected BackGround backGround; // 场景protected static int killNum = 0; // 击杀数private boolean jumpDirectionChangeRequested = false; // 跳跃时的方向改变请求protected List<BufferedImage> leftStandImages; // 左站立图集protected List<BufferedImage> rightStandImages; // 右站立图集protected List<BufferedImage> leftRunImages; // 左跑图集protected List<BufferedImage> rightRunImages; // 右跑图集protected List<BufferedImage> leftJumpImages; // 左跳图集protected List<BufferedImage> rightJumpImages; // 右跳图集protected List<BufferedImage> leftAttackImages; // 左攻图集protected List<BufferedImage> rightAttackImages; // 右攻图集public Person(int x, int y, BackGround backGround) {this.x = x;this.y = y;this.backGround = backGround;this.t = new Thread(this);t.start();setImageList();}protected void setImageList() { // 初始化图集leftStandImages = StaticValue.leftPersonImgs.subList(0, 4);rightStandImages = StaticValue.rightPersonImgs.subList(0, 4);leftRunImages = StaticValue.leftPersonImgs.subList(5, 9);rightRunImages = StaticValue.rightPersonImgs.subList(5, 9);leftJumpImages = StaticValue.leftPersonImgs.subList(6, 7);rightJumpImages = StaticValue.rightPersonImgs.subList(6, 7);leftAttackImages = StaticValue.leftPersonImgs.subList(9, 12);rightAttackImages = StaticValue.rightPersonImgs.subList(9, 12);}@Overridepublic void run() {// 线程更新人物while (true) {try {switch (status) {case 1: // 向右-站立if (this.moving > 3) {this.moving = 0;}this.showImage = rightStandImages.get((int)moving);moving += 0.2;break;case 2: // 向右-跑if (this.moving > 3) {this.moving = 0;}this.showImage = rightRunImages.get((int)moving);moving += 0.5;break;case 3: // 向右-跳跃this.moving = 0;this.showImage = rightJumpImages.get((int)moving);if (jumpDirectionChangeRequested) {if (jumpMoveDirection == -1) {status = -3;}jumpDirectionChangeRequested = false;}if (jumpMoveDirection > 0) {x += 10;} else if (jumpMoveDirection < 0) {x -= 10;}y -= jumpForce + 2;if (y > 250) {y = 250;if (jumpMoveDirection > 0) {this.status = 2;} else if (jumpMoveDirection < 0) {this.status = -2;} else {this.status = this.status > 0? 1 : -1;}}jumpForce--;break;case 4: // 向右-攻击if (this.moving > 2) {this.moving = 0;}this.showImage = rightAttackImages.get((int)moving);moving += 0.5;if (this.moving == 2){this.status = this.status > 0 ? 1 : -1;}break;case -1: // 向左-站立if (this.moving > 3) {this.moving = 0;}this.showImage = leftStandImages.get((int)moving);moving += 0.2;break;case -2: // 向左-跑if (this.moving > 3) {this.moving = 0;}this.showImage = leftRunImages.get((int)moving);moving += 0.5;break;case -3: // 向左-跳跃this.moving = 0;this.showImage = leftJumpImages.get((int)moving);if (jumpDirectionChangeRequested) {if (jumpMoveDirection == 1) {status = 3;}jumpDirectionChangeRequested = false;}if (jumpMoveDirection > 0) {x += 10;} else if (jumpMoveDirection < 0) {x -= 10;}y -= jumpForce + 2;if (y > 250) {y = 250;if (jumpMoveDirection > 0) {this.status = 2;} else if (jumpMoveDirection < 0) {this.status = -2;} else {this.status = this.status > 0? 1 : -1;}}jumpForce--;break;case -4: // 向左-攻击if (this.moving > 2) {this.moving = 0;}this.showImage = leftAttackImages.get((int)moving);moving += 0.5;if (this.moving == 2){this.status = this.status > 0 ? 1 : -1;}default:break;}moveXY(); // 人物移动// 边界控制if (x < -100) {x = -100;}if (x > 650) {x = 650;}// 攻击敌人if (this.backGround != null) {List<Enemy> allEnemy = this.backGround.getAllEnemy(); // 获取场景中所有的敌人for (int i = 0; i < allEnemy.size(); i++) {Enemy enemy = allEnemy.get(i);if (this.status == 4 && (this.x + 125) > (enemy.getX()) && (this.x + 125) < (enemy.getX() + 250)) {enemy.dead();} else if (this.status == -4 && (this.x + 125) < (enemy.getX() + 400) && (this.x + 125) > (enemy.getX() + 256)) {enemy.dead();}}}Thread.sleep(50);}catch (InterruptedException e) {e.printStackTrace();}}}private void moveXY() { // 人物移动方法switch (status) {case 1: // 向右-站立break;case 2: // 向右-跑x += 10;break;case 3: // 向右-跳跃if (this.jumpMoveDirection > 0) {x += 10;}else if (this.jumpMoveDirection < 0) {x -= 10;}y -= jumpForce + 2;if (y > 250) {y = 250;if (this.jumpMoveDirection > 0) {this.status = 2;} else if (this.jumpMoveDirection < 0) {this.status = -2;}else {this.status = this.status > 0 ? 1 : -1;}}jumpForce--;break;case 4: // 向右-攻击break;case -1: // 向左-站立break;case -2: // 向左-跑x -= 10;break;case -3: // 向左-跳跃if (this.jumpMoveDirection > 0) {x += 10;}else if (this.jumpMoveDirection < 0) {x -= 10;}y -= jumpForce + 2;if (y > 250) {y = 250;if (this.jumpMoveDirection > 0) {this.status = 2;} else if (this.jumpMoveDirection < 0) {this.status = -2;}else {this.status = this.status > 0 ? 1 : -1;}}jumpForce--;break;case -4: // 向左-攻击break;default:break;}}public int getX() {return x;}public int getY() {return y;}public void setX(int x) {this.x = x;}public void setY(int y) {this.y = y;}public int getKillNum() {return killNum;}public BufferedImage getShowImage() {if (showImage == null) { // 当图片显示为空获取图片showImage = StaticValue.rightPersonImgs.get(0); // 获取第一张}return showImage;}public void setShowImage(BufferedImage showImage) {this.showImage = showImage;}public void rightRun() { // 右跑if (this.status == 3 || this.status == -3) { // 浮空状态不允许改变状态return;}this.status = 2;}public void leftRun() { // 左跑if (this.status == 3 || this.status == -3) { // 浮空状态不允许改变状态return;}this.status = -2;}public void stopRightRun() { // 停止右跑if (this.status == 3 || this.status == -3) { // 浮空状态不允许改变状态this.jumpMoveDirection = 0; // 跳跃结束恢复站立return;}this.status = 1;}public void stopLeftRun() { // 停止左跑if (this.status == 3 || this.status == -3) { // 浮空状态不允许改变状态this.jumpMoveDirection = 0; // 跳跃结束恢复站立return;}this.status = -1;}public void jump() { // 跳跃if (this.status != 3 && this.status != -3) {if (this.status == 2 || this.status == -2) {this.jumpMoveDirection = this.status > 0 ? 1 : -1;}this.status = this.status > 0 ? 3 : -3; // 设置状态为跳跃this.jumpForce = 15; // 设置跳跃力}}public void attack() { // 攻击if (this.status > 0) {this.status = 4;}else {this.status = -4;}}public int getStatus() {return status;}public void setStatus(int status) {this.status = status;}public BackGround getBackGround() {return backGround;}public void setBackGround(BackGround backGround) {this.backGround = backGround;}public void setJumpDirectionChangeRequested(boolean jumpDirectionChangeRequested) {this.jumpDirectionChangeRequested = jumpDirectionChangeRequested;}public void setJumpMoveDirection(int jumpMoveDirection) {this.jumpMoveDirection = jumpMoveDirection;}private double veloctiyY = 0; // 当前速度public void applyGravity() { // 跳跃攻击后落地方法if (this.y < 250) {double GRAVITY = 0.5;this.veloctiyY += GRAVITY;this.y += (int)this.veloctiyY;if (this.y >= 250) {this.y = 250;this.veloctiyY = 0;}}}public void flash() { // 闪现if (this.status == 1 || this.status == 2) {this.x += 100;}else if (this.status == -1 || this.status == -2) {this.x -= 100;}}
}
package game.util;import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.List;public class StaticValue {// 获取项目目录public static final String ImagePath = System.getProperty("user.dir") + "/res/";// 背景图片public static BufferedImage bg01 = null;public static BufferedImage bg02 = null;public static BufferedImage bg03 = null;public static BufferedImage bg04 = null;// 人物图片集合public static List<BufferedImage> leftPersonImgs = new ArrayList<>();public static List<BufferedImage> rightPersonImgs = new ArrayList<>();// 敌人图片集合public static List<BufferedImage> leftEnemyImgs = new ArrayList<>();public static List<BufferedImage> rightEnemyImgs = new ArrayList<>();static {try {// 获取背景图片bg01 = ImageIO.read(new File(ImagePath + "background/1.png"));bg02 = ImageIO.read(new File(ImagePath + "background/2.png"));bg03 = ImageIO.read(new File(ImagePath + "background/3.png"));bg04 = ImageIO.read(new File(ImagePath + "background/4.png"));// 获取人物图片for (int i = 1; i <= 14; i++) {DecimalFormat decimalFormat = new DecimalFormat("00");String num = decimalFormat.format(i);// 添加人物图片到集合中leftPersonImgs.add(ImageIO.read(new File(ImagePath + "person/left/" + num + ".png")));rightPersonImgs.add(ImageIO.read(new File(ImagePath + "person/right/" + num + ".png")));}// 加载敌人图片for (int i = 0; i <= 6; i++) {File rightfile = new File(ImagePath + "enemy/right/517_move_" + i + ".png");File leftfile = new File(ImagePath + "enemy/left/517_move_" + i + ".png");leftEnemyImgs.add(ImageIO.read(leftfile));rightEnemyImgs.add(ImageIO.read(rightfile));}for (int i = 0; i <= 7; i++) {File rightfile = new File(ImagePath + "enemy/right/517_skill_1027_" + i + ".png");File leftfile = new File(ImagePath + "enemy/left/517_skill_1027_" + i + ".png");leftEnemyImgs.add(ImageIO.read(leftfile));rightEnemyImgs.add(ImageIO.read(rightfile));}for (int i = 0; i <= 7; i++) {File rightfile = new File(ImagePath + "enemy/right/517_stand_" + i + ".png");File leftfile = new File(ImagePath + "enemy/left/517_stand_" + i + ".png");leftEnemyImgs.add(ImageIO.read(leftfile));rightEnemyImgs.add(ImageIO.read(rightfile));}}catch (IOException e) {e.printStackTrace();}}
}
新增功能
杀敌数量显示
Person添加killNum属性记录杀敌数量
Frame.java
// 绘画时间graphics.drawString("时间 " + (dif/1000/60) + " : " + (dif/1000%60), 600, 60);
跳跃可攻击
Person.java
public void attack() { // 攻击if (this.status > 0) {this.status = 4;}else {this.status = -4;}}
public void applyGravity() { // 落地方法if (this.y < 250) {double GRAVITY = 0.5;this.veloctiyY += GRAVITY;this.y += (int)this.veloctiyY;if (this.y >= 250) {this.y = 250;this.veloctiyY = 0;}}}
跳跃可转身
Person.java
private boolean jumpDirectionChangeRequested = false; // 跳跃时的方向改变请求public void setJumpDirectionChangeRequested(boolean jumpDirectionChangeRequested) {this.jumpDirectionChangeRequested = jumpDirectionChangeRequested;}public void setJumpMoveDirection(int jumpMoveDirection) {this.jumpMoveDirection = jumpMoveDirection;}private void moveXY() { // 人物移动方法switch (status) {case 1: // 向右-站立break;case 2: // 向右-跑x += 10;break;case 3: // 向右-跳跃if (this.jumpMoveDirection > 0) {x += 10;}else if (this.jumpMoveDirection < 0) {x -= 10;}y -= jumpForce + 2;if (y > 250) {y = 250;if (this.jumpMoveDirection > 0) {this.status = 2;} else if (this.jumpMoveDirection < 0) {this.status = -2;}else {this.status = this.status > 0 ? 1 : -1;}}jumpForce--;break;case 4: // 向右-攻击break;case -1: // 向左-站立break;case -2: // 向左-跑x -= 10;break;case -3: // 向左-跳跃if (this.jumpMoveDirection > 0) {x += 10;}else if (this.jumpMoveDirection < 0) {x -= 10;}y -= jumpForce + 2;if (y > 250) {y = 250;if (this.jumpMoveDirection > 0) {this.status = 2;} else if (this.jumpMoveDirection < 0) {this.status = -2;}else {this.status = this.status > 0 ? 1 : -1;}}jumpForce--;break;case -4: // 向左-攻击break;default:break;}}
Frame.java
@Override // 按下某个键时调用public void keyPressed(KeyEvent e) {int keyCode = e.getKeyCode();if (keyCode == 68) { // 按下D时右跑this.person.rightRun();}if (keyCode == 65) { // 按下A时左跑this.person.leftRun();}if (keyCode == 75) { // 按下K时跳跃this.person.jump();}if (keyCode == 74) { // 按下J时攻击this.person.attack();}if (keyCode == 76) { // 按下L时闪现this.person.flash();}// 当按下A或D键且人物处于跳跃状态时,设置方向改变请求为trueif (person.getStatus() == 3 || person.getStatus() == -3) {if (keyCode == 68) {person.setJumpDirectionChangeRequested(true);person.setJumpMoveDirection(1);} else if (keyCode == 65) {person.setJumpDirectionChangeRequested(true);person.setJumpMoveDirection(-1);}}}
闪现
Person.java
public void flash() { // 闪现if (this.status == 1 || this.status == 2) {this.x += 100;}else if (this.status == -1 || this.status == -2) {this.x -= 100;}}