使用Android完成案例教学

目录

题目:完成在Android平台下2个玩家分别利用2个手机连接在同一局域网下通过滑动摇杆分别使红飞机和黄飞机移动的开发。(全代码解析)


题目:完成在Android平台下2个玩家分别利用2个手机连接在同一局域网下通过滑动摇杆分别使红飞机和黄飞机移动的开发。(全代码解析)

用一个真机运行,连接此电脑 的模拟机进行利用2个手机连接在同一局域网下通过滑动摇杆分别使红飞机和黄飞机移动的开发

运行结果: 

模拟机:

真机:

DrawThread.java代码:
package com.example.client.thread;

import com.example.clinet.view.GameView;

import android.annotation.SuppressLint;
import android.graphics.Canvas;
import android.view.SurfaceHolder;

public class DrawThread extends Thread
{
    private int SLEEP_SPAN =50;//睡眠的毫秒数
    private SurfaceHolder surfaceHolder;
    private GameView view;
    private boolean flag = true;
    public DrawThread(SurfaceHolder surfaceHolder, GameView view) {//构造器
        this.surfaceHolder = surfaceHolder;
        this.view = view;
    }
    public void setFlag(boolean flag) {//设置循环标记位
        this.flag = flag;
    }
    @SuppressLint("WrongCall")
    public void run()
    {
        Canvas c;
        while(flag)
        {
            c = null;
            try
            {// 锁定整个画布,在内存要求比较高的情况下,建议参数不要为null
                c = this.surfaceHolder.lockCanvas(null);
                synchronized (this.surfaceHolder)
                {
                    this.view.onDraw(c);
                }
            } finally
            {
                if (c != null)
                {
                    //更新屏幕显示内容
                    this.surfaceHolder.unlockCanvasAndPost(c);
                }
            }
            try
            {
                Thread.sleep(SLEEP_SPAN);//睡眠指定毫秒数
            }
            catch(Exception e)
            {
                e.printStackTrace();
            }
        }
    }
}

KeyThread.java代码:
package com.example.client.thread;

import com.example.client.MainActivity;
import com.example.util.GameData;


public class KeyThread extends Thread
{
	int SPAN_SLEEP=10;
	MainActivity father;
	boolean flag=true;

	public KeyThread(MainActivity father)
	{
		this.father=father;
	}

	public void run()
	{
		while(flag)
		{

			try
			{
				if(GameData.state==2)
				{
					father.nt.dout.writeUTF("<#KEY#>"+father.KeyDispX+"|"+father.KeyDispY);
				}
				Thread.sleep(SPAN_SLEEP);

			}
			catch(Exception e)
			{
				e.printStackTrace();
			}
		}
	}
}
更改自己电脑上的IP地址,win+R输入cmd,然后输入ipconfig命令获取此电脑的IP地址,NetworkThread.java代码如下:
package com.example.client.thread;

import android.util.Log;

import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.net.Socket;
import com.example.client.MainActivity;
import com.example.util.GameData;

