<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
<title type="text">九天雁翎的博客</title>
<generator uri="https://github.com/mojombo/jekyll">Jekyll</generator>
<link rel="self" type="application/atom+xml" href="https://www.jtianling.com/feed.xml" />
<link rel="alternate" type="text/html" href="https://www.jtianling.com" />
<updated>2026-03-14T22:29:21+08:00</updated>
<id>https://www.jtianling.com/</id>
<author>
  <name></name>
  <uri>https://www.jtianling.com/</uri>
  <email></email>
</author>


<entry>
  <title type="html"><![CDATA[只给 Spec, 不给代码: 也许这会成为一种新的软件发布方式]]></title>
 <link rel="alternate" type="text/html" href="https://www.jtianling.com/spec-first-software-release.html" />
  <id>https://www.jtianling.com/spec-first-software-release</id>
  <published>2026-03-14T21:52:56+08:00</published>
  <updated>2026-03-14T21:52:56+08:00</updated>
  <author>
    <name></name>
    <uri>https://www.jtianling.com</uri>
    <email></email>
  </author>
  <content type="html">&lt;p&gt;最近看到 &lt;a href=&quot;https://github.com/openai/symphony&quot;&gt;openai/symphony&lt;/a&gt; 这个项目, 我第一反应不是”这个实现我想试试”, 而是”这个发布方式有点意思”.&lt;/p&gt;

&lt;p&gt;因为它在 README 里给出的第一个选项, 不是先教你怎么安装官方实现, 而是先让你根据 &lt;a href=&quot;https://github.com/openai/symphony/blob/main/SPEC.md&quot;&gt;SPEC.md&lt;/a&gt; 自己做一个. 官方当然也附了一个实验性的 Elixir 参考实现, 但那个被放在了第二个选项. 这个顺序本身就很说明问题: openai 真正想先传递出去的, 可能不是某一份具体代码, 而是这套系统的设计.&lt;/p&gt;

&lt;p&gt;我感觉这件事情挺值得记一下. 随着 code agent 越来越强, 以后有些软件的”发布”, 也许真的不一定非得先附带一份完整源码, 而是可以先给出一份足够明确的 spec, 让大家各自用自己熟悉的语言和运行环境去实现. 代码还是会有, 但它开始更像是 spec 的一个实例, 而不是唯一的交付物.&lt;/p&gt;

&lt;!-- more --&gt;

&lt;h3 id=&quot;为什么我会觉得这件事很有意思&quot;&gt;为什么我会觉得这件事很有意思&lt;/h3&gt;

&lt;p&gt;以前我们看到一个开源项目, 默认的理解通常是: 仓库里的源码就是产品本体, 文档只是帮助你理解和使用它. 就算一个项目有协议, 语言标准或者设计文档, 大多数时候也是配角.&lt;/p&gt;

&lt;p&gt;但 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Symphony&lt;/code&gt; 这次给我的感觉不太一样. 它的 README 直接把 “Option 1. Make your own” 放在前面, 然后指向那份很长的 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;SPEC.md&lt;/code&gt;. 这就不是”如果你有兴趣, 也可以看看设计文档”了, 而是很明确地把”按照这个 spec 自己实现”当成一个正式的入口.&lt;/p&gt;

&lt;p&gt;这个姿态变化挺有意思的. 因为它隐含着一个新前提: 对一部分软件来说, “实现” 这件事情本身正在变便宜, 便宜到作者已经可以默认读者不一定非得使用官方代码, 也可以直接把作者的思想搬到自己熟悉的技术栈里.&lt;/p&gt;

&lt;p&gt;虽然吧, openai 还能通过这种方式让你消耗多一点的 Token, 一举两得.&lt;/p&gt;

&lt;h3 id=&quot;为什么这件事在今天开始成立&quot;&gt;为什么这件事在今天开始成立&lt;/h3&gt;

&lt;p&gt;我觉得最核心的变量, 还是 code agent 变强了.&lt;/p&gt;

&lt;p&gt;如果放在前些年, “你自己照着 spec 实现一个” 这句话听起来更像玩笑. 因为哪怕 spec 写得再清楚, 从文档到工程代码之间, 还是隔着大量机械而繁琐的实现劳动. 很多人不是不理解设计, 而是没有精力把它完整落出来.&lt;/p&gt;

&lt;p&gt;但现在情况已经开始不一样了. 尤其像 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Symphony&lt;/code&gt; 这种项目, 它的核心价值其实并不在某个特别难复现的底层算法, 而是在一套系统边界划分和工作流设计上: 问题是什么, 目标是什么, 有哪些核心组件, 域模型是什么, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;WORKFLOW.md&lt;/code&gt; 这种仓库内契约怎么组织, 配置怎么解析, agent runner 和 issue tracker 怎么配合. 这些东西一旦写进 spec, 就已经把最重要的”思想骨架”交代得差不多了.&lt;/p&gt;

&lt;p&gt;剩下的代码, 很多时候更像是把这份骨架翻译成某一种语言和工程风格. 而”翻译” 这件事情, 恰恰是 code agent 现在越来越擅长做的.&lt;/p&gt;

&lt;h3 id=&quot;这和以前的标准还不太一样&quot;&gt;这和以前的”标准”还不太一样&lt;/h3&gt;

&lt;p&gt;当然, “先有规范, 后有实现” 并不是什么新鲜事. 协议, 语言标准, 文件格式标准, 以前一直都有. 但我觉得这次不太一样的地方在于, 它不是某个成熟生态经过多年沉淀以后, 再慢慢整理出一份标准文档.&lt;/p&gt;

&lt;p&gt;它更像是一开始就在把 spec 当成第一交付物.&lt;/p&gt;

&lt;p&gt;而且这里还多了一个以前没有那么强的前提: 发布者已经可以合理假设, 读者身边有一个足够能干的 coding agent, 可以把 spec 迅速翻成一个能跑的版本. 也就是说, 这份 spec 面向的, 并不只是耐心读文档的人类工程师, 还面向一个随时可以开工的实现代理.&lt;/p&gt;

&lt;p&gt;这就让 “spec” 从过去那种偏静态, 偏归档的文档, 变成了一种可以被直接执行的发布介质.&lt;/p&gt;

&lt;h3 id=&quot;我觉得以后可能会出现什么&quot;&gt;我觉得以后可能会出现什么&lt;/h3&gt;

&lt;p&gt;我现在越来越觉得, 以后有一类软件项目, 可能真的会逐渐走向这种 “spec-first” 的发布方式.&lt;/p&gt;

&lt;p&gt;也就是作者发布的核心内容会变成:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;一份足够明确的 spec&lt;/li&gt;
  &lt;li&gt;一份说明系统边界和约束的工作流/提示词&lt;/li&gt;
  &lt;li&gt;一组可以验证行为的测试或者样例&lt;/li&gt;
  &lt;li&gt;也许再附一个参考实现, 但它不一定是唯一实现&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;然后使用者这边, 就不再只是 “git clone 然后跑起来”, 而是”把 spec 交给我自己的 agent, 让它按我熟悉的语言, 框架, 部署方式生成一个版本”.&lt;/p&gt;

&lt;p&gt;这件事的好处其实不少.&lt;/p&gt;

&lt;p&gt;第一, 不同团队可以更自然地贴合自己的技术栈. 有人想用 Elixir, 有人想用 Go, 有人想用 Rust, 有人甚至只想把核心思想吸收到自己现有系统里, 都不必被官方实现绑定得太死.&lt;/p&gt;

&lt;p&gt;第二, 作者传播的重点会从”这一份代码”转向”这一套设计”. 这样的话, 项目的影响力有时候反而可能更大, 因为别人采纳的不只是仓库, 而是背后的方法论.&lt;/p&gt;

&lt;p&gt;第三, 对很多 agent 时代的新工具来说, 参考实现的寿命未必像以前那么重要. 真正持久的, 可能是 spec, 测试和工作流约束; 具体代码则可以不断被本地化, 重写, 替换.&lt;/p&gt;

&lt;h3 id=&quot;当然-这也不是所有软件都适合&quot;&gt;当然, 这也不是所有软件都适合&lt;/h3&gt;

&lt;p&gt;不过我觉得这条路也不是哪里都能用.&lt;/p&gt;

&lt;p&gt;如果一个项目的核心价值在于非常细致的性能优化, 极重的工程积累, 某种很难被文字完全描述的交互体验, 那么光有 spec 显然不够. 还有一些东西, 比如模型权重, 特定训练结果, 特定数据集加工产物, 也不是”给个 spec 就能自己做一个”的.&lt;/p&gt;

&lt;p&gt;所以更可能先变成 spec-first 的, 我猜会是这几类东西:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;orchestration / workflow 类工具&lt;/li&gt;
  &lt;li&gt;协议和服务胶水层&lt;/li&gt;
  &lt;li&gt;很多企业内部其实只想落地思想, 不一定执着于官方实现的系统&lt;/li&gt;
  &lt;li&gt;本来就很强调 contract 的基础设施组件&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;另外, 如果真的要让 spec 变成主要交付物, 我觉得以后还得配套更多东西, 比如 conformance test, 标准样例输入输出, 甚至针对 agent 的实现提示. 不然 spec 写得再长, 不同实现之间还是很容易漂.&lt;/p&gt;

&lt;h3 id=&quot;一个我觉得很新鲜的变化&quot;&gt;一个我觉得很新鲜的变化&lt;/h3&gt;

&lt;p&gt;以前 Linus Torvalds 说 “talk is cheap, show me the code”. 这句话放到今天可能就不太对了. 因为, “code is cheap”. 在 code agent 逐渐成熟以后, 也许会开始出现另一种情况: 真正稳定的部分不一定是某一份源码, 而是源码背后的 spec.&lt;/p&gt;

&lt;p&gt;源码变成了 spec 的一个瞬时投影, 可以用这个语言实现, 也可以用那个语言再实现一次; 可以今天这样组织, 明天换一套框架重写. 只要 spec 和行为约束还在, 作者真正想表达的东西就还在.&lt;/p&gt;

&lt;p&gt;如果真往这个方向发展, 那以后”发布一个软件”这件事情本身, 可能都会和今天不太一样. 发布的不只是代码, 而是设计, 是约束, 是一份足够清晰到可以让 agent 去继续生产代码的说明书.&lt;/p&gt;

&lt;p&gt;我觉得这件事挺有意思的. &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Symphony&lt;/code&gt; 当然还远远不是这个趋势的终点, 甚至它自己也仍然带着参考实现. 但至少它已经把一种以前不太像”正式发布方式”的东西, 很自然地摆到了台前.&lt;/p&gt;

  &lt;p&gt;&lt;a href=&quot;https://www.jtianling.com/spec-first-software-release.html&quot;&gt;只给 Spec, 不给代码: 也许这会成为一种新的软件发布方式&lt;/a&gt; was originally published by  at &lt;a href=&quot;https://www.jtianling.com&quot;&gt;九天雁翎的博客&lt;/a&gt; on March 14, 2026.&lt;/p&gt;</content>
</entry>


<entry>
  <title type="html"><![CDATA[Agent of Empires：一个基于 tmux 的 AI agent 会话管理器]]></title>
 <link rel="alternate" type="text/html" href="https://www.jtianling.com/agent-of-empires-intro.html" />
  <id>https://www.jtianling.com/agent-of-empires-intro</id>
  <published>2026-03-13T15:21:39+08:00</published>
  <updated>2026-03-13T15:21:39+08:00</updated>
  <author>
    <name></name>
    <uri>https://www.jtianling.com</uri>
    <email></email>
  </author>
  <content type="html">&lt;p&gt;最近一段时间，各种 AI coding agent 工具我都在试。试来试去以后，我越来越觉得，真正麻烦的往往不是模型本身，而是怎么把多个 agent 安排好：谁在什么分支上工作，谁在跑什么任务，当前是不是卡住了，要不要我去接管一下，关掉界面以后它是不是还在继续跑。这些事情如果全靠手工管理，agent 一多，很快就乱了。&lt;/p&gt;

&lt;p&gt;这两天看到一个我觉得挺有意思的工具：&lt;a href=&quot;https://github.com/njbrake/agent-of-empires&quot;&gt;Agent of Empires&lt;/a&gt;。名字起得很大，不过它做的事情倒是挺朴素：它不是重新造一整套“AI IDE”，而是站在 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;tmux&lt;/code&gt; 和 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;git worktree&lt;/code&gt; 这些已经很好用的基础设施上，做了一个专门给 AI agent 用的会话管理器。这个思路我很喜欢。&lt;/p&gt;

&lt;p&gt;仓库地址：&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;原版：&lt;a href=&quot;https://github.com/njbrake/agent-of-empires&quot;&gt;https://github.com/njbrake/agent-of-empires&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;我的 fork：&lt;a href=&quot;https://github.com/jtianling/agent-of-empires&quot;&gt;https://github.com/jtianling/agent-of-empires&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;!-- more --&gt;

&lt;h3 id=&quot;一句话说明&quot;&gt;一句话说明&lt;/h3&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Agent of Empires&lt;/code&gt; 可以理解成一个终端里的 AI agent 调度面板。它把不同 agent 跑在各自独立的 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;tmux session&lt;/code&gt; 里，并且可以结合 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;git worktree&lt;/code&gt; 同时在同一个项目的不同分支上开工。&lt;/p&gt;

&lt;h3 id=&quot;为什么我会觉得它有意思&quot;&gt;为什么我会觉得它有意思&lt;/h3&gt;

&lt;p&gt;现在做 AI 辅助编程，比较自然的一种工作方式，其实已经不是“我和一个 agent 一问一答”了，而是：&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;一个 agent 写功能&lt;/li&gt;
  &lt;li&gt;一个 agent 跑测试或者修 lint&lt;/li&gt;
  &lt;li&gt;一个 agent 只做 code review&lt;/li&gt;
  &lt;li&gt;还有一个 agent 去查文档或者整理思路&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;这种情况下，单纯开很多终端标签页也不是不行，但是很快就会碰到几个问题：目录容易乱，分支容易串，关掉窗口以后状态不好追，另外 agent 当前到底是在忙、在等、还是已经结束了，也不容易一眼看清。&lt;/p&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Agent of Empires&lt;/code&gt; 的思路就是把这些问题系统化处理掉。它的几个核心点我觉得比较实用：&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;基于 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;tmux&lt;/code&gt;，所以会话本身是持续存在的，关掉 TUI 以后 agent 也不会停&lt;/li&gt;
  &lt;li&gt;能结合 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;git worktree&lt;/code&gt;，让不同 agent 在不同分支上并行工作&lt;/li&gt;
  &lt;li&gt;有 TUI，也有 CLI，不一定非得全程待在界面里&lt;/li&gt;
  &lt;li&gt;可以看状态，也可以直接 attach 进去接管&lt;/li&gt;
  &lt;li&gt;还支持 Docker sandbox，这一点对于想把 agent 跑得更隔离一些的人也挺有吸引力&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;说白了，它不是去替代终端，而是把“同时管理很多个 agent 终端”这件事情做得更顺手。&lt;/p&gt;

&lt;h3 id=&quot;安装和最基本的用法&quot;&gt;安装和最基本的用法&lt;/h3&gt;

&lt;p&gt;原版 README 里给了几种安装方式，最简单的大概是这样：&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;curl &lt;span class=&quot;nt&quot;&gt;-fsSL&lt;/span&gt; &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
  https://raw.githubusercontent.com/njbrake/agent-of-empires/main/scripts/install.sh &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
  | bash
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;或者如果你用 Homebrew，也可以：&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;brew &lt;span class=&quot;nb&quot;&gt;install &lt;/span&gt;aoe
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;启动以后，最直接的用法就是：&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;aoe
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;另外它也支持直接从命令行加 session，比如：&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c&quot;&gt;# 在当前项目上加一个 session&lt;/span&gt;
aoe add &lt;span class=&quot;nb&quot;&gt;.&lt;/span&gt;

&lt;span class=&quot;c&quot;&gt;# 在新的 worktree / 分支上加一个 session&lt;/span&gt;
aoe add &lt;span class=&quot;nb&quot;&gt;.&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-w&lt;/span&gt; feat/my-feature &lt;span class=&quot;nt&quot;&gt;-b&lt;/span&gt;

&lt;span class=&quot;c&quot;&gt;# 用 sandbox 方式启动&lt;/span&gt;
aoe add &lt;span class=&quot;nt&quot;&gt;--sandbox&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;这个设计里面我最喜欢的一点，就是它没有把底层模型藏起来。底层还是 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;tmux&lt;/code&gt; session，所以真出了什么问题，你随时都可以 attach 进去看，不会有那种“界面一关，一切都变成黑盒”的感觉。&lt;/p&gt;

&lt;h3 id=&quot;它适合什么样的人&quot;&gt;它适合什么样的人&lt;/h3&gt;

&lt;p&gt;我觉得它尤其适合下面这类场景：&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;已经习惯终端工作流，至少不排斥 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;tmux&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;一个项目里会同时跑多个 AI agent&lt;/li&gt;
  &lt;li&gt;会认真使用 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;git worktree&lt;/code&gt; 或多分支并行开发&lt;/li&gt;
  &lt;li&gt;希望 agent 是长期运行的，而不是一次性问答式工具&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;反过来说，如果你平时本来就不怎么用终端，也不太愿意接受 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;tmux&lt;/code&gt; 这一层概念，那上手成本可能还是会觉得偏高一点。这个工具显然不是给“完全不想碰终端”的用户准备的。&lt;/p&gt;

&lt;h3 id=&quot;为什么我会把-aoe-本身运行在一个-tmux-里&quot;&gt;为什么我会把 aoe 本身运行在一个 tmux 里&lt;/h3&gt;

&lt;p&gt;我自己现在比较喜欢的一种用法，是不只是让 AoE 去管理里面那些 agent session，而是把 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;aoe&lt;/code&gt; 自己也放到一个外层的 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;tmux session&lt;/code&gt; 里跑。&lt;/p&gt;

&lt;p&gt;这样做的好处非常直接：假如我离开了工位，随便拿一个手机上的 SSH 客户端登录到自己的电脑，只需要 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;tmux attach&lt;/code&gt; 到那个跑着 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;aoe&lt;/code&gt; 的 session，就可以在手机上继续管理所有 coding agent。哪些 agent 还在跑，哪些在等输入，要不要 attach 进去接管，都会方便很多。&lt;/p&gt;

&lt;p&gt;对我来说，这种体验其实很有意思，因为它有点像一个更适合程序员的 OpenClaw。不是说界面更花哨，而是它本质上建立在 SSH、&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;tmux&lt;/code&gt;、终端这些程序员本来就天天在用的东西上，所以远程接管这件事情会显得特别自然。&lt;/p&gt;

