-
Notifications
You must be signed in to change notification settings - Fork 0
/
index.html
440 lines (267 loc) · 43.4 KB
/
index.html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Creeper Blog</title>
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<meta property="og:type" content="website">
<meta property="og:title" content="Creeper Blog">
<meta property="og:url" content="http://example.com/index.html">
<meta property="og:site_name" content="Creeper Blog">
<meta property="og:locale">
<meta property="article:author" content="creeper12356">
<meta name="twitter:card" content="summary">
<link rel="alternate" href="/atom.xml" title="Creeper Blog" type="application/atom+xml">
<link rel="shortcut icon" href="/favicon.png">
<link rel="stylesheet" href="/css/style.css">
<link rel="stylesheet" href="/fancybox/jquery.fancybox.min.css">
<meta name="generator" content="Hexo 7.3.0"></head>
<body>
<div id="container">
<div id="wrap">
<header id="header">
<div id="banner"></div>
<div id="header-outer" class="outer">
<div id="header-title" class="inner">
<h1 id="logo-wrap">
<a href="/" id="logo">Creeper Blog</a>
</h1>
</div>
<div id="header-inner" class="inner">
<nav id="main-nav">
<a id="main-nav-toggle" class="nav-icon"><span class="fa fa-bars"></span></a>
<a class="main-nav-link" href="/">Home</a>
<a class="main-nav-link" href="/archives">Archives</a>
</nav>
<nav id="sub-nav">
<a class="nav-icon" href="/atom.xml" title="RSS Feed"><span class="fa fa-rss"></span></a>
<a class="nav-icon nav-search-btn" title="Suche"><span class="fa fa-search"></span></a>
</nav>
<div id="search-form-wrap">
<form action="//google.com/search" method="get" accept-charset="UTF-8" class="search-form"><input type="search" name="q" class="search-form-input" placeholder="Suche"><button type="submit" class="search-form-submit"></button><input type="hidden" name="sitesearch" value="http://example.com"></form>
</div>
</div>
</div>
</header>
<div class="outer">
<section id="main">
<article id="post-解决Windows下zip压缩包在Linux下解压乱码问题" class="h-entry article article-type-post" itemprop="blogPost" itemscope itemtype="https://schema.org/BlogPosting">
<div class="article-meta">
<a href="/2024/10/27/%E8%A7%A3%E5%86%B3Windows%E4%B8%8Bzip%E5%8E%8B%E7%BC%A9%E5%8C%85%E5%9C%A8Linux%E4%B8%8B%E8%A7%A3%E5%8E%8B%E4%B9%B1%E7%A0%81%E9%97%AE%E9%A2%98/" class="article-date">
<time class="dt-published" datetime="2024-10-27T07:55:17.000Z" itemprop="datePublished">2024-10-27</time>
</a>
</div>
<div class="article-inner">
<header class="article-header">
<h1 itemprop="name">
<a class="p-name article-title" href="/2024/10/27/%E8%A7%A3%E5%86%B3Windows%E4%B8%8Bzip%E5%8E%8B%E7%BC%A9%E5%8C%85%E5%9C%A8Linux%E4%B8%8B%E8%A7%A3%E5%8E%8B%E4%B9%B1%E7%A0%81%E9%97%AE%E9%A2%98/">解决Windows下zip压缩包在Linux下解压乱码问题</a>
</h1>
</header>
<div class="e-content article-entry" itemprop="articleBody">
<p>由于编码格式的不同,在Windows下压缩的zip文件在Linux下解压后,其中中文的文件名会出现乱码。解决方式:</p>
<p>安装7z和convmv</p>
<figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">sudo</span> apt install 7zip convmv</span><br></pre></td></tr></table></figure>
<p>执行压缩后将编码从GBK转为UTF-8</p>
<figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">LANG=C 7za x your-zip-file.zip</span><br><span class="line">convmv -f GBK -t utf8 --notest -r .</span><br></pre></td></tr></table></figure>
<p>参考:<br><a target="_blank" rel="noopener" href="https://blog.csdn.net/suiyueruge1314/article/details/90766185">https://blog.csdn.net/suiyueruge1314/article/details/90766185</a></p>
</div>
<footer class="article-footer">
<a data-url="http://example.com/2024/10/27/%E8%A7%A3%E5%86%B3Windows%E4%B8%8Bzip%E5%8E%8B%E7%BC%A9%E5%8C%85%E5%9C%A8Linux%E4%B8%8B%E8%A7%A3%E5%8E%8B%E4%B9%B1%E7%A0%81%E9%97%AE%E9%A2%98/" data-id="cm2rarilc0000yl1r5tw6c1sp" data-title="解决Windows下zip压缩包在Linux下解压乱码问题" class="article-share-link"><span class="fa fa-share">Teilen</span></a>
</footer>
</div>
</article>
<article id="post-使用libGDX移植20年前的J2ME游戏《中国跳棋》" class="h-entry article article-type-post" itemprop="blogPost" itemscope itemtype="https://schema.org/BlogPosting">
<div class="article-meta">
<a href="/2024/08/25/%E4%BD%BF%E7%94%A8libGDX%E7%A7%BB%E6%A4%8D20%E5%B9%B4%E5%89%8D%E7%9A%84J2ME%E6%B8%B8%E6%88%8F%E3%80%8A%E4%B8%AD%E5%9B%BD%E8%B7%B3%E6%A3%8B%E3%80%8B/" class="article-date">
<time class="dt-published" datetime="2024-08-25T12:38:24.000Z" itemprop="datePublished">2024-08-25</time>
</a>
</div>
<div class="article-inner">
<header class="article-header">
<h1 itemprop="name">
<a class="p-name article-title" href="/2024/08/25/%E4%BD%BF%E7%94%A8libGDX%E7%A7%BB%E6%A4%8D20%E5%B9%B4%E5%89%8D%E7%9A%84J2ME%E6%B8%B8%E6%88%8F%E3%80%8A%E4%B8%AD%E5%9B%BD%E8%B7%B3%E6%A3%8B%E3%80%8B/">使用libGDX移植20年前的J2ME游戏《中国跳棋》</a>
</h1>
</header>
<div class="e-content article-entry" itemprop="articleBody">
<!-- 背景介绍
下载游戏jar包
使用microemulator运行原版游戏
使用cfr反编译出Java代码
尝试理解源代码逻辑,同时对源代码优化可读性
基于libGDX框架重写代码,都是Java -->
<h3 id="背景介绍"><a href="#背景介绍" class="headerlink" title="背景介绍"></a>背景介绍</h3><p>暑假闲来无事,我在家中无意翻找到了自己使用的第一部触屏手机,是一个Samsung Anycall手机,由于电池老化的原因,我无法再次打开这个手机了。十年前我还是个小学生,智能手机并不普及,对于这第一个触屏手机也是非常有新鲜感,什么都想玩一下。其中最为印象深刻的就是一个跳棋游戏,主人公需要和6个npc对战中国跳棋,最终通关游戏。由于是将近二十年前开发的老游戏,在互联网上完全无法查到游戏开发商的任何信息,这个游戏也不可能在现代的机器上运行了,想到这个,我有些心血来潮,想让这个童年吸引我的小游戏重新焕发一次生命力。</p>
<h3 id="查找游戏资源"><a href="#查找游戏资源" class="headerlink" title="查找游戏资源"></a>查找游戏资源</h3><p>我只记得这个游戏叫做《中国跳棋》,并且是十年前的Samsung手机内置的,于是在bilibili和抖音都搜索了一下,果然搜出了几个视频,都是展示在十几年前的手机上玩这个游戏的。从视频中我回忆起了一些关于这个游戏的具体信息,在互联网上进行了查找。不久我就在一个论坛(DOSPY论坛)上找到了这个游戏的相关资源:<a target="_blank" rel="noopener" href="https://www.dospy.wang/thread-9224-1-1.html">【稀有资源】中 国 跳 棋</a>,游戏的形式是一个jar包。</p>
<h3 id="使用模拟器运行J2ME游戏"><a href="#使用模拟器运行J2ME游戏" class="headerlink" title="使用模拟器运行J2ME游戏"></a>使用模拟器运行J2ME游戏</h3><p>十几年前按键手机和部分触屏手机上的很多游戏都是使用J2ME开发的,维基百科对于J2ME的介绍为:</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">Java ME以往称作J2ME(Java Platform, Micro Edition)是为机顶盒、移动电话和PDA之类嵌入式消费电子设备提供的Java语言平台,包括虚拟机和一系列标准化的Java API。它和Java SE、Java EE一起构成Java技术的三大版本,并且同样是通过JCP(Java Community Process)制订的。</span><br></pre></td></tr></table></figure>
<p>J2ME是一个过时的框架,使用其开发的游戏自然无法在现代的操作系统上运行。因此,需要使用模拟器运行游戏的jar包。手机端可以选择<a target="_blank" rel="noopener" href="https://github.com/nikita36078/J2ME-Loader">J2ME Loader</a>,电脑端可以选择<a target="_blank" rel="noopener" href="https://sourceforge.net/projects/microemulator/">microemulator</a>。<br>我使用microemulator运行原版游戏,部分界面如下:</p>
<div style="display: flex; justify-content: space-between;">
<img src="images/Screenshot_20240825_213323.png" alt="alt text" style="width: 45%;">
<img src="images/Screenshot_20240825_213354.png" alt="alt text" style="width: 45%;">
</div>
<h3 id="解包游戏并反编译"><a href="#解包游戏并反编译" class="headerlink" title="解包游戏并反编译"></a>解包游戏并反编译</h3><p>从DOSPY论坛上下载的jar包其实就是一个zip压缩文件,在Linux中,可通过unzip命令解压缩到指定目录extracted: </p>
<figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">unzip your-file.jar -d extracted/</span><br></pre></td></tr></table></figure>
<p>进入extracted目录,可看到包含Java的.class文件和资源文件(图片、音频)<br><img src="/images/Screenshot_20240825_214045.png" alt="alt text"><br>与C/C++程序不同的是,Java编译出的.class字节码非常容易被反编译为Java代码,所以通常开发者会对代码进行混淆,使得其可读性下降,难以被破解。<br>我使用<a target="_blank" rel="noopener" href="https://github.com/leibnitz27/cfr">CFR工具</a>反编译字节码,当然也有很多其他的工具。<br>CFR工具本身也是一个jar文件,反编译单个字节码文件:</p>
<figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">java -jar cfr.jar target.jar > target.java</span><br></pre></td></tr></table></figure>
<p>在Linux中,使用find命令,将extracted目录下所有的.class文件都反编译为.java文件:</p>
<figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">find extracted/ -name <span class="string">"*.class"</span> -<span class="built_in">exec</span> java -jar cfr.jar {} --outputdir extracted \;</span><br></pre></td></tr></table></figure>
<h3 id="阅读源代码"><a href="#阅读源代码" class="headerlink" title="阅读源代码"></a>阅读源代码</h3><p>幸运的是,本游戏的代码并没有过度混淆,不幸的是,即使反编译为Java源代码,我也不可能在我的机器上运行这些代码,只能阅读代码,同时借助Copilot加速理解代码。<br>虽然代码的结构清晰,但是由于代码量较大,我花了整整两天时间理解整个游戏的代码逻辑,由于篇幅限制,只能说几个较为重要的发现。</p>
<h4 id="整型常量被大量使用"><a href="#整型常量被大量使用" class="headerlink" title="整型常量被大量使用"></a>整型常量被大量使用</h4><p>代码中整型常量被大量使用,例如:</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">BoardView</span></span><br><span class="line"> <span class="keyword">implements</span> <span class="title class_">XTimerListener</span>,</span><br><span class="line"> Viewable {</span><br><span class="line"> <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">final</span> <span class="type">int</span> <span class="variable">GAMEREADY</span> <span class="operator">=</span> <span class="number">0</span>;</span><br><span class="line"> <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">final</span> <span class="type">int</span> <span class="variable">SELECTDIA</span> <span class="operator">=</span> <span class="number">1</span>;</span><br><span class="line"> <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">final</span> <span class="type">int</span> <span class="variable">MOVEDIA</span> <span class="operator">=</span> <span class="number">2</span>;</span><br><span class="line"> <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">final</span> <span class="type">int</span> <span class="variable">MOVINGDIA</span> <span class="operator">=</span> <span class="number">3</span>;</span><br><span class="line"> <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">final</span> <span class="type">int</span> <span class="variable">COMTHINK</span> <span class="operator">=</span> <span class="number">4</span>;</span><br><span class="line"> <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">final</span> <span class="type">int</span> <span class="variable">COMBO_MSG</span> <span class="operator">=</span> <span class="number">5</span>;</span><br><span class="line"> <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">final</span> <span class="type">int</span> <span class="variable">TIMEOUT_MSG</span> <span class="operator">=</span> <span class="number">6</span>;</span><br><span class="line"> <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">final</span> <span class="type">int</span> <span class="variable">CHANGETURN</span> <span class="operator">=</span> <span class="number">7</span>;</span><br><span class="line"> <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">final</span> <span class="type">int</span> <span class="variable">GAMEOVER</span> <span class="operator">=</span> <span class="number">8</span>;</span><br><span class="line"> <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">final</span> <span class="type">int</span> <span class="variable">VIEWRESULT</span> <span class="operator">=</span> <span class="number">9</span>;</span><br><span class="line"> <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">final</span> <span class="type">int</span> <span class="variable">NEXTROUND</span> <span class="operator">=</span> <span class="number">10</span>;</span><br><span class="line"> <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">final</span> <span class="type">int</span> <span class="variable">NEXTSTAGE</span> <span class="operator">=</span> <span class="number">11</span>;</span><br><span class="line"> <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">final</span> <span class="type">int</span> <span class="variable">READYTALK</span> <span class="operator">=</span> <span class="number">12</span>;</span><br><span class="line"> <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">final</span> <span class="type">int</span> <span class="variable">RETURNVSMENU</span> <span class="operator">=</span> <span class="number">13</span>;</span><br><span class="line"> <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">final</span> <span class="type">int</span> <span class="variable">GAMEFAILED</span> <span class="operator">=</span> <span class="number">14</span>;</span><br><span class="line"> <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">final</span> <span class="type">int</span> <span class="variable">COMMOVEDIA</span> <span class="operator">=</span> <span class="number">15</span>;</span><br><span class="line"> <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">final</span> <span class="type">int</span> <span class="variable">HOMEIN</span> <span class="operator">=</span> <span class="number">16</span>;</span><br><span class="line"></span><br><span class="line"> <span class="comment">//...</span></span><br><span class="line">}</span><br></pre></td></tr></table></figure>
<p>Java的枚举类型是在Java5引入的特性,在当时的Java2中还不存在。开发者具有良好的编程习惯,将这些枚举值都使用常量代替,避免了Magic Number。然而,Java编译器直接将这些常量编译成了整数,反编译后,并未保留常量的变量名,使得代码难以理解,例如:</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">if</span> (<span class="built_in">this</span>.state == <span class="number">12</span>) {</span><br><span class="line"> <span class="comment">// do something</span></span><br><span class="line">} <span class="keyword">else</span> <span class="keyword">if</span> (<span class="built_in">this</span>.state == <span class="number">0</span>) {</span><br><span class="line"> <span class="comment">// do something</span></span><br><span class="line">} <span class="keyword">else</span> <span class="keyword">if</span> (<span class="built_in">this</span>.state == <span class="number">1</span>) {</span><br><span class="line"> <span class="comment">// do something</span></span><br><span class="line">}</span><br></pre></td></tr></table></figure>
<p>如果没有联系上述常量的定义,确实难以理解这些分支的语义,因此,我在阅读这些代码时,还原了这些常量,使得代码更易于理解。</p>
<h4 id="适配不同的屏幕大小"><a href="#适配不同的屏幕大小" class="headerlink" title="适配不同的屏幕大小"></a>适配不同的屏幕大小</h4><p>即使是二十年前的代码,也对不同型号的手机屏幕进行了适配:</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title function_">checkScreenSize</span><span class="params">()</span> {</span><br><span class="line"> <span class="keyword">if</span> (totalWidth > <span class="number">118</span> && totalWidth < <span class="number">122</span>) {</span><br><span class="line"> lcdSize = <span class="number">3</span>;</span><br><span class="line"> } <span class="keyword">else</span> <span class="keyword">if</span> (totalWidth > <span class="number">174</span> && totalWidth < <span class="number">178</span>) {</span><br><span class="line"> lcdSize = <span class="number">2</span>;</span><br><span class="line"> } <span class="keyword">else</span> <span class="keyword">if</span> (totalWidth > <span class="number">238</span> && totalWidth < <span class="number">242</span>) {</span><br><span class="line"> lcdSize = totalHeight > <span class="number">180</span> ? <span class="number">1</span> : <span class="number">2</span>;</span><br><span class="line"> } <span class="keyword">else</span> <span class="keyword">if</span> (totalWidth > <span class="number">319</span> && totalWidth < <span class="number">321</span>) {</span><br><span class="line"> lcdSize = <span class="number">4</span>;</span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">static</span> <span class="type">boolean</span> <span class="title function_">isQVGA</span><span class="params">()</span> {</span><br><span class="line"> <span class="keyword">return</span> lcdSize == <span class="number">1</span> || lcdSize == <span class="number">4</span>;</span><br><span class="line">}</span><br></pre></td></tr></table></figure>
<p>我专门查了一下QVGA屏幕的含义:</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">QVGA images or videos are 320 pixels wide and 240 pixels tall (320 x 240 pixels). The name Quarter VGA is written as QVGA and the resolution is four times smaller than VGA resolution (640 x 480 pixels).</span><br></pre></td></tr></table></figure>
<h4 id="存在性能优化的代码写法"><a href="#存在性能优化的代码写法" class="headerlink" title="存在性能优化的代码写法"></a>存在性能优化的代码写法</h4><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br></pre></td><td class="code"><pre><span class="line"><span class="type">int</span> <span class="title function_">computeMoveGuide</span><span class="params">(<span class="type">int</span> n)</span> {</span><br><span class="line"> <span class="type">byte</span> <span class="variable">by</span> <span class="operator">=</span> <span class="built_in">this</span>.dia[n].posx;</span><br><span class="line"> <span class="type">byte</span> <span class="variable">by2</span> <span class="operator">=</span> <span class="built_in">this</span>.dia[n].posy;</span><br><span class="line"> <span class="type">int</span> <span class="variable">n2</span> <span class="operator">=</span> <span class="number">0</span>;</span><br><span class="line"> <span class="keyword">if</span> (<span class="built_in">this</span>.moveCnt > <span class="number">0</span> && <span class="built_in">this</span>.jumpMove == <span class="number">0</span>) {</span><br><span class="line"> <span class="built_in">this</span>.possibleDirCnt = <span class="number">0</span>;</span><br><span class="line"> <span class="keyword">for</span> (<span class="type">int</span> <span class="variable">i</span> <span class="operator">=</span> <span class="number">0</span>; i < <span class="number">6</span>; ++i) {</span><br><span class="line"> <span class="built_in">this</span>.moveGuide[i] = <span class="number">0</span>;</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">for</span> (<span class="type">int</span> <span class="variable">i</span> <span class="operator">=</span> <span class="number">0</span>; i < <span class="number">6</span>; ++i) {</span><br><span class="line"> <span class="built_in">this</span>.moveGuide[i] = <span class="number">0</span>;</span><br><span class="line"> <span class="built_in">this</span>.moveGuide[i] = <span class="built_in">this</span>.diaBoard.checkBoard(<span class="built_in">this</span>.index, by + Resource.hInc[i], by2 + Resource.vInc[i]);</span><br><span class="line"> <span class="keyword">if</span> (<span class="built_in">this</span>.moveGuide[i] == <span class="number">2</span>) {</span><br><span class="line"> <span class="built_in">this</span>.moveGuide[i] = <span class="built_in">this</span>.diaBoard.checkBoard(<span class="built_in">this</span>.index, by + Resource.hInc[i] * <span class="number">2</span>, by2 + Resource.vInc[i] * <span class="number">2</span>);</span><br><span class="line"> <span class="built_in">this</span>.moveGuide[i] = <span class="built_in">this</span>.moveGuide[i] == <span class="number">1</span> ? <span class="number">2</span> : <span class="number">0</span>;</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">if</span> (<span class="built_in">this</span>.jumpMove > <span class="number">0</span> && <span class="built_in">this</span>.moveGuide[i] == <span class="number">1</span>) {</span><br><span class="line"> <span class="built_in">this</span>.moveGuide[i] = <span class="number">0</span>;</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">if</span> (<span class="built_in">this</span>.moveGuide[i] == <span class="number">0</span>) <span class="keyword">continue</span>;</span><br><span class="line"> ++n2;</span><br><span class="line"> }</span><br><span class="line"> <span class="built_in">this</span>.possibleDirCnt = n2;</span><br><span class="line"> <span class="keyword">return</span> n2;</span><br><span class="line">}</span><br></pre></td></tr></table></figure>
<p>在<code>computeMoveGuide</code>的for循环中,使用n2这个局部变量进行累加计算,最终将n2的值赋值给this.possibleDirCnt,而并没有将this.possibleDirCnt直接进行累加。this.possibleDirCnt是一个类的成员变量,存储在堆内存内,而n2是一个局部变量,可以被放在寄存器中,操作n2只需要读写寄存器,比读写堆内存快得多,这对于十几年前的手机来说应该是有性能的提升。</p>
<h3 id="使用libGDX重写游戏代码"><a href="#使用libGDX重写游戏代码" class="headerlink" title="使用libGDX重写游戏代码"></a>使用libGDX重写游戏代码</h3><p>经过一个上午的了解,我选择了libGDX框架,对J2ME游戏进行移植,主要原因有几点:</p>
<ul>
<li>编程语言相同:libGDX和J2ME都是使用Java开发,游戏核心算法部分不需要任何改动,只需要修改各种调用的库即可。</li>
<li>跨平台:不仅Java语言本身跨平台,libGDX框架也是跨平台的,支持桌面端(Windows, MacOS, Linux)和移动端(Android, iOS)</li>
<li>运行高效:libGDX本身对性能做了一定的优化。</li>
</ul>
<p>具体的游戏移植过程技术难度并不高,只是比较繁琐,需要同时关注移植前后接口的变化,主要包括:</p>
<ul>
<li>绘制场景的框架不同:J2ME使用<code>javax.microedition.lcdui.Graphics</code>绘制图像,而libGDX使用<code>SpriteBatch</code>和<code>Stage</code>绘制图像和UI,同时,二者的坐标系统完全不同,需要进行坐标变换。</li>
<li>动画播放的框架不同:J2ME使用逐帧绘制的方式绘制动画,每个动画需要使用多个状态成员来记录动画播放的阶段,代码量较大且难以理解,而libGDX使用<code>Action</code>来定义和绘制动画,内置了很多基本动画,编码较为简单可读。</li>
<li>响应事件的逻辑不通:J2ME使用了大量嵌套分支语句对于用户的按键编写对于用户按键的响应逻辑,而libGDX可以使用类似回调函数的方式定义事件的响应逻辑。</li>
<li>播放音效的框架不同。</li>
</ul>
<h3 id="移植代码仓库"><a href="#移植代码仓库" class="headerlink" title="移植代码仓库"></a>移植代码仓库</h3><p>现阶段已经完成了故事模式6关的核心部分,已经可以和20年前的AI完跳棋了,与原版游戏对比如图:</p>
<p><img src="/images/origin_ported.png" alt="alt text"></p>
<p>其中左侧为原版,右侧为移植版(可以看到较为简陋)</p>
<p>视频演示在Bilibili: </p>
<p><a target="_blank" rel="noopener" href="https://www.bilibili.com/video/BV1KDWZetEg4/?share_source=copy_web&vd_source=70024a5eb82a8b6b82eac10977ce41b8">https://www.bilibili.com/video/BV1KDWZetEg4/?share_source=copy_web&vd_source=70024a5eb82a8b6b82eac10977ce41b8</a></p>
<p>我将代码开源在了Github和Gitee,持续更新中:</p>
<p><a target="_blank" rel="noopener" href="https://github.com/creeper12356/ChineseCheckerPorted">https://github.com/creeper12356/ChineseCheckerPorted</a></p>
<p><a target="_blank" rel="noopener" href="https://gitee.com/creeper12356/ChineseCheckerPorted">https://gitee.com/creeper12356/ChineseCheckerPorted</a></p>
<p>欢迎共同交流学习!</p>
</div>
<footer class="article-footer">
<a data-url="http://example.com/2024/08/25/%E4%BD%BF%E7%94%A8libGDX%E7%A7%BB%E6%A4%8D20%E5%B9%B4%E5%89%8D%E7%9A%84J2ME%E6%B8%B8%E6%88%8F%E3%80%8A%E4%B8%AD%E5%9B%BD%E8%B7%B3%E6%A3%8B%E3%80%8B/" data-id="cm09o8rek0000dr1r2rej24zm" data-title="使用libGDX移植20年前的J2ME游戏《中国跳棋》" class="article-share-link"><span class="fa fa-share">Teilen</span></a>
</footer>
</div>
</article>
<article id="post-Linux切换java版本" class="h-entry article article-type-post" itemprop="blogPost" itemscope itemtype="https://schema.org/BlogPosting">
<div class="article-meta">
<a href="/2024/08/18/Linux%E5%88%87%E6%8D%A2java%E7%89%88%E6%9C%AC/" class="article-date">
<time class="dt-published" datetime="2024-08-18T13:51:20.000Z" itemprop="datePublished">2024-08-18</time>
</a>
</div>
<div class="article-inner">
<header class="article-header">
<h1 itemprop="name">
<a class="p-name article-title" href="/2024/08/18/Linux%E5%88%87%E6%8D%A2java%E7%89%88%E6%9C%AC/">Linux切换java版本</a>
</h1>
</header>
<div class="e-content article-entry" itemprop="articleBody">
<p>Linux系统中同时安装了多个版本的Java,可以使用update-alternatives命令来切换默认的Java版本。以下是具体的步骤:</p>
<p>打开终端,输入:</p>
<figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">sudo</span> update-alternatives --config java</span><br></pre></td></tr></table></figure>
<p>这将列出系统中所有可用的Java版本。<br>在提示选择版本的列表中,输入想要设为默认的Java版本对应的数字,然后按回车,即可切换默认的java版本。</p>
</div>
<footer class="article-footer">
<a data-url="http://example.com/2024/08/18/Linux%E5%88%87%E6%8D%A2java%E7%89%88%E6%9C%AC/" data-id="clzzmp7tf0000441rewwp8z05" data-title="Linux切换java版本" class="article-share-link"><span class="fa fa-share">Teilen</span></a>
</footer>
</div>
</article>
<article id="post-使用Spring-Cloud-Feign构建声明式客户端" class="h-entry article article-type-post" itemprop="blogPost" itemscope itemtype="https://schema.org/BlogPosting">
<div class="article-meta">
<a href="/2024/07/26/%E4%BD%BF%E7%94%A8Spring-Cloud-Feign%E6%9E%84%E5%BB%BA%E5%A3%B0%E6%98%8E%E5%BC%8F%E5%AE%A2%E6%88%B7%E7%AB%AF/" class="article-date">
<time class="dt-published" datetime="2024-07-26T02:20:50.000Z" itemprop="datePublished">2024-07-26</time>
</a>
</div>
<div class="article-inner">
<header class="article-header">
<h1 itemprop="name">
<a class="p-name article-title" href="/2024/07/26/%E4%BD%BF%E7%94%A8Spring-Cloud-Feign%E6%9E%84%E5%BB%BA%E5%A3%B0%E6%98%8E%E5%BC%8F%E5%AE%A2%E6%88%B7%E7%AB%AF/">使用Spring Cloud Feign构建声明式客户端</a>
</h1>
</header>
<div class="e-content article-entry" itemprop="articleBody">
<p>在使用Spring Boot开发微服务后端时,有时需要向其他微服务发起HTTP请求。如果使用传统的RestTemplate方法,先构造HTTP请求,再解析返回的HTTP响应,会产生很多冗余代码,降低项目的可读性。Spring Cloud Feign可以很好地解决这个问题。Feign是一种声明式、模板化的HTTP客户端,开发者只需要定义接口,便可以向调用本地方法一样调用远程接口,非常简洁方便。<br>此处Spring Boot项目使用maven构建,在<code>pom.xml</code>中加入依赖并安装:</p>
<figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag"><<span class="name">dependency</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">groupId</span>></span>org.springframework.cloud<span class="tag"></<span class="name">groupId</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">artifactId</span>></span>spring-cloud-starter-openfeign<span class="tag"></<span class="name">artifactId</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">version</span>></span>4.1.1<span class="tag"></<span class="name">version</span>></span></span><br><span class="line"><span class="tag"></<span class="name">dependency</span>></span></span><br></pre></td></tr></table></figure>
<p>在Spring Boot的主文件中加入<code>@EnableFeignClients</code>注解:</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@SpringBootApplication</span></span><br><span class="line"><span class="meta">@EnableFeignClients</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">UniGptBotServiceApplication</span> {</span><br><span class="line"></span><br><span class="line"> <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title function_">main</span><span class="params">(String[] args)</span> {</span><br><span class="line"> SpringApplication.run(UniGptBotServiceApplication.class, args);</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line">}</span><br></pre></td></tr></table></figure>
<p>创建一个<code>client</code>目录,用于放置所有Feign客户端类,例如,我需要向微服务<code>user-service</code>发送远程请求,则创建一个<code>UserServiceClient</code>类:</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> com.unigpt.bot.client;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> org.springframework.cloud.openfeign.FeignClient;</span><br><span class="line"><span class="keyword">import</span> org.springframework.stereotype.Component;</span><br><span class="line"><span class="keyword">import</span> org.springframework.web.bind.annotation.DeleteMapping;</span><br><span class="line"><span class="keyword">import</span> org.springframework.web.bind.annotation.PathVariable;</span><br><span class="line"><span class="keyword">import</span> org.springframework.web.bind.annotation.RequestHeader;</span><br><span class="line"></span><br><span class="line"><span class="meta">@Component</span></span><br><span class="line"><span class="meta">@FeignClient(name = "user-service", url = "http://localhost:8082/internal")</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">interface</span> <span class="title class_">UserServiceClient</span> {</span><br><span class="line"></span><br><span class="line"> <span class="meta">@DeleteMapping("/users/used-bots/{botId}")</span></span><br><span class="line"> <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">deleteBotFromUsedList</span><span class="params">(</span></span><br><span class="line"><span class="params"> <span class="meta">@PathVariable</span> Integer botId,</span></span><br><span class="line"><span class="params"> <span class="meta">@RequestHeader(name = "X-User-Id")</span> Integer userId)</span>;</span><br><span class="line">}</span><br></pre></td></tr></table></figure>
<p>此处,我们定义了<code>UserServiceClient</code>接口,<code>@FeignClient</code>注解定义了服务的<strong>名称</strong>和<strong>url</strong>,接口的函数定义与controller类似,可以使用注解规定路径参数、请求参数、请求头、请求体信息。Feign会根据定义的接口和注解自动生成实现。</p>
<p>定义完客户端接口类后,依赖注入<code>UserServiceClient</code>类,即可使用<code>deleteBotFromUsedList</code>方法,像调用本地方法一样调用远程服务。</p>
</div>
<footer class="article-footer">
<a data-url="http://example.com/2024/07/26/%E4%BD%BF%E7%94%A8Spring-Cloud-Feign%E6%9E%84%E5%BB%BA%E5%A3%B0%E6%98%8E%E5%BC%8F%E5%AE%A2%E6%88%B7%E7%AB%AF/" data-id="clz22sxqd0000bt1r1p6c588x" data-title="使用Spring Cloud Feign构建声明式客户端" class="article-share-link"><span class="fa fa-share">Teilen</span></a>
</footer>
</div>
</article>
<article id="post-测试发布文章" class="h-entry article article-type-post" itemprop="blogPost" itemscope itemtype="https://schema.org/BlogPosting">
<div class="article-meta">
<a href="/2024/07/07/%E6%B5%8B%E8%AF%95%E5%8F%91%E5%B8%83%E6%96%87%E7%AB%A0/" class="article-date">
<time class="dt-published" datetime="2024-07-07T08:41:39.000Z" itemprop="datePublished">2024-07-07</time>
</a>
</div>
<div class="article-inner">
<header class="article-header">
<h1 itemprop="name">
<a class="p-name article-title" href="/2024/07/07/%E6%B5%8B%E8%AF%95%E5%8F%91%E5%B8%83%E6%96%87%E7%AB%A0/">测试发布文章</a>
</h1>
</header>
<div class="e-content article-entry" itemprop="articleBody">
<h1 id="Creeper-Blog-测试发布文章"><a href="#Creeper-Blog-测试发布文章" class="headerlink" title="Creeper Blog 测试发布文章"></a>Creeper Blog 测试发布文章</h1><p>测试内容</p>
</div>
<footer class="article-footer">
<a data-url="http://example.com/2024/07/07/%E6%B5%8B%E8%AF%95%E5%8F%91%E5%B8%83%E6%96%87%E7%AB%A0/" data-id="clybb1zya00007s1r3j5e1ov4" data-title="测试发布文章" class="article-share-link"><span class="fa fa-share">Teilen</span></a>
</footer>
</div>
</article>
</section>
<aside id="sidebar">
<div class="widget-wrap">
<h3 class="widget-title">Archiv</h3>
<div class="widget">
<ul class="archive-list"><li class="archive-list-item"><a class="archive-list-link" href="/archives/2024/10/">October 2024</a></li><li class="archive-list-item"><a class="archive-list-link" href="/archives/2024/08/">August 2024</a></li><li class="archive-list-item"><a class="archive-list-link" href="/archives/2024/07/">July 2024</a></li></ul>
</div>
</div>
<div class="widget-wrap">
<h3 class="widget-title">letzter Beitrag</h3>
<div class="widget">
<ul>
<li>
<a href="/2024/10/27/%E8%A7%A3%E5%86%B3Windows%E4%B8%8Bzip%E5%8E%8B%E7%BC%A9%E5%8C%85%E5%9C%A8Linux%E4%B8%8B%E8%A7%A3%E5%8E%8B%E4%B9%B1%E7%A0%81%E9%97%AE%E9%A2%98/">解决Windows下zip压缩包在Linux下解压乱码问题</a>
</li>
<li>
<a href="/2024/08/25/%E4%BD%BF%E7%94%A8libGDX%E7%A7%BB%E6%A4%8D20%E5%B9%B4%E5%89%8D%E7%9A%84J2ME%E6%B8%B8%E6%88%8F%E3%80%8A%E4%B8%AD%E5%9B%BD%E8%B7%B3%E6%A3%8B%E3%80%8B/">使用libGDX移植20年前的J2ME游戏《中国跳棋》</a>
</li>
<li>
<a href="/2024/08/18/Linux%E5%88%87%E6%8D%A2java%E7%89%88%E6%9C%AC/">Linux切换java版本</a>
</li>
<li>
<a href="/2024/07/26/%E4%BD%BF%E7%94%A8Spring-Cloud-Feign%E6%9E%84%E5%BB%BA%E5%A3%B0%E6%98%8E%E5%BC%8F%E5%AE%A2%E6%88%B7%E7%AB%AF/">使用Spring Cloud Feign构建声明式客户端</a>
</li>
<li>
<a href="/2024/07/07/%E6%B5%8B%E8%AF%95%E5%8F%91%E5%B8%83%E6%96%87%E7%AB%A0/">测试发布文章</a>
</li>
</ul>
</div>
</div>
</aside>
</div>
<footer id="footer">
<div class="outer">
<div id="footer-info" class="inner">
© 2024 creeper12356<br>
Powered by <a href="https://hexo.io/" target="_blank">Hexo</a>
</div>
</div>
</footer>
</div>
<nav id="mobile-nav">
<a href="/" class="mobile-nav-link">Home</a>
<a href="/archives" class="mobile-nav-link">Archives</a>
</nav>
<script src="/js/jquery-3.6.4.min.js"></script>
<script src="/fancybox/jquery.fancybox.min.js"></script>
<script src="/js/script.js"></script>
</div>
</body>
</html>