找回密码
 点一下
查看: 7913|回复: 52

location魔法。location是比GameCache更牛逼的存在

[复制链接]
发表于 2006-4-12 09:48:14 | 显示全部楼层 |阅读模式
  在Jass中有一种数据类型叫location(位置。WE中的Point??点)。它的基本处理函数有:
[jass]
native Location                 takes real x, real y returns location
native RemoveLocation           takes location whichLocation returns nothing
native MoveLocation             takes location whichLocation, real newX, real newY returns nothing
native GetLocationX             takes location whichLocation returns real
native GetLocationY             takes location whichLocation returns real

// This function is asynchronous. The values it returns are not guaranteed synchronous between each player.
//  If you attempt to use it in a synchronous manner, it may cause a desync.
native GetLocationZ             takes location whichLocation returns real
[/jass]

  可以看出,location实际上是一个存储三维坐标的数据类型。但是暴雪没提供修改location的 Z 分量的函数,而且GetLocationZ还是不同步的。所以我们在很多情况下只能将location当作二维坐标来看。
  注意,可以用MoveLocation修改location的 X、Y 分量的,利用这一点我们可以做许多有趣的东西。



一、向量

  记得高中学习向量时,我开始总是想不明白 坐标 与 向量 到底有什么区别。都差不多嘛,都是有 X、Y分量的东西,就是运算方式有点区别:坐标 减 坐标 是 向量、坐标 加 向量 是 坐标、向量 加 向量 还是 向量、向量 与 向量 的点积是 数……
  后面才明白,运算方式的区别 就是 坐标与向量的根本区别。
  现在Jass中有location这种数据类型,又有基本的操作函数,我们就可以根据向量运算法则编写向量函数??把 location 当作 向量 来使用。



二、复数

  复数是什么东西?
  简单的来说,复数是具有两个分量的数。
  两个分量?那不就是location吗!
  哈哈!现在我们有 复数 这种数据类型了!



三、链表

  先回头来想想“return bug”能干什么。比如可以将handle转为integer,将integer转为real。
  location不就是从handle继承的吗,那么location可以转成real。
  啊!location的分量不就是real型的吗,我们可以用location的分量来存放location(的引用)。
  哈哈!这不就是链表嘛!

  再仔细设计一下。我们可以用 X分量 存放 下一节点(的引用),用 Y分量 存放节点数据。由于现在有“return bug”,所以 Y分量 能存放任何数据。

  现在我们就可以用location链表来制作线性表了,还可以写许多线形表操作函数,如查找、排序之类的。
  有了线性表,我们还可以做出 栈、队列、双端队列 等数据结构。

  查找、排序 需要比较对象,但是用“return bug”转型后没有了类型信息。怎么办?
  想想在C语言中是怎么实现排序的。是使用函数指针来调用回调函数来对较对象大小。
  哈哈!不是可以创建触发器吗,给触发器加动作时填的不就是函数地址嘛,我们可以用触发器模拟函数指针。

  这时可能会有人弱弱的问“线性表有什么作用?”
  在Jass中,函数的参数不能是数组,现在我们可以利用线性表在函数之间传递大批数据??特别是给AI发消息时。



四、二叉树

  线性表好虽好,但是存在一个严重的问题??检索速度太慢。
  对于高速检索,《数据结构》上的标准解决方案是使用二叉树。
  二叉树的节点需要三个参数:数据,左节点指针,左节点指针。
  可location只能使用 X、Y分量,难道去要求暴雪开放 Z分量?

  不不不!
  还记得我们做链表吗,当对于有两个节点的链表,有三个字段可以使用的:首节点的 Y分量,下一节点的 X、Y分量。
  这不就是三个分量了吗。

  由于我们 对节点数据的操作 远超过 对指针的操作。
  所以我建议:用 X分量 存放记录左右子节点的location,用 Y分量 存放数据。

  现在我们能构造二叉树了,就可以实现 平衡二叉树、堆(优先队列) 等经典数据结构。



五、挑战GameCache

  单位、物品不是自定义值吗。
  它是integer型,可以利用“return bug”让它存放location。
  结合上面的内容,我们可以用location构造复杂数据类型。
  即:可以利用 location 在 自定义值 中 存放很多数据。

  这是什么功能?
  这就是GameCache垄断的领域!

  GameCache的缺点:
  1.必须创建一个GameCache,而且必须用全局变量来存放。
  2.GameCache是用字符串来标识不同的数据,I2S、S2I字符串转换效率低

  而location没有这些缺点!能做到比GameCache更纯粹的局部化。而且避开了低效的字符串转化,效率极高。


  成也萧何败也萧何。
  location的缺点就是不能按名访问。
  可这正是GameCache的强项。


  有必要 倚天、屠龙 对砍吗?
  GameCache中不是能利用“return bug”来存放location吗。
  双剑合璧才是王道!
  对于一大堆类似的数据,用location最好。
  对于按名访问,GameCache最好。


  最后奉上我对location的评语:道生一,一生二,二生三,三生万物 ?? 老子《道德经》