&lt;p&gt;如果电脑本身是在内网里，也不是什么大问题。只要再配合一下 Tailscale 或者 Cloudflare WARP，手机连回自己电脑这件事情其实并不难。这样一来，不管人在不在工位前，整个 agent 工作台都还是可达的。&lt;/p&gt;

&lt;p&gt;原版 README 其实已经提到了移动端 SSH 客户端这种使用方式，不过我自己在实际这样用的时候，发现原版在这条工作流上还有一些 bug，尤其是 nested tmux 相关的 detach、鼠标和界面体验问题。我 fork 里把这些地方修掉以后，这种“手机上接回去管理 agent”的体验就顺很多了。&lt;/p&gt;

&lt;h3 id=&quot;我自己-fork-以后改了几处&quot;&gt;我自己 fork 以后改了几处&lt;/h3&gt;

&lt;p&gt;原版已经很好用了，不过我自己在用的时候，还是顺手改了几处更偏“日常体验”的问题。因为这些修改还没有写进 README，这里简单提一下重点。&lt;/p&gt;

&lt;p&gt;第一类是终端标题和状态可见性。我给它加了动态 terminal tab title，让 TUI、自身状态和 agent 状态能反映到终端标题上。对我来说最有用的是 Codex 这类工具等待用户输入的时候，更容易一眼看出来，而不用切进去挨个确认。&lt;/p&gt;

&lt;p&gt;第二类是 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;tmux&lt;/code&gt; 里的交互体验问题。比如 nested tmux 下的 detach 行为、鼠标滚轮被错误当成方向键、TUI flicker 之类，这些单独看都不算大功能，但是如果每天都在里面切来切去，其实非常影响体验。我 fork 里把这些地方顺手补了一遍。&lt;/p&gt;

&lt;p&gt;第三类是 profile 机制。原版更偏全局单实例，不管你在哪个目录里启动，管理的基本还是同一套 AoE 状态。我自己加了基于运行目录自动分配的 profile，这样不同项目可以分别管理各自的一组 agent，不容易混在一起。当然，如果你就是想强制共用同一个 profile，也还是支持通过命令或环境变量明确指定。&lt;/p&gt;

&lt;p&gt;第四类是 session 切换效率。我加了 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Ctrl+b j/k&lt;/code&gt; 在 agent session 之间切换，这样在同一个 profile 里来回看几个 agent 的时候，不一定非得先退回 TUI 再进下一个。这个改动不大，但是挺顺手。&lt;/p&gt;

&lt;h3 id=&quot;总的感觉&quot;&gt;总的感觉&lt;/h3&gt;

&lt;p&gt;我觉得 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Agent of Empires&lt;/code&gt; 最有价值的地方，不是它又支持了多少个模型，而是它抓住了一个很实际的问题：当 AI agent 从“偶尔用一下”变成“同时跑好几个”以后，真正需要管理的是会话、状态、隔离和上下文，而不是一个更花哨的聊天框。&lt;/p&gt;

&lt;p&gt;所以如果你本来就在终端里工作，也已经开始习惯用多个 agent 并行做事，那这个工具确实值得试一下。对我自己来说，它至少属于那种“看完 README 以后会想亲手装起来跑跑看”的工具，而不是看起来很酷、但落不到日常工作流里的那种。&lt;/p&gt;

  &lt;p&gt;&lt;a href=&quot;https://www.jtianling.com/agent-of-empires-intro.html&quot;&gt;Agent of Empires：一个基于 tmux 的 AI agent 会话管理器&lt;/a&gt; was originally published by  at &lt;a href=&quot;https://www.jtianling.com&quot;&gt;九天雁翎的博客&lt;/a&gt; on March 13, 2026.&lt;/p&gt;</content>
</entry>


<entry>
  <title type="html"><![CDATA[net-use 发布：监控 macOS app 实际访问了哪些 IP]]></title>
 <link rel="alternate" type="text/html" href="https://www.jtianling.com/net-use-release.html" />
  <id>https://www.jtianling.com/net-use-release</id>
  <published>2026-03-13T14:52:52+08:00</published>
  <updated>2026-03-13T14:52:52+08:00</updated>
  <author>
    <name></name>
    <uri>https://www.jtianling.com</uri>
    <email></email>
  </author>
  <content type="html">&lt;p&gt;有时候想给某个 app 配防火墙白名单, 最麻烦的不是配规则, 而是根本不知道它到底连了哪些地址. 而且现在很多 app 都不只是一个主进程, 还会拉起 helper, renderer, crash reporter 之类的子进程, 只盯着一个 PID 往往不够. 于是写了个小工具 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;net-use&lt;/code&gt;, 用来实时追踪指定 app 及其整个子进程树访问过的远端 IP, 并把结果去重输出出来.&lt;/p&gt;

&lt;p&gt;仓库地址：&lt;a href=&quot;https://github.com/jtianling/net-use&quot;&gt;https://github.com/jtianling/net-use&lt;/a&gt;&lt;/p&gt;

&lt;!-- more --&gt;

&lt;h3 id=&quot;一句话说明&quot;&gt;一句话说明&lt;/h3&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;net-use&lt;/code&gt; 是一个 macOS 上的应用网络连接监控工具. 它基于 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;proc_pidfdinfo&lt;/code&gt; 系统调用枚举 socket 信息, 能实时抓到指定 app 以及它的所有子进程访问过的 TCP/UDP 远端地址. 为了更适合防火墙白名单这个场景, IPv4 默认会聚合成 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/24&lt;/code&gt; 子网, IPv6 则保留完整地址.&lt;/p&gt;

&lt;h3 id=&quot;为什么做这个&quot;&gt;为什么做这个&lt;/h3&gt;

&lt;p&gt;我自己的需求很简单, 就是想知道一个 app 实际在访问什么地方, 并且把结果整理成一份后续可直接使用的白名单.&lt;/p&gt;

&lt;p&gt;如果只是临时看一下网络连接, 其实有很多工具能凑合用. 但是一旦要落到具体 app 上, 尤其是桌面 app 还会拉起很多子进程的时候, 事情就开始变麻烦了: 进程会变, PID 会变, 连接是动态出现的, 还要自己做去重. 所以干脆写了一个专门做这件事情的小工具.&lt;/p&gt;

&lt;h3 id=&quot;使用&quot;&gt;使用&lt;/h3&gt;

&lt;p&gt;安装:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;cargo &lt;span class=&quot;nb&quot;&gt;install &lt;/span&gt;net-use
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;最简单的用法是直接进入 TUI 模式:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nb&quot;&gt;sudo &lt;/span&gt;net-use
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;启动后可以浏览本机已安装 app, 输入文字筛选, 回车选中以后开始监控. 监控过程中支持导出到文件、复制到剪贴板、切换排序方式, 也可以在子网聚合显示和原始 IP 显示之间切换.&lt;/p&gt;

&lt;p&gt;如果你不想进界面, 也可以直接走 CLI:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c&quot;&gt;# 按 Bundle ID 监控&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;sudo &lt;/span&gt;net-use &lt;span class=&quot;nt&quot;&gt;--bundle&lt;/span&gt; com.google.Chrome &lt;span class=&quot;nt&quot;&gt;--no-tui&lt;/span&gt;

&lt;span class=&quot;c&quot;&gt;# 按进程名监控&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;sudo &lt;/span&gt;net-use &lt;span class=&quot;nt&quot;&gt;--name&lt;/span&gt; curl &lt;span class=&quot;nt&quot;&gt;--no-tui&lt;/span&gt;

&lt;span class=&quot;c&quot;&gt;# 按 PID 监控&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;sudo &lt;/span&gt;net-use &lt;span class=&quot;nt&quot;&gt;--pid&lt;/span&gt; 1234 &lt;span class=&quot;nt&quot;&gt;--no-tui&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;输出是去重后的地址列表, 例如:&lt;/p&gt;

&lt;div class=&quot;language-text highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;142.250.80.0/24
172.217.14.0/24
2607:f8b0:4004:800::200e
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;这样拿去做白名单就比较直接了.&lt;/p&gt;

&lt;h3 id=&quot;另外几个我觉得比较有用的点&quot;&gt;另外几个我觉得比较有用的点&lt;/h3&gt;

&lt;ul&gt;
  &lt;li&gt;支持监控尚未启动的 app, 检测到启动后自动开始采集&lt;/li&gt;
  &lt;li&gt;app 退出后历史数据不会丢, 下次再出现会继续累加&lt;/li&gt;
  &lt;li&gt;可以暂停/恢复监控&lt;/li&gt;
  &lt;li&gt;支持把历史结果持久化到文件&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;限制&quot;&gt;限制&lt;/h3&gt;

&lt;p&gt;这个工具目前只支持 macOS, 并且需要 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;sudo&lt;/code&gt;, 因为读取进程 socket 信息本身就需要权限.&lt;/p&gt;

&lt;p&gt;另外它是基于轮询实现的, 默认 200ms 一次, 所以生命周期特别短的连接理论上还是可能漏掉. 再有就是某些通过 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;launchd&lt;/code&gt; 拉起的 XPC service, 不一定能完全落在同一棵进程树里, 这也是目前的一个限制.&lt;/p&gt;

&lt;p&gt;总之, 如果你也有“一个 app 到底连了哪些 IP”这种需求, 可以试试看. 对我自己来说, 至少终于不用一边盯 Activity Monitor, 一边再手动整理白名单了.&lt;/p&gt;

  &lt;p&gt;&lt;a href=&quot;https://www.jtianling.com/net-use-release.html&quot;&gt;net-use 发布：监控 macOS app 实际访问了哪些 IP&lt;/a&gt; was originally published by  at &lt;a href=&quot;https://www.jtianling.com&quot;&gt;九天雁翎的博客&lt;/a&gt; on March 13, 2026.&lt;/p&gt;</content>
</entry>


<entry>
  <title type="html"><![CDATA[skillsmgr 发布]]></title>
 <link rel="alternate" type="text/html" href="https://www.jtianling.com/skillsmgr-release.html" />
  <id>https://www.jtianling.com/skillsmgr-release</id>
  <published>2026-02-03T00:00:00+08:00</published>
  <updated>2026-02-03T00:00:00+08:00</updated>
  <author>
    <name></name>
    <uri>https://www.jtianling.com</uri>
    <email></email>
  </author>
  <content type="html">&lt;p&gt;最近在整理各种 AI 编程工具的 skills 时，发现每个工具都有自己的目录和格式，切来切去很容易乱。索性就做了一个统一管理的小工具：skillsmgr。它把 skills 集中放到 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;~/.skills-manager/&lt;/code&gt; 里，然后一键部署到不同的工具里。&lt;/p&gt;

&lt;p&gt;仓库地址：&lt;a href=&quot;https://github.com/jtianling/skills-manager&quot;&gt;https://github.com/jtianling/skills-manager&lt;/a&gt;&lt;/p&gt;

&lt;!-- more --&gt;

&lt;h3 id=&quot;一句话说明&quot;&gt;一句话说明&lt;/h3&gt;

&lt;p&gt;skillsmgr 是一个统一的 skills 管理器，帮你把一份技能库同步到多个 AI 编程工具。&lt;/p&gt;

&lt;h3 id=&quot;安装&quot;&gt;安装&lt;/h3&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;npx skillsmgr setup
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;使用&quot;&gt;使用&lt;/h3&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c&quot;&gt;# 初始化本地 skills 仓库结构&lt;/span&gt;
npx skillsmgr setup

&lt;span class=&quot;c&quot;&gt;# 安装官方 Anthropic skills&lt;/span&gt;
npx skillsmgr &lt;span class=&quot;nb&quot;&gt;install &lt;/span&gt;anthropic

&lt;span class=&quot;c&quot;&gt;# 进入项目并部署到本项目&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;cd &lt;/span&gt;your-project
npx skillsmgr init
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;支持的工具&quot;&gt;支持的工具&lt;/h3&gt;

&lt;p&gt;目前支持 Claude Code、Cursor、Windsurf、Cline、Roo Code、Kilo Code、OpenCode、Trae、Antigravity 等多个 AI 编程工具，目录结构会按各自规范自动处理。&lt;/p&gt;

&lt;h3 id=&quot;支持的功能特性&quot;&gt;支持的功能/特性&lt;/h3&gt;

&lt;ul&gt;
  &lt;li&gt;统一管理：所有 skills 都放在 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;~/.skills-manager/&lt;/code&gt; 下&lt;/li&gt;
  &lt;li&gt;多工具部署：一份 skills 同时部署到多个工具&lt;/li&gt;
  &lt;li&gt;默认软链接：技能更新可以自动同步&lt;/li&gt;
  &lt;li&gt;搜索过滤：技能仓库大时也能快速挑选&lt;/li&gt;
  &lt;li&gt;增量更新：只增删变更的技能，不用全量重装&lt;/li&gt;
&lt;/ul&gt;


  &lt;p&gt;&lt;a href=&quot;https://www.jtianling.com/skillsmgr-release.html&quot;&gt;skillsmgr 发布&lt;/a&gt; was originally published by  at &lt;a href=&quot;https://www.jtianling.com&quot;&gt;九天雁翎的博客&lt;/a&gt; on February 03, 2026.&lt;/p&gt;</content>
</entry>


<entry>
  <title type="html"><![CDATA[rulesmgr 发布：一份规则，多工具同步]]></title>
 <link rel="alternate" type="text/html" href="https://www.jtianling.com/rules-manager-release.html" />
  <id>https://www.jtianling.com/rules-manager-release</id>
  <published>2026-02-03T00:00:00+08:00</published>
  <updated>2026-02-03T00:00:00+08:00</updated>
  <author>
    <name></name>
    <uri>https://www.jtianling.com</uri>
    <email></email>
  </author>
  <content type="html">&lt;p&gt;最近在使用 Claude Code、Cursor、Cline 之类的 AI 编程工具时，总会遇到一个重复劳动：每个工具都有自己的规则目录，格式略有差异，团队的约定需要在多个地方复制粘贴，还容易漂移。于是做了一个小工具 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;rulesmgr&lt;/code&gt;，统一管理一份规则，然后一次性部署到多个工具。&lt;/p&gt;

&lt;p&gt;仓库地址：&lt;a href=&quot;https://github.com/jtianling/rules-manager&quot;&gt;https://github.com/jtianling/rules-manager&lt;/a&gt;&lt;/p&gt;

&lt;!-- more --&gt;

&lt;h3 id=&quot;一句话说明&quot;&gt;一句话说明&lt;/h3&gt;

&lt;p&gt;维护一份规则模板，选择目标工具后自动生成对应目录结构，并支持复制模式的同步更新。&lt;/p&gt;

&lt;h3 id=&quot;安装&quot;&gt;安装&lt;/h3&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;npx rulesmgr setup
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;它会在 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;~/.rules-manager/&lt;/code&gt; 生成示例规则模板，结构类似下面这样：&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;~/.rules-manager/
├── 01-tech-stack.md
├── 02-coding-principles.md
├── 03-architecture.md
├── 04-testing.md
├── 05-git-commit.md
├── 06-code-review.md
└── languages/
    ├── typescript-coding-style.md
    ├── python-coding-style.md
    └── ...
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;部署到项目&quot;&gt;部署到项目&lt;/h3&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c&quot;&gt;# 交互模式&lt;/span&gt;
npx rulesmgr init

&lt;span class=&quot;c&quot;&gt;# 指定工具与语言&lt;/span&gt;
npx rulesmgr init &lt;span class=&quot;nt&quot;&gt;--tools&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;claude-code,cursor &lt;span class=&quot;nt&quot;&gt;--lang&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;typescript

&lt;span class=&quot;c&quot;&gt;# 使用复制模式&lt;/span&gt;
npx rulesmgr init &lt;span class=&quot;nt&quot;&gt;--tools&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;claude-code &lt;span class=&quot;nt&quot;&gt;--copy&lt;/span&gt;

&lt;span class=&quot;c&quot;&gt;# 部署 .gitignore&lt;/span&gt;
npx rulesmgr init &lt;span class=&quot;nt&quot;&gt;--gitignore&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;同步复制模式的规则&quot;&gt;同步复制模式的规则&lt;/h3&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;npx rulesmgr &lt;span class=&quot;nb&quot;&gt;sync&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;支持的工具&quot;&gt;支持的工具&lt;/h3&gt;

&lt;p&gt;当前支持 Claude Code、Cursor、Cline、Roo Code、Kilo Code、Windsurf、OpenCode、TRAE、Goose、Antigravity 等工具，具体目录映射可参考仓库 README。&lt;/p&gt;

&lt;p&gt;欢迎试用和反馈，后续会继续补充更多工具与模板。&lt;/p&gt;

  &lt;p&gt;&lt;a href=&quot;https://www.jtianling.com/rules-manager-release.html&quot;&gt;rulesmgr 发布：一份规则，多工具同步&lt;/a&gt; was originally published by  at &lt;a href=&quot;https://www.jtianling.com&quot;&gt;九天雁翎的博客&lt;/a&gt; on February 03, 2026.&lt;/p&gt;</content>
</entry>


<entry>
  <title type="html"><![CDATA[Ollama rerank adapter]]></title>
 <link rel="alternate" type="text/html" href="https://www.jtianling.com/ollama-rerank-adapter.html" />
  <id>https://www.jtianling.com/ollama-rerank-adapter</id>
  <published>2025-12-17T00:00:00+08:00</published>
  <updated>2025-12-17T00:00:00+08:00</updated>
  <author>
    <name></name>
    <uri>https://www.jtianling.com</uri>
    <email></email>
  </author>
  <content type="html">&lt;p&gt;A lightweight HTTP service that wraps Ollama’s Rerank model into a standard Rerank API, enabling Dify and other applications to use local Ollama models for document reranking.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://github.com/jtianling/dify-ollama-rerank-adapter&quot;&gt;https://github.com/jtianling/dify-ollama-rerank-adapter&lt;/a&gt;&lt;/p&gt;


  &lt;p&gt;&lt;a href=&quot;https://www.jtianling.com/ollama-rerank-adapter.html&quot;&gt;Ollama rerank adapter&lt;/a&gt; was originally published by  at &lt;a href=&quot;https://www.jtianling.com&quot;&gt;九天雁翎的博客&lt;/a&gt; on December 17, 2025.&lt;/p&gt;</content>
</entry>


