【Java小專案】打飛機
主要功能:
1.w,a,s,d八個方向移動,j射擊
2.預設會右有5個敵機,敵機會有一個隨機方向,並一直按著這個方向移動,碰到邊界會發生反彈
3.每個飛機只能發5個子彈,只有玩家的子彈才能對敵機造成傷害。
4.用ArrayList存放子彈,repaint的時候遍歷重繪
5.用ConcurrentHashMap存放飛機,用HaskMap的話,當遍歷的時候如果改變HaskMap的元素的話就會有一個Concurrent異常,而ConcurrentHashMap會自己檢查變化。
遇到的問題:
plane類:
問題:在按鍵觸發時執行,但是飛機的移動不順滑即按住一個方向它會頓一下才繼續向前。
解決方法:給飛機類加個Runnable介面,用執行緒來處理飛機移動,給4個方向boolean標誌。
完整程式碼:
Enemy類:package com.ztc.plane; import javax.swing.*; import java.awt.*; /** * Created by ztc on 15-11-29. */ public class Plane implements Runnable{ //座標 double x,y; double speed; Image img; //移動方向,存活狀態 boolean up,down,left,right,alive; //發射子彈數 int bulletSum; String name; public void setUp(boolean up) { this.up = up; } public void setDown(boolean down) { this.down = down; } public void setLeft(boolean left) { this.left = left; } public void setRight(boolean right) { this.right = right; } public Plane(){} public void setAlive(boolean alive) { this.alive = alive; } public Plane(String path,double x,double y,double speed,String name){ this.x=x; this.y=y; this.speed=speed; this.alive=true; this.name=name; img=Util.getImage(path); } public void draw(Graphics g){ g.drawImage(img,(int)x,(int)y,null); } public void move(boolean up,boolean down,boolean left,boolean right){ if(up&&y-speed>0) y-=speed; if(down&&y+speed<Constant.GrameHeight-new ImageIcon(img).getIconHeight()) y+=speed; if(left&&x-speed>0) x-=speed; if(right&&x+speed<Constant.GrameWidht-new ImageIcon(img).getIconWidth()) x+=speed; } public Rectangle getRect(){ return new Rectangle((int)x,(int)y,new ImageIcon(img).getIconWidth(),new ImageIcon(img).getIconHeight()); } public void boom(Graphics g) { for (int i = 3; i > 0; i--) { g.drawImage(Util.getImage("assets/boom0" + i + ".png"), (int) x, (int) y, null); } } public int getBulletSum() { return bulletSum; } public void setBulletSum(int bulletSum) { this.bulletSum = bulletSum; } public Bullet shot(){ Bullet bullet=null; if(alive&&bulletSum<Constant.BulletSum) { bullet = new Bullet("assets/bullet02.png", (int) x - 7 + new ImageIcon(img).getIconWidth() / 2, (int) y-15, Constant.BulletSpeed, 0.5,name); new Thread(bullet).start(); bulletSum++; } return bullet; } @Override public void run() { while(true){ move(up,down,left,right); try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } } } }
Enemy類繼承Plane類,所以它的移動只要重寫run函式。
隨機角度:double o=new Random().nextDouble()*Math.PI*2;
問題:遇到邊界後鏡面反彈;
解決方法:以隨機出來的方向與垂直向下的方向的夾角為要計算的角度,顯然若碰到垂直的邊則o= Math.PI*2-o碰到水平方向則o=Math.PI-o;
完整程式碼:
package com.ztc.plane;
import javax.swing.*;
import java.util.Random;
/**
* Created by ztc on 15-11-30.下午1:22
*/
public class Enemy extends Plane{
//軌跡
String track;
double o=new Random().nextDouble()*Math.PI*2;
public Enemy(){}
public Enemy(String path,double x,double y,double speed,String name,String track){
super(path,x,y,speed,name);
this.track=track;
}
//隨機方向,遇邊鏡面反射
public void myTrack(){
x-=speed*Math.sin(o);
y-=speed*Math.cos(o);
if(x<0||x>Constant.GrameWidht-new ImageIcon(img).getIconWidth()){
o= Math.PI*2-o;
}
if(y<0||y>Constant.GrameHeight-new ImageIcon(img).getIconHeight()-100){
o=Math.PI-o;
}
}
public void run(){
while(true){
myTrack();
if(alive&&bulletSum<Constant.BulletSum) {
Bullet bullet = new Bullet("assets/bullet01.png", (int) x - 7 + new ImageIcon(img).getIconWidth() / 2, (int) y + new ImageIcon(img).getIconHeight(), Constant.BulletSpeed, 0,name);
new Thread(bullet).start();
Util.bullets.add(bullet);
bulletSum++;
}
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
Bullet類:
問題:剛開始時把移動寫了一個方法在repaint的時候呼叫,速度很怪異
解決:加Runnable藉口,移動寫在run裡
package com.ztc.plane;
import javax.swing.*;
import java.awt.*;
import java.util.Random;
/**
* Created by ztc on 15-11-29.下午12:35
*/
public class Bullet implements Runnable{
//座標
double x=200,y=200;
double speed;
Image img;
//方向(0,1)
double direct;
double o=new Random().nextDouble()*Math.PI*2;
boolean alive;
String owner;
public boolean isAlive() {
return alive;
}
public void setAlive(boolean alive) {
this.alive = alive;
}
public Bullet(){
}
public Bullet(String path,double x,double y,double speed,double direct,String owner){
this.x=x;
this.y=y;
this.speed=speed;
this.direct=direct;
this.alive=true;
this.owner=owner;
img=Util.getImage(path);
}
public void draw(Graphics g){
g.drawImage(img,(int)x,(int)y,null);
}
public String getOwner() {
return owner;
}
//隨機方向,遇邊鏡面反射
public void drawRandom(Graphics g){
g.drawImage(img,(int)x,(int)y,null);
x-=speed*Math.sin(o);
y-=speed*Math.cos(o);
if(x<0||x>Constant.GrameWidht){
o=Math.PI*2-o;
}
if(y<0||y>Constant.GrameHeight){
o=Math.PI-o;
}
}
public Rectangle getRect(){
return new Rectangle((int)x,(int)y,new ImageIcon(img).getIconWidth(),new ImageIcon(img).getIconHeight());
}
@Override
public void run() {
while(true){
x+=speed*Math.sin(direct*Math.PI*2);
y+=speed*Math.cos(direct*Math.PI*2);
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
if(y<0||x<0||y>Constant.GrameHeight||x>Constant.GrameWidht) {
alive=false;
break;
}
}
}
}