利用小游戏学习多线程之飞机躲子弹

来源:互联网 发布:市场份额数据优缺点 编辑:程序博客网 时间:2024/06/07 20:25

新的游戏思路如下:

通过鼠标来点击屏幕,在鼠标点击的位置生成小球,并且颜色随机。点击一次启动一个线程,一个线程代表一个小球,小球可以随机移动,假如小飞机碰到小球,则小球停止移动,即线程死亡。代码只有三个类,复制起来比较容易。


PlaneBall3.java


package com.study.thread;


import java.awt.Color;
import java.awt.Font;
import java.awt.Frame;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.util.ArrayList;


import com.game.util.Constant;
import com.game.util.GameUtil;




public class PlaneBall3 extends Frame{
long starttime;
int x = 200;
int y = 100;
private boolean renew = true;
Plane plane = new Plane("images/plane.PNG",50,50);
private java.util.List<Ball> balls = new ArrayList<>();
int frame_x;
int frame_y;
boolean title=true;
public void launch() {
setSize(600, 400);
setLocation(200,200);
setVisible(true);
addWindowListener(new WindowAdapter() {
@Override
public void windowClosing(WindowEvent e) {
System.exit(0);
}
});
addMouseListener(new MouseAdapter() {


@Override
public void mouseClicked(MouseEvent e) {
Point point = java.awt.MouseInfo.getPointerInfo().getLocation();

frame_x=getX();
frame_y=getY();
if(renew==true){
new BallThread((point.x-frame_x), (point.y-frame_y)).start();
}
title = false;
}

});
addKeyListener(new KeyMonitor());
starttime = System.currentTimeMillis();
}

class BallThread extends Thread{
int x;
int y;

public BallThread(int x, int y) {
this.x = x;
this.y = y;
  }
  public void  run(){
Ball ball = new Ball();
ball.x = x;
ball.y = y;
balls.add(ball);

for(int i = 0;i<5000;i++){
    ball.move();
    if(ball.getRec().intersects(plane.getRec())){
   
    break;
   
    }
    try {
Thread.currentThread().sleep(40);
} catch (InterruptedException e) {
e.printStackTrace();
}
    repaint();
}

  }
}

@Override
public void paint(Graphics g) {

g.drawString("游戏时间:"+(System.currentTimeMillis()-starttime)/1000+"s", 20, 50);
for (Ball ball : balls)
      {
if(ball.visible == true){
Color color = new Color(
(new Double(Math.random() * 128)).intValue()+50,
(new Double(Math.random() * 128)).intValue()+50,
(new Double(Math.random() * 128)).intValue()+50);
g.setColor(color);
g.fillOval(ball.x, ball.y, 15, 15);
}
      }
plane.draw(g);
 
if(title==true){
Font font2 = new Font("微软雅黑", Font.ITALIC, 40);
g.setFont(font2);
g.drawString("请点击窗体开始游戏", 100, 200);
}
}
private Color backColor = new Color(0x65, 0xc2, 0x94);
    private Image offScreenImage = null;
public void update(Graphics g) {
        if (this.offScreenImage == null) {
            this.offScreenImage = this.createImage(600, 400);
        }
        Graphics goff = offScreenImage.getGraphics();
        Color c = goff.getColor();
        goff.setColor(this.backColor);
        goff.fillRect(0, 0, 600, 400);
        goff.setColor(c);
        paint(goff);
        g.drawImage(this.offScreenImage, 0, 0, null);
    }
class KeyMonitor extends KeyAdapter{


@Override
public void keyPressed(KeyEvent e) {
plane.adddirection(e);
}


@Override
public void keyReleased(KeyEvent e) {
plane.reduceirection(e);
}

}
public static void main(String[] args) {
new PlaneBall3().launch();
}
class Ball{
int x;
int y;
double degree = Math.PI*2*Math.random();
boolean visible = true;
public Ball() {}


public Ball(int x, int y) {
this.x = x;
this.y = y;
}

public void move(){
x +=10*Math.cos(degree);
y +=10*Math.sin(degree);
if(x<0||x>600-20){
degree = Math.PI-degree;
}
if(y<0||y>400-20){
degree = -degree;
}
}
public Rectangle getRec(){
return new Rectangle(x, y, 20, 20);
}
}
}


Plane.java

package com.study.thread;


import java.awt.Graphics;
import java.awt.Image;
import java.awt.Rectangle;
import java.awt.event.KeyEvent;