[ 本帖最后由 zyl910 于 2006-4-12 13:51 编辑 ]
 楼主| 发表于 2006-4-12 09:48:26 | 显示全部楼层

代码和演示

保留


复数运算法则:
  • z1 + z2 = (x1 + i*y1) + (x2 + i*y2) = (x1 + x2) + i*(y1 + y2)
  • z1 - z2 = (x1 - x2) + i*(y1 - y2)
  • z1 * z2 = (x1 + i*y1) + (x2 + i*y2) = (x1*x2 - y1*y2) + i*(x1*y2 + x2*y1)
  • z1 / z2 = (x1 + i*y1) / (x2 + i*y2)
    = ((x1 + i*y1) * (x2 - i*y2)) / ((x2 + i*y2) * (x2 - i*y2))  // 利用共轭复数
    = ((x1*x2 + y1*y2) + i*(x2*y1 - x1*y2)) / (x2*x2 + y2*y2)
  • z^n = (r * e^(i*th))^n = (r^n) * e^(i*(th * n))
  • ln(z) = ln(r * e^(i*th)) = ln(r) + ln(e^(i*th)) = ln(r) + i*(th + 2*k*Pi)


注意后面的两个都是把复数换成三角形式来计算的(欧拉公式)

[ 本帖最后由 zyl910 于 2006-4-12 22:47 编辑 ]
回复

使用道具 举报

 楼主| 发表于 2006-4-12 09:48:32 | 显示全部楼层

下一版本计划

保留
回复

使用道具 举报

发表于 2006-4-12 10:37:11 | 显示全部楼层
不错的想法,不过还是有一些限制,比如要给一个unit存10个integer怎么处理?
还有,unit/item是有use data的,timer, trigger, timerdialog等呢?

location实质上是一个integer->(real,real)的映射,用>=2个数组就可以实现了。

[ 本帖最后由 zyl910 于 2006-4-12 10:45 编辑 ]
回复

使用道具 举报

 楼主| 发表于 2006-4-12 10:45:41 | 显示全部楼层
原帖由 lars 于 2006-4-12 10:37 发表
不错的想法,不过还是有一些限制,比如要给一个unit存10个integer怎么处理?
还有,unit/item是有use data的,timer, trigger, timerdialog等呢?

location实质上是一个integer->(real,real)的映射,用> ...



看“三、链表”

函数间不能传递数组的

按名存储是GameCache的强项,两者可以结合的

在wc3jass看到有人用GameCache做堆(优先队列),感觉效率太低了,所以才想这个东西的


PS:汗,刚才点错了

[ 本帖最后由 zyl910 于 2006-4-12 10:48 编辑 ]
回复

使用道具 举报

发表于 2006-4-12 10:47:37 | 显示全部楼层
数组是全局的,只需要传递一个index的。Location的\"index\"-他的handle,其实也是全局的,对吧?
回复

使用道具 举报

 楼主| 发表于 2006-4-12 10:52:23 | 显示全部楼层
原帖由 lars 于 2006-4-12 10:47 发表
数组是全局的,只需要传递一个index的。Location的\"index\"-他的handle,其实也是全局的,对吧?


我要传递一大批数据怎么办?

可以这样构造location链表:
loc0: X=loc1, Y= data0
loc1: X=loc2, Y= data1
loc2: X=0, Y= data2

然后把loc0传递过去
这样实际上把 data0、data1、data2 这三个数据传递过去了

PS:
这牵涉到《数据结构》中的一些概念
早知道发到“算法区”算了

[ 本帖最后由 zyl910 于 2006-4-12 10:53 编辑 ]
回复

使用道具 举报

发表于 2006-4-12 10:55:57 | 显示全部楼层
GameCache的一个好处是,除了I2S外,其他运算都是在native code中做的,native code中做的东西时间几乎都可以忽略,而JASS中连一个函数调用都会很费时间,看Vexorian测试平方函数,用的几种方法:
1) local real y=4*4
2) local real x=4
    local real y=x*x
3) local real x=4
    local real y=Pow(x,2)
4)function Sqr takes real x returns real
       return x*x
   endfunction
       set y=Sqr(4)

方法1,2差别不大,3用了Pow比较慢可以理解,方法4居然是最慢的,几乎是方法1的二倍半,唯一的解释就是方法4多了一次JASS的函数调用. 所以能把事情丢给assemble code做的就丢过去为好。
回复

