源代码:点此下载

这篇博客是我上一篇博客的延续,之所以还要写这篇博客,是希望给大家一些灵感,写一些有趣的东西出来。

上篇博客:android遥控器:控制电脑上的暴风影音播放(C#作为服务端)

首先讲一下手机和电脑的互联:

1,家里有无线网路由器的话,直接将手机介入无线网就可以了。

2,只有手机和笔记本的话,可以打开android的wifi热点。设置-无线和网络-绑定与便携式热点,打开便携式热点。然后用笔记本连接。这里要注意一下,笔记本自动获取ip的话,就可以通过android上网了,想阻止笔记本联网(省流量),可以看下笔记本自动获取到的ip和掩码,然后将ip改为手动设置,填入刚才自动获取的ip和掩码,注意千万不要设置网关和dns,不然你就等着流量耗完泪奔吧。

实现思路:

手机和笔记本使用无线网连接,手机向笔记本上的C#服务端发送控制消息,C#服务端再模拟键盘消息,从而控制了极品飞车。

不过这里不在使用postmessage,而是使用keybd_event(),因为keybd_event()控制键盘比较方便,而且飞车游戏是全屏幕运行的,所以不需要像控制暴风影音一样,在非顶端窗口也要能接收到消息。keybd_event()就是直接模拟键盘消息,而不是向某一个进程发送键盘消息。因此哪个程序获得焦点,keybd_event()模拟的键盘消息就发送给哪个。关于keybd_event()的使用方法,参考:这里

程序使用了两个端口,一个是12121,是手机按钮发送的消息。还有一个是12122,是重力感应发送的消息。

实现功能:

手机左右旋转控制×××左右方向,同时手机屏幕强制全屏横屏显示,程序界面上有加速,倒退,刹车等按钮。关于重力感应x,y,z三轴的说明,参考:这里。这里我只是监控了y轴,当把手机横着放时,y轴的值为0,向左倾斜时,值为负数,向右倾斜时,值为正数。当然,考虑到实际情况,当×××要保持向前移动时,你的手机也不可能是完全水平放置的,所以这里我设了一个范围,值为-2.5到2.5之间,就可以视为水平放置。

我程序里使用的是Sensor.TYPE_ACCELEROMETER传感器,大家可以根据自己手机的实际情况,作相应的更改。

程序相关代码:

C#服务端控制键盘
      [DllImport("user32.dll")] 
  
 static extern void keybd_event(byte bVk, byte bScan, uint dwFlags, uint dwExtraInfo); 
  

 [DllImport("user32.dll")] 
  
 static extern byte MapVirtualKey(byte wCode, int wMap); 
  

 /// <summary> 
  
 ///left down 
  
 /// </summary> 
  
 public void LeftDown() 
  
 { 
  
 keybd_event(0x25, MapVirtualKey(0x25, 0), 0, 0); 
  
 } 
  

 /// <summary> 
  
 /// left up 
  
 /// </summary> 
  
 public void LeftUp() 
  
 { 
  
 keybd_event(0x25, MapVirtualKey(0x25, 0), 0x2, 0); 
  
 }



复制代码

上面代码中:LeftDown()方法发送了一个按住方向左键的消息,这里这个消息只要发送一个,极品飞车就会一直向左拐弯,直到收到松开左键的消息LeftUp(),因此在用重力感应控制方向的时候要判断上次按下的键盘。例如:现在收到按下左键的消息,首先要判断当前的状态,如果当前已经为按下左键了,就可以忽略这个消息,如果上次是按下右键,就要先发送松开右键的消息,然后再发送按下左键。下面的静态类实现了这个判断:

public static class CarState 
  
 { 
  
 private static double lastNum = 0; 
  
 private static double maxNum = 2.5;  //保持水平的最小值。 
  
 private static double minNum = -2.5;  //保持水平的最大值 
  

 public static string Change(double num) 
  
 { 
  
 string str = null; 
  

 if (num > maxNum) //向右 
  
 { 
  
 if (lastNum <maxNum) //如果上次是向左的,就返回向右的消息,否则不用发送,因为已经向右了。 
  
 str= "ridn";  //ridn 就是right down的缩写,其它同此。 
  
 } 
  
 else if (num < minNum) //向左 
  
 { 
  
 if (lastNum > minNum) 
  
 str = "ledn"; 
  
 } 
  
 else if (num > minNum && num < maxNum) //向前 
  
 { 
  
 if(lastNum>maxNum||lastNum<minNum) 
  
 str = "notg"; //nothing 
  
 } 
  
 lastNum = num; 
  
 return str; 
  
 } 
  
 }


复制代码

C#监听端口:
View Code  class NetControl   
 {   
 SendMsg sendMsg = new SendMsg();   
 TextBox textBox1;   
 TextBox textBox2;   

 public NetControl(TextBox tmpTextBox1, TextBox tmpTextBox2)   
 {   
 textBox1 = tmpTextBox1;   
 textBox2 = tmpTextBox2;   
 }   

 /// <summary>   
 /// 开始监听   
 /// </summary>   
 public void BeginListen()   
 {   
 Thread listenOneThread = new Thread(new ThreadStart(ListenOne));   
 listenOneThread.Start();   
 Thread listenTwoThread = new Thread(new ThreadStart(ListenTwo));   
 listenTwoThread.Start();   
 }   

 /// <summary>   
 /// 监听android按钮发送的消息   
 /// </summary>   
 private void ListenOne()   
 {   
 Thread.CurrentThread.IsBackground = true;   
 TcpListener server = new TcpListener(IPAddress.Any, 12121);   
 server.Start();   
 while (true)   
 {   
 TcpClient client = server.AcceptTcpClient();   
 client.NoDelay = true;   
 Thread clientThread = new Thread(new ParameterizedThreadStart(receiveMsg));   
 clientThread.Start(client);   
 }   
 }   

 /// <summary>   
 /// 监听android重力感应发送的消息   
 /// </summary>   
 private void ListenTwo()   
 {   
 Thread.CurrentThread.IsBackground = true;   
 TcpListener server = new TcpListener(IPAddress.Any, 12122);   
 server.Start();   
 while (true)   
 {   
 TcpClient client = server.AcceptTcpClient();   
 client.NoDelay = true;   
 Thread clientThread = new Thread(new ParameterizedThreadStart(receiveMsg));   
 clientThread.Start(client);   
 }   
 }   

 /// <summary>   
 /// 服务器侦听   
 /// </summary>   
 /// <param name="result"></param>   
 private void receiveMsg(Object obj)   
 {   
 Thread.CurrentThread.IsBackground = true;   
 Control.CheckForIllegalCrossThreadCalls = false;   
 Thread.CurrentThread.IsBackground = true;   
 textBox1.Text += "\r\nconnect!";   
 using (TcpClient client =(TcpClient)obj)   
 {   
 using (NetworkStream stream = client.GetStream())   
 {   
 int dataLength = 0;   
 string str;   
 string msg;   
 do   
 {   
 byte[] buffer = new byte[32];   
 dataLength = stream.Read(buffer, 0, buffer.Length);   
 str = Encoding.ASCII.GetString(buffer, 0, dataLength);   
 msg = Encoding.ASCII.GetString(buffer);   
 sendMessage(msg);   
 textBox1.Text += "\r\n" + msg;   
 } while (dataLength!=0);   
 }   
 }   
 }   

 /// <summary>   
 /// 根据收到信息,使用不同的功能   
 /// </summary>   
 private void sendMessage(string msg)   
 {   
 msg=msg.Substring(0,4);   
 switch (msg)   
 {   
 case "riup": //riup就是right up的缩写,意思是按下方向右键,其它同此。   
 sendMsg.RightUp();   
 break;   
 case "dndn":   
 sendMsg.DownDown();   
 break;   
 case "dnup":   
 sendMsg.DownUp();   
 break;   
 case "upup":   
 sendMsg.UpUp();   
 break;   
 case "updn":   
 sendMsg.UpDown();   
 break;   
 case "sfup":   
 sendMsg.ShiftUp();   
 break;   
 case "sfdn":   
 sendMsg.ShiftDown();   
 break;   
 case "spup":   
 sendMsg.SpaceUp();   
 break;   
 case "spdn":   
 sendMsg.SpaceDown();   
 break;   
 default://接收到数字,就是重力感应发送过来的y轴的值。   
 double num = -1;   
 double.TryParse(msg, out num);   
 textBox2.Text +="\r\n"+ num.ToString();   
 if (num != -1)   
 {   
 string ctl = CarState.Change(num);   
 switch (ctl)   
 {   
 case "ledn":   
 textBox2.Text += "left";   
 sendMsg.RightUp();   
 sendMsg.LeftDown();   
 break;   
 case "ridn":   
 textBox2.Text += "right";   
 sendMsg.LeftUp();   
 sendMsg.RightDown();   
 break;   
 case "notg": //notg :nothing   
 textBox2.Text += "notg";   
 sendMsg.LeftUp();   
 sendMsg.RightUp();   
 break;   
 }   
 }   
 break;   
 }   
 }   
 }


android连接C#服务端:

View Code  package com.android.baofengControl;   

import java.io.BufferedWriter;   
import java.io.IOException;   
import java.io.OutputStreamWriter;   
import java.io.PrintWriter;   
import java.net.InetAddress;   
import java.net.Socket;   
import java.net.UnknownHostException;   

import android.R.bool;   
import android.content.Context;   
import android.widget.TextView;   

public class Client {   
 Socket client;   
 PrintWriter out;   
 TextView txt;   
 Context context;   
 int port;   

 public Client(int _port)   
 {   
 port=_port;   
 }   

 public Client(TextView txt,int _port)   
 {   
 this.txt=txt;   
 port=_port;   
 }   

 ///建立连接,并保持   
 public void connectServer(String ip)   
 {   
 InetAddress serverAddress = null;   
 try {   
 serverAddress = InetAddress.getByName(ip);   
 } catch (UnknownHostException e) {   
// txt.setText(e.getLocalizedMessage()+txt.getText());   
 e.printStackTrace();   
 }   

 try {   
 client=new Socket(serverAddress,port);   
 out=new PrintWriter(new BufferedWriter(new OutputStreamWriter(client.getOutputStream())),true);   
 } catch (IOException e) {   
// txt.setText(e.getLocalizedMessage()+txt.getText());   
 e.printStackTrace();   
 }   
 }   

 public void sendMsg(String msg) throws IOException   
 {   
 out.println(msg);   
 }   

 public void close()   
 {   
 out.close();   
// txt.setText("end"+txt.getText());   
 }   

 public boolean isConnected()   
 {   
 return client.isConnected();   
 }   
}

重力感应:

View Code  package com.android.baofengControl;   

import java.io.IOException;   

import android.content.Context;   
import android.hardware.Sensor;   
import android.hardware.SensorEvent;   
import android.hardware.SensorEventListener;   
import android.hardware.SensorManager;   
import android.widget.Button;   
import android.widget.TextView;   

public class MySensor {   
 SensorManager sensorManager;   
 Client client;   
 TextView textView;   
 Button btnUp;   
 String ip;   
 float lastNum; //上次num的数字   
 float min=0; //不改变方向的最小值,小于该值想向左转   
 float max=0; //不改变方向的最大值,大于该值向右转   
 long lastTime=0;   
 long currentTime=0;   

 ///开始监听加速传感器   
 public void Listen(SensorManager sensorManager,String _ip,Client _client)   
 {   
 client=_client;   
 this.sensorManager=sensorManager;   
 Sensor sensor=sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);   
 sensorManager.registerListener(sensorEventListener, sensor, SensorManager.SENSOR_DELAY_NORMAL);   
 }   

 SensorEventListener sensorEventListener =new SensorEventListener(){   
 public void onAccuracyChanged(android.hardware.Sensor arg0, int arg1) {   
 // TODO Auto-generated method stub   

 }   

 public void onSensorChanged(SensorEvent e) {   
 currentTime=System.currentTimeMillis();   
 if(client.isConnected()==true&¤tTime-lastTime>10)   
 {   
 float num=e.values[SensorManager.DATA_Y];   
 try {   
 client.sendMsg(String.valueOf(num));   
 } catch (IOException e1) {   
 // TODO Auto-generated catch block   
 e1.printStackTrace();   
 }   
 lastTime=currentTime;   
 }   
 }};   
}

使用:

打开C#服务端,打开极品飞车(我特地跑到网吧拖了一个极品飞车5,这个比较小,200多m)。

然后打开安卓客户端,点击连接,ok,开始游戏吧。

后续:

大家有兴趣的话,还可以写一个拳皇之类的游戏手柄,当游戏里两个人僵持的时候,游戏里是要狂按按钮,谁按的快就是谁赢,这里可以改成狂晃手机,谁晃得快谁就赢(思路都了,大家可以写一个分享出来玩玩呀,),然后找个朋友,一人一台手机,控制笔记本上的游戏,疯狂pk吧,哈哈。

如果觉得不错的话,大家就顶一下本文吧,写个博客不容易呀。


转载于:https://blog.51cto.com/515632/791834