<entry>
  <title type="html"><![CDATA[给 DeepSeek 网站加个搜索功能的Chrome插件]]></title>
 <link rel="alternate" type="text/html" href="https://www.jtianling.com/add-search-to-deepseek.html" />
  <id>https://www.jtianling.com/add-search-to-deepseek</id>
  <published>2025-12-08T00:00:00+08:00</published>
  <updated>2025-12-08T00:00:00+08:00</updated>
  <author>
    <name></name>
    <uri>https://www.jtianling.com</uri>
    <email></email>
  </author>
  <content type="html">&lt;p&gt;DeepSeek 很好用, 但是他们公司一直不注重使用体验的优化, 比如在 DeepSeek 网站中, 就一直没有一个搜索历史记录的功能, 于是, 我做了一个. 没有上架商店, 开源自取.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://github.com/jtianling/deepseek-search-chrome&quot;&gt;https://github.com/jtianling/deepseek-search-chrome&lt;/a&gt;&lt;/p&gt;


  &lt;p&gt;&lt;a href=&quot;https://www.jtianling.com/add-search-to-deepseek.html&quot;&gt;给 DeepSeek 网站加个搜索功能的Chrome插件&lt;/a&gt; was originally published by  at &lt;a href=&quot;https://www.jtianling.com&quot;&gt;九天雁翎的博客&lt;/a&gt; on December 08, 2025.&lt;/p&gt;</content>
</entry>


<entry>
  <title type="html"><![CDATA[编程语言语法比较网站]]></title>
 <link rel="alternate" type="text/html" href="https://www.jtianling.com/programming-language-comparison.html" />
  <id>https://www.jtianling.com/programming-language-comparison</id>
  <published>2025-12-02T00:00:00+08:00</published>
  <updated>2025-12-02T00:00:00+08:00</updated>
  <author>
    <name></name>
    <uri>https://www.jtianling.com</uri>
    <email></email>
  </author>
  <content type="html">&lt;p&gt;一直以来, 经常需要同时使用多种编程语言, 要么是自己在自学一个新的编程语言, 正在做一些练手的项目, 同时公司的项目也在开发.  或者在某个项目中, 同时写前后端, 而前后端用的分别是不同的语言, 这些时候, 我都有一个想法, 要是有个网站, 能并排列出我正在使用的几个语言的语法示例就好了, 这些在切换编程语言的时候, 脑子不容易乱.  这么多年过去了, 因为大模型的成熟, 写这么一个网站变得如此的容易, 我把网址贴出来, 有一样需求的人随时查看吧.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://www.jtianling.com/programming-language-comparison&quot;&gt;https://www.jtianling.com/programming-language-comparison&lt;/a&gt;&lt;/p&gt;


  &lt;p&gt;&lt;a href=&quot;https://www.jtianling.com/programming-language-comparison.html&quot;&gt;编程语言语法比较网站&lt;/a&gt; was originally published by  at &lt;a href=&quot;https://www.jtianling.com&quot;&gt;九天雁翎的博客&lt;/a&gt; on December 02, 2025.&lt;/p&gt;</content>
</entry>


<entry>
  <title type="html"><![CDATA[Rust 的交叉编译]]></title>
 <link rel="alternate" type="text/html" href="https://www.jtianling.com/cross-compile-with-rust.html" />
  <id>https://www.jtianling.com/cross-compile-with-rust</id>
  <published>2022-05-18T00:00:00+08:00</published>
  <updated>2022-05-18T00:00:00+08:00</updated>
  <author>
    <name></name>
    <uri>https://www.jtianling.com</uri>
    <email></email>
  </author>
  <content type="html">&lt;p&gt;&lt;a href=&quot;https://www.rust-lang.org/&quot;&gt;Rust&lt;/a&gt; 作为编译型的语言, 交叉编译挺方便的, 这样开发和部署, 都能简单挺多. 本文以在 Mac 上, 交叉编译一个使用 SDL 库的程序到一个手持 ARM 设备(&lt;a href=&quot;https://www.clockworkpi.com/gameshell&quot;&gt;clockwork Gameshell&lt;/a&gt;) 为例, 记录一下怎么使用 Rust 的交叉编译, 特别是怎么在交叉编译的时候, 还能链接类似 SDL 这种外部的库.
Rust 的生态是比较完善的, 只是相关的资料比较少的, 基本上是一步一个坑. 除了对 Rust 自身的 Rustup 等工具的了解, 还需要用到 &lt;a href=&quot;https://www.docker.com/&quot;&gt;Docker&lt;/a&gt;, Linux 包管理等知识, 希望对同样被困住的同学有帮助. 同时, 本文也会顺便讲讲思路, 以帮助大家将相关知识应用到其他交叉编译的场景.&lt;/p&gt;

&lt;!-- more --&gt;
&lt;h1 id=&quot;环境&quot;&gt;环境&lt;/h1&gt;
&lt;p&gt;先厘清几个术语, 在交叉编译的时候, 用于编译的机器, 叫做 Host(宿主), 这里用的是我的 Mac(12.1), 用来运行程序的机器叫做 Target(目标设备), 例子中是前面提到的 Clockwork GameShell, 一个 ARM 设备.  我们的目标就是在宿主机器上编译, 然后直接在目标设备上运行编译好的程序.&lt;br /&gt;
这种方式的好处是宿主可以是台式机, 编译速度快, 而目标设备可以是任意设备, 包括速度很慢, 不太适合执行编译任务的嵌入式设备.&lt;/p&gt;

&lt;h1 id=&quot;最简单的情况&quot;&gt;最简单的情况&lt;/h1&gt;
&lt;p&gt;假如你并不需要用其他外部库, 那可以直接使用 Rust 内置的交叉编译功能, 使用还挺简单的. 
你可以通过 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;rustup target list&lt;/code&gt; 列出当前系统支持的所有交叉编译目标, 在我的 Mac 上运行以后, 有 86 个之多, 其中会有一个默认的. 显示&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;x86_64-apple-darwin (installed)
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;这个也是我们现在本机用的.&lt;br /&gt;
这么多编译目标, 那我们应该用哪一个呢? 这里有个&lt;a href=&quot;https://doc.rust-lang.org/nightly/rustc/platform-support.html&quot;&gt;官方的列表&lt;/a&gt;, 分为几个支持的级别, 可以直接过去看.&lt;/p&gt;

&lt;p&gt;同样是 Linux 和 ARM, 选择也不少. 可以在目标设备上, 用 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;uname -a&lt;/code&gt; 命令看到一部分信息.&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;$ uname -a
Linux clockworkpi 5.3.6-clockworkpi-cpi3 #1 SMP Tue Oct 15 17:26:44 CST 2019 armv7l GNU/Linux
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;起码知道了是 armv7, 但是 armv7 的 target 还有几个, 后来我想到的办法是, 在目标设备上安装 Rust, 然后通过前面的命令来看.  当然, 前提是目标设备也能运行 Rust 才行, 要是不行的话, 那就只能查资料和尝试了.&lt;br /&gt;
在我的目标设备, 运行前面的 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;rustup target list&lt;/code&gt; 命令后, 显示&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;armv7-unknown-linux-gnueabihf (installed)
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;稍微提醒一下, 这个是刚装完 Rust 后的情况, 你要是已经按下面的操作添加了各种 target, 那这个就不准了.&lt;br /&gt;
然后, 在宿主设备上, 用以下命令&lt;/p&gt;

&lt;div class=&quot;language-shell highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;rustup target add armv7-unknown-linux-gnueabihf
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;来添加对应的交叉编译目标.  直接编译试试&lt;/p&gt;

&lt;div class=&quot;language-shell highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;cargo build &lt;span class=&quot;nt&quot;&gt;--target&lt;/span&gt; armv7-unknown-linux-gnueabihf
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;到这一步, 你会看到一大堆的错误(要是这就成功了, 那我就不写这篇文章了)&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;error: linking with `cc` failed: exit status: 1
  |
  = note: &quot;cc&quot;
= note: clang: warning: argument unused during compilation: &apos;-pie&apos; [-Wunused-command-line-argument]
          ld: unknown option: --as-needed
          clang: error: linker command failed with exit code 1 (use -v to see invocation)
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;基本上的意思, 就是虽然编译是好了, 但是链接的时候发生错误了, 原因在于现在明显是使用了宿主的链接器(linker), 而不是对应的目标设备的链接器.&lt;/p&gt;

&lt;p&gt;这里有几种解决办法&lt;/p&gt;
&lt;ol&gt;
  &lt;li&gt;手动下载目标的链接器, 参考&lt;a href=&quot;https://john-millikin.com/notes-on-cross-compiling-rust&quot;&gt;这篇&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;直接用 brew 安装一下链接器 (不一定所有 target 都有).  参考&lt;a href=&quot;https://sigmaris.info/blog/2019/02/cross-compiling-rust-on-mac-os-for-an-arm-linux-router/&quot;&gt;这篇&lt;/a&gt;,&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;我这里是 ARM 设备, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;brew&lt;/code&gt; 是有的, 为了简单, 我直接用 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;brew&lt;/code&gt; 命令安装了&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;brew install arm-linux-gnueabihf-binutils
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;然后, 在 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;~/.cargo/config&lt;/code&gt; 中, 添加如下两行配置, 修改对应 target 的链接器设置&lt;/p&gt;

&lt;div class=&quot;language-toml highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nn&quot;&gt;[target.armv7-unknown-linux-gnueabihf]&lt;/span&gt;
&lt;span class=&quot;py&quot;&gt;linker&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;arm-linux-gnueabihf-ld&quot;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;再用前面的命令编译试试, 此时还是会报错:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;  = note: arm-linux-gnueabihf-ld: cannot find -lgcc_s: No such file or directory
          arm-linux-gnueabihf-ld: cannot find -lutil: No such file or directory
          arm-linux-gnueabihf-ld: cannot find -lrt: No such file or directory
          arm-linux-gnueabihf-ld: cannot find -lpthread: No such file or directory
          arm-linux-gnueabihf-ld: cannot find -lm: No such file or directory
          arm-linux-gnueabihf-ld: cannot find -ldl: No such file or directory
          arm-linux-gnueabihf-ld: cannot find -lc: No such file or directory
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;简单的原因, 就是一切就绪了, 但是对应的一些 gnu 基础库找不到. 此时可以去找到对应的库都下到本地, 还有, 我找到一个神奇的方法, 换成 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;armv7-unknown-linux-musleabihf&lt;/code&gt; 这个 target, 这里用了 &lt;a href=&quot;https://zh.m.wikipedia.org/zh/Musl&quot;&gt;musl&lt;/a&gt; 这个库, 就不需要用 gnu 的那些库了.&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;% cargo build --target=armv7-unknown-linux-musleabihf
    Finished dev [unoptimized + debuginfo] target(s) in 0.08s
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;编译后, 你可以可以在工程的 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;target/armv7-unknown-linux-musleabihf&lt;/code&gt; 目录下面, 找到交叉编译后的文件. 在目标设备上实测运行, 是可以运行的.&lt;br /&gt;
最后这种方式, 是绕过了配置链接需要的库, 理论上, 手动下载回来然后配置正确的话, 可以在 Mac 上直接编译链接成功, 应该会非常麻烦.&lt;br /&gt;
当我准备使用 SDL 这种库, 一定需要配置正确链接的库时, 这种方法就不好用了.&lt;br /&gt;
接下来, 介绍一种更全面的方法.&lt;/p&gt;

&lt;h1 id=&quot;使用-cross-rs&quot;&gt;使用 cross-rs&lt;/h1&gt;
&lt;p&gt;这个方式, 也是我个人比较推荐的方式, 万能, 而且是利用 Docker 环境来编译, 不需要在本地装一大堆纯为了编译的各种库, 当然, 代价是得装 Docker, 而众所周知, Docker 的 image 动不动就几个 G 的大小.-_-! 可能好处就是不用的时候, 清理起来方便一些了. &lt;br /&gt;
而且, 使用 Docker, 可以直接基于 Ubuntu 这种 Linux 环境, apt 的包管理感觉比 Mac  的 brew 还是要更强大.&lt;br /&gt;
对了, 其实接下来的步骤, 虽然是利用了 Docker, 但是除了 Docker 的部分, 也可以看做是在 Linux 上使用 Rust 交叉编译的过程. 假如你的宿主机本身是 Linux 的话, 那这些方法也是可以直接使用的(就不用 Docker 了), 怎么说呢, 果然 Linux 才是对开发者最友好的系统.&lt;/p&gt;

&lt;h2 id=&quot;安装-cross-rs&quot;&gt;安装 cross-rs&lt;/h2&gt;
&lt;p&gt;参考 &lt;a href=&quot;https://github.com/cross-rs/cross&quot;&gt;cross-rs 的页面&lt;/a&gt;, 每一步都相对清晰.
安装 cross-rs&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;$ cargo install cross
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;然后, 在交叉编译的时候, 直接用 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;cross&lt;/code&gt; 命令, 替换掉 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;cargo&lt;/code&gt;. 比如我们前面的那个简单例子, 在安装 cross-rs 后, 改成用 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;cross&lt;/code&gt; 命令.&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;% cross build --target=armv7-unknown-linux-gnueabihf
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;在下载了一个 Docker image 后, 直接就成功了…有点意外加惊喜.&lt;br /&gt;
此时, 能看到多了一个用于编译 armv7-unknown-linux-gnueabihf 的 docker image.&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;% docker image list
rustembedded/cross   armv7-unknown-linux-gnueabihf-0.2.1
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;链接外部库&quot;&gt;链接外部库&lt;/h2&gt;
&lt;p&gt;这里用 SDL 为例子, 演示怎么加载外部库.&lt;br /&gt;
首先随便找个 &lt;a href=&quot;https://sunjay.dev/learn-game-dev/opening-a-window.html&quot;&gt;SDL 的例子&lt;/a&gt;.
然后继续按上面的 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;cross&lt;/code&gt; 命令编译, 会报链接错误&lt;/p&gt;
&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;  = note: /usr/lib/gcc-cross/arm-linux-gnueabihf/5/../../../../arm-linux-gnueabihf/bin/ld: cannot find -lSDL2
          /usr/lib/gcc-cross/arm-linux-gnueabihf/5/../../../../arm-linux-gnueabihf/bin/ld: cannot find -lSDL2_mixer
          /usr/lib/gcc-cross/arm-linux-gnueabihf/5/../../../../arm-linux-gnueabihf/bin/ld: cannot find -lSDL2_image
          /usr/lib/gcc-cross/arm-linux-gnueabihf/5/../../../../arm-linux-gnueabihf/bin/ld: cannot find -lSDL2_ttf
          /usr/lib/gcc-cross/arm-linux-gnueabihf/5/../../../../arm-linux-gnueabihf/bin/ld: cannot find -lSDL2_gfx
          collect2: error: ld returned 1 exit status
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;很明显, 就是前面多次碰到的找不到对应的动态库.  不过这次我们解决这个问题.&lt;br /&gt;
前面我们已经能看到默认情况下, cross-rs 会给我们添加一个 image, 但是这个 image 里面没有我们需要的库.  我们来添加一下.&lt;/p&gt;

&lt;h3 id=&quot;1-交互式运行这个-image-创建一个-container&quot;&gt;1. 交互式运行这个 image, 创建一个 container&lt;/h3&gt;
&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;% docker run -i -t rustembedded/cross:armv7-unknown-linux-gnueabihf-0.2.1 /bin/bash
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;2-在-container-中添加我们需要的库&quot;&gt;2. 在 container 中添加我们需要的库&lt;/h3&gt;
&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;# apt-get update
# dpkg --add-architecture armhf
# apt-get update
# apt-get install libsdl2-dev:armhf libsdl2-mixer-dev:armhf libsdl2-ttf-dev:armhf libsdl2-image-dev:armhf libsdl2-gfx-dev:armhf
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;这里是以 SDL 为例, 其中 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;dpkg --add-architecture armhf&lt;/code&gt; 的这一步, 很关键, 因为 Docker 运行的也不是目标设备的系统, 后面的 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;apt-get install&lt;/code&gt; 的时候, 也用了 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;:armhf&lt;/code&gt; 的后缀, 表示安装的是针对 ARM 的对应包. 要是没有这几步, 直接用 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;apt-get&lt;/code&gt; 安装也是没有用的.&lt;/p&gt;

&lt;h3 id=&quot;3-用这个做好的-container-来创建我们自定义的-image&quot;&gt;3. 用这个做好的 container 来创建我们自定义的 image&lt;/h3&gt;
&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;% docker ps
CONTAINER ID   IMAGE                                                    COMMAND       CREATED          STATUS          PORTS     NAMES
98744316d89e   rustembedded/cross:armv7-unknown-linux-gnueabihf-0.2.1   &quot;/bin/bash&quot;   19 minutes ago   Up 19 minutes             naughty_mccarthy
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;此时, 注意我们正在运行的container id.&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;% docker commit 98744316d89e my/clockwork
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;4-然后指定-cross-rs-使用我们自定义的-image&quot;&gt;4. 然后指定 cross-rs 使用我们自定义的 image&lt;/h3&gt;
&lt;p&gt;在工程中, 增加一个 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Cross.toml&lt;/code&gt; 文件, 内容如下:&lt;/p&gt;
&lt;div class=&quot;language-toml highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nn&quot;&gt;[target.armv7-unknown-linux-gnueabihf]&lt;/span&gt;
&lt;span class=&quot;py&quot;&gt;image&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;my/clockwork&quot;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;准备就绪, 再次使用&lt;/p&gt;
&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;% cross build --target=armv7-unknown-linux-gnueabihf
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;编译, 搞定. 此时可以将编译好的程序拷贝到目标设备上运行, 没有问题.
最后, 因为本身就是配置一个编译环境, 直接交互式运行 image 还是挺方便的, 以后有更多依赖库的时候, 重复上述步骤即可.&lt;/p&gt;

&lt;h1 id=&quot;参考&quot;&gt;参考&lt;/h1&gt;

&lt;ol&gt;
  &lt;li&gt;&lt;a href=&quot;https://rust-lang.github.io/rustup&quot;&gt;The rustup book&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/cross-rs/cross&quot;&gt;cross-rs&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://john-millikin.com/notes-on-cross-compiling-rust&quot;&gt;Notes on cross-compiling Rust&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://sigmaris.info/blog/2019/02/cross-compiling-rust-on-mac-os-for-an-arm-linux-router/&quot;&gt;Cross compiling Rust on Mac OS for an ARM Linux router&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://sunjay.dev/learn-game-dev/intro.html&quot;&gt;Learn Game Development in Rust&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;

  &lt;p&gt;&lt;a href=&quot;https://www.jtianling.com/cross-compile-with-rust.html&quot;&gt;Rust 的交叉编译&lt;/a&gt; was originally published by  at &lt;a href=&quot;https://www.jtianling.com&quot;&gt;九天雁翎的博客&lt;/a&gt; on May 18, 2022.&lt;/p&gt;</content>
</entry>


