[Java 游戏编程]STG类游戏的实现3-Enemy&&BulletCollision

Game.java

import javax.swing.JFrame;


public class Game {
	public static void main(String [] args) {
		JFrame window = new JFrame("飞碟大战");
		window.setResizable(false);
		window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		window.add(new GamePanel());
		window.pack();
		
		window.setLocationRelativeTo(null);
		window.setVisible(true);
	}
}


GamePanel.java

import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.image.BufferedImage;
import java.util.ArrayList;

import javax.swing.JPanel;


public class GamePanel extends JPanel implements Runnable, KeyListener {
	
	// 640 480
	public static int WIDTH = 320;
	public static int HEIGHT = 240;
	public static int SCALE = 2;
	
	// 游戏线程 游戏循环
	private Thread thread;
	private boolean running;
	
	// 实现双缓冲
	private BufferedImage image;
	private Graphics2D	g;
	
	private Player player;
	public static ArrayList<Bullet> bullets;
	public static ArrayList<Enemy> enemies;
	// 设置窗口大小以及事件的捕捉
	public GamePanel() {
		setPreferredSize(new Dimension(WIDTH * SCALE, HEIGHT * SCALE));
		setFocusable(true);
		requestFocus();
	}
	
	// 初始化游戏线程并启动游戏线程 增加键盘监听器
	public void addNotify() {
		super.addNotify();
		if (thread == null) {
			thread = new Thread(this);
			thread.start();
		}
		addKeyListener(this);
	}
	
	private void init() {
		running = true;		//实现游戏循环
		image = new BufferedImage(WIDTH*SCALE, HEIGHT*SCALE, BufferedImage.TYPE_INT_RGB);	//创建一个后备缓冲
		
		g = (Graphics2D) image.getGraphics();
		
		player = new Player(WIDTH, HEIGHT);
		bullets = new ArrayList<Bullet>();
		enemies = new ArrayList<Enemy>();
		for(int i = 0; i < 100; i++) {
			enemies.add(new Enemy(1,1));
		}
	}
	
	public void run() {
	
		init();
		
		
		int fps = 30;
		long startTime;
		long elapsedTime;
		long waitTime;
		long targetTime = 1000 / fps;
		
		while (running) {
			startTime = System.nanoTime();
			update();
			render();
			draw();
			elapsedTime = (System.nanoTime() - startTime) / 1000000;
			waitTime = targetTime - elapsedTime;
			try {
				Thread.sleep(waitTime);
			}
			catch (Exception e) {
				e.printStackTrace();
			}
		}
	}
	
	private void update() {
		player.update();
		
		// 子弹更新
		for (int i = 0; i < bullets.size(); i++) {
			boolean remove = bullets.get(i).update();
			if (remove) {
				bullets.remove(i);
				i--;
			}
		}
		
		// 敌人更新
		for (int i = 0; i < enemies.size(); i++) {
			enemies.get(i).update();
		}
		
		
		// 子弹和敌人的碰撞检测
		for (int i = 0; i < bullets.size(); i++) {
			Bullet b = bullets.get(i);
			double br = b.getr();
			double bx = b.getx();
			double by = b.gety();
			
			for(int j = 0; j < enemies.size(); j++) {
				Enemy e = enemies.get(j);
				double er = e.getr();
				double ex = e.getx();
				double ey = e.gety();
				double dx = bx - ex;
				double dy = by - ey;
				double dist = Math.sqrt(dx * dx + dy * dy);
				
				if (dist < br + er) {
					e.hit();
					bullets.remove(i);
					i--;
					break;
				}
				
			}
		}
		
		// 敌人的更新
		// 死亡则删除
		for (int i = 0; i < enemies.size(); i++) {
			if(enemies.get(i).isDead()) {
				enemies.remove(i);
				i--;
			}
		}
	}
	
	private void render() {
		g.setColor(new Color(20, 15, 20));
		g.fillRect(0, 0, GamePanel.WIDTH*GamePanel.SCALE, GamePanel.HEIGHT*GamePanel.SCALE);
		
		player.draw(g);
		// 绘制子弹
		for (int i = 0; i < bullets.size(); i++)
			bullets.get(i).draw(g);
		// 绘制敌人
		for (int i = 0; i < enemies.size(); i++) {
			enemies.get(i).draw(g);
		}
	}
	
