1 module example.gamemap;
2 version(GAMEEXAMPLE){
3 
4 import nudsfml.graphics;
5 
6 import std.algorithm;
7 import std.conv;
8 import std.string;
9 import std.format;
10 
11 import gameentity;
12 
13 enum TileTypes {
14     None = -1,
15     Floor = 0,
16     Wall = 1,
17     WallShadow = 2,
18 }
19 
20 struct Tile {
21     int id;
22     int type = TileTypes.None;
23     Vector2f offset;
24     Vector2f pos;
25 }
26 
27 class GameMap {
28     Tile [] tiles;
29     IntRect [] tileRects;
30 
31     int width; 
32     int height;
33     int gridWidth;
34     int gridHeight;
35     int tileWidth;
36     int tileHeight;
37 
38     float frameChange =  1f / 15f;
39     float currentFrame = 0f;
40     int currentFrameIndex = 0;
41     int currentMaxFrameIndex = 30;
42 
43     Entity [] entities;
44 
45     Texture tex;
46 
47     AppleEntity addApple(int x, int y) {
48         AppleEntity apple = new AppleEntity(tex);
49         apple.mapLocation = Vector2i(x, y);
50         apple.position = Vector2f(x*gridWidth, y*gridHeight);
51         entities ~= apple;
52         sortEntities();
53         return apple;
54     }
55 
56     void addSnake(ref SnakeEntity snakepart){
57         entities ~= snakepart;
58         sortEntities();
59     }
60 
61     void sortEntities() {
62         entities.sort!((a,b) => a.position.y < b.position.y);
63     }
64 
65     void  update(float deltaTime){
66         foreach(ref entity; entities) {
67             entity.update(deltaTime);
68         }
69         currentFrame += deltaTime;;
70         if(currentFrame > frameChange){
71             currentFrame = 0f;
72             currentFrameIndex++;
73             if(currentFrameIndex > currentMaxFrameIndex){
74                 currentFrameIndex = 0;
75             }
76 
77         }
78     }
79 
80 
81 
82     enum Direction {
83         Up = 1,
84         Right = 2,
85         Down = 4,
86         Left = 8
87     }
88 
89 
90 
91     this(){
92         width = 32;
93         height = 24;
94         gridWidth = 32;
95         gridHeight = 32;
96         tileWidth = 32;
97         tileHeight = 48;
98 
99         tiles.length = (width * height *2);
100 
101         for (int y = 0; y < 4; y++){
102             for (int x = 0; x < 16; x++){
103                 tileRects ~= IntRect(x * tileWidth, y * tileHeight, tileWidth, tileHeight);
104             }
105         }
106 
107         tex = new Texture;
108         tex.loadFromFile("data/snaketiles.png");
109 
110         createMap();
111     }
112 
113     int getIndex(int x, int y, int layer = 0){
114         int index = (layer * width * height) + (y * width) + x;
115 
116         if ( index < 0 || index > (width * height * 2)){
117             return -1;
118         }
119         return index;
120     }
121 
122     void createMap(){
123         for(int i = 0; i < width; i++){
124             for(int j = 0; j < height; j++){
125                 if(i == 0 || i == width - 1 || j == 0 || j == height - 1){
126                     tiles[i + j * width].type = TileTypes.Wall;
127                 }
128                 else{
129                     tiles[i + j * width].type = TileTypes.Floor;
130                 }
131                 getTile(i,j).pos = Vector2f(i * gridWidth,j * gridHeight);
132                 getTile(i, j).offset = Vector2f(0,-16);
133             }
134         }
135 
136         calcWallIndexes();
137         calcWallShadows();
138 
139 
140     }
141 
142     void calcWallShadows(){
143         //calc shadows 
144         for(int y = 1 ; y < height; y++){
145             for(int x = 0; x < width; x++){
146                 int index = getIndex(x,y - 1);
147                 if(tiles[index].type == TileTypes.Wall && tiles[getIndex(x,y)].type == TileTypes.Floor){
148                     tiles[getIndex(x,y,1)].id = 16*3+1; // using magic numbers
149                     tiles[getIndex(x,y,1)].type = TileTypes.WallShadow;
150                 } else {
151                     tiles[getIndex(x,y,1)].type = TileTypes.None;
152                     tiles[getIndex(x,y,1)].offset =  Vector2f(0,-16);
153                 }
154             }
155         }
156     }
157 
158 
159 
160     void calcWallIndexes(){
161         //convert forloop to a function to make it easier to read
162         for(int y = 0 ; y < height; y++){
163             for(int x = 0; x < width; x++){
164                 int index = getIndex(x,y);
165                 if(tiles[index].type == TileTypes.Wall){
166                     tiles[index].id = 0 + calcTileNeighbors(x,y);
167                 } else {
168                     tiles[index].id = 32; // + random_number(0,3);
169                 }
170             }
171         }
172     }
173 
174     int addToTileset(IntRect rect) {
175         int id =  tileRects.length.to!int;
176         tileRects ~= rect;
177 
178         return id;
179     }
180 
181     int calcTileNeighbors(int x, int y) {
182         int neighbors = 0;
183         auto t = getTile(x,y);
184         if (x > 0) {
185             if (getTile(x - 1, y).type == t.type) {
186                 neighbors += Direction.Left;
187             }
188         }
189         if (x < width - 1) {
190             if (getTile(x + 1, y).type == t.type) {
191                 neighbors += Direction.Right;
192             }
193         }
194         if (y > 0) {
195             if (getTile(x, y - 1).type == t.type) {
196                 neighbors += Direction.Up;
197             }
198         }
199         if (y < height - 1) {
200             if (getTile(x,y + 1).type == t.type)  {
201                 neighbors += Direction.Down;
202             }
203         }
204         return neighbors;
205     }
206 
207     ref Tile getTile(int x, int y) {
208         return tiles[x + y * width];
209     }
210 
211     void draw(Vector2f pos, RenderTarget target) {
212         import std.stdio;
213         RectangleShape rect = new RectangleShape();
214         rect.fillColor = Color.White;
215         rect.size = Vector2f(tileWidth, tileHeight);
216         rect.setTexture(tex);
217         int entityIndex = 0;
218         for (int y = 0; y < height; y++) {
219             for (int x = 0; x < width; x++) {
220                 for(int l = 0; l < 2; l++){
221                     int index = getIndex(x,y,l);
222                     if(tiles[index].type != TileTypes.None){
223                         rect.position = pos  + Vector2f(gridWidth * x, gridHeight * y ) + tiles[index].offset;
224 
225                         rect.textureRect = tileRects[tiles[index].id];
226                         target.draw(rect);
227                     }
228                 }
229             }
230             //writeln("Y: ", y);
231             if (entityIndex < entities.length ) {
232                 while (entities[entityIndex].position.y < ((y - 1) * gridHeight)) {
233                    // writeln(format("%d pos(%f,%f)", entityIndex, entities[entityIndex].position.x, entities[entityIndex].position.y));
234                     entities[entityIndex].draw(target);
235                     entityIndex++;
236                     if(entityIndex >= entities.length){
237                         break;
238                     }
239                 }
240             }   
241         }
242     }
243 }
244 }