使用Android完成案例教学

news2024/11/19 6:39:33

目录

题目:完成在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>

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

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

利用native的方式实现跨线程调用

简介 在OpenHarmony应用开发实践中&#xff0c;经常会遇到一些耗时的任务&#xff0c;如I/O操作、域名解析以及复杂计算等。这些任务如果直接在主线程中执行&#xff0c;将会严重阻塞主线程&#xff0c;影响后续任务的正常流程&#xff0c;进而导致用户界面响应延迟甚至卡顿。…

基于沙漏 Tokenizer 的高效三维人体姿态估计框架HoT

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 摘要Abstract文献阅读&#xff1a;基于沙漏 Tokenizer 的高效三维人体姿态估计框架HoT1、研究背景2、提出方法3、模块详细3.1、什么是HoT3.2、HoT 框架3.3、Token 剪…

JS 利用 webcam访问摄像头 上传到服务器

webcam JS 较为详细的指南 定义标题 <!doctype html> <html> <head><meta name"viewport" content"widthdevice-width, initial-scale1.0"><title>How to capture picture from webcam with Webcam.js</title></…

【UnityRPG游戏制作】Unity_RPG项目之界面面板分离和搭建

&#x1f468;‍&#x1f4bb;个人主页&#xff1a;元宇宙-秩沅 &#x1f468;‍&#x1f4bb; hallo 欢迎 点赞&#x1f44d; 收藏⭐ 留言&#x1f4dd; 加关注✅! &#x1f468;‍&#x1f4bb; 本文由 秩沅 原创 &#x1f468;‍&#x1f4bb; 收录于专栏&#xff1a;Uni…

计算机视觉——基于傅里叶幅度谱文档倾斜度检测与校正

概述 在计算机视觉领域&#xff0c;处理文档数据时&#xff0c;OCR算法的性能往往会受到文档的倾斜度影响。如果文档在输入到模型之前没有经过恰当的校正&#xff0c;模型就无法期待模型能够提供准确的预测结果&#xff0c;或者模型预测的精度会降低。例如&#xff0c;在信息提…

python上传以及下载AWS S3上的文件

​ 免死金牌 由于本人平常是做NodeJS开发的&#xff0c;本次做的任务含有 Scheduled Job &#xff0c;所以选择了使用Python作为这次开发的语言&#xff0c;毕竟跑脚本还是这玩意适合。 其中有一个任务是要从S3上拉下一些文件来处理&#xff0c;处理完成后再push 上去的需求…

深入浅出 -- 系统架构之负载均衡Nginx动静分离

一、Nginx动静分离 动静分离应该是听的次数较多的性能优化方案&#xff0c;那先思考一个问题&#xff1a;为什么需要做动静分离呢&#xff1f;它带来的好处是什么&#xff1f; 其实这个问题也并不难回答&#xff0c;当你搞懂了网站的本质后&#xff0c;自然就理解了动静分离的重…

【学习分享】小白写算法之选择排序篇

【学习分享】小白写算法之选择排序篇 前言一、什么是选择排序算法二、选择排序算法如何实现三、C语言实现算法四、复杂度计算五、算法稳定性六、小结 前言 简单排序有三种&#xff0c;冒泡排序&#xff0c;插入排序和选择排序。这三种排序的算法算是入门级别的&#xff0c;打好…

torchvision中的数据集使用

torchvision中的数据集使用 使用和下载CIFAR10数据集 输出测试集中的第一个元素&#xff08;输出img信息和target&#xff09; 查看分类classes 打断点–>右键Debug–>找到classes 代码 import torchvisiontrain_set torchvision.datasets.CIFAR10(root"./data…

显示学习1(基于树莓派Pico) -- 基础

先上图为敬。 驱动的是0.96寸的OLED&#xff0c;SSD1315。使用的I2C接口驱动。 有一说一树莓派Pico用来学习底层真的太好了&#xff0c;没有之一。首先是价格便宜&#xff0c;10块钱包邮还要什么自行车。然后底层封装很完备&#xff0c;接近闭源。最后是用的python&#xff0c…

4.2.k8s的pod-标签管理、镜像拉取策略、容器重启策略、资源限制、优雅终止