public class Plane {

Image img;
public double x;
public double y;
public boolean left,right,up,down;
public int speed = 7;
public int width,height;
public Rectangle getRec(){
return new Rectangle((int)x, (int)y, width, height);
}




public void draw(Graphics g){
g.drawImage(img, (int)x, (int)y, null);
move();
}
public void move(){
if(left){
x -=speed;
if(x<0){
x = 0;
}
}
if(right){
x +=speed;
if(x>600-width){
x = 600-width;
}
}
if(up){
y -=speed;
if(y<height){
y = height;
}
}
if(down){
y +=speed;
if(y>400-height){
y = 400-height;
}
}
}
public void adddirection(KeyEvent e){
switch (e.getKeyCode()) {
case KeyEvent.VK_LEFT:
left = true;
break;
case KeyEvent.VK_RIGHT:
right = true;
break;
case KeyEvent.VK_UP:
up = true;
break;
case KeyEvent.VK_DOWN:
down = true;
break;
default:
break;
}
}
public void reduceirection(KeyEvent e){
switch (e.getKeyCode()) {
case KeyEvent.VK_LEFT:
left = false;
break;
case KeyEvent.VK_RIGHT:
right = false;
break;
case KeyEvent.VK_UP:
up = false;
break;
case KeyEvent.VK_DOWN:
down = false;
break;
default:
break;
}
}
public Plane(){


}
public Plane(String path,double x,double y){

this.img = GameUtil.getImage(path);
this.width = img.getWidth(null);
this.height = img.getHeight(null);
this.x = x;
this.y = y;
}
}


GameUtil.java

package com.study.thread;


import java.awt.Image;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.net.URL;


import javax.imageio.ImageIO;


public class GameUtil {

private GameUtil(){}

public static Image getImage(String path){
URL u=GameUtil.class.getClassLoader().getResource(path);
BufferedImage img=null;
try {
img = ImageIO.read(u);
} catch (IOException e) {
e.printStackTrace();
}

return img;

}
}

游戏运行起来的时候发现,假如小球越多,小飞机的速度就会越快,想了想是因为每个小球都代表了一个线程,每次产生小球的时候都会调用repaint()这个方法,小球越多,调用次数就会越来越多,小飞机的速度就会加快。假如并不想让小飞机的速度加快,可以直接在一个线程里面实现产生多个小球,然后控制这个线程的死亡与否,便可以实现我之前一直想要的不点击运行按钮便重新开始游戏。













之前打算写的小游戏是利用键盘控制屏幕中的小飞机来躲避子弹,假如飞机碰到子弹则游戏结束。

这个小游戏只要利用重写paint()方法即可实现。


代码如下:

PlaneGameFrame.java


package com.game.plane;


import java.awt.Font;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.util.ArrayList;


import com.game.util.Bullet;
import com.game.util.GameUtil;
import com.game.util.MyFrame;
import com.game.util.Plane;


public class PlaneGameFrame extends MyFrame {


Plane plane = new Plane("image/plane.PNG",50,50);
Boolean Game = true;
ArrayList bulletlist = new ArrayList();
long start = System.currentTimeMillis();
Image sky = GameUtil.getImage("image/sky.jpg");
public void paint(Graphics g){
if(Game==true){
plane.draw(g);
for(int i=0;i<18;i++){
Bullet bullet = new Bullet();
bullet = (Bullet) bulletlist.get(i);
bullet.draw(g);
if(plane.getRec().intersects(bullet.getRec())){
Game = false;
}
}

}else {
Font font = new Font("宋体", Font.BOLD, 100);
g.setFont(font);
g.drawString("game over", 200, 200);
Font font2 = new Font("微软雅黑", Font.ITALIC, 30);
g.setFont(font2);
g.drawString("游戏时间:"+(System.currentTimeMillis()-start)/1000+"s", 300, 500);
}

}

public void launchFrame(){
super.launchFrame();
addKeyListener(new KeyMonitor());
for(int i=0;i<18;i++){
Bullet b = new Bullet();
bulletlist.add(b);
}
}

class KeyMonitor extends KeyAdapter{


@Override
public void keyPressed(KeyEvent e) {
plane.adddirection(e);
}


@Override
public void keyReleased(KeyEvent e) {
plane.reduceirection(e);
}

}

public static void main(String[] args) {
new PlaneGameFrame().launchFrame();
}
}


Ball.java

package com.game.util;


import java.awt.Font;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.Rectangle;






public class Ball {
public int x;
public int y;
public double degree = -Math.PI/6;
Image img ;
private int width;
public int height;

public Ball(){
}
public Ball(String imgpath,int x,int y){
img = GameUtil.getImage(imgpath);
width = img.getWidth(null);
height = img.getHeight(null);
this.x = x;
this.y = y;
}
public void move(long start){

x +=Constant.SPEED*Math.cos(degree);
y +=Constant.SPEED*Math.sin(degree);

if(x<0||x>500-25){
degree = Math.PI-degree;
}
if(y<0){
degree = -degree;
}
if(y>500-25){

degree = -degree;
}

}
public Rectangle getRec(){
return new Rectangle(x, y, width, height);
}

public void draw(Graphics g){
g.drawImage(img, x, y, null);
}
}

Bullet.java

package com.game.util;


import java.awt.Color;
import java.awt.Graphics;
import java.awt.Rectangle;


