你畫我猜核心功能實現 Android客戶端+Java服務端
本篇文章是我以前寫的一篇文章的改版,上一篇文章已刪除,因為以前的部落格有的朋友說執行不起來,我現在想起來所以重新修改了以下程式碼,因為我這測試機就兩個,只能測試一個繪製者和一個觀看者。
下面上程式碼,首先是我們的Android客戶端-------------------
Android實現原理就是自定義View,然後繼承的是SurfaceView,不繼承View的原因就是SurfaceView這個視圖裡內嵌了一個專門用於繪製的Surface。
先看一下我們自定義的DrawGameView,也就是繼承自SurfaceView的一個View。
public class DrawGameView extendsSurfaceView implements SurfaceHolder.Callback { private SurfaceHolder holder; private SurfaceThread thread; WindowManager wm = (WindowManager) getContext() .getSystemService(Context.WINDOW_SERVICE); int screenW = wm.getDefaultDisplay().getWidth(); int screenH = wm.getDefaultDisplay().getHeight();// private Canvas canvas; public SurfaceThread getThread() { return thread; } public DrawGameView(Context context) { super(context); init(); } public DrawGameView(Context context, AttributeSet attrs) { super(context, attrs); init(); } public void init() { holder= getHolder(); holder.addCallback(this); } @Override public void surfaceCreated(SurfaceHolder holder) { thread = new SurfaceThread(); thread.start(); } @Override public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) { } @Override public void surfaceDestroyed(SurfaceHolder holder) { } public class SurfaceThread extends Thread { private Path path; private Paint paint; private ArrayList<DrawStep> steps = new ArrayList<DrawStep>(); private ArrayList<Path> paths = new ArrayList<Path>(); public SurfaceThread() { path = new Path(); paint = new Paint(); paint.setAntiAlias(true); paint.setColor(Color.BLUE); paint.setStrokeWidth(5); paint.setStyle(Paint.Style.STROKE); } @Override public void run() { super.run(); while (true) { draw(); try { Thread.sleep(17); } catch (InterruptedException e) { e.printStackTrace(); } } } public void addStep(DrawStep step) { steps.add(step); } public void draw() { Canvas canvas = null; try { canvas = holder.lockCanvas();//鎖整個畫布 if (canvas != null) { while (steps.size() > 0) { DrawStep step = steps.remove(0); if (step.getType() == DrawStep.MoveTo) { path.moveTo(screenW * ((float) step.getxP() / 10000), screenH * ((float) step.getyP() / 10000)); } else if (step.getType() == DrawStep.LineTo) { path.lineTo(screenW * ((float) step.getxP() / 10000), screenH * ((float) step.getyP() / 10000)); } else if (step.getType() == DrawStep.UP) { Path path1 = new Path(path); paths.add(path1); } } for (int i = 0; i < paths.size(); i++) { canvas.drawPath(paths.get(i), paint); } canvas.drawPath(path, paint); holder.unlockCanvasAndPost(canvas); } } catch (Exception e) { } } } }
我先把所有程式碼貼上吧,沒什麼東西,如果有問題可以給我發私信。
MainActivity程式碼
public class MainActivity extends Activity { private static DrawGameView drawGameView; DisplayMetrics dm = new DisplayMetrics(); int screenW; int screenH; @SuppressLint("ClickableViewAccessibility") @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); NetWorkMessage.get_Instance().setActivity(this); drawGameView = new DrawGameView(this); setContentView(drawGameView); getWindowManager().getDefaultDisplay().getMetrics(dm); screenW = dm.widthPixels; screenH = dm.heightPixels; drawGameView.setOnTouchListener(new View.OnTouchListener() { @Override public boolean onTouch(View v, MotionEvent event) { if (NetWorkMessage.get_Instance().isDrawer()) { // if (true) { switch (event.getAction() & MotionEvent.ACTION_MASK) { case MotionEvent.ACTION_DOWN: addStep(DrawStep.MoveTo, (int) (event.getX() / screenW * 10000), (int) (event.getY() / screenH * 10000)); break; case MotionEvent.ACTION_MOVE: addStep(DrawStep.LineTo, (int) (event.getX() / screenW * 10000), (int) (event.getY() / screenH * 10000)); break; case MotionEvent.ACTION_UP: addStep(DrawStep.UP, 0, 0); break; } return true; } else { return false; } } }); } public void addStep(byte type, int xp, int yp) { DrawStep step = new DrawStep(); step.setType(type); step.setxP(xp); step.setyP(yp); NetWorkMessage.get_Instance().sendDrawMsgToServer(step); addOneStep(step); } public void addOneStep(DrawStep step) { drawGameView.getThread().addStep(step); } // public static void drawStep(DrawStep drawStep) { // drawGameView.postInvalidate(); //// drawView.forceLayout(); // } }
GameApplication在這裡做了Socket的初始化
public class GameApplication extends Application { @Override public void onCreate() { super.onCreate(); NetWorkMessage.get_Instance().createNetWork(); // NetWorkMessage.get_instaance().receiveLoginNetWork(); NetWorkMessage.get_Instance().receiveDrawNetWork(); } }
Command定義的伺服器與客戶端互動的命令
public class Command { public static final byte LOGIN = 1; public static final byte DRAW = 2; public static final byte LOGIN_OUT = 3;//登出 }
NetWorkMessage主要是處理Socket連線、接收和傳送資料的
public class NetWorkMessage { private final String TAG = "NetWorkMessage"; private Socket socket = new Socket(); private static NetWorkMessage _instance = new NetWorkMessage(); public boolean isDraw; private MainActivity activity; public MainActivity getActivity() { return activity; } public void setActivity(MainActivity activity) { this.activity = activity; } public static NetWorkMessage get_Instance() { return _instance; } public void sendDrawMsgToServer(DrawStep drawStep) { try { //傳送內容 DataOutputStream outputStream = new DataOutputStream(socket.getOutputStream()); int len = 10; ByteArray data = new ByteArray(); data.writeInt(len); data.writeByte(Command.DRAW); data.writeByte(drawStep.getType()); data.writeInt(drawStep.getxP()); data.writeInt(drawStep.getyP()); outputStream.write(data.toByteArray()); outputStream.flush(); } catch (Exception e) { e.printStackTrace(); Log.d(TAG, "沒有傳送成功======客戶端----斷開連線"); } } public void createNetWork() { new Thread(createNetwork).start(); } public void receiveDrawNetWork() { new Thread(receiveDrawNetwork).start(); } private Runnable createNetwork = new Runnable() { @Override public void run() { try { // socket = new Socket("192.168.0.102", 8888); socket = new Socket("192.168.1.105", 8888); requestLogin(); } catch (IOException e) { e.printStackTrace(); } } }; /** * 請求登入 */ private void requestLogin() { try{ DataOutputStream outputStream = new DataOutputStream(socket.getOutputStream()); String userKey = (String) SharedPreferencesUtil.getData(getActivity(), Configs.LOCAL_USER_KEY, ""); int len = 5 + userKey.length(); ByteArray data = new ByteArray(); data.writeInt(len); data.writeByte(Command.LOGIN); data.writeByteArray(userKey.getBytes()); outputStream.write(data.toByteArray()); outputStream.flush(); }catch (Exception e) { } } private Runnable receiveDrawNetwork = new Runnable() { @Override public void run() { while (true) { receiveDraw(); } } }; private void receiveDraw() { //接收伺服器返回資訊 try { DataInputStream inputStream = new DataInputStream(socket.getInputStream()); if (inputStream.available() != 0) { int len = inputStream.readInt(); byte[] buffer = new byte[len]; inputStream.read(buffer, 0, len); ByteArray data = new ByteArray(buffer); byte cmd = data.readByte(); if (cmd == Command.LOGIN) { Log.d(TAG, "-----------BEGIN-----------------"); byte[] userKeyByteArr = data.readByteArray(5, 36); Log.d(TAG, "-----------EDN-----------------"); String userKey = new String(userKeyByteArr); if (userKey != null && !"".equals(userKey)) { SharedPreferencesUtil.saveData(getActivity(), Configs.LOCAL_USER_KEY, userKey); } Log.d(TAG, "userKey=============" + userKey); //12e0962f-3789-48a5-9b9e-74a256544949 int tag = data.readInt(); Log.d(TAG, "tag=============" + tag); if (tag == 1) { setDrawer(true); } else { setDrawer(false); } } else if (cmd == Command.DRAW) { byte type = data.readByte(); int x = data.readInt(); int y = data.readInt(); DrawStep drawStep = new DrawStep(); drawStep.setxP(x); drawStep.setyP(y); drawStep.setType(type); activity.addOneStep(drawStep); } // MainActivity.drawStep(msg); } } catch (Exception e) { e.printStackTrace(); } } public boolean isDrawer() { return isDraw; } public void setDrawer(boolean draw) { isDraw = draw; } }
DrawSept,繪製的時候前後臺互動傳輸的資料格式
public class DrawStep { public static final byte MoveTo = 1; public static final byte LineTo = 2; public static final byte UP = 3; private byte type; private int xP; private int yP; public byte getType() { return type; } public void setType(byte type) { this.type = type; } public int getxP() { return xP; } public void setxP(int xP) { this.xP = xP; } public int getyP() { return yP; } public void setyP(int yP) { this.yP = yP; } }
SharePreferencesUtil 本地儲存工具類,用來儲存伺服器返回的userKey
public class SharedPreferencesUtil { //儲存的sharedpreferences檔名 private static final String FILE_NAME = "save_file_name"; /** * 儲存資料到檔案 * * @param context * @param key * @param data */ public static void saveData(Context context, String key, Object data){ String type = data.getClass().getSimpleName(); SharedPreferences sharedPreferences = context .getSharedPreferences(FILE_NAME, Context.MODE_PRIVATE); SharedPreferences.Editor editor = sharedPreferences.edit(); if ("Integer".equals(type)){ editor.putInt(key, (Integer)data); }else if ("Boolean".equals(type)){ editor.putBoolean(key, (Boolean)data); }else if ("String".equals(type)){ editor.putString(key, (String)data); }else if ("Float".equals(type)){ editor.putFloat(key, (Float)data); }else if ("Long".equals(type)){ editor.putLong(key, (Long)data); } editor.commit(); } /** * 清除本地儲存的資料 * * @param context * @param key */ public static void removeData(Context context, String key) { SharedPreferences sharedPreferences = context .getSharedPreferences(FILE_NAME, Context.MODE_PRIVATE); SharedPreferences.Editor editor = sharedPreferences.edit(); editor.remove(key); editor.commit(); } /** * 從檔案中讀取資料 * @param context * @param key * @param defValue * @return */ public static Object getData(Context context, String key, Object defValue){ String type = defValue.getClass().getSimpleName(); SharedPreferences sharedPreferences = context.getSharedPreferences (FILE_NAME, Context.MODE_PRIVATE); //defValue為為預設值,如果當前獲取不到資料就返回它 if ("Integer".equals(type)){ return sharedPreferences.getInt(key, (Integer)defValue); }else if ("Boolean".equals(type)){ return sharedPreferences.getBoolean(key, (Boolean)defValue); }else if ("String".equals(type)){ return sharedPreferences.getString(key, (String)defValue); }else if ("Float".equals(type)){ return sharedPreferences.getFloat(key, (Float)defValue); }else if ("Long".equals(type)){ return sharedPreferences.getLong(key, (Long)defValue); } return null; } }
ByteArray
public class ByteArray { /** * DEFAULT_SIZE */ private static final byte DEFAULT_SIZE = 16; /** * BOOLEAN_SIZE */ static final public byte BOOLEAN_SIZE = 1; /** * BYTE_SIZE */ static final public byte BYTE_SIZE = 1; /** * CHAR_SIZE */ static final public byte CHAR_SIZE = 2; /** * SHORT_SIZE */ static final public byte SHORT_SIZE = 2; /** * INT_SIZE */ static final public byte INT_SIZE = 4; /** * LONG_SIZE */ static final public byte LONG_SIZE = 8; /** * 當前位置 */ private int currentPos = 0; /** * byte陣列資料 */ private byte[] data; /** * 預設大小構造 */ public ByteArray() { this(DEFAULT_SIZE); } /** * 指定大小構造 * * @param size 指定的大小 */ public ByteArray(int size) { data = new byte[size]; currentPos = 0; } /** * 指定資料構造 * * @param src 指定的資料來源 */ public ByteArray(byte[] src) { data = src; currentPos = 0; } /** * writeBoolean * * @param val */ public void writeBoolean(boolean val) { ensureCapacity(BOOLEAN_SIZE); data[currentPos++] = (byte) (val ? 1 : 0); } /** * writeByte * * @param val */ public void writeByte(byte val) { ensureCapacity(BYTE_SIZE); data[currentPos++] = val; } /** * writeByte * * @param val */ public void writeByte(int val) { writeByte((byte) val); } /** * writeChar * * @param c */ public void writeChar(char c) { ensureCapacity(CHAR_SIZE); data[currentPos + 1] = (byte) (c >>> 0); data[currentPos + 0] = (byte) (c >>> 8); currentPos += 2; } /** * writeShort * * @param val */ public void writeShort(short val) { ensureCapacity(SHORT_SIZE); data[currentPos + 1] = (byte) (val >>> 0); data[currentPos + 0] = (byte) (val >>> 8); currentPos += 2; } /** * writeShort * * @param val */ public void writeShort(int val) { writeShort((short) val); } /** * writeInt * * @param val */ public void writeInt(int val) { ensureCapacity(INT_SIZE); data[currentPos + 3] = (byte) (val >>> 0); data[currentPos + 2] = (byte) (val >>> 8); data[currentPos + 1] = (byte) (val >>> 16); data[currentPos + 0] = (byte) (val >>> 24); currentPos += INT_SIZE; } /** * writeLong * * @param val */ public void writeLong(long val) { ensureCapacity(LONG_SIZE); data[currentPos + 7] = (byte) (val >>> 0); data[currentPos + 6] = (byte) (val >>> 8); data[currentPos + 5] = (byte) (val >>> 16); data[currentPos + 4] = (byte) (val >>> 24); data[currentPos + 3] = (byte) (val >>> 32); data[currentPos + 2] = (byte) (val >>> 40); data[currentPos + 1] = (byte) (val >>> 48); data[currentPos + 0] = (byte) (val >>> 56); currentPos += LONG_SIZE; } /** * writeByteArray *相關推薦
你畫我猜核心功能實現 Android客戶端+Java服務端
本篇文章是我以前寫的一篇文章的改版,上一篇文章已刪除,因為以前的部落格有的朋友說執行不起來,我現在想起來所以重新修改了以下程式碼,因為我這測試機就兩個,只能測試一個繪製者和一個觀看者。下面上程式碼,首先是我們的Android客戶端------------------
使用websocket實現“你畫我猜”
1,環境配置(nodejs) 檔案結構: package.json: { "name": "websocket", "version": "1.0.0", "description": "", "main": "index.js", "scrip
你畫我猜題目庫
之前在電腦上玩過線上的你畫我猜,感覺很有意思。正好我們部門迭代會之後都會玩個小遊戲,於是我組織了一個線下的你畫大家猜,效果還不錯。 由於線下不同線上的特點我對規則重新制定了一下,規則可以是靈活多變的,大家都認同玩的開心就好。 再下面就是遊戲的題目庫了,這些題目都是我收集的,看到這些
canvas+websocket+vue做一個你畫我猜小遊戲
做這個主要是學習使用一下canvas和websocket,專案地址。 你畫我猜大家應該都玩過,一個人畫,其他人猜。現在剛剛實現了最基本的功能,以後還會慢慢修改的。 完成進度 登入,登入後username儲存到了sessionStorage中。 座位,登入後
Java課程設計之你畫我猜
這幾天要做資料結構的課程設計,寫了幾天終於完成,雖然有很多不足之處,但勉強完成了。過後感覺從大一到現在寫過許多項 目,是該總結一下那些年的課程設計了。 大一做的課程設計是“你畫我猜”,那時候修修改改,前後用了一個月的時間,資料庫方面是凡神做的,最後的成績還不錯。下面總
React+Nodejs+Socket+Webpack版你畫我猜
React版我畫你猜 之前有看到過一個Vue版本的 我畫你猜 然後用 React 也做了一個。技術棧:React + Nodejs + Socket.io + Webpack + Less 先上
騰訊雲搭建多終端《你畫我猜》Socket伺服器
結合一個小demo,分享如何用騰訊雲的Socket伺服器代理各種socket請求,實現低延遲,和不同端之間的互動 作者:金朝麟 文章出處:騰雲閣文章 ---------------------------------------------------- 專案概述
谷歌AI版“你畫我猜”背後是什麼樣的原理?
我們先看看這個小程式是什麼,開啟微信小程式搜尋頁面,搜尋“猜畫小歌”,開啟這個小程式,點選開始作
你畫我猜---websocket
前段時間接觸了websocket,具體的就不介紹了,他就是與後臺建立長連線,完成資訊的傳送與接受,有興趣看我之前的blog或者google一下!之前完成了單聊與多聊的功能,分別實用tomcat7和to
Java小程式之你畫我猜
package com.huaxin.client; import java.awt.BasicStroke; import java.awt.BorderLayout; import java.awt.Color; import java.awt.Dimension; import java.awt.Gr
iOS 小遊戲專案——你話我猜升級版
級別: ★☆☆☆☆ 標籤:「iOS」「小遊戲專案」「你話我猜」 作者: MrLiuQ 審校: QiShare團隊 前言:最近公司部門在組織團建,需要準備兩個團建小遊戲, 分別是“數字速算升級版”和“你話我猜升級版”。 小編琢磨了一下,發現這個兩個小專案很適合iOS入門學習,故這篇文章誕生了。 本
一對一聊天系統核心功能實現方式有哪些,哪種方式可取?
一對一社交平臺我們可以在應用商店裡看到很多,他們都屬於一對一聊天系統的範疇,只是功能各異,各有各的產品定位及運營特色。然而它們有一個共同的核心功能:使用者間的一對一視訊(或語音)聊天。那麼各具特色的一對一聊天系統,它的核心功能是如何實現的呢? 常見的一對一聊天功能的實現方式有以下幾種: 1.
Android Accessibility(輔助功能) --實現Android應用自動安裝、解除安裝
對於那些由於視力、聽力或其它身體原因導致不能方便使用Android智慧手機的使用者,Android提供了Accessibility功能和服務幫助這些使用者更加簡單地操作裝置,包括文字轉語音、觸覺反饋、手勢操作、軌跡球和手柄操作。開發者可以搭建自己的Accessibi
基於環信實現android客戶端客服聊天功能
本來類似於這種第三方的功能是沒有必要寫部落格的,但是由於環信客服功能的文件實在版本過舊,所以在此記錄下,希望能給大家帶來一點便利。 工具:androidStudio 第1步: 註冊一個環信的賬號,地址如下,有了直接登入就可以了。https://kefu.eas
第一章 “我要點爆”微信小程式雲開發之專案建立與我的頁面功能實現
第一章 “我要點爆”微信小程式雲開發之專案建立與我的頁面功能實現 開發環境搭建使用自己的AppID新建小程式專案,後端服務選擇小程式·雲開發,點選新建,完成專案新建。 新建成功後跳轉到開發者工具介面 新建後,微信端為我們提供了一個參考的模板程式,這裡我們自己來建
用 Java 做個“你畫手機猜”的小遊戲
> 本文適合有 Java 基礎的人群 ![](https://img2020.cnblogs.com/blog/759200/202009/759200-20200923184426141-1352914100.gif) 作者:**DJL-Lanking** HelloGitHub 推出的[《講
unity_小功能實現(客戶端相互通信功能)
直接 endpoint 客戶端和服務器端 network hat sockets odi family void 服務器端:在VS中新建項目,用於服務器的搭建 using System;using System.Collections.Generic; using
從Android端到服務端全端開發------二級評論表的實現
前言:對於專門開發android端或者服務端某一端的開發者來說,對另一方可能也不太熟悉,希望通過這篇文章使大家更加熟悉另外一端,讓開發協作變得更加默契。 web伺服器端和app伺服器端的區別: 幾乎一樣,不過作為app,以下幾點是需要考慮的: 1、使用者的手機流量,由於手機套餐流量是一定
java服務端,微信支付功能的實現
接入微信的支付功能在java服務端,現在記錄下來這個過程,方便以後用到。程式碼都是參考網路,功能可以實現 實際參考https://github.com/wxpay/WXPay-SDK-Java ①,寫一個介面,作為引數配置的介面,當然也可以不用介
java服務端對多個客戶端的群聊功能程式碼實現
以下程式碼可以實現服務端傳送一條訊息,多個客戶端可以同時收到這條訊息,同時客戶端可以單獨的和服務端通訊 需要注意的是,此時服務端只需要一個傳送訊息的程序 服務端程式碼: /** * 實現多個客戶端對應一個服務端進行通訊 * * @author wa