	private void draw() {
		// 主缓冲 
		Graphics g2 = getGraphics();
		if (g2 == null) {
			System.out.println("G2 is NULL");
			System.exit(0);
		}
		// 把后备缓冲绘制到主缓冲 实现平滑的动态效果
		g2.drawImage(image, 0, 0, null);
		g2.dispose();
	}
	
	public void keyPressed(KeyEvent event) {
		int keyCode = event.getKeyCode();
		player.keyPressed(keyCode);
	}
	
	public void keyReleased(KeyEvent event) {
		int keyCode = event.getKeyCode();
		player.keyReleased(keyCode);
	}
	
	public void keyTyped(KeyEvent event) {
		
	}
	
}


Player.java

import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.event.KeyEvent;
import java.util.ArrayList;


public class Player {
	
	// w: 宽度
	// h: 高度
	// x, y: 玩家坐标
	// dx, dy: 要移动的坐标
	// speed: 速度
	private int w;
	private int h;
	private double x;
	private double y;
	private double dx;
	private double dy;
	private double speed;
	
	private boolean up;
	private boolean down;
	private boolean left;
	private boolean right;
	
	private boolean firing;
	private long firingTimer;
	private long firingDelay;
	
	public Player(double x, double y) {
		this.x = x;
		this.y = y;
		this.dx = 0;
		this.dy = 0;
		this.w = 16;
		this.h = 16;
		this.speed = 5;
		
		// 发射状态
		// 以及子弹的刷新时间
		this.firing = false;
		this.firingTimer = System.nanoTime();
		this.firingDelay = 150;
	}
	
	public void update() {
		// 角色移动
		if (left) {
			dx = -speed;
		}
		if (right) {
			dx = speed;
		}
		if (up) {
			dy = -speed;
		}
		if (down) {
			dy = speed;
		}
		x += dx;
		y += dy;
		
		// 碰撞检测
		if (x < 0) { x = 0; }
		if (y < 0) { y = 0; }
		if (x > GamePanel.WIDTH * GamePanel.SCALE - w) {
			x = GamePanel.WIDTH * GamePanel.SCALE - w;
		}
		if (y > GamePanel.HEIGHT * GamePanel.SCALE - h) {
			y = GamePanel.HEIGHT * GamePanel.SCALE - h;
		}
		
		if (firing) {
			long elapsed = (System.nanoTime() - firingTimer) / 1000000;
			if (elapsed > firingDelay) {
				GamePanel.bullets.add(new Bullet(270, x, y, this));
				firingTimer = System.nanoTime();
			}
			
		}
		// 重置目的坐标
		dx = 0;
		dy = 0;
	}
	
	public void draw(Graphics2D g) {
		g.setColor(new Color(0, 120, 255));
		g.fillRect((int)x, (int)y, w, h);
	}
	
	public int getw() { return w; }
	
	public int geth() { return h; }
	
	private void setUp(boolean v) { this.up = v; }
	private void setDown(boolean v) { this.down = v; }
	private void setLeft(boolean v) { this.left = v; }
	private void setRight(boolean v) { this.right = v; }
	private void setFiring(boolean v) { this.firing = v; }
	
	public void keyPressed(int keyCode) {
		if (keyCode == KeyEvent.VK_UP) {
			setUp(true);
		}
		if (keyCode == KeyEvent.VK_DOWN) {
			setDown(true);
		}
		if (keyCode == KeyEvent.VK_RIGHT) {
			setRight(true);
		}
		if (keyCode == KeyEvent.VK_LEFT) {
			setLeft(true);
		}
		if (keyCode == KeyEvent.VK_SPACE) {
			setFiring(true);
		}
	}
	
	public void keyReleased(int keyCode) {
		if (keyCode == KeyEvent.VK_UP) {
			setUp(false);
		}
		if (keyCode == KeyEvent.VK_DOWN) {
			setDown(false);
		}
		if (keyCode == KeyEvent.VK_RIGHT) {
			setRight(false);
		}
		if (keyCode == KeyEvent.VK_LEFT) {
			setLeft(false);
		}
		if (keyCode == KeyEvent.VK_SPACE) {
			setFiring(false);
		}
	}
	
}


