<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Some reminiscences, some memories &#187; Demo</title>
	<atom:link href="http://www.mikespook.com/index.php/tag/demo/feed" rel="self" type="application/rss+xml" />
	<link>http://www.mikespook.com</link>
	<description>Just another boring day</description>
	<lastBuildDate>Thu, 05 Aug 2010 14:36:19 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.0.1</generator>
		<item>
		<title>Twisted 的 MemcacheProtocol 使用</title>
		<link>http://www.mikespook.com/index.php/archives/467</link>
		<comments>http://www.mikespook.com/index.php/archives/467#comments</comments>
		<pubDate>Mon, 08 Feb 2010 14:16:11 +0000</pubDate>
		<dc:creator>mikespook</dc:creator>
				<category><![CDATA[Python]]></category>
		<category><![CDATA[defer]]></category>
		<category><![CDATA[Demo]]></category>
		<category><![CDATA[memcache]]></category>
		<category><![CDATA[twisted]]></category>

		<guid isPermaLink="false">http://www.mikespook.com/?p=467</guid>
		<description><![CDATA[Twisted 的 defer 是个强大但是诡异的东西，遗憾的是，除了官方文档和这些文档的翻译，其他资料不多。而基于 defer 的客户端协议实现资料就更少了。Memcache 的协议实现也是利用 defer，但是除了一个单元测试的代码外，很难看到其他可以参考的实现。搞了几天，总算是有一个简单的封装，可以避开 defer，无须让所有参与开发的技术人员一定要弄懂 defer 才能用 MemCacheProtocol。 上代码吧，这样封装，应该是比较好理解的…… #!/usr/bin/evn python # -*- coding:utf-8 -*- ''' Created on 2010-2-7 &#160; @author: mikespook ''' from twisted.internet import reactor, protocol from twisted.protocols.memcache import MemCacheProtocol, DEFAULT_PORT &#160; from pnp.log import log &#160; class MemCache: ''' memcache 调用接口 &#62;&#62;&#62;def printResult(result): &#62;&#62;&#62; print result &#62;&#62;&#62;mc = [...]]]></description>
			<content:encoded><![CDATA[<p>Twisted 的 defer 是个强大但是诡异的东西，遗憾的是，除了官方文档和这些文档的翻译，其他资料不多。而基于 defer 的客户端协议实现资料就更少了。Memcache 的协议实现也是利用 defer，但是除了一个单元测试的代码外，很难看到其他可以参考的实现。搞了几天，总算是有一个简单的封装，可以避开 defer，无须让所有参与开发的技术人员一定要弄懂 defer 才能用 MemCacheProtocol。<br />
上代码吧，这样封装，应该是比较好理解的……<span id="more-467"></span></p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;"><span style="color: #808080; font-style: italic;">#!/usr/bin/evn python</span>
<span style="color: #808080; font-style: italic;"># -*- coding:utf-8 -*-</span>
<span style="color: #483d8b;">''</span><span style="color: #483d8b;">'
Created on 2010-2-7
&nbsp;
@author: mikespook
'</span><span style="color: #483d8b;">''</span>
<span style="color: #ff7700;font-weight:bold;">from</span> twisted.<span style="color: black;">internet</span> <span style="color: #ff7700;font-weight:bold;">import</span> reactor, protocol
<span style="color: #ff7700;font-weight:bold;">from</span> twisted.<span style="color: black;">protocols</span>.<span style="color: black;">memcache</span> <span style="color: #ff7700;font-weight:bold;">import</span> MemCacheProtocol, DEFAULT_PORT
&nbsp;
<span style="color: #ff7700;font-weight:bold;">from</span> pnp.<span style="color: black;">log</span> <span style="color: #ff7700;font-weight:bold;">import</span> log
&nbsp;
<span style="color: #ff7700;font-weight:bold;">class</span> MemCache:
    <span style="color: #483d8b;">''</span><span style="color: #483d8b;">'
    memcache 调用接口
    &gt;&gt;&gt;def printResult(result):
    &gt;&gt;&gt;    print result
    &gt;&gt;&gt;mc = MemCache()
    &gt;&gt;&gt;mc.version(printResult)
    &gt;&gt;&gt;reactor.callLater(1, reactor.stop)
    &gt;&gt;&gt;reactor.run()
    '</span><span style="color: #483d8b;">''</span>
    <span style="color: #808080; font-style: italic;"># 客户端创建对象</span>
    clientCreator = protocol.<span style="color: black;">ClientCreator</span><span style="color: black;">&#40;</span>reactor, MemCacheProtocol<span style="color: black;">&#41;</span>
    <span style="color: #ff7700;font-weight:bold;">def</span> <span style="color: #0000cd;">__init__</span><span style="color: black;">&#40;</span><span style="color: #008000;">self</span>, host, port=DEFAULT_PORT<span style="color: black;">&#41;</span>:
        <span style="color: #483d8b;">''</span><span style="color: #483d8b;">'
        初始化
        @param host: 主机名
        @param port: 端口号
        '</span><span style="color: #483d8b;">''</span>
        <span style="color: #008000;">self</span>.<span style="color: black;">mcDefer</span> = <span style="color: #008000;">self</span>.<span style="color: black;">clientCreator</span>.<span style="color: black;">connectTCP</span><span style="color: black;">&#40;</span>host, port<span style="color: black;">&#41;</span>
        <span style="color: #008000;">self</span>.<span style="color: black;">mcDefer</span>.<span style="color: black;">addErrback</span><span style="color: black;">&#40;</span><span style="color: #008000;">self</span>._onErr<span style="color: black;">&#41;</span>
&nbsp;
    <span style="color: #ff7700;font-weight:bold;">def</span> _onErr<span style="color: black;">&#40;</span><span style="color: #008000;">self</span>, err<span style="color: black;">&#41;</span>:
        <span style="color: #483d8b;">''</span><span style="color: #483d8b;">'
        错误回调
        '</span><span style="color: #483d8b;">''</span>
        log.<span style="color: black;">err</span><span style="color: black;">&#40;</span>err<span style="color: black;">&#41;</span> 
&nbsp;
    <span style="color: #ff7700;font-weight:bold;">def</span> version<span style="color: black;">&#40;</span><span style="color: #008000;">self</span>, callback<span style="color: black;">&#41;</span>:
        <span style="color: #483d8b;">''</span><span style="color: #483d8b;">'
        获取版本
        @param callback: 回调函数，结果将作为参数传递入该接口
        '</span><span style="color: #483d8b;">''</span>
        <span style="color: #008000;">self</span>.<span style="color: black;">mcDefer</span>.<span style="color: black;">addCallback</span><span style="color: black;">&#40;</span><span style="color: #008000;">self</span>._mcVersion, callback<span style="color: black;">&#41;</span>
&nbsp;
    <span style="color: #ff7700;font-weight:bold;">def</span> _mcVersion<span style="color: black;">&#40;</span><span style="color: #008000;">self</span>, proto, callback<span style="color: black;">&#41;</span>:
        <span style="color: #483d8b;">''</span><span style="color: #483d8b;">'
        版本回调
        @param proto: twisted.p.mMemCacheProtocol
        @param callback: 回调函数返回结果
        '</span><span style="color: #483d8b;">''</span>
        d = proto.<span style="color: black;">version</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
        d.<span style="color: black;">addErrback</span><span style="color: black;">&#40;</span><span style="color: #008000;">self</span>._onErr<span style="color: black;">&#41;</span>
        d.<span style="color: black;">addCallback</span><span style="color: black;">&#40;</span>callback<span style="color: black;">&#41;</span>
        <span style="color: #ff7700;font-weight:bold;">return</span> proto
&nbsp;
    <span style="color: #ff7700;font-weight:bold;">def</span> increment<span style="color: black;">&#40;</span><span style="color: #008000;">self</span>, key, callback<span style="color: black;">&#41;</span>:
        <span style="color: #483d8b;">''</span><span style="color: #483d8b;">'
        增长
        @param key: 键
        @param callback: 回调函数
        '</span><span style="color: #483d8b;">''</span>
        <span style="color: #008000;">self</span>.<span style="color: black;">mcDefer</span>.<span style="color: black;">addCallback</span><span style="color: black;">&#40;</span><span style="color: #008000;">self</span>._mcIncrement, key, callback<span style="color: black;">&#41;</span>        
&nbsp;
    <span style="color: #ff7700;font-weight:bold;">def</span> _mcIncrement<span style="color: black;">&#40;</span><span style="color: #008000;">self</span>, proto, key, callback<span style="color: black;">&#41;</span>:
        <span style="color: #483d8b;">''</span><span style="color: #483d8b;">'
        增长回调
        @param proto: twisted.p.mMemCacheProtocol
        @param key: 键
        @param callback: 回调函数返回结果
        '</span><span style="color: #483d8b;">''</span>
        d = proto.<span style="color: black;">increment</span><span style="color: black;">&#40;</span>key<span style="color: black;">&#41;</span>
        d.<span style="color: black;">addErrback</span><span style="color: black;">&#40;</span><span style="color: #008000;">self</span>._onErr<span style="color: black;">&#41;</span>
        d.<span style="color: black;">addCallback</span><span style="color: black;">&#40;</span>callback<span style="color: black;">&#41;</span>
        <span style="color: #ff7700;font-weight:bold;">return</span> proto
&nbsp;
    <span style="color: #ff7700;font-weight:bold;">def</span> decrement<span style="color: black;">&#40;</span><span style="color: #008000;">self</span>, key, callback<span style="color: black;">&#41;</span>:
        <span style="color: #483d8b;">''</span><span style="color: #483d8b;">'
        减少
        @param key: 键
        @param callback: 回调函数
        '</span><span style="color: #483d8b;">''</span>
        <span style="color: #008000;">self</span>.<span style="color: black;">mcDefer</span>.<span style="color: black;">addCallback</span><span style="color: black;">&#40;</span><span style="color: #008000;">self</span>._mcDecrement, key, callback<span style="color: black;">&#41;</span>        
&nbsp;
    <span style="color: #ff7700;font-weight:bold;">def</span> _mcDecrement<span style="color: black;">&#40;</span><span style="color: #008000;">self</span>, proto, key, callback<span style="color: black;">&#41;</span>:
        <span style="color: #483d8b;">''</span><span style="color: #483d8b;">'
        减少回调
        @param proto: twisted.p.mMemCacheProtocol
        @param key: 键
        @param callback: 回调函数返回结果
        '</span><span style="color: #483d8b;">''</span>
        d = proto.<span style="color: black;">decrement</span><span style="color: black;">&#40;</span>key<span style="color: black;">&#41;</span>
        d.<span style="color: black;">addErrback</span><span style="color: black;">&#40;</span><span style="color: #008000;">self</span>._onErr<span style="color: black;">&#41;</span>
        d.<span style="color: black;">addCallback</span><span style="color: black;">&#40;</span>callback<span style="color: black;">&#41;</span>
        <span style="color: #ff7700;font-weight:bold;">return</span> proto
&nbsp;
    <span style="color: #ff7700;font-weight:bold;">def</span> get<span style="color: black;">&#40;</span><span style="color: #008000;">self</span>, key, callback<span style="color: black;">&#41;</span>:
        <span style="color: #483d8b;">''</span><span style="color: #483d8b;">'
        获取值
        @param key: 键
        @param callback: 回调函数
        '</span><span style="color: #483d8b;">''</span>
        <span style="color: #008000;">self</span>.<span style="color: black;">mcDefer</span>.<span style="color: black;">addCallback</span><span style="color: black;">&#40;</span><span style="color: #008000;">self</span>._mcGet, key, callback<span style="color: black;">&#41;</span>        
&nbsp;
    <span style="color: #ff7700;font-weight:bold;">def</span> _mcGet<span style="color: black;">&#40;</span><span style="color: #008000;">self</span>, proto, key, callback<span style="color: black;">&#41;</span>:
        <span style="color: #483d8b;">''</span><span style="color: #483d8b;">'
        获取值回调
        @param proto: twisted.p.mMemCacheProtocol
        @param key: 键
        @param callback: 回调函数返回结果
        '</span><span style="color: #483d8b;">''</span>
        d = proto.<span style="color: black;">get</span><span style="color: black;">&#40;</span>key<span style="color: black;">&#41;</span>
        d.<span style="color: black;">addErrback</span><span style="color: black;">&#40;</span><span style="color: #008000;">self</span>._onErr<span style="color: black;">&#41;</span>
        d.<span style="color: black;">addCallback</span><span style="color: black;">&#40;</span>callback<span style="color: black;">&#41;</span>
        <span style="color: #ff7700;font-weight:bold;">return</span> proto
&nbsp;
    <span style="color: #ff7700;font-weight:bold;">def</span> <span style="color: #008000;">set</span><span style="color: black;">&#40;</span><span style="color: #008000;">self</span>, key, value, callback<span style="color: black;">&#41;</span>:
        <span style="color: #483d8b;">''</span><span style="color: #483d8b;">'
        设置值
        @param key: 键
        @param value: 值
        @param callback: 回调函数
        '</span><span style="color: #483d8b;">''</span>
        <span style="color: #008000;">self</span>.<span style="color: black;">mcDefer</span>.<span style="color: black;">addCallback</span><span style="color: black;">&#40;</span><span style="color: #008000;">self</span>._mcSet, key, value, callback<span style="color: black;">&#41;</span>        
&nbsp;
    <span style="color: #ff7700;font-weight:bold;">def</span> _mcSet<span style="color: black;">&#40;</span><span style="color: #008000;">self</span>, proto, key, value, callback<span style="color: black;">&#41;</span>:
        <span style="color: #483d8b;">''</span><span style="color: #483d8b;">'
        设置值回调
        @param proto: twisted.p.mMemCacheProtocol
        @param key: 键
        @param value: 值
        @param callback: 回调函数返回结果
        '</span><span style="color: #483d8b;">''</span>
        d = proto.<span style="color: #008000;">set</span><span style="color: black;">&#40;</span>key, value<span style="color: black;">&#41;</span>
        d.<span style="color: black;">addErrback</span><span style="color: black;">&#40;</span><span style="color: #008000;">self</span>._onErr<span style="color: black;">&#41;</span>
        d.<span style="color: black;">addCallback</span><span style="color: black;">&#40;</span>callback<span style="color: black;">&#41;</span>
        <span style="color: #ff7700;font-weight:bold;">return</span> proto
&nbsp;
    <span style="color: #ff7700;font-weight:bold;">def</span> delete<span style="color: black;">&#40;</span><span style="color: #008000;">self</span>, key, callback<span style="color: black;">&#41;</span>:
        <span style="color: #483d8b;">''</span><span style="color: #483d8b;">'
        删除
        @param key: 键
        @param value: 值
        @param callback: 回调函数
        '</span><span style="color: #483d8b;">''</span>
        <span style="color: #008000;">self</span>.<span style="color: black;">mcDefer</span>.<span style="color: black;">addCallback</span><span style="color: black;">&#40;</span><span style="color: #008000;">self</span>._mcDelete, key, callback<span style="color: black;">&#41;</span>        
&nbsp;
    <span style="color: #ff7700;font-weight:bold;">def</span> _mcDelete<span style="color: black;">&#40;</span><span style="color: #008000;">self</span>, proto, key, value, callback<span style="color: black;">&#41;</span>:
        <span style="color: #483d8b;">''</span><span style="color: #483d8b;">'
        删除回调
        @param proto: twisted.p.mMemCacheProtocol
        @param key: 键
        @param value: 值
        @param callback: 回调函数返回结果
        '</span><span style="color: #483d8b;">''</span>
        d = proto.<span style="color: black;">delete</span><span style="color: black;">&#40;</span>key<span style="color: black;">&#41;</span>
        d.<span style="color: black;">addErrback</span><span style="color: black;">&#40;</span><span style="color: #008000;">self</span>._onErr<span style="color: black;">&#41;</span>
        d.<span style="color: black;">addCallback</span><span style="color: black;">&#40;</span>callback<span style="color: black;">&#41;</span>
        <span style="color: #ff7700;font-weight:bold;">return</span> proto
&nbsp;
    <span style="color: #ff7700;font-weight:bold;">def</span> stats<span style="color: black;">&#40;</span><span style="color: #008000;">self</span>, callback<span style="color: black;">&#41;</span>:
        <span style="color: #483d8b;">''</span><span style="color: #483d8b;">'
        状态
        @param key: 键
        @param value: 值
        @param callback: 回调函数
        '</span><span style="color: #483d8b;">''</span>
        <span style="color: #008000;">self</span>.<span style="color: black;">mcDefer</span>.<span style="color: black;">addCallback</span><span style="color: black;">&#40;</span><span style="color: #008000;">self</span>._mcStats, callback<span style="color: black;">&#41;</span>        
&nbsp;
    <span style="color: #ff7700;font-weight:bold;">def</span> _mcStats<span style="color: black;">&#40;</span><span style="color: #008000;">self</span>, proto, callback<span style="color: black;">&#41;</span>:
        <span style="color: #483d8b;">''</span><span style="color: #483d8b;">'
        状态回调
        @param proto: twisted.p.mMemCacheProtocol
        @param key: 键
        @param value: 值
        @param callback: 回调函数返回结果
        '</span><span style="color: #483d8b;">''</span>
        d = proto.<span style="color: black;">stats</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
        d.<span style="color: black;">addErrback</span><span style="color: black;">&#40;</span><span style="color: #008000;">self</span>._onErr<span style="color: black;">&#41;</span>
        d.<span style="color: black;">addCallback</span><span style="color: black;">&#40;</span>callback<span style="color: black;">&#41;</span>
        <span style="color: #ff7700;font-weight:bold;">return</span> proto
&nbsp;
    <span style="color: #ff7700;font-weight:bold;">def</span> flushAll<span style="color: black;">&#40;</span><span style="color: #008000;">self</span>, callback<span style="color: black;">&#41;</span>:
        <span style="color: #483d8b;">''</span><span style="color: #483d8b;">'
        刷新
        @param key: 键
        @param value: 值
        @param callback: 回调函数
        '</span><span style="color: #483d8b;">''</span>
        <span style="color: #008000;">self</span>.<span style="color: black;">mcDefer</span>.<span style="color: black;">addCallback</span><span style="color: black;">&#40;</span><span style="color: #008000;">self</span>._mcFlushAll, callback<span style="color: black;">&#41;</span>        
&nbsp;
    <span style="color: #ff7700;font-weight:bold;">def</span> _mcFlushAll<span style="color: black;">&#40;</span><span style="color: #008000;">self</span>, proto, callback<span style="color: black;">&#41;</span>:
        <span style="color: #483d8b;">''</span><span style="color: #483d8b;">'
        刷新回调
        @param proto: twisted.p.mMemCacheProtocol
        @param key: 键
        @param value: 值
        @param callback: 回调函数返回结果
        '</span><span style="color: #483d8b;">''</span>
        d = proto.<span style="color: black;">flushAll</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
        d.<span style="color: black;">addErrback</span><span style="color: black;">&#40;</span><span style="color: #008000;">self</span>._onErr<span style="color: black;">&#41;</span>
        d.<span style="color: black;">addCallback</span><span style="color: black;">&#40;</span>callback<span style="color: black;">&#41;</span>
        <span style="color: #ff7700;font-weight:bold;">return</span> proto</pre></div></div>

]]></content:encoded>
			<wfw:commentRss>http://www.mikespook.com/index.php/archives/467/feed</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>在游戏中使用脚本语言</title>
		<link>http://www.mikespook.com/index.php/archives/330</link>
		<comments>http://www.mikespook.com/index.php/archives/330#comments</comments>
		<pubDate>Fri, 22 May 2009 05:55:34 +0000</pubDate>
		<dc:creator>mikespook</dc:creator>
				<category><![CDATA[Game]]></category>
		<category><![CDATA[NetBeans]]></category>
		<category><![CDATA[Demo]]></category>
		<category><![CDATA[Scripting]]></category>
		<category><![CDATA[游戏]]></category>

		<guid isPermaLink="false">http://www.mikespook.com/?p=330</guid>
		<description><![CDATA[这只是一个有趣的探索，demo 使用 java 编写。模拟了一个龙与地下城类 RPG 游戏中，在不同的房间内移动的简单游戏场景。 阅读本文前，首先下载使用 Netbeans 6.5 建立的完整项目代码：下载。然后，我会用 UML 图的方式来说明如何在游戏中使用脚本，其中可能还会简介一下游戏中实体对象的建立和管理（不知道值得不值得另外写一篇文章来介绍了）。 I have a dream&#8230; 现在要构建一个极为无聊的小世界。说它小，是因为我只打算让它有三个房间，三个房间之间两两互通的门。仅此而已。首先上图： 我们假设左边上面的房间叫 room-1，右边上面的房间叫 room-2，下面的房间叫 room-3。玩家在这三个房间中穿行，当然，不可能是穿墙。人，一定是要走门的。如图。就这么简单的逻辑而已，不用脚本语言也能轻松完成。不过如果希望多来一点拓展性呢？比如，room-3 不允许等级在5级以下玩家进入；room-2 当十级以上玩家进入后就会自动瞬间移动到 room-1；门锁住以后就不能通过，更夸张一点，门锁住以后如果不把锁打坏就不能通过……可能性太多了。不用脚本的情况下，如果要将这么多都实现，是一件非常繁琐的事情。 好吧，让我们来看看那些游戏公司是怎么解决这个问题的。哦，需要说明的是，这里的解决方案仅仅是一个 demo，只用来解释原理。真正的环境中，还要更复杂一点，不过也就是复杂一点点而已。 游戏中实体类如图设计，为了简化期间，没有实体管理器，所以也没有集成自统一的父类。 Ninny 类也就是玩家，有保存当前所在房间的成员变量。Room 类也就是房间，保存有在当前房间的玩家列表。Door 是描述门的类，保存了这个门连接的两个房间的列表。 为了简单期间，demo 中使用了 java 内置的 javascript 作为脚本语言，详情看这里。 本来还想多写一点的，急着出门。算了，反正有代码，大家看看先。有空回头写。重点在 js 目录下的那几个脚本 enterDoor.js，exitDoor.js，enterRoom.js，exitRoom.js。 好，继续！ 为了用起来方便，稍稍封装了一下Scripting的代码。大家直接看代码，不说话： 1 2 3 4 5 6 7 8 9 10 11 12 [...]]]></description>
			<content:encoded><![CDATA[<p>这只是一个有趣的探索，demo 使用 java 编写。模拟了一个龙与地下城类 RPG 游戏中，在不同的房间内移动的简单游戏场景。</p>
<p>阅读本文前，首先下载使用 Netbeans 6.5 建立的完整项目代码：<a href="http://www.mikespook.com/wp-content/uploads/2009/05/gamescripting.zip">下载</a>。然后，我会用 UML 图的方式来说明如何在游戏中使用脚本，其中可能还会简介一下游戏中实体对象的建立和管理（不知道值得不值得另外写一篇文章来介绍了）。</p>
<p>I have a dream&#8230;<span id="more-330"></span></p>
<p>现在要构建一个极为无聊的小世界。说它小，是因为我只打算让它有三个房间，三个房间之间两两互通的门。仅此而已。首先上图：<a href="http://www.mikespook.com/wp-content/uploads/2009/05/rooms.gif"><img class="alignright size-full wp-image-333" title="三个房间" src="http://www.mikespook.com/wp-content/uploads/2009/05/rooms.gif" alt="三个房间" width="241" height="241" /></a></p>
<p>我们假设左边上面的房间叫 room-1，右边上面的房间叫 room-2，下面的房间叫 room-3。玩家在这三个房间中穿行，当然，不可能是穿墙。人，一定是要走门的。如图。就这么简单的逻辑而已，不用脚本语言也能轻松完成。不过如果希望多来一点拓展性呢？比如，room-3 不允许等级在5级以下玩家进入；room-2 当十级以上玩家进入后就会自动瞬间移动到 room-1；门锁住以后就不能通过，更夸张一点，门锁住以后如果不把锁打坏就不能通过……可能性太多了。不用脚本的情况下，如果要将这么多都实现，是一件非常繁琐的事情。</p>
<p>好吧，让我们来看看那些游戏公司是怎么解决这个问题的。哦，需要说明的是，这里的解决方案仅仅是一个 demo，只用来解释原理。真正的环境中，还要更复杂一点，不过也就是复杂一点点而已。</p>
<p><a href="http://www.mikespook.com/wp-content/uploads/2009/05/gamescripting-e7b1bbe59bbe-1.jpg"><img class="alignleft size-medium wp-image-334" title="类图" src="http://www.mikespook.com/wp-content/uploads/2009/05/gamescripting-e7b1bbe59bbe-1-300x211.jpg" alt="类图" width="300" height="211" /></a>游戏中实体类如图设计，为了简化期间，没有实体管理器，所以也没有集成自统一的父类。</p>
<p>Ninny 类也就是玩家，有保存当前所在房间的成员变量。Room 类也就是房间，保存有在当前房间的玩家列表。Door 是描述门的类，保存了这个门连接的两个房间的列表。</p>
<p>为了简单期间，demo 中使用了 java 内置的 javascript 作为脚本语言，详情看<a href="http://java.sun.com/developer/technicalArticles/J2SE/Desktop/scripting/" target="_blank">这里</a>。</p>
<p><span style="text-decoration: line-through;">本来还想多写一点的，急着出门。算了，反正有代码，大家看看先。有空回头写。重点在 js 目录下的那几个脚本 enterDoor.js，exitDoor.js，enterRoom.js，exitRoom.js。</span></p>
<p>好，继续！</p>
<p>为了用起来方便，稍稍封装了一下Scripting的代码。大家直接看代码，不说话：</p>

<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
</pre></td><td class="code"><pre class="java" style="font-family:monospace;"><span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">java.io.FileNotFoundException</span><span style="color: #339933;">;</span>
<span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">java.io.FileReader</span><span style="color: #339933;">;</span>
<span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">java.util.logging.Level</span><span style="color: #339933;">;</span>
<span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">java.util.logging.Logger</span><span style="color: #339933;">;</span>
<span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">javax.script.ScriptEngine</span><span style="color: #339933;">;</span>
<span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">javax.script.ScriptEngineManager</span><span style="color: #339933;">;</span>
<span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">javax.script.ScriptException</span><span style="color: #339933;">;</span>
&nbsp;
<span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">class</span> Script <span style="color: #009900;">&#123;</span>
&nbsp;
    <span style="color: #000000; font-weight: bold;">private</span> <span style="color: #000000; font-weight: bold;">final</span> <span style="color: #000000; font-weight: bold;">static</span> ScriptEngineManager factory <span style="color: #339933;">=</span> <span style="color: #000000; font-weight: bold;">new</span> ScriptEngineManager<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    <span style="color: #000000; font-weight: bold;">private</span> <span style="color: #000000; font-weight: bold;">final</span> <span style="color: #000000; font-weight: bold;">static</span> ScriptEngine engine <span style="color: #339933;">=</span> factory.<span style="color: #006633;">getEngineByName</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;JavaScript&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
    <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000066; font-weight: bold;">void</span> put<span style="color: #009900;">&#40;</span><span style="color: #003399;">String</span> key, <span style="color: #003399;">Object</span> value<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
        engine.<span style="color: #006633;">put</span><span style="color: #009900;">&#40;</span>key, value<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    <span style="color: #009900;">&#125;</span>
&nbsp;
    <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #003399;">Object</span> get<span style="color: #009900;">&#40;</span><span style="color: #003399;">String</span> key<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
        <span style="color: #000000; font-weight: bold;">return</span> engine.<span style="color: #006633;">get</span><span style="color: #009900;">&#40;</span>key<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    <span style="color: #009900;">&#125;</span>
&nbsp;
    <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #003399;">Object</span> eval<span style="color: #009900;">&#40;</span><span style="color: #003399;">String</span> fileName<span style="color: #009900;">&#41;</span> <span style="color: #000000; font-weight: bold;">throws</span> ScriptException <span style="color: #009900;">&#123;</span>
        <span style="color: #000000; font-weight: bold;">try</span> <span style="color: #009900;">&#123;</span>
            <span style="color: #000000; font-weight: bold;">return</span> engine.<span style="color: #006633;">eval</span><span style="color: #009900;">&#40;</span><span style="color: #000000; font-weight: bold;">new</span> <span style="color: #003399;">FileReader</span><span style="color: #009900;">&#40;</span><span style="color: #003399;">System</span>.<span style="color: #006633;">getProperty</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;user.dir&quot;</span>, <span style="color: #0000ff;">&quot;.&quot;</span><span style="color: #009900;">&#41;</span> <span style="color: #339933;">+</span> <span style="color: #0000ff;">&quot;/js/&quot;</span> <span style="color: #339933;">+</span> fileName <span style="color: #339933;">+</span> <span style="color: #0000ff;">&quot;.js&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
        <span style="color: #009900;">&#125;</span> <span style="color: #000000; font-weight: bold;">catch</span> <span style="color: #009900;">&#40;</span><span style="color: #003399;">FileNotFoundException</span> ex<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
            Logger.<span style="color: #006633;">getLogger</span><span style="color: #009900;">&#40;</span>Script.<span style="color: #000000; font-weight: bold;">class</span>.<span style="color: #006633;">getName</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span>.<span style="color: #006633;">log</span><span style="color: #009900;">&#40;</span>Level.<span style="color: #006633;">SEVERE</span>, <span style="color: #000066; font-weight: bold;">null</span>, ex<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
        <span style="color: #009900;">&#125;</span>
        <span style="color: #000000; font-weight: bold;">return</span> <span style="color: #000066; font-weight: bold;">null</span><span style="color: #339933;">;</span>
    <span style="color: #009900;">&#125;</span>
<span style="color: #009900;">&#125;</span></pre></td></tr></table></div>

<p>从类图上可以看到，Door 和 Room 都实现了 Enterable 接口，两个方法：一个入 enter，一个出 exit。显然，当进入一个 Room 的时候，必须从另外一个房间出来。为了保证这个一致性，所以限定玩家不能穿墙只能走门：</p>

<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
2
3
4
5
6
7
</pre></td><td class="code"><pre class="java" style="font-family:monospace;">        Room r1 <span style="color: #339933;">=</span> <span style="color: #000000; font-weight: bold;">new</span> Room<span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;room-1&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
        Room r2 <span style="color: #339933;">=</span> <span style="color: #000000; font-weight: bold;">new</span> Room<span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;room-2&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
        Door d12 <span style="color: #339933;">=</span> <span style="color: #000000; font-weight: bold;">new</span> Door<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
        d12.<span style="color: #006633;">add</span><span style="color: #009900;">&#40;</span>r1<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
        d12.<span style="color: #006633;">add</span><span style="color: #009900;">&#40;</span>r2<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
        Ninny player <span style="color: #339933;">=</span> <span style="color: #000000; font-weight: bold;">new</span> Ninny<span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;ninny&quot;</span>, r1<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
        d12.<span style="color: #006633;">enter</span><span style="color: #009900;">&#40;</span>player<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></pre></td></tr></table></div>

<p>在不用脚本的情况下怎么写这个 Door 的 enter 方法呢？首先判断一下 ninny 是不是跟 Door 在同一个房间；获得 ninny 的当前房间后 exit；获得门另一端的房间 enter。就是这么简单。不过考虑到前面说说的那种种可能性，为了拓展让我们来看一看用脚本是如何处理的：</p>

<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
</pre></td><td class="code"><pre class="java" style="font-family:monospace;"><span style="color: #666666; font-style: italic;">// Door 的 enter 方法</span>
    <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000066; font-weight: bold;">boolean</span> enter<span style="color: #009900;">&#40;</span>Ninny ninny<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
        Room currentRoom <span style="color: #339933;">=</span> ninny.<span style="color: #006633;">getOwner</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
        <span style="color: #666666; font-style: italic;">// 玩家在当前门所在的房间</span>
        <span style="color: #000000; font-weight: bold;">if</span><span style="color: #009900;">&#40;</span><span style="color: #339933;">!</span>member.<span style="color: #006633;">containsKey</span><span style="color: #009900;">&#40;</span>currentRoom.<span style="color: #006633;">getName</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
            <span style="color: #000000; font-weight: bold;">return</span> <span style="color: #000066; font-weight: bold;">false</span><span style="color: #339933;">;</span>
        <span style="color: #009900;">&#125;</span>
        <span style="color: #666666; font-style: italic;">// 门另一侧的房间</span>
        Room nextRoom <span style="color: #339933;">=</span> getAnotherRoom<span style="color: #009900;">&#40;</span>currentRoom<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
        <span style="color: #000000; font-weight: bold;">try</span> <span style="color: #009900;">&#123;</span>
            Script script <span style="color: #339933;">=</span> <span style="color: #000000; font-weight: bold;">new</span> Script<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
            script.<span style="color: #006633;">put</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;room1&quot;</span>, currentRoom<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
            script.<span style="color: #006633;">put</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;room2&quot;</span>, nextRoom<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
            script.<span style="color: #006633;">put</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;door&quot;</span>, <span style="color: #000000; font-weight: bold;">this</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
            script.<span style="color: #006633;">put</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;player&quot;</span>, ninny<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
            script.<span style="color: #006633;">eval</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;enterDoor&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
            <span style="color: #003399;">System</span>.<span style="color: #006633;">out</span>.<span style="color: #006633;">println</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;enterDoor: &quot;</span> <span style="color: #339933;">+</span> script.<span style="color: #006633;">get</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;message&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
            <span style="color: #000000; font-weight: bold;">return</span> <span style="color: #003399;">Boolean</span>.<span style="color: #006633;">valueOf</span><span style="color: #009900;">&#40;</span>script.<span style="color: #006633;">get</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;result&quot;</span><span style="color: #009900;">&#41;</span>.<span style="color: #006633;">toString</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
        <span style="color: #009900;">&#125;</span> <span style="color: #000000; font-weight: bold;">catch</span> <span style="color: #009900;">&#40;</span>ScriptException ex<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
            Logger.<span style="color: #006633;">getLogger</span><span style="color: #009900;">&#40;</span>Door.<span style="color: #000000; font-weight: bold;">class</span>.<span style="color: #006633;">getName</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span>.<span style="color: #006633;">log</span><span style="color: #009900;">&#40;</span>Level.<span style="color: #006633;">SEVERE</span>, <span style="color: #000066; font-weight: bold;">null</span>, ex<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
            <span style="color: #000000; font-weight: bold;">return</span> <span style="color: #000066; font-weight: bold;">false</span><span style="color: #339933;">;</span>
        <span style="color: #009900;">&#125;</span>        
    <span style="color: #009900;">&#125;</span></pre></td></tr></table></div>

<p>这里实际上 enter 什么也没有做，只是传递了一些数据到 Script，然后执行了 enterDoor 这个脚本：</p>

<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
2
3
4
5
6
7
8
9
</pre></td><td class="code"><pre class="javascript" style="font-family:monospace;">importClass<span style="color: #009900;">&#40;</span>Packages.<span style="color: #660066;">foobar</span>.<span style="color: #660066;">Room</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
importClass<span style="color: #009900;">&#40;</span>Packages.<span style="color: #660066;">foobar</span>.<span style="color: #660066;">Ninny</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
importClass<span style="color: #009900;">&#40;</span>Packages.<span style="color: #660066;">foobar</span>.<span style="color: #660066;">Door</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
room1.<span style="color: #660066;">exit</span><span style="color: #009900;">&#40;</span>player<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
room2.<span style="color: #660066;">enter</span><span style="color: #009900;">&#40;</span>player<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
<span style="color: #003366; font-weight: bold;">var</span> message <span style="color: #339933;">=</span> player.<span style="color: #660066;">getName</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #339933;">+</span> <span style="color: #3366CC;">&quot; enter from the room &quot;</span> <span style="color: #339933;">+</span> room1.<span style="color: #660066;">getName</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #339933;">+</span>  <span style="color: #3366CC;">&quot; to the romm &quot;</span> <span style="color: #339933;">+</span> room2.<span style="color: #660066;">getName</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #339933;">+</span> <span style="color: #3366CC;">&quot;!&quot;</span><span style="color: #339933;">;</span>
<span style="color: #003366; font-weight: bold;">var</span> result <span style="color: #339933;">=</span> <span style="color: #003366; font-weight: bold;">true</span><span style="color: #339933;">;</span></pre></td></tr></table></div>

<p>脚本也很简单，只是让玩家推出当前房间，进入下一个房间。如果房间对进入的玩家有等级要求，则只需：</p>

<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
</pre></td><td class="code"><pre class="javascript" style="font-family:monospace;">importClass<span style="color: #009900;">&#40;</span>Packages.<span style="color: #660066;">foobar</span>.<span style="color: #660066;">Room</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
importClass<span style="color: #009900;">&#40;</span>Packages.<span style="color: #660066;">foobar</span>.<span style="color: #660066;">Ninny</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
importClass<span style="color: #009900;">&#40;</span>Packages.<span style="color: #660066;">foobar</span>.<span style="color: #660066;">Door</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
<span style="color: #003366; font-weight: bold;">var</span> result <span style="color: #339933;">=</span> <span style="color: #003366; font-weight: bold;">false</span><span style="color: #339933;">;</span>
<span style="color: #003366; font-weight: bold;">var</span> message <span style="color: #339933;">=</span> <span style="color: #3366CC;">''</span><span style="color: #339933;">;</span>
<span style="color: #000066; font-weight: bold;">if</span><span style="color: #009900;">&#40;</span>room2.<span style="color: #660066;">needLevel</span> <span style="color: #339933;">&gt;=</span> player.<span style="color: #660066;">level</span> <span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
    room1.<span style="color: #660066;">exit</span><span style="color: #009900;">&#40;</span>player<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    room2.<span style="color: #660066;">enter</span><span style="color: #009900;">&#40;</span>player<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
    message <span style="color: #339933;">=</span> player.<span style="color: #660066;">getName</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #339933;">+</span> <span style="color: #3366CC;">&quot; enter from the room &quot;</span> <span style="color: #339933;">+</span> room1.<span style="color: #660066;">getName</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #339933;">+</span>  <span style="color: #3366CC;">&quot; to the romm &quot;</span> <span style="color: #339933;">+</span> room2.<span style="color: #660066;">getName</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #339933;">+</span> <span style="color: #3366CC;">&quot;!&quot;</span><span style="color: #339933;">;</span>
    result <span style="color: #339933;">=</span> <span style="color: #003366; font-weight: bold;">true</span><span style="color: #339933;">;</span>
<span style="color: #009900;">&#125;</span> <span style="color: #000066; font-weight: bold;">else</span> <span style="color: #009900;">&#123;</span>
    message <span style="color: #339933;">=</span> player.<span style="color: #660066;">getName</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #339933;">+</span> <span style="color: #3366CC;">&quot; can't enter the romm &quot;</span> <span style="color: #339933;">+</span> room2.<span style="color: #660066;">getName</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #339933;">+</span> <span style="color: #3366CC;">&quot;! Level&quot;</span> <span style="color: #339933;">+</span> room2.<span style="color: #660066;">needLevel</span> <span style="color: #339933;">+</span><span style="color: #3366CC;">&quot; needed!&quot;</span><span style="color: #339933;">;</span>
<span style="color: #009900;">&#125;</span></pre></td></tr></table></div>

<p>在我的例子代码中并没有这部分代码，实际上 Room、Door、Ninny 这几个类都应该从一个父类 Entity 中继承。这个 Entity 有一个 Map<String, Object> 的成员变量。通过 setAttr(String, Object) 和 getAttr(String) 两个方法就可以分别设置和获取每个 Entity 的属性。这样就可以在脚本中自由的使用各种属性来实现各种功能。<br />
通过 Enterable（可进入），Pickable（可捡起），Attackable（可攻击）等接口，调用对应的脚本来完成真正的游戏逻辑。<br />
其实那神秘的游戏脚本化就是这么简单。本来还想画几个序列图说明一下脚本的调用，实在有些困了。<br />
准备洗洗睡觉。尚未补充完整的内容，全当大家进阶学习吧。</p>
]]></content:encoded>
			<wfw:commentRss>http://www.mikespook.com/index.php/archives/330/feed</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
	</channel>
</rss>