<entry>
  <title type="html"><![CDATA[用 Dart 加 Pixijs 写 HTML 游戏]]></title>
 <link rel="alternate" type="text/html" href="https://www.jtianling.com/dart-with-pixijs.html" />
  <id>https://www.jtianling.com/dart-with-pixijs</id>
  <published>2020-03-09T00:00:00+08:00</published>
  <updated>2020-03-09T00:00:00+08:00</updated>
  <author>
    <name></name>
    <uri>https://www.jtianling.com</uri>
    <email></email>
  </author>
  <content type="html">&lt;p&gt;最近 &lt;a href=&quot;https://flutter.dev/&quot;&gt;Flutter&lt;/a&gt; 的流行, 让 &lt;a href=&quot;https://dart.dev/&quot;&gt;Dart&lt;/a&gt; 这个似乎已经要死的语言又复活了.  最近在找能同时在 iOS 和 H5 两端同时运行的编程语言, 没想到 Dart 竟然是非常合适的对象, 有点意外, 于是看了看 Dart.&lt;/p&gt;

&lt;!-- more --&gt;
&lt;h1 id=&quot;提要&quot;&gt;提要&lt;/h1&gt;

&lt;p&gt;实在的说, 语法特性并没有什么亮点. 类型系统除了添加了类似 Mixin 这种相对靠谱的东西外, 写起来和 C++ 的感觉都差不多, 并发上, 添加了类似 JavaScript 的 Async-Await 异步写法, 暂时没有尝试, 不过就使用 JavaScript 的经验来说, 可能真用来写服务器, 并不能很好的写 多线程/多协程 的程序, 可能要用单线程-多进程的思维来实现并发.&lt;/p&gt;

&lt;h1 id=&quot;dart-with-pixijs&quot;&gt;dart with pixijs&lt;/h1&gt;
&lt;p&gt;为了熟悉语法, 把最近 &lt;a href=&quot;/learn-python-by-game-examples-2.html&quot;&gt;用 Python 写游戏&lt;/a&gt;里面的例子实现了一下. 也算有些坑, 主要是在 Dart 和 JS/Dom 的交互上的, 比如获取键盘响应等事件上.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://github.com/jtianling/dart-pixi-test&quot;&gt;源代码&lt;/a&gt;放在 Github 上了, 因为是写的第一个 Dart 程序, 写的难看的地方, 就不要太在意了…&lt;/p&gt;

&lt;p&gt;因为是 H5 版本, 可以直接通过这个链接看到效果:
&lt;a href=&quot;http://www.jtianling.com/dart-pixi-test&quot;&gt;http://www.jtianling.com/dart-pixi-test&lt;/a&gt;&lt;/p&gt;

&lt;h1 id=&quot;引用的库&quot;&gt;引用的库&lt;/h1&gt;
&lt;p&gt;pixi 的 Dart 封装:
&lt;a href=&quot;https://pub.dev/packages/pixi&quot;&gt;https://pub.dev/packages/pixi&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;pixijs:
&lt;a href=&quot;https://www.pixijs.com&quot;&gt;https://www.pixijs.com&lt;/a&gt;&lt;/p&gt;

  &lt;p&gt;&lt;a href=&quot;https://www.jtianling.com/dart-with-pixijs.html&quot;&gt;用 Dart 加 Pixijs 写 HTML 游戏&lt;/a&gt; was originally published by  at &lt;a href=&quot;https://www.jtianling.com&quot;&gt;九天雁翎的博客&lt;/a&gt; on March 09, 2020.&lt;/p&gt;</content>
</entry>


<entry>
  <title type="html"><![CDATA[用 Python 写游戏 第二篇]]></title>
 <link rel="alternate" type="text/html" href="https://www.jtianling.com/learn-python-by-game-examples-2.html" />
  <id>https://www.jtianling.com/learn-python-by-game-examples-2</id>
  <published>2020-03-08T00:00:00+08:00</published>
  <updated>2020-03-08T00:00:00+08:00</updated>
  <author>
    <name></name>
    <uri>https://www.jtianling.com</uri>
    <email></email>
  </author>
  <content type="html">&lt;p&gt;学编程后, 过了初期的语法熟悉阶段, 新手往往会比较迷茫, 因为也不知道编程能干嘛, 对于这种情况, 我的建议当然是实际的做一些项目, 这里用一些游戏和 Python 的例子, 来真正的了解和熟悉编程吧.&lt;/p&gt;

&lt;p&gt;本文为该系列的第二篇&lt;/p&gt;

&lt;!-- more --&gt;

&lt;h1 id=&quot;主角就绪&quot;&gt;主角就绪&lt;/h1&gt;
&lt;p&gt;参考&lt;a href=&quot;/learn-python-by-game-examples-1.html&quot;&gt;教程的第一篇&lt;/a&gt;及&lt;a href=&quot;/learn-python-by-game-examples-1-answer.html&quot;&gt;第一篇课后的答案&lt;/a&gt;, 我们已经获得了一个操作上较为靠谱的主角, 暂时用一个小圆点来表示.
再次回顾一下代码:&lt;/p&gt;