public class Bullet {
double x,y;
int speed = 10;
double degree;
int width = 10;
int height = 10;
public Bullet(){
degree = Math.random()*Math.PI*2;
x = Constant.GAME_WIDTH/2;
y = Constant.GAME_HEIGHT/2;
}
public Rectangle getRec(){
return new Rectangle((int)x, (int)y, width, height);
}

public void draw(Graphics g){
Color color = g.getColor();
g.setColor(Color.RED);
g.fillOval((int)x, (int)y, width, height);
x +=speed*Math.cos(degree);
y +=speed*Math.sin(degree);

if(x<0||x>Constant.GAME_WIDTH-width){
degree = Math.PI-degree;
}
if(y<height||y>Constant.GAME_HEIGHT-height){
degree = -degree;
}


g.setColor(color);
}
}

Constant.java

package com.game.util;


public class Constant {

public static final int GAME_WIDTH = 800;
public static final int GAME_HEIGHT = 600;
public static final int SPEED = 20;
}

GameUtil.java

package com.game.util;


import java.awt.Image;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.net.URL;


import javax.imageio.ImageIO;


public class GameUtil {

private GameUtil(){}

public static Image getImage(String path){
URL u=GameUtil.class.getClassLoader().getResource(path);
BufferedImage img=null;
try {
img = ImageIO.read(u);
} catch (IOException e) {
e.printStackTrace();
}

return img;

}
}


MyFrame.java

package com.game.util;


import java.awt.Color;
import java.awt.Frame;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;




public class MyFrame extends Frame {


public void launchFrame(){
setSize(Constant.GAME_WIDTH,Constant.GAME_HEIGHT);
setVisible(true);
new PaintThread().start();
addWindowListener(new WindowAdapter() {
@Override
public void windowClosing(WindowEvent event){
System.exit(0);
}
});



// private Image offScreenImage = null;
// public void update(Graphics g){
// if(offScreenImage == null)
// offScreenImage = this.createImage(Constant.GAME_WIDTH,Constant.GAME_HEIGHT);
// Graphics gOff = offScreenImage.getGraphics();
// paint(gOff);
// g.drawImage(offScreenImage, 0, 0, null);
// }
private Color backColor = new Color(0x65, 0xc2, 0x94);
    private Image offScreenImage = null;
public void update(Graphics g) {
        if (this.offScreenImage == null) {
            this.offScreenImage = this.createImage(Constant.GAME_WIDTH, Constant.GAME_HEIGHT);
        }
        Graphics goff = offScreenImage.getGraphics();
        Color c = goff.getColor();
        goff.setColor(this.backColor);
        goff.fillRect(0, 0, Constant.GAME_WIDTH, Constant.GAME_HEIGHT);
        goff.setColor(c);
        paint(goff);
        g.drawImage(this.offScreenImage, 0, 0, null);
    }


class PaintThread extends Thread {

public void run() {
while(true) {
repaint();
try {
Thread.sleep(40);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}


Plane.java

package com.game.util;


import java.awt.Graphics;
import java.awt.Image;
import java.awt.Rectangle;
import java.awt.event.KeyEvent;


public class Plane {

Image img;
public double x;
public double y;
public boolean left,right,up,down;
public int speed = 10;
public int width,height;
public Rectangle getRec(){
return new Rectangle((int)x, (int)y, width, height);
}




public void draw(Graphics g){
g.drawImage(img, (int)x, (int)y, null);
move();
}
public void move(){
if(left){
x -=speed;
if(x<0){
x = 0;
}
}
if(right){
x +=speed;
if(x>500-width){
x = 500-width;
}
}
if(up){
y -=speed;
if(y<height){
y = height;
}
}
if(down){
y +=speed;
if(y>500-height){
y = 500-height;
}
}
}
public void adddirection(KeyEvent e){
switch (e.getKeyCode()) {
case KeyEvent.VK_LEFT:
left = true;
break;
case KeyEvent.VK_RIGHT:
right = true;
break;
case KeyEvent.VK_UP:
up = true;
break;
case KeyEvent.VK_DOWN:
down = true;
break;
default:
break;
}
}
public void reduceirection(KeyEvent e){
switch (e.getKeyCode()) {
case KeyEvent.VK_LEFT:
left = false;
break;
case KeyEvent.VK_RIGHT:
right = false;
break;
case KeyEvent.VK_UP:
up = false;
break;
case KeyEvent.VK_DOWN:
down = false;
break;
default:
break;
}
}
public Plane(){


}
public Plane(String path,double x,double y){

this.img = GameUtil.getImage(path);
this.width = img.getWidth(null);
this.height = img.getHeight(null);
this.x = x;
this.y = y;
}
}

这样勉强就可以玩游戏了,但是我玩了几回,发现实在太麻烦了,每次结束都需要重新点击运行按钮,我就想可不可以在游戏结束之后重新开始游戏呢,几次尝试之后,我觉着利用单线程的boolean变量实现起来很麻烦,这样自然会想到多线程。


新的游戏思路如下:

通过鼠标来点击屏幕,在鼠标点击的位置生成小球,并且颜色随机。点击一次启动一个线程,一个线程代表一个小球,小球可以随机移动,假如小飞机碰到小球,则小球停止移动,即线程死亡。

原创粉丝点击