public class NetworkThread extends Thread{
	MainActivity activity;
	Socket sc;
	DataInputStream din;
	DataOutputStream dout;
	public boolean flag=true;
	public NetworkThread(MainActivity activity)
	{
		this.activity=activity;
	}
	public void run()
	{
		try
		{//与服务端建立连接 ,参数分别是要连接的服务端IP地址和要连接的服务端对应的监听端口
			Log.i("测试", "run: 开始连接");
			sc=new Socket("192.168.43.252",9999);
			din=new DataInputStream(sc.getInputStream());
			dout=new DataOutputStream(sc.getOutputStream());
			dout.writeUTF("<#CONNECT#>");
			Log.i("测试", "run: 完成连接");
		}
		catch(Exception e)
		{
			Log.e("测试", "run: 执行失败",e );
			e.printStackTrace();
			return;
		}
		while(flag)
		{
			try
			{
				String msg=din.readUTF();
				if(msg.startsWith("<#OK#>"))
				{
					System.out.println("Connect ok...");
					GameData.state=1;
				}
				else if(msg.startsWith("<#BEGIN#>"))
				{
					GameData.state=2;
					this.activity.kt.start();
				}
				else if(msg.startsWith("<#FULL#>"))
				{
					System.out.println("Full...");
					break;
				}
				else if(msg.startsWith("<#GAME_DATA#>"))
				{
					String nr=msg.substring(13);
					String[] strA=nr.split("\\|");
					int temprx=Integer.parseInt(strA[0]);
					int tempry=Integer.parseInt(strA[1]);
					int tempgx=Integer.parseInt(strA[2]);
					int tempgy=Integer.parseInt(strA[3]);
					synchronized(this.activity.gd.lock)
					{
						this.activity.gd.rx=temprx;
						this.activity.gd.ry=tempry;
						this.activity.gd.gx=tempgx;
						this.activity.gd.gy=tempgy;
					}
				}
			}catch(Exception e)
			{
				e.printStackTrace();
			}
		}

		try
		{
			din.close();
			dout.close();
			sc.close();
		}catch(Exception e)
		{
			e.printStackTrace();
		}
	}
}

MainActivity.Java代码:
package com.example.client;

import com.example.client.thread.KeyThread;
import com.example.client.thread.NetworkThread;
import com.example.clinet.view.GameView;
import com.example.util.GameData;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuItem;
import android.app.Activity;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;

public class MainActivity extends Activity {
	public int KeyDispX=0;//方向x
	public int KeyDispY=0;//方向y

	public Bitmap planer;
	public Bitmap planeg;
	public GameData gd=new GameData();
	public KeyThread kt=new KeyThread(this);
	public 	NetworkThread nt;
	GameView gv;



	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.main);

		planer=BitmapFactory.decodeResource(getResources(), R.drawable.red);//红飞机
		planeg=BitmapFactory.decodeResource(getResources(), R.drawable.yellow);//黄飞机

		gv=(GameView)this.findViewById(R.id.mf1);
	}

	@Override
	public boolean onCreateOptionsMenu(Menu menu)
	{
		//调用Activity的getMenuInflater()得到一个MenuInflater,
		//使用inflate方法来把布局文件中的定义的菜单 加载给 第二个参数所对应的menu对象

		getMenuInflater().inflate(R.menu.activity_main, menu);
		return true;
	}
	@Override
	public boolean onOptionsItemSelected(MenuItem item) {
		if(item.getItemId()==R.id.menu_connect)
		{
			if(this.nt==null)
			{
				this.nt=new NetworkThread(MainActivity.this);
				this.nt.start();
			}


		}
		return true;
	}
}
ServerAgentThread.java代码如下:
package com.example.util;

import java.io.*;
import java.net.*;
import java.util.*;

public class ServerAgentThread extends Thread
{
	//�ͻ��˼�����
	static int count=0;
	//�ͻ����б�
	static List<ServerAgentThread> ulist=new ArrayList<ServerAgentThread>();
	//ȫ������
	static int rx=150;
	static int ry=750;
	static int gx=460;
	static int gy=750;
	//��������
	static Queue<Action> aq=new LinkedList<Action>();
	//����������
	static Object lock=new Object();
	
	Socket sc;
	DataInputStream din;
	DataOutputStream dout;
	int redOrYellow;
	boolean flag=true;
	
	public static void broadcastState()
	{
		for(ServerAgentThread sa:ulist)
		{
			try
			{
				sa.dout.writeUTF("<#GAME_DATA#>"+rx+"|"+ry+"|"+gx+"|"+gy);
			}
			catch(Exception e)
			{
				e.printStackTrace();
			}
		}
	}
	
	public ServerAgentThread(Socket sc)
	{
		this.sc=sc;
		try
		{
			din=new DataInputStream(sc.getInputStream());
			dout=new DataOutputStream(sc.getOutputStream());
		}
		catch(Exception e)
		{
			e.printStackTrace();
		}
	}
	
