目录
题目:完成在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>
今天就分享到这里,感谢预览~