一、标签管理 1.标签在k8s中极其重要&#xff0c;大多数资源的相互关联就需要使用标签&#xff1b;也就是说&#xff0c;资源的相互关联大多数时候&#xff0c;是使用标签进行关联的&#xff1b; 2.其他作用&#xff0c;在k8s集群中&#xff0c;node节点的一些操作比如污点及污…

Python向带有SSL/TSL认证服务器发送网络请求小实践(附并发http请求实现asyncio+aiohttp)

1. 写在前面 最近工作中遇到这样的一个场景&#xff1a;给客户发送文件的时候&#xff0c;为保证整个过程中&#xff0c;文件不会被篡改&#xff0c;需要在发送文件之间&#xff0c; 对发送的文件进行签名&#xff0c; 而整个签名系统是另外一个团队做的&#xff0c; 提供了一…

c# wpf XmlDataProvider 简单试验

1.概要 2.代码 <Window x:Class"WpfApp2.Window12"xmlns"http://schemas.microsoft.com/winfx/2006/xaml/presentation"xmlns:x"http://schemas.microsoft.com/winfx/2006/xaml"xmlns:d"http://schemas.microsoft.com/expression/blend…

【一】学习TDengine-总结新技术学习的思考

学习TDengine-总结新技术学习的思考 概要 因业务场景需要我们开始接触时序数据库&#xff0c;于是开始根据以往的学习经验着手熟悉这一项新技术&#xff0c;学习也是一种技能&#xff0c;成功的人越容易成功&#xff0c;因为他们掌握了一套成功的方法&#xff0c;这里提到学习经…

Docker容器与虚拟化技术:OpenEuler 部署 Prometheus 与 Grafana

目录 一、实验 1.环境 2.OpenEuler 部署 Prometheus 3.OpenEuler 部署 Grafana 4.使用cpolar内网穿透 二、问题 1.拉取镜像失败 2.如何导入Grafana监控模板&#xff08;ES&#xff09; 一、实验 1.环境 &#xff08;1&#xff09;主机 表1 主机 系统架构版本IP备注…

机器学习(理论第一课)

一、理解人工智能、机器学习、深度学习、强化学习&#xff1f; 人工智能、机器学习和深度学习之间存在递进关系&#xff0c;它们的覆盖范围逐层递减。 **人工智能&#xff08;Artificial Intelligence&#xff0c;AI&#xff09;**是最宽泛的概念&#xff0c;旨在研究、开发用于…

第十四届蓝桥杯物联网试题(省赛)

这个题还是有点难度的&#xff0c;刚好能做完&#xff0c;还遇到一个意料之外的BUG,这次算是失败了&#xff0c;因为那个BUG让我以为是板子坏了其实是我LORA没初始化 储存信息用结构体存储 第一次写结构体能一次实验成功也挺开心的 值得赞扬的是我这样排版的好处是所有变量都在…

基于Whisper的实时语音识别(1): 流式显示视频帧和音频帧

Whistream &#xff08;微流&#xff09;是基于openai-whisper 大语音模型下的流式语音识别工具 本期主要介绍实时显示工具Whishow&#xff0c;可以实时逐帧显示视频流&#xff08;RTSP/RTMP&#xff09;和离线文件&#xff08;mp4,avi等&#xff09; 下载地址&#xff1a;ht…

复现chatgpt_ros,需要openapi key

&#xff11;&#xff0e; 前置工作&#xff1a; 现在&#xff55;buntu系统是20.04ros1&#xff0c;现在用docker新建并安装ros2&#xff1a; 最简单的&#xff0c;用大佬的一键安装&#xff1a; wget http://fishros.com/install -O fishros && . fishros 其次自己装…

深入浅出 -- 系统架构之负载均衡Nginx资源压缩

一、Nginx资源压缩 建立在动静分离的基础之上&#xff0c;如果一个静态资源的Size越小&#xff0c;那么自然传输速度会更快&#xff0c;同时也会更节省带宽&#xff0c;因此我们在部署项目时&#xff0c;也可以通过Nginx对于静态资源实现压缩传输&#xff0c;一方面可以节省带宽…