Jump to content
  • Advertisement
  • entries
    27
  • comments
    62
  • views
    26065

It's Done!

Sign in to follow this  
JEJoll

1802 views

[font=arial]It's Done! Finally.[/font]


[font=arial]It's true! The game is complete! After a couple of (painful) weeks of waiting to hear back from sponsors, I'm sorry to say that I have (so far) been unsuccessful in securing sponsorship for the game. However, my primary goal for this game was simply to complete an entire project, so I'll consider this a success :D.[/font]

[font=arial]I'm not going to wait forever to hear back from sponsors, so at this point, I've decided to publish on my own. See a little lower for links to the game.[/font]

[font=arial]This project has been a pretty big challenge. Mind you, it wasn't a particularly hard game to develop (though I don't really have anything else as reference), but seeing it through to the end has been tough. To be honest, there were a lot of times where I was just sick of this game, and wanted to move on to other things. Many times I felt like the game was shit, and looking at the same damn blocks of color for nearly a year gets really frustrating at times. But I'm glad I stuck with it. I remember reading somewhere that whenever you finish a game, you'll never really be satisfied or happy with it. I kind of get that. I mean, I would have loved to secure a sponsor (there's still some time for that yet if I do well on release, however), and I wish it didn't take me so damn long. But I think I have to say that, for the most part, whoever wrote that probably just made shitty games :P.[/font]

[font=arial]When I originally had the idea for this game, I had planned to spend somewhere around two months on it. It was supposed to be a 'quick' game--one that I could just say I had finished. It's been somewhere around 10 or 11 months now.[/font]

[font=arial]There are a number of things that I attribute to the game's development taking so much longer than planned, the heaviest of which are feature creep (damn those of you who suggested exploding limbs :wink:), completely losing motivation and not touching the project for a couple of months, and my evidently horrendous time estimation abilities.[/font]

[font=arial]Let's comb through my previous posts in this journal for evidence shall we? (Cue the flashback music)[/font]

[font=arial]February 4, 2016:
[color=#282828]"If I'm lucky/diligent, hopefully I'll be done this bad boy by the end of February".[/color][/font]

[font=arial][color=#282828]March 23, 2016:[/color]
[color=#282828]"[/color][color=#282828]I can see the light at the end of the tunnel... The project is almost done, but I'm struggling to sit down and get it done."[/color][/font]

[font=arial]July 8, 2016:
[color=#282828]"[/color][color=#282828]Hopefully late July/early August I'll be done everything? So I'm getting excited to have my first game complete!"[/color][/font]

[font=arial]So there you have it. I really suck at time estimates.[/font]


[font=arial]Promoting[/font]


[font=arial]Since I'm talking about promotion, I suppose this is the best place to do this:[/font]

[font=arial]Pixel Zombie Shooter is the most amazing game you'll ever play! Seriously, you won't know what hit you! It's incredible! No one has ever made a game better than this one in the history of video games ever. And I'm being modest! Until you've played this game, you haven't truly lived! DO IT!!!! And check out this trailer:[/font]


[font=arial][color=#0000FF]
[/color][/font]


[font=arial]You can (and really should :P) play the game on Kongregate and Newgrounds. Also, if you do play, please take a quick minute to at least leave a rating. These sites base how much they promote a game based mostly on plays and ratings, so you'll really be doing me a solid if you leave a rating. If you have the time, a review would be awesome too![/font]

[font=arial]Ok, now that's out of the way...[/font]

[font=arial]I recognize the importance of promoting my game. If I just upload it to a site, someone might stumble across it, then someone else, someone might share it with a friend, etc., etc. But that's super passive, and really relying on chance. Any game needs exposure. And that's not just going to happen just by magic.[/font]

[font=arial]In my own efforts to promote my game and game company (Fidelum Games), I've started a [color=#0000FF]Youtube channel[/color] where I've been uploading weekly Unity tutorials, and where I've also posted the trailer you see above. In addition, I've linked to [color=#0000FF]Fidelum Games' Facebook page[/color] from said channel, where I post pretty regularly. I'm posting the tutorials in the hopes that people will 'stumble' upon my game trailer, and my Facebook page, where they can find links to the game and play it. If you feel like helping me out, give my Facebook page a like, and share the most recent post about the game's release. It really does make a big difference. Just one share gets it in front of hundreds of people who wouldn't see it otherwise. Just imagine what would happen if everyone who read this shared it! Look, I'll even make it easy for you: SHARE ME[/font]

[font=arial]Now let's talk about some more interesting stuff.[/font]


[font=arial]Tying Up Loose Ends[/font]


[font=arial]I've been quiet over the last few months, focusing on getting the last 'small' details of my game worked out and implemented.[/font]

[font=arial]In my last update, I provided a list of tasks that I set for myself to complete for the beta/test version, and I haven't been back on to talk about it since. For sake of completeness and continuity, I'll talk a bit about that.[/font]

[font=arial]The list I gave myself was as follows:[/font]


  • Implement Headshots
  • [font=arial]More enemy variants[/font]


  • [font=arial]Having my 'Blood Bird' (a crow variant) affect the player's move speed and jump height.[/font]


  • [font=arial]Fixing an accuracy bug[/font]


  • [font=arial]Game ending (The player riding away on the bike when it's repaired)[/font]


  • [font=arial]Playtuning:[/font]


  • [font=arial]Rate of currency accumulation[/font]


  • [font=arial]Cost of weapons, ammo, upgrades and medkits[/font]


  • [font=arial]Upgrade values (weapon damage, accuracy, capacity, fire rate, etc.[/font]


  • [font=arial]Rate of experience accumulation and levelling curve[/font]


  • [font=arial]Ability values (how much damage does the Iron Skin ability negate, how fast should the Fast Feet ability make the player move?, etc.)[/font]


  • [font=arial]Enemy Health and Damage[/font]


  • [font=arial]Wave Tuning (Number of enemies in each wave, types of enemies in each wave, number of predefined waves, infinite wave generator)[/font]


  • [font=arial]Bike repair speed[/font]



    [font=arial]I gave myself 8 days to complete these tasks, and with the exception of the game ending, I was successful. I added the changes, and sent the link to the build to testers just after midnight on the 16th of July (so I missed my deadline by a couple of minutes).[/font]

    [font=arial]Implementing Headshots[/font]

    [font=arial]RjQ1f31.png[/font]

    [font=arial]When I first thought about implementing headshots, I thought that I would just use another collider as a child object to the enemy's main GameObject, and whenever collision occurred on said object, I would send a message upward to the parent to take double damage. Of course, as with most things in life, this didn't go exactly according to plan.[/font]

    [font=arial]After some fiddling, I realized that all collisions occurring anywhere within my Enemy's GameObject hierarchy were being intercepted by the parent object. Apparently, this is the expected behaviour when a parent GameObject has a Rigidbody and Collider attached. So, because of this, my original solution wouldn't work. However, I didn't have to start from scratch.[/font]

    [font=arial]I was able to keep the child Collider, and rather than attach a custom Head script to it and look for that reference in my Projectile's OnCollisionEnter2D function, I started digging more into Unity's Collision2D class. It turns out that this class is good for a lot more than just things like[/font]

    void OnCollisionEnter2D(Collision2D col){ if(col.tag == "Enemy"){ col.getComponent().TakeDamage(damage); }}

    [font=arial]which tended to be similar to how I've used it in the past.[/font]


    [font=arial]Collision2D contains a number of useful properties that we have access to. Most of these have to do with information about the GameObject involved in the collision (such as references to the GameObject, it's Rigidbody, etc.), but the one that proved to be useful for my purposes was Collision2D.contacts. This property contains an array of ContactPoint2D objects, which have a 'point' property, which gives the location in space where the collision occurred. Because each of my enemy types are of a fixed height, I was able to check that the y coordinate of this value was above a certain limit. If so, headshot.[/font]

    [font=arial]

    Handling UI Updates; Lessons Learned

    [/font]
    [font=arial]In one of my earlier posts, I mentioned that I may have made a bad design choice when handling my UI updates. Originally, I had references to my Stats script (which holds properties for ammo, health, XP, Cash, etc.) inside of each of my UI classes. Then, these UI classes would just update their corresponding elements with whatever values they were interested in on every frame. It seemed to me that doing this every frame was bad practice and had the potential to be more processing intensive than necessary (not much, mind you, but still). So I decided to take an approach where the UI would only be updated when a stat value actually changed. This meant removing the references to Stats from my UI classes, and instead giving references to all of my UI classes to my Stats class, basically just inverting the relationship. Then, rather than call the UI update methods in the Update function, I would call them inside the methods that actually caused stats to change (TakeDamage, Fire, AddCash, etc.) This wound up being so disgusting that I decided to add another layer and bring in a UIManager class. This just wound up making everything more disgusting, and in the long run, my UIManager just wound up updating stats every frame anyway. What a disgusting waste of time. The end result is, from the outside, identical. Internally, however, it's probably worse in all ways imaginable.[/font]

    [font=arial]In hindsight, I should've just left it.[/font]

    [font=arial]I shudder at the thought of what the UML or something for my project might look like. Okay, you twisted my arm, here you go (those of you who are easily offended or prone to seizures, look away now):[/font]

    [font=arial]aUWie0S.png[/font]

    As you can see, I pretty much threw design out the window at some point on this project. This is completely unreadable and really makes me want to barf. There's circular dependency pretty much everywhere. It's just gross.

    For those of you who are interested, here is the diagram for just the UI and Upgrade related stuff, which is still pretty nasty:

    X0WZR6V.png

    [font=arial]Of course, as it always goes, now that I have finished the game, I figured out the perfect way to only update when required, and to do so cleanly and maintainably: Events and Delegates.[/font]

    [font=arial]Rather than store references to everything all over the place, polluting my code and making for poor structure, I could have many of my classes completely agnostic to one another. [/font]

    [font=arial]I could use events a delegates all over the place in my project (or any for that matter). They seem like a really great way to keep things clean and avoid storing a jillion references, especially when they're only needed once. However, the implementation I would need for my UI updates would be something simple like this:[/font]

    [font=arial]Stats.cs:[/font]//Create the delegate with the method signature which each UI class will implementpublic delegate void StatEventHandler(float currentStatValue, maxStatValue);//Create events which each UI class will subscribe to, and make them static to avoid the need of storing references to Statspublic static event StatEventHandler OnAmmoChange;public static event StatEventHandler OnHealthChange;public static event StatEventHandler OnXPChange;//Etc., etcprivate void Fire(){... ammoCount--; OnAmmoChange(ammoCount, maxAmmo);...}public void IncreaseAmmo(int amount){... ammoCount += amount; OnAmmoChange(ammoCount, maxAmmo);...}public void GainXP(float amount){... currentXP += amount; OnXPChange(currentXP, xpToNextLevel);...}public void TakeDamage(float amount){... health -= amount; OnHealthChange(health, maxHealth);...}public void Heal(float amount){... health = Mathf.Clamp(health + amount, 0, healthMax); OnHealthChange(health, maxHealth);...}//Etc., etc.
    [font=arial]Then in each UI class, I just subscribe to the event so that my UI class's UpdateUI function is called when these events occur.[/font]


    [font=arial]HealthUI.cs (or any UI class, slightly modified):[/font]Stats.OnHealthChange += UpdateUI;private void UpdateUI(float currentStatValue, maxStatValue){ healthText.text = statValue + " / " + maxStatValue; healthSlider.value = currentStatValue / maxStatValue;}
    [font=arial]Now stats doesn't have a reference to UI classes, or vice-versa, which makes things a lot cleaner. Also, UI elements are only updated when a change actually occurs. I think this is the perfect solution for this case. [/font]


    [font=arial]In fact, events and delegates seem like one of the most useful tools I've found thus far. I could envision a game where you can pretty much avoid storing references altogether (unless absolutely necessary), and rely on a custom event system to drive the game. I could even see this going a step further and having an EventManager class (potentially with subclasses) which acts as an intermediary. It would subscribe to events fired by other classes, but the only events that other classes would subscribe to are ones fired by EventManagers in response to the events that IT has subscribed to. [/font]

    [font=arial]Basically, EventManager would listen to all GameObjects which were firing events, and GameObjects would ONLY listen to EventManager. It seems that this would provide a nice centralized solution. Granted, this would introduce a different kind of circular dependency, but one that I think would be acceptable. I might try something like this on my next projects. Has anyone tried something like this, or know of some design pattern that functions like this? Please share your thoughts.[/font]

    [font=arial]That's really all I have time to write at the moment, but stay tuned for a proper post-mortem and some news on what I'll be working on next.[/font]

    [font=arial]And please, if you have the time, check out the game and leave a rating![/font]

Sign in to follow this  


5 Comments


Recommended Comments

Congrats on finishing, that's one of the hardest parts.

 

The Eventmanager type pattern is pretty common.  Main thing to watch out for is if you have a ton of stuff hooked up to an event, and you process your events as they come, you can get a sudden drop in FPS.  One way to work around that is to have the events go in a queue, and then have the event manager go through some number of events per update.

Share this comment


Link to comment

Sometimes UML charts can only display small sections of things to prevent poor illustration.

Share this comment


Link to comment

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

We are the game development community.

Whether you are an indie, hobbyist, AAA developer, or just trying to learn, GameDev.net is the place for you to learn, share, and connect with the games industry. Learn more About Us or sign up!

Sign me up!