Search Unity

  1. Megacity Metro Demo now available. Download now.
    Dismiss Notice
  2. Unity support for visionOS is now available. Learn more in our blog post.
    Dismiss Notice

I'm making a Unity version of Daniel Linssen's Ludum Dare 34 game Reap

Discussion in 'Works In Progress - Archive' started by TwiiK, Jan 20, 2016.

  1. TwiiK

    TwiiK

    Joined:
    Oct 23, 2007
    Posts:
    1,729


    Reap is a game made in GameMaker by Daniel Linssen for Ludum Dare 34. This thread will detail my efforts in attempting to make a Unity version of the game, a fan project if you will, because Reap is a truly spectacular game, especially considering it's been made in less than 48 hours.

    Reap is an exploration game with a procedurally generated world. It has stunning pixel art, but it also has this really ingenious gameplay mechanic where you're given a map, but the map doesn't show your own location, you have to figure that out based on the landmarks around you, and thanks to the fantastic procedural world generator in the game, you're given a huge new world with interesting landmarks for every new playthrough.

    The world generator was the reason I decided to download the source code for Reap even though the game is made with GameMaker, a game engine I know practically nothing about. Initially I was thinking about just trying to learn enough about GameMaker and Daniel's code to be able to fish the world generator code out of there, but I've decided that I'm going to challenge myself and try to port Reap in it's entirety from GameMaker to Unity. By trying to port the entire game I'm hoping to gain some valuable knowledge about doing pixel art games in Unity as well, because like most GameMaker games, Reap is pixel perfect and that's not something that's easily achieved in Unity. The motivating factor here is that the original game was made in under 48 hours, which means there can't possibly be that much for me to port, right? I guess time will tell.

    Whenever I accomplish something noteworthy I will upload a Web Player build for you to play with and after (if) I finish the game I will make the entire project available to download for free. I'm also considering writing an accompanying article detailing anything I learned in regards to this. Perhaps there are other people out there who are curious about the differences between Unity and GameMaker and what it is like to port a 2D game made in a 2D engine into a 3D engine.

    Disclaimer: I've spoken with Daniel and I've been given permission to do this. Everything in the project will remain the property of Daniel Linssen - all the graphics, the sounds, and the source code belongs to him. You're free to download the project, learn from it and play around with it, but don't redistribute it and please don't be a dick and try to sell it.

    I will be back shortly with more information, in the meantime you can check out the original game or some of Daniel's other games through the links below.

    The original GameMaker game is available from Daniel's website, here:
    http://managore.itch.io/reap

    Also consider checking out Daniel's other games, they are all really clever and beautifully crafted:
    http://managore.itch.io
     
    Last edited: Jan 24, 2016
    jister, theANMATOR2b and GarBenjamin like this.
  2. GarBenjamin

    GarBenjamin

    Joined:
    Dec 26, 2013
    Posts:
    7,441
    Such a cool idea. More people should try to do this kind of thing. There are a lot of great games made in these jams by devs using GameMaker, Construct and so forth.

    Good luck.
     
  3. TwiiK

    TwiiK

    Joined:
    Oct 23, 2007
    Posts:
    1,729
    I've currently managed to get the world generator working and I've uploaded the first build to my website. Here's an image of the sort of world it creates:


    There are hundreds of thousands of sprites in this image and Unity has crashed at least a dozen times while I've been working on this. It's perfectly fine when you're viewing just a small section of the map at the time, which will be the case in the actual game, so I doubt I'm going to optimize it any, but if there are some simple tricks I can do I would like to hear them. :)

    You can try out the current build, version 0.0.1 :p, here:
    http://twiik.net/projects/reap-unofficial-unity-port

    Interesting discoveries so far:
    • In both GameMaker and Unity C# you can have implicitly typed variables, that is using the "var" keyword instead of int, float etc. When porting this game I chose to explicitly type each variable just to get a better understanding about what I was working with because there seems to be a lot of implied casts between float and int in the original source code, which isn't allowed in C#.
    • irandom_range() in GameMaker is inclusive for the max value, Random.Range() in Unity is exclusive for the max value so everywhere this function is used I've had to increase the max value by 1 to achieve the same range.
    • In GameMaker 0,0 on the coordinate system is top left, in Unity 0,0 is bottom left. This meant a few changes had to be made regarding the tile map. This took me a few hours to figure out. :p
     
    Last edited: Jan 24, 2016
  4. TwiiK

    TwiiK

    Joined:
    Oct 23, 2007
    Posts:
    1,729
    Thanks, and yeah. The code for the world generator I could pretty much just copy and paste into Unity and it worked. I had to change the syntax to C# of course, but there wasn't much more to it than that. This actually surprised me a bit. I thought GameMaker was more like that visual scripting asset, PlayMaker?, or Blueprint in Unreal Engine. But it turns out it's very familiar if you're used to Unity. The project is organized in much the same way, you can debug your code in much the same way. It wasn't hard to get used to at all.
     
    Last edited: Jan 24, 2016
    GarBenjamin and theANMATOR2b like this.
  5. TwiiK

    TwiiK

    Joined:
    Oct 23, 2007
    Posts:
    1,729
    Version 0.1.0 is out!


    http://twiik.net/projects/reap-unofficial-unity-port

    I'm doing everything I can to make this port as identical to the original as possible which means implementing some of the standard GameMaker quirks as well. Just like almost any GameMaker game out there Reap is framerate dependent, so I've made my Unity version framerate dependent as well, even though it pained me to do it. You also move faster diagonally just like in the original game. :p

    I know GameMaker has delta time, but almost no developers seem to use it. It seems like a really poor practice to me. Perhaps it's not taught in the beginner tutorials or something. Reap is a 48-hour game so I won't read much into it here, but I have a lot of released games on Steam made with GameMaker that are framerate dependent.

    It also seems like this project is going to take a lot longer than I anticipated. Mostly because 2D in Unity is really foreign to me, but at the same time it seems to to a lot more convoluted than I expected it to be at this point. Porting the world generator was really easy because it was so engine-agnostic, but sprite drawing etc. is trivial in GameMaker and apparently extremely involved in Unity. From what I can gather I have to involve Mecanim, the dope sheet and do so much just to be able to animate a sprite. I honestly thought I could just assign a sprite to the sprite renderer and give it a framerate or something like that. Why is it so convoluted?

    But we'll see once I get to that. It's probably the next thing I tackle. Read below for all the changes to this version.

    Changes for version 0.1.0:
    • Removed the initial debug camera and world re-generation functionality.
    • Implemented the player character with grid based movement just like in the original.
    • All the input methods of the original should work the same here.
    • Implemented collision detection. With the grid based movement and Daniel's clever algorithm this collision detection is just 1(!) line of code.
    • I've left my debug boxes in there so you can see how funky the character is positioned on the grid. It took me many hours to figure that one out.
    • The player spawning code which ensures the player spawns with some room around him is implemented, but because you don't yet have the axe you may be forced to restart the game if you spawn in a less than ideal position.
    • I've also tweaked the pixel perfect rendering in this build.
     
    Last edited: Jan 24, 2016
  6. TwiiK

    TwiiK

    Joined:
    Oct 23, 2007
    Posts:
    1,729
    Version 0.2.0 is out!


    http://twiik.net/projects/reap-unofficial-unity-port

    I postponed the animations because I felt it was more important the game was properly playable first. In this update I've added the axe and you can use it to traverse the entire world. Chop down trees, build rafts and bridges and go where no one has gone before.

    I'm still amazed at how much code I can pretty much take directly out of GameMaker and paste into Unity and have it work, but I sense I will have some pretty major challenges ahead of me when it comes to dealing with sprites. One such challenge I've already faced and I haven't found a very good solution for it yet. In GameMaker you have access to direct draw methods and can just draw sprites anywhere you want without consequence. In Unity you can't do that. So I've had to refactor some code to keep track of prefab instances and swap the parent/position of those instead of just being able to draw sprites for anything whenever I feel like it. One clear example of this is the raft. I still haven't found a good way for interpolating its movement so at the moment it jumps to the next grid position when you use it. In the original game Daniel just draws the raft sprite independently of the raft object using GameMaker's draw_sprite() function. I guess I would have to put the sprite as a child of the raft or something to be able to do something similar in Unity.

    But when it comes to sprite animation and the definition of a sprite in Unity I don't really understand the reasoning behind it. There seems to be no way to access a "sprite strip" or "sprite sheet" in Unity because Unity's definition of a sprite is just 1 frame of the sprite. I don't get that at all. Why isn't a sprite the entire thing and then in the sprite renderer we can reference the individual frames as we please? I guess I will need to write some helper classes for this part as I refuse to use Mecanim for it, that's just way too overkill for something like this, and I would constantly have to fight transitions and all the other crap Mecanim throws at you.

    I've already made one helper script:
    Code (CSharp):
    1. using UnityEngine;
    2. using UnityEditor;
    3.  
    4. public class SpritePostProcessor : AssetPostprocessor {
    5.  
    6.     /// <summary>
    7.     /// Allows you to assign defaults to the texture importer so you don't have
    8.     /// to set the same values manually for every sprite you import.
    9.     /// </summary>
    10.     void OnPostprocessTexture(Texture2D texture) {
    11.         // I found this line of code through Google. I don't know how it works,
    12.         // but without it you're not able to change texture importer values
    13.         // manually anymore. With this line the defaults below only apply to
    14.         // newly imported textures.
    15.         Object asset = AssetDatabase.LoadAssetAtPath(assetPath, typeof(Texture2D));
    16.         if (asset) {
    17.             return;
    18.         }
    19.  
    20.         // Set the defaults we want all the sprites in our project to have.
    21.         TextureImporter textureImporter = assetImporter as TextureImporter;
    22.         textureImporter.spritePixelsPerUnit = 1;
    23.         textureImporter.filterMode = FilterMode.Point;
    24.         textureImporter.mipmapEnabled = false;
    25.         textureImporter.textureFormat = TextureImporterFormat.AutomaticTruecolor;
    26.     }
    27. }
    You place it in a folder named "Editor" in your project and it sets the default texture import values for all the sprites you add to your project. Very handy compared to having to set them manually for every single sprite.

    Changes for version 0.2.0:
    • Added the axe. Use it to cause global warming.
    • You can now chop down trees and use the logs that drop to build rafts and bridges.
    • This means the entire world should be explorable now.
    • Added the ambient wind sound. It feels a bit louder in Unity than in GameMaker. Not sure if it's just me or if there's a difference there.
    • Removed the debug visuals, they are no longer needed.
    More interesting discoveries:
    • The tilemap in Reap is offset so the player is actually walking on the corners between the tiles rather than in the middle of the tiles (this is visible in my screenshot from version 0.1.0). This means that when you chop down a tree you're not interacting with just 1 tile, but with 2x2 tiles. I still don't know why it's done this way, but I'm sure it has something to do with the very sleek algorithm used for finding the correct neighbour tiles.
    • GameMaker has a special keyword called "with" which allows you to very easily run code on all instances of a prefab. What I'm doing in Unity to approximate this is to keep track of all instances of a prefab in a list and then iterate over that list wherever the original code uses "with". It seems to work fine, but it obviously requires quite a bit more code than the GameMaker alternative.
     
    Last edited: Jan 24, 2016
  7. GarBenjamin

    GarBenjamin

    Joined:
    Dec 26, 2013
    Posts:
    7,441
    I'd just make a wrapper function using the name irandom_range() that adds one to the max value. Then use that function for everything and you can basically copy and paste without needing to be sure you are continually incrementing the max value. Just something to consider.
     
  8. Farelle

    Farelle

    Joined:
    Feb 20, 2015
    Posts:
    504
    thats awesome :) it's one of the games I enjoyed alot to playtest :D
     
  9. TwiiK

    TwiiK

    Joined:
    Oct 23, 2007
    Posts:
    1,729
    Yeah, I could do that, but that would be more work than putting on a +1. :p Anyways, I'm making this for people who use Unity, but I'm commenting the source code sort of as if you were switching from GameMaker to Unity or had experience with both engines. I'll do an evaluation of the entire project before I release it to see what makes the most sense. At the moment the Unity source code is probably ~90% identical to the GameMaker source code and if it stays like that I'll probably keep Daniel's original naming conventions etc. just to keep the two sources as identical as possible, but if it turns out I have to make big changes to make it work in Unity I may just refactor everything to use my own naming conventions.

    At the moment I'm also making an effort to stay as faithful to the original GameMaker source as possible, even in places where Unity offers tools that perhaps make more sense. Like for instance the "with" statement. In Unity I could use triggers, bounding boxes or raycasts to find the item I'm standing on, rather than looping over all the items in the world to see if there is one under my feet, but it's fun trying to replicate the original exactly. :)

    Thanks, yeah, I played through most of the top 100 games and this one really stood out to me as something special. After playing it I started following Daniel on Twitter, checking out his website etc. and he's constantly making amazing games. :p
     
    GarBenjamin likes this.
  10. TwiiK

    TwiiK

    Joined:
    Oct 23, 2007
    Posts:
    1,729
    Version 0.3.0 is out!

    http://twiik.net/projects/reap-unofficial-unity-port

    No new content has been added in this version, but I've polished everything up quite a bit and I've put down a lot of the foundation for completing the rest of the game. I've added controllers for handling animations and sounds among other things.

    For the animations I knew I didn't want to mess around with Mecanim. I've tried that before and it was awful. But as it turns out, making my own sprite animator wasn't much work at all, and best of all it supports some of the same tricks that GameMaker and the original Reap utilizes. Here's the code for it in its current form. I will surely tweak it some before I'm done with the game:
    Code (CSharp):
    1. using UnityEngine;
    2.  
    3. public class SpriteAnimator : MonoBehaviour {
    4.  
    5.     [System.Serializable]
    6.     public class Animation {
    7.         public string name;
    8.         public Sprite[] frames;
    9.     }
    10.  
    11.     public Animation[] animations;
    12.  
    13.     // Set this to control the speed of the animation.
    14.     [HideInInspector]
    15.     public int fps;
    16.     // Set this to control the animation to play.
    17.     [HideInInspector]
    18.     public string currentAnimationName = "";
    19.     // Set this to control the current frame of the animation. F. ex. setting
    20.     // fps to 0 and this to 0 let's us show only the initial frame of the animation
    21.     // for as long as we wish.
    22.     [HideInInspector]
    23.     public int currentFrame;
    24.     // The default sprite is the one we've assigned to the sprite renderer.
    25.     // Store it here so we can put it back later if we need to. We'll lose the
    26.     // one on the sprite renderer when we play an animation.
    27.     [HideInInspector]
    28.     public Sprite defaultSprite;
    29.  
    30.     SpriteRenderer spriteRenderer;
    31.     Animation currentAnimation;
    32.     string lastAnimationName = "";
    33.     float timer;
    34.  
    35.     void Start() {
    36.         spriteRenderer = GetComponent<SpriteRenderer>();
    37.         defaultSprite = spriteRenderer.sprite;
    38.     }
    39.  
    40.     void Update() {
    41.         // Don't do anything if there is no animation assigned.
    42.         if (currentAnimationName == "") {
    43.             return;
    44.         }
    45.  
    46.         // If the name for the current animation is different from the animation
    47.         // we played last frame it means we should swap the animation we're playing.
    48.         if (currentAnimationName != lastAnimationName) {
    49.             SetAnimation(currentAnimationName);
    50.         }
    51.  
    52.         // This is a really clever way of handling looping.
    53.         // Taken from GameMaker, and inspired by Daniel Linssen's code.
    54.         currentFrame = currentFrame % currentAnimation.frames.Length;
    55.  
    56.         // If the framerate is zero don't calculate the next frame, just keep
    57.         // returning the current frame. We can change the current frame
    58.         // from outside this script and animate the sprite this way as well.
    59.         if (fps == 0) {
    60.             spriteRenderer.sprite = currentAnimation.frames[currentFrame];
    61.             return;
    62.         }
    63.  
    64.         timer += Time.deltaTime;
    65.         if (timer > (1f / fps)) {
    66.             timer = 0;
    67.             spriteRenderer.sprite = currentAnimation.frames[currentFrame];
    68.             currentFrame++;
    69.             lastAnimationName = currentAnimationName;
    70.         }
    71.     }
    72.  
    73.     void SetAnimation(string name) {
    74.         foreach (Animation animation in animations) {
    75.             if (animation.name == name) {
    76.                 currentAnimation = animation;
    77.             }
    78.         }
    79.     }
    80. }
    It's almost no code at all, but it works almost perfectly in my opinion. The coolest thing about it is the looping mechanism, which for all I know may be the standard way of doing something like this, but it surely wasn't my initial approach. Rather than writing something like:
    Code (CSharp):
    1. if (currentFrame >= currentAnimation.frames.Length) currentFrame = 0;
    which in fact was my initial approach I'm instead using the modulus operator to loop the animation. The reason I started investigating this at all was because the code in the original game was asking for frames 0-20 when it was animating a 3 frame animation. How this could work at all made no sense to me until I found a section about it in the GameMaker documentation. It described that asking for frame 4 in a 3 frame animation would return frame 1, asking for frame 6 would return frame 3 and so on. It just counts over the frames like 1,2,3,1,2,3 until it reaches the frame number you asked for. And using the modulus operator gives me this exact functionality. It has no downsides and it makes it a whole lot easier to animate certain things. The axe swinging animations uses this functionality.

    To use the sprite animator just put it on a game object with a sprite renderer. And then to play the different animations you do something like:
    Code (CSharp):
    1. if (_v < 0) {
    2.     spriteAnimator.currentAnimationName = "s_player_south";
    3. }
    4. else if (_h < 0) {
    5.     spriteAnimator.currentAnimationName = "s_player_west";
    6. }
    7. else if (_h > 0) {
    8.     spriteAnimator.currentAnimationName = "s_player_east";
    9. }
    10. else if (_v > 0) {
    11.     spriteAnimator.currentAnimationName = "s_player_north";
    12. }
    where _v and _h are the values returned from Input.GetAxis. To control the speed you just set the fps. Set it to 0 when you're standing still and to whatever value you like when you're moving. It's just as simple as it is in GameMaker which is what I wanted. That is one way of animation your sprite, but you can also animate the sprite by setting the current frame directly, which is what I'm doing for the axe swinging animation, just like in the original GameMaker version of the game.

    My biggest gripe with 2D and sprites in Unity so far is the fact that a sprite in Unity is just 1 frame of a sprite and not the entire sheet. There doesn't seem to be any way to get a reference to the entire sheet. With the current method whenever I change anything in my animation like for example add a new frame or reorder the frames I have to add all the frames to my public variables in the inspector again. I just don't understand why Unity decided to do it this way.

    Ohh, and I also figured out why audio was much louder in Unity than in GameMaker. You set the volume directly on the audio clips in GameMaker. You set them by dragging a slider between what I assume is 0 and 1, but there is no label on the slider so I've had to guess what volume I should set each sound to in Unity, but at least it sounds a lot nicer now and a lot more like the original.

    Changes for version 0.3.0:
    • Added a custom sprite animator script so I won't have to mess around with Mecanim and the dope sheet.
    • Added animations to the player and the axe.
    • Added most of the sounds in the game.
    • Fixed the raft movement.
    • Reordered some of the sprites to make them appear correctly behind and in front of the player depending on the context.
     
    Last edited: Jan 28, 2016
  11. Farelle

    Farelle

    Joined:
    Feb 20, 2015
    Posts:
    504
    hm not sure what you mean with "you can't get reference to whole sheet" I was quite sucessfully using a sprite sheet with unity and it was holding all my animations which I imported as a (quite huge) sprite sheet and I could then define in unity which sprites from that sheet it should use :eek: and I was able to reimport the sheet and just reassign those which I had changed or maybe I missunderstood what you mean, but it doesn't seem right that unity would make this more difficult...
     
  12. TwiiK

    TwiiK

    Joined:
    Oct 23, 2007
    Posts:
    1,729
    @Farelle I mean if I make a public variable like:
    Code (CSharp):
    1. public Sprite sprite;
    I can only assign 1 frame of my sprite animation to that variable. If I try dragging the entire sprite sheet onto the variable in the inspector Unity still only assigns the first frame. So the only way for me to get a reference to the entire sprite animation is to define it as:
    Code (CSharp):
    1. public Sprite[] sprites;
    and drag all the individual frames to the variable, but then every time I make a change to the sheet I will have to update the reference because I'm not referencing the sheet, I'm referencing specific frames in the sheet. In GameMaker you reference the sheet and then say that you want frame 0, frame 1, frame 2 etc. I don't understand why we can't do that in Unity.

    I was thinking that if a sprite in Unity held a reference to the entire sheet then we could do things like sprite.index[0] to get the first frame, and ideally we would be able to set things like framerate etc. directly on the sprite renderer to animate our sprites. I don't feel like this would have many downsides, but it would make it a whole lot easier to work with sprite animation in Unity. The sprite renderer could assume a framerate of 0 and show the first frame of the sprite by default to ensure todays functionality is kept intact. At least in my opinion. :)

    A workaround I thought about was to change my code to:
    Code (CSharp):
    1. public Texture2D spriteSheet;
    and assign the texture (my sprite sheet) to this variable, and then in code programatically create the individual frames as sprites, but that means bypassing the entire sprite importer and sprite editor and it will only work if I'm using grid based animation so it felt too hacky. :p
     
    Last edited: Jan 29, 2016
    GarBenjamin likes this.
  13. Farelle

    Farelle

    Joined:
    Feb 20, 2015
    Posts:
    504
    how about you turn the frames you choose into an animation? and go from there?
     
  14. TwiiK

    TwiiK

    Joined:
    Oct 23, 2007
    Posts:
    1,729
    I'm sorry, but I don't know what you mean by that.
     
  15. Farelle

    Farelle

    Joined:
    Feb 20, 2015
    Posts:
    504
    okay what I mean is, that whenever you create a spritesheet in unity you can open all it's frames inside your asset folder by clicking the little arrow on it and then you can shift+left click to select all the frames you want and then rightclick and "create animation"
    it creates an animation file which includes those frames you selected and as far as I know, then you can use Animationclips: http://docs.unity3d.com/ScriptReference/AnimationClip.html

    to define framerate, to play it etc.

    then you would only need to update the animations which frames you changed in a sprite sheet.

    I should mention that this approach is best used with making an animation file for every movement you want from a spritesheet to gain the most out of it, so not making the whole spritesheet into an animation :p
     
    Last edited: Jan 29, 2016
  16. TwiiK

    TwiiK

    Joined:
    Oct 23, 2007
    Posts:
    1,729
    Yeah, that's the approach I meant when I initially mentioned Mecanim and the dope sheet. To each his own I guess, but I feel that way of doing it was very clumsy. I have an older project where I tried doing it like you describe, but in my opinion the way I'm doing it here in Reap is much faster and more intuitive. It's just missing a few tiny features. :p

    Perhaps it's possible for me to create my own asset type or something in Unity, but I have never tried doing something like that. It's perhaps also possible to extend the default sprite renderer to make it include my sprite animator functionality or something like that as well, but these are advanced topics that I haven't explored yet, and probably won't bother to explore with this project.

    But the thing you say about having a big sprite sheet and not wanting to make the entire thing into a single animation is a good point. For this project I'm using the original art files and each animation is a separate sprite sheet. I like this way of doing it as it's very organized, but I agree but both ways would have to be supported. I guess Unity's current implementation support them both equally well/bad. :)
     
    GarBenjamin likes this.
  17. GarBenjamin

    GarBenjamin

    Joined:
    Dec 26, 2013
    Posts:
    7,441
    I am glad I am not the only one who finds that animation system very tedious to work with. It is far simpler to just code it up. I just define arrays of Sprite for the anims and load them in the editor. Then it is super easy to animate everything exactly as you want in code by defining animation tables. Certainly more efficient than working in the editor to do it or at least for me (and apparently you) it is.
     
    JoeStrout likes this.
  18. sngdan

    sngdan

    Joined:
    Feb 7, 2014
    Posts:
    1,154
    Farelle, JoeStrout and GarBenjamin like this.
  19. GarBenjamin

    GarBenjamin

    Joined:
    Dec 26, 2013
    Posts:
    7,441
    JoeStrout likes this.
  20. JoeStrout

    JoeStrout

    Joined:
    Jan 14, 2011
    Posts:
    9,859
    I'm glad somebody found that article useful! Yes, I agree, in a case like this it is much easier to just take control of the sprite frames yourself. Unity's animation system is very powerful, particularly if you need to animate colliders or sub-objects of any kind, but for a lot of games (like this one) you don't need all that.
     
    GarBenjamin likes this.
  21. TwiiK

    TwiiK

    Joined:
    Oct 23, 2007
    Posts:
    1,729
    Wow, that looks like a comprehensive article. Thanks. I'll take a look at it when I get home.
     
    JoeStrout likes this.
  22. Farelle

    Farelle

    Joined:
    Feb 20, 2015
    Posts:
    504
    yay more information :D that article is great and now I learned something new also :)
     
    JoeStrout likes this.
  23. TwiiK

    TwiiK

    Joined:
    Oct 23, 2007
    Posts:
    1,729
    Version 0.4.0 is out!


    http://twiik.net/projects/reap-unofficial-unity-port

    For this version I did a lot of refactoring to make it easy to add the remaining items, while staying as true as possible to original code. I've added all the items now I think, but only the map has functionality, the rest can only be picked up and dropped.

    Just like with the world generator I was able to more or less directly copy-paste the code for the map from GameMaker into Unity. In GameMaker the map is drawn to a surface, but in Unity I'm drawing it to a texture using SetPixel() and then I create a sprite from that texture.

    I have a couple of really challenging tasks ahead of me now and it would be amazing if anyone has any tips for me on how to solve them:
    1. The map is missing the markers for the pieces of the treasure map (the "goal" of the game). These markers are sprites and I need to find a way to place these into my map texture, "splat" is perhaps the correct term?
    2. I need to draw a lot of lines, circles etc. for the UI that are confined to the pixel grid, ie. no anti-aliasing and sub pixel stuff. I have no clue how to draw like this in Unity, but I'm guessing I need to access some low level stuff like this (http://docs.unity3d.com/ScriptReference/GL.html)?
    3. I need like a vignette shader that is confined to the pixel grid to simulate the peephole-functionality of the original game. I have no clue here, but I'm guessing I can find some help regarding the pixel grid stuff in the built-in sprite shader seeing as it has a "pixel snap" option.
    I would really appreciate it if anyone had any tips or pointers regarding the above problems as I fear I will be spending a lot of time trying to find solutions for these. :)

    Changes for version 0.4.0:
    • Added the map. Hold the use key while holding it to view it. The only thing missing is the markers for the pieces of the treasure map.
    • Added all the remaining items as well, I think. You can pick them up and drop them, but their functionality is not implemented yet.
    • Changed the game resolution to 1280x720 to stay true to the original game. I'll begin working on the UI soon and I want to make sure I'm working at the correct resolution from the start.
    More interesting discoveries:
    • GameMaker has a special shorthand for for-loops called repeat. You just write repeat(x) {} and the code within the brackets is repeated x amount of times. In Unity I've replaced this with for-loops, obviously.
    • GameMaker also supports includes so you can pile all the code for something like the player onto the player object(prefab), but by separating the code out into separate scripts that are included where they are needed the whole thing ends up looking fairly neat. C# does not support this and my scripts are starting to become very long. In the future I will break it up into separate classes to alleviate this. I use PHP at work, which also supports includes, and I like them. :( I'm still not very familiar with object oriented programming.
     
    Last edited: Jan 31, 2016
    GarBenjamin and Whiteleaf like this.
  24. Farelle

    Farelle

    Joined:
    Feb 20, 2015
    Posts:
    504
    regarding the vignette shader, have you looked into UI mask? it may give you what you want :D
     
  25. TwiiK

    TwiiK

    Joined:
    Oct 23, 2007
    Posts:
    1,729
    Thanks for the tip. I looked at it now and I don't think I can use it as is, but it seems to be using stencil buffers/shaders which is probably what I want, but I've spent a few hours now fiddling with it without getting anywhere. I guess this can take a while. :p

    The problem is obviously that I have no clue how to write shaders so I'm just googling and copy/pasting other peoples code trying to make something happen, but I guess I actually have to read up on this and try to make something from scratch.
     
  26. Farelle

    Farelle

    Joined:
    Feb 20, 2015
    Posts:
    504


    maybe this can help :D
     
  27. Farelle

    Farelle

    Joined:
    Feb 20, 2015
    Posts:
    504
    okay so I tested it to try out if that could work and tadaaa it did :D

    so what I did is I created a new image in photoshop set first layer to transparent and second i filled with white,
    then I created a layer mask and made a circle gradient from black to white (middle as black), I'm pretty sure this works also by just cutting a hole into the white surface with heavily blurred edges to have that gradient effect.
    then I saved that image as png with transparency into my unity asset folder.
    In Unity I was setting up a new Material which I set to Unlit/Transparent Cutout and added my texture into it. Now I could use the alpha cutoff to make it appear as if the circle closes and opens :D (this can be modified by script btw)
    Then I created a new Image in the scene (for canvas) and added for source image my texture and for material the one I had just created. Then made sure that the images position is on 0,0,0 and then happy circling :D the material cutoff works directly on the image inside the canvas aswell :) so now you should have it on your screen and even as ui element :D
     
  28. JoeStrout

    JoeStrout

    Joined:
    Jan 14, 2011
    Posts:
    9,859
    Not if you use PixelSurface. :) Splat textures into your pixel-perfect surface (just as you do in GameMaker!) using DrawTexture. Use FillRect, FillEllipse, and DrawLines to draw lines. When you need to get or set individual pixels, you can very efficiently do that too.

    It's designed for exactly this sort of thing, precisely because the built-in functionality of Unity doesn't make it very easy. And if you find there is any functionality lacking, just let me know — I'm eager to make it better.

    And for the vignette, if I understand correctly what you want, I would simply layer a second PixelSurface in front of the first, and draw a nice transparency gradient (perhaps using a series of FillEllipse, or using SetPixel with a function based on distance from the center) in that.

    Best,
    - Joe
     
  29. TwiiK

    TwiiK

    Joined:
    Oct 23, 2007
    Posts:
    1,729
    @Farelle Thanks for the link and the mini tutorial. :)

    But I think I would really like to avoid using a texture for the effect as I consider that a bit of a hassle, and I think it will be really hard to control. So far I've managed to programatically draw a circle in a shader although I'm not entirely sure which part of the shader that does it, but I guess I only need a cutout shader, not a stencil thingy, it's probably easier for me as a complete shader noob to fiddle with a cutout shader.

    @JoeStrout That does look neat, but I'm giving this project away with full source code so I guess I need to figure something out myself. Perhaps I'll consider buying it to learn from it, but I'll consider that a last resort. :p

    Great article by the way, I finally read it. I'll add it to the collection on my website when I have some time.
     
    JoeStrout likes this.
  30. JoeStrout

    JoeStrout

    Joined:
    Jan 14, 2011
    Posts:
    9,859
    OK, that's a good point. You can't generally open-source Asset Store plugins (including mine ;)).

    Well, in the end it is fundamentally just textured quads. You've already found GetPixel/SetPixel, which are easy to use though not terribly efficient. You want to do things like batch SetPixel calls so you only call Apply once, or use SetPixels to set many at one time.

    Unity doesn't have any drawing routines (lines, curves, etc.) for textures built in, so you'll need to look up how those are done (see here for example).

    One thing's for sure: you're going to learn a ton from this project, and definitely level up your skills!
     
  31. TwiiK

    TwiiK

    Joined:
    Oct 23, 2007
    Posts:
    1,729
    @JoeStrout Thanks for the tips and I'm sure you're right, that is if I'm able to complete the project at all. :p I knew going in that some parts would be tough, especially if my goal is to perfectly recreate the original game, which is obviously is.



    The UI and the day night cycle is coming along, but I just realized my motion is much smoother than in the original game. At first I couldn't understand why because there is no sub pixel movement there, but then I realized that when you define 1 pixel to be 2x2 pixels in GameMaker then that's actually how all the game logic and everything behaves, but in Unity you only render it that way, everything still moves according to the normal pixels which are "half pixels" compared to the rendered output.

    Not sure how to best fix this. I'm thinking either some render texture trickery or actually define my own rounding functions which rounds everything to even pixels or something like that. :p
     
    GarBenjamin likes this.
  32. TwiiK

    TwiiK

    Joined:
    Oct 23, 2007
    Posts:
    1,729
    Now we're getting somewhere.



    @Farelle Thanks again for the tip about the cutout shader. I'm doing this with an UI image with a cutout shader on it now. Now I need to figure out how to get the black outline and how to render stuff at 2x2 pixels.
     
  33. Farelle

    Farelle

    Joined:
    Feb 20, 2015
    Posts:
    504
    hm....maybe it could be simply a circle (line)image without any filtering(to keep the pixelated look) and transparency put on top which you could just adjust it's scale? or you create it with the same technique with the cutout shader, rendered behind the current one and being always a little bit more closed then the top one to create an outline effect.




    btw.: I wished I would have the same easyness making POCs for your game, for my own game XD bleh, even though your game project is definitely not easier XD
     
    Last edited: Feb 2, 2016
  34. Hormic

    Hormic

    Joined:
    Aug 12, 2014
    Posts:
    251
    have you stopped with porting further?
     
  35. TwiiK

    TwiiK

    Joined:
    Oct 23, 2007
    Posts:
    1,729
    Heh, a bunch of people have e-mailed me and asked that same question.

    Most of my hobbies are very passion driven and I lost the interest for Unity back in February. This happens at least a couple of times a year for me so it's nothing new. Usually it's a cool tutorial or something that brings me back, but the last few days I've actually been updating Unity and the project to the latest version and I've at least opened it again. I'm trying to figure out where I left off and what's left to do. Once I figure that out I'll try to restart it again and finish it.

    So hopefully you'll hear from me sooner rather than later. :)
     
    GarBenjamin and Hormic like this.
  36. Hormic

    Hormic

    Joined:
    Aug 12, 2014
    Posts:
    251
    That is very nice to hear. It is a cool gameidea and very intersting to see how you develop it in unity.

    And i also have to say thank you very much to your stealth tut port, great work!!! :)
    It was the first tutorial i accomplished using unity and it's a great example which you have made nicer and more polished than the original.
     
  37. TwiiK

    TwiiK

    Joined:
    Oct 23, 2007
    Posts:
    1,729
    Version 0.5.0 is out!


    http://twiik.net/projects/reap-unofficial-unity-port

    I feel like I've finally gotten the ball rolling again and I'll try my best to keep this momentum going. I know this update was small, but I had to reinstall GameMaker, learn it again, refactor a ton of code and get comfortable with Unity again to make this happen. The next update will be more substantial and will happen quicker.

    I know I was working on the cutout shader and proper pixel scaling when I stopped many months ago, but I just had to comment all that out to be able to get back into this project again because I just didn't remember anything about it. I may just postpone that until the end because it's definitely the hardest part of this project. I'll implement all the systems and game functionality first.

    Changes for version 0.5.0:
    • The gamepad triggers are working just like in the original game now. At least for xbox 360 controllers on Windows as that's all I've tested.
    • The turnips and logs now have random sprites for when they are dropped.
    • All the items have proper sprites and positioning for when they are carried now.
     
    GarBenjamin and Hormic like this.
  38. Hormic

    Hormic

    Joined:
    Aug 12, 2014
    Posts:
    251
    hey great that you are on track again! :)
    I also think it's better to focus on the gameplay aspects in the first place and postpone the graphical details for the finetuning at the end.
     
    GarBenjamin likes this.
  39. TwiiK

    TwiiK

    Joined:
    Oct 23, 2007
    Posts:
    1,729
    Version 0.6.0 is out!


    http://twiik.net/projects/reap-unofficial-unity-port

    Almost every item can be interacted with now. The only major gameplay functionality that remains is for you to be able to look at the completed treasure map and locate and dig up the treasure so you win the game. Apart from that there's a lot of visual polish and I have to implement time, food and energy.

    Changes for version 0.6.0:
    • The shovel can now be used to dig the ground for planting turnips.
    • Turnips can now be planted. They don't grow because there's no implementation of time yet.
    • Turnips can be eaten. They don't do anything because food isn't implemented as a stat yet.
    • The markers for the treasure map pieces are now drawn on the map.
    • The treasure map can now be assembled if you gather all 4 pieces. It can't be interacted with yet.
     
    GarBenjamin and Hormic like this.
  40. TwiiK

    TwiiK

    Joined:
    Oct 23, 2007
    Posts:
    1,729
    Version 0.7.0 is out!


    http://twiik.net/projects/reap-unofficial-unity-port

    Everything is basically in the game now. The only thing missing is the survival aspect with food and energy and the polish.

    For this version I spent a ton of time trying to match every single particle effect exactly to the original game. I had to rewrite my custom sprite animator script to be framerate dependent to get the results I wanted, but as a result my port is now even more similar to the original game.

    I also made the first "major" change to my port compared to the original GameMaker game. In the original game the treasure map is created by running a nearly identical version of the world generation for a small section of the map and then saving that as a sprite. There's no reason I couldn't do the exact same thing in Unity, but from the start I knew I wanted to try doing it with a render texture because I've never tried that before. In my version I just position a second camera over the treasure chest and then set it's viewport to be 160x160 pixels just like in the original game and then render what that camera sees to a sprite. This was very simple and much less code than in the original game. As a bonus it also ensures that all the trees, rivers etc. are identical on the treasure map and in the game world, while in the original game they use different sprites because they are generated with different randomization seeds.

    Changes for version 0.7.0:
    • You can now view the treasure map and use it to find and dig up the treasure to win the game.
    • All the particle effects have been added.
    • Turnips can be reaped with the hoe. They still don't grow, but you can recover the one you planted.
    • The bridges are now animated.
    • I've rewritten my custom sprite animator script to be framerate dependent to ensure everything is as similar as possible to the original game.
     
    GarBenjamin and Hormic like this.
  41. Hormic

    Hormic

    Joined:
    Aug 12, 2014
    Posts:
    251
    wohoo great work Twiik, seems its not far from finishing! I will have a look this weekend! :)
    Great and also logical idea with the Treasure Cam! From my point of view, there is no reason to do all things exactly the same way, as the original, when the gameplay is as fun and entertaining.
     
  42. GarBenjamin

    GarBenjamin

    Joined:
    Dec 26, 2013
    Posts:
    7,441
    This has been very interesting reading and honestly it has me tempted to take a look at the Gamemaker Studio I bought on sale last year. Been sitting on my hard drive all of this time. The behind the scenes view you have provided during your porting process makes it seem like GM is much more logical and straightforward for 2D game dev.

    I get that wasn't your intention. Just the impression I have from reading all of this ^^^^

    Although at this point I have Unity working basically the same way. So I'll let GM gather dust for a while longer.
     
  43. TwiiK

    TwiiK

    Joined:
    Oct 23, 2007
    Posts:
    1,729
    In general I completely agree, but this was an exercise for me just to see how similar GameMaker and Unity were and whether or not I can port a game more or less straight across between the two engines, a game that is not well suited for Unity's 3D environment at all no less. Some of my favorite games are pixel art 2D games and I'm sure I'm not alone. Obviously GameMaker is a lot more suited for making such games, but I'm trying to prove to myself that it's not that hard in Unity either if you just know what you're doing. And the 3D environment gives you the option of doing many neat things that would be near impossible to do in GameMaker.

    GameMaker does have some really neat features for working with 2D, but if I were to switch to a more 2D oriented engine I think there are better, more modern options out there. I feel like there are a lot of archaic and weird things you have to work around in GameMaker. Like making sure your game is framerate independent seems to be a really hard thing to do and something almost no GameMaker developer bothers to do. In my mind it's ludicrous to have a game in 2016 that is framerate dependent.

    So far the stuff I'm having the most trouble with so far in my Unity port is ensuring everything is drawn at 2x scale. Especially when it comes to special shaders, UI, multiple cameras, render textures etc. It feels like everything has to be handled separately. It would be nice if I could just set my game to render to 640x360 and then tell it to output everything as 1280x720 when the game is played. Perhaps that is possible and I've just overlooked it? Now that I have a tiny bit of experience with render textures I'm starting to think that I could perhaps render the entire game screen to a render texture and try to scale that up 2x or something.

    And also drawing lines, circles and other things. The last part I haven't looked at yet, but I'm going to try and get all the UI in for the next version and I anticipate that it's going to be very problematic. Drawing random stuff to the screen in GameMaker or any 2D engine is a breeze by comparison.
     
    GarBenjamin likes this.
  44. GarBenjamin

    GarBenjamin

    Joined:
    Dec 26, 2013
    Posts:
    7,441
    I am surprised GM doesn't just run on a timer or even just run at 60 fps for updates on some sort of interrupt timer. Since that has been the standard for a long time for games (since like 35 years or so ago). Actually figured it might even have a developer selected target update rate as most stuff does these days.

    Anyway, the auto-scaling is easy in Unity. Just use the camera. You don't need a render texture. For example, in my 2D games I just camera to Orthographic and then set the size as desired. For example if you have size set to 128 and then you change the size to 64 everything will be double size (and that will be quite low res). Dropping it down to 32 will double the size again. You can target any resolution you want as far as the output goes.
     
  45. TwiiK

    TwiiK

    Joined:
    Oct 23, 2007
    Posts:
    1,729
    Yeah, that works for the main graphics, but shaders don't seem to respect that. If I draw a circle mask in a shader (like what I'm showing here: http://forum.unity3d.com/threads/im...-ludum-dare-34-game-reap.380830/#post-2493245) it uses normal pixels and not 2x2 pixels. And my second camera and render texture for the treasure map had to be set up independently of the main camera. I'm also struggling quite a bit with the UI and wondering if it's best to do that just with normal sprites or with the actual built-in UI. So it's quite a hassle and I still haven't solved the shader mask thingy. Everything in the game should use 2x2 pixels, and I feel like it shouldn't have to be something I worry about. I should just be able to work with pixels as normal and then tell the game to render at 2x scale in the end, or 4x or whatever I want, really.
     
    GarBenjamin likes this.
  46. GarBenjamin

    GarBenjamin

    Joined:
    Dec 26, 2013
    Posts:
    7,441
    Ah I see. Fancy stuff like that I won't need to deal with for quite a long time. It's only about 1980. If I needed to do that I'd have to come up with a way using tiles and / or sprites to simulate the effect. It is possible of course because some NES games did it.

    I don't know much about shaders and what I do know came from time spent last year playing around with Ogre3D.
     
  47. GarBenjamin

    GarBenjamin

    Joined:
    Dec 26, 2013
    Posts:
    7,441
    Actually... ya know... that'd be straightforward... two playfields. Mainly solid tiles on the foreground (in Unity could be a single image) and a square of empty tiles with tiles around the edge forming the circular shape. The back playfield is then scrolled around as needed.
     
  48. TwiiK

    TwiiK

    Joined:
    Oct 23, 2007
    Posts:
    1,729
    Version 0.8.0 is out!


    http://twiik.net/projects/reap-unofficial-unity-port

    All the wrapping has finally been added. The game now starts with the title screen, then shows the instructions while it's generating the world (which goes 100 times faster in Unity btw than in GameMaker *high five Unity*) and in-game you now have the UI telling you what each item does and the circle mask simulating your field of view throughout the day.

    I managed to the get the game rendering correctly at 2x scale by rendering everything to a render texture, outputting that to a quad and then using a second camera to show what's on that quad. Now even my mask shader and UI get's the correct 2x2 pixels. It's still a bit fiddly, but now it actually works and it's easier to use.

    However, I was actually ready to come here and rant and cry and ask for help because inside the editor this looks awful and runs awful. The UI jitters when I move the character (it lags behind) and when I open/close the maps the entire UI flashes and shows artifacts. I'm also unable to edit my UI in realtime inside Unity, I have to toggle my camera on/off to see the changes I've made. But when I finally made an actual build everything ran beautifully so I won't bother investigating this further at the moment. But it's not the best development experience to say the least. :p

    I need help with my shader
    My mask shader (I'm a complete noob with shaders) works almost the way it should, but the black outline isn't exactly 1px thick all the way around. I'm not sure how to approach that because everything in the shader is just floats and tresholds, there's no concept of a pixel in there as far as I can tell. Here's the entire shader. Be warned, it's just cut/paste from various sources with no real understanding of anything at all. :p
    Code (csharp):
    1. Shader "Custom/CircleMask" {
    2.  
    3.     Properties{
    4.         _Color("Color", Color) = (1,1,1,1)
    5.         _StrokeThickness("Stroke Thickness", Float) = 1
    6.         _StrokeColor("Stroke Color", Color) = (1,1,1,1)
    7.         _Radius("Radius", Float) = 0.5
    8.     }
    9.  
    10.     SubShader {
    11.         Pass {
    12.             CGPROGRAM
    13.             #pragma vertex vert
    14.             #pragma fragment frag
    15.             #include "UnityCG.cginc"
    16.  
    17.             fixed4 _Color;
    18.             Float _StrokeThickness;
    19.             fixed4 _StrokeColor;
    20.             Float _Radius;
    21.  
    22.             struct fragmentInput {
    23.                 float4 pos : SV_POSITION;
    24.                 float2 uv : TEXTCOORD0;
    25.             };
    26.  
    27.             fragmentInput vert(appdata_base v) {
    28.                 fragmentInput o;
    29.                 o.pos = mul(UNITY_MATRIX_MVP, v.vertex);
    30.                 o.uv = v.texcoord.xy - fixed2(0.5,0.5);
    31.                 return o;
    32.             }
    33.  
    34.             fixed4 frag(fragmentInput i) : SV_Target {
    35.                 float distance = sqrt(pow(i.uv.x, 2) + pow(i.uv.y,2)) * 2;
    36.                 if (distance < _Radius) {
    37.                     discard;
    38.                 }
    39.                 if (distance < (_Radius + _StrokeThickness)) {
    40.                     return _StrokeColor;
    41.                 }
    42.                 return _Color;
    43.             }
    44.             ENDCG
    45.         }
    46.     }
    47. }
    Changes for version 0.8.0:
    • The title, instructions and loading screens are now in.
    • Almost all the UI is in. The only thing missing is the energy and food meters.
    • The circle simulating your field of view is in, but it's not perfect yet because I'm a shader noob. The outline is not 1 pixel thick all around the circle.
    • I'm now rendering the entire game to a render texture which ensures everything including UI, shaders etc. output at 2x scale. This is super buggy in the editor, but seems to work perfectly fine in the final build.
     
    GarBenjamin likes this.
  49. TwiiK

    TwiiK

    Joined:
    Oct 23, 2007
    Posts:
    1,729
    I'm still struggling with getting clean lines and strokes. I managed to implement the energy and food meter using GL.LINES, but they suffer from the same issue as my mask shader.

    Here's an image I made in Photoshop illustrating the problem:


    Basically I want lines and strokes that are always 1 pixel thick. Is that possible in Unity? With GL.LINES I've experimented with using shaders with pixelsnap, but it still gives me these "blobs".

    The GL.LINES also appear above the UI. They should be below the "pin"-sprite on the energy and food meters, but I think that can be fixed by using different shaders or something. I haven't looked at that problem extensively yet.

    Funny side note, drawing lines like this in Unity is not actually that much harder than drawing lines in GameMaker. I was able to copy/paste the line drawing code from the original game almost directly across.
     
    Last edited: Aug 7, 2016
    GarBenjamin likes this.
  50. TwiiK

    TwiiK

    Joined:
    Oct 23, 2007
    Posts:
    1,729
    Version 0.9.0 is out!


    http://twiik.net/projects/reap-unofficial-unity-port

    The game is feature complete now, I think. But the issues with the lines still remain and for me that is a major source of irritation. :p I also noticed that in the actual build the line for the food meter isn't pixel perfect when the meter is full. These are massive issues as you can surely understand. I will probably release the project without them being fixed though because honestly, I have no idea how to fix them and if I release it one of you can fix them for me and tell me how you did it... if I'm lucky. :D

    I need to get in touch with Daniel again before I can release the final project and I want to clean it up a bit first as well.

    Changes for version 0.9.0:
    • Food implemented as a stat. You lose food every time you fall asleep. Eat turnips to regain lost food. If you run out of food you die and the game restarts.
    • Energy implemented as a stat. Doing anything costs energy. When your energy runs out you fall asleep until the next morning.
    • Implemented normal and hard difficulty. In hard difficulty days are shorter, you have less food, less energy and there are fewer resources on the map.
    • Time implemented. There's now a day night cycle and turnips grow.
     
    Last edited: Aug 20, 2016
    Hormic likes this.