Sonntag, 18. September 2016

6 Tipps Boosting Your Productivity With HackNPlan

The tool Hack 'N' Plan is a very sophisticated project managing tool made by gamedevs for gamedevs. I have been working with it for about 5 months and my productivity sparked ever since. I am more focused and notice when my game is suffering from the infamous scope creep syndrome.

In the following I want to present you 5 tipps how to work with this piece of software. These may work without making use of Hack 'N' Plan, too!


  1. Plan out the most important features first. Focus on those.

  2. Avoid spontaneously added tasks as much as possible.Bugs and improvements of existing code/assets are an exception. This serves mainly the purpose to prevent a scope creep. I know it's tempting to add one idea after the other, but like this you will never get your game done. Ever.

  3. Use the game model feature to set a design direction(e.g. game mechanics you want to have). This will be your focus. Do not add tasks that do not support your game model (except bug fixing)! Push them down the abyss of the forgotten mercilessly if you find any.



    Or just dump sidetracking tasks into a "unimportant brainfarts" milestone if you're not a ruthless task-murderer like me.



    In fact, I'm still trying to find a most effective way on how to use this.

  4. Make many milestones with small scope.Keep it 10 tasks and below, add a max of 5 tasks spontaneously (thus a maximum of 15 tasks in total). You need ruthless focus and this will help you establish it.

  5. Cut tasks into the smallest chunks.You don't have to (and shouldn't) plan out every detail of your project, but if you notice you need more tasks, make them small.

  6. Group together tasks that cover a similar topic.Not doing so has a chance of making you feel scatter-headed because you are jumping from one section in your code to the other. This is ok when you fix bugs, but not when you need focus to do progress.

    Do not make a clutter like this:



    ...but keep it more like this.



    Those are all UI-tasks I got done very quickly because I grouped them ruthlessly. Kept the scope of these tasks small, too.

I hope this helped with your gamedev endeavours. Keep on rocking, keep on coding!

How Introverts and Extroverts can get along

I have a very close friend of mine who I have been friends for almost a decade. We couldn't be more different, as he is mostly extroverted, a persuader, a good joke teller, and I am more of an introvert who is shy and withdrawn. But despite of that, we get along very well. Heres some tipps on how (these points may pose as dating advice too).


Extroverts dealing with Introverts Introverts dealing with Extroverts

Introverts need a lot of time to process what happens around them as they feel often uneasy and overwhelmed by a sudden influx of attention, or information. Give them time to think and process what you are saying. If you overload them too much, they may try to escape and avoid any further conversation. To them, this is the natural way of dealing with things. They may be able to react better and give you more useful information the next time as they may have processed the previous conversation and prepared themselves for it. So for you when discussing important issues, it may be better to approach them twice.
They also may say something to you, but the fact they are not repeating that doesn't mean they stopped thinking that way, e.g. when you do something they do not like. They won't say anything, but that doesn't mean they suddenly started liking it. When an introvert says something to you, you should generally take it seriously - they do not say it primarily to persuade or negotiate with you, they say it because it's the way it is. But even then, they may something very clumsily and come off wrong saying something completely different than they wanted to say. It's hard for them and it's even harder to read them right, but that's why it's important to communicate.
Not everything extroverts say is objectively truthful. They exaggerate or sugarcoat things to persuade you, get you into doing something, test you, figure you out, or simply to get out of trouble. That's not a bad thing at all - just a reminder for an introvert that they may say things that seem negative to you, when its them trying to gain your support or trust. Sometimes lying is the right way for them to do this, too. This may seem wrong from a introvert's point of view. From the outside, introverts often communicate on a very factual level, and want to say whats important and true, while extroverts focus on negotiating and persuading. I think that's something you can learn from an extrovert. Market yourself better!


