小編最近想玩一下射擊類的空戰飛機遊戲,看到新手遊裡有幾款,索性下載玩了玩,真是感覺垃圾啊,滿屏的「首充」啊、「禮包」啊在晃蕩,如下圖:
這樣的遊戲品質和幕後公司啊,越操心玩家的錢包越賺不到錢,可能也就騙騙無知的小朋友充值吧。
以後沒有好網遊攻略的時候,超仔給大家陸續提供一些簡單的安卓手遊app開發入門教程,咱們今天就來個飛機小遊戲的製作吧。
工具還是AndroidStudio(超仔用的版本3.6.2),首先我們新建一個項目(Create Android Project或者Start a new Android Studio Project):
新建java類「guanqia1」,採用默認設置即可:
guanqia1.java代碼如下,大家複製就行:
package com.example.myplane;
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 chaozai on 2020/4/25.
*/
class my{//新建一個類 裡面的東西都是靜態的 當全局變量用
public static int js=0;//擊殺數
public static int w,h;//屏幕的寬高
public static float bili;//比例,用於適應不同屏幕
public static Vector
public static Vector
public static Bitmap myhj,drhj,bj,myzd;//圖片:我的飛機、敵人、背景、我的子彈
public static myhj my;//我的飛機
public static bj b;//背景
}
public class guanqia1 extends View{//畫
private Paint p=new Paint();//畫筆
private float x,y;//按下屏幕時的坐標
private float myx,myy;//按下屏幕時玩家飛機的坐標
public guanqia1(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.biyao1);//加載圖片
my.drhj=BitmapFactory.decodeResource(getResources(),R.mipmap.xueqi1);
my.myzd=BitmapFactory.decodeResource(getResources(),R.mipmap.shixuezhu1);
my.bj=BitmapFactory.decodeResource(getResources(), R.mipmap.backgroundp1);
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的比例
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();//刷新畫布
}
}
}
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.example.myplane;
import androidx.appcompat.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 guanqia1(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();
}
}
把用到的biyao1、xueqi1、shixuezhu1、backgroundp1等png圖片放入res下mipmap文件夾。
大功告成,build生成apk安卓安裝文件,用qq等傳至手機安裝就可以玩了。因為手邊正好有幾個遊戲圖片,就隨便選了幾個,app簡單就叫《碧瑤大戰陸雪琪》吧,主要就是我方飛機「碧瑤」發出嗜血珠打敵人陸雪琪,大家領會精神即可:
我們今天做的小遊戲一共涉及倆程序和幾個圖片,非常簡單也比較簡陋。以後感興趣的朋友可以加上技能、boss、關卡和動畫劇情等功能。
推薦大家以後可以採用SurfaceView(屬於View的子類),它是專門為製作遊戲而產生的,它的功能非常強大,最重要的是它支持OpenGL ES庫,2D和3D的效果都可以較好的實現。
<完>