	public void run()
	{
		while(flag)
		{
			try
			{
				String msg=din.readUTF();
				if(msg.startsWith("<#CONNECT#>"))
				{
					if(count==0)
					{
						dout.writeUTF("<#OK#>");
						redOrYellow=0;
						ulist.add(this);
						count++;
						System.out.println("==red connect...");
//						for(ServerAgentThread sa:ulist)
//						{
//							sa.dout.writeUTF("<#BEGIN#>");
//						}
					}
					else if(count==1)
					{
						dout.writeUTF("<#OK#>");
						redOrYellow=1;
						ulist.add(this);
						count++;
						System.out.println("==yellow connect...");
						
						for(ServerAgentThread sa:ulist)
						{
							sa.dout.writeUTF("<#BEGIN#>");
						}
					}
					else
					{
						dout.writeUTF("<#FULL#>");
						break;
					}
				}
				else if(msg.startsWith("<#KEY#>"))
				{
					String iStr=msg.substring(7);
					String[] str=iStr.split("\\|");
					synchronized(lock)
					{//���¶����������
						aq.offer(new Action(this.redOrYellow,Integer.parseInt(str[0]),Integer.parseInt(str[1])));
					}
				}
			}
			catch(Exception e)
			{
				e.printStackTrace();
			}
		}
		try
		{
			din.close();
			dout.close();
			sc.close();
		}
		catch(Exception e)
		{
			e.printStackTrace();
		}
	}
}
Joystick.java代码:
package com.example.util;

import com.example.client.MainActivity;
import com.example.client.R;
import com.example.clinet.view.GameView;

import static com.example.util.Constant.*;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;

public class Joystick
{
	public MainActivity activity;
	public GameView view;
	public int length;
	public float x;
	public float y;
	public Joystick( GameView view,MainActivity activity,float x,float y)
	{
		this.view=view;
		this.activity=activity;
		this.x=x;
		this.y=y;
	}

	public void drawJoystick(Canvas canvas)
	{
		canvas.drawBitmap(BitmapFactory.decodeResource(this.activity.getResources(),R.drawable.yaogan1),
				JK_Start_x,JK_Start_y, null);
		canvas.drawBitmap(BitmapFactory.decodeResource(this.activity.getResources(),R.drawable.yaogan2),
				x,y,null);
	}


	public boolean change(float x,float y)
	{
		length=getLength(this.view.pCenter.x,this.view.pCenter.y, x,y);
		if(length>radio)
		{//如果手指触点不在大环范围内
			return false;
		}
		else if(length<radio)
		{ //如果手指在摇杆活动范围内,则摇杆处于手指触摸位置
			this.view.mJoystick.x=x;
			this.view.mJoystick.y=y;
		}
		else
		{//设置摇杆位置,使其处于手指触摸方向的 摇杆活动范围边缘
			float angle=getRadian(this.view.pCenter.x,this.view.pCenter.y, x, y);
			this.view.mJoystick.x=(int)(this.view.pCenter.x+radio* Math.cos(angle));
			this.view.mJoystick.y=(int)(this.view.pCenter.y+radio*Math.sin(angle));
		}
		//方向
		this.activity.KeyDispX=(int) (x-this.view.pCenter.x);//x偏移量
		this.activity.KeyDispY=(int) (y-this.view.pCenter.y);//y偏移量
		return true;
	}
}

 Action.java代码:

package com.example.util;

public class Action 
{
	int redOrYellow;//0-red 1-green	
	float keyX;
	float keyY;
	int span=20;//�ƶ�����
	
	public Action(int redOrYellow,float keyX,float keyY)
	{
		this.redOrYellow=redOrYellow;
		this.keyX=keyX;
		this.keyY=keyY;
	}
	
