Jump to content

Sakura Engine


Antidote
 Share

Recommended Posts

It's still VERY much WIP (considering i started writing it last night) but the basics are in place, all that's needed is a widget system, bitmap font class, and all the Zelda trappings :D

 

 

Posted Image

 

 

Currently the Octorok just chases Link around and cause 1 damage so obviously his AI needs work.

 

GITHUB REPO:

https://github.com/Antidote/2dzeldaengine

 

Don't mind the Derpy code, the stuff in Octorok is just hacky stuff to test delta timing and me learning AI programming as i go.

  • Like 9
Link to comment
Share on other sites

Yep, it's looking quite nice and (from that glimpse into the project's files on the screenshot) well-organized. Wouldn't mind hearing more about the design, too, like... how your entities interact, ex. how the Octorok "knows" Link and chases him or somesuch? I don't really know about a lot of what goes into making a game or game engine, from AI to collision detection to who knows what :P

 

Also, if I may say this: You're indirectly at fault that I stayed up through the night, as you kinda inspired me to try and create a game engine of sorts (yet) again. Which'll probably go nowhere as can be guess from the above. Got as far as an animated ALttP Link running around, tho via C# + MonoGame, but for now I'm too tired to keep going...

 

Link to comment
Share on other sites

XD Sorry about that, and as for the Octorok chasing Link, it's just a basic circle algorithm without the radius. On top of that EntityManager keeps track of the Player Object, and only allows 1 instance of an entity of type "Player"

void Octorok::think(sf::Time dt){    sf::Vector2f playerVec = Engine::instance().entityManager().player()->position();    move((playerVec - m_pos) * (2.f*dt.asSeconds()));}
If you want to know how i'm doing depth sorting, it's pretty simple: std::sort :3

 

 

BUMP

As promised last night during ShadowFire's stream, i've uploaded the source to github, if you want to help out in anyway just ask and I'll see about adding you to the repo.

 

I'd love for this engine to go somewhere :D

 

EDIT:

To mods, I only double posted to inform people following this of the status update, please merge this post with my previous one.

Link to comment
Share on other sites

That would be great, right now i'm sticking with ALTTP Style, but I may go with MC style later on.

 

EDIT:
Been ripping sprites from ALTTP using zcompress and yy-chr (via wine)  so here is an example of what i'm able to do using yy-chr's unique "palette set" feature which makes ripping a breeze

Before:

Posted Image

After:

Posted Image

 

The NPC sprite and blue bird use different palettes from the red bird and the bunny (which is demonic if you ask me lol)

Later on I'll right a tutorial on how to rip them this way.

  • Like 1
Link to comment
Share on other sites

When creating the input manager i noticed something pretty bad: it had a very negative affect on the whole program.

 

I have a 9800GTX+ (pretty high end 6 years ago) and i was averaging about 300 FPS with the input manager being updated every frame, which is poor design to begin with, but bear with me. So I decided to make put it on a separate thread, which is normal practice for modern games anyway, and boy was I surprised by the difference

Before:

 

 

Posted Image

 

 

 

EDIT: Added it back

AFTER (screw you xfce4-screenshooter)

 

 

Posted Image

 

 

Link to comment
Share on other sites

I just did a test to see how many entities i can have on screen at once, NO view culling used.

I was able to render about 900 entities at once, each doing about 400 cycles of a simple AI routine, before things started slowing down really bad. I don't know of a case where I'll EVER need to do that, so i think that's a success :3

  • Like 2
Link to comment
Share on other sites

Working on my map compiler right now, once it's finished I'll start writing the read class (which forces me to right the Map -> Layer -> Tile classes)

Right now the only collision types that are supported are Solid = 0x00, and non-Solid =0xFF

 

Since I've decided to make Tiled-Qt the official map editor of this engine, A dedicated "Collision" layer will be used to calculate this using tile properties, (basically meaning you can use any image you damn well please for each collision type minus Non Solid, which is defined by a lack of tile) Once I've decided on the naming convention I'll let you know so people can make tests maps if they desire.

 

Anyway here is the map compiler as it sits right now:
 

MapFileWriter.cpp:

http://pastebin.com/TYreGFYT

 

MapFileWriter.hpp:

http://pastebin.com/hbn5h5sX

 

Here is an example of what i mean, you guys should recognize it despite it's ugliness:

Posted Image

  • Like 2
Link to comment
Share on other sites

Ran out of room in that post So double posting due to an update.

Here is an updated collision map:

Posted Image

 

I personally think it looks pretty professional.

 

EDIT:
After 2 hours of head scratching, compiler WTFs and 1D10T errors, the map format is complete, Now to write the reader and the classes.

 

Here is the completed source (header is the same)

 

#include "MapFileWriter.hpp"#include <Exception.hpp>#include <TmxParser/Tmx.h>#include <sstream>#include <algorithm>#include <Map.hpp>#include <iostream>#include <iomanip> namespace zelda{namespace utility{inline void tolower(std::string& str){    std::transform(str.begin(), str.end(), str.begin(), ::tolower);} }namespace io{  MapFileWriter::MapFileWriter(const Uint8* data, const Uint64 length)    : base(data, length){} MapFileWriter::MapFileWriter(const std::string &filepath)    : base(filepath){} struct TileFlags{    bool Horizontal:1;    bool Vertical:1;    bool Diagonal:1;}; void MapFileWriter::fromTMX(const std::string &filepath){    Tmx::Map map;    map.ParseFile(filepath);    if (map.HasError())    {        std::stringstream err;        err << "error in Tmx::Parser : " << (int)map.GetErrorCode() << ": " << map.GetErrorText() << std::endl;        throw zelda::error::Exception(err.str());    }    base::writeUInt32(Map::MAGIC_NUMBER);    base::writeUInt32(Map::VERSION);    base::writeUInt16(0xFEFF);    base::writeUInt32(map.GetWidth()*map.GetTileWidth());    base::writeUInt32(map.GetHeight()*map.GetTileHeight());    base::writeUInt32(map.GetTileWidth());    base::writeUInt32(map.GetTileHeight());    base::writeUByte(map.GetOrientation()); // will probably go unused but you never know    base::writeUInt32(map.GetTilesets().size());    Uint64 layerCountOffset = base::position();    base::writeUInt32(map.GetLayers().size() - 1);    // Align to 32bytes for Wii/GCN support    base::seek((m_position + 0x1F) & ~0x1F, base::Beginning);     for (Tmx::Tileset* tileset : map.GetTilesets())    {        std::string path = tileset->GetImage()->GetSource();        path = path.substr(path.find_last_of("/") + 1, (path.size() - path.find_last_of("/")) - 1);        base::writeString(path);    }     // Align to 32bytes for Wii/GCN support    base::seek((base::position() + 0x1F) & ~0x1F, base::Beginning);     Tmx::Layer* colLayer = NULL;     Uint32 layerCount = 0;    for (Tmx::Layer* layer : map.GetLayers())    {        std::string name = (std::string)layer->GetName();        utility::tolower(name);        if (!name.compare("collision"))        {            if (!colLayer)                colLayer = layer;            else                throw "Too many collision layers, The map can have at most 1 Collision layer, please remove the extraneous layers";            continue;        }         int tileCount = 0;         for (int y = 0; y < layer->GetHeight(); y++)        {            for (int x = 0; x < layer->GetWidth(); x++)            {                if (layer->GetTileTilesetIndex(x, y) == -1)                    continue;                tileCount++;            }        }         if (tileCount == 0)            continue;         layerCount++;        base::writeBool(layer->IsVisible());        base::writeUInt32(layer->GetZOrder());        //base::writeUInt32(layer->GetProperties().GetSize());         base::writeUInt32(tileCount);         // Align to 32bytes for Wii/GCN support        base::seek((base::position() + 0x1F) & ~0x1F, base::Beginning);        for (int y = 0; y < layer->GetHeight(); y++)        {            for (int x = 0; x < layer->GetWidth(); x++)            {                if (layer->GetTileTilesetIndex(x, y) == -1)                    continue;                 Tmx::MapTile& tile = (Tmx::MapTile&)layer->GetTile(x, y);                base::writeInt32(tile.id);                base::writeUInt32(layer->GetTileTilesetIndex(x, y));                TileFlags flags;                flags.Horizontal = tile.flippedHorizontally;                flags.Vertical = tile.flippedVertically;                flags.Diagonal = tile.flippedDiagonally;                base::writeUBytes((Uint8*)&flags, 1);                base::writeUInt16(x*map.GetTileWidth());                base::writeUInt16(y*map.GetTileHeight());            }        }          base::seek((base::position() + 0x1F) & ~0x1F, base::Beginning);    }      // Write the collision data    for (int y = 0; y < map.GetHeight(); y++)    {        for (int x = 0; x < map.GetWidth(); x++)        {            if (colLayer)            {                if (colLayer->GetTileTilesetIndex(x, y) != -1)                {                    Tmx::MapTile& mapTile = (Tmx::MapTile&)colLayer->GetTile(x, y);                    const Tmx::Tile* tile = map.GetTileset(mapTile.tilesetId)->GetTile(mapTile.id);                    Uint8 flags = 0;                    if (tile)                    {                        Uint8 flippedDamage = 0;                        flippedDamage |= (colLayer->IsTileFlippedHorizontally(x, y) ? 0x01 : 0x00);                        flippedDamage |= (colLayer->IsTileFlippedVertically(x, y) ? 0x02 : 0x00);                         if (tile->GetProperties().HasProperty("Type"))                        {                            // Clear this flag for the ones that don't need it                            flags |= 0x01;                            std::string type = tile->GetProperties().GetLiteralProperty("Type");                            if (!type.compare("Angle45"))                            {                                flags |= 0x02;                                std::cout << "Angle45 " << std::hex << (int)flags << std::endl;                            }                            else if (!type.compare("Angle25"))                            {                                flags |= 0x04;                                std::cout << "Angle25 " << std::hex << (int)flags << std::endl;                            }                            else if (!type.compare("Jump"))                            {                                flags &= ~0x01;                                flags |= 0x08;                                std::cout << "Jump " << std::hex << (int)flags << std::endl;                            }                            else if (!type.compare("WaterShallow"))                            {                                flags &= 0x01;                                flags |= 0x10;                            }                            else if (!type.compare("WaterDeep"))                            {                                flags &= 0x01;                                flags |= 0x20;                            }                            else if (!type.compare("Damage"))                            {                                flags &= ~0x01;                                flags |= 0x40;                                if (tile->GetProperties().HasProperty("Value"))                                {                                    // Damage tiles ignore flipping                                    flippedDamage = (Uint8)(tile->GetProperties().GetNumericProperty("Value") & 0xFF);                                }                                else                                {                                    flippedDamage = 0;                                }                                std::cout << "Damage " << std::hex << (int)flags << std::endl;                            }                        }                        else                        {                            std::cout  << "WARNING: Collision tile with no type at " << x << "," << y << " assuming complete solid" << std::endl;                            flags |= 0x01;                        }                         std::cout << "Final value: " << std::setw(2) << std::setfill('0') << (int)flags << std::dec << std::endl;                        base::writeByte(flags);                        base::writeByte(flippedDamage);                    }                    else                        base::writeUInt16(0);                }                else                    base::writeUInt16(0);            }        }    }    base::seek(layerCountOffset, base::Beginning);    base::writeUInt32(layerCount);    std::cout << layerCount << std::endl;    // Finally save the map    base::save();} void MapFileWriter::setFilepath(const std::string& filepath){    base::m_filepath = filepath;}}}
Edited by Antidote
  • Like 4
Link to comment
Share on other sites

Good thing i always go back and read my posts, or i probably wouldn't have noticed that i wasn't properly clearing those bits

XD

 

flags &= 0x01;

instead of

flags &= ~0x01;

 

that would have caused a TON of headaches down the line if i didn't catch it.

 

@Crownjo:

Thanks, once I'm done with the map reader i'll be able to really get started.

  • Like 1
Link to comment
Share on other sites

 Share

×
×
  • Create New...

Important Information

By using this site, you agree to our Terms of Use.