使用道具 举报

发表于 2006-4-12 10:59:45 | 显示全部楼层
Location和Array+Array他们的实质是一样的阿,能做的事情也都一样的。我曾需要过linklist,用JASS的两个数组模拟过。在Pascal等没有指针也没有对象的语言里做链表就是这么搞得。
回复

使用道具 举报

 楼主| 发表于 2006-4-12 11:00:34 | 显示全部楼层
在脚本语言中
函数调用的开销是很大的
回复

使用道具 举报

 楼主| 发表于 2006-4-12 11:01:44 | 显示全部楼层
原帖由 lars 于 2006-4-12 10:59 发表
Location和Array+Array他们的实质是一样的阿,能做的事情也都一样的。我曾需要过linklist,用JASS的两个数组模拟过。在Pascal等没有指针也没有对象的语言里做链表就是这么搞得。


Jass中的数组最多只有8192
而location理论上是无限了

而且数组必须是全局变量
回复

使用道具 举报

发表于 2006-4-12 11:02:04 | 显示全部楼层
关于复数有个问题:
个人觉得二维只是复数的一个性质 而复数最更本的特点应是其虚部上  i ^2= -1  离开了这条性质 复数实际上就是二维向量了 在狭义相对论中 闵科夫斯基空间的时间那一维的度归为 i 如果代而用 1 的话是无法正确得出罗伦兹变换的 当然 在很多问题中只利用了她二维的性质可以统一和简化描述 但有些时候确实是离不开 i 的
而要让复数具有 i 这样的运算性质 是不是要在写运算代码的时候定义好一个函数满足这样的规则?

[ 本帖最后由 illlusion 于 2006-4-12 11:08 编辑 ]
回复

使用道具 举报

 楼主| 发表于 2006-4-12 11:03:37 | 显示全部楼层
原帖由 lars 于 2006-4-12 10:59 发表
在Pascal等没有指针也没有对象的语言里做链表就是这么搞得。



Pascal有指针语法啊

只有VB没有指针
但在VB可以用通过修改SafeArray来模拟指针
看AdamBear的真是想不到系列:
http://dev.csdn.net/user/AdamBear
回复

使用道具 举报

 楼主| 发表于 2006-4-12 11:05:51 | 显示全部楼层
原帖由 illlusion 于 2006-4-12 11:02 发表
关于复数有个问题:
个人觉得二维只是复数的一个性质 而复数最更本的特点应是 i = (-1)^0.5 的 离开了这条性质 复数实际上就是二维向量了 在狭义相对论中 闵科夫斯基空间的时间那一维的度归为 i 如果代而用 1 的 ...




i就是 Location(0, 1)
自己可以写复数的Pow函数的

复数有很多奇妙的性质
比如复数的对数有无穷多个

PS:汗。刚才点错了
回复

使用道具 举报

发表于 2006-4-12 11:06:11 | 显示全部楼层
你说的是Borland自己改的Objective Pascal吧。
回复

使用道具 举报

发表于 2006-4-12 11:06:42 | 显示全部楼层
原帖由 zyl910 于 2006-4-12 11:05 发表




i就是 Location(0, 1)
自己可以写复数的Pow函数的

复数有很多奇妙的性质
比如复数的对数有无穷多个

PS:汗。刚才点错了


运算的时候怎么办?
回复

使用道具 举报

 楼主| 发表于 2006-4-12 11:09:02 | 显示全部楼层
原帖由 lars 于 2006-4-12 11:06 发表
你说的是Borland自己改的Objective Pascal吧。


至少80年代的Turbo Pascal教材都讲了指针
特别是严蔚敏的《数据结构》
回复

使用道具 举报

 楼主| 发表于 2006-4-12 11:10:38 | 显示全部楼层
原帖由 illlusion 于 2006-4-12 11:06 发表


运算的时候怎么办?


自己写运算函数

去看看C++标准库中的复数类怎么实现的吧


PS:C++真的好牛逼,特别是重载运算符
回复

使用道具 举报

发表于 2006-4-12 11:10:55 | 显示全部楼层
我对代码里实现这些运算法则很好奇
例如我想运算 S^2 = X^2 + Y^2 + Z^2 + (i*T)^2  这个应该怎么处理?
回复

使用道具 举报

发表于 2006-4-12 11:11:54 | 显示全部楼层
那就是我记错了   :)
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 点一下

本版积分规则

Archiver|移动端|小黑屋|地精研究院

GMT+8, 2024-12-22 15:20 , Processed in 0.130833 second(s), 19 queries .

Powered by Discuz! X3.5

© 2001-2023 Discuz! Team.

快速回复 返回顶部 返回列表