屏幕坐標(biāo)位置的確定用公式計(jì)算:
屏幕的x坐標(biāo)=地圖格子邏輯數(shù)組中的位置X * 格子寬度
屏幕的y坐標(biāo)=地圖格子邏輯數(shù)組中的位置Y * 格子高度/2
得到的圖應(yīng)該是這樣的:
那么這個公式是怎樣得到呢?
這個地圖有5行,看著這個地圖你會想,怎么拼圖才能將地圖拼出來。再畫張圖來演示:
從這張圖可以看出,拼圖時從左到右,從上到下,跟正規(guī)的矩形拼圖一樣,唯一同的是,地圖元素與元素之間有重疊,看看第一行和第二行之間,第二行的地圖元素會壓在第一行的元素上,而第三行的的地圖元素則壓在第二行的元素上。所以,只要找到正確的公式,你就能正確地設(shè)計(jì)程序,再來一張圖:
圖上綠點(diǎn)(是高亮度綠色,不是暗綠色)是每塊地圖元素的起點(diǎn),第一行的行坐標(biāo)是0,第二行的行坐標(biāo)是1,第三行的行坐標(biāo)是2,......由這些行坐標(biāo)決定你的地圖元素的起點(diǎn),從這個規(guī)律中看出行坐標(biāo)0,和行坐標(biāo)2的橫向坐標(biāo)X的起點(diǎn)是一樣的是0,行坐標(biāo)為1的起點(diǎn)是向右移半塊地圖元素。
再從縱向坐標(biāo)找規(guī)律,看行坐標(biāo)0和行坐標(biāo)2,兩塊地圖元素之間的距離剛好是一塊地圖元素的高。再看看行坐標(biāo)0和行坐標(biāo)1,兩塊地圖元素之間的距離剛好是半塊地圖元素的高。所以,計(jì)算每塊地圖元素的位置,你的轉(zhuǎn)換屏幕坐標(biāo)和邏輯公式剛好是:
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)等點(diǎn),和得到的結(jié)果完全一樣···
重要:
首先以上的公式只適用于Staggered斜45度角地圖,而slide,和Diamond形地圖,這個公式要稍加修改才能用。
Staggered:
Slide:
Diamond:
而得到的邏輯坐標(biāo)就是把了斜45度得到的實(shí)際坐標(biāo)么?當(dāng)然不是···
仔細(xì)觀察,如果我們想用一個直角的坐標(biāo)來表示這個地圖,那么大家可能開發(fā)起來也更加直觀一些,看這個坐標(biāo)表示出來的y軸都是扭曲的用起來實(shí)在不爽,那么我們來將它轉(zhuǎn)換到直角坐標(biāo),那么再來加上尋路等算法都沒有任何難度了
首先我們將地圖的高進(jìn)行轉(zhuǎn)換,這個轉(zhuǎn)換主要是將菱形還原成正方形,例如菱形的高寬比是2:1,那么在地圖上則需要將地圖高度擴(kuò)大一倍,然后旋轉(zhuǎn)-45度,那么得到對應(yīng)坐標(biāo)如下
我們更加仔細(xì)的對這個圖的坐標(biāo)進(jìn)行
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 }
標(biāo)注:
1 比方說定義格子的長度(W=80像素),高度(H=40像素)
2 Constants.TILE_WIDTH = 80;
3 Constants.TILE_HEIGHT= 40;
4 1:格子坐標(biāo)與像素坐標(biāo)的互相轉(zhuǎn)換公式
5 1.1:格子坐標(biāo)轉(zhuǎn)像素坐標(biāo)
6 /**
7 * 像素坐標(biāo)轉(zhuǎn)換成斜45度的格子坐標(biāo)
8 * @param px 像素X坐標(biāo)
9 * @param py 像素Y坐標(biāo)
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:像素坐標(biāo)轉(zhuǎn)格子坐標(biāo)
26 /**
27 * 斜45度的格子坐標(biāo)轉(zhuǎn)換成像素坐標(biāo)
28 * @param tx 斜45度的格子X坐標(biāo)
29 * @param ty 斜45度的格子Y坐標(biāo)
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:兩格子坐標(biāo)四方向相差的格子數(shù)計(jì)算
41
42 /**
43 * 忽略地圖地形(計(jì)算兩個格子之間經(jīng)過的格子數(shù))
44 * @param bx 開始格子X坐標(biāo)
45 * @param by 開始格子Y坐標(biāo)
46 * @param ex 目標(biāo)格子X坐標(biāo)
47 * @param ey 目標(biāo)格子Y坐標(biāo)
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:靠近某目標(biāo)格子的相關(guān)計(jì)算
59
60 /**
61 * 獲取以此格子坐標(biāo)(x,y)為中心的四個方向的其他格子坐標(biāo)
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坐標(biāo)偶數(shù)時 X坐標(biāo)減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 地圖數(shù)據(jù)
93 * @param begin 起點(diǎn)位置數(shù)據(jù)
94 * @param end 目標(biāo)位置格子坐標(biāo)
95 * @param moveAbility 可移動的格子數(shù)
96 * @param areaNum 所占格子數(shù)
97 * @param isOmit 忽略地形
98 * @return
99 */ public static Object[] findMinTileLine(byte[][]map,SlgNode begin,short[] end,byte moveAbility,byte areaNum,boolean isOmit){
100 //最小格子數(shù)
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 //找出周圍四個格子離目標(biāo)的位置
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移動格子坐標(biāo)數(shù)據(jù)定義
161 * @author Administrator
162 *
163 */
164 public class SlgNode implements Comparable<SlgNode>{
165 //格子坐標(biāo)
166 private short tx;
167 private short ty;
168 //父節(jié)點(diǎn)
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