1 /// contains the tile map object class 2 module ysge.objects.tileMap; 3 4 import std.math; 5 import ysge.project; 6 7 struct Tile { 8 int id; 9 10 this(int pid) { 11 id = pid; 12 } 13 } 14 15 struct TileDef { 16 RenderType renderType; 17 RenderValue render; 18 bool hasCollision; 19 } 20 21 /// tile map object with fast AABB collision 22 class TileMap : GameObject { 23 Tile*[][] tiles; 24 Vec2!int tileSize; 25 TileDef[int] tileDefs; 26 Vec2!int pos; 27 28 /// initialises the tile map 29 this(Vec2!ulong size) { 30 tiles = new Tile*[][](size.y, size.x); 31 32 foreach (ref line ; tiles) { 33 foreach (ref tile ; line) { 34 tile = new Tile(0); 35 } 36 } 37 } 38 39 /// loads tiles from a 2d array of tile ids 40 void FromIDs(int[][] ids) { 41 foreach (i, ref line ; ids) { 42 foreach (j, ref tile ; line) { 43 tiles[i][j] = new Tile(tile); 44 } 45 } 46 } 47 48 /** 49 * updates the tile map 50 * should not be called by user 51 */ 52 override void Update(Project parent) { 53 54 } 55 56 /** 57 * checks collision with fast AABB 58 * should not be called by user 59 */ 60 override bool CollidesWith(SimpleBox other) { 61 Vec2!int posOnMap = Vec2!int(other.box.x, other.box.y); 62 posOnMap.x -= pos.x; 63 posOnMap.y -= pos.y; 64 65 Vec2!int start = Vec2!int( 66 cast(int) floor(posOnMap.CastTo!float().x / tileSize.x), 67 cast(int) floor(posOnMap.CastTo!float().y / tileSize.y) 68 ); 69 Vec2!int end = Vec2!int( 70 cast(int) ceil(posOnMap.CastTo!float().x / tileSize.x), 71 cast(int) ceil(posOnMap.CastTo!float().y / tileSize.y) 72 ); 73 74 Vec2!int otherSize = Vec2!int(other.box.w, other.box.h); 75 76 end.x += cast(int) ceil(otherSize.CastTo!float().x / tileSize.x); 77 end.y += cast(int) ceil(otherSize.CastTo!float().y / tileSize.y); 78 79 for (int y = start.y; y <= end.y; ++ y) { 80 for (int x = start.x; x <= end.x; ++ x) { 81 if ( 82 (y < 0) || 83 (x < 0) || 84 (y >= tiles.length) || 85 (x >= tiles[0].length) 86 ) { 87 continue; 88 } 89 90 auto tile = tiles[y][x]; 91 auto def = tileDefs[tile.id]; 92 93 if (!def.hasCollision) { 94 continue; 95 } 96 97 SDL_Rect box; 98 box.x = x * tileSize.x; 99 box.y = y * tileSize.y; 100 box.w = tileSize.x; 101 box.h = tileSize.y; 102 103 if ( 104 (box.x < other.box.x + other.box.w) && 105 (box.x + box.w > other.box.x) && 106 (box.y < other.box.y + other.box.h) && 107 (box.y + box.h > other.box.y) 108 ) { 109 return true; 110 } 111 } 112 } 113 114 return false; 115 } 116 117 /** 118 * renders the object 119 * should not be called by user 120 */ 121 override void Render(Project parent) { 122 Vec2!int start = Vec2!int( 123 pos.x - parent.currentScene.camera.x, 124 pos.y - parent.currentScene.camera.y 125 ); 126 127 for (int y = 0; y < tiles.length; ++ y) { 128 for (int x = 0; x < tiles[0].length; ++ x) { 129 Vec2!int tilePos = Vec2!int( 130 start.x + (x * tileSize.x), 131 start.y + (y * tileSize.y) 132 ); 133 Vec2!int tileEnd = Vec2!int( 134 tilePos.x + tileSize.x, 135 tilePos.y + tileSize.y 136 ); 137 138 auto res = parent.GetResolution(); 139 140 if ( 141 (tileEnd.x < 0) || 142 (tileEnd.y < 0) 143 ) { 144 continue; 145 } 146 147 if ( 148 (tilePos.x > res.x) || 149 (tilePos.y > res.y) 150 ) { 151 break; 152 } 153 154 auto tile = tiles[y][x]; 155 auto def = tileDefs[tile.id]; 156 auto rect = SDL_Rect( 157 tilePos.x, tilePos.y, tileSize.x, tileSize.y 158 ); 159 160 switch (def.renderType) { 161 case RenderType.Colour: { 162 if (def.render.colour.a == 0) { 163 break; 164 } 165 166 SDL_SetRenderDrawColor( 167 parent.renderer, 168 def.render.colour.r, 169 def.render.colour.g, 170 def.render.colour.b, 171 def.render.colour.a 172 ); 173 SDL_RenderFillRect(parent.renderer, &rect); 174 break; 175 } 176 case RenderType.Texture: { 177 SDL_RenderCopy( 178 parent.renderer, def.render.texture, null, &rect 179 ); 180 break; 181 } 182 default: assert(0); 183 } 184 } 185 } 186 } 187 }