Introverts only say something when its absolutely necessary, when it constructively contributes to the discussion, and when they want to enhance it with meaning. They are often quiet observers. They acknowledge what is being said, but they do not chose to comment on it. They enjoy having their thoughts for themselves as it deflects undesired attention that makes them feel uneasy. If you as an extrovert want to have a meaningful conversation with an introvert, you should chose a quiet place with not too many people around you, ideally just you and the introvert. If they feel comfortable with you, they may open up and tell you their deepest secrets. Once they are familiar with you, they will not get enough from your attention.
This is probably one of the hardest to understand for an introvert. An extrovert generally carries their thoughts and emotions outwards. So if an extrovert is mad or angry, they will let everyone know they are. But that's reckless and unfair to take out your anger on others, right? As long as they aren't taking it too far, no. It is really just the way they deal with their feelings and thoughts. They often don't even know what tumult they may cause in an introvert by directing their emotion towards them. So next time you find yourself in this situation ask yourself: did they really mean that or could they not find another way of processing their emotions?
The fact that introverts are easily overwhelmed with information, causes them to require a lot of time for themselves, putting a lot of energy to reflect and process what is happening around them. Because of this, introverts do not have this much energy and often appear lazy. They also do not like it when you tell them they are lazy - when in fact their mind is in a "healing state" of daydreaming, thinking about the world, and doing mind experiments in their heads. They need this to stay sane in this insane world. Since their attention and energy is so limited, its truly a gift to be in the world of an introvert. Extroverts like attention. A lot. They like to be around people because it gives them security and confidence. They love their community and are devoted to keep it strong and motivated. They enjoy hearing praise when they did a good job, because this is the language they speak. And that's exactly the catch as an introvert: How do you compete with all these people for an extrovert's attention? How do you do appreciate an extrovert's friendship when you're directing your thoughts and emotions inward? So the best thing you can do about maintaining a friendship with an extrovert, is to show or tell them you want them as a friend as often as you can (and feel is appropriate) by complimenting them, approaching them, offering them support etc. etc. I know for one that I often have positive thoughts about people, but I am voicing that too rarely. Be more open towards your extroverts. Of course, it has to be the right person in the right moment (which can be hard to figure out as an introvert) - but they will appreciate it.

Samstag, 27. August 2016

Vote & Help Developing CamoTactics!


Involving the gaming community is important making a great game. For this purpose I have created two polls that allow you to share your thoughts on CamoTactics.



Future Content


The first poll is all about future content to be added to the game. You can give it a shot on Google Forms. By filling this out you help me focusing on the feature you would like to play most. Make sure to share your ideas, no matter how silly they may sound! They may lead to other interesting ideas. :)

Your User Experience


The second poll is about your gaming experience with CamoTactics. If you played the game you can submit your feedback here on Google Forms. If you didn't play CamoTactics yet, go do it nao!


Happy voting and thank you for playing CamoTactics!


Freitag, 26. August 2016

Life is like Gamedev

It happens to me when I code all the time: Create something just to later discard it and start new from scratch. You make two steps forward just to make one step back again. It's frustrating sometimes.

Come to think of it, it's just like real life. Sometimes you're trying to make a change in your life, trying to adapt some habits, like trying to stick to your marketing schedule or diet plan. Then there's times when things happen, you slack and fall back to your old habits.

It's a bit like marble in a funnel that's slowly rolling towards the hole in the center. You're trying to roll towards the center, but sometimes you go too fast and bounce back to the outer edge. You do this until you finally achieve your final breakthrough: when your good habits finally stick and your code finally works (well... mostly ;) ).

Just like in gamedev.

So when you practice going through this with gamedev, it will likely spread over other parts of your life.

Code away, never stop creating and keep making awesome games!


Donnerstag, 25. August 2016

CamoTactics Arena Mode & Missions in 7.2!

Despite of delays because of real life stuff (I HATE moving twice within two months D;) progress was still made on CamoTactics!

Prepare your sitting device for new features, pics and gifs:



For one, enjoy feeding your foes some lead in arena mode! This isn't just a dummy feature, this has functionality and the character/weapon you've chosen will be carried into the arena.





Sail through the tutorial mission with ease! Missions now feature a very handy command line style trigger handling that lets you do almost anything on mission/objective start, success or failure. This is very important for the campaign of the game.





Your positional awareness is now provided by this very useful HUD aiming aid! You will see why you need this when moving around and shooting...





A few fixes and improvements include but are not limited to:

  • Better infantry graphics
  • Fixes for picking up items
  • Fixes for mounting vehicles
  • Fixes for wrong light positions
  • Faster renderer (very noticable if you compare it to 7.1)
  • Mission and Statistics Screen
  • Better Camouflage implementation
Making this game is a lot like wading in deep water not knowing what features fit and which to discard, considering a lot of that is experimental (not to mention lost time when discarding one). That process takes ages but the results are promising already and I have no doubt the end product will be amazing!

These features are to come very soon with CamoTactics Alpha 7.2. Until then, please check out CamoTactics Alpha 7.1 here:


CamoTactics Alpha 7.1

Samstag, 16. Juli 2016

Why PokemonGo is such a success

Only a few weeks in after its release, PokemonGo has become a hit for gamers world wide. It even goes so far that people are paying less attention and getting themselves hurt and deputies making demands to regulate the game.
 
But what exactly made it such a success?

First off, the player base of Pokemon is huge. Pokemon has been around for decades and influenced generations of gamers and accumulated a vast following during that time. It's a game that can be played with your smartphone everywhere at anytime (that is if the servers aren't shitting the bed). Another side effect is, you also connect with people as they venture to the same Pokemon hotspots as you.

While the gameplay isn't much at the moment, it still taps into the desire of discovery and collecting all Pokemon - or collecting enough Pokemon candy to level up your favorites. What is genius about it is that it takes the act of catching them to real life - no doubt that for some gamers, dreams came true!


