Jump to content
A 2021 backup has been restored. Forums are closed and work in progress. Join our Discord server for more updates! ×
SoaH City Message Board

luksamuk

Members
  • Posts

    1,594
  • Joined

  • Last visited

  • Days Won

    12

Posts posted by luksamuk

  1. Here's a video of my another hack(Sonic: Emerald Land). Showing a TropicalRevoid(Green Hill Zone) act1, the level is not 100% complete but is playable. So enjoy the video guys:

    Comment and criticism welcome!

     

    Although this is a hack and this kind of criticism must be approached very carefully, I feel like the music simply doesn't match the level, nor the game. All the music: Title Screen, Speed Sneakers, the level music.

    It simply feels like it doesn't fit, and although this might be the instruments' fault, I feel like varying the instruments more won't solve the issue, but I have yet to hear this variation of instruments to be sure.

  2. I started under the fangaming flag, then moved to romhacks, then moved to fangames, then moved to my own indie games.

    Point is: They are complementary.

    There are hacks that look like fangames, and there are fangames that look like hacks.

    This association can be seen at the point where we are all Sonic fans, and we are also fans of the way a Sonic Engine operates.

     

     

    From my point of view, the quick trip I had at romhacking made me understand better the way a processor and the memory work, and also introducted me to the way the old Sonic physics were programmed.

    When I came back and finally started messing with Sonic Worlds, I noticed how different the collision was programmed on MMF2 to achieve a similar effect of Genesis games.

    Both ways gave me info on how to code collision itself properly.

    • Like 1
  3. I0LZNdS.pngRecognize something? Yeah, the beta goggles. I implemented it in the game.

     

    Nice. Are they used like the bubble shield? Do you lose them when you get hit?

     

    Screenshot of a brand new stage in Sonic Adventure Emerald. When I say brand new this stage hasn't been in any version of the game.

    utZuPgc.png

     

    I like the design of your HUD, though I feel like it's too big for the viewport size...

     

     

     

     

    Also, a little something I made with 4 hours, using the same Oficina Framework that I used to create the Mario you guys seen earlier on this same thread.

    It's pretty obvious that it's a Flappy Bird clone, yeah, but I did it mostly because I was defied to; I did it with the purpose of showing that this game is NOT something special, and is NOT hard to make, if you're thinking about making your games, and that pure programming is hard.

     

    Kq3mw03.png

    c1r5aOP.png

    uSsm8u3.png

     

    If anyone's interested, I'd gladly provide a download link (x86_64 Linux only for now, I'm sorry. I might provide a 32-bit Windows executable soon, who knows) and the source code (though the source code runs over Oficina's library, which isn't opensource, at least for now; but it'd serve to show the algorithm itself).

    Please notice I (thankfully) don't have the rights over Shitty Flappy Bird.

     

    EDIT: I'll just drop the code anyway, I don't have to hide it. Prepare for bad programming.

    #include <OficinaFramework/OficinaFramework.h>
    using namespace OficinaFramework;
    // 1m = 100px
    #define M2P(x) (x*100.0f)
    #define P2M(x) (x/100.0f)
    // Fonte para o debugger
    RenderingSystem::Texture* font_texture;
    RenderingSystem::Font* font;
    AudioSystem::SFX* sfx_coin,
                    * sfx_shatter,
                    * sfx_swooper;
    RenderingSystem::Texture* m_pipe_texture;
    const float m_gravity = 9800000.0f;
    bool gameplaying = false;
    int score = 0;
    int best[5] = {0};
     
    const float easy_speed   = 2.5f,
                normal_speed = 3.5f,
                hard_speed   = 5.0f,
                veryhard_speed  = 6.8f,
                ninja_speed = 10.0f;
    float difficulty_speed = easy_speed;
     
    int difficulty = 0;
     
    float random_float()
    {
        return ((float)rand() / RAND_MAX);
    }
     
    float generate_pipe_gap_center()
    {
        switch(difficulty) {
        case 0:
            // Easy mode
            return (random_float() * 114.0f) + 183.0f;
        case 1:
            // Normal mode
            return (random_float() * 178.0f) + 119.0f;
        case 2:
        case 4:
            // Hard mode / Ninja mode
            return (random_float() * 242.0f) + 55.0f;
        case 3:
            // Very Hard mode
            //return (random_float() * 480.0f);
            //return (random_float() * 416.0f) + 32.0f;
            return (random_float() * 384.0f) + 64.0f;
        }
        // if by any change I someday make a training mode.
        return RenderingSystem::GetViewportSize().y / 2.0f;
    }
     
    class Pipe : public EntitySystem::DrawableEntity
    {
    private:
        bool spawned_friend = false;
        bool m_upside;
        bool scored = false;
    public:
        Pipe(bool upside, float gapcenter)
        {
            SetName("Pipe");
            m_upside = upside;
            if(upside) {
                m_orientation = RenderingSystem::RENDER_NORMALLY;
                m_position.y = gapcenter + (difficulty == 4 ? 41.25f : ( difficulty == 0 ? 65.5f : 55.0f )  );
                //m_position.y = gapcenter + 55.0f;
            }
            else {
                m_orientation = RenderingSystem::RENDER_FLIP_Y;
                m_position.y = gapcenter - 480.0f - (difficulty == 4 ? 41.25f : ( difficulty == 0 ? 65.0f : 55.0f ) );
                //m_position.y = gapcenter - 480.0f - 55.0f;
            }
     
            m_position.x = RenderingSystem::GetViewportSize().x + 80.0f;
        }
     
        void Init() override {}
        void LoadContent() override {}
        void UnloadContent() override {}
     
        void Update() override
        {
            if(gameplaying)
                m_position.x -= difficulty_speed * TimingSystem::StepCorrection();
     
            if(m_position.x <= -80.0f)
                RemoveMe();
     
            // Adiciona mais. Apenas o cano de baixo executa esta ação
            if(m_upside && !spawned_friend
               && m_position.x <= (difficulty == 3 ? (640.0f - 512.0f)  :  (difficulty == 4 ? 64.0f : (640.0f - 256.0f))))
            {
                spawned_friend = true;
                float center_pipe = generate_pipe_gap_center();
                GetParent()->Add("_pipe", new Pipe(false, center_pipe));
                GetParent()->Add("_pipe", new Pipe(true, center_pipe));
            }
        }
     
        void Draw() override
        {
            m_pipe_texture->Draw(m_position, // Posição
                                 m_pipe_texture->GetSize().toVec2(), // Tamanho do contêiner
                                 vec2::Zero(), // Posição superior esquerda do sampler
                                 m_pipe_texture->GetSize().toVec2(), // Tamanho do sampler
                                 0.0f, // Ângulo
                                 1.0f, // Transparência
                                 vec2::Zero(), // Hotspot
                                 Color4::MaskToColor4(WHITE), // Cor de pintura do sampler
                                 m_orientation); // Orientação
        }
     
        void CountToScore()
        {
            if(m_upside && !scored && m_position.x <= 16.0f)
            {
                score++;
                scored = true;
                AudioSystem::PlaySFX(sfx_coin);
            }
        }
    };
     
    class Bird : public EntitySystem::DrawableEntity
    {
    private:
        RenderingSystem::Texture* m_bird_texture;
        float m_yspeed;
        float m_meteryspeed;
        const float m_terminalvelocity = 10000.0f;
        vec2 m_meterposition;
     
        // Hitbox do pássaro é um círculo, porque sou um cara legal.
        const float m_circle_r = 10.0f;
     
    public:
        void Init() override
        {
            SetName("Bird");
            Reposition();
            SetDrawDepth(1.0f);
        }
     
        void LoadContent() override
        {
            m_bird_texture = RenderingSystem::TexturePool::LoadTexture("sprites/bird.png");
        }
     
        void UnloadContent() override
        {
            RenderingSystem::TexturePool::DisposeTexture(m_bird_texture);
        }
     
        void Update() override
        {
            // Aplicando gravidade
            // Como estamos lidando com uma quantidade variada de quadros
            // por segundo no jogo, a gravidade requer modelagem sobre as
            // leis de movimento uniformemente variado e a variação de tempo
            // entre os quadros.
     
            if(gameplaying)
            {
                // Por padrão, devemos converter o DeltaTime da Oficina de ms para s
                float m_delta_yspeed = m_gravity * (TimingSystem::GetDeltaTime() / 1000.0f);
                float m_meteryspeed_new = m_meteryspeed + m_delta_yspeed;
                clamp(m_meteryspeed, -m_terminalvelocity, m_terminalvelocity);
                m_meterposition.y += (TimingSystem::GetDeltaTime() / 1000.0f) * (m_meteryspeed + m_meteryspeed_new) / 2.0f;
                m_meteryspeed = m_meteryspeed_new;
                m_position = M2P(m_meterposition);
                m_yspeed = M2P(m_meteryspeed) / 100000.0f;
     
     
                // Impulso ao apertar o botão
                if(InputSystem::PressedButton(InputSystem::GamePadButton::A))
                {
                    m_meteryspeed = -3550.0f;
                    InputSystem::Rumble(0.5f, 250u);
                    AudioSystem::PlaySFX(sfx_swooper);
                }
     
                // Efeito: altere o ângulo de acordo com a velocidade de queda
                // e subida
                m_angle = -22.5f + (45.0f * (m_yspeed + 3.0f) / 6.0f);
     
                // Detecção de colisão
                for(auto e : *GetParent())
                {
                    if(e.second->GetName() == "Pipe")
                    {
                        if(IsCollidingWithPipe(e.second->GetPosition())) {
                            gameplaying = false;
                            AudioSystem::PlaySFX(sfx_shatter);
                            if(score > best[difficulty]) best[difficulty] = score;
                        }
                        else
                        {
                            Pipe* p = (Pipe*)e.second;
                            p->CountToScore();
                        }
                    }
                }
     
                // Não sair da play area
                if(m_meterposition.y < 0.0f)
                    m_meterposition.y = 0.0f;
                if(m_position.y >= 480.0f + m_circle_r) {
                    gameplaying = false;
                    AudioSystem::PlaySFX(sfx_shatter);
                    if(score > best[difficulty]) best[difficulty] = score;
                }
            }
            else
            {
                m_meteryspeed = m_yspeed = 0.0f;
            }
     
            // Output do debugger
            stringstream ss;
            ss << "Y Position (m):  " << m_meterposition.y << endl
               << "Y Position (px): " << m_position.y << endl
               << "Y Speed (m/s):   " << m_meteryspeed << endl
               << "Y Speed (px/ms): " << m_yspeed << endl
               << "Angle:           " << m_angle << endl;
            ScreenSystem::Debug_AddLine(ss.str());
        }
     
        void Draw() override
        {
            m_bird_texture->Draw(m_position, // Posição
                                 m_bird_texture->GetSize().toVec2(), // Tamanho do contêiner
                                 vec2::Zero(), // Posição superior esquerda do sampler
                                 m_bird_texture->GetSize().toVec2(), // Tamanho do sampler
                                 m_angle, // Ângulo
                                 1.0f, // Transparência
                                 (m_bird_texture->GetSize().toVec2() / 2.0f), // Hotspot
                                 Color4::MaskToColor4(WHITE)); // Cor de pintura do sampler
        }
     
     
        bool IsCollidingWithPipe(vec2 pipePosition)
        {
            vec2 true_position = m_position;
            vec2 closest = true_position;
            clamp(closest.x, pipePosition.x, pipePosition.x + 64.0f);
            clamp(closest.y, pipePosition.y, pipePosition.y + 480.0f);
            vec2 delta(true_position.x - closest.x, true_position.y - closest.y);
            float squareDistance = (delta.x * delta.x) + (delta.y * delta.y);
            return (squareDistance <= (m_circle_r * m_circle_r));
        }
     
        void Reposition()
        {
            m_position = vec2(80.0f, RenderingSystem::GetViewportSize().y / 2.0f);
            m_meterposition = P2M(m_position);
            m_yspeed = m_meteryspeed = 0.0f;
        }
    };
     
    class PlayScreen : public ScreenSystem::Screen
    {
        EntitySystem::DrawableEntityCollection drawables;
    public:
        ~PlayScreen()
        {
        }
     
        void Initialize() override
        {
            SetActive(true);
            SetVisible(true);
            drawables.Add("_bird", new Bird);
            // Crie o primeiro
            float center_pipe = generate_pipe_gap_center();
            drawables.Add("_pipe", new Pipe(false, center_pipe));
            drawables.Add("_pipe", new Pipe(true, center_pipe));
            drawables.Init();
            InputSystem::StartJoystickRumbleSupport();
            ScreenSystem::Screen::Initialize();
        }
     
        void ReInitialize() override
        {
            for(auto e : drawables)
            {
                if(e.second->GetName() == "Pipe")
                    e.second->RemoveMe();
                else if(e.second->GetName() == "Bird")
                {
                    Bird* b = (Bird*)e.second;
                    b->Reposition();
                }
            }
            float center_pipe = generate_pipe_gap_center();
            drawables.Add("_pipe", new Pipe(false, center_pipe));
            drawables.Add("_pipe", new Pipe(true, center_pipe));
            score = 0;
     
            switch(difficulty) {
            case 0:
                difficulty_speed = easy_speed;
                break;
            case 1:
                difficulty_speed = normal_speed;
                break;
            case 2:
                difficulty_speed = hard_speed;
                break;
            case 3:
                difficulty_speed = veryhard_speed;
                break;
            case 4:
                difficulty_speed = ninja_speed;
                break;
            }
     
            gameplaying = true;
        }
     
        void LoadContent() override
        {
            drawables.LoadContent();
            m_pipe_texture = RenderingSystem::TexturePool::LoadTexture("sprites/pipe.png");
            sfx_coin = AudioSystem::AudioPool::LoadSFX("sound/coin.ogg");
            sfx_shatter = AudioSystem::AudioPool::LoadSFX("sound/shatter.ogg");
            sfx_swooper = AudioSystem::AudioPool::LoadSFX("sound/swooper.ogg");
            ScreenSystem::Screen::LoadContent();
        }
     
        void UnloadContent() override
        {
            // Save high scores
            FILE* fp;
            fp = fopen("highscores.txt", "w");
            if(fp) {
                for(int i = 0; i < 5; i++)
                    fprintf(fp, "%d\n", best[i]);
                fclose(fp);
            }
     
            drawables.UnloadContent();
            RenderingSystem::TexturePool::DisposeTexture(m_pipe_texture);
            AudioSystem::AudioPool::DisposeAudio(sfx_coin);
            AudioSystem::AudioPool::DisposeAudio(sfx_shatter);
            AudioSystem::AudioPool::DisposeAudio(sfx_swooper);
            InputSystem::StopJoystickRumbleSupport();
            ScreenSystem::Screen::UnloadContent();
        }
     
        void Update() override
        {
            drawables.Update();
            if(InputSystem::PressedButton(InputSystem::GamePadButton::LSHOULDER1))
            {
                ScreenSystem::SetDebug(!ScreenSystem::IsDebugActive());
            }
            else if(InputSystem::PressedButton(InputSystem::GamePadButton::START))
            {
                if(!gameplaying)
                    ReInitialize();
            }
     
            if(!gameplaying)
            {
                if(InputSystem::PressedButton(InputSystem::GamePadButton::HAT_DOWN))
                    if(difficulty < 4) difficulty++;
                if(InputSystem::PressedButton(InputSystem::GamePadButton::HAT_UP))
                    if(difficulty > 0) difficulty--;
            }
        }
     
        void Draw() override
        {
            drawables.Draw();
            stringstream scoretext;
            scoretext << "Score: " << score;
            if(best[difficulty]) scoretext << endl << "Best:  " << best[difficulty];
            font->DrawString(vec2(320.0f,400.0f) - (font->MeasureString(scoretext.str(), 2.0f) / 2.0f),
                               scoretext.str(), 2.0f);
     
            if(!gameplaying) {
                vec2 difficultytext_halfsize = font->MeasureString("Difficulty:\nEasy\nNormal\nHard\nVery Hard\nNinja", 2.0f) / 2.0f;
                vec2 difficultytext_pos = vec2(RenderingSystem::GetViewportSize().toVec2().x / 2.0f, 66.0f) - difficultytext_halfsize;
     
                RenderingSystem::DrawRectangle(vec2(difficultytext_pos.x - (difficultytext_halfsize.x / 4.0f), difficultytext_pos.y + 30.0f + (22.0f * float(difficulty))),
                                               vec2(5.0f), 45.0f, WHITE, 0.7f);
     
                font->DrawString(difficultytext_pos, "Difficulty:\nEasy\nNormal\nHard\nVery Hard\nNinja", 2.0f);
     
                switch(InputSystem::GetType()) {
                case InputSystem::Type::KEYBOARD:
                    font->DrawString(vec2(RenderingSystem::GetViewportSize().toVec2() / 2.0f) - (font->MeasureString("Press Enter to Retry", 4.0f) / 2.0f),
                            "Press Enter to Retry", 4.0f);
                    font->DrawString(vec2(RenderingSystem::GetViewportSize().toVec2() / 2.0f) - (font->MeasureString("\n\n\n\n\nTip: Tap Space to make the bird jump", 1.0f) / 2.0f),
                            "\n\n\n\n\nTip: Tap Space to make the bird jump", 1.0f);
                    break;
                case InputSystem::Type::XBOXPAD:
                    font->DrawString(vec2(RenderingSystem::GetViewportSize().toVec2() / 2.0f) - (font->MeasureString("Press Start to Retry", 4.0f) / 2.0f),
                        "Press Start to Retry", 4.0f);
                    font->DrawString(vec2(RenderingSystem::GetViewportSize().toVec2() / 2.0f) - (font->MeasureString("\n\n\n\n\nTip: Tap A to make the bird jump", 1.0f) / 2.0f),
                        "\n\n\n\n\nTip: Tap A to make the bird jump", 1.0f);
                    break;
                case InputSystem::Type::JOYPAD:
                    font->DrawString(vec2(RenderingSystem::GetViewportSize().toVec2() / 2.0f) - (font->MeasureString("Press Start to Retry", 4.0f) / 2.0f),
                        "Press Start to Retry", 4.0f);
                    font->DrawString(vec2(RenderingSystem::GetViewportSize().toVec2() / 2.0f) - (font->MeasureString("\n\n\n\n\nTip: Tap Button 1 to make the bird jump", 1.0f) / 2.0f),
                        "\n\n\n\n\nTip: Tap Button 1 to make the bird jump", 1.0f);
                    break;
                }
            }
        }
    };
     
     
    int main(int argc, char** argv)
    {
        srand(time(NULL));
        std::list<string>* confv = new std::list<string>;
        confv->push_back("gamename=Shitty Bird");
        confv->push_back("resolution=640x480");
        confv->push_back("windowsize=640x480");
     
        EngineCore::Initialize(argc, argv, confv);
        IOSystem::AddToSearchPath("data");
        // Barra de espaço e botão "A" do controle funcionam para o mesmo propósito
        InputSystem::BindKey(SDLK_SPACE, InputSystem::GamePadButton::A);
        // Outros botões
        InputSystem::BindKey(SDLK_F1, InputSystem::GamePadButton::LSHOULDER1);
        InputSystem::BindKey(SDLK_RETURN, InputSystem::GamePadButton::START);
        InputSystem::BindKey(SDLK_DOWN, InputSystem::GamePadButton::HAT_DOWN);
        InputSystem::BindKey(SDLK_UP, InputSystem::GamePadButton::HAT_UP);
     
        // Coloca-se a fonte no debugger para que ele possa aparecer
        font_texture = RenderingSystem::TexturePool::LoadTexture("fonts/gohufont-6-11-pad1.png");
        font = new RenderingSystem::Font(font_texture, vec2dw(6,11), vec2b::One());
        ScreenSystem::Debug_SetFont(font);
        // Adiciona-se a tela de jogo
        ScreenSystem::AddScreen(new PlayScreen, 1.0f);
        RenderingSystem::SetLinearFiltering(false);
     
     
        // Load High Scores
        FILE* fp;
        fp = fopen("highscores.txt", "r");
        if(fp) {
            for(int i = 0; i < 5; i++)
                fscanf(fp, "%d", &best[i]);
            fclose(fp);
        }
     
     
        return EngineCore::DoGameLoop();
    }

    • Like 1
  4. So my friend kind of finished the level designer or, at least, made it stable for loading and exporting scripts.

    I've also began to program some objects, and so the breakable blocks and interrogation blocks, both now containing items.

    Been thinking about finishing it on free time, then release it. On next SAGE, maybe?

     

    Fraa04f.png

    49Uqkd2.png

    75NhTUS.png

    • Like 5
  5. I decided to start a new fangame creation program, named Sonic Fan Game Development Kit (SFGDK for short).

    The program will be made with C# using .NET Framework 4.0, and the engine maybe DirectX (which version??)

     

    SFGDK will be game-maker-like environment with these features:

    • Sprite Editor - A sprite editor for your game graphics (with sub-animations, origin point, and collision mask).
    • Sound & Music Editor - Imports (and exports) .wav, .mp3 to your fangame. You can set looping points.
    • Font Editor - Create and modify sprite-based fonts. (with kerning, glyph size).
    • Tile Editor - Make your level tiles. (and collision masks of them). You can make animated ones!
    • Chunk Editor - Make large blocks from your tiles (like these of sonic hacking), and set their solidity and behavior.
    • Background Editor - Make backgrounds for your levels & screens, and set parallax scrolling settings.
    • Object Editor - Manage your game objects, and edit their behavior. You can add properties and variables.
    • Code Editor - Make functions, structures, macros and enumerations for the gameplay, using c#-like language.
    • Level Editor - Design your zones with your chunks and your objects.
    • Screen Editor - Manage the fangame's screen (e.g. SEGA Screen, Title Screen, Level Screen) and their codes.
    • Misc. Editor - This one will store other binary and text reources for your game.

    And MANY more features...

     

    I hope this project will be helpful. 

     

    PLEASE do not use DirectX.

    Either use either XNA/MonoGame (specially the SDL2 fork), or use OpenGL directly.

    Using DirectX will only narrow your platforms to Windows and Xbox One (if you're using DX11);

    If you use OpenGL/MonoGame, you'll be able to deliver to Windows, Linux (SteamOS included) (Wine is NOT an option), Mac OS X, Playstation 4 and perharps iOS and Android. Think about that.

    DX sucks ass, don't make me declare variables like LPVERTEXBUFFERFUCKINGCALLBACKDX9 vb;

     

    C# is a good language. I like to think of it as Java's efficient second degree cousin. Good choice.

     

    I suggest you guys start a GitHub repo and start coding your way into the stars right now. I'd also be eager to help with general programming, cuz right now that's what I do. There's also this little repo I started a few days ago, which is supposed to be the foundation to Sonic Worlds' port to C++11 shhh it's a secret. I talked a bit to DimensionWarped but it only has minimal things right now. This is not the right place to talk about it, since I'll probably be making a thread @ SW forum, but that's just to reinforce that projects like this one you guys are starting should ALWAYS be reinforced to keep up, and not die out. Start creating milestones and issues on GitHub.

  6. TL;DR: Test my game's very-early-pre-alpha, will ya?

     

    Some of you know I disappeared for a bit from the fangaming scene (it's been about two years since I made something Sonic-related), and that it was because I was starting my own indie game, from scratch, using real programming languages (Not debunking MMF2, which is STILL an awesome tool, but I wanted more control over things).

     

    So, after months and months of programming and learning and scratching projects and improving code, I've finally come with something good: OficinaFramework, an indie games framework with several "subsystems", based on SDL 2.0 and OpenGL.

     

    I'd like to request you guys to test out the binaries.

     

    They have nothing unusual; they're quite simple, and wouldn't require too much time to make, weren't they made focusing on bringing stable and versatile features from the ground up - like a queued background music system, pretty much inspired on Sonic Worlds Delta's music engine.

     

    (I've removed the download link, I'll post it again soon.)

     

    The packed Linux libraries seem to only work on Ubuntu 13.10 and up, didn't test on an older version. The readme instructs on how you could proceed if you're eager to make it work on a different distro, but it's not a definitive guide.

    Please be also sure to get the default binary for your distro. Even though 32-bit binaries will work on 64-bit operating systems, if you are willing to give me feedback, I'd really like you to do it using the proper build for your system.

     

    Although it is not really opensource, at least yet, I'd like to have some info on how it's behaving on you guys' PCs - specially the old PCs. Here's the info I request:

     

    - Operational system and architecture of your SO (32/64bit, i386, amd64);

    - Model and frequency of your processor;

    - GPU model;

    - Total amount of RAM;

     

    And these infos which can be retrieved by the in-game debugger:

     

    - Type of input/controller used (specially the name of the controller which is shown there);

    - Usage of physical and virtual memory by the (main) process (this is only monitored on Linux, but I wouldn't complain if you took a little peak on your Windows task manager);

    - Average use of CPU (the value is hard to watch as it changes all the time, but try to get the biggest value);

    - Average FPS (default is 60)

     

    The resolution is locked on 720p, sorry about that.

     

    Thank you in advance  :(<

     

    EDIT: Don't mind the graphics. It's for testing. Mind the performance.

    EDIT2: You don't have to tell me everything about your PC if you don't want to, but it'll make my life lotta easier to fix eventual bugs and performance issues...

  7. Sonic 1: 14pts 

    Sonic 2: 9pts

    Sonic CD: 11pts 

    Sonic 3: 11pts

    Sonic & Knuckles: 12pts 

    Sonic Adventure: 11pts 

    Sonic Adventure 2: 23pts

    Sonic Heroes: 14pts

    Sonic Unleashed: 15pts [+1]

    Sonic Colours: 17pts

    Sonic Generations: 17pts [-1]

    Sonic Lost World: 4pts

  8. I didn't really read anything on this topic, but I'd like to share something with you guys.

     

    One of these days, a friend that lives with me just woke up and said "I had this weird dream in which I was playing a Sonic MMO".

     

    He described that the mechanics were rather simple. It was a 3D game, and there wasn't anything you wouldn't find in Sonic Adventure on the moves: Homing Attack, jumping, running around.

    But he said the big catch were how the enemies were interesting, complex, and beating them depended on attacking on the right spot at the right time.

    He also said that he believed another players could come and help you beat that enemy, but he was unsure how (it was a dream, after all) and the playable characters he saw were Sonic, Tails, Knuckles and maybe Shadow.

     

    When I asked him about the possibilities of other characters like Amy, Blaze, Chaotix or whatever, he stated that, in his opinion, it'd be much more interesting if it stick to the original trio (haha, this kinda beats the MMO thing, unless you could have multiple instances of the same character). That's some valuable info, since he's not a Sonic fan -- in fact, the last Sonic game he played was Sonic 1 about six years ago.

     

    I know this might be a little too subjective, but maybe I could inspire someone here. He plays League of Legends, Final Fantasy and Monster Hunter quite a lot, apart from others, and since I'm not much of an RPG or MMOs in general player, he's the biggest example I get when I think of these genres (or whatever it is).

     

    PS. Sorry for the vague explanation again. After all, it's a dream retold by other person lol. I'll see if I can grab some more info from my friend.

  9. Why should the player's time zone matter if you can just get the hour (the hour they have set on their clock that is) from the system clock in the first place?

     

    This is a very simple problem.  Figure out the hour using the calender or date/time object. Create the actives based on the hour. Make sure they are positioned correctly. Done. I'll whip up a tutorial when I get home if you haven't solved this by then.

     

    In SPhoenix, the levels were in real places of the world, so they had their own timezone. This is why I had to make this kind of calculation. But surely, you're right. This is a simple problem.

  10. I believe I already lost the files of Sonic Phoenix, but I remember that I implemented this using the Date/Time object, yes.

    It gets your current hour.

    Also I had to make it mandatory for the player to input its timezone. Perharps there might be a way to grab it from somewhere, but I'm almost certain you can't.

    Then all I did was calculate the current hour of the level using all the data I got.

     

    So it wasn't really real-time, it only calculated the local time of the level in hours, then a certain background would become visible in the beginning of the level accordingly. Nothing really special.

     

    I think the biggest job is to find matching backgrounds/recolors for each time you want to set. If you have HWA, I believe you can also write a shader and input the current hour to set the backdrops' coloring. Never tried that, though.

  11. I'd say that the most accurate way is to actually make a Vector3-based coordinate system for your world (X, Y, Z) and, for rendering, just convert it to a 2D point according to the camera (in your case, an isometric perspective - which represents a camera in 30 degrees approximately).

    According to this post I found in StackOverflow....

    Here's a very general answer. Say the camera's at (Xc, Yc, Zc) and the point you want to project is P = (X, Y, Z). The distance from the camera to the 2D plane onto which you are projecting is F (so the equation of the plane is Z-Zc=F). The 2D coordinates of P projected onto the plane are (X', Y').

    Then, very simply:

    X' = ((X - Xc) * (F/Z)) + Xc

    Y' = ((Y - Yc) * (F/Z)) + Yc

    If your camera is the origin, then this simplifies to:

    X' = X * (F/Z)

    Y' = Y * (F/Z)

    You might wanna take this into consideration.

    It might not be a problem to handle what is in front of what too.

    As for collisions, you might want to handle it using collision boxes, pretty much the way you'd do in a 3D game. Maths are maths, doesn't matter how you see them. The result will always be printed onscreen the way you specify it.

  12. @Jassbec: I'm looking forward to it on SAGE. Seems like you made big progress in little time :D awesome

    @Highwire4: Those buttons on the screenshot... you planning to release it on OUYA?

    @Mr. Potatobadger: Great, I wonder how this QQz boss will work. Looking forward to it.

    One note: If you're using omnidirectional animations for Sonic, you might wanna do the same for the other objects ingame. For example, the chain that ties the ball of the boss - and the ball itself - are rotated on your mockup. If you take a quick look on Sonic 1's first boss, the chain rings and the ball aren't rotated.

    It is not mandatory though - it depends on what you're trying to achieve.

    Thought I'd just drop this screenshot here...

    csonicss.png

    Not a big progress though, it's probably like this for a month.

    News include up to 4 resolution types (2x on the photo, 15/20/30/60 FPS which you can choose depending on your machine, and a tile system much like classic Sonic games, with 32-bit coordinates system.

    There's also experimental fullscreen (which SDL1.2 tends to fuck up with on Linux) and motion blur (using the OpenGL Accumulation Buffer, making the game run SLOOOWWWWW), but still WIP.

    You can grab the full code under the MIT License :D

  13. Thanks, Core D: I really messed up on that angleInRadians thing.

    There's no real significancy on converting angles to radians and vice-versa, it actually depends on which Framework/API you're using to render your game.

    Taking C/C++ as an example,

    void glRotatef(GLfloat angle, GLfloat x, GLfloat y, GLfloat z);

    requires your angle value to be in degrees, meaning you can use the direct value of double atan2(double, double).

    XNA Game Studio, though, uses radians in the method

    SpriteBatch.Draw (Texture2D texture, Rectangle dest, Nullable<Rectangle> src, Color color, Single angle, Vector2 origin, SpriteEffects effect, Single depth)

    for example. (note: float is an alias for Single in C#)

    One last thing I'd like to add: Apparently, the angles of the masks are also stored on the tiles' data, on classic Sonic games. But that's only for angle-mode changing and rendering purposes. The actual influence of ramps on speed is calculated in real-time, because Sonic can be over two pieces (16x16) at the same time. This way, you get a gradual influence of the slopes on speed.

×
×
  • Create New...