1 moduletest4.app;
2 3 /*
4 This is a template for creating games with PixelPerfectEngine.
5 Contains some basic setup, but needs further work to be fully featured besides of adding some game logic.
6 7 Feel free to modify this, or even create your own templates (you might want to modularize). Contact me, if you encounter any errors on the way.
8 */9 10 //Some commonly used stuff11 importstd.stdio;
12 importstd.typecons : BitFlags; //This is a good way to create bitflags, so you don't need to keep track of a bunch of boolean values.13 importstd.file : readText;
14 15 importbindbc.sdl; //As of now, this is needed to initialize the SDL API. Might be changed in the future16 //Graphics related imports17 importpixelperfectengine.graphics.outputscreen;//Needed to display the final graphics18 importpixelperfectengine.graphics.raster; //Needed to display layers in order19 importpixelperfectengine.graphics.layers; //Imports all layers and layer-related functionality20 importpixelperfectengine.graphics.bitmap; //Imports bitmaps and all bitmap-related functionality21 //The next two lines imports the collision detector22 importpixelperfectengine.collision.common;
23 importpixelperfectengine.collision.objectcollision;
24 //Various system related imports25 importpixelperfectengine.system.input; //Every game needs some sort of interaction capability, and thus here's the input26 importpixelperfectengine.system.file; //Used to load bitmap and image files27 importpixelperfectengine.system.config; //Needed for configuration files28 importpixelperfectengine.system.common;
29 30 importpixelperfectengine.system.rng; //64 bit LFSR random number generator31 importpixelperfectengine.system.timer; //Low-precision timer for keeping time-based events relatively precise32 //Audio-related imports33 importpixelperfectengine.audio.base.handler; //Most of the basic stuff we will need34 importpixelperfectengine.audio.base.modulebase;//Module interfaces to play back sound effects otherwise not tied to the sequence being played back35 importpixelperfectengine.audio.base.config; //Audio configuration loader and parser36 importpixelperfectengine.audio.base.midiseq; //MIDI sequencer37 //Imports the engine's own map format.38 importpixelperfectengine.map.mapformat;
39 //Other imports that might be important. Uncomment any you feel you'll need.40 /* import pixelperfectengine.system.common; */41 /* import pixelperfectengine.scripting.lua;
42 import pixelperfectengine.scripting.globals; */43 44 45 ///Our main function, needed for the program to operate.46 ///You can add `string[] args` if your either really need or really want.47 intmain() {
48 initialzeSDL(); //Initializes the SDL subsystem, so we will have input and graphics49 initLua();
50 try { //A try-catch block to handle any errors. A bit ugly, but can save us when there's issues with debug symbols, or an error happened outside of a D code51 GameAppapp = newGameApp();
52 app.whereTheMagicHappens();
53 } catch (Throwablee) {
54 writeln(e);
55 debugreadln(); //RemedyBG closes cmd line windows immediately, this stops that.56 }
57 return0;
58 }
59 ///I generally like to put most of the application logic into one class to keep track of globals, as well as targets to certain events.60 publicclassGameApp : SystemEventListener, InputListener {
61 ///Defines various states of the game.62 ///I have added some quite useful and very often used ones63 enumStateFlags {
64 isRunning = 1<<0,
65 pause = 1<<1,
66 mainMenu = 1<<2,
67 }
68 ///Defines various states for the control. Mainly used to avoid effects from typematic and such.69 ///These are the bare minimum requirements for a game.70 enumControlFlags {
71 up = 1<<0,
72 down = 1<<1,
73 left = 1<<2,
74 right = 1<<3,
75 }
76 ///Stores the currently loaded map file with all related data.77 MapFormatmapSource;
78 ///To display our game's graphics79 OutputScreenoutput;
80 ///To manage our layers and palette.81 Rasterrstr;
82 ///For input handling.83 InputHandlerih;
84 ///Detects object collisions that were registered to it.85 ObjectCollisionDetectorocd;
86 ///Contains various game state flags (is it running, is it paused, etc).87 BitFlags!StateFlagsstateFlags;
88 ///Contains various control state flags89 BitFlags!ControlFlagscontrolFlags;
90 ///Contains the pointer to the textlayer.91 ///Can be used for the menu, status bars, etc.92 TileLayertextLayer;
93 ///Contains pointer to the game field, so we can easily interact with it.94 SpriteLayergameField;
95 ///Contains the random number generator and its state.96 //RandomNumberGenerator rng;97 //ConfigurationProfile cfg;98 //Audio related stuff goes here.99 //Note: some of the audio stuff is preliminary. It works, but cannot handle certain cases, such as sample rate mismatches, or device disconnection.100 //Sequencer is untested as of now due to a lack of time and manpower.101 AudioDeviceHandleradh; ///Handles audio devices and outputs.102 ModuleManagermodMan; ///Handles the modules and their output.103 ModuleConfigmodCfg; ///Loads and handles module configuration, including routing, patches, and samples.104 SequencerM1midiSeq;///MIDI sequencer for MIDI playback.105 /* LuaScript scrp; */106 107 /// Initializes our application.108 /// Put other things here if you need them.109 this () {
110 stateFlags.isRunning = true; //Sets the state to running, so the main loop will stay running.111 output = newOutputScreen("Your app name here", 424 * 4, 240 * 4); //Creates an output window with the display size of 1696x960.112 rstr = newRaster(424,240,output,0);//Creates a raster with the size of 424x240.113 output.setMainRaster(rstr); //Sets the main raster of the output screen.114 115 ih = newInputHandler(); //Creates an instance of an InputHandler (should be only one)116 ih.systemEventListener = this; //Sets the system event target to this instance117 ih.inputListener = this; //Sets the input event target to this instance118 119 //ocd = new ObjectCollisionDetector(&onCollision, 0); //Creates an object collision detector120 //Let's create our layer for statuses, etc121 textLayer = newTileLayer(16,16, RenderingMode.Copy); //Creates a TileLayer with 8x8 tiles and alpha blending122 textLayer.paletteOffset = 0; //Sets the palette offset to 512. You might want to change this to the value to the place where you loaded your GUI palette123 textLayer.masterVal = 255; //Sets the master value for the alpha blending, making this layer semi-transparent initially.124 rstr.addLayer(textLayer, 0);
125 gameField = newSpriteLayer();
126 rstr.addLayer(gameField, 16);
127 //cfg = new ConfigurationProfile(); //Creates and loads the configuration profile.128 /* //Comment the next part out, if you're having too much trouble with audio working, since you still can add sound later on.
129 //audio related part begin
130 AudioDeviceHandler.initAudioDriver(OS_PREFERRED_DRIVER); //Initializes the driver
131 AudioSpecs as = AudioSpecs(predefinedFormats[PredefinedFormats.FP32], 48_000, 0, 2, cfg.audioBufferLen,
132 Duration.init); //Sets up a default audio specification
133 adh = new AudioDeviceHandler(as, 1024, 1024 / 128); //Creates a new AudioDeviceHandler and sets up the basics
134 adh.initAudioDevice(-1); //Initializes the default device
135 modMan = new ModuleManager(adh); //Initializes the module manager
136 modCfg = new ModuleConfig(modMan); //Initializes the module configurator
137 modCfg.loadConfigFromFile("../assets/test4_audio.sdl");//This line loads an audio configuration file (make sure you have a valid one - create one with the ADK/test1!)
138 modCfg.compile(false); //Compiles the current module configuration.
139 midiSeq = new SequencerM1(modMan.moduleList, modCfg.midiRouting, modCfg.midiGroups);
140 modMan.runAudioThread(); //Runs the audio thread.
141 //audio related part end
142 */143 textLayer.loadMapping(32, 16, newMappingElement[](32*16));
144 145 //<Put other initialization code here>146 mainRaster = rstr;
147 {
148 ImagedlangMan = loadImage(File("../assets/d-man.tga"));
149 scrptResMan["dlangman"] = loadBitmapFromImage!Bitmap8Bit(dlangMan);
150 rstr.loadPaletteChunk(loadPaletteFromImage(dlangMan),0);
151 Imagekumapu = loadImage(File("../assets/kumapu.png"));
152 textLayer.addTile(loadBitmapFromImage!Bitmap32Bit(kumapu), 0x0000);
153 }
154 for (inty ; y < 16 ; y++) {
155 for (intx ; x < 32 ; x++) {
156 textLayer.writeMapping(x, y, MappingElement(0x0000));
157 }
158 }
159 /* scrp = new LuaScript(readText("../assets/test4.lua"), "test4.lua"); */160 //scrp.runMain();161 //scrp.callFunction("Initialize");162 }
163 voidwhereTheMagicHappens() {
164 while (stateFlags.isRunning) {
165 //Refreshes the raster, then sends the new image to the output window.166 rstr.refresh();
167 //Tests the input devices for events.168 ih.test();
169 /* scrp.callFunction("UpdateFunc"); */170 //Tests the timer for any registered events that are to happen.171 //Note: You can put this call into a separate thread for more precision.172 timer.test();
173 //Calling the RNG for every frame will make it less deterministic. Speed runners might hate you for this.174 //rng();175 //This calls the collision detector on all registered objects.176 //You'll want to only call it on moving objects, especially when you have a lot of objects on screen.177 //ocd.testAll();178 179 //<Per-frame code comes here>180 }
181 //scrp.deinit();182 }
183 ///This function will load a map file to display levels, or portions of levels.184 ///If you're clever, you can store other things in map files185 voidloadMap(stringm) {
186 //This loop removes all previously loaded layers from the raster.187 foreach (key, elem; mapSource.layeroutput) {
188 rstr.removeLayer(key);
189 }
190 mapSource = newMapFormat(File(m)); //Loads the map file itself, and parses it.191 mapSource.loadTiles(rstr); //Loads the tiles with the palettes needed to display them.192 mapSource.loadAllSpritesAndObjects(rstr, ocd); //Loads all sprites and objects to the layers, and the collision detector. Also loads the palettes for the sprites193 mapSource.loadMappingData(); //Loads all mapping data to the tilelayers.194 rstr.loadLayers(mapSource.layeroutput); //Adds the layers to the raster for display.195 //Stores a reference to the gamefield.196 //Change the index number if you want.197 gameField = cast(SpriteLayer)(mapSource.layeroutput[16]);
198 }
199 ///Collision events can be handled from here.200 publicvoidonCollision(ObjectCollisionEventevent) {
201 202 }
203 ///Called if the window is closed, etd.204 publicvoidonQuit() {
205 //You might want to put here a more complicated prompt instead.206 stateFlags.isRunning = false;
207 }
208 ///Called when a controller is added to the system.209 ///Note: This function will be changed once I move input handling and output screen handling to iota.210 publicvoidcontrollerAdded(uintid) {
211 212 }
213 ///Called when a controller is removed the system.214 ///Note: This function will be changed once I move input handling and output screen handling to iota.215 publicvoidcontrollerRemoved(uintid) {
216 217 }
218 ///Called if a key input event has occured.219 ///Note: This function will be changed once I move input handling and output screen handling to iota.220 publicvoidkeyEvent(uintid, BindingCodecode, uinttimestamp, boolisPressed) {
221 222 }
223 ///Called if an axis input event has occured.224 ///Note: This function will be changed once I move input handling and output screen handling to iota.225 publicvoidaxisEvent(uintid, BindingCodecode, uinttimestamp, floatvalue) {
226 227 }
228 }