So in other words, you have:
  • a high accessibility mobile game
  • a giant following of fans of all ages
  • bringing a well-selling gaming franchise to real life
  • game mechanics that stimulate the urge to collect and discover (Pokemon and their spawning points, in this case)
They really got out the best of what they already had and struck a real hit on the mobile market.

I remember back a year or so Nintendo's decision to go mobile was generally met with skepticism. Now they have managed to create a hype that will not only change the game industry, but also society. Forever.

Well done, Nintendo. Well done.


Mittwoch, 6. Juli 2016

Creating a Mission System in Java


So... how do you create a Mission System?

I asked myself this question twice so far and recently I came up with the following approach. This system is relatively simple but you can do most of basic missions with it. It consists of a tree with depth 3: Mission, Objectives. Conditions. Each of the components has a mission state, consisting of PENDING, SUCCESS and FAILURE.

First, I will describe the classes needed, which is then followed by their java code at the end of this article.


The general structure is as follows:






Mission:
  • A Mission has a title, a debrief description and a short description. 
  • A Mission has multiple objectives.
  • As general rule, a mission is deemed a success if all its child objectives are deemed successful.

Objective:
  • An Objective has numerous conditions.
  • Objectives have a different behavior per type, described below:

    Default: All objectives must be set to success for a mission to return success.
    Failure: If this objective is failed, the entire mission fails.
    Optional: The objective is effectively ignored by the mission, but can be used to, say, determine a score.
     
  • By default, they are not being updated once a condition was met or failed, but you can change them to run permanent updates.
 
Conditions
  • All conditions must be met for an Objective to be successful. Behavior types (default, failure, optional) do not apply here to keep it simple. To make up for that, I've added the possibility to invert them.
  • Conditions are implemented by you via an interface and an abstract helper class. 
  • For GUI purposes, there's also methods to display the condition as string for the end user.

To use it, you setup your Mission, Objectives and Conditions and call Mission.update() each time you update your game.

Here's the code:



Mission


/**
 *
 * @author B5cully
 */
public class Mission {
  
    public String title;
    public String debrief;
    public String summary;   
    public LinkedList<Objective> objectives = new LinkedList();
    Objective.State state = Objective.State.PENDING;

    public Mission() {
    }
   
    public Mission(String title) {
        this.title = title;
    }

   
    public Objective.State getState() {
        return state;
    }
   
    public void addObjective(Objective obj) {
        objectives.add(obj);
    }
   
    public void start() {
        for( Objective objective : objectives ) {
            objective.start();
        }
    }
   
    public void stop() {
        for( Objective objective : objectives ) {
            objective.stop();
        }
    }

    /**
     * Updates this mission's state
     * @return
     */
    public void update() {
        int i=0;
        boolean success = true;
        boolean failure = false;
        for( Objective objective : objectives ) {
            switch (objective.state) {
                case SUCCESS:
                    if( objective.constant_check ) objective.checkState();
                    break;
                case FAILURE:
                    if( objective.constant_check ) objective.checkState();
                    break;
                case PENDING:
                    objective.checkState();
                    break;
            }
            switch( objective.type ) {
                case NORMAL: {
                    success = i == 0 ? objective.state.equals(Objective.State.SUCCESS) :
                                   success && objective.state.equals(Objective.State.SUCCESS);               
                } break;
                case OPTIONAL: {
                    //ignore the objective
                } break;
                case FAIL: {
                    //only consider fail state
                    failure = failure || objective.state.equals(Objective.State.FAILURE);                       
                } break;
                   
            }
            i++;
        }
        if( success ) {
            state = Objective.State.SUCCESS;
        }
        if( failure ) {
            state = Objective.State.FAILURE;
        }
    }





Objective

/**
 *
 * @author B5cully
 */
public class Objective {
  
    public enum Type{
        /**
         * The objective contributes to success of the mission.
         */
        NORMAL,
        /**
         * The objective counts as fail condition of the mission.+
         * If one objective of this type closes with failure,
         * the entire mission fails. The pending state of
         * FAIL objectives are ignored in the total outcome.
         */
        FAIL,
        /**
         * The objective is optional, it has no effect
         * on the total outcome.
         */
        OPTIONAL;
    }
    public enum State{
        PENDING, SUCCESS, FAILURE;
    }
  
    public String title;
    /**if this is true, the objective is constantly validated. If false,
       the objective is validated once and succeeds permanently once triggered.*/
    public boolean constant_check;
    /***/
    public Type type = Type.NORMAL;
    State state = State.PENDING;
    /**
     * All conditions must be met in order for na objective to
     * succeed.
     */
    LinkedList<ConditionImpl> conditions = new LinkedList<ConditionImpl>();

    public Objective() {
    }
  