	public void doAction()
	{		
		float xx=0;
		float yy=0;
		if(Math.sqrt(keyX*keyX+keyY*keyY)!=0)
		{//ת��Ϊ��λ����ֵ
			xx= (float) (keyX/Math.sqrt(keyX*keyX+keyY*keyY));
			yy=(float) (keyY/Math.sqrt(keyX*keyX+keyY*keyY));
		}
		if(redOrYellow==0)
		{//��
			if(ServerAgentThread.ry+yy*span>=0&&ServerAgentThread.ry+yy*span<=1100)
			{//���÷ɻ��ƶ���Χ
				ServerAgentThread.ry+=yy*span;
			}			
			if(ServerAgentThread.rx+xx*span>=0&&ServerAgentThread.rx+xx*span<=600)
			{
				ServerAgentThread.rx+=xx*span;
			}
		}
		else
		{//��
			if(ServerAgentThread.gy+yy*span>=0&&ServerAgentThread.gy+yy*span<=1100)
			{//���÷ɻ��ƶ���Χ
				ServerAgentThread.gy+=yy*span;
			}		
			if(ServerAgentThread.gx+xx*span>=0&&ServerAgentThread.gx+xx*span<=600)
			{
				ServerAgentThread.gx+=xx*span;
			}
		}
		
	}
}
ActionThread.java代码:
package com.example.util;

public class ActionThread extends Thread
{
	static final int SLEEP=5;
	boolean flag=true;
		
	public void run()
	{
		while(flag)
		{
			Action a=null;
			
			synchronized(ServerAgentThread.lock)
			{
				//��ȡ���Ƴ�����Ԫ��
				a=ServerAgentThread.aq.poll();
			}
			if(a!=null)
			{
				a.doAction();
				ServerAgentThread.broadcastState();	
			}
			else
			{
				try
				{
					Thread.sleep(SLEEP);
				}
				catch(Exception e)
				{
					e.printStackTrace();
				}
			}
		}
	}
}
Constant.java代码:
package com.example.util;

public class Constant {

	public static final int radio=80;//半径
	public static final int JK_Start_x=30;//摇杆大环起点x
	public static final int JK_Start_y=830;//摇杆大环起点y
	public static final int  xJoystick=100;//摇杆小环x
	public static final int  yJoystick=900;//摇杆小环y


	//获取水平线夹角弧度
	public static float getRadian (float x1,float y1,float x2,float y2)
	{
		float lenA=x2-x1;
		float lenB=y2-y1;
		float lenC=(float) Math.sqrt(lenA*lenA+lenB*lenB);
		float angle=(float)Math.acos(lenA/lenC);
		angle=angle*(y2<y1?-1:1);
		return angle;
	}

	//获取长度
	public static int getLength(float centerX,float centerY,float x,float y)
	{
		int result=(int)Math.sqrt(Math.pow(x-centerX, 2)+Math.pow(y-centerY, 2));
		return result;
	}
}

GameData.java代码;
package com.example.util;

public class GameData {
	public static int state=0;//0--未连接  1---成功连接  2--游戏开始

	public Object lock=new Object();

	public int rx=150;
	public int ry=750;
	public int gx=460;
	public int gy=750;
}
启动ServerThread.java代码:
package com.example.util;
import java.net.*;

public class ServerThread extends Thread
{
	boolean flag=false;
	ServerSocket ss;
	
	public void run()
	{
		try
		{
			ss=new ServerSocket(9999);
			System.out.println("Server Listening on 9999...");
			flag=true;
			new ActionThread().start();
		}
		catch(Exception e)
		{
			e.printStackTrace();
		}
		
		while(flag)
		{
			try
			{
				Socket sc=ss.accept();
				System.out.println(sc.getInetAddress()+" connect...");
				new ServerAgentThread(sc).start();
			}
			catch(Exception e)
			{
				e.printStackTrace();
			}
		}
	}
	
	public static void main(String args[])
	{
		new ServerThread().start();
	}
}

 main.xml代码如下:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical" >
    <com.example.clinet.view.GameView
        android:id="@+id/mf1"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        />

</LinearLayout>

 今天就分享到这里,感谢预览~

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/521358.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Open CASCADE学习|旋转变换

物体在三维空间中的旋转变换操作通常可以通过三种不同的方式来表示&#xff1a;矩阵&#xff08;Matrix&#xff09;、欧拉角&#xff08;Euler Angles&#xff09;和四元数&#xff08;Quaternion&#xff09;。下面详细解释这三种表示方法。 矩阵&#xff08;Matrix&#xf…

