================================================================================ == KAGE Development Log == ================================================================================ ++ Jan 21, 2010 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ I started coding the game engine again from scratch today, because my existing code is only on my computer at work and I can't get to it right now. Besides, I had coded myself into a corner, as it were, because Perl/Tk has an interesting issue with key press/release events... For non-modifier keys such as arrow keys, if you hold the key down, a Press event is fired for the key... but then, your keyboard's auto-repeat feature kicks in, and Tk sees rapid Release/Press/Release/Press events. In KAGE I worked around it by, on key down it keeps track that the key is being held down, but when the key is released it merely logs the time it was released, using Time::HiRes so we get millisecond values too. Then, after 100 milliseconds pass, if there wasn't another Press event, it accepts that the key was REALLY released this time. This threshold may need to be adjusted down the line after seeing how the arrow keys will work in action, once the engine is able to render the overworld and character movement. What's Done: - Started coding. Have the basic framework put together. - Loads config from runtime package directory (RTP): db/quest.ini - Calls gInit, which makes a Tk MainWindow, passing the title, width & height and bgcolor from quest.ini - Sets the "system clock" for the main loop based off ms speed set in quest.ini - Worked around Tk's keypress/release limitations, so holding down arrow keys works reasonably well. - Visually? You run kagetk.pl and you get a 640x480 black Tk window. The term prints out stuff when you hold and release arrow keys. Escape key terminates the application. - Still nothing really interactive. - New callbacks: - gInit - gDestroy - gMainLoop - gSetTitle - fReadText - New modules: - KAGE - KAGE::Config - KAGE::Frontend - KAGE::GFE::Tk - KAGE::SFE::Null - KAGE::FFE::Direct What's Planned Next: - Integrate Image::Tileset and start loading some tile sets with Tk - Make up a system for representing maps - Get Tk to render the maps - Add config to set how many map tiles should be rendered at a time - Add a character sprite - Let the arrow keys move the character around in the map ++ Jan 22, 2010 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ I did some brainstorming about how to manage the map scrolling as the hero character walks around. There were basically two options I was considering: do it Pokemon-style where the only graphical objects loaded in memory at a time is exactly what you see on your screen, and when you walk, the game loads the next row of tiles off-screen, scrolls the entire screen over until the new row is visible, and then deleting the row that just went off-screen. The other way is to have the entire map in memory at once, and use Tk::Scrolled to scroll the viewport around. Benefits of the Pokemon style: - It's easier to make a seamless overworld, since the game could also load tiles from the edges of neighboring maps when you get near the borders. - It's very light on resources. Drawbacks: - The game would have to forget about actors who go off-screen, so the idea of having any actor be controllable within a map is made more complicated. The game could keep track, in data, of what's going on elsewhere in the map, but it adds a layer of complexity as it needs to determine when an off-screen event should start being shown on screen, etc. Benefits of the Scrolled style: - Just use Tk's built-in scrollbar support - If the scrollbars follow the character around and the character gets close to the edge of the map, the character will stop being in the center of the screen. This is good, and it's just a natural consequence of the fact that scrollbars have limits. They can TRY to follow the character as it walks to the very corner of a map, but the scrollbars can't scroll any further. I've decided to use the scrollbar approach. The map files are an Apache-style config file. There is a block that has basic properties about the map (name, size, background music, wrap- around, etc.), a block that maps named tiles from the tileset to arbitrary codes (in the test map, it maps the tiles to symbols, but these could be mapped to numbers as well). There is a block which surrounds the map data for the bottom (ground) layer. The map data consists of the shortcut codes you made up for the tiles from the block, with each code separated by a space. If a map editor springs up for this, it can generate codes automatically (probably numerically) and the human doesn't have to look at these conf files directly. Things Completed from Last To-Do List: [x] Integrate Image::Tileset and start loading some tile sets with Tk [x] Make up a system for representing maps [x] Get Tk to render the maps [x] Add config to set how many map tiles should be rendered at a time [ ] Add a character sprite [ ] Let the arrow keys move the character around in the map What's New: - Changed the role of the "width" and "height" settings in quest.ini; they are not pixel dimensions of the window anymore, but are the number of tiles to show in the window (in overworld mode, at least). This is currently set to 15x13 tiles. Added a "tilesize" field in quest.ini, set to 32x32, that defines how large the tiles in the tilesets are going to be. - The Tk window is no longer resizable. - Added support for tileset loading. Added a map description file format. The Tk Canvas is able to load and display the map. - The Canvas is now a Scrolled canvas; when a map is loaded, the scroll region on the canvas is set to the dimensions of the rendered map. Currently there are visible scrollbars, but these will be going away shortly. - Using the default main.png tileset from RPG Maker 2003; scaled up the image to have 32x32 pixel tiles instead of 16x16. Will probably be using this tileset for a while to come until everything that has to do with map rendering is completed. - Visually? You run kagetk.pl and get a 480x416 window (15x13 tiles), it shows the loaded test map which features an ocean and two islands connected by a sand bridge, with sand and grass terrain. Scrollbars are visible and you can drag them to see the rest of the map. Tiles are very hard and square; no auto-tiling is implemented yet. - Nothing interactive yet. - New callbacks: - gLoadTile - gLoadMap - fReadBin - New modules: - KAGE::Map What's Planned Next: - Add some basic support for actors. Actors only need to respond to arrow keys to move them around, and they only need basic attributes at this point, including their movement speed. - Add support for the camera to focus on an actor. When an actor gains focus the map should scroll so that the actor is in the center of the map, and the arrow keys should command the actor to move. While the actor travels the camera should smoothly track its movements. - Add support for basic collision detection: grass and sand are OK, but water can't be walked upon. - Add support for auto-tiles. Left Over From Previous To-Do List: - Add a character sprite - Let the arrow keys move the character around in the map * These items are superceded by the actor support. Implementing actors will naturally take care of the above two items. ++ Feb 3, 2010 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ I took a break to figure out the best way to implement actors and camera support. I eventually wrote the "Actors.pod" devel-doc that describes how I plan to implement them. Read that for details. I wrote it before I started programming in the actor system. What's New: - Added actor files in the RTP/actors folder and wrote a hero.act file. - Added a charset for testing my hero.act (it doesn't render in-game yet though) - On init, all actors are loaded, all singletons are scanned through and their respective maps are loaded into memory. - Separated the loading and rendering of maps. Many maps can be in memory at once but only one is rendered visible to the user at a time. - Added a setting in quest.ini to define the default singleton actor who has the focus (the main hero actor). - Hard-coding of loading test.map no longer exists. Now, actors are loaded and maps that have singletons are loaded into memory, and the default singleton from quest.ini gets the focus and its map is rendered visible. - Added preliminary code for the focus model. It only supports shifting focus to a singleton so far, and if the singleton exists on a map that isn't visible, it sets the map visible and renders it. It sets a "$KAGE->{maps}->{focus}" variable to the actor that has the focus. - Added a debug mode keybinding for Tk GUI: Ctrl-D. It dumps the entire $KAGE data structure, and prints it to the terminal as well as to >Dumper.txt - New modules: - KAGE::Actor What's Planned Next: - In the renderMap function, make it also render and place actors. If the rendered actor has focus, scroll the map so that the actor is in the center of the screen. - Start responding to arrow keys finally, by making the focused actor walk to another tile on the map. The camera should track him as he walks. - Support focusing non-singleton actors. - Add a debug mode keybinding, probably Ctrl-A, to pop up a window that lists all actors on all maps; let the user select an actor to switch focus to. ++ Feb 8, 2010 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ I finally got actor support programmed in! The test map renders the hero actor, using its default tile (doesn't yet support default direction for the actor to be facing), identifies it as the focused singleton and adjusts the canvas position to center on the actor. Tk finally sends key events up to Core via cKeyDown/cKeyUp core handlers. Core in turn calls "moveActor()", which takes an actor ID, map ID, map-actor ID, and a direction for the actor to "walk" in (i.e. up, down). This function figures out the X/Y coords (pixels) of the actor, the coords of its destination, and sets a movement flag. The main loop looks for movement flags, lets all actors who have movement, move their "speed" in pixels per loop until they reach their destination. When actors move, Tk gets the gMoveSprite event, telling it the actor ID, map-actor ID, and coordinates (in pixels). Tk identifies the focused actor and adjusts the camera to keep him centered. The engine is finally interactive! No animations yet, but the engine does try to get the actor's graphics for "walking" in all directions; but right now it's hard-coded to s/walk/stand/ so it only shows the non-animated pose for facing each direction. What's New: - GUI renders actors when drawing the map. - Tk identifies the focused actor and adjusts the scroll position to put him in the center of the screen. - Tk sends key press/release events to Core. - Basic support for making actors move from one position to another. - MainLoop adjusts position of actors and informs Tk of their new X/Y coords. What's Planned Next: - Super simple collision detection; don't let the actor walk on water - Restrict the actor's position so he can't walk outside the scrollable area ++ Feb 16, 2010 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Just small tweaks and playing around. Added a new actor called "herodummy", it uses the same graphics as the hero but is not a singleton. Placed a couple of them on the test map. The herodummy actor has a default "facing direction" of "left" and the map correctly renders them facing left. Doing so forced me to fix a few bugs; in a few places the actor's "actor id" was referenced instead of its "map-unique" ID. Changing the focused actor works; I can hard-code it to set the focused actor to "dummy2" in the start() method, which changes the focused actor that was previously set to "hero". Arrow keys move the newly focused "dummy2" actor. When I previously added support for actors to move around, I sorta hacked in a {position} hashref into the actor's data structure, i.e. $self->{maps}->{actors}->{$map_id}->{$auid}->{position}->{moving} = "down"; I've added the default structure for this into Actor.pm just to make it official. I have yet to put in some sort of system of remembering which tiles each actor is on, by tile coordinate. Once this is done, when changing focus to a different actor on the same map, the map should be able to just scroll to follow the new actor. Right now it doesn't remember the coordinates to this actor. What's New: - Added a second actor, and this actor is used twice in the same map (with unique "map-unique IDs" for each instance). - Actors can be drawn facing a default direction. - Changing focus from a singleton to a non-singleton actor works, and the arrow keys control the new actor. However, the map doesn't scroll to center on the new actor until it moves. What's Planned Next: - Try to get animations implemented, at least for the actors' walking movement. Bonus points if I can get the water animated too. * Still everything from the last list * - Super simple collision detection; don't let the actor walk on water. Don't let actors walk on top of other actors, either. - Restrict the actor's position so he can't walk outside the scrollable area ++ Feb 19, 2010 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ A lot of progress has been made! The game keeps track of which "tiles" each actor is placed on, and collision detection between actors works now. In the actor's block there's a new "Solid" option, i.e. "Solid true", which defines whether a fellow actor can intersect the tile that this actor is sitting on. The hero and dummyhero actors have both been set as solid. New collision file format for tileset tiles has been added. These are *.col files that sit beside the *.xml and *.png files in the tileset folder. They have a simple format: they list the tile's IDs (defined in the XML) and describe whether they're solid or not. This will be expanded in the future to support more complicated stuff, like making the tile only be solid along one edge for example, to be able to create cliff edges in the game engine. When an actor wants to move to a new tile, a new "collision" method of KAGE is called to see if anything is sitting on that tile that will prevent the actor from moving there. If so, it returns data about what's there: whether a solid actor is blocking you, or a terrain element (and it will return the layer that the terrain element was on). This will be handy in the future to be able to invoke "on touch" events, for when the hero bumps into another actor or vice versa. I've finally built in the debug mode option to pop up an actor chooser window. Pressing Ctrl-A in-game while debug mode is active will pop up a small actor list window. This window grabs focus from the main window until dismissed, is transient to the main window (so it always stays on top, and loses its minimize button), and is not resizable (so it loses its maximize button too). Pressing escape dismisses this pop-up, as does clicking on one of the actors. Maps in this window are labeled in red, and all actors are buttons. The buttons with blue labels are singleton actors. When changing focus from one actor to another, the map automatically scrolls to center on the new actor, which is an improvement since last time. Finally, I've renamed the main front-end script from "kagetk.pl" to "kage.pl" -- now it accepts command-line options, parsed by KAGE::CLI, where the user can specify whether they want debug mode or choose which front-end modules to use. What's New: - Collision detection between actors and terrain works! Now the actors can't walk on top of each other and they can't walk on water either. Still to do though is prevent actors from walking out of map boundaries, but in the test map they're surrounded by water and can't reach the map boundaries anyway. - Debug window for changing the focused actor, so you can choose and switch actors in-game now and the camera automatically follows each actor as you switch between them. - Collision definition files for tilesets have been added. New Modules: - KAGE::Collision - Parser for the new *.col collision files for tilesets. - KAGE::CLI - A generic module used by front-end scripts that parses the command-line arguments. What's Planned Next: - Don't let actors walk outside map boundaries. - Add a second map, add a singleton to this map, see if switching focus will render the second map. - Add teleportation between maps so that a singleton from map A can walk themselves over to map B. - Add animation support. ++ Mar 5, 2010 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ I've created some new character sprites! There's a naked template sprite set, and some (temporary!) characters with spiky hair and brown/white clothes - they come in the green, blue, and red haired varieties. I eventually want the charset file to include not only walking animations, but also face portraits and other things. The spiky-haired hero type sets are therefore only temporary mock-ups based on the naked template set. The new charsets are 64x32 pixels, instead of 32x32 like the old placeholder charset was, and I was pleased to see that switching to the new dimension was completely painless: everything *just worked*, the character is still anchored by their bottom-left corner and everything works as you'd expect. One small issue is, since the characters are taller than one tile, they'll overlap other actors. So right now when you move an actor above another, the actor on top appears to be standing on top of the face of the actor below; but if the actor moves below another actor, it looks as it should: the lower actor is drawn on top of the upper actor. I'll have to mess with Z-indexes to fix it for the other way around. I've set the dummyhero actor to use the green-haired charset, and I created a new singleton actor named "rival" (red hair), and put him on a new map named "tinyisland". When the game loads, both maps are loaded into memory. I can choose any actor from any map using the Ctrl-A actor selector window. When I focus the rival actor, it successfully erases the hero's map and renders the rival's. When I switch back to an actor on the hero's map, all the actors are as I left them. This is good: even the non-singleton actors' positions are remembered even after the map is unrendered and redrawn. Non-singletons don't lose their info until the map is completely purged from memory (i.e. when all singletons leave the map). Next, for sure, is to add teleporter support, and animations. I'm putting these two things in high priority. After that... text support. That will be fun. What's New: - New charset graphics. - New singleton actor named "rival". - New map named "tinyisland", rival starts on this map. - You can select any actor from any loaded map and it all works how I wanted it to. What's Planned Next: - Still, don't let actors walk outside map boundaries. - Teleporters to send singletons from one map to another.* - Animation support. * When all singletons leave a map, the map should be completely purged from memory. Non-singleton actor positions should be forgotten about.