1 /// main YSGE module containing everything you need to make a game 2 module ysge.project; 3 4 import std.file; 5 import std.path; 6 import std.string; 7 8 public import bindbc.sdl; 9 public import ysge.util; 10 public import ysge.scene; 11 public import ysge.types; 12 public import ysge.uiBase; 13 public import ysge.texture; 14 public import ysge.animation; 15 public import ysge.gameObject; 16 public import ysge.objects.simpleBox; 17 18 /// used when something goes wrong in the project 19 class ProjectException : Exception { 20 this(string msg, string file = __FILE__, size_t line = __LINE__) { 21 super(msg, file, line); 22 } 23 } 24 25 /// main project class used for the game as a whole 26 class Project { 27 bool running; /// while true, update functions are called 28 SDL_Window* window; 29 SDL_Renderer* renderer; 30 TTF_Font* font; 31 Scene[] scenes; 32 Scene currentScene; 33 bool usingLogicalRes; /// DON'T MODIFY!!!! 34 Vec2!int logicalRes; /// DON'T MODIFY!!!! 35 Vec2!int mousePos; 36 ulong frames; /// how many frames have passed since the game was started 37 38 this() { 39 40 } 41 42 ~this() { 43 if (window) { 44 SDL_DestroyWindow(window); 45 } 46 if (renderer) { 47 SDL_DestroyRenderer(renderer); 48 } 49 SDL_Quit(); 50 } 51 52 /// called once at the start 53 abstract void Init(); 54 55 /// creates the window 56 void InitWindow(string name, int w, int h, bool resizable) { 57 SDLSupport support; 58 59 version (Windows) { 60 support = loadSDL(cast(char*) (dirName(thisExePath()) ~ "/sdl2.dll")); 61 } 62 else { 63 support = loadSDL(); 64 } 65 66 if (support != sdlSupport) { 67 throw new ProjectException("Failed to load SDL"); 68 } 69 70 int flags = 0; 71 72 if (resizable) { 73 flags |= SDL_WINDOW_RESIZABLE; 74 } 75 76 window = SDL_CreateWindow( 77 toStringz(name), SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, 78 w, h, flags 79 ); 80 81 if (window is null) { 82 throw new ProjectException("Failed to create window"); 83 } 84 85 renderer = SDL_CreateRenderer( 86 window, -1, SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC 87 ); 88 89 if (renderer is null) { 90 throw new ProjectException("Failed to create renderer"); 91 } 92 } 93 94 /// initialises the text library 95 void InitLibs() { 96 // SDL_TTF 97 SDLTTFSupport supportTTF; 98 99 version (Windows) { 100 supportTTF = loadSDLTTF( 101 cast(char*) (dirName(thisExePath()) ~ "/sdl2_ttf.dll") 102 ); 103 } 104 else { 105 supportTTF = loadSDLTTF(); 106 } 107 108 if (supportTTF < SDLTTFSupport.v2_0_12) { 109 throw new ProjectException("Failed to load SDL_TTF library"); 110 } 111 112 if (TTF_Init() < 0) { 113 throw new ProjectException("Failed to initialise SDL_TTF"); 114 } 115 116 // SDL_Image 117 auto supportIMG = loadSDLImage(); 118 119 if (supportIMG < SDLImageSupport.v2_0_0) { 120 throw new ProjectException("Failed to load SDL_Image library"); 121 } 122 123 int imgFlags = IMG_INIT_PNG; 124 if (IMG_Init(imgFlags) != imgFlags) { 125 throw new ProjectException("Failed to initialise SDL_Image"); 126 } 127 } 128 129 void LoadFontFile(string path, int pointSize) { 130 font = TTF_OpenFont(toStringz(path), pointSize); 131 132 if (font is null) { 133 throw new ProjectException("Failed to load font"); 134 } 135 } 136 137 void LoadFontData(ubyte[] data) { 138 auto rw = SDL_RWFromMem(data.ptr, cast(int) data.length); 139 font = TTF_OpenFontRW(rw, 1, 16); 140 141 if (font is null) { 142 throw new ProjectException("Failed to load font"); 143 } 144 } 145 146 /// gets the resolution of the window 147 Vec2!int GetResolution() { 148 if (usingLogicalRes) { 149 return logicalRes; 150 } 151 else { 152 Vec2!int ret; 153 154 SDL_GetWindowSize(window, &ret.x, &ret.y); 155 156 return ret; 157 } 158 } 159 160 /// sets the logical resolution of the window 161 void SetResolution(uint w, uint h) { 162 SDL_RenderSetLogicalSize(renderer, w, h); 163 usingLogicalRes = true; 164 logicalRes = Vec2!int(w, h); 165 } 166 167 /// sets window size 168 void SetWindowSize(uint w, uint h) { 169 SDL_SetWindowSize(window, cast(int) w, cast(int) h); 170 } 171 172 /// gets the directory the game executable is in 173 string GetGameDirectory() { 174 return dirName(thisExePath()); 175 } 176 177 /// checks if a key is pressed 178 bool KeyPressed(SDL_Scancode key) { 179 auto keys = SDL_GetKeyboardState(null); 180 181 return keys[key]? true : false; 182 } 183 184 /// adds a scene to the project scene array 185 void AddScene(Scene scene) { 186 scenes ~= scene; 187 } 188 189 /// sets the current scene to a scene from the project scene array 190 void SetScene(Scene scene) { 191 currentScene = scene; 192 currentScene.Setup(); 193 currentScene.Init(this); 194 } 195 196 /// sets the current scene to a scene from the project scene array 197 void SetScene(size_t index) { 198 currentScene = scenes[index]; 199 currentScene.Setup(); 200 currentScene.Init(this); 201 } 202 203 /// loads a texture from a file 204 Texture LoadTextureFromFile(string fileName) { 205 auto surface = IMG_Load(cast(char*) fileName.toStringz()); 206 207 if (surface is null) { 208 throw new ProjectException("Failed to load texture"); 209 } 210 211 auto texture = SDL_CreateTextureFromSurface(renderer, surface); 212 213 if (texture is null) { 214 throw new ProjectException("Failed to load texture"); 215 } 216 217 return new Texture(texture); 218 } 219 220 /// loads a texture from raw file data 221 Texture LoadTextureFromData(ref ubyte[] data) { 222 auto rw = SDL_RWFromMem(data.ptr, cast(int) data.length); 223 auto surface = IMG_Load_RW(rw, 1); 224 225 if (surface is null) { 226 throw new ProjectException("Failed to load texture"); 227 } 228 229 auto texture = SDL_CreateTextureFromSurface(renderer, surface); 230 231 if (texture is null) { 232 throw new ProjectException("Failed to load texture"); 233 } 234 235 return new Texture(texture); 236 } 237 238 /// runs the game 239 void Run() { 240 running = true; 241 Init(); 242 243 if (currentScene is null) { 244 throw new ProjectException("Scene not set"); 245 } 246 247 if (font is null) { 248 throw new ProjectException("Font not loaded"); 249 } 250 251 while (running) { 252 ++ frames; 253 254 currentScene.animations.Update(this, currentScene); 255 currentScene.UpdateObjects(this); 256 currentScene.Update(this); 257 currentScene.UpdateCamera(this); 258 currentScene.Render(this); 259 260 SDL_Event e; 261 while (SDL_PollEvent(&e)) { 262 switch (e.type) { 263 case SDL_QUIT: { 264 running = false; 265 return; 266 } 267 case SDL_MOUSEMOTION: { 268 mousePos = Vec2!int(e.motion.x, e.motion.y); 269 break; 270 } 271 default: { 272 if (currentScene.HandleUIEvent(this, e)) { 273 continue; 274 } 275 276 currentScene.HandleEvent(this, e); 277 break; 278 } 279 } 280 } 281 } 282 } 283 }