屏幕坐标位置的确定用公式计算:
屏幕的x坐标=地图格子逻辑数组中的位置X * 格子宽度
屏幕的y坐标=地图格子逻辑数组中的位置Y * 格子高度/2
得到的图应该是这样的:
那么这个公式是怎样得到呢?
这个地图有5行,看着这个地图你会想,怎么拼图才能将地图拼出来。再画张图来演示:
从这张图可以看出,拼图时从左到右,从上到下,跟正规的矩形拼图一样,唯一同的是,地图元素与元素之间有重叠,看看第一行和第二行之间,第二行的地图元素会压在第一行的元素上,而第三行的的地图元素则压在第二行的元素上。所以,只要找到正确的公式,你就能正确地设计程序,再来一张图:
图上绿点(是高亮度绿色,不是暗绿色)是每块地图元素的起点,第一行的行坐标是0,第二行的行坐标是1,第三行的行坐标是2,......由这些行坐标决定你的地图元素的起点,从这个规律中看出行坐标0,和行坐标2的横向坐标X的起点是一样的是0,行坐标为1的起点是向右移半块地图元素。
再从纵向坐标找规律,看行坐标0和行坐标2,两块地图元素之间的距离刚好是一块地图元素的高。再看看行坐标0和行坐标1,两块地图元素之间的距离刚好是半块地图元素的高。所以,计算每块地图元素的位置,你的转换屏幕坐标和逻辑公式刚好是:
logic.y = ( 2 * stage.y ) / TileHeigth;
logic.x = ( stage.x / TileWidth ) - ( logic.y & 1 ) * ( TileWidth / 2 );
stage.x = logic.x * TileWidth + ( logic.y & 1) * ( TileWidth / 2 );
stage.y = logic.y * TileHeigth / 2;
其中TileHeigth和TileWidth是菱形的高和宽,这样你可以再尝试着定义(0,1),(0,2),(0,3)等点,和得到的结果完全一样···
重要:
首先以上的公式只适用于Staggered斜45度角地图,而slide,和Diamond形地图,这个公式要稍加修改才能用。
Staggered:
Slide:
Diamond:
而得到的逻辑坐标就是把了斜45度得到的实际坐标么?当然不是···
仔细观察,如果我们想用一个直角的坐标来表示这个地图,那么大家可能开发起来也更加直观一些,看这个坐标表示出来的y轴都是扭曲的用起来实在不爽,那么我们来将它转换到直角坐标,那么再来加上寻路等算法都没有任何难度了
首先我们将地图的高进行转换,这个转换主要是将菱形还原成正方形,例如菱形的高宽比是2:1,那么在地图上则需要将地图高度扩大一倍,然后旋转-45度,那么得到对应坐标如下
我们更加仔细的对这个图的坐标进行
1 /**
2 *
3 * @author myth815
4 */
5 package ContainerObjectManager
6 {
7 import flash.geom.Point;
8 import Math;
9 public class PointExchange
10 {
11 private static var TileWidth : int = 60;
12 private static var TileHeigth : int = 30;
13 public function PointExchange()
14 {
15 //this Class not allow init!
16 }
17
18 public static function StageToLogic(stage:Point):Point
19 {
20 var logic : Point = new Point;
21 logic.y = ( 2 * stage.y ) / TileHeigth;
22 logic.x = ( stage.x / TileWidth ) - ( logic.y & 1 ) * ( TileWidth / 2 );
23 return logic;
24 }
25
26 public static function LogicToStage(logic:Point):Point
27 {
28 var stage : Point = new Point;
29 stage.x = logic.x * TileWidth + ( logic.y & 1) * ( TileWidth / 2 );
30 stage.y = logic.y * TileHeigth / 2;
31 return stage;
32 }
33 }
34 }
标注:
1 比方说定义格子的长度(W=80像素),高度(H=40像素)
2 Constants.TILE_WIDTH = 80;
3 Constants.TILE_HEIGHT= 40;
4 1:格子坐标与像素坐标的互相转换公式
5 1.1:格子坐标转像素坐标
6 /**
7 * 像素坐标转换成斜45度的格子坐标
8 * @param px 像素X坐标
9 * @param py 像素Y坐标
10 * @return
11 */
12 public static short[] pixToTile(int px,int py){
13 int ty= 2*py/Constants.TILE_HEIGHT-1;
14 if(ty<0){
15 log.error("ty:"+py);
16 ty = 0;
17 }
18 int tx= (px-(ty&1)*(Constants.TILE_WIDTH/2))/Constants.TILE_WIDTH;
19 if(tx<0){
20 log.error("tx:"+px);
21 tx = 0;
22 }
23 return new short[]{(short)tx,(short)ty};
24 }
25 1.2:像素坐标转格子坐标
26 /**
27 * 斜45度的格子坐标转换成像素坐标
28 * @param tx 斜45度的格子X坐标
29 * @param ty 斜45度的格子Y坐标
30 * @return
31 */
32 public static short[] tileToPix(int tx,int ty){
33 int px=(tx*Constants.TILE_WIDTH+((ty&1)+1)*(Constants.TILE_WIDTH/2));
34 int py=(ty+1)*(Constants.TILE_HEIGHT/2);
35 return new short[]{(short)px,(short)py};
36 }
37
38
39
40 2:两格子坐标四方向相差的格子数计算
41
42 /**
43 * 忽略地图地形(计算两个格子之间经过的格子数)
44 * @param bx 开始格子X坐标
45 * @param by 开始格子Y坐标
46 * @param ex 目标格子X坐标
47 * @param ey 目标格子Y坐标
48 * @return
49 */
50 public static int getTileNumFromTile(short bx,short by,short ex,short ey){
51 short[] beginPix = tileToPix(bx,by);
52 short[] endPix = tileToPix(ex,ey);
53 int subX = Math.abs(endPix[0]-beginPix[0])/(Constants.TILE_WIDTH/2);
54 int subY = Math.abs(endPix[1]-beginPix[1])/(Constants.TILE_HEIGHT/2);
55 return Math.max(subX, subY);
56 }
57
58 3:靠近某目标格子的相关计算
59
60 /**
61 * 获取以此格子坐标(x,y)为中心的四个方向的其他格子坐标
62 * @param x
63 * @param y
64 * @return
65 */
66 public static short[][] getNext4(short x,short y){
67 short[][] nextXy= new short[4][2];
68 //Y坐标偶数时 X坐标减1
69 if(y%2==0){
70 short preX = (short)(x-1);
71 short preY = (short)(y-1);
72 short nexY = (short)(y+1);
73 nextXy[0]=new short[]{preX,preY};
74 nextXy[1]=new short[]{preX,nexY};
75 nextXy[2]=new short[]{x,preY};
76 nextXy[3]=new short[]{x,nexY};
77 }else{
78 short preY = (short)(y-1);
79 short nexY = (short)(y+1);
80 short nextX = (short)(x+1);
81 nextXy[0]=new short[]{x,preY};
82 nextXy[1]=new short[]{x,nexY};
83 nextXy[2]=new short[]{nextX,preY};
84 nextXy[3]=new short[]{nextX,nexY};
85 }
86 return nextXy;
87 }
88
89
90 /**
91 * 找出最短格子路线
92 * @param map 地图数据
93 * @param begin 起点位置数据
94 * @param end 目标位置格子坐标
95 * @param moveAbility 可移动的格子数
96 * @param areaNum 所占格子数
97 * @param isOmit 忽略地形
98 * @return
99 */ public static Object[] findMinTileLine(byte[][]map,SlgNode begin,short[] end,byte moveAbility,byte areaNum,boolean isOmit){
100 //最小格子数
101 int minNums = getTileNumFromTile(begin.getTx(),begin.getTy(),end[0],end[1]);
102 if(minNums<2)return null;
103 if(areaNum>1){
104 short[][] infos = getTopArea(begin.getTx(),begin.getTy(),areaNum);
105 for(int i=1;i<infos.length;i++){
106 int tmpNums = getTileNumFromTile(infos[i][0],infos[i][1],end[0],end[1]);
107 if(tmpNums<minNums){
108 minNums = tmpNums;
109 if(minNums < 2) return null;
110 }
111 }
112 }
113 int curr=0;
114 SlgNode node = begin;
115 while(curr<moveAbility){
116 //找出周围四个格子离目标的位置
117 short[][] data = getNext4(node.getTx(),node.getTy());
118 SlgNode minNode = null;
119 int omit = (isOmit?2:1);
120
121 for(int i=0;i<data.length;i++){
122 short tx =data[i][0],ty =data[i][1];
123 //格子位置是否合法(没有被障碍物阻止)
124 if(ty>=0&&ty<map.length&&tx>=0&&tx<map[0].length&&map[ty][tx]<omit){
125 int tmpNums = getTileNumFromTile(tx,ty,end[0],end[1]);
126 boolean isFlag = true;
127 //如果是占用多格子的检测其他的格子是否合法
128 if(areaNum>1){
129 short[][] infos = getTopArea(tx,ty,areaNum);
130 for(int j=1;j<infos.length;j++){
131 short tx0 = infos[j][0],ty0=infos[j][1];
132 if(ty0<map.length&&tx0 <map[0].length && ty0>=0&&tx0>=0&&map[ty0][tx0]<omit){
133 if(tmpNums>1){
134 int tmpNums0 = getTileNumFromTile(tx0,ty0,end[0],end[1]);
135 if(tmpNums0<tmpNums)tmpNums = tmpNums0;
136 }
137 }else{
138 isFlag = false;break;
139 }
140 }
141 }
142 if(tmpNums<minNums && isFlag){
143 minNode= new SlgNode(tx,ty,(byte)(node.getLen()+1));
144 minNode.setParent(node);
145 if(tmpNums<2)return new Object[]{minNode,tmpNums};
146 minNums = tmpNums;
147 }
148 }
149 }
150 if(minNode==null)return curr==0?null:new Object[]{minNode,minNums};
151 curr++;
152 node = minNode;
153 }
154 return new Object[]{node,minNums};
155 }
156
157
158
159 /**
160 * SLG移动格子坐标数据定义
161 * @author Administrator
162 *
163 */
164 public class SlgNode implements Comparable<SlgNode>{
165 //格子坐标
166 private short tx;
167 private short ty;
168 //父节点
169 private SlgNode parent;
170 //步长
171 private byte len;
172
173 public SlgNode(){
174
175 }
176
177
178 public SlgNode(short tx,short ty,byte len){
179 this.tx = tx;
180 this.ty= ty;
181 this.len = len;
182 }
183
184 public short getTx() {
185 return tx;
186 }
187 public void setTx(short tx) {
188 this.tx = tx;
189 }
190 public short getTy() {
191 return ty;
192 }
193 public void setTy(short ty) {
194 this.ty = ty;
195 }
196 public SlgNode getParent() {
197 return parent;
198 }
199 public void setParent(SlgNode parent) {
200 this.parent = parent;
201 }
202 public byte getLen() {
203 return len;
204 }
205 public void setLen(int len) {
206 this.len = (byte)len;
207 }
208
209 public static String getCode(int x,int y){
210 return x+"_"+y;
211 }
212
213 public String getCode(){
214 return getCode(tx,ty);
215 }
216
217 public String toString(){
218 StringBuilder path = new StringBuilder().append("[").append(tx).append(",").append(ty).append("][").append(len).append("]");
219 if(this.parent!=null){
220 path.append("->").append(this.parent.toString());
221 }
222 return path.toString();
223 }
224
225 public int compareTo(SlgNode o) {
226 if(len>0 && o.getLen()>0){
227 return len-o.getLen();
228 }else if(o.getLen()>0){
229 return 1;
230 }
231 return 0;
232 }
233 }
234