【51单片机入门记录】RTC(实时时钟)-DS1302应用

目录 一、DS1302相关写函数 &#xff08;1&#xff09;Write&#xff3f;Ds1302 &#xff08;2&#xff09;Write&#xff3f;Ds1302&#xff3f;Byte 二、DS130相关数据操作流程及相关代码 &#xff08;1&#xff09;DS1302初始化数据操作流程及相关代码 (shijian[i]/10&…

【学习分享】小白写算法之插入排序篇

【学习分享】小白写算法之插入排序篇 前言一、什么是插入排序算法二、插入排序算法如何实现三、C语言实现算法四、复杂度计算五、算法稳定性六、小结 前言 要学好每个算法&#xff0c;我觉得需要先总结出规律&#xff0c;然后自己去推演一遍&#xff0c;加深记忆&#xff0c;否…

阿里云8核32G云服务器租用优惠价格表,包括腾讯云和京东云

8核32G云服务器租用优惠价格表&#xff0c;云服务器吧yunfuwuqiba.com整理阿里云8核32G服务器、腾讯云8核32G和京东云8C32G云主机配置报价&#xff0c;腾讯云和京东云是轻量应用服务器&#xff0c;阿里云是云服务器ECS&#xff1a; 阿里云8核32G服务器 阿里云8核32G服务器价格…

【记录】LangChain|llama 2速通版

官方教程非常长&#xff0c;我看了很认可&#xff0c;但是看完了之后呢就需要一些整理得当的笔记让我自己能更快地找到需求。所以有了这篇文章。【写给自己看的&#xff0c;里面半句废话的解释都没有&#xff0c;如果看不懂的话直接看官方教程再看我的】 我是不打算一开始就用…

Jenkins (四) - 搭建 Docker SonarQube

Jenkins (四) - 搭建 Docker SonarQube 拉取 SonarQube $ docker pull sonarqube拉取 postgres $ $ docker pull postgres运行 postgres $ docker run -itd \ -e TZAsia/Shanghai -e POSTGRES_USERtester \ -e POSTGRES_PASSWORD123456 \ -p 5432:5432 \ -v /home/tester/d…

京东云服务器4核8G主机租用价格418元一年,1899元3年

京东云轻量云主机4核8G服务器租用价格418元一年&#xff0c;1899元3年&#xff0c;配置为&#xff1a;轻量云主机4C8G-180G SSD系统盘-5M带宽-500G月流量&#xff0c;京东云主机优惠活动 yunfuwuqiba.com/go/jd 可以查看京东云服务器详细配置和精准报价单&#xff0c;活动打开如…

【mac操作】brew指令集

brew指令集记录 1. brew search 【软件名称】2. rm -rf $(brew --cache)3. brew install 【软件名】4. brew uninstall 【软件名】5. 未完待续&#xff0c;&#xff0c;&#xff0c;&#xff0c; 官网路径&#xff1a; Homebrew官网 最上面就来一个homebrew安装指令吧&#xf…

win10上一个详细的Django开发入门例子

1.Django概述 Django是一个开放源代码的Web应用框架&#xff0c;由Python写成。采用了MTV的框架模式&#xff0c;即模型M&#xff0c;视图V和模版T。 Django 框架的核心组件有&#xff1a; 用于创建模型的对象关系映射&#xff1b; 为最终用户设计较好的管理界面&#xff1b…

阿里云倚天云服务器详解_CPU采用倚天710处理器

阿里云倚天云服务器CPU采用倚天710处理器&#xff0c;租用倚天服务器c8y、g8y和r8y可以享受优惠价格&#xff0c;阿里云服务器网aliyunfuwuqi.com整理倚天云服务器详细介绍、倚天710处理器性能测评、CIPU架构优势、倚天服务器使用场景及生态支持&#xff1a; 阿里云倚天云服务…

c# wpf LiveCharts MVVM绑定 简单试验