&lt;div class=&quot;language-python highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;n&quot;&gt;player_pos_x&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;100&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;player_pos_y&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;100&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;draw&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;():&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;screen&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;clear&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;screen&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;draw&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;filled_circle&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;((&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;player_pos_x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;player_pos_y&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt; 
                                &lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; 
                                &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;255&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;255&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;255&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;up&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;bp&quot;&gt;False&lt;/span&gt;    
&lt;span class=&quot;n&quot;&gt;down&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;bp&quot;&gt;False&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;left&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;bp&quot;&gt;False&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;right&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;bp&quot;&gt;False&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;on_key_down&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;key&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;global&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;up&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;down&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;left&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;right&lt;/span&gt;
   
    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;key&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;keys&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;UP&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;up&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;bp&quot;&gt;True&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;elif&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;key&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;keys&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;DOWN&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;down&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;bp&quot;&gt;True&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;elif&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;key&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;keys&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;LEFT&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;left&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;bp&quot;&gt;True&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;elif&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;key&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;keys&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;RIGHT&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;right&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;bp&quot;&gt;True&lt;/span&gt;        

&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;update&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;():&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;global&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;up&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;down&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;left&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;right&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;player_pos_x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;player_pos_y&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;up&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;player_pos_y&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;player_pos_y&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;down&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;player_pos_y&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;player_pos_y&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;left&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;player_pos_x&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;player_pos_x&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;right&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;player_pos_x&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;player_pos_x&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;
        
&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;on_key_up&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;key&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;global&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;down&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;up&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;left&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;right&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;key&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;keys&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;UP&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;up&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;bp&quot;&gt;False&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;elif&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;key&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;keys&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;DOWN&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;down&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;bp&quot;&gt;False&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;elif&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;key&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;keys&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;LEFT&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;left&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;bp&quot;&gt;False&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;elif&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;key&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;keys&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;RIGHT&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;right&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;bp&quot;&gt;False&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h1 id=&quot;添加敌人&quot;&gt;添加敌人&lt;/h1&gt;
&lt;p&gt;只有主角, 没有敌人, 那叫什么游戏啊, 我们用小方块来表示敌人吧, 还记得怎么绘制方块吗?&lt;/p&gt;

&lt;div class=&quot;language-python highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;
&lt;span class=&quot;n&quot;&gt;player_pos_x&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;100&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;player_pos_y&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;100&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;enemy_pos_x&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;200&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;enemy_pos_y&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;200&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;draw&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;():&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;screen&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;clear&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;screen&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;draw&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;filled_circle&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;((&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;player_pos_x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;player_pos_y&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt; 
                                &lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; 
                                &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;255&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;255&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;255&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
                                
    &lt;span class=&quot;n&quot;&gt;screen&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;draw&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;filled_rect&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Rect&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;((&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;enemy_pos_x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;enemy_pos_y&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;5&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;5&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)),&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;255&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;以上的代码只有 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;draw&lt;/code&gt; 部分, 不过也能看到, 屏幕上多了一个红色, 看起来很危险的敌人.&lt;/p&gt;

&lt;h1 id=&quot;让敌人动起来&quot;&gt;让敌人动起来&lt;/h1&gt;
&lt;p&gt;敌人是静止的, 也没有什么意思, 我们先做一个能追踪主角的敌人吧. 这个时候, 几何知识不够丰富也没有关系, 我们想一想, 怎么样才能让敌人追上主角呢?
最朴素的思想是, 让敌人的 x 坐标和 y 坐标, 都尽量的向主角靠拢, 这个想法够朴素了吧, 代码如下:&lt;/p&gt;

&lt;div class=&quot;language-python highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;n&quot;&gt;player_pos_x&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;100&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;player_pos_y&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;100&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;enemy_pos_x&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;200&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;enemy_pos_y&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;200&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;draw&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;():&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;screen&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;clear&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;screen&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;draw&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;filled_circle&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;((&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;player_pos_x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;player_pos_y&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt; 
                                &lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; 
                                &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;255&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;255&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;255&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
                                
    &lt;span class=&quot;n&quot;&gt;screen&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;draw&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;filled_rect&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Rect&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;((&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;enemy_pos_x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;enemy_pos_y&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;5&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;5&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)),&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;255&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;


&lt;span class=&quot;n&quot;&gt;up&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;bp&quot;&gt;False&lt;/span&gt;    
&lt;span class=&quot;n&quot;&gt;down&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;bp&quot;&gt;False&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;left&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;bp&quot;&gt;False&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;right&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;bp&quot;&gt;False&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;on_key_down&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;key&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;global&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;up&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;down&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;left&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;right&lt;/span&gt;
   
    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;key&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;keys&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;UP&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;up&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;bp&quot;&gt;True&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;elif&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;key&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;keys&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;DOWN&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;down&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;bp&quot;&gt;True&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;elif&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;key&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;keys&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;LEFT&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;left&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;bp&quot;&gt;True&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;elif&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;key&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;keys&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;RIGHT&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;right&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;bp&quot;&gt;True&lt;/span&gt;        

&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;update&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;():&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;global&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;up&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;down&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;left&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;right&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;player_pos_x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;player_pos_y&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;enemy_pos_x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;enemy_pos_y&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;up&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;player_pos_y&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;player_pos_y&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;down&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;player_pos_y&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;player_pos_y&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;left&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;player_pos_x&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;player_pos_x&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;right&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;player_pos_x&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;player_pos_x&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;
        
    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;enemy_pos_x&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;player_pos_x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;enemy_pos_x&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;enemy_pos_x&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;elif&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;enemy_pos_x&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;player_pos_x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;enemy_pos_x&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;enemy_pos_x&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;
        
    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;enemy_pos_y&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;player_pos_y&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;enemy_pos_y&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;enemy_pos_y&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;elif&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;enemy_pos_y&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;player_pos_y&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;enemy_pos_y&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;enemy_pos_y&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;
        
&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;on_key_up&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;key&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;global&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;down&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;up&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;left&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;right&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;key&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;keys&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;UP&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;up&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;bp&quot;&gt;False&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;elif&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;key&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;keys&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;DOWN&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;down&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;bp&quot;&gt;False&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;elif&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;key&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;keys&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;LEFT&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;left&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;bp&quot;&gt;False&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;elif&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;key&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;keys&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;RIGHT&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;right&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;bp&quot;&gt;False&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;需要注意的时候, 注意什么样的代码, 写在什么地方, 让敌人向主角靠拢的代码, 记得写在 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;update&lt;/code&gt; 函数里面, 运行以后, 你会发现, 敌人现在直奔主角而去, 几乎难逃他的魔掌. 作为游戏玩法, 因为敌人的速度和主角一样, 主角几乎难逃魔掌, 并且, 我们能发现, 随着全局变量的增加, 我们的代码有太多的 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;global&lt;/code&gt; 变量需要声明, 是时候简化一下代码了.&lt;/p&gt;

&lt;h1 id=&quot;引入类型&quot;&gt;引入类型&lt;/h1&gt;
&lt;p&gt;我们用 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;class&lt;/code&gt; 来优化一下代码, 首先用一个 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Global&lt;/code&gt; 的类型, 来简化全局变量的声明和使用, 另外引入 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Role&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Player&lt;/code&gt; 和 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Enmey&lt;/code&gt;, 我们先从简化 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Draw&lt;/code&gt;函数的实现开始:&lt;/p&gt;

&lt;div class=&quot;language-python highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;
&lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Game&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;pass&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Role&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;__init__&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;y&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
        &lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;x&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;
        &lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;y&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;y&lt;/span&gt;
    
    &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;draw&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;pass&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Player&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Role&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;draw&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;screen&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;draw&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;filled_circle&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;((&lt;/span&gt;&lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;y&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt; 
                                &lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; 
                                &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;255&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;255&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;255&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
                                

&lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Enemy&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Role&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;draw&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;screen&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;draw&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;filled_circle&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;((&lt;/span&gt;&lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;y&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt; 
                                &lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; 
                                &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;255&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;g&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Game&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;g&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;player&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Player&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;100&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;100&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;g&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;enemy&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Enemy&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;200&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;200&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;g&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;up&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;bp&quot;&gt;False&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;g&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;down&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;bp&quot;&gt;False&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;g&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;left&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;bp&quot;&gt;False&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;g&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;right&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;bp&quot;&gt;False&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;draw&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;():&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;screen&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;clear&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;g&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;player&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;draw&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;g&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;enemy&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;draw&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;on_key_down&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;key&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;key&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;keys&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;UP&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;g&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;up&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;bp&quot;&gt;True&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;elif&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;key&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;keys&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;DOWN&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;g&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;down&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;bp&quot;&gt;True&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;elif&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;key&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;keys&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;LEFT&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;g&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;left&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;bp&quot;&gt;True&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;elif&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;key&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;keys&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;RIGHT&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;g&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;right&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;bp&quot;&gt;True&lt;/span&gt;        

&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;on_key_up&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;key&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;key&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;keys&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;UP&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;g&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;up&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;bp&quot;&gt;False&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;elif&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;key&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;keys&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;DOWN&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;g&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;down&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;bp&quot;&gt;False&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;elif&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;key&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;keys&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;LEFT&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;g&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;left&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;bp&quot;&gt;False&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;elif&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;key&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;keys&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;RIGHT&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;g&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;right&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;bp&quot;&gt;False&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;update&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;():&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;g&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;up&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;g&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;player&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;y&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;g&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;down&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;g&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;player&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;y&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;g&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;left&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;g&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;player&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;x&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;g&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;right&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;g&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;player&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;x&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;
        
    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;g&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;enemy&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;x&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;g&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;player&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;g&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;enemy&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;x&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;elif&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;g&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;enemy&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;x&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;g&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;player&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;g&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;enemy&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;x&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;
        
    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;g&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;enemy&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;y&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;g&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;player&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;y&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;g&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;enemy&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;y&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;g&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;enemy&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;y&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;elif&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;g&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;enemy&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;y&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;g&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;player&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;y&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;g&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;enemy&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;y&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;
    
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;代码比原来多了一些内容, 要是还不明白 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Role&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Player&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Enemy&lt;/code&gt; 几个类, 还有定义在 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Game&lt;/code&gt; 类型的变量 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;g&lt;/code&gt; 中的 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;player&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;enemy&lt;/code&gt; 变量的含义, 建议赶紧回去复习一下 Python 的相关内容, 所谓面向对象编程, 不知道怎么定义类型和对象, 那可不行.
上面的代码, 我们的 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;player&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;enemy&lt;/code&gt; 对象, 自己处理了自己的 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;draw&lt;/code&gt; 而不是由外部来处理, 这种代码设计的方向, 我们称其为自己对自己负责, 这是一个能导向良好代码设计的方向, 因为只有所有对象都为自己负责, 才不需要把自己的更多内容, 告诉外部, 让外部控制自己. 做人也是这样, 不是吗?&lt;/p&gt;

&lt;h1 id=&quot;更负责的对象&quot;&gt;更负责的对象&lt;/h1&gt;
&lt;p&gt;既然要做一个负责任的对象, 当然不能仅仅为 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;draw&lt;/code&gt; 这一件事情负责, 自己的移动这么重要的事情, 当然也不能交给别人来做. 接下来, 我们让 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;player&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;enmey&lt;/code&gt; 对象自己也接管自己的移动吧.&lt;/p&gt;

&lt;div class=&quot;language-python highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;
&lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Game&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;pass&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Role&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;__init__&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;y&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;max_speed&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
        &lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;x&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;
        &lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;y&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;y&lt;/span&gt;
        &lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;max_speed&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;max_speed&lt;/span&gt;
    
    &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;get_pos_x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;
        
    &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;get_pos_y&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;y&lt;/span&gt;
        
    &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;draw&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;pass&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Player&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Role&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;__init__&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;y&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;max_speed&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
        &lt;span class=&quot;nb&quot;&gt;super&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;().&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;__init__&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;y&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;max_speed&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;_cur_speed_x&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;
        &lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;_cur_speed_y&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;
        
    &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;draw&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;screen&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;draw&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;filled_circle&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;((&lt;/span&gt;&lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;y&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt; 
                                &lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; 
                                &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;255&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;255&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;255&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
    
    &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;on_key_down&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;key&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;key&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;keys&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;UP&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
            &lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;_cur_speed_y&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+=&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;max_speed&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;elif&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;key&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;keys&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;DOWN&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
            &lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;_cur_speed_y&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+=&lt;/span&gt; &lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;max_speed&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;elif&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;key&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;keys&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;LEFT&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
            &lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;_cur_speed_x&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+=&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;max_speed&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;elif&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;key&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;keys&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;RIGHT&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
            &lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;_cur_speed_x&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+=&lt;/span&gt; &lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;max_speed&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;on_key_up&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;key&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;key&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;keys&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;UP&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
            &lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;_cur_speed_y&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-=&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;max_speed&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;elif&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;key&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;keys&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;DOWN&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
            &lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;_cur_speed_y&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-=&lt;/span&gt; &lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;max_speed&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;elif&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;key&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;keys&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;LEFT&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
            &lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;_cur_speed_x&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-=&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;max_speed&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;elif&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;key&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;keys&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;RIGHT&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
            &lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;_cur_speed_x&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-=&lt;/span&gt; &lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;max_speed&lt;/span&gt;
    
    &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;move&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
        &lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;x&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+=&lt;/span&gt; &lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;_cur_speed_x&lt;/span&gt;
        &lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;y&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+=&lt;/span&gt; &lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;_cur_speed_y&lt;/span&gt;
                                

&lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Enemy&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Role&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;draw&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;screen&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;draw&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;filled_circle&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;((&lt;/span&gt;&lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;y&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt; 
                                &lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; 
                                &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;255&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
                                
    &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;chase&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;player&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;x&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;g&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;player&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;get_pos_x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;():&lt;/span&gt;
            &lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;x&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+=&lt;/span&gt; &lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;max_speed&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;elif&lt;/span&gt; &lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;x&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;g&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;player&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;get_pos_x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;():&lt;/span&gt;
            &lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;x&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-=&lt;/span&gt; &lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;max_speed&lt;/span&gt;
        
        &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;g&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;enemy&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;y&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;g&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;player&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;y&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
            &lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;y&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+=&lt;/span&gt; &lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;max_speed&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;elif&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;g&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;enemy&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;y&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;g&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;player&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;y&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
            &lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;y&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-=&lt;/span&gt; &lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;max_speed&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;g&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Game&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;g&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;player&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Player&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;100&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;100&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;g&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;enemy&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Enemy&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;200&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;200&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;draw&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;():&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;screen&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;clear&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;g&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;player&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;draw&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;g&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;enemy&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;draw&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;on_key_down&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;key&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;g&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;player&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;on_key_down&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;key&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
      

&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;on_key_up&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;key&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;g&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;player&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;on_key_up&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;key&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;update&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;():&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;g&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;player&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;move&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;g&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;enemy&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;chase&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;g&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;player&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;这种自己为自己负责, 把内部的变量(也叫属性)不让外部使用, 而是仅仅自己知道和使用的方式, 我们称之为 &lt;strong&gt;封装&lt;/strong&gt;, 按其字面意思的理解就很贴切了, 意思就是把自己封闭起来,装的很牛的样子…
上面的代码, 已经比原来的玩具代码, 更像正常该有的样子了, 类似 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;draw&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;on_key_down&lt;/code&gt; 函数里面的内容很少, 仅仅只有对某个对象的函数的调用, 而真正的逻辑, 都写在&lt;strong&gt;类&lt;/strong&gt;里面.
上面的代码, 其实和前面刚添加完敌人时候的作用一模一样, 但是样子却变化很大, 首先可以自己感受一下, 两者的区别.&lt;/p&gt;

&lt;h1 id=&quot;课后练习&quot;&gt;课后练习&lt;/h1&gt;
&lt;p&gt;今天我们添加了敌人, 并且尝试用类封装了主角和敌人, 可能经过这么多修改, 了解了很多新的概念, 但是你还对这些复杂的操作将信将疑, 为什么我们需要这么麻烦呢? 前面的代码看起来也挺直观的, 不是也挺好的吗?
通过一个练习, 我们来感受一下这么封装的好处吧, 那就是, 我们随机的, 在屏幕上生成更多的敌人, 比如每 5 秒,添加 1 个, 上限 100 个.&lt;/p&gt;

&lt;p&gt;简单的提示, 用一个列表来存储所有的敌人吧.&lt;/p&gt;

  &lt;p&gt;&lt;a href=&quot;https://www.jtianling.com/learn-python-by-game-examples-2.html&quot;&gt;用 Python 写游戏 第二篇&lt;/a&gt; was originally published by  at &lt;a href=&quot;https://www.jtianling.com&quot;&gt;九天雁翎的博客&lt;/a&gt; on March 08, 2020.&lt;/p&gt;</content>
</entry>


<entry>
  <title type="html"><![CDATA[用 Python 写游戏 第一篇]]></title>
 <link rel="alternate" type="text/html" href="https://www.jtianling.com/learn-python-by-game-examples-1.html" />
  <id>https://www.jtianling.com/learn-python-by-game-examples-1</id>
  <published>2020-03-07T00:00:00+08:00</published>
  <updated>2020-03-07T00:00:00+08:00</updated>
  <author>
    <name></name>
    <uri>https://www.jtianling.com</uri>
    <email></email>
  </author>
  <content type="html">&lt;p&gt;学编程后, 过了初期的语法熟悉阶段, 新手往往会比较迷茫, 因为也不知道编程能干嘛, 对于这种情况, 我的建议当然是实际的做一些项目, 这里用一些游戏和 Python 的例子, 来真正的了解和熟悉编程吧.&lt;/p&gt;

&lt;!-- more --&gt;

&lt;h1 id=&quot;前提&quot;&gt;前提&lt;/h1&gt;
&lt;p&gt;以下的教程基于 Python3.7, 并且假设你已经会 Python 的基本语法和概念了.&lt;br /&gt;
要是还没有学会, Python 的各种教程太多了, 先找来学习一下吧.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://docs.python.org/zh-cn/3.7/tutorial/index.html&quot;&gt;官方文档&lt;/a&gt;&lt;br /&gt;
&lt;a href=&quot;https://www.liaoxuefeng.com/wiki/1016959663602400&quot;&gt;廖雪峰的 Python教程&lt;/a&gt;&lt;/p&gt;

&lt;h1 id=&quot;用什么写游戏&quot;&gt;用什么写游戏&lt;/h1&gt;
&lt;p&gt;写游戏一般都会用到一个叫&lt;strong&gt;游戏引擎&lt;/strong&gt;的库, 游戏引擎的概念来自汽车引擎, 汽车引擎驱动汽车, 提供动力, 游戏引擎驱动游戏, 简化我们写游戏的步骤.&lt;/p&gt;

&lt;p&gt;这里, 为了最友好的面向初学者, 我们首先用的是一个叫 pyzero 的游戏引擎, 这个引擎本身就是设计给初学者使用的, 所以接口和使用方式非常简单.&lt;/p&gt;

&lt;h1 id=&quot;准备环境&quot;&gt;准备环境&lt;/h1&gt;

&lt;p&gt;准备一个专业的环境, 一共分 3 步:&lt;/p&gt;
&lt;ol&gt;
  &lt;li&gt;安装 Python&lt;/li&gt;
  &lt;li&gt;安装 pyzero 库&lt;/li&gt;
  &lt;li&gt;找个编辑器, 比如 VSCode&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;想长久享受编程乐趣的话, 可以自己学习一下怎么弄, 环境都没弄好, 估计 Python 也还没学会. 不过对于初学者, 还是有个简化的选项, 那就是 &lt;a href=&quot;https://codewith.mu/&quot;&gt;&lt;strong&gt;Mu&lt;/strong&gt;&lt;/a&gt;, 下载, 安装, bong! 以上 3 步的工具, 就都有了.&lt;/p&gt;

&lt;p&gt;不得不感叹, 现在的编程世界, 对初学者的大门是完全敞开的, 学不学得会, 只取决于想不想学, 其实没有什么门槛.&lt;/p&gt;

&lt;p&gt;下面的教程, 都基于 Mu 来说明.&lt;/p&gt;

&lt;h1 id=&quot;mu-的操作&quot;&gt;Mu 的操作&lt;/h1&gt;
&lt;p&gt;Mu 上面一排大大的按钮, 选择 Mode, 在列表里面选择 Pygame Zero, 就表示我们准备用 pyzero 来写游戏了.
写完游戏, 按 Save 保存, 方便下次用 Load 选择文件(也可以直接把文件拖到编辑区域) 继续编写.
编写完后, 按 Play 运行游戏.&lt;/p&gt;

&lt;h1 id=&quot;第一个可运行的程序&quot;&gt;第一个可运行的程序&lt;/h1&gt;
&lt;p&gt;在编程里, 我们一般把一个方向, 最小规模的一个程序, 叫做 &lt;strong&gt;Hello World&lt;/strong&gt; 程序, 这个惯例来自于一本上世纪特别流行的 C 语言教材, 有兴趣的朋友可以去了解一下.&lt;/p&gt;

&lt;p&gt;下面看我们的程序:&lt;/p&gt;
&lt;div class=&quot;language-python highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;draw&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;():&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;screen&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;fill&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;((&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;128&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;就这么夸张, 就两行代码, 一个函数…
简单说明一下, 定义一个叫 &lt;strong&gt;draw&lt;/strong&gt; 的函数, 然后用 &lt;strong&gt;screen&lt;/strong&gt; 对象里面的 &lt;strong&gt;fill&lt;/strong&gt; 函数表示背景的填充.&lt;br /&gt;
运行上面的代码, 你会得到一个夸张的红背景.&lt;/p&gt;

&lt;p&gt;其中 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;draw&lt;/code&gt; 函数, 我们并没有像普通程序一样, 由我们自己调用, 而是由 pyzero 游戏引擎在恰当的时候调用, 我们一般把这种函数, 叫做 &lt;strong&gt;回调函数&lt;/strong&gt;, 表示我们不直接调用, 也不关心具体什么时候这个函数被调用, 只提供实现, 而是由类似 pyzero 这样的游戏引擎或者框架调用.
当然, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;draw&lt;/code&gt; 函数, 就像它的英文意思一样, 表示需要在屏幕上画东西的时候被调用, 我们的 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;screen.fill((128, 0, 0))&lt;/code&gt; 表示我们具体想画的是什么东西.&lt;br /&gt;
而 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;screen&lt;/code&gt; 对象, 属于 pyzero 游戏引擎帮我们实现的对象, 用来简化我们的绘制步骤, 下面我们会用到很多.&lt;/p&gt;

&lt;h1 id=&quot;简单解释一下颜色&quot;&gt;简单解释一下颜色&lt;/h1&gt;
&lt;p&gt;为什么上面 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;(128, 0, 0)&lt;/code&gt; 表示红色? 首先, 颜色的表示, 我们一般用所谓的光学三原色来表示, 也就是熟称的 红(Red), 绿(Green), 蓝(Blue), 我们往往用三个单词的第一个字母缩写, 即 RGB 来表示颜色的值, RGB 每个数值的范围一般是 0 到 255.&lt;br /&gt;
上面的 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;(128, 0, 0)&lt;/code&gt; 是 Python 里面的 &lt;a href=&quot;https://docs.python.org/zh-cn/3.7/tutorial/datastructures.html#tuples-and-sequences&quot;&gt;元组&lt;/a&gt;, 三个整数分别表示我们需要的颜色的 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;(R, G, B)&lt;/code&gt; 值. 
我们可以尝试调整这个元组数值, 看看打开窗口颜色的变化. 比如 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;(0, 255, 0)&lt;/code&gt; 表示纯绿色.&lt;/p&gt;

&lt;h1 id=&quot;画一些其他的东西&quot;&gt;画一些其他的东西&lt;/h1&gt;
&lt;p&gt;比如, 我们先画一个白色的圆, 来表示主角.&lt;/p&gt;

&lt;div class=&quot;language-python highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;draw&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;():&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;screen&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;draw&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;circle&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;((&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;160&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;120&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;255&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;255&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;255&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;运行程序, 能看到在漆黑像夜空一样的背景中, 有一个想星星一样的圆点.&lt;/p&gt;

&lt;p&gt;这个圆点还是用 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;screen&lt;/code&gt; 对象来实现绘制, 现在我们用的是 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;screen&lt;/code&gt; 对象里面的 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;draw&lt;/code&gt; 对象的 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;circle&lt;/code&gt; 函数(中文表示填满的圆的意思).
函数的具体参数的含义, 可以参考&lt;a href=&quot;https://pygame-zero.readthedocs.io/en/stable/builtins.html#screen&quot;&gt;pyzero官网&lt;/a&gt;&lt;/p&gt;

&lt;div class=&quot;language-python highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c1&quot;&gt;# Draw the outline of a circle.
&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;screen&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;draw&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;circle&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;pos&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;radius&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;r&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;g&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;参数解释:&lt;/p&gt;
&lt;ol&gt;
  &lt;li&gt;第一个参数, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;(160, 120)&lt;/code&gt; 也是一个元组, 表示我们想画的这个圆点的位置.&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;3&lt;/code&gt; 表示我们想画的圆的半径, 也就是用来表示圆有多大&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;(255, 255, 255)&lt;/code&gt;, 要是前面的内容看的认真, 看到这里就知道了, 这个表示圆的颜色&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;知道了参数类型以后, 我们尝试改改这几个参数, 看看画出来的圆的效果变化情况吧.&lt;/p&gt;

&lt;h1 id=&quot;坐标的含义&quot;&gt;坐标的含义&lt;/h1&gt;

&lt;p&gt;位置坐标的含义, pyzero 里面用的位置, 使用的是所谓的屏幕坐标系, 以左上角为原点(即 0,0 点), X 向右增加, Y 向下增加.
&lt;img src=&quot;/public/images/2020/axis.png&quot; alt=&quot;坐标示意图&quot; /&gt;&lt;/p&gt;

&lt;h1 id=&quot;更多形状&quot;&gt;更多形状&lt;/h1&gt;

&lt;p&gt;参考前面的&lt;a href=&quot;https://pygame-zero.readthedocs.io/en/stable/builtins.html#screen&quot;&gt;pyzero官网&lt;/a&gt;, 只要你看明白了参数的类型, 试试更多的形状吧.&lt;/p&gt;

&lt;p&gt;我推荐试试下面几个常用的, 下面是参数说明&lt;/p&gt;

&lt;div class=&quot;language-python highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c1&quot;&gt;# Draw a line from start to end. 画线
&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;screen&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;draw&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;line&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;start&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;end&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;r&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;g&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;# Draw the outline of a circle.
&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;screen&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;draw&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;circle&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;pos&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;radius&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;r&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;g&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;# Draw a filled circle. 实心圆
&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;screen&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;draw&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;filled_circle&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;pos&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;radius&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;r&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;g&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;# Draw the outline of a rectangle. 矩形
&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;screen&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;draw&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;rect&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;rect&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;r&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;g&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;# Draw a filled rectangle. 实心矩形
&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;screen&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;draw&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;filled_rect&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;rect&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;r&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;g&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;# Draw text. 文字
&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;draw&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;text&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;text&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;pos&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;**&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;kwargs&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;试试运行下面这个程序, 看看各种形状&lt;/p&gt;

&lt;div class=&quot;language-python highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;draw&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;():&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;screen&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;draw&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;text&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;Hello World&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;100&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;100&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;

    &lt;span class=&quot;c1&quot;&gt;# Draw a line from start to end.
&lt;/span&gt;    &lt;span class=&quot;n&quot;&gt;screen&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;draw&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;line&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;((&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;100&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;100&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;300&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;100&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;255&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;

    &lt;span class=&quot;c1&quot;&gt;# Draw the outline of a circle.
&lt;/span&gt;    &lt;span class=&quot;n&quot;&gt;screen&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;draw&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;circle&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;((&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;300&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;100&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;10&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;255&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;

    &lt;span class=&quot;c1&quot;&gt;# Draw a filled circle. 
&lt;/span&gt;    &lt;span class=&quot;n&quot;&gt;screen&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;draw&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;filled_circle&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;((&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;400&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;100&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;15&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;255&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;

    &lt;span class=&quot;c1&quot;&gt;# Draw the outline of a rectangle.
&lt;/span&gt;    &lt;span class=&quot;n&quot;&gt;screen&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;draw&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;rect&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Rect&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;((&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;100&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;200&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;50&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;50&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)),&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;255&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;255&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;255&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;

    &lt;span class=&quot;c1&quot;&gt;# Draw a filled rectangle. 
&lt;/span&gt;    &lt;span class=&quot;n&quot;&gt;screen&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;draw&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;filled_rect&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Rect&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;((&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;200&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;200&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;100&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;100&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)),&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;128&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;128&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;128&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h1 id=&quot;动画&quot;&gt;动画&lt;/h1&gt;
&lt;p&gt;我们都知道, 游戏不是静态的图片, 那么我们光靠静态的绘制, 也没有什么意思, 现在我们尝试让前面绘制的圆动起来.&lt;/p&gt;

&lt;p&gt;看看下面这个程序:&lt;/p&gt;

&lt;div class=&quot;language-python highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;n&quot;&gt;player_pos_x&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;100&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;player_pos_y&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;100&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;draw&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;():&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;screen&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;clear&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;screen&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;draw&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;circle&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;((&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;player_pos_x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;player_pos_y&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;255&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;255&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;255&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
    
&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;update&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;():&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;global&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;player_pos_x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;player_pos_y&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;player_pos_x&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;player_pos_x&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt; 
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;先运行一下上面的程序, 能看到一个圆, 一直在向右移动.&lt;/p&gt;

&lt;h2 id=&quot;位置变量的定义&quot;&gt;位置变量的定义&lt;/h2&gt;
&lt;p&gt;我们在新的程序里面, 不再直接用位置坐标来绘制圆了, 我们用了 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;player_pos_x&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;player_pos_y&lt;/code&gt; 两个变量, 分别表示圆的 x 坐标位置和 y 坐标位置.&lt;/p&gt;

&lt;h2 id=&quot;update-回调函数&quot;&gt;update 回调函数&lt;/h2&gt;
&lt;p&gt;这个程序已经比前面复杂很多了, 特别是我们多了一个 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;update&lt;/code&gt; 函数, 就像 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;draw&lt;/code&gt; 函数一样, 这个函数也是一个回调函数, 一般我们将我们想做的游戏逻辑, 写在这个 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;update&lt;/code&gt; 函数里面.&lt;br /&gt;
在这个例子里面, 我们是修改了 x 坐标的位置.
你自己尝试一下, 让圆从现在的从左往右移动, 改成从右往左试试. 
还有, 可以尝试让圆在 y 轴上移动试试.&lt;/p&gt;

&lt;p&gt;需要稍微注意的一点是, 在 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;update&lt;/code&gt; 函数里面, 因为需要修改函数外部的全局变量, 需要用 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;global&lt;/code&gt; 关键字说明, 不然 Python 里面默认是找局部变量的.&lt;/p&gt;

&lt;h2 id=&quot;清理屏幕&quot;&gt;清理屏幕&lt;/h2&gt;
&lt;p&gt;上面还有一个小的地方需要注意, 和原来的直接绘制圆不同, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;draw&lt;/code&gt; 函数里面在画圆之前, 多了一句 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;screen.clear&lt;/code&gt;. 表示在每次绘制的时候, 先把屏幕清理干净.
为了加深对清理屏幕作用的理解, 你可以尝试把这一行删掉, 看看会发生什么.&lt;/p&gt;

&lt;h1 id=&quot;操作&quot;&gt;操作&lt;/h1&gt;
&lt;p&gt;游戏, 也不光光是动画, 我们还要能操作才行.  说到这里, 我已经能给出游戏的完整表述的:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;游戏, 就是可以即时交互的动画&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;试试下面的程序, 并在程序运行时, 尝试按按键盘或者任何可以操作键.&lt;/p&gt;
&lt;div class=&quot;language-python highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;n&quot;&gt;player_pos_x&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;100&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;player_pos_y&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;100&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;draw&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;():&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;screen&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;clear&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;screen&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;draw&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;circle&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;((&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;player_pos_x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;player_pos_y&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;255&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;255&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;255&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
    
&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;update&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;():&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;global&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;player_pos_x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;player_pos_y&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;player_pos_x&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;player_pos_x&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt; 
    
&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;on_key_down&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;():&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;global&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;player_pos_x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;player_pos_y&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;player_pos_y&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;player_pos_y&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;10&lt;/span&gt; 
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;我们能看到, 除了圆持续的还是往右移动以外, 每次按下任意一个按键, 圆都会往下移动 10 个像素.&lt;/p&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;on_key_down&lt;/code&gt; 这个回调函数, 会在我们按下按键的时候产生被调用. 不过目前我们并没有判断按下的是什么按键.&lt;/p&gt;

&lt;h1 id=&quot;真实的操作&quot;&gt;真实的操作&lt;/h1&gt;

&lt;p&gt;前面的例子里面, 我们没有判断按下的按键是什么, 这个比较无聊, 我们来看看真正的简单操作应该是什么样的.&lt;/p&gt;

&lt;div class=&quot;language-python highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;n&quot;&gt;player_pos_x&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;100&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;player_pos_y&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;100&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;draw&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;():&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;screen&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;clear&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;screen&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;draw&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;circle&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;((&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;player_pos_x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;player_pos_y&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;255&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;255&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;255&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
      
&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;on_key_down&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;key&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;global&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;player_pos_x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;player_pos_y&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;key&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;keys&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;LEFT&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;player_pos_x&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;player_pos_x&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;10&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;elif&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;key&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;keys&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;RIGHT&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;player_pos_x&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;player_pos_x&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;10&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;elif&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;key&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;keys&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;UP&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;player_pos_y&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;player_pos_y&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;10&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;elif&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;key&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;keys&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;DOWN&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;player_pos_y&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;player_pos_y&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;10&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;我们去掉了 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;update&lt;/code&gt; 函数, 并且判断了 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;on_key_down&lt;/code&gt; 被回调时, 传进来的 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;key&lt;/code&gt; 参数的值, 然后再按我们设定的规则去操作了这个圆, 试试吧.
具体的按键枚举, 还是可以在&lt;a href=&quot;https://pygame-zero.readthedocs.io/en/stable/hooks.html#buttons-and-keys&quot;&gt;pyzero官网&lt;/a&gt;看到&lt;/p&gt;

&lt;h1 id=&quot;课后练习&quot;&gt;课后练习&lt;/h1&gt;
&lt;p&gt;这里我留下一个思考题, 我们平时操作游戏的时候, 不会一直不停的按键盘, 那样太累, 怎么样把上面的程序改成当我们按下方向键的时候, 圆一直移动呢?&lt;/p&gt;

&lt;p&gt;这里给个提示, 你还需要实现 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;on_key_up&lt;/code&gt; 函数, 来获得我们松开键盘按键的信息.&lt;/p&gt;

&lt;h1 id=&quot;第一篇的结束&quot;&gt;第一篇的结束&lt;/h1&gt;
&lt;p&gt;我们现在已经了解了一个游戏需要的基础知识, 游戏开发的大门, 已经向我们打开了, 有想好要做什么游戏了吗?&lt;/p&gt;

  &lt;p&gt;&lt;a href=&quot;https://www.jtianling.com/learn-python-by-game-examples-1.html&quot;&gt;用 Python 写游戏 第一篇&lt;/a&gt; was originally published by  at &lt;a href=&quot;https://www.jtianling.com&quot;&gt;九天雁翎的博客&lt;/a&gt; on March 07, 2020.&lt;/p&gt;</content>
</entry>


<entry>
  <title type="html"><![CDATA[用 Python 写游戏 第一篇 课后习题答案]]></title>
 <link rel="alternate" type="text/html" href="https://www.jtianling.com/learn-python-by-game-examples-1-answer.html" />
  <id>https://www.jtianling.com/learn-python-by-game-examples-1-answer</id>
  <published>2020-03-07T00:00:00+08:00</published>
  <updated>2020-03-07T00:00:00+08:00</updated>
  <author>
    <name></name>
    <uri>https://www.jtianling.com</uri>
    <email></email>
  </author>
  <content type="html">&lt;p&gt;用 Python 写游戏 第一篇 课后习题答案&lt;/p&gt;

&lt;!-- more --&gt;

&lt;h1 id=&quot;第一篇课后练习&quot;&gt;第一篇课后练习&lt;/h1&gt;
&lt;p&gt;这里我留下一个思考题, 我们平时操作游戏的时候, 不会一直不停的按键盘, 那样太累, 怎么样把上面的程序改成当我们按下方向键的时候, 圆一直移动呢?&lt;/p&gt;

&lt;p&gt;这里给个提示, 你还需要实现 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;on_key_up&lt;/code&gt; 函数, 来获得我们松开键盘按键的信息.&lt;/p&gt;

&lt;h1 id=&quot;答案&quot;&gt;答案&lt;/h1&gt;

&lt;div class=&quot;language-python highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;
&lt;span class=&quot;n&quot;&gt;player_pos_x&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;100&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;player_pos_y&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;100&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;draw&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;():&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;screen&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;clear&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;screen&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;draw&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;filled_circle&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;((&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;player_pos_x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;player_pos_y&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;255&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;255&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;255&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;up&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;bp&quot;&gt;False&lt;/span&gt;    
&lt;span class=&quot;n&quot;&gt;down&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;bp&quot;&gt;False&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;left&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;bp&quot;&gt;False&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;right&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;bp&quot;&gt;False&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;on_key_down&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;key&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;global&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;up&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;down&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;left&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;right&lt;/span&gt;
   
    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;key&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;keys&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;UP&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;up&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;bp&quot;&gt;True&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;elif&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;key&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;keys&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;DOWN&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;down&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;bp&quot;&gt;True&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;elif&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;key&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;keys&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;LEFT&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;left&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;bp&quot;&gt;True&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;elif&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;key&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;keys&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;RIGHT&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;right&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;bp&quot;&gt;True&lt;/span&gt;        

&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;update&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;():&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;global&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;up&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;down&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;left&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;right&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;player_pos_x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;player_pos_y&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;up&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;player_pos_y&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;player_pos_y&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;down&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;player_pos_y&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;player_pos_y&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;left&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;player_pos_x&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;player_pos_x&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;right&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;player_pos_x&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;player_pos_x&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;
        
&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;on_key_up&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;key&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;global&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;down&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;up&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;left&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;right&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;key&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;keys&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;UP&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;up&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;bp&quot;&gt;False&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;elif&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;key&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;keys&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;DOWN&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;down&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;bp&quot;&gt;False&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;elif&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;key&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;keys&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;LEFT&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;left&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;bp&quot;&gt;False&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;elif&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;key&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;keys&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;RIGHT&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;right&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;bp&quot;&gt;False&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;该习题完成后, 我们就有了一个可以较自由操作的主角了, 期待接下来的课程吧.&lt;/p&gt;

  &lt;p&gt;&lt;a href=&quot;https://www.jtianling.com/learn-python-by-game-examples-1-answer.html&quot;&gt;用 Python 写游戏 第一篇 课后习题答案&lt;/a&gt; was originally published by  at &lt;a href=&quot;https://www.jtianling.com&quot;&gt;九天雁翎的博客&lt;/a&gt; on March 07, 2020.&lt;/p&gt;</content>
</entry>


<entry>
  <title type="html"><![CDATA[读瑞 达利欧的"原则"]]></title>
 <link rel="alternate" type="text/html" href="https://www.jtianling.com/review-of-principles.html" />
  <id>https://www.jtianling.com/review-of-principles</id>
  <published>2018-12-16T00:00:00+08:00</published>
  <updated>2018-12-16T00:00:00+08:00</updated>
  <author>
    <name></name>
    <uri>https://www.jtianling.com</uri>
    <email></email>
  </author>
  <content type="html">&lt;p&gt;作者瑞·达利欧(Ray Dalio), 是世界上当前资产规模最大的对冲基金, 桥水基金的创始人.  听着 “原则” 这种书名, 又是所谓 “成功人士” 写的书, 放在两年前的话, 这种书我光看介绍, 都会直接过滤掉, 无非就是那种 “成功人士” 向你兜售一些所谓的成功秘方, 只要按照”我”的做, 你就能像”我”一样成功这种.&lt;br /&gt;
但是, 去年我因为别人推荐, 看了查理芒格的 “穷查理宝典”, 对做投资的人有了一些新的认识, 甚至对这个世界也有了一些新的认识.  总的来说, 就是我发现, 要是一个人纯粹靠投资就能成功, 一定是对这个世界的运行规律, 有非常深刻的认识, 而为了对这个世界有充分的认识呢, 这个人读的书一定非常多, 比如查理芒格, 你看他的书, 会感觉他就不像个做投资的, 更像个学者, 或者哲学家那种, 这个以后有机会再说说.&lt;br /&gt;
实际上, 看完 “原则” 这本书, 也会觉得 瑞·达利欧 是一个很理想主义的学者.&lt;br /&gt;
原则这本书分三部分, 第一部分是作者的自传, 第二, 三部分分别是生活原则和工作原则, 原则有好几百条, 我只选择感触最深的三个讲一下.&lt;/p&gt;

&lt;!-- more --&gt;

&lt;h1 id=&quot;作者的经历&quot;&gt;作者的经历&lt;/h1&gt;
&lt;p&gt;第一部分的故事非常有意思, 瑞·达利欧讲述了他自己怎么一次又一次的犯下很严重的错误, 好像每一次都快破产了, 然后每次犯错后是怎么思考的, 最后他得出来了一个很有意思的思维过程, 那就是从认为 “我是对的”, 变成问自己 “我怎么知道我是对的”, 而回答这个问题的方式, 他想的是跟其他人交流, 但是呢, 不是去交流其他人的意见或结论, 而是去理解其他人的推理过程, 并且还让别人对自己的推理过程进行 “压力测试”.  他说, “我们都可以通过这种方式降低自己犯错的可能性”.&lt;br /&gt;
我想下一次我要做一些特别重要的决定的时候, 可能真会试试这个办法.  同时, 现在我自己有一些想法的时候, 也愿意把推理的过程讲出来, 这样要是有问题, 别人也能指出来.&lt;br /&gt;
还有个故事, 我印象挺深的, 他说到他因为精力原因, 放弃了 “桥水中国合作伙伴” 这个公司的时候, 想法很有意思, 他明明确信中国会在 21 世纪成为全球最大的经济体, 而且他要是把全部精力投入到中国这边的公司的话, 他会取得很大的成功, 但是, 尽管错过了这个好机会, 但他说他并不后悔他的决定, 他说&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;如果你以勤奋和有创造性的方式工作, 你几乎可以得到你想要的任何东西, 但你不可能同时得到所有东西.&lt;br /&gt;
成熟意味着你可以放弃一些好的选择, 从而追求更好的选择.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;他说的意思首先是说不要贪心, 而且, 成熟的选择, 意味着放弃, 我觉得比一般人看问题, 更深刻的地方在, 甚至放弃的还不是差的选择, 那没什么好纠结的, 为了更好的选择, 我们连一些很好的选择都应该放弃.&lt;/p&gt;

&lt;h1 id=&quot;真实的面对自己--极度求真和极度透明&quot;&gt;真实的面对自己 + 极度求真和极度透明&lt;/h1&gt;
&lt;p&gt;然后是我感触最深的两个原则.&lt;br /&gt;
讲生活原则的时候, 瑞·达利欧说要真实的面对自己, 讲工作原则的时候, 瑞·达利欧说要极度求真和极度透明.&lt;br /&gt;
我觉得这两个事情本质上是类似的, 一个是真实的面对自己, 一个是真实的对待他人.&lt;/p&gt;

&lt;h2 id=&quot;先说真实的面对自己&quot;&gt;先说真实的面对自己&lt;/h2&gt;
&lt;p&gt;首先, 真实的面对自己真的很难, 因为人的本性就是会拔高自己的, 比如瑞·达利欧就举了个例子, 假如让大家评估自己在某个机构中的贡献比例, 得到的总数大概是 300%, 也就是平均每人会高估自己 3 倍.&lt;br /&gt;
其次, 人是不会愿意暴露自己缺点的, 往往要隐藏起来, 这样在别人的心目中的形象会更好一些.&lt;br /&gt;
然后, 人都愿意听好话, 不会愿意承认自己实际是有缺点的, 听到对自己的批评本身就是有很强的挫折感, 很痛苦.&lt;br /&gt;
那要对自己真实, 怎么做到呢:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;不要为自身形象担心, 只需关心能不能实现你的目标.&lt;/li&gt;
  &lt;li&gt;不要让痛苦妨碍进步, 要理解对自己不真实本身, 实际是会阻碍自己进步的, 你都觉得自己啥都知道了, 那还学啥, 我们的目标应该是要真的成为一个很厉害的人, 而不是装成一个很厉害的人.&lt;/li&gt;
  &lt;li&gt;自我归因, 不要把不好的结果归咎于任何人, 从自己身上找原因.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2 id=&quot;真实的面对他人&quot;&gt;真实的面对他人&lt;/h2&gt;

&lt;p&gt;瑞·达利欧说的极度透明到什么地步呢, 他说的是:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;若不想当面议论别人, 背地里也不要说, 要批评别别人就当面指出来&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;这一条, 对于下属员工也适用的话, 就需要非常透明和真实才行, 还得考虑下属能否真能接受.  就算在美国, 我看瑞·达利欧自己书中也说有媒体说他疯了, 而且看到一些文章说, 桥水的新员工离职率比较高.&lt;/p&gt;

&lt;h1 id=&quot;培养人&quot;&gt;培养人&lt;/h1&gt;
&lt;ol&gt;
  &lt;li&gt;不断的提供反馈, 这也是我对培养人感觉最有用的手段&lt;/li&gt;
  &lt;li&gt;反馈包括鼓励和批评, 需要准确的评价&lt;/li&gt;
  &lt;li&gt;授人以渔&lt;/li&gt;
  &lt;li&gt;允许犯错, 瑞·达利欧说 他对别人宽容到什么程度时, 说:&lt;/li&gt;
&lt;/ol&gt;

&lt;blockquote&gt;
  &lt;p&gt;我可以容忍你把车蹭掉了漆或撞凹了一块, 但我不会冒很大风险让你把车子给毁了.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;怎么把被培养的人犯的错误控制在能接受的范围内, 本身也是 leader 的职责.&lt;/p&gt;

&lt;h1 id=&quot;还有很多值得一提的原则&quot;&gt;还有很多值得一提的原则&lt;/h1&gt;
&lt;ol&gt;
  &lt;li&gt;当心 “温水煮青蛙综合症”, 人们都有慢慢习惯于不可接受事物的倾向.  在公司看到不少这种情况, 我后来了解到这种行为是有心理学基础的, 参看 &lt;a href=&quot;https://wiki.mbalib.com/wiki/%E4%B9%A0%E5%BE%97%E6%80%A7%E6%97%A0%E5%8A%A9&quot;&gt;“习得性无助”&lt;/a&gt;, 原来看到乔布斯的 “Stay hungry, Stay foolish”, 欣赏的是用hungry和foolish来表达自己求知的状态, 现在其实发现, 最有力的字是 “Stay”, 一时hungry/foolish易, “stay”最难.&lt;/li&gt;
  &lt;li&gt;把公司当做一台运转的机器, 由”文化和人”两个部件构成, 当出现问题是, 诊断问题的步骤:&lt;/li&gt;
&lt;/ol&gt;

&lt;blockquote&gt;
  &lt;ol&gt;
    &lt;li&gt;结果是好是坏?&lt;/li&gt;
    &lt;li&gt;谁对结果负责?&lt;/li&gt;
    &lt;li&gt;如果结果不好, 是因为责任人能力不够还是机器设计有问题?&lt;/li&gt;
  &lt;/ol&gt;
&lt;/blockquote&gt;

&lt;p&gt;并且要探寻到问题的根源, 而不是表面.&lt;/p&gt;
&lt;ol&gt;
  &lt;li&gt;问责过程要触及你直接下属的下一级&lt;/li&gt;
  &lt;li&gt;创意择优的决策方式&lt;/li&gt;
  &lt;li&gt;几个公式:&lt;/li&gt;
&lt;/ol&gt;

&lt;blockquote&gt;
  &lt;p&gt;梦想 + 现实 + 决心 = 成功的生活&lt;br /&gt;
痛苦 + 反思 = 进步&lt;br /&gt;
思考 -&amp;gt; 原则 -&amp;gt; 算法 -&amp;gt; 好决策&lt;br /&gt;
创意择优 = 极度求真 + 极度透明 + 可信度加权的决策&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;好内容太多, 无法一一列举.&lt;/p&gt;

&lt;h1 id=&quot;结束&quot;&gt;结束&lt;/h1&gt;
&lt;p&gt;用瑞·达利欧在第一章前就写到的这句话结尾:&lt;/p&gt;
&lt;blockquote&gt;
  &lt;p&gt;时间就像一条河流, 带着我们顺流而下, 我们会碰到各种问题, 需要我们去决策, 但我们没有办法停下来, 也没有办法躲避, 只能用我们选择的最好的方式去应对.&lt;/p&gt;
&lt;/blockquote&gt;


  &lt;p&gt;&lt;a href=&quot;https://www.jtianling.com/review-of-principles.html&quot;&gt;读瑞 达利欧的"原则"&lt;/a&gt; was originally published by  at &lt;a href=&quot;https://www.jtianling.com&quot;&gt;九天雁翎的博客&lt;/a&gt; on December 16, 2018.&lt;/p&gt;</content>
</entry>


<entry>
  <title type="html"><![CDATA[写一个自己的Golang Module(Golang1.11以后版本支持)]]></title>
 <link rel="alternate" type="text/html" href="https://www.jtianling.com/private-module-in-golang.html" />
  <id>https://www.jtianling.com/private-module-in-golang</id>
  <published>2018-09-28T00:00:00+08:00</published>
  <updated>2018-09-28T00:00:00+08:00</updated>
  <author>
    <name></name>
    <uri>https://www.jtianling.com</uri>
    <email></email>
  </author>
  <content type="html">&lt;p&gt;在新的Golang 1.11版本中, 官方实验性添加了一种标准的 Module 写法, 用于替代原来非常不方便的 vendor, GOPATH 那一套东西, 经过了这么长时间, 那批老顽固总算是搞清楚了一些什么. Golang 原来的包管理, 可以说是新一代的语言里面最垃圾的.&lt;/p&gt;

&lt;!-- more --&gt;

&lt;h1 id=&quot;一个-module-的诞生-go-module-的-hello-world&quot;&gt;一个 Module 的诞生, go module 的 hello world&lt;/h1&gt;

&lt;p&gt;首先, 在 GOPATH 目录以外, 建一个 Module 想放的目录, 是的, 不要放在原来的 GOPATH 里面.&lt;br /&gt;
通过 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;go mod init MODULE_NAME&lt;/code&gt; 来初始化一个想要建立的 Module, 比如下面这样:&lt;/p&gt;
&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;go mod init github.com/jtianling/goModule

go: creating new go.mod: module github.com/jtianling/goModule
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;此时会在当前目录下面新建一个叫 go.mod 的文件, 你可以理解成类似 package.json 的文件(事实上格式也挺像的)&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nv&quot;&gt;$cat&lt;/span&gt; go.mod

module github.com/jtianling/goModule
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;然后开始创建自己 Module 的内容吧&lt;/p&gt;
&lt;div class=&quot;language-go highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;package&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;goModule&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
    &lt;span class=&quot;s&quot;&gt;&quot;fmt&quot;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Print&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;fmt&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Println&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;hello, world&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;提交项目文件到 github 以后, 我们找个工程来应用这个新写的 Module.&lt;/p&gt;

&lt;p&gt;新建一个 goModuleTest 目录, 用 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;go mod init goModuleTest&lt;/code&gt; 再初始化这个测试工程.&lt;br /&gt;
创建一个调用前面 module 的 main.go 文件:&lt;/p&gt;

&lt;div class=&quot;language-go highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;package&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;main&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
  &lt;span class=&quot;s&quot;&gt;&quot;github.com/jtianling/goModule&quot;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;main&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;goModule&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Print&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;用 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;go build&lt;/code&gt; 尝试编译运行&lt;/p&gt;
&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;go build

go: finding github.com/jtianling/goModule latest
go: downloading github.com/jtianling/goModule v0.0.0-20180928104915-d4c10f8ba563

&lt;span class=&quot;nv&quot;&gt;$.&lt;/span&gt;/goModuleTest

hello, world
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;运行没有毛病, 而且自动化的下载了我们引用了的库.&lt;/p&gt;

&lt;h1 id=&quot;版本控制&quot;&gt;版本控制&lt;/h1&gt;
&lt;p&gt;go module 使用了&lt;a href=&quot;https://semver.org/&quot;&gt;语义化的版本号&lt;/a&gt;, 简单的说就是v(major).(minor).(patch), 实践中, 只要 API 不兼容的时候, 就应该提 major 版本, 增加 API 或者优化, 可以自增加 minor 版本号.&lt;br /&gt;
在 goModule 目录下,&lt;/p&gt;
&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;git tag v0.0.1
&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;git push &lt;span class=&quot;nt&quot;&gt;--tags&lt;/span&gt;

Total 0 &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;delta 0&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;, reused 0 &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;delta 0&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
To github.com:jtianling/goModule.git
 &lt;span class=&quot;k&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;new tag]         v0.0.1 -&amp;gt; v0.0.1
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;然后删掉 goMoudleTest 工程, 再来一次, 结果会有些不一样:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;go build

go build
go: finding github.com/jtianling/goModule v0.0.1
go: downloading github.com/jtianling/goModule v0.0.1

&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;cat &lt;/span&gt;go.mod

module goModuleTest

require github.com/jtianling/goModule v0.0.1
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;没错, 增加了版本号, 我们试试升级自己的 module, 并 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;git tag v0.0.2&lt;/code&gt; 试试, 
然后在 goModuleTest 工程中, 可以通过传统的 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;go get&lt;/code&gt; 加指定的版本号升级:&lt;/p&gt;
&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;$ go get github.com/jtianling/goModule@v0.0.2

go: finding github.com/jtianling/goModule v0.0.2
go: downloading github.com/jtianling/goModule v0.0.2

$ cat go.mod
module goModuleTest

require github.com/jtianling/goModule v0.0.2
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;可以看到 go.mod 里面的内容也自动变了. 此时再 build 然后运行, 会发现 module 正常更新了.&lt;br /&gt;
假如不想指定版本, 仅仅想更新到最新版本, 可以通过&lt;br /&gt;
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;go get github.com/jtianling/goModule@latest&lt;/code&gt; 的形式更新到最新版&lt;br /&gt;
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;go get -u&lt;/code&gt; 的形式升级所有的依赖库&lt;/p&gt;

&lt;h1 id=&quot;多-package-的-module&quot;&gt;多 package 的 module&lt;/h1&gt;
&lt;p&gt;一个 package 的 module 好说, 假如你的 module 包含多个 package, 那么所有的 package 指定的时候, 直接用 package 明就好, 但是 import 的时候应该有共同的前缀.
如下:&lt;/p&gt;

&lt;div class=&quot;language-go highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c&quot;&gt;// content.go in goModule/content&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;package&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;content&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
    &lt;span class=&quot;s&quot;&gt;&quot;fmt&quot;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Print&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;fmt&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Println&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;hello, world v0.0.3&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;c&quot;&gt;// module.go&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;package&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;goModule&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
    &lt;span class=&quot;s&quot;&gt;&quot;github.com/jtianling/goModule/content&quot;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Print&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;content&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Print&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h1 id=&quot;module-测试&quot;&gt;module 测试&lt;/h1&gt;
&lt;p&gt;module 文件同样支持 golang 自带的 unit test 方法, 可以方便的在发布前进行单元测试:&lt;/p&gt;

&lt;div class=&quot;language-go highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c&quot;&gt;// goModule_test.go&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;package&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;goModule_test&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
  &lt;span class=&quot;s&quot;&gt;&quot;testing&quot;&lt;/span&gt;
  &lt;span class=&quot;s&quot;&gt;&quot;github.com/jtianling/goModule&quot;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;TestPrint&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;t&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;testing&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;T&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;goModule&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Print&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;测试方法也一样&lt;/p&gt;
&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;go &lt;span class=&quot;nb&quot;&gt;test

&lt;/span&gt;hello, world v0.0.3
PASS
ok  	github.com/jtianling/goModule	0.005s
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h1 id=&quot;私有的-module&quot;&gt;私有的 module&lt;/h1&gt;
&lt;p&gt;对于公开的 module, 按上面的做法已经够用了, 私有的 module 需要对 module 的引用做一些处理, 因为 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;go get&lt;/code&gt; 实际是利用了git, 所以我们通过 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;git config&lt;/code&gt; 改改 url 就能做到.  下面以 github 为例.&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;git config &lt;span class=&quot;nt&quot;&gt;--global&lt;/span&gt; url.&lt;span class=&quot;s2&quot;&gt;&quot;git@github.com:&quot;&lt;/span&gt;.insteadOf &lt;span class=&quot;s2&quot;&gt;&quot;https://github.com/&quot;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;对于自己的私有仓库, 可能还需要用 http:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;git config &lt;span class=&quot;nt&quot;&gt;--global&lt;/span&gt; url.&lt;span class=&quot;s2&quot;&gt;&quot;git@github.com:&quot;&lt;/span&gt;.insteadOf &lt;span class=&quot;s2&quot;&gt;&quot;http://github.com/&quot;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h1 id=&quot;参考&quot;&gt;参考&lt;/h1&gt;

&lt;p&gt;1.&lt;a href=&quot;https://github.com/golang/go/wiki/Modules&quot;&gt;golang wiki&lt;/a&gt;&lt;/p&gt;


  &lt;p&gt;&lt;a href=&quot;https://www.jtianling.com/private-module-in-golang.html&quot;&gt;写一个自己的Golang Module(Golang1.11以后版本支持)&lt;/a&gt; was originally published by  at &lt;a href=&quot;https://www.jtianling.com&quot;&gt;九天雁翎的博客&lt;/a&gt; on September 28, 2018.&lt;/p&gt;</content>
</entry>


<entry>
  <title type="html"><![CDATA[读"面向模式的软件架构1-模式系统"]]></title>
 <link rel="alternate" type="text/html" href="https://www.jtianling.com/review-of-a-system-of-patterns.html" />
  <id>https://www.jtianling.com/review-of-a-system-of-patterns</id>
  <published>2018-02-28T00:00:00+08:00</published>
  <updated>2018-02-28T00:00:00+08:00</updated>
  <author>
    <name></name>
    <uri>https://www.jtianling.com</uri>
    <email></email>
  </author>
  <content type="html">&lt;p&gt;该书把软件的设计模式分类分的更细, 在 GOF 设计模式上, 增加了一个架构模式, 在下面增加了一个 “成例”(Idiom), 也叫代码模式.  &lt;br /&gt;
书中也算是理清了一些概念, 并给出了一些概念的定义, 但是整体看下来, 并不如 GOF 的设计模式那么经典, 特别是模式的选择上, 要么是一个分类只提供1个模式, 要么是我感觉一些所谓的模式根本不足以支撑这个分类, 还有的模式横跨了几个分类…
另外, 看了这本书后远不如看GOF的书后那种大呼过瘾的感觉, 而是感觉世间的设计模式只有一种–增加中间层&lt;/p&gt;

&lt;!-- more --&gt;

&lt;p&gt;&lt;img src=&quot;/public/images/2018/mindmap-of-a-system-of-patterns.png&quot; alt=&quot;面向模式的软件架构1-模式系统一书的思维导图&quot; /&gt;&lt;/p&gt;


  &lt;p&gt;&lt;a href=&quot;https://www.jtianling.com/review-of-a-system-of-patterns.html&quot;&gt;读"面向模式的软件架构1-模式系统"&lt;/a&gt; was originally published by  at &lt;a href=&quot;https://www.jtianling.com&quot;&gt;九天雁翎的博客&lt;/a&gt; on February 28, 2018.&lt;/p&gt;</content>
</entry>


<entry>
  <title type="html"><![CDATA[读"启动大脑"]]></title>
 <link rel="alternate" type="text/html" href="https://www.jtianling.com/review-of-use-your-head.html" />
  <id>https://www.jtianling.com/review-of-use-your-head</id>
  <published>2018-02-26T00:00:00+08:00</published>
  <updated>2018-02-26T00:00:00+08:00</updated>
  <author>
    <name></name>
    <uri>https://www.jtianling.com</uri>
    <email></email>
  </author>
  <content type="html">&lt;p&gt;用一天的上下班路上的时间把 “启动大脑” 一书快速略读了一遍, 大概花了1个多小时, 用的方法就是书上介绍的, 先看目录, 找到目标, 然后再略读一遍, 然后再回头复习一遍, 顺便画了下面的思维导图.&lt;br /&gt;
最近一年听了 “得到” 上不少的书籍音频, 但是感觉假如能自己快速的阅读的话, 还是需要自己读才能有比较深刻的印象, 不然光凭听一遍, 基本上是过耳忘.&lt;/p&gt;

&lt;!-- more --&gt;

&lt;p&gt;&lt;img src=&quot;/public/images/2018/mindmap-of-use-your-head.png&quot; alt=&quot;启动大脑一书的思维导图&quot; /&gt;&lt;/p&gt;


  &lt;p&gt;&lt;a href=&quot;https://www.jtianling.com/review-of-use-your-head.html&quot;&gt;读"启动大脑"&lt;/a&gt; was originally published by  at &lt;a href=&quot;https://www.jtianling.com&quot;&gt;九天雁翎的博客&lt;/a&gt; on February 26, 2018.&lt;/p&gt;</content>
</entry>


<entry>
  <title type="html"><![CDATA[读"思维导图"]]></title>
 <link rel="alternate" type="text/html" href="https://www.jtianling.com/review-of-the-mind-map-book.html" />
  <id>https://www.jtianling.com/review-of-the-mind-map-book</id>
  <published>2018-02-26T00:00:00+08:00</published>
  <updated>2018-02-26T00:00:00+08:00</updated>
  <author>
    <name></name>
    <uri>https://www.jtianling.com</uri>
    <email></email>
  </author>
  <content type="html">&lt;p&gt;最近再次简单的略读了一下”思维导图”这本书, 感觉还是值得看一下的, 毕竟名气那么大, 至于怎么用, 那就看自己了. 顺便, 为”思维导图” 一书画了个思维导图.&lt;/p&gt;

&lt;!-- more --&gt;

&lt;p&gt;&lt;img src=&quot;/public/images/2018/mindmap-of-the-mind-map-book.png&quot; alt=&quot;思维导图一书的思维导图&quot; /&gt;&lt;/p&gt;


  &lt;p&gt;&lt;a href=&quot;https://www.jtianling.com/review-of-the-mind-map-book.html&quot;&gt;读"思维导图"&lt;/a&gt; was originally published by  at &lt;a href=&quot;https://www.jtianling.com&quot;&gt;九天雁翎的博客&lt;/a&gt; on February 26, 2018.&lt;/p&gt;</content>
</entry>


<entry>
  <title type="html"><![CDATA[小议入门语言对初学者的影响]]></title>
 <link rel="alternate" type="text/html" href="https://www.jtianling.com/talk-about-the-first-programming-language-you-learn.html" />
  <id>https://www.jtianling.com/talk-about-the-first-programming-language-you-learn</id>
  <published>2017-10-28T00:00:00+08:00</published>
  <updated>2017-10-28T00:00:00+08:00</updated>
  <author>
    <name></name>
    <uri>https://www.jtianling.com</uri>
    <email></email>
  </author>
  <content type="html">&lt;p&gt;很多初学编程的人都喜欢问一个问题, 那就是刚开始学编程, 首先学什么语言好啊, 在不同的阶段, 我自己关于这个问题的思考也不一样, 这里聊聊我现在的思考.&lt;/p&gt;

&lt;!-- more --&gt;

&lt;p&gt;&lt;strong&gt;目录&lt;/strong&gt;:&lt;/p&gt;

&lt;ul id=&quot;markdown-toc&quot;&gt;
  &lt;li&gt;&lt;a href=&quot;#常见的回答&quot; id=&quot;markdown-toc-常见的回答&quot;&gt;常见的回答&lt;/a&gt;    &lt;ul&gt;
      &lt;li&gt;&lt;a href=&quot;#不屑的态度&quot; id=&quot;markdown-toc-不屑的态度&quot;&gt;不屑的态度&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;#从简单的入门&quot; id=&quot;markdown-toc-从简单的入门&quot;&gt;从简单的入门&lt;/a&gt;&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#我的思考&quot; id=&quot;markdown-toc-我的思考&quot;&gt;我的思考&lt;/a&gt;    &lt;ul&gt;
      &lt;li&gt;&lt;a href=&quot;#语言决定了工作的领域&quot; id=&quot;markdown-toc-语言决定了工作的领域&quot;&gt;语言决定了工作的领域&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;#语言的选择-也是语言环境的选择&quot; id=&quot;markdown-toc-语言的选择-也是语言环境的选择&quot;&gt;语言的选择, 也是语言环境的选择&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;#一开始熟悉的语言-决定了你的思维方式&quot; id=&quot;markdown-toc-一开始熟悉的语言-决定了你的思维方式&quot;&gt;一开始熟悉的语言, 决定了你的思维方式&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;#语言决定了你的学习方向&quot; id=&quot;markdown-toc-语言决定了你的学习方向&quot;&gt;语言决定了你的学习方向&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;#你还觉得入门语言的选择不重要吗&quot; id=&quot;markdown-toc-你还觉得入门语言的选择不重要吗&quot;&gt;你还觉得入门语言的选择不重要吗&lt;/a&gt;&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#怎么选择入门语言&quot; id=&quot;markdown-toc-怎么选择入门语言&quot;&gt;怎么选择入门语言&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#我是怎么选择的&quot; id=&quot;markdown-toc-我是怎么选择的&quot;&gt;我是怎么选择的&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#最后&quot; id=&quot;markdown-toc-最后&quot;&gt;最后&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h1 id=&quot;常见的回答&quot;&gt;常见的回答&lt;/h1&gt;
&lt;h2 id=&quot;不屑的态度&quot;&gt;不屑的态度&lt;/h2&gt;
&lt;p&gt;常常能看到很多&lt;em&gt;牛人&lt;/em&gt;对这种问题都是很不屑的, 包括我在以前某个阶段, 也是这种态度, 总体上的意思就是, 假如你真成为了程序员, 那么你总归会学会一大堆编程语言, 所以, 你刚开始学什么并不重要, 学就好了, 重要的是你快点开始学.&lt;br /&gt;
现在我认为这种态度是有问题的, 因为最后你能吃饱, 所以吃什么, 怎么吃, 吃东西的顺序就不重要? 当然不是.&lt;/p&gt;

&lt;h2 id=&quot;从简单的入门&quot;&gt;从简单的入门&lt;/h2&gt;
&lt;p&gt;稍微靠谱点的人, 会推荐你从某个简单的语言入门, 比如Python, JavaScript, 理由也是类似语言不重要, 重要的是先学会编程思考的逻辑和通过入门语言学会常见编程语言的特性, 然后就可以触类旁通, 用任何你实际需要的语言工作就好了.&lt;br /&gt;
那么问题来了, 入门语言只要是相对简单, 并且没有什么大的毛病就好了吗?  其实没有那么简单.&lt;/p&gt;

&lt;h1 id=&quot;我的思考&quot;&gt;我的思考&lt;/h1&gt;
&lt;p&gt;我觉得一般常见的回答都把入门的语言选择这个事情考虑的太简单了, 也把这个决定的影响看的太小.&lt;br /&gt;
刚开始学编程时选择的入门语言对初学者的影响其实非常大, 起码有以下几点:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;语言决定了工作的领域&lt;/li&gt;
  &lt;li&gt;语言的选择, 也是语言环境的选择&lt;/li&gt;
  &lt;li&gt;语言决定了你的思维方式&lt;/li&gt;
  &lt;li&gt;语言决定了你的学习方向&lt;/li&gt;
&lt;/ol&gt;

&lt;h2 id=&quot;语言决定了工作的领域&quot;&gt;语言决定了工作的领域&lt;/h2&gt;
&lt;p&gt;初学的编程语言, 很可能就是初学者找的第一份工作用的语言, 而因为不同的语言都有自己擅长的领域, 所以这个语言的选择几乎就决定了你第一份工作的领域.&lt;br /&gt;
要求初学者先从某个语言入门(比如Python), 然后再考虑自己想找什么工作, 再学会这个工作会用的语言, 这个弯路走的就有点远了.&lt;/p&gt;

&lt;p&gt;进一步的说, 就算同样是编程, 在不同的细分领域之间的切换其实是有比较大的成本的, 也没那么简单, 对于一些人来说(特别是没有那么愿意不停折腾的人) 这可能就是你一辈子工作的领域.&lt;/p&gt;

&lt;p&gt;这个, 当然需要慎之又慎.&lt;/p&gt;

&lt;h2 id=&quot;语言的选择-也是语言环境的选择&quot;&gt;语言的选择, 也是语言环境的选择&lt;/h2&gt;
&lt;p&gt;说只需要学会语言特性, 就能简单的在多种语言中切换的人, 十有八九的确是用新的语言在做一些简单的初级工作而已, 并且还是低效的在工作.  实际的工作并没有那么简单.&lt;br /&gt;
对一门语言的学习, 最后真正决定效率的是不仅仅是语法的熟悉, 还有对新语言的惯例的熟悉, 编程风格的熟悉, 运行环境的了解, 社区的了解, 常见库的 API 的熟悉(包括标准库).&lt;br /&gt;
这就像你也许以为从 Python 切换到 Ruby 很简单, 因为这两个语言基本上就是一个语言(Guido van Rossum自己说的), 互相的特性也差不太多, 但是要达到一个非常熟悉 Ruby 的程序员一样的工作效率, 这中间还有很多路要走, 哪怕是最接近的切换, 比如从Python Django开发到 Ruby on Rails开发, 你还是需要先熟悉 Rails 的 API, 不同的HTML模板语言,  Ruby 不一样的对集合的惯用处理方式, Ruby 的Block, Proc, Ruby 的 Gem, Bundle 的用法, 可能还需要有 Rakefile 工具的使用, Ruby 自己的版本控制, 这些哪是简单的看看语法, 说切换就能切换的.&lt;br /&gt;
更何况, 现实中的工作内容切换, 可比从Python Django 到 Ruby on Rails 要复杂的多.  慎重的选择一个入门语言, 并且熟悉相关的环境, 能少浪费很多不必要浪费的时间.&lt;/p&gt;

&lt;h2 id=&quot;一开始熟悉的语言-决定了你的思维方式&quot;&gt;一开始熟悉的语言, 决定了你的思维方式&lt;/h2&gt;
&lt;blockquote&gt;
  &lt;p&gt;语言的界限就是一个人世界的界限	
– 维特根斯坦&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;一个人的母语, 是会很大的影响一个人的思维模式的, 一个民族的语言里面没有可以用词来描述的东西, 这个民族的人很难了解. 据说中国人数学比欧美国家好, 有个很大的原因是, 中国的的数字发音都是单音节, 比英语中很多数字的多音节发音效率要高, 这个会影响计算时的速度.&lt;/p&gt;

&lt;p&gt;一开始学习的编程语言, 就相当于你编程时的母语, 影响效果也是一样的深远, 你也没法去思考你用的语言中不存在的特性, 也没法去想用其他语言的特性来更简单的实现某个功能.  就像你要是一开始学习的是 C++, 可能就没有函数式编程的思路, 习惯用迭代而不是递归,  习惯于用for迭代, 而不是用reduce和map.&lt;/p&gt;

&lt;p&gt;我在&lt;a href=&quot;/The-limits-of-my-language-means-the-limits-of-my-world.html&quot;&gt;原来有篇博文&lt;/a&gt;中就感叹过类似的意思, 当时从 C++ 的语言环境切换 Ruby 的工作环境, 真的是有些开眼界了的感觉.&lt;/p&gt;

&lt;p&gt;而且, 因为前面提到的原因, 你可能在第一个语言上工作很长时间, 可能会适应这个语言的缺点, 就算你将来再去学习其他语言, 要扭转这种思维模式, 会花更大得多的代价.&lt;/p&gt;

&lt;h2 id=&quot;语言决定了你的学习方向&quot;&gt;语言决定了你的学习方向&lt;/h2&gt;
&lt;p&gt;你的工作领域很大程度上决定了你工作后继续学习的方向, 这个自然不用说, 但是, 就算你是一个很热爱编程, 业余时间的学习也很难逃脱一开始的选择.&lt;br /&gt;
虽然不排除特例, 但是你要是从底层的语言入门的(比如C, C++), 就是可能会更关注代码的效率优化(因为你的工作语言是C, C++, 很可能对代码的运行效率要求更高), 因为优化的原因, 你去了解了操作系统相关的知识, 了解操作系统的任务调度, 内存管理.&lt;br /&gt;
要是你一开始学习的是Java, 那么你更可能看的是怎么管理更大规模的代码, 比如设计模式, API 设计, 企业架构等, 更牛一点的, 也就是看到JVM字节码, 很少有人会去看汇编.&lt;/p&gt;

&lt;p&gt;还是假设你是个爱学习的人, 那么你业余时间肯定也是会学习, 也是会去了解工作相关行业的信息, 那么, 你学的是C++, 你就会关心C++ 1X的进展, 你学习的是Java, 你会关注Java的新版, 你学习的是Python 你会关心PyCon, PEP, 你学习的是Objective-C, 你会看WWDC, 你会开始学习 Swift, 你学的是 JavaScript, 你会看ES7, Babel, TypeScript等, 简单的说, 你会在你选择的语言相关的信息上花很多很多的时间, 事实上, 说语言之间能简单切换的同学, 你们真的能了解所有这些语言新的特性, 新的成熟的库, 用每个语言最新的特性, 以社区最新的推荐惯例用法来写代码吗? 没有人能做到.&lt;/p&gt;

&lt;h2 id=&quot;你还觉得入门语言的选择不重要吗&quot;&gt;你还觉得入门语言的选择不重要吗&lt;/h2&gt;
&lt;p&gt;上述表达都用了”决定”二字, 可能太过绝对, 但是用”很大程度上决定”, 真是一点也不过分.  要是你认为自己天赋异禀, 能轻松掌握各种语言, 或者你一开始就是把编程作为智力游戏, 没打算作为职业, 或者你准备好了一开始随便学个语言, 然后用更多的精力去学习其他语言, 然后再工作, 你都当我没说过, 你开心就好.&lt;/p&gt;

&lt;h1 id=&quot;怎么选择入门语言&quot;&gt;怎么选择入门语言&lt;/h1&gt;
&lt;p&gt;既然入门语言这么重要, 就不要那么轻松的做决定了, 不是仅仅简单的说没有大毛病就可以了.&lt;/p&gt;

&lt;p&gt;其实我感觉, 回答怎么选择入门语言这个问题之前, 应该想一想自己将来想在哪个领域工作, 然后选择这个领域最热门的语言就好了, 这个可能是最最重要的, 至于这个语言本身什么情况, 哪怕是类似C++这样的语言, 该学也学, 这也比你真的”入错行”, 或者随便学个大家都推荐的Python然后想去开发游戏, 或者App, 发现找不到工作要好.&lt;/p&gt;

&lt;p&gt;基于同样的原因, 一些人推荐的Scheme, 我是不太推荐入门就学习的, 除非你的领域真的就需要Scheme.&lt;/p&gt;

&lt;p&gt;而思维方式的弥补,  就参考Peter Norvig的&lt;a href=&quot;http://www.norvig.com/21-days.html&quot;&gt;Teach Yourself Programming in Ten Years&lt;/a&gt;吧.&lt;/p&gt;

&lt;h1 id=&quot;我是怎么选择的&quot;&gt;我是怎么选择的&lt;/h1&gt;
&lt;blockquote&gt;
  &lt;p&gt;Two roads diverged in a wood, and I took the one less traveled by, And that has made all the difference. 
– Robert Frost&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;懂了那么多道理, 其实还是过不好这一生…&lt;br /&gt;
C++是我入门编程学习的第一门语言, 我博客里面关于 C++的内容也是最多的, 当年刚毕业, 很无知, 对于未来干什么, 学习什么语言完全没有概念, 当时的语言选择也没有现在这么多, 无非也就是C++, Java, C#这几个相对热门,  但是我最后比较神奇的选择了 C++, 理由也很简单, 我听说 C++ 很复杂, 所以就选择了 C++ 而不是 JAVA, C#, 这个选择影响深远.&lt;br /&gt;
因为学的是 C++, 所以在长沙不好找工作(因为那边原来都是做软件外包, 用的都是 Java), 所以来了北京, 因为 C++ 的应用领域也有限, 最后找的工作是做游戏(这完全是学习 C++然后找工作的被动选择), 然后, 很长很长时间, 都是在做游戏……
我可以这么说, 这个决定就是影响了我的一生的, 假如当时选择了 Java, 我一定是有不一样的人生轨迹, 至于比现在好, 还是差, 这个就只有天知道了.&lt;/p&gt;

&lt;h1 id=&quot;最后&quot;&gt;最后&lt;/h1&gt;
&lt;p&gt;最近总算完成了多年的一个心愿, 为了方便在多个编程语言中切换, 做了一个简单的辅助大脑切换的工具.&lt;br /&gt;
为 C++ 部分写简介的时候, 莫名其妙就写多了, 有感而发, 又很久没有写博客了, 单独写了这一篇.&lt;/p&gt;

  &lt;p&gt;&lt;a href=&quot;https://www.jtianling.com/talk-about-the-first-programming-language-you-learn.html&quot;&gt;小议入门语言对初学者的影响&lt;/a&gt; was originally published by  at &lt;a href=&quot;https://www.jtianling.com&quot;&gt;九天雁翎的博客&lt;/a&gt; on October 28, 2017.&lt;/p&gt;</content>
</entry>


<entry>
  <title type="html"><![CDATA[HTML5 游戏的 loading 速度优化]]></title>
 <link rel="alternate" type="text/html" href="https://www.jtianling.com/loading-optimizing-in-html5-game.html" />
  <id>https://www.jtianling.com/loading-optimizing-in-html5-game</id>
  <published>2016-09-13T00:00:00+08:00</published>
  <updated>2016-09-13T00:00:00+08:00</updated>
  <author>
    <name></name>
    <uri>https://www.jtianling.com</uri>
    <email></email>
  </author>
  <content type="html">&lt;p&gt;据说以前的页游的 loading 时间一旦超过 5 秒, 就会流失大量用户, 现在的微信 H5 游戏既然也是页游, 既然也想很好的利用网页游戏不用安装, 即点即玩的好处, 对 loading 的要求应该也是一样的.
最近优化了一下我们的游戏, 用到了一些手段, 这里收集整理如下.&lt;/p&gt;

&lt;!-- more --&gt;

&lt;p&gt;&lt;strong&gt;目录&lt;/strong&gt;:&lt;/p&gt;

&lt;ul id=&quot;markdown-toc&quot;&gt;
  &lt;li&gt;&lt;a href=&quot;#调试和验证方法&quot; id=&quot;markdown-toc-调试和验证方法&quot;&gt;调试和验证方法&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#减少初始资源的载入大小&quot; id=&quot;markdown-toc-减少初始资源的载入大小&quot;&gt;减少初始资源的载入大小&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#源代码和-json-文件的压缩&quot; id=&quot;markdown-toc-源代码和-json-文件的压缩&quot;&gt;源代码和 json 文件的压缩&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#减少-http-的交互次数&quot; id=&quot;markdown-toc-减少-http-的交互次数&quot;&gt;减少 http 的交互次数&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#egret-库的合并&quot; id=&quot;markdown-toc-egret-库的合并&quot;&gt;egret 库的合并&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#脚本加载的精确控制&quot; id=&quot;markdown-toc-脚本加载的精确控制&quot;&gt;脚本加载的精确控制&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#总结&quot; id=&quot;markdown-toc-总结&quot;&gt;总结&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h1 id=&quot;调试和验证方法&quot;&gt;调试和验证方法&lt;/h1&gt;
&lt;ol&gt;
  &lt;li&gt;在 chrome 中开启 developer 工具后, 选择 Network, 查看每个资源载入的时间和大小, 用于查看各个资源的大小和载入时间, 可以排序选择最大的入手.&lt;/li&gt;
  &lt;li&gt;在 chrome 中开启 developer 工具后, 选择 Timeline, 然后刷新网页, 会自动 record, 出现比较直观的时间流程图, 可以看到各个脚本应该并行加载的时候正的并行, 看到每次 HTTP 的交互是否是必要的, 是否可以合并.&lt;/li&gt;
  &lt;li&gt;自己在各个程序运行的关键点输出时间, 主要用于脚本载入以后, 脚本执行初始化流程, 包括登录验证等逻辑流程,  直到游戏画面正常出现过程中的优化.&lt;/li&gt;
&lt;/ol&gt;

&lt;h1 id=&quot;减少初始资源的载入大小&quot;&gt;减少初始资源的载入大小&lt;/h1&gt;
&lt;p&gt;这个是最核心和关键的因素. 你 loading 10M 的资源, 怎么优化也优化不过只 loading 10K 的.&lt;/p&gt;

&lt;p&gt;这里特别明确一下的目的, 我们需要的是将玩家进入游戏的 loading 等待之间尽量缩短, 也就是说, 把进入游戏前 loading 的资源尽量缩小就好了, 进入游戏以后, 再异步 loading 的资源和原来其实差不多大, 但是玩家进入游戏的体验还是提升了.&lt;/p&gt;

&lt;p&gt;图片资源, 游戏配置文件, UI 布局文件, 都只 loading 游戏启动必要的部分, 其他可以留到需要的时候再加载.&lt;/p&gt;

&lt;p&gt;代码本身, 在稍微大规模项目中, 在将图片和配置减少到一定程度, 代码反而会成为最大的资源, 目前没有特别好的优化手段, 考虑过将代码模块化, 特别是 UI 部分的代码, 实现 UI 操作的时候动态载入运行, 理论上可行, 没有验证.&lt;/p&gt;

&lt;p&gt;这里比较尴尬的是显示 loading 进度的背景图本身的问题, 这个图本身的加载就需要时间, 所以我建议尽量精简这个图片本身的大小.  作为更激进的做法, 很多游戏实际是没有 loading 图的, 而是用 1 / 100 这样的纯数字来表示.  这个之间的权衡, 就看各个项目本身的情况了.&lt;/p&gt;

&lt;h1 id=&quot;源代码和-json-文件的压缩&quot;&gt;源代码和 json 文件的压缩&lt;/h1&gt;
&lt;p&gt;最简单的办法是利用 http server(或者 CDN) 的 gzip 压缩功能,&lt;/p&gt;

&lt;p&gt;首先 CDN 需要支持和开启 gzip 压缩, 并且在源栈配置好合适的类型, javascript 的源代码 和 json(配置) 都是可以通过 gzip 压缩的, 效果明显. 关于源栈, 我们就碰到过 nginx 服务器不自动识别 json, 导致原来的 json 配置都没有压缩的问题.&lt;/p&gt;

&lt;p&gt;看 headers 的话, js 是
Content-Encoding:gzip
Content-Type:application/x-javascript&lt;/p&gt;

&lt;p&gt;json 是
Content-Encoding:gzip
Content-Type:application/json&lt;/p&gt;

&lt;p&gt;表示已经开启了 gzip 压缩, 实际传输大小可以减少很多.&lt;/p&gt;

&lt;p&gt;也可以直接在 chrome 的 network 里面打开 Content-Encoding 列, 然后看此列是否有 gzip 标志.&lt;/p&gt;

&lt;p&gt;另外, 假如真的有更高的要求, 也是可以自己压缩源代码和 json 文件的, 这样你可以选择用比 gzip 压缩比更高的压缩算法, 不过, 注意 javascript 本身的运行效率, 别用太慢的压缩算法.
比如 &lt;a href=&quot;https://stuk.github.io/jszip/&quot;&gt;jszip&lt;/a&gt; 这个库.&lt;/p&gt;

&lt;h1 id=&quot;减少-http-的交互次数&quot;&gt;减少 http 的交互次数&lt;/h1&gt;
&lt;p&gt;因为 http 的交互比较慢, 减少交互的次数可以显著提高载入速度.&lt;/p&gt;

&lt;p&gt;对于图片, 载入期必要图片都应该打包成图集, 最好是能打包成 1 个文件, 我们项目中最后做到了, 我命名为 gamemin, 这个图集可以进一步的考虑压缩, 比如使用 png8 格式.  因为最后的大小已经在 150K 的水平了, 没有进一步的使用诸如 webp 等压缩比更大的图片格式, 有更严格要求和追求的话, 可以考虑, 不过需要测试一下对应的 javascript 解码库的效率.&lt;/p&gt;

&lt;p&gt;游戏配置, 成规模的项目, 又是策划写 excel 导出的话, 往往有几十个, 可以合并成一个, 去掉空格换行等. 为此我写了个合并工具: &lt;a href=&quot;https://github.com/jtianling/json_compacker&quot;&gt;json_compacker&lt;/a&gt;&lt;/p&gt;

&lt;h1 id=&quot;egret-库的合并&quot;&gt;egret 库的合并&lt;/h1&gt;
&lt;p&gt;在新的 egret 中, 进行了模块化的设计, 每个模块可以单独选择是否添加, 但是这样一来, 原来只需要 loading 一个库, 现在需要 loading 好几个, 实际是划不来的, 而 egret 官方没有提供官方的解决方案.&lt;/p&gt;

&lt;p&gt;合并 js 的工具不少, 不过我在官方论坛上找到一个, 使用是最方便的.
&lt;a href=&quot;http://bbs.egret.com/forum.php?mod=viewthread&amp;amp;tid=16765&amp;amp;highlight=%E5%90%88%E5%B9%B6&quot;&gt;合并 egret 库的工具&lt;/a&gt;&lt;/p&gt;

&lt;h1 id=&quot;脚本加载的精确控制&quot;&gt;脚本加载的精确控制&lt;/h1&gt;
&lt;p&gt;首先, 在我们游戏中有个例子, 就是接入了很多平台, 原来的做法是所有平台的 sdk 都加载 (你要看平台 SDK 的文档的话, 都是这么教你的), 然后选择性的运行对应的代码.  这样做实际多加载了很多不必要的平台 sdk, 平台这些 sdk 还都是从合作方网站上下载回来的, 我们缺乏控制.  修改后变成首先判断渠道, 然后只加载渠道对应的一个平台 sdk.&lt;/p&gt;

&lt;p&gt;动态加载脚本的方法在”高性能 JavaScript”一书中有比较详细的介绍, 简单的说就是可以用下面这两个库:&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://github.com/rgrove/lazyload&quot;&gt;lazyload&lt;/a&gt;
&lt;a href=&quot;https://github.com/getify/LABjs&quot;&gt;LABjs&lt;/a&gt;&lt;/p&gt;

&lt;h1 id=&quot;总结&quot;&gt;总结&lt;/h1&gt;
&lt;p&gt;因为是公司项目, 所以略去的所有相关的源代码, 总体来说, 我用到的优化手段都提到了.
需要说明的是, 优化的时候更多的是在一个完全没有优化的版本上进行的, 随便优化一下, 都能获得比较大的改进, 所以实际工作做的不是足够严谨, 在有多个优化方案时, 都是选择相对简单的那个解决方案, 而不是详细的对比多个方案的实际情况, 经过测试然后选择.(这个才是正确的做法)&lt;/p&gt;

  &lt;p&gt;&lt;a href=&quot;https://www.jtianling.com/loading-optimizing-in-html5-game.html&quot;&gt;HTML5 游戏的 loading 速度优化&lt;/a&gt; was originally published by  at &lt;a href=&quot;https://www.jtianling.com&quot;&gt;九天雁翎的博客&lt;/a&gt; on September 13, 2016.&lt;/p&gt;</content>
</entry>

</feed>