    public Objective(String title) {
        this.title = title;
    }
  
    public void addCondition(ConditionImpl condition) {
        conditions.add(condition);
    }
  
    public void start() {
        for( ConditionImpl condition : conditions ) {
            condition.start();
        }
    }
  
    public void stop() {
        for( ConditionImpl condition : conditions ) {
            condition.stop();
        }
    }
  

    @Override
    public String toString() {
        String s = "";
        int i =0;
        for( ConditionImpl condition : conditions ) {
            s += condition.getName() + ": " + condition.getDisplayedText();
            if( i > 0 && i < conditions.size()) s += "\n";
            i++;
        }
        return s;
    }

    public State getState() {
        return state;
    }
  
    public void checkState() {
        boolean success = false;
        int i =0;

        //check the conditions
        for( ConditionImpl condition : conditions ) {
          
            state = condition.getState();
          
            if( !state.equals(State.PENDING) && constant_check) {
                //still update the condition if constant check enabled
                condition.checkState();
            } else
            if( state.equals(State.PENDING) ) {
                //pending: simply update. No updates if failed or succeeded.
                condition.checkState();
            }
            success = i == 0 ? state.equals(Objective.State.SUCCESS) :
                               success && state.equals(Objective.State.SUCCESS);
            switch( state ) {
                case FAILURE: {
                    this.state = State.FAILURE;
                    return;
                }
                default: break;
            }
            i++;
        }
        if( success) this.state = State.SUCCESS;
        else this.state = State.PENDING;
    }
}



Condition 


/**
 *
 * @author B5cully
 */
public interface ConditionImpl {
  

    /**
     * Invoked on condition start.
     */
    public void start();
   
    /**
     * Gets the name of this condition
     * @return
     */
    public String getName();
    /**
     * A Localized, properly formatted display
     * text for this condition.
     * @return
     */
    public String getDisplayedText();
   
    /**
     * @return the state of the condition
     */
    public Objective.State getState();
   
    /**
     * Evaluates the state of this condition. This normally involves
     * calculations.
     */
    public void checkState();
   
    /**
     * Invoked on condition stop (e.g. when
     * it has failed or is being reset)
     */
    public void stop();

}

Here's the helper class for Condition, followed by an example implementation. 


/**
 *
 * @author B5cully
 */
public abstract class Condition implements ConditionImpl {
  
    protected Objective.State state = Objective.State.PENDING;
    protected boolean inverted = false;
    /**
     * The name of this condition.
     */
    protected String name;
    /**
     * A format string to display the condition.
     */
    protected String format_string;
    /**
     * The string returned for display. This is usually
     * name + String.format(format_string, args), where
     * args is relevant info about the condition.
     */
    protected String displayed_text;

    public Condition(String name, String format_string) {
        this.name = name;
        this.format_string = format_string;
    }
   
    @Override
    public String getName() {
        return name;
    }
   
    /**
     * Inverts the result. E.g. Instead of delivering
     * SUCCESS by default, FAILED is being returned.
     * @param inverted
     */
    public void setInverted(boolean inverted) {
        this.inverted = inverted;
    }
   
    @Override
    public void start() {
    }

    @Override
    public Objective.State getState() {
        return state;
    }

    @Override
    public void stop() {
    }
}


/**
 *
 * @author B5cully
 */
public class ConditionKilledEnemies extends Condition{

    LinkedList<Entity> enemies = new LinkedList<Entity>();
    LinkedList<ListenerEntityImpl> listeners = new LinkedList<ListenerEntityImpl>();
    int size = 0;
   
    String current_displayed_text = "";
   
    {
        format_string = "%d/%d";
    }

    public ConditionKilledEnemies() {
        super("Killed", "%d/%d");
    }
   
    public void registerEnemy(Entity enemy) {
        //add enemy to list
        //add a entity listener that tracks the enemy death
        //and adds to the counter here
        ListenerEntityImpl listener = getListener(enemy);
        enemy.addEntityListener( listener);
        enemies.add(enemy);
        listeners.add(listener);
        size++;
        current_displayed_text = String.format(format_string, enemies.size(), size);
    }
   
    public ListenerEntityImpl getListener(Entity enemy) {
        return new ListenerEntityImpl() {

            @Override
            public void onDeath(EntityMobile object) {
                super.onDeath(object);
                int index = enemies.indexOf(object);
                if( index >= 0 ) {
                    enemies.remove(index);
                    listeners.remove(index);
                    current_displayed_text = String.format(format_string, enemies.size(), size);
                }
            }
        };
    }
   
    @Override
    public String getDisplayedText() {
        return current_displayed_text;
    }

    @Override
    public void checkState() {
        //success if the list is empty
        if( enemies.isEmpty() ) state = Objective.State.SUCCESS;
        else state = Objective.State.PENDING;
    }