1.概要 c# wpf LiveCharts MVVM绑定 简单试验 2.代码 <Window x:Class"WpfApp3.Window3"xmlns"http://schemas.microsoft.com/winfx/2006/xaml/presentation"xmlns:x"http://schemas.microsoft.com/winfx/2006/xaml"xmlns:d"http://s…

gitea简单介绍

Gitea是一个轻量级的开源自托管Git服务&#xff0c;提供了类似GitHub的功能和界面。它是一个简单、易于安装和使用的Git代码托管解决方案&#xff0c;适用于个人、小型团队和企业。 Gitea的主要特点如下&#xff1a; 自托管&#xff1a;Gitea允许在自己的服务器上搭建和管理…

web安全学习笔记(6)

记一下第十节课的内容。 一.PHP语言中的if else判断 语法和c语言中非常类似&#xff0c;不再赘述&#xff0c;也可以使用if...elseif...elseif...else 1.True和False 2.&#xff0c;和 一个等号是赋值 两个等号是比较 三个等号是全等&#xff08;内容相等&#xff0c;数…

调用阿里云API接口实现电商领域命名实体识别NER

文章目录 阿里云简介命名实体识别NER阿里云API注册调用代码阿里云简介 阿里云是全球领先的云计算及人工智能科技公司,成立于2009年,为200多个国家和地区的企业、开发者和政府机构提供服务。阿里云提供了一系列的云计算服务,包括服务器租赁、云数据库、云存储、人工智能等,…

pytest的时候输出一个F后面跟很多绿色的点解读

使用pytest来测试pyramid和kotti项目&#xff0c;在kotti项目测试的时候&#xff0c;输出一个F后面跟很多绿色的点&#xff0c;是什么意思呢&#xff1f; 原来在使用pytest进行测试时&#xff0c;输出中的“F”代表一个失败的测试&#xff08;Failed&#xff09;&#xff0c;而…

自动驾驶中的交通标志识别原理及应用

自动驾驶中的交通标志识别原理及应用 附赠自动驾驶学习资料和量产经验&#xff1a;链接 概述 道路交通标志和标线时引导道路使用者有秩序使用道路&#xff0c;以促进道路行车安全&#xff0c;而在驾驶辅助系统中对交通标志的识别则可以不间断的为整车控制提供相应的帮助。比如…

Yalmip使用教程(7)-求解器的参数设置

博客中所有内容均来源于自己学习过程中积累的经验以及对yalmip官方文档的翻译&#xff1a;https://yalmip.github.io/tutorials/ 这篇博客将详细介绍yalmip工具箱中常用的求解器设置选项。 1.求解器的基本设置 使用sdpsettings函数可以对求解的相关参数进行设置。最常用的设置…

【操作系统】STM32-操作系统——持续更新

【操作系统】STM32-操作系统——持续更新 文章目录 前言一、ucosii二、freertos1.介绍2.移植 总结 前言 提示&#xff1a;以下是本篇文章正文内容&#xff0c;下面案例可供参考 一、ucosii UCOSII移植到STM32F103C8T6上之移植记录&#xff08;一&#xff09; UCOSII移植到ST…

京东云16核64G云服务器租用优惠价格500元1个月、5168元一年,35M带宽

京东云16核64G云服务器租用优惠价格500元1个月、5168元一年&#xff0c;35M带宽&#xff0c;配置为&#xff1a;16C64G-450G SSD系统盘-35M带宽-8000G月流量 华北-北京&#xff0c;京东云活动页面 yunfuwuqiba.com/go/jd 活动链接打开如下图&#xff1a; 京东云16核64G云服务器…

通用爬虫的概念简述

一、&#x1f308;什么是通用爬虫 通用爬虫&#xff08;General Purpose Web Crawler或Scalable Web Crawler&#xff09;是一种网络爬虫&#xff0c;其设计目标是对整个互联网或尽可能广泛的网络空间进行数据抓取。通用爬虫主要用于搜索引擎构建其庞大的网页索引数据库&#…