学习笔记--分布式数字华容道(下)
想了解更多内容,学习下请访问:
和华为官方合作共建的笔记鸿蒙技术社区
https://harmonyos.51cto.com
前言
我又来了。最近比较忙,分布导致这一篇文章拖了好久还没写,式数只能趁着国庆放假抽空写一写了。字华继前两篇文章的容道铺垫,我们这一篇文章就来实现分布式数字华容道的学习下双人模式。前面的笔记请参考学习笔记–分布式数字华容道(中)。
那现在就先开始我们今天的分布学习吧。

正文
那我们在双人模式中呢,式数怎么进行同步就是字华一个最重要的问题了。那我们这个游戏呢,容道就运用分布式数据库来进行我们两台设备数据的学习下同步了。
那要实现出一个分布式数据库的笔记话,我们就需要先定义一些变量。分布
private static final HiLogLabel TAG = new HiLogLabel(HiLog.LOG_APP,0x12345,"signal"); private static int difficulty = 3; private DirectionalLayout layout; private static int length; private static final int interval = 5; private static final int left = 32; private static final int top = 300; private static final int margin = 15; private static int length1; private static final int left1 = 32; private static final int top1 = 1350; private static final int margin1 = 10; private static int row_a0; private static int column_a0; private static int row_b0; private static int column_b0; private float startX; private float startY; private static Timer timer; private static Timer updatetimer; private static Timer restarttimer; private static Timer backtimer; private static Text timetext ; private static Text maxtext; private static Text wintext; private static int hour; private static int min; private static int sec; private static int msec; private static int restart = 0; private static int back = 0; private static int maxhour = 23; private static int maxmin = 59; private static int maxsec = 59; private static int maxmsec = 99; private static int[][] grids_a; private static int[][] grids_b; private static final String STROE_ID = "data"; private static String randomstr = ""; private static String winner = ""; private static KvManager kvManager; private static String strhour = ""; private static String strmin = ""; private static String strsec = ""; private static String strmsec = ""; private static String text = "暂停"; private SingleKvStore singleKvStore; private static Button button_moveback; private static Boolean isLocal;接下来就是写一个分布式数据库
private KvManager createManger() { //辅助类 KvManager manager = null; try{ KvManagerConfig config = new KvManagerConfig(this); manager = KvManagerFactory.getInstance().createKvManager(config); } catch (KvStoreException exception) { HiLog.info(TAG,"ERROR"); } return manager; } private SingleKvStore createDb(KvManager kvManager) { //数据库 SingleKvStore kvStore = null; try{ Options options = new Options(); options.setCreateIfMissing(true).setEncrypt(false).setKvStoreType(KvStoreType.SINGLE_VERSION); kvStore = kvManager.getKvStore(options,STROE_ID); } catch (KvStoreException exception) { HiLog.info(TAG,"ERROR"); } return kvStore; } private void subscribeDb(SingleKvStore singleKvStore) { //订阅 class KvStoreObserveClient implements KvStoreObserver { @Override public void onChange(ChangeNotification notification) { } } KvStoreObserver kvStoreObserverClient = new KvStoreObserveClient(); singleKvStore.subscribe(SubscribeType.SUBSCRIBE_TYPE_ALL,kvStoreObserverClient); } private void initDbManager() { kvManager = createManger(); singleKvStore = createDb(kvManager); subscribeDb(singleKvStore); }再写两个写入数据库的函数还有读取的函数。
private int queryContact_int(String key) { try { return singleKvStore.getInt(key); } catch (KvStoreException exception) { HiLog.info(TAG,"int error" + exception.getMessage()); return -1; } } private String queryContact_String(String key) { try { return singleKvStore.getString(key); } catch (KvStoreException exception) { HiLog.info(TAG,"String error" + exception.getMessage()); return null; } } private void writeData_String(String key , String value) { if (key == null || key.isEmpty() || value == null || value.isEmpty()) return; singleKvStore.putString(key,value); } private void writeData_int(String key,int value) { if (key == null || key.isEmpty()) { return; } singleKvStore.putInt(key,value); }那接下里我们就写一个在数据库中读取记录的函数,当开始游戏的时候,会读取该阶数中的最快的云服务器提供商记录。
public void getrecord() { if (queryContact_int("hour" + difficulty) != -1) maxhour = queryContact_int("hour" + difficulty); else maxhour = 23; if (queryContact_int("min" + difficulty) != -1) maxmin = queryContact_int("min" + difficulty); else maxmin = 59; if (queryContact_int("sec" + difficulty) != -1) maxsec = queryContact_int("sec" + difficulty); else maxsec = 59; if (queryContact_int("msec" + difficulty) != -1) maxmsec = queryContact_int("msec" + difficulty); else maxmsec = 99; }接下来我们就开始初始化我们的数组了,然后把一台设备初始化完了的数组写到数据库中,让另外一台设备来读取数据库中的数据,再用来初始化该设备的数组。
public void createGrids() { randomstr = ""; if (isLocal) { int random; int i = 0; while(i < difficulty * difficulty * 5) { random = (int)Math.floor(Math.random() *4 ); randomstr += random; int temp_row = row_a0; int tem_column = column_a0; if(random == 0){ changeGrids(row_a0 - 1, column_a0); }else if(random == 1){ changeGrids(row_a0 + 1, column_a0); }else if(random == 2){ changeGrids(row_a0, column_a0 - 1); }else if(random == 3){ changeGrids(row_a0, column_a0 + 1); } if(temp_row != row_a0 || tem_column != column_a0){ i++; } } HiLog.info(TAG,randomstr); writeData_String("randomstr",randomstr); } else { while (true) { if (queryContact_String("randomstr") != null && !queryContact_String("randomstr").isEmpty()) { break; } } randomstr = queryContact_String("randomstr"); HiLog.info(TAG,"randomstr: "+randomstr); int random; int i = 0; while(i < randomstr.length()) { random = randomstr.charAt(i) - 0; if(random == 0){ changeGrids(row_a0 - 1, column_a0); }else if(random == 1){ changeGrids(row_a0 + 1, column_a0); }else if(random == 2){ changeGrids(row_a0, column_a0 - 1); }else if(random == 3){ changeGrids(row_a0, column_a0 + 1); } i++; } singleKvStore.putString("randomstr",""); } for (int row = 0;row < difficulty; row++) { for (int column = 0;column <difficulty; column++) { grids_b[row][column] = grids_a[row][column]; } } row_b0 = row_a0; column_b0 = column_a0; HiLog.info(TAG,"row_a0: "+ row_a0 + " column_a0: " + column_a0); }那接下去就是把数组中的数字给画出来了。
public void drawGrids() { layout.setLayoutConfig((new ComponentContainer.LayoutConfig(ComponentContainer.LayoutConfig.MATCH_PARENT, ComponentContainer.LayoutConfig.MATCH_PARENT))); Component.DrawTask task = new Component.DrawTask() { @Override public void onDraw(Component component, Canvas canvas) { Paint paint = new Paint(); Color backcolor = new Color(Color.rgb(151,75,49)); paint.setColor(backcolor); RectFloat rect = new RectFloat(left - margin, top - margin, length * difficulty + interval * (difficulty - 1) + left + margin, length * difficulty + interval * (difficulty - 1) + top + margin); canvas.drawRect(rect, paint); for (int row = 0; row < difficulty; row++) { for (int column = 0; column < difficulty; column++) { Color backgroundcolor = new Color(Color.rgb(229,188,132)); paint.setColor(backgroundcolor); RectFloat rectFloat = new RectFloat(left + column * (length + interval), top + row * (length + interval), left + length + column * (length + interval), top + length + row * (length + interval)); canvas.drawRect(rectFloat, paint); Color numbercolor = new Color(Color.rgb(140,85,47)); paint.setColor(numbercolor); paint.setTextSize(length / 2); if(grids_a[row][column] != 0){ if(grids_a[row][column] < 10){ canvas.drawText(paint,Integer.toString(grids_a[row][column]),left + column * (length + interval) + length / 12 * 5,top + row * (length + interval) + length / 3 * 2); }else{ canvas.drawText(paint,Integer.toString(grids_a[row][column]),left + column * (length + interval) + length / 12 * 3,top + row * (length + interval) + length / 3 * 2); } } } } paint.setColor(backcolor); length1 = 600 / difficulty - interval; RectFloat rect1= new RectFloat(left1 - margin1, top1 - margin1, length1 * difficulty + interval * (difficulty - 1) + left1 + margin1, length1 * difficulty + interval * (difficulty - 1) + top1 + margin1); canvas.drawRect(rect1, paint); for (int row = 0; row < difficulty; row++) { for (int column = 0; column < difficulty; column++) { Color backgroundcolor1 = new Color(Color.rgb(229,188,132)); paint.setColor(backgroundcolor1); RectFloat rectFloat = new RectFloat(left1 + column * (length1 + interval), top1 + row * (length1 + interval), left1 + length1 + column * (length1 + interval), top1 + length1 + row * (length1 + interval)); canvas.drawRect(rectFloat, paint); Color numbercolor1 = new Color(Color.rgb(140,85,47)); paint.setColor(numbercolor1); paint.setTextSize(length1 / 2); if(grids_b[row][column] != 0){ if(grids_b[row][column] < 10){ canvas.drawText(paint,Integer.toString(grids_b[row][column]),left1 + column * (length1 + interval) + length1 / 12 * 5,top1 + row * (length1 + interval) + length1 / 3 * 2); }else{ canvas.drawText(paint,Integer.toString(grids_b[row][column]),left1 + column * (length1 + interval) + length1 / 12 * 3,top1 + row * (length1 + interval) + length1 / 3 * 2); } } } } } }; layout.addDrawTask(task); setUIContent(layout); }接下来就是把我们的时间还有按钮这些给画出来了。
public void draw() { maxtext = new Text(this); setMaxtext(); maxtext.setTextSize(80); maxtext.setMarginTop(40); maxtext.setMarginLeft(140); layout.addComponent(maxtext); timetext = new Text(this); timetext.setText("time: 00:00:00:00"); timetext.setTextSize(80); timetext.setMarginTop(10); timetext.setMarginLeft(230); layout.addComponent(timetext); ShapeElement background = new ShapeElement(); background.setRgbColor(new RgbColor(138,70,50)); background.setCornerRadius(100); Button button_again = new Button(this); button_again.setText("重新开始"); button_again.setTextAlignment(TextAlignment.CENTER); button_again.setTextColor(Color.WHITE); button_again.setTextSize(100); button_again.setMarginTop(1150); button_again.setMarginLeft(730); button_again.setPadding(30, 0, 30, 0); button_again.setBackground(background); button_again.setClickedListener(new Component.ClickedListener() { @Override public void onClick(Component component) { getrecord(); writeData_int("restart",1); } }); layout.addComponent(button_again); Button button_back = new Button(this); button_back.setText("返回"); button_back.setTextAlignment(TextAlignment.CENTER); button_back.setTextColor(Color.WHITE); button_back.setTextSize(100); button_back.setMarginLeft(730); button_back.setMarginTop(90); button_back.setPadding(30, 0, 30, 0); button_back.setBackground(background); button_back.setClickedListener(new Component.ClickedListener() { @Override public void onClick(Component component) { } }); layout.addComponent(button_back); setUIContent(layout); }
这就是我们的效果图,你们也可以运行查看一下是否完全一样。保证一样了之后才继续跟着一步一步慢慢走。
我们这已经算是完成了最开始同步的问题了,这算是比较重要的一个问题了,那我们接下来就要继续先完成我们的游戏功能,那在完成游戏功能之前,我们需要先写一个判断游戏是否成功的函数。服务器租用
public boolean gamesuccess() { int[][] Grids = new int[difficulty][difficulty]; for (int row = 0; row < difficulty; row++){ for (int column = 0; column < difficulty; column++){ Grids[row][column] = difficulty * row + column + 1; } } Grids[difficulty - 1][difficulty - 1] = 0; for (int row = 0; row < difficulty; row++){ for (int column = 0; column < difficulty; column++){ if(grids_a[row][column] != Grids[row][column]){ return false; } } } return true; }那接下来再写一个判断当前时间是否比最短时间要快的函数,并且写一个将当前时间写到数据库的函数。
public boolean compare() { int nowtime = hour * 36000 + min * 6000 + sec * 100 + msec; int maxtime = maxhour * 36000 + maxmin * 6000 + maxsec * 100 + maxmsec; return nowtime > maxtime; } public void Write() { if (!compare()) { writeData_int("hour" + difficulty, hour); writeData_int("min" + difficulty, min); writeData_int("sec" + difficulty,sec); writeData_int("msec" + difficulty, msec); } }那现在我们就可以来完成的我们的游戏功能了,并且我们要实现出在这一台设备上玩游戏,要将数据写入数据库,让另外一台设备来读取数据,实现数据的同步。
public void swipeGrids(){ layout.setTouchEventListener(new Component.TouchEventListener() { @Override public boolean onTouchEvent(Component component, TouchEvent touchEvent) { MmiPoint point = touchEvent.getPointerScreenPosition(0); switch (touchEvent.getAction()) { case TouchEvent.PRIMARY_POINT_DOWN: startX = point.getX(); startY = point.getY(); String str_row = String.valueOf(Math.floor((startY - top - 80) / (length + interval))); String str2_column = String.valueOf(Math.floor((startX - left) / (length + interval))); if (!gamesuccess()) { writeData_int("row" + isLocal ,str_row.charAt(0)-0); writeData_int("column" + isLocal ,str2_column.charAt(0)-0); changeGrids(str_row.charAt(0)-0, str2_column.charAt(0)-0); drawGrids(); if(gamesuccess()){ getrecord(); setMaxtext(); HiLog.info(TAG,Integer.toString(maxmsec)); timer.cancel(); updatetimer.cancel(); if (!compare()) { maxhour = hour; maxmin = min; maxsec = sec; maxmsec = msec; Write(); setMaxtext(); setUIContent(layout); } } } break; } return true; } }); }那数据同步了之后,我们是还没将数据写呈现出来。那我们现在就需要将数组b中的内容给画出来了,那我们就来写另外一个时间线程,来实现这个功能。
public void update() { updatetimer = new Timer(); updatetimer.schedule(new TimerTask() { @Override public void run() { getUITaskDispatcher().asyncDispatch(() -> { drawGrids(); }); } },0,500); }那我们还需要在订阅函数中去添加一个数据同步的操作。
if (queryContact_int("row" + !isLocal)!=-1 && queryContact_int("column" + !isLocal)!=-1) changeGrids_b(queryContact_int("row"+ !isLocal),queryContact_int("column"+ !isLocal));那我们接下来就去写一个函数让我们的时间开始动起来。
public void runing(){ timer = new Timer(); timer.schedule(new TimerTask() { @Override public void run() { getUITaskDispatcher().asyncDispatch(()->{ msec++; if (msec >= 100){ sec++; msec = msec % 100; if (sec >= 60) { min++; sec = sec % 60; if (min >= 60) { hour++; min = min % 60; } } } String strhour = ""; String strmin = ""; String strsec = ""; String strmsec = ""; if (msec < 10) { strmsec = "0" + Integer.toString(msec); } else if (msec >= 10) { strmsec = Integer.toString(msec); } if (sec < 10){ strsec = "0" + Integer.toString(sec); } else if (sec >= 10) { strsec = Integer.toString(sec); } if (min < 10){ strmin = "0" + Integer.toString(min); } else if (min >= 10) { strmin = Integer.toString(min); } if (hour < 10){ strhour = "0" + Integer.toString(hour); } else if (hour >= 10) { strhour = Integer.toString(hour); } timetext.setText("time: "+ strhour +":"+strmin+":"+strsec+":"+strmsec); }); } },0,10); }同样的也是需要在订阅函数中实现数据的同步
if (queryContact_int("hour"+difficulty) != -1) maxhour = queryContact_int("hour"+difficulty); if(queryContact_int("min"+difficulty)!=-1) maxmin = queryContact_int("min"+difficulty); if(queryContact_int("sec"+difficulty)!=-1) maxsec = queryContact_int("sec"+difficulty); if (queryContact_int("msec"+difficulty)!=-1) maxmsec = queryContact_int("msec"+difficulty);那这样子我们就已经是完成了游戏功能了,接下去就来做返回按钮的点击事件吧。
timer.cancel(); updatetimer.cancel(); terminate();那接下来我们就来写重新开始的点击事件了。亿华云计算那为了两台设备能同时重新开始,我就在点击重新开始的时候往数据库里面写一个信号,然后还是用一个时间线程来检测这个信号,检测到了,就重新开始游戏。
public void restarting() { restarttimer = new Timer(); restarttimer.schedule(new TimerTask() { @Override public void run() { getUITaskDispatcher().asyncDispatch(() ->{ if (restart == 1){ timer.cancel(); updatetimer.cancel(); restart = 0; initialize(); runing(); update(); } }); } },0,25); }那到这里我们的游戏也就完成了。我们也可以利用这些分布式能力来创建更多双人小游戏了。
文章相关附件可以点击下面的原文链接前往下载
https://harmonyos.51cto.com/resource/1294
想了解更多内容,请访问:
和华为官方合作共建的鸿蒙技术社区
https://harmonyos.51cto.com