|
1 /* |
|
2 * Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies). |
|
3 * All rights reserved. |
|
4 * This component and the accompanying materials are made available |
|
5 * under the terms of "Eclipse Public License v1.0" |
|
6 * which accompanies this distribution, and is available |
|
7 * at the URL "http://www.eclipse.org/legal/epl-v10.html". |
|
8 * |
|
9 * Initial Contributors: |
|
10 * Nokia Corporation - initial contribution. |
|
11 * |
|
12 * Contributors: |
|
13 * |
|
14 * Description: |
|
15 * |
|
16 */ |
|
17 package javax.microedition.lcdui.game; |
|
18 |
|
19 import javax.microedition.lcdui.Graphics; |
|
20 import javax.microedition.lcdui.Image; |
|
21 |
|
22 public class TiledLayer extends Layer { |
|
23 |
|
24 // Animated tile array increment |
|
25 private static final int ANIM_ARRAY_INCREMENT = 4; |
|
26 |
|
27 private int rows; |
|
28 private int cols; |
|
29 |
|
30 private int[][] cells; |
|
31 private int[] animArray; |
|
32 private int animCount; |
|
33 |
|
34 public TiledLayer(int cols, int rows, Image tileImage, int tileWidth, int tileHeight) { |
|
35 super(tileImage, tileWidth, tileHeight); |
|
36 |
|
37 if (cols < 1 || rows < 1) { |
|
38 throw new IllegalArgumentException( |
|
39 MsgRepository.TILEDLAYER_EXCEPTION_INVALID_DIMENSIONS); |
|
40 } |
|
41 |
|
42 this.cols = cols; |
|
43 this.rows = rows; |
|
44 cells = new int[rows][cols]; |
|
45 animArray = new int[ANIM_ARRAY_INCREMENT]; |
|
46 animCount = 0; |
|
47 } |
|
48 |
|
49 public void setStaticTileSet(Image tileImage, int tileWidth, int tileHeight) { |
|
50 final int oldTileCount = tileCount; |
|
51 |
|
52 setTileImage(tileImage, tileWidth, tileHeight); |
|
53 |
|
54 // If the new static tile set has as many or more tiles, then the |
|
55 // animated tiles and cell contents will be preserved. |
|
56 // If not, the contents of the grid will be cleared (all cells will |
|
57 // contain index 0) and all animated tiles will be deleted. |
|
58 // |
|
59 if (tileCount < oldTileCount) { |
|
60 fillCells(0, 0, cols, rows, 0); |
|
61 animCount = 0; |
|
62 } |
|
63 } |
|
64 |
|
65 public void setCell(int col, int row, int aTileIndex) { |
|
66 validateTileIndex(aTileIndex); |
|
67 cells[row][col] = aTileIndex; |
|
68 } |
|
69 |
|
70 public int getCell(int col, int row) { |
|
71 return cells[row][col]; |
|
72 } |
|
73 |
|
74 public void fillCells(int col, int row, int numCols, int numRows, int tileIndex) { |
|
75 if (numCols < 0) { |
|
76 throw new IllegalArgumentException( |
|
77 MsgRepository.TILEDLAYER_EXCEPTION_INVALID_NUMBER_OF_COLUMNS); |
|
78 } |
|
79 if (numRows < 0) { |
|
80 throw new IllegalArgumentException( |
|
81 MsgRepository.TILEDLAYER_EXCEPTION_INVALID_NUMBER_OF_ROWS); |
|
82 } |
|
83 validateTileIndex(tileIndex); |
|
84 |
|
85 for (int i = col + numCols; --i >= col;) { |
|
86 cells[row][i] = tileIndex; |
|
87 } |
|
88 for (int i = row + numRows; --i > row;) { |
|
89 System.arraycopy(cells[row], col, cells[i], col, numCols); |
|
90 } |
|
91 } |
|
92 |
|
93 public int createAnimatedTile(int tileIndex) { |
|
94 if (tileIndex < 0 || tileIndex > tileCount) { |
|
95 throw new IndexOutOfBoundsException( |
|
96 MsgRepository.TILEDLAYER_EXCEPTION_INVALID_TILE_INDEX); |
|
97 } |
|
98 |
|
99 final int index = animCount; |
|
100 checkCapacity(index + 1); |
|
101 animArray[index] = tileIndex; |
|
102 animCount++; |
|
103 return ~index; |
|
104 } |
|
105 |
|
106 /** |
|
107 * Grows the animated tile array if required. |
|
108 */ |
|
109 private void checkCapacity(int requiredLength) { |
|
110 int length = animArray.length; |
|
111 if (requiredLength > length) { |
|
112 int[] array = new int[length + ANIM_ARRAY_INCREMENT]; |
|
113 System.arraycopy(animArray, 0, array, 0, length); |
|
114 animArray = array; |
|
115 } |
|
116 } |
|
117 |
|
118 public void setAnimatedTile(int animIndex, int tileIndex) { |
|
119 final int index = ~animIndex; |
|
120 if (index >= animCount) { |
|
121 throw new IndexOutOfBoundsException( |
|
122 MsgRepository.TILEDLAYER_EXCEPTION_INVALID_ANIMTILE_INDEX); |
|
123 } |
|
124 if (tileIndex < 0 || tileIndex > tileCount) { |
|
125 throw new IndexOutOfBoundsException( |
|
126 MsgRepository.TILEDLAYER_EXCEPTION_INVALID_TILE_INDEX); |
|
127 } |
|
128 animArray[index] = tileIndex; |
|
129 } |
|
130 |
|
131 public int getAnimatedTile(int animIndex) { |
|
132 final int index = ~animIndex; |
|
133 if (index >= animCount) { |
|
134 throw new IndexOutOfBoundsException( |
|
135 MsgRepository.TILEDLAYER_EXCEPTION_INVALID_ANIMTILE_INDEX); |
|
136 } |
|
137 return animArray[index]; |
|
138 } |
|
139 |
|
140 public final int getCellWidth() { |
|
141 return tileWidth; |
|
142 } |
|
143 |
|
144 public final int getCellHeight() { |
|
145 return tileHeight; |
|
146 } |
|
147 |
|
148 public final int getColumns() { |
|
149 return cols; |
|
150 } |
|
151 |
|
152 public final int getRows() { |
|
153 return rows; |
|
154 } |
|
155 |
|
156 public final void paint(Graphics aGraphics) { |
|
157 if (visible) { |
|
158 aGraphics.translate(x, y); |
|
159 |
|
160 int clipX1 = aGraphics.getClipX(); |
|
161 int clipY1 = aGraphics.getClipY(); |
|
162 int clipX2 = clipX1 + aGraphics.getClipWidth(); |
|
163 int clipY2 = clipY1 + aGraphics.getClipHeight(); |
|
164 |
|
165 final int tw = tileWidth; |
|
166 final int th = tileHeight; |
|
167 final int lw = getWidth(); // layer width |
|
168 final int lh = getHeight(); // layer height |
|
169 |
|
170 clipX1 = (clipX1 < 0 ? 0 : clipX1); |
|
171 clipY1 = (clipY1 < 0 ? 0 : clipY1); |
|
172 clipX2 = (clipX2 > lw ? lw : clipX2); |
|
173 clipY2 = (clipY2 > lh ? lh : clipY2); |
|
174 |
|
175 final int begRow = clipY1 / tileHeight; |
|
176 final int begCol = clipX1 / tileWidth; |
|
177 final int endRow = (clipY2 - 1) / tileHeight; |
|
178 final int endCol = (clipX2 - 1) / tileWidth; |
|
179 |
|
180 int sx = begRow * th; |
|
181 int sy = begCol * tw; |
|
182 int dx; |
|
183 int dy; |
|
184 |
|
185 for (int row = begRow; row <= endRow; row++) { |
|
186 for (int col = begCol; col <= endCol; col++) { |
|
187 final int index = validateTileIndex(cells[row][col]); |
|
188 if (index >= 0) { |
|
189 // Future performace improvement suggestion: accumulate |
|
190 // region |
|
191 // |
|
192 // We have a visible tile in the clip rect, if its |
|
193 // bounding rect is disjoint from our accumulated rect, |
|
194 // we draw what we have accumulated so far and reset our |
|
195 // accumulation rect, else we just add this tile to the |
|
196 // accumulation rect. |
|
197 // |
|
198 // This helps with the not totally uncommon case of |
|
199 // cells in the tiled layer containing adjacent tiles |
|
200 // from the tile image. Accumulating the tiles turns |
|
201 // multiple bitblt's into a single bitblt, saving a bit |
|
202 // on setup/teardown/data transfer. |
|
203 |
|
204 dx = col * tw; |
|
205 dy = row * th; |
|
206 |
|
207 int tr = index / tileColumns; |
|
208 int tc = index % tileColumns; |
|
209 |
|
210 sx = tc * tw; |
|
211 sy = tr * th; |
|
212 |
|
213 aGraphics.drawRegion(tileImage, |
|
214 sx, sy, |
|
215 tw, th, |
|
216 Sprite.TRANS_NONE, |
|
217 dx, dy, 0); |
|
218 } |
|
219 } |
|
220 } |
|
221 |
|
222 aGraphics.translate(-x, -y); |
|
223 } |
|
224 } |
|
225 |
|
226 private int validateTileIndex(int tileIndex) { |
|
227 if (tileIndex > tileCount) { |
|
228 throw new IndexOutOfBoundsException( |
|
229 MsgRepository.TILEDLAYER_EXCEPTION_INVALID_TILE_INDEX); |
|
230 } |
|
231 // check createAnimatedTile has been called, getAnimatedTile will throw |
|
232 // exception if hasn't. |
|
233 if (tileIndex < 0) { |
|
234 tileIndex = getAnimatedTile(tileIndex); |
|
235 } |
|
236 return tileIndex - 1; |
|
237 } |
|
238 |
|
239 boolean collidesCell(int aX1, int aY1, int aX2, int aY2) { |
|
240 // tiled layer rect in painter's coordinates |
|
241 int tlX1 = x; |
|
242 int tlY1 = y; |
|
243 int tlX2 = x + getWidth(); |
|
244 int tlY2 = y + getHeight(); |
|
245 |
|
246 // compute intersection of TiledLayer bounds and sprite collision |
|
247 // rectangle. |
|
248 tlX1 = Math.max(tlX1, aX1); |
|
249 tlY1 = Math.max(tlY1, aY1); |
|
250 tlX2 = Math.min(tlX2, aX2); |
|
251 tlY2 = Math.min(tlY2, aY2); |
|
252 |
|
253 // return false if empty intersection. |
|
254 if (!((tlX1 < tlX2) && (tlY1 < tlY2))) { |
|
255 return false; |
|
256 } |
|
257 |
|
258 // transform to tiled layer coordinates |
|
259 tlX1 -= x; |
|
260 tlY1 -= y; |
|
261 tlX2 -= x; |
|
262 tlY2 -= y; |
|
263 |
|
264 int startRow = (tlY1 / tileHeight); |
|
265 int startCol = (tlX1 / tileWidth); |
|
266 int endRow = (tlY2 - 1) / tileHeight; |
|
267 int endCol = (tlX2 - 1) / tileWidth; |
|
268 |
|
269 for (int row = startRow; row <= endRow; row++) { |
|
270 for (int col = startCol; col <= endCol; col++) { |
|
271 if (cells[row][col] != 0) { |
|
272 // at least one cell is not empty |
|
273 return true; |
|
274 } |
|
275 } |
|
276 } |
|
277 |
|
278 // all cells in overlap are empty |
|
279 return false; |
|
280 } |
|
281 |
|
282 int getLayerWidth() { |
|
283 return cols * tileWidth; |
|
284 } |
|
285 |
|
286 int getLayerHeight() { |
|
287 return rows * tileHeight; |
|
288 } |
|
289 } |