第一次發博客,學了3天的android studio還有一點以前的java基礎做了個基於多線程的飛機大戰的遊戲
遊戲比較簡單大概就這幾個功能
1.會動的背景
2.我的飛機
3.發射子彈
3.敵人飛機
第一步新建一個項目
我用的是Android4.4版本
新建好項目之後 xml文件之類的什麼都不用管
先新建個類
叫做hua
hua.java
package com.dahuijii.liziguo;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.RectF;
import android.view.MotionEvent;
import android.view.View;
import java.util.Vector;
/**
* Created by Liziguo on 2018/5/10.
*/
class my{//新建一個類 裏面的東西都是靜態的 當全局變量用
public static int js=0;//擊殺數
public static int w,h;//屏幕的寬高
public static float bili;//比例,用於適應不同屏幕
public static Vector<hj> list=new Vector<hj>();//所有飛行物的集合,添加進這個集合才能被畫出來
public static Vector<hj> drlist=new Vector<hj>();//敵人飛機的集合,添加進這個集合才能被子彈打中
//我集合學的挺爛的哈 爲什麼用Vector呢?因爲他線程是安全的。。。
public static Bitmap myhj,drhj,bj,myzd;//圖片:我的灰機 敵人灰機 背景 我的子彈
public static myhj my;//我的灰機
public static bj b;//背景
}
public class hua extends View{//畫
private Paint p=new Paint();//畫筆
private float x,y;//按下屏幕時的座標
private float myx,myy;//按下屏幕時玩家飛機的座標
public hua(Context context) {
super(context);
//添加事件控制玩家飛機
setOnTouchListener(new OnTouchListener() {
@Override
public boolean onTouch(View view, MotionEvent e) {
if(e.getAction()==MotionEvent.ACTION_DOWN){
x=e.getX();
y=e.getY();
myx=my.my.r.left;
myy=my.my.r.top;
}
float xx=myx+e.getX()-x;
float yy=myy+e.getY()-y;
//我的飛機不能飛出屏幕
xx=xx<my.w-my.my.w/2?xx:my.w-my.my.w/2;
xx=xx>-my.my.w/2?xx:-my.my.w/2;
yy=yy<my.h-my.my.h/2?yy:my.h-my.my.h/2;
yy=yy>-my.my.h/2?yy:-my.my.h/2;
my.my.setX(xx);
my.my.setY(yy);
return true;
}
});
setBackgroundColor(Color.BLACK);//設背景顏色爲黑色
my.myhj= BitmapFactory.decodeResource(getResources(),R.mipmap.hj);//加載圖片
my.drhj=BitmapFactory.decodeResource(getResources(),R.mipmap.dr);
my.myzd=BitmapFactory.decodeResource(getResources(),R.mipmap.zd);
my.bj=BitmapFactory.decodeResource(getResources(), R.mipmap.bj);
new Thread(new re()).start();//新建一個線程 讓畫布自動重繪
new Thread(new loaddr()).start();//新建一個 加載敵人的線程
}
@Override
protected void onDraw(Canvas g) {//這個相當於swing的paint方法吧 用於繪製屏幕上的所有物體
super.onDraw(g);
g.drawBitmap(my.b.img,null,my.b.r,p);//畫背景 我沒有把背景添加到list裏
for(int i=0;i<my.list.size();i++){//我們把所有的飛行物都添加到了my.list這個集合裏
hj h=my.list.get(i); //然後在這裏用一個for循環畫出來
g.drawBitmap(h.img,null,h.r,p);
}
g.drawText("擊殺:"+my.js,0,my.h-50,p);
}
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {//這個方法用來獲取屏幕寬高的
super.onSizeChanged(w, h, oldw, oldh);
my.w=w;//獲取寬
my.h=h;//高
//獲取手機(應該不是手機的吧 是這控件的吧)分辨率和1920*1080的比例
//然後飛機的寬高乘上這個分辨率就能在不同大小的屏幕正常顯示了
//爲什麼用1920*1080呢 因爲我手機就是這個分辨率。。。
my.bili= (float) (Math.sqrt(my.w * my.h)/ Math.sqrt(1920 * 1080));
p.setTextSize(50*my.bili);//設置字體大小,“擊殺”的大小
p.setColor(Color.WHITE);//設爲白色
//好了 到這裏遊戲開始了
my.b=new bj();//初始化背景
my.my=new myhj();//初始化 我的灰機
}
private class re implements Runnable {
@Override
public void run() {
//每10ms刷新一次界面
while(true){
try { Thread.sleep(10);} catch (InterruptedException e) {e.printStackTrace();}
postInvalidate();//刷新畫布
//就是這個東西拖了我一天
//swing是repaint()方法刷新的
//然後這裏沒有repaint方法
//然後突然想起C#有一個invalidate()方法是刷新畫布的
//然後這線程裏用invalidate()會閃退.....
//煩死了
}
}
}
private class loaddr implements Runnable{
@Override
public void run() {
while(true){
//每300ms刷一個敵人
try {Thread.sleep(300);} catch (InterruptedException e) {e.printStackTrace();}
try {
new drhj();
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
}
class hj{//遊戲內所有物體的父類
public RectF r=new RectF();//這個是用來確定位置的
public int hp;//生命
public float w,h;//寬高
public Bitmap img;//圖片
//這裏的畫圖方法和swing的不太一樣
//設兩個方法來設置x,y的座標
public void setX(float x){
r.left=x;
r.right=x+w;
}
public void setY(float y){
r.top=y;
r.bottom=y+h;
}
public boolean pengzhuang(hj obj,float px) {//判斷碰撞 判斷時忽略px個像素
px*=my.bili;//凡是涉及到像素的 都乘一下分辨率比例my.bili
if (r.left+px - obj.r.left <= obj.w && obj.r.left - this.r.left+px <= this.w-px-px)
if (r.top+px - obj.r.top <= obj.h && obj.r.top - r.top+px <= h-px-px) {
return true;
}
return false;
}
}
class bj extends hj implements Runnable{//背景
public bj(){
w=my.w;
h=my.h*2;//背景的高是 屏幕高的兩倍
img=my.bj;
setX(0);
setY(-my.h);
new Thread(this).start();
}
@Override
public void run() {
//這裏控制背景一直向下移
while(true){
try {Thread.sleep(10);} catch (InterruptedException e) {e.printStackTrace();}
if(r.top+2<=0){
setY(r.top+2);
}else{
setY(-my.h);
}
}
}
}
class drhj extends hj implements Runnable{//敵人灰機
private long sd0=(long) (Math.random()*10)+10;//生成一個[10,20)的隨機數 用來控制敵人速度 敵人速度是不一樣的
public drhj(){
// w=my.w/5.4f;
// h=my.h/9.6f;
w=h=200*my.bili;
//敵人刷出來的位置
setX((float)( Math.random()*(my.w-w)));//x是隨機的
setY(-h);//在屏幕外 剛好看不到的位置
img=my.drhj;
hp=12;//生命=12
my.list.add(this);//添加到集合裏 這樣才能被畫出來
my.drlist.add(this);//添加到敵人的集合 添加進這個集合子彈纔打得到
new Thread(this).start();
}
@Override
public void run() {
while(hp>0){//如果生命>0 沒有死 就繼續向前飛,死了還飛什麼?
try {Thread.sleep(sd0);} catch (InterruptedException e) {e.printStackTrace();}
setY(r.top+2*my.bili);
if(r.top>=my.h)break;//敵人飛出屏幕 跳出循環
}
//從集合刪除
my.list.remove(this);
my.drlist.remove(this);
}
}
class myhj extends hj implements Runnable{//我的灰機
public myhj(){
w=h=200*my.bili;//凡是涉及到像素的 都乘一下分辨率比例my.bili
//設置初始位置
setX(my.w/2-w/2);
setY(my.h*0.7f-h/2);
img=my.myhj;//初始化圖片
my.list.add(this);//添加到集合裏 這樣才能被畫出來
new Thread(this).start();//發射子彈的線程
}
@Override
public void run() {
while(true){
//90毫秒發射一發子彈
try {Thread.sleep(90);} catch (InterruptedException e) {e.printStackTrace();}
new myzd(this);
}
}
}
class myzd extends hj implements Runnable{//我的子彈
private int dps;
private float sd0;
public myzd(hj hj){
w=h=90*my.bili;//凡是涉及到像素的 都乘一下分辨率比例my.bili
img=my.myzd;//圖片
sd0=6*my.bili;//速度=6
dps=6;//傷害=6
//設在玩家中心的偏上一點
setX(hj.r.left+hj.w/2-w/2);
setY(hj.r.top-h/2);
my.list.add(this);//添加到集合裏 這樣才能被畫出來
new Thread(this).start();//新建一個子彈向上移動的線程
}
@Override
public void run() {
boolean flag=false;//一個標記 用來跳出嵌套循環
while(true){
try {Thread.sleep(5);} catch (InterruptedException e) {e.printStackTrace();}
setY(r.top-sd0);//向上移sd0個像素,sd0=6
try {//try一下 怕出錯
//這裏判斷有沒有和集合裏的敵人發生碰撞
for(int i=0;i<my.drlist.size();i++){
hj h=my.drlist.get(i);
if(pengzhuang(h,30)){//判斷碰撞
h.hp-=dps;//敵人生命-子彈傷害
flag=true;//一個標記 用來跳出嵌套循環
my.js++;//擊殺+1
break;
}
}
} catch (Exception e) {
e.printStackTrace();
break;
}
if(flag || r.top+h<=0)break;//如果子彈擊中過敵人 或者超出屏幕範圍 跳出循環
}
my.list.remove(this);//從集合刪除
}
}
然後回到MainActivity.java
package com.dahuijii.liziguo;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.KeyEvent;
import android.widget.Toast;
public class MainActivity extends AppCompatActivity {
private long time;//用於檢測按兩次 "再按一次退出遊戲"
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
getSupportActionBar().hide();//隱藏標題欄
setContentView(new hua(this));
//setContentView()跟swing的add()差不多吧,不過這裏只能添加一個控件,默認鋪滿屏幕
}
public boolean onKeyDown(int keyCode,KeyEvent event) { //返回鍵
if (keyCode == KeyEvent.KEYCODE_BACK && event.getRepeatCount() == 0){
long t=System.currentTimeMillis();//獲取系統時間
if(t-time<=500){
exit(); //如果500毫秒內按下兩次返回鍵則退出遊戲
}else{
time=t;
Toast.makeText(getApplicationContext(),"再按一次退出遊戲",Toast.LENGTH_SHORT).show();
}
return true;
}
return false;
}
public void exit(){
MainActivity.this.finish();
new Thread(new Runnable(){
@Override
public void run() {
try {Thread.sleep(500);} catch (InterruptedException e) {e.printStackTrace();}
System.exit(0);
}
}).start();
}
}
把圖片添加到mipmap
bj.png 背景
dr.png 敵人
hj.png 我的灰機
zd.png 子彈
好了!大功告成!快試試吧!
下載地址:https://download.csdn.net/download/u010756046/10406656