android studio飞机大战游戏带注释源码教程(多线程)[通俗易懂]

android studio飞机大战游戏带注释源码教程(多线程)[通俗易懂]第一次发博客,学了3天的androidstudio还有一点以前的java基础做了个飞机大战的游戏游戏比较简单大概就这几个功能1.会动的背景2.我的飞机3.发射子弹3.敌人飞机第一步新建一个项目我用的是Android4.4版本新建好项目之后xml文件之类的什么都不用管先新建个类叫做huahua.javapackagecom.dahuijii.liziguo;importandroid.c…

大家好,又见面了,我是你们的朋友全栈君。

第一次发博客,学了3天的android studio还有一点以前的java基础做了个基于多线程的飞机大战的游戏

不过,不建议这么做,游戏一般一个主线程控制所有对象

游戏比较简单大概就这几个功能

1.会动的背景

2.我的飞机

3.发射子弹

3.敌人飞机

第一步新建一个项目

android studio飞机大战游戏带注释源码教程(多线程)[通俗易懂]

我用的是Android4.4版本

android studio飞机大战游戏带注释源码教程(多线程)[通俗易懂]

android studio飞机大战游戏带注释源码教程(多线程)[通俗易懂]

android studio飞机大战游戏带注释源码教程(多线程)[通俗易懂]

新建好项目之后 xml文件之类的什么都不用管

先新建个类

android studio飞机大战游戏带注释源码教程(多线程)[通俗易懂]

叫做hua

android studio飞机大战游戏带注释源码教程(多线程)[通俗易懂]

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 子弹

android studio飞机大战游戏带注释源码教程(多线程)[通俗易懂]

好了!大功告成!快试试吧!

android studio飞机大战游戏带注释源码教程(多线程)[通俗易懂]

下载地址:https://download.csdn.net/download/u010756046/10406656

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

发布者:全栈程序员-用户IM,转载请注明出处:https://javaforall.cn/130591.html原文链接:https://javaforall.cn

【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛

【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...

(2)
blank

相关推荐

  • pytest指定用例_pytest如何循环执行用例

    pytest指定用例_pytest如何循环执行用例前言测试用例在设计的时候,我们一般要求不要有先后顺序,用例是可以打乱了执行的,这样才能达到测试的效果.有些同学在写用例的时候,用例写了先后顺序,有先后顺序后,后面还会有新的问题(如:上个用例返回

  • 太原智慧小区有哪些_智慧城市规划

    太原智慧小区有哪些_智慧城市规划经过3个月的紧张施工,至7月初,位于龙城大街的“首开·国风上观”小区成为我市首个实现电、水、热采集“多表合一”的智能化小区。记者从国网太原供电公司了解到,该试点小区住户达3524户,是目前国内“多表合一”改造试点中规模较大的,也是我省试点中规模最大的小区。今年,国家发改委、国家能源局、工信部曾联合出台《关于推进“互联网+”智慧能源发展的指导意见》,其中…

  • sigaction函数解析

    sigaction函数解析sigaction函数的功能是检查或修改与指定信号相关联的处理动作(可同时两种操作)。他是POSIX的信号接口,而signal()是标准C的信号接口(如果程序必须在非POSIX系统上运行,那么就应该使用这个接口)给信号signum设置新的信号处理函数act,同时保留该信号原有的信号处理函数oldactint sigaction(int signo,

  • python进入文件目录 命令_python创建目录

    python进入文件目录 命令_python创建目录python进入到指定目录下的方法:Python可以使用os.chdir()方法转到指定目录。os.chdir()方法用于改变当前工作目录到指定的路径。chdir()方法语法格式如下:os.chdir(path)参数path–要切换到的新路径。实例以下实例演示了chdir()方法的使用:#!/usr/bin/python#-*-coding:UTF-8-*-importos,…

  • 级联下拉菜单的实现「建议收藏」

    级联下拉菜单的实现「建议收藏」级联下拉菜单的实现

  • 在线视频下载网址合集

    在线视频下载网址合集视频鱼:http://m.shipinyu.cn/微博党:http://weibodang.cn/index硕鼠:http://www.flvcd.com/微博秒拍视频解析下载:https://weibo.iiilab.com/短视频解析下载:http://dy.ck921.com/飞狐视频下载:https://www.3987.com/dsp/ks.html兔兔解析:http://w…

发表回复

您的电子邮箱地址不会被公开。

关注全栈程序员社区公众号