Bullet.java

import java.awt.Color;
import java.awt.Graphics2D;


public class Bullet {
	
	protected Player player;
	
	private double x;
	private double y;
	private int w;
	private int h;
	private double r; // to bullet-enemies collision
	
	private double dx;
	private double dy;
	private double rad;
	private double speed;
	
	private Color color;
	
	public Bullet(double angle, double x, double y, Player player) {
		
		this.player = player;
		
		this.x = x;
		this.y = y;
		
		this.rad = Math.toRadians(angle);
		this.speed = 15.44;
		this.w = this.h = 3;
		// 计算子弹的半径 
		// 用于实现子弹与敌人的碰撞检测
		this.r = Math.sqrt(w*w + h*h)/2;
		// 确保子弹在角色上方
		this.dx = (int) (Math.cos(rad) * speed);
		this.dy = (int) (Math.sin(rad) * speed);
		
		color = new Color(255, 220, 0);
	}
	
	public double getx() { return x; }
	public double gety() { return y; }
	public int getw() { return w; }
	public int geth() { return h; }
	public double getr() { return r; }
	public boolean update() {

		x += dx;
		y += dy;

		if (x < -w || x > GamePanel.WIDTH*GamePanel.SCALE + w ||
			y < -h || y > GamePanel.HEIGHT*GamePanel.SCALE + h) {
			return true;
		}
		return false;
	}
	
	public void draw(Graphics2D g) {
		g.setColor(color);
		g.fillRect((int)(x+player.getw()/2-1), (int)(y+player.geth()/2), w, h);
	}
}


Enemy.java

import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Graphics2D;


public class Enemy {
	private double x;
	private double y;
	private double r;
	
	private double dx;
	private double dy;
	private double rad;
	private double speed;
	
	private int health;
	private int type;
	private int rank;
	
	private Color color1;
	
	private boolean dead;
	
	public Enemy(int type, int rank) {
		this.type = type;	// 类型
		this.rank = rank;	// 级别
		
		if (type == 1) {
			color1 = Color.YELLOW;	// 颜色
			r = 5;					// 外观
			if (rank == 1) {		// 战斗属性
				speed = 2;
				
				health = 2;
			}
		}
		
		// 生成坐标
		x = (Math.random() * GamePanel.HEIGHT*GamePanel.SCALE / 2 + GamePanel.WIDTH*GamePanel.SCALE / 4);
		y = -r;
		
		// 坐标方向
		double angle = Math.random() * 140 + 20;
		rad = Math.toRadians(angle);
		
		// 偏移坐标
		dx = Math.cos(rad)*speed;
		dy = Math.sin(rad)*speed;
	
		dead = false;
	}
	
	public double getx() { return x; }
	public double gety() { return y; }
	public double getr() { return r; }
	
	
	public boolean isDead() { return dead; }
	
	public void hit() {
		health--;
		color1 = Color.RED;
		if (health <= 0) {
			dead = true;
		}
	}
	
	public void update() {
		
		x += dx;
		y += dy;
		
		// 屏幕的碰撞检测
		
		// 碰撞屏幕后自动便宜
		if (x < r && dx < 0) dx = -dx;
		if (y < r && dy < 0) dy = -dy;
		if (x > GamePanel.WIDTH*GamePanel.SCALE - r && dx > 0) dx = -dx;
		if (y > GamePanel.HEIGHT*GamePanel.SCALE  - r && dy > 0) dy = -dy;
	}
	
	public void draw(Graphics2D g) {
		
		g.setColor(color1);
		g.fillOval((int)(x - r), (int) (y - r), (int)(2 * r), (int)(2 * r));
		
		g.setStroke(new BasicStroke(3));
		g.setColor(color1.darker());
		g.drawOval((int)(x-r), (int)(y-r), (int)(2 * r), (int)(2 * r));
		g.setStroke(new BasicStroke(1));
	}
	
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值