Letter
两天前看到好多人在朋友圈晒出网易云2020听歌报告,这才意识到新的一年又快到了。今年确实是很特殊的一年,也看到有同学写了年度总结,作为纪念。这篇文章大概是三个月前写好的,为的是记录在UM的两年对我来说重要或者有意义的事情。之前一直设置为加密,因为一些情绪更多是写给自己看的,算是给自己的一个答复。我觉得现在到了适当的时间了。2020年12月29日。
两天前看到好多人在朋友圈晒出网易云2020听歌报告,这才意识到新的一年又快到了。今年确实是很特殊的一年,也看到有同学写了年度总结,作为纪念。这篇文章大概是三个月前写好的,为的是记录在UM的两年对我来说重要或者有意义的事情。之前一直设置为加密,因为一些情绪更多是写给自己看的,算是给自己的一个答复。我觉得现在到了适当的时间了。2020年12月29日。
波多黎各之行是在三月初,安娜堡最后一个春假。原本的计划是欧洲,心心念念的巴黎,可惜因为疫情的原因只能妥协,最终选择了一个温暖的地方看看海。四个月后回忆这次不成想的毕业旅行,还是很愉快的。
一下飞机就能感受到阳光,对于无法忍受安娜堡冬天的我来说简直是赐福。到了海边的住处,竟然有一间海景房(可惜猜拳输了没睡成),窗口就能吹到海风,出了院落的小门就是沙滩。于是放下行李,去海滩散步。踩着沙滩海水,不一会儿就把裤子弄湿了,海水、海风、落日余晖,都是温暖的。离住处不远有一栋满是涂鸦的房子,门口有一群小猫,应该有人家收养着,不怕生。圣胡安给了我不错的第一印象。
波多黎各的夜晚没有想象中热闹。原以为圣胡安旧城会多一些烟火气,可晚餐时间一过,街上行人就不多了,大概都回家休息了,有点日出而作日落而息的意思。带着小阳台的欧式建筑,隔着一条小道相对着,这种形制总是让我想到一些法语音乐剧,维罗纳、红与黑,要是哪个夹缝里藏了架梯子我也不会感到太奇怪。有那么几个场景和灯光有点墨西哥城宪法广场旁旧式公寓楼的味道,我还挺喜欢的。
海角城堡是个好玩儿的地方。从一处喷泉开始,沿着靠海的城墙走,有着几处超现实主义的雕塑,一转进城门又是旧城模样。窗台种着花花草草,小猫小狗树荫乘凉,彩色的墙壁就很适合当背景作头像。走上斜坡就是一大片绿色草坪,第一眼就像看到了微软经典桌面,躺倒晒太阳是真的舒服。城堡的四角都有造型别致的瞭望台,有点儿像古时候的灯座。在城堡的高处能一览整个海峡,海岸线、帆船、灯塔,别样风景。
不觉得波多黎各有什么特别好吃的,不过倒是有很不错的饮品。冲浪完来一杯piñacoladas,走进咖啡店点一杯frappes,热情的服务生和总是对不上姓名为上错单而害羞的女生,都是这座小岛真实的样子,连色彩都更鲜活了。若是有兴致,院落喝酒,唱歌夜谈,调一杯极其随意的mojito,用薄荷柠檬味雪碧兑当地的朗姆酒,也挺不错的。
这次旅行抽出了一天时间环岛自驾,一路看见沙滩就踩,看见礁石就登,走走停停算是拍了不少豪情壮志的大场面。沙滩上晒太阳的,打沙排的,海里戏水的,海角看海的,不得不说那里的居民真的很会享受生活。在一处沙滩遇到卖椰子的摊位,一人一个,开个小口插了吸管直接喝,甘甜。喝完剖开,用椰子皮刮了果肉吃,口感很好。不过我的还是太青了些,果肉只有薄薄的一层,半透明的,看着倒是很精致。
旅途中有两处景色让我很感动,反而不愿用相机记录下来。其一是荧光湖。划着船穿过小河道,夜晚船尾星星点点的灯串在一起,桨声水声,就这么蜿蜿蜒蜒地流向湖心。满月,最美的不是微微泛着蓝色荧光的湖水,而是夜空星辰。一抬头,觉得一切都暂时平静了下来。那时心里想着,如果可以一整晚都静静地躺在湖面上该有多好。现在回想起来,却是昨夜闲潭梦落花,可怜春半不还家。
其二是岛屿西南的海角。大概是人生中第一次看海角落日,却想到了很多人和事。坐在海角的岩石上,云意外得像自己曾想描绘的样子,耳机放着Mando Diao的歌单,那首瑞典古诗总是会在特别的时刻打动我。回来的路上特意换到了最后一排座位,想给自己一点空间,短暂逃避一会儿。晚上和朋友聊了很久很久,躺在沙发上睡着了,直到第二天早晨阳光洒进玻璃窗。
回程的飞机上睡得很香,睁开眼已经快到底特律了。同学提醒拉下遮光板,恰好是日落时分。天色和城市点亮的灯光相映,很美好的结尾。想了很久,还是决定分享一下这次的回忆,就当作是一份礼物了。
The paper investigates quantitative supervisory control with a local mean payoff objective for weighted discrete event system. The supervisor is designed to ensure that the mean payoff of weights over a fixed number of transitions never drops below a given threshold, aka the system stability. The algorithms transfer the supervisory control problem to a biparty game between the supervisor and the environment.
The weighted discrete event system can be modeled as an automaton. Here shows an example. The state with “!” is unsafe ($x_8$). The set of controllable events is $E_c=\{a,b,c,d,e,f\}$, and the set of uncontrollable events is $E_{uc}=\{u_1,u_2,u_3,u_4,u_5\}$. The localhost website gui is supported by the WebMachine from transitions_gui package.
1 | def visualizeMachine(states, transitions, initial, name, ordered_transitions=False, ignore_invalid_triggers=True, auto_transitions=False): |
The first algorithm is to transform the automaton model to a biparty game. It has two steps: insert transition states into the original automaton, and remove deadlocking or unsafe states. We can use DFS to find out all transitions, and generally the inserted transition states of one original state are the combination of all controllable events at that state plus the uncontrollable ones.
1 | def DoDFS(y, X, x0, f, Ec, Euc, w, Qy, Qz, G, fyz, fzy): |
The second algorithm is to find the supervisor’s winning region. It first calculates the window mean payoff function which tracks the best worst-case accumulative weights that the supervisor may achieve from a state within N event occurrences (window size). Then the goal equivalents to adopting a control strategy to obtain a nonnegative accumulative payoff while the environment aims to spoil that goal by enforcing negative payoffs. We can use divide-and-conquer to find out all stable windows where the local window mean payoffs are all nonnegative. The example has a window size of three.
1 | def StableWindow(Qy, Qz, fyz, fzy, w, N): |
The third algorithm is to reconstruct and unfold the result of the second algorithm. It has two steps. The first one is to merge all stable windows in the second algorithm together, and add original states back to the automaton so that each original state has only one transit-out arrow. The second one is to remove all the inserted environment states to simplify the automaton and finally give a stable workflow.
1 | def Unfold(y0u, Qyu, Qzu, fyzu, fzyu, Qy, Qz, fyz, fzy): |
Imagine in this pandemic of Covid-19, some engineers have no access to manufacturing machines. Or, imagine we students want to learn to use some machines in the factory. How can we learn this online? So our motivation is to use virtual reality and augmented reality technology to synchronously show the manufacturing process and simulate the milling process.
Before heading to the details, we first have a overview of our system. There are three main parts: user, transmission and machine. The remote users could control the machine by gesture and observe the machine with VR headset. The local user can use the mobile application to see a virtual workpiece rendered on the screen. The red arrow represents control signals input; while blue arrows are real-time feedbacks from the machine. Our system looks complicated at first sight, but it would be clear later.
In terms of needs, for VR part, users require real time synchronization, high degree of freedom, and immersive experience. For AR part, we need precisely positioning and carving. Particularly, a sample of AR effect is shown here. Users will scan the machine without materials to know how an artifact will be manufactured. It helps validate the correctness of manufacturing program without wasting materials. For both subfunctions, users need high portability, low financial cost and low learning cost.
From the needs, we formulate some engineering specifications. We set refresh frequency and latency as the real time criteria and we also add the specifications for object deviation rate, financial cost and so on. The engineering specifications will affect our concept generation and selection.
From the needs, we list out the necessary sub-functions we want to have and choose. We use weight matrices to carry out decision selection based on the engineering specifications. For the user side, we choose HTC Vive Pro as the headset for VR since it a commonly used VR headset with friendly handles and good user experience. We choose smartphones to be the AR terminal because that everyone can download an APP and access to the system. Unity 3D is chose to build the model since it can make and simulate vivid 3D model. For the transmission side, we choose socket connection to reduce the latency and raise the update frequency. Mysql is a stable and fast database that can transmit and store structured data in a short time. For the machine side, we choose Mach3 to control the CNC milling machine, the software can read the real time milling machine status in a low latency.
Now let’s discuss about implementation details. For VR control system part, currently we have implemented environment to enable user to control CNC machine manually to start, move and stop virtually. Also, user may choose to load precompiled Gcode Program to show simulation result of a model. We use Unity Package SteamVR and VRTK to build up the VR environment. Then we setup the control panel by Csharp scripts in Unity which sends user’s commands to MySQL database while simulating CNC machine with data feedback from database.
For real-time simulation, we create a brand new algorithm with several Csharp scripts to simulate real time cutting effect of CNC machine in Unity. Below displays actual effect of two controlling methods. In Unity, the program would first generate enough mesh vertices on surface of the piece. Then, whenever the cutter contacts with the vertices, the vertices will modify its height to display cutting effect. This algorithm ensures real-time connection between devices.
Most parts of the AR environment is a migration from VR. Besides, we utilize vuforia tools to build the AR visualization. We designed the image target to stable the model, which we’ll show later in the demo. Also, we seperate the 3D calculation and the AR visualization to make the whole program run smoothly.
The VR system is built up by three parts: from left to right, remote client, MySQL server and Mach3 client. In the remote client, we built a unity model which is divided into four parts: the base and x, y, z axis. The scale of the coordinate and the directions of the axis are consistent with the real machine. Therefore, given the real-world coordinate, the model will visualize the machine correctly. The Mach3 client is a relay between MySQL server and Mach3. It receives commands from sql and sends to Mach3 and also receives coordinates from Mach3 and sends to sql. MySQL then is a data storage for remote communication. The desktop running Mach3 and Mach3 client is connected to the real machine to operate.
For the real-time transmission, we have two parts. First, the Mach3 client will create connection to the MySQL database and query the data in every loop, which is more than 30Hz, so that once there’s new command (such as “Load” or “Stop”) sent to the database, the client can get it immediately. The second part is the socket transmission. Once the client queries the new command data, it will send it through the socket channel to Mach3. In the meantime, Mach3 VB script will always listen to the socket port, and if there’s any data in the socket channel buffer, it will run sockRead to get the command. With our prototype, the whole transmission process is in real-time.
For the AR, the visualization is similar to VR, but it has a different database connection method and a new tag recognition task. Due to mobile security issue, both android and ios don’t allow direct connection to online database. So we wrote a php website on the google cloud platform app engine. It directly connects to the database and opens a web api which is a query to the position data so that on the mobile platform, our program can utilize webrequest package to request the api url to get the data through html form. About the tag recognition, we designed a tag which has a lot of geometric features. The round SJTU logo can help locate the center and the color blocks on the margin have character points which help Vuforia engine determine the direction.
In the video, the right-hand-side is the laptop running our VR model, and on the left is the real cutting process. We can click buttons or use VR device to remote control Mach3 client which is connected to the real physical machine. And the Mach3 client will send back position and moving information back to VR model for visualization. We can see the latency is very low, and it is due to the internet connection and low computing power of the old lab desktop.
Here is the AR APP running on the iOS platform. We can either pre-load our JI cutting model into database or run the Gcode in real-time, and the AR APP can visualize it.
After finishing the prototype, we conducted some experiments for validation. Using the network tool Wireshark, we calculated the frequency of the position feedback, which is around 20 packets per second. At the same time, on the RHS the round-trip time graph shows that the latency is around 50ms, which is lower than our expectation 200ms.
Our system enables remote and real-time simulation. Those who are thousands miles away from the machine can still have access to the control and feedback. The database storage enables the users to recap their Gcode programs. However, due to the hardware setting limit, our computer cannot afford greater amount of calculations for higher precision. If we need to simulate a sophisticated artifact, our current design may not give precise enough outcomes.
Reviewing our design, we found many aspects that we could’ve done better. The first point is computer hardware. Since our CNC Milling machine can only support Windows 7 32bit, it later became our performance bottleneck. If we could start over, we should pay more attention to the choice of hardware. Also, we expect that in the future, AR can adapt itself to the nested mobile device.
In summary, we are dedicated to a remote, real-time control system. Our design used socket connection and MySQL database to record position parameters. We also designed a new shader algorithm for workpiece simulation. In general, our design meets most of the requirements. The server establishment and shader algorithm are the two most important achievements. During this pandemic, we witnessed the power of remote teamwork, and the importance of time management. We are excited and grateful to be a part of this wonderful journey.
既然不是那么严肃的个人主页,我也会介绍一些喜欢的游戏,音乐和书籍。这次聊一聊歧路旅人,可以说是第一个让我感到惊艳的游戏。当时看了游戏的预告瞬间被精致的画风震撼到,类型和小时候在同学家玩儿的最终幻想有些类似,但光影效果地图细节好了太多太多,可以说是被迷住了,直接下了数字版,完全等不了卡带版本的物流时间。
游戏开始毫不犹豫就选了舞娘作为初始角色,纯粹是因为舞娘的立绘太漂亮了,过于美好以至于让我对旅人这个词产生了形象上的冲突,更加好奇旅途中会有怎样的故事发生。但当我开始舞娘的故事线,听到主题的瞬间,才真正明白为什么歧路旅人会让这么多玩家感动。沙漠中金色的小镇,美丽的舞娘,如此契合的主题。即便结局未知,已然心醉。
除了每个角色的主题外,地图上不同的地区也会有不一样的主题音乐。其中我最喜欢的是崖地主题,第一次注意到是在盗贼离开Bolderfall启程寻找龙石的时候。长笛(其实有一点像尺八)的声音真的很适合表现旅途的漫长,以至于途经崖地时常驻足。
兜兜转转,走完了八条主线,完成了所有的支线任务,甚至听完了所有酒馆中的对话,回过头来串起整个故事,无限感慨。每个故事线的结尾都会有一张角色绘图,我都一一截图保存了下来,每一个角色都有了新的生活,但我始终觉得舞娘的结局有些遗憾。七位旅人启程时有人送,归来时有人迎,唯独舞娘一个人寻找旅程的意义。
花了三个星期的时间重制了塞尔达传说地牢关。为了尽可能地复制原版本的细节,把这一关卡玩儿了有上百遍,以至于经典BGM都要听厌了,甚至上手了红白机,体验旧手柄特有的触感。在野炊时代回看初代塞尔达,仍旧非常耐玩,也算是我的入坑之作了。
既然是自己重制的第一个游戏,那么除了游戏截图和过程视频外,准备多讲一些制作细节。首先是环境。虽然是一个2D游戏,但由于墙壁、障碍物和水之类的游戏元素都有层次上的区别,以及游戏转场过程中相机的移动,把环境设置为3D会更容易制作。只需点亮2D视角,无论是canvas还是游戏主界面都和2D游戏的制作没什么区别。
其次是collider和trigger以及rigidbody的设置,这是最最头疼的。比如说武器与怪物的接触和林克和怪物的接触就需要不同的接触机制,这样才能做出原版的击打效果。人物和障碍物为了防止穿模的情况发生,都会加上rigidbody性质,同时为了减少碰撞对速度的影响,在每次接触检测后都需要重置一下速度。甚至相同的物体在不同的情况下接触条件都会有所区别,比如在受到伤害后的冷却时间内,林克与怪物的碰撞检测会被取消以免受到重复伤害。这些可能会需要设置许多tag和layer去逐个设置碰撞条件。
所有的怪物中,猪是最难实现的,因为他本身会使用武器。除了继承骷髅和蝙蝠的随机移动之外,还需要去考虑掷出回旋镖的情况。回旋镖的最大投掷距离有多远,如果在中途触碰围墙该如何判定,回旋镖触碰怪物和触碰林克的区别,甚至需要考虑在投掷过程中猪被杀死的情况。这些大多是由collider和trigger的判定去实现的。
原以为一款像素风的老游戏不会太精细,但真正上手之后才发现好多细节没有想的那么简单。比如说人物行走,看似只要根据上下左右的按键给出移动距离,但因为地图是由正方形格子拼成的,而为了营造3D的效果,人物的collider其实是小于半格的,这样一来就需要在每次移动时将人物的横纵坐标近似到固定的几条纵横线上以达到走格子的效果。再比如剑的远程攻击的实现,在剑飞行的过程中其实林克依然可以挥剑的,也可以朝另一个方向投掷,只是不允许同时朝一个方向投掷多把剑。这样一来可能就需要创建五把剑:手持一把,另外四个方向隐藏四把,在需要的时候设置可见。另外还有一些击退效果和免疫效果需要去思考。
除了原版的地图和怪物之外,自己另外设计了两个小房间,算是开了脑洞了。第一个房间国际象棋的设计有两个灵感来源:一是地图的格子很像棋盘,二是哈利波特的巫师棋。于是就想着把白棋作为怪物,林克需要扮演一枚黑子去赢下这局,而棋盘外摆放的棋子提示了林克扮演的是城堡。林克只有走到checkmate的位置才会触发游戏机关。如果是哈迷可能会发现残局的摆放其实是密室那一局的小改动,效果还是挺有趣的。第二个房间制作得比较随意,就想换个风格,结果吓到了试玩的同学。房间的红色地砖如果踩踏的时间久了就会对林克造成伤害。只有杀死所有红蝙蝠才能拿到通关的钥匙。在视频里最后不小心死了,就没能拿到。希望玩家会喜欢这两个小设计。
It’s in the game
Years ago, in the middle-earth…
Warrior waves the sword
Thief steals from others
Witch shoots fireballs
Bomberman drops bombs
The four elites cooperate and compete with each other to collect golds from a newly found gold mine
Want to join? Follow The Gold Rush
Presented by Godzilli
A game prototype I created within one week, inspired by the book Das Glasperlenspiel. In the game, players can step on the lights to control the movement of various parts to form the path to the end. The designed view change will help players solve the puzzle. Enjoy.
Calw是德国的一个小镇,也是我最喜爱的作家黑塞的故乡。原是想借着这地名和黑塞书中所感写一两首严肃一些的配乐的,但周遭的变故让我改变了想法。那时对于被困家中还有些许新鲜感,好像突然多了很多自我的时间可以翻翻书,看看电影,听听音乐。于是乎偶然地重温了《挪威的森林》,电影里的插曲也成了循环播放的歌单,夜晚散步的好陪伴。
不过说起来,可能都是因为一张明信片吧,来自Goteborg一个晴朗的五月天,一年后再次翻看竟有些恍惚了,我一时不知该怎么称呼她。烟火气和牛肉汤的香味,旧书店,是想象中的模样,却又有些小诙谐。于是就凭着感觉写下了这两小段音乐,盼着有一天可以独自旅行走过老城广场,希望再次相见不必等太久。
我讨厌安娜堡的冬天,尤其是下雪的日子,从房间窗口看出去只有被雪压着的枯枝和一堵不好看的红墙,颜色深一些或淡一些都会好很多,可惜了。记得在这里的第一年冬,天天祈求天公作美,大概是没那闲情逸致喝酒赏雪吧。不知是不是因为习惯了寒冷,自觉今年的冬天过得快,本以为是好事,现在想来还不如白茫茫一片落得平静自在。
得知奶奶过世的消息是在傍晚太阳落山的时候,我一个人在Northwood散步。奶奶听不大懂普通话,所以每次打电话我都说得很慢,说得很响,这样她就能明白我的意思了,这样她就会开心。可还是因为时间和地域的缘故,距离拉近又疏远。每次回老家都觉得自己像是个客人,生分了拘谨了,但有些东西心里是再清楚不过的。
这一次是我失约了。哥哥的婚礼,朋友的聚会,说好了的事情。可别怪我呀,我也无能为力,我也很累。
希望在故事的结尾还会有做梦的机会。
墨西哥有很多故事可以讲,非常愉快的一段经历。这半年多来有遇到不开心的时候就会想去翻看旅行的照片,也一直想着找一个安静的夜晚把这些故事记录下来,不过因为种种原因拖到了现在。既然时间过去那么久了,那就索性想到哪儿写到哪儿,一点一点把这篇不算游记的游记写完。
第一站,坎昆。下飞机的第一感受就是暖和,相比于纽约和安娜堡的天气,坎昆简直太舒服了,瞬间心情舒畅。乘小巴士从机场去住处,一路沿着海岸开过酒店区,恰好日落时分,晚霞很美。在安娜堡看了太多雪,很期待沙滩和大海。
作为游客,第一件事就是兑换货币,然而在墨西哥的这一周美元对比索的汇率自始至终都是个谜。第一晚我们就找了三家OXXO连锁便利店兑换,三家的汇率竟然都不一样,甚至还看到了店主临时更改汇率,不多不少就比同行好那么一点点。
第一顿晚饭吃得非常愉快。在预约的时候服务生不小心跳过了我们,为了表达歉意特意把我们安排在了乐队表演区,于是体验了一次点歌服务。一开始还有些不好意思,毕竟三个什么墨西哥歌曲都不知道的异乡人被乐队热情地围着,一时有些不知所措,直到起鹏想起了一首。当音乐响起,大家就都放松了下来,慢慢得融进了氛围里。哪天有空准备把这一段演唱的视频剪一剪放上来,还挺有味道的。我们听琛哥推荐,点了不少特色菜肴,名字是全然记不得了,就记得特别好吃,还有特别好喝的大杯柠檬汁。那天恰好是平安夜,服务生都戴着圣诞帽,还有装饰的彩灯彩旗,就感觉很美好。
虽然AT&T说在墨西哥有电信服务,但实际速度感人,为了第二天的行程不受影响,去了路边一家小超市买了张电话卡,价格可以说很便宜了。我们顺带也买了点早餐,超市里的食品种类挺丰富的,能想到的基本都有,还有不少当地的酒,酒瓶上有海龟图案,热带风情就有了。
第二天报了个团去奇琴伊察,也就是玛雅金字塔所在。路上看了关于玛雅文化的电影,血腥场面都没有删减,比书上更直观得了解了关于玛雅的一些故事,也就少了一些神秘感。到了遗址,亲眼所见并没有让我失望,确实震撼。天工作美,墙上金字塔上图案的细节能看得很细致,也有雄鹰翱翔,英雄主义的悲壮感也被渲染出了一些。
在坎昆更多是水上项目,我们玩了单板和浮潜,还有水上乐园Xplore。先说单板吧,是站在板上拿桨划的那种。一开始上板比较怕落水,反而有些不稳,逐渐适应平衡之后很快就能站起来了。我们沿着河道跟着法国教练,习惯之后慢慢开始加速,也开始期盼谁先失足落水,琛哥也每让我们失望,落水画面很巧也被gopro记录了下来。浮潜是我最期待的,我们先在小池子里适应呼吸器和氧气瓶的重量。水没有那么清澈,有一种压迫感让人在心理上很难呼吸。教练也告诉我们几个重要手势和指令,方便水下交流。乘小艇到浮潜点,顺着绳索降到海床,确实能感受到洋流的力量,如果没抓住绳子,对于新手很容易漂走。我的潜水镜密封不是很好,被迫上浮跟教练互换了一下。在水下我们很幸运地看到了海龟,还尝试追逐一番,也让珊瑚礁里的小鱼啄了手指,很特殊的体验。
Xplore是我们在坎昆最后一天去的。我们本来打算搭水上乐园接驳车的,但因为前两天玩得实在太累了,三个人全部睡过了头,最后只能打Uber,谁知因祸得福,比班车更早到了乐园,免去了排队之苦。在乐园玩的最开心的就是滑索,记得六七个索道全部玩了两次。另外就是开越野车,无证驾驶很刺激。回程的路上琛哥进行了西班牙语数字教学,成果卓著,到了第二天还能勉强全部记住。
坎昆的最后一晚去了当地的夜市,各种小吃零食种类还挺多的,但最最惊喜的还是坎昆街头艺人和西语rap。一身黑色摇滚行头,拉着一个音响,唱的好像是柔情的曲子,和环境有些格格不入。后来心血来潮查了一查,是Héroes del Silencio的La chispa adecuada,其中有这样一段歌词:
去瓜纳华托这座离墨西哥城五个多小时车程的小镇算是我的坚持吧,在看到照片的第一眼就被迷住了。
不过故事要从在墨西哥城下飞机开始说起。我们取完行李准备打车去汽车站,想着搭下午的那班汽车去瓜纳华托。大概是因为赶飞机起得太早,飞机上靠着也没睡好,在Uber上琛哥发出了“要是能打车去就好了”的感叹。接下来发生的事完全超出了我的理解范围:琛哥试探地问了司机愿不愿意载我们去瓜纳华托,司机认真考虑了一会儿并且向家里女主人汇报了情况后还真就同意了,并且还客串了回导游,带我们去了当地人喜欢的快餐连锁店吃了顿好吃的。于是,瓜纳华托,这段奇妙的旅程就这么开始了。
沿途一路的风景,在晚餐前到达了目的地。我们的住处在半山腰,可能还要再朝上些,爬上楼顶的平台可以鸟瞰大半个城镇。太阳还未落山,灯火未亮,小巷弄和五彩的砖石房子,确实是想象中的模样,心情舒畅。
在我眼里,瓜纳华托的一切都好像在等待着夜晚。傍晚时分的瓜纳华托是恬静的,路上没什么行人,会让我想到过去在老家生火做晚饭的情景。在下山的路上,遇到一位老人用法语和我们打招呼,还有三两孩童和小狗。夜幕落下,华灯初上,瓜纳华托也就热闹了起来。到了山谷的城镇中心,市民和游客在集会游行,庆祝亡灵节,有乐手扛着传统乐器和大提琴带领着整个队伍唱着歌,我们也跟着队伍走到山谷另一边的观景平台。
在观景台上看到的瓜纳华托绚丽浪漫,完全不比电影中的场景逊色。灯光和色彩让我们驻足良久,觉得这五个小时的颠簸完全值得。言语很难描述当时的心情,觉得瓜纳华托需要配上爱情。
在回住处的路上,碰巧还有一家面包店没有关门,嗅着香味就进去了。陈设很简单,家庭小作坊的样子,里头一间是烤箱,外头是架子。面包还有刚出炉的,特别好吃。
我们在瓜纳华托只住了一晚,第二天早晨赶了当地的集市,在一个大棚里有各种食物和日用品出售,还能看到可口可乐之类的小广告牌,有一种十年前国内小城镇赶集的感觉。
中午乘双层大巴回墨西哥城,有留恋,没有遗憾。
墨西哥城给我留下的第一印象其实并不好,可能是因为还沉浸在瓜纳华托的色彩吧,墨西哥城的夜晚好像有些太过冷清了。不过这短暂的孤独感很快就被晚餐冲散了,如果我没记错的话大概等了半小时号就排到了那家网红店(原谅我不记店名),又点了甜布丁和加了不少辣酱的玉米粥(pozole?),餐厅电视放着南美足球赛,虽然水平不高,但好像大家都挺喜欢看的。吃完晚饭就开始沿街闲逛,墙上贴了好多《Parasite》的海报,和坎昆街头2012年电影《The Great Gatsby》海报相比显得与时俱进了不少。除此之外,还意外发现了小丑涂鸦,瞬间对这座城市有了更多的期待。印象里走了不少街道,还聊起了在上海骑车的小故事,于是乎萌生了墨西哥城骑行的念头,可惜某位当时骑车还不够熟练,也就作罢了。回住处的路上,车里广播放了Dire Straits的Sultans of Swing,心情又好了许多。
墨西哥城主要看了宪法广场和人类学博物馆,本来是想看看科幻风格的图书馆的,可惜那段时间闭馆,所以只能沿着街道走去人类学博物馆,看看墨西哥城的居民区和墙上女艺术家的涂鸦画像。在博物馆可谓大开眼界,我在大三上了人类学课,课上提到的遗址遗迹和考古发现在这里都能找到,都能看到实物。我简单当了回讲解,感觉良好。
在宪法广场我们先是上了南美第一高楼,虽然只有两百多米高,但因为历史原因,墨西哥城有太多教堂导致无法规划建设高楼,所以在观景层能把整座城市尽收眼底。宪法广场另外三座主要建筑是大教堂,市政厅和邮局。邮局真的金碧辉煌,让我们以为误入了市政厅。
墨西哥城吃得挺好的。路边有椰子喝,还有鲜榨果汁店,一升木瓜汁只要两刀不到。还有taco路边摊,量大肉多,吃的时候还有吟游诗人表演节目,店家不会英语,但非常热情地给我们介绍表演的节目,我们全靠谷歌翻译,算是给翻译软件做压力测试了。店家还给我们推荐了买纪念品和银饰的地方,我们也最终买银饰花光了所有现金,导致没买明信片,最后还是回纽约在时代广场买了几张寄给了朋友。
最后一晚是跨年,在宪法广场好像出了些骚乱,我们便匆匆回了住处,数了倒计时垮了年。在回美国准备开始新学期前讲了些心里话。