• Announcements

    • khawk

      Download the Game Design and Indie Game Marketing Freebook   07/19/17

      GameDev.net and CRC Press have teamed up to bring a free ebook of content curated from top titles published by CRC Press. The freebook, Practices of Game Design & Indie Game Marketing, includes chapters from The Art of Game Design: A Book of Lenses, A Practical Guide to Indie Game Marketing, and An Architectural Approach to Level Design. The GameDev.net FreeBook is relevant to game designers, developers, and those interested in learning more about the challenges in game development. We know game development can be a tough discipline and business, so we picked several chapters from CRC Press titles that we thought would be of interest to you, the GameDev.net audience, in your journey to design, develop, and market your next game. The free ebook is available through CRC Press by clicking here. The Curated Books The Art of Game Design: A Book of Lenses, Second Edition, by Jesse Schell Presents 100+ sets of questions, or different lenses, for viewing a game’s design, encompassing diverse fields such as psychology, architecture, music, film, software engineering, theme park design, mathematics, anthropology, and more. Written by one of the world's top game designers, this book describes the deepest and most fundamental principles of game design, demonstrating how tactics used in board, card, and athletic games also work in video games. It provides practical instruction on creating world-class games that will be played again and again. View it here. A Practical Guide to Indie Game Marketing, by Joel Dreskin Marketing is an essential but too frequently overlooked or minimized component of the release plan for indie games. A Practical Guide to Indie Game Marketing provides you with the tools needed to build visibility and sell your indie games. With special focus on those developers with small budgets and limited staff and resources, this book is packed with tangible recommendations and techniques that you can put to use immediately. As a seasoned professional of the indie game arena, author Joel Dreskin gives you insight into practical, real-world experiences of marketing numerous successful games and also provides stories of the failures. View it here. An Architectural Approach to Level Design This is one of the first books to integrate architectural and spatial design theory with the field of level design. The book presents architectural techniques and theories for level designers to use in their own work. It connects architecture and level design in different ways that address the practical elements of how designers construct space and the experiential elements of how and why humans interact with this space. Throughout the text, readers learn skills for spatial layout, evoking emotion through gamespaces, and creating better levels through architectural theory. View it here. Learn more and download the ebook by clicking here. Did you know? GameDev.net and CRC Press also recently teamed up to bring GDNet+ Members up to a 20% discount on all CRC Press books. Learn more about this and other benefits here.
Sign in to follow this  
Followers 0
  • entries
    34
  • comments
    61
  • views
    70075

Entries in this blog

Gamieon

https://gamieon.itch.io/field-of-heroes


[media]

[/media]

a2.gif a3.gif

After just over three months of working on it in my free time, I just released an online multiplayer soccer MOBA on itch.io as a prototype. This is a departure from my normal routine where I come up with an idea, develop it through to the end, and release a polished version of it.

Backstory and Motivation

I got the idea for Field of Heroes back in 2014 when I was tinkering with the Unreal Editor. It seemed like a good project for learning how UE and behavior trees work, and I was inspired by mechanics from games like Altitude and Pigskin 621 A.D.. Back then I worked on it for a few months before moving it to the backburner since there wasn't a real interest in it from anyone else. I revived the project in Unity this past October after another developer released "What the Box?" on Steam after just one month of work, and it went viral. I was so inspired by their success that I just had to give it a shot.

I don't want to develop fully featured polished games alone anymore because I don't have the kind of free time and energy that I used to. I therefore decided I would make and release Field of Heroes as a prototype to see if it generates a lot of interest. If it does, then I'll put more effort into it and maybe work with an established studio to make it really polished and much more content-rich and fun. If it doesn't then I'll keep it available for free indefinitely and move on to a smaller project.

Have any of you out there reading this been in a similar position? What did you do and how did things work out?

Gamieon

fighting1.gif





Foreword: I'm developing an online soccer MOBA where upwards of ten players will be jockeying for a soccer ball. This journal is a brain dump to help me get a handle on the mechanics of managing a soccer ball in an online soccer game using Unity3D and the Photon network engine. I apologize in advance for the lack of helpful diagrams, animated GIF's, and the covering of every single edge case from start to finish; I'm saving those for the day when I can confidently write an article on "These are the mechanics of ball management in a network soccer game which work well enough for a polished release."


Game Environment



The game is made with Unity using the Photon network library. All players can send messages to each other, and one player is the Photon "master client" which I'll refer to as the "master player" going forward.

The master player is the authority that resolves any disputes among the peers; for instance whether a goal was really scored, and how much damage a player really takes from another's attack. Without a master player, the minor differences in everyone's game experience due to latency would escalate to become major differences, and everyone could be completely out of sync before long.



The Ball



There is only one ball on the soccer field. When no player possesses it, it rolls around the field managed by the physics simulation. After a player takes possession of it by running onto it, the ball will always be positioned in front of them (it becomes synchronized to the player's transform instead of its own transform).

I'm purposefully leaving the details of who controls the physics simulation and who decides what player possesses the ball out here; I explain those things in the various implementations below.



Ball Control Implementations




Failure: Ball physics centralized, player control centralized

My first implementation had the master player doing all the work: They would manage all the ball physics, detect when players were near enough the ball to possess it, and other players would have to send an RPC to the master player when they wanted to kick the ball away.

This implementation worked poorly because all the non-master players had to wait on the master player to give them ball possession or relinquish it. If I were a non-master player, I would not appear to possess the ball by running onto it; I would instead have run over it and even a few steps in front of it before the ball attached itself to me. When I kick the ball, it would stick to me for a brief moment before being teleported back to the point I actually kicked it from.



Failure: Ball physics centralized, player control decentralized

My second implementation had the master player still managing ball physics, but each player would determine when they possessed the ball and when they kicked the ball. They would tell the master player when they did either. The master player would do a check to determine whether the request was legitimate, and then relay the ball's final owner to all the players.

The problem here is that when the ball was kicked by a player, the ball would rubberband backwards on that player's instance. This is because the master player resumed the physics simulation from the kick point at the time the ball was already far away from the kick point on the kicker's instance.



Potential success: Ball physics decentralized, player control decentralized

My third implementation follows these rules:

  • The PhotonView owner of the soccer ball is always the master player
  • When a player possesses the ball, they control everything about it and stream ball position and rotation information to other players (the streaming is done through OnPhotonSerializeView calls in a hidden GameObject belonging to that player)
  • If the master player disagrees with the player possession, it will override it and notify all players through the ball's OnPhotonSerializeView call



    Here is the step-by-step process of what happens when a non-master player takes possession of the ball and kicks it later:

    1. Ball is rolling across the field. Player A controls the ball and is simulating its physics. All other players are getting a stream of ball position and rotation updates from Player A.
    2. Player B moves their player to the ball to possess it.
    3. Player B sends an RPC to all other players that it "tentatively" possesses the ball; its own session locks the ball to its character position and makes its rigidbody kinematic.
    4. All other non-master players get the RPC and lock the ball to Player B's position also making it kinematic.
    5. The master player gets the RPC and determines who should be in possession of the ball; in this case it is indeed Player B. The master player updates the ball's serializable data to reflect that, and its own session locks the ball to Player B's position and makes it kinematic.
    6. All the non-master players (including Player B) call OnPhotonSerializeView on the soccer ball and see that the master player confirmed Player B owns the ball. No action is needed.
    7. Player B decides it's time to kick the ball.
    8. Player B makes the ball not kinematic any longer, adds a kick force to it and sends an RPC to all other players that it kicked the ball.
    9. Now that the ball is in motion, Player B begins streaming the ball's position to all the players from its hidden GameObject.
    10. All other non-master players get the RPC and unlock the ball from Player B. Since Player B is streaming its position and rotation, the ball immediately begins to move in the direction of the kick.
    11. The master player gets the RPC, unlocks the ball from Player B, and updates its serializable data to reflect that the ball has no possessor. Since Player B is streaming its position and rotation, the ball immediately begins to move in the direction of the kick.



    So what happens if two players claim the ball one right after the other? All "tentative possession" RPC's after the first one are ignored until after the ball's serializable data update is received from the master player. This is accomplished by tagging each possession assignment with a sequence number that is incremented only by the master player in the serializable data payload.

    So what happens if the master player decides Player B doesn't possess the ball in step 5 because it's too far away for example? The master player will populate its serializable data with the fact that Player A still controls the ball. All other players, including Player B, will receive that and update the possessor on their instance accordingly. Player A will resume ball physics simulation.



    The kludge

    There's a bit of a kludge with the physics however: By the time the master player denied Player B's possession, Player A will have already stopped simulating the physics. Consequently when it resumes ball physics simulation, the ball will be at a dead stop in front of Player B. The only time this is avoided is if Player A is also the master player.

    There are some ways to resolve that kludge:

    • Make it so Player B is never denied ball possession (and therefore cheating becomes easier)
    • Make the most recent possessor, rather than the master player, verified the ball's transfer of ownership. I tried that and failed because I couldn't figure out the logistics of how to get all the players to agree on who was the most recent possessor.



      Outcome



      When I had two network players play with the ball one at a time using this implementation, the ball movement appeared natural in both sessions during all 11 steps. How well will this work with 3+ players actually playing the game? I don't know, but I'm fairly sure it will work better than my first two failed implementations.

Gamieon

Recently I downloaded MagicaVoxel which lets you create and modify blocky objects, and bought PicaVoxel which lets you import them into Unity3D projects. The purpose was twofold: to help my friend Highsight develop his first game, and to have access to powerful tools in case I ever wanted to make a voxel art game.

Highsight claimed difficulties with Rigidbody objects flying through the imported voxel objects. Upon looking at how the MeshColliders were built for the voxel objects, I guessed that the issue was with the fact the colliders were paper thin. Seeing that all of the voxel faces were one-sided, I figured that the best way to handle the issue was to create a BoxCollider behind every face.

The script below, when attached to a voxel object, will iterate through all Chunk objects and generate bounding boxes for them on simulation startup:


(Download the script from http://gamieon.com/blogimages/devblog/20160918/PicaBoxColliderGenerator.cs or copy from below)

using UnityEngine;using System.Collections;using PicaVoxel;///

/// Attach this script to a voxel object to generate box colliders for all the chunks therein/// when the game or simulation begins. The advantage of this over using existing mesh colliders/// is that these colliders have depth and are therefore less prone to objects going through or/// other weird collision behavior happening/// public class PicaBoxColliderGenerator : MonoBehaviour { /// /// The thickness of a box collider. Would be nice to auto-calculate this someday /// public float thickness = 0.1f; /// /// True if the box colliders should be static /// public bool staticColliders = false; // Use this for initialization void Start () { GenerateBoxColliders(); } /// /// Generates box colliders for all child chunks of this object /// void GenerateBoxColliders() { foreach (Chunk c in gameObject.GetComponentsInChildren()) { GenerateBoxColliders(c); } } /// /// Generates box colliders for a single child chunk of this object /// /// The chunk void GenerateBoxColliders(Chunk chunk) { // MAJOR ASSUMPTION: The object is not static (or else mesh optimization occurs and you'll get an error getting the mesh) // First get the mesh information MeshFilter meshFilter = chunk.gameObject.GetComponent(); Mesh mesh = meshFilter.sharedMesh; // MAJOR ASSUMPTION: Each pair of triangles is a rectangle // Now do for all rectangles for (int i = 0; i < mesh.triangles.Length; i += 6) { // Get the vertices of one of the triangles that make this rectangle // // v2 ------- v1 // | | // | | // v3 ------- * // Vector3 v1 = mesh.vertices[mesh.triangles]; Vector3 v2 = mesh.vertices[mesh.triangles[i + 1]]; Vector3 v3 = mesh.vertices[mesh.triangles[i + 2]]; // Get the two sides of the triangle which also make up two edges of the rectangle // connected by the same vertex (v2) Vector3 a = v1 - v2; Vector3 b = v3 - v2; // Get the normalized vector of the rectangle facing inward Vector3 n = Vector3.Cross(a.normalized, b.normalized); // Get the center of the rectangle by calculating the midpoint of two diagonally opposing points Vector3 c = (v1 + v3) * 0.5f; // Create an empty object at the center of the rectangle and make it a child of the chunk GameObject go = new GameObject("ChunkBoxCollider"); go.transform.SetParent(chunk.transform); // Position the object such that when we eventually add the collider, the "outermost" face of the collider // will be in the same plane as the rectangle go.transform.localPosition = c + n * thickness * 0.5f; // The object should always be facing the rectangle. This is so when we size the box collider, // we can be sure of the role that each axe has. Keep in mind that LookAt deals in world coordinates // so we need to adjust for the chunk's world rotation go.transform.LookAt(go.transform.position + chunk.transform.rotation * n, chunk.transform.rotation * b.normalized); // Now create the box collider BoxCollider boxCollider = go.AddComponent(); // Size the box collider boxCollider.size = new Vector3(a.magnitude, b.magnitude, thickness); // Make the collider static if desired go.isStatic = staticColliders; } }}

The script has two properties


  • thickness: How thick the colliders should be (0.4 works well)
  • staticColliders: If true, all the colliders will be static

    Keep in mind that if your voxel object is static, the script will have problems accessing the mesh data. You can address this by making the object not static.

    Because of the time it takes to generate the BoxColliders, you may want to consider writing an Editor script based on PicaBoxColliderGenerator to generate those boxes at design time instead of run time.

    Here is how the scene looked with no colliders, and how it looked with box colliders.

    scene1.jpg

    scene2.jpg


    On testing it with box colliders, I had no issues with Rigidbodies flying through the voxel at reasonable speeds. Highsight found the same to be true as well.

    I hope you find this helpful! Even if you don't, please check out my portfolio and follow me!

    Games: http://www.gamieon.com/games
    Twitch: https://www.twitch.tv/gamieon
    Facebook: https://www.facebook.com/gamieon
    Twitter: https://www.twitter.com/gamieon
    YouTube: https://www.youtube.com/gamieon

Gamieon
Though I've dabbled in game development since the late 1980's, it wasn't until October 26, 2004 that I incorporated Gamieon for fun, adventure, and maybe even a little profit. It's a part-time studio owned by myself and an investor who helps me cover expenses. Together we're the only employees of Gamieon. I do all the programming, releases, website maintenance, social networking and business upkeep. Tasks that are contracted out on a need-to basis include graphic, sound effect, music development and sometimes marketing. My full time job is medical software development; I've been employed by the same company for over seventeen years. I opted not to go into full-time gamedev largely because I don't want to leave my current job and because I like to treat gamedev as a hobby more than as a career (though it wasn't always that way).


[color=#800000]Pre-Gamieon[/color]



I initially learned to program in BASIC with help from my father. Years later I learned how to program in C; mostly self taught but with some help from a friend on a local BBS I called frequently. I conceived of many projects but never finished any until around 1994 when I programmed and released "Flash Infiltrator;" a free ANSI war game you could play online a "Major BBS" real-time with up to five other players.

fi.png

Within a year following I released "Flash Tankfire" which was a free Scorched Earth clone also playable online a Major BBS.



ftf.png

The development cycle was "code-and-fix" for all that time, and I didn't really think about collaborating with other developers. I was having fun on my own, and had not come across anyone else who wrote games. After those two games I turned my attention toward learning DirectX and engine development. I wrote a basic 3D video engine and a fast smooth voxel terrain renderer like that of the "Mars" voxel demo shown below:

mars10.gif
(Source: http://rainmak3r.altervista.org/voxel/download/ukindex.htm )

Sadly I lost the code to those projects many years ago, so I have nothing to show for it here.




Later in college I developed and released "Cycles3D." The game is a free clone of the original Tron light cycle simulation. The initial release got thousands of downloads within the first day of being available; and later I discovered it was downloaded so many times that it created a distinct spike in campus network traffic for a short while. That was the legacy I left the University of Dayton with smile.png.

c3d1.png c3d2.png c3d3.png

You can still download it at http://www.cycles3d.com

College was also when I got a co-op job developing medical software. After graduation my boss set up a full-time game development studio called Astound for me because, back then, I wanted a full time job developing games and he thought it could be lucrative. It was a dream come true, and I jumped right in. At Astound I worked with another programmer on a 3D shooter called "Zeos Fighters."

zeos1.png zeos2.png zeos4.png



After a year of work I deemed the project a failure and returned to medical software development. Its failure can be summed up in one sentence: I treated Astound like a programming exercise, not a game studio. The itch to develop games never went away, so I started development on a 3D physics puzzle game in my free time called "Dominoze." It was during development of that game that I founded Gamieon in order to formalize its development and collaborate with other developers under a corporate entity.


[color=rgb(128,0,0)]Gamieon's Unreleased Projects[/color]


(Number in parenthesis denotes most recent year of development)


[color=#008080]

Dominoze (2010)

[/color]

http://www.indiedb.com/games/dominoze


[media]
[/media]


d1.png

d2.png

d3.png



Dominoze is a 3D physics puzzle game, and though unfinished, the crown jewel of my personal game development experience. In each level you figure out how to arrange objects in a scene such that all the dominoes can be knocked over in one continuous chain. I think the idea is amazing but the execution was poor. I spent nine years building the game, editor and engine (even writing a lightmapper from scratch) only to walk away from what became an endless cycle of feature creep and no direction.

You can read all about Dominoze at http://www.gamasutra.com/blogs/ChristopherHaag/20130312/188293/Dominoze_PC_Postmortem_Nine_Years_One_Programmer.php


[color=#008080]

Gamieon Construction Kit (2010)

[/color]

http://www.indiedb.com/games/gamieon-construction-kit


[media]
[/media]
gck1.png gck2.png

This was a learning project for Unity network development and also an attempt to make a Rube Goldberg sandbox simulation consisting of physics and simple shapes. I like the underlying idea of a simulator where people can build and share contraptions online, but I never came up with a complete design. I abandoned it after a few months to move on to more exciting projects.


[color=#008080]

Cycles3D 2.0 (2012)

[/color]

http://www.indiedb.com/games/cycles3d


[media]
[/media]


c3d2_1.png c3d2_2.png

I ported my old Cycles3D project to Unity on a whim to see how fast I could do it and to make it look pretty along the way. I stopped development because I lost interest, but it remains on GitHub at https://github.com/Gamieon/Cycles3D should anyone want to tinker with it.




[color=#008080]

Gauntlet Clone (2014)

[/color]

(This project has no homepage)


[media]
[/media]
g1.png g2.png

This was my first immersion into Unreal 4 development. I wanted to make Unreal's cave fly-through demo into a small Gauntlet level. I did just that in a very short time; and it was fun to play even though players didn't take damage. I abandoned the project right after I made the video because I wanted to work on something else more original. All in all it was a good learning experience.


[color=#008080]Field of Heroes (2015)[/color]


http://www.indiedb.com/games/field-of-heroes


[media]
[/media]

foh1.png foh2.png



This is my second Unreal 4 project, and one I'd like to see come to fruition someday with help from a big studio. FoH is a soccer game where players fight each other, literally, for control of the ball. Even if the project doesn't go anywhere, at least I got to learn how behavior trees and character animations generally work in modern game development tools. This project is in development at the time of this writing.


[color=#800000]Gamieon's Released Projects[/color]


(Number in parenthesis denotes release year)


[color=#008080]

Tiltz (2010)

[/color]

http://www.indiedb.com/games/tiltz


[media]
[/media]
tiltz1.png tiltz2.png

Tiltz is a simple mobile game where you tilt your device and pull incline ramps down with your finger to guide marbles into a barrel. It was my first venture into mobile development and my first released game that used the Unity engine. You can read more about it in the post-mortem (which I called "sunset" at the time) at:

http://www.indiedb.com/members/gamieon/blogs/game-sunset-report-tiltz

At the time of this writing it's still available on these platforms:

iTunes - http://itunes.apple.com/us/app/tiltz-deluxe/id460936061?ls=1&mt=8
Google Play - https://market.android.com/details?id=com.gamieon.tiltzdeluxe


[color=#008080]

Hyperspace Pinball (2011)

[/color]

http://www.indiedb.com/games/hyperspace-pinball


[media]
[/media]
pb1.png pb2.png
The objective in this game, which is my second mobile and first desktop Unity game released, is to destroy aliens on the screen using pinball-like controls. It was my first attempt at a seriously successful mobile game, and my most successful game by download. You can read the post-mortem at:

https://www.gamedev.net/blog/1606/entry-2255775-hyperspace-pinball-development-the-almost-sunset-story/

At the time of this writing, you can still get it from these links:

iTunes - http://itunes.apple.com/us/app/hyperspace-pinball/id449062825?ls=1&mt=8
Google Play - https://play.google.com/store/apps/details?id=com.gamieon.hyperspacepinball
Desura - http://www.desura.com/games/hyperspace-pinball
BrassMonkey - http://playbrassmonkey.com/hyperspacepinball


[color=#008080]

Hamster Chase (2013)

[/color]

http://www.indiedb.com/games/hamster-chase


[media]
[/media]
hc1.png hc2.png

Hamster Chase is a mobile accelerometer puzzle game where you tilt the device to get all the hamsters within their hamster balls onto their seed piles. It's my second attempt at a successful mobile game, and my first where I leverage a cartoony theme as many popular mobile games do. I commissioned Meta3D studios to do all the art, and NovyPR to do the release blast rather than trying to do both myself.

It did not reach the success I had hoped for, and I never wrote a post-mortem. I think the game would have done better had I released it as a free app designed around a solid in-app purchase model, and made regular updates to it with new features and achievements.

You can see the virtual hamster cage at http://www.gamieon.com/hammys/ and click on the hamsters. If you do it enough they may tell a joke!
You can get Hamster Chase from:

iTunes - https://itunes.apple.com/us/app/hamster-chase/id564548708?ls=1&mt=8
Google Play - https://play.google.com/store/apps/details?id=com.gamieon.hamsterchase
Windows Phone - http://www.windowsphone.com/en-us/store/app/hamster-chase/0a538986-ef86-49ad-bb39-9b1bb8e9de24


[color=#008080]

Domino Arena (2013)

[/color]

http://www.indiedb.com/games/domino-arena


[media]
[/media]
da1.png da2.png

Have you ever had an idea for a game that floated around your head for over a year, and you knew it wouldn't be popular but you finally wrote it anyway just to get it out of your head? That's Domino Arena. The objective is to alter the course of falling dominoes that change color as they fall so that as many of them become your color as possible.

I released it just to see how it would do, and as expected it didn't garner a lot of interest. You can play it from:

iTunes - https://itunes.apple.com/us/app/domino-arena/id743797890?ls=1&mt=8
Google Play - https://play.google.com/store/apps/details?id=com.gamieon.dominoarena
GameJolt - http://gamejolt.com/games/arcade/domino-arena/18964/
Domino Arena - http://www.kongregate.com/games/gamieoninc/domino-arena


[color=#008080]

Paper Cowboys (2013)

[/color]

http://www.indiedb.com/games/paper-cowboys/


[media]
[/media]
pc1.png pc2.png
This game marked a turn in my development philosophy. Instead of trying to develop a new concept, I decided to see how fast I could make an online stick-figure western platform shooter. I finished it in 48 total hours. You can play the released version at:

http://gamejolt.com/games/platformer/paper-cowboys/15184/

you can see the post-mortem at:

https://www.gamedev.net/blog/1606/entry-2256481-paper-cowboys-personal-48-hr-game-jam-post-mortem/

It received enough views and positive comments to motivate me into commissioning Meta3D studios a version with all new papercraft art. In another change of my development philosophy, I put the entire game design in their hands and limited my role only to programmer. This project is still in development at the time of this writing.


[color=#008080]

Tiltz Tournament (2014)

[/color]

http://www.indiedb.com/games/tiltz-tournament


tt1.png tt2.PNG
Skillz, a company developing a mobile multiplayer platform with real cash prizes, approached me about adding part of Tiltz to their lineup. Tiltz Tournament basically takes the Tiltz mini-game of trying to make marbles fall into point slots, and makes it so players can compete online and win money by getting the higher score.

I abandoned the project after a quiet release and after I lost personal interest in it. There is no post-mortem for this game. You can try it at:

iTunes - https://itunes.apple.com/us/app/tiltz-tournament/id792492685?mt=8


[color=#800000]Downloads / Plays from Nov 30, 2010 - Jan 14, 2015[/color]




Tiltz
iOS - ~36,400
Android - 44,638

Hyperspace Pinball
iOS - ~18,080
Android - 96,922
Desura - 874

Hamster Chase
iOS - ~30,600
Android - 47,104
Windows Phone - 9,397

Domino Arena
iOS - ~4,870
Android - 2,615
GameJolt - 177
Kongregate - 457

Tiltz Tournament
iOS - 127

Paper Cowboys
GameJolt - 6,460


Total downloads/plays: ~298,720
Total income: (I'm omitting this number; I will say however that none of my projects have ever made a profit)


[color=#800000]Some Lessons I've Learned[/color]


  • Few things can be as fun to a game developer as getting together with some friends and walking to a restaurant and back; all the while discussing ideas for video games.
  • Mentors are powerful allies in helping you learn how to develop games.
  • If you need a powerful game engine, first make sure you really need it and then look at third party solutions before you consider writing your own.
  • Careful planning and doing things right don't guarantee a successful, profitable release. It does however greatly increase your chances.
  • Development is very risky when you do it by yourself; there's nobody else around to error check your plans, your designs and your code.
  • There is always room for another popular game with simple graphics and addicting game play.
  • Learn and use source control early on. You'll thank yourself later.
  • If your goal is to make money, design the monetization model for your game as early as you start designing the game.
  • Graphics are great for getting attention; game play is great for keeping it.
  • Never underestimate the success of a game that users can mod.
  • Set goals and limits. Decide the project must be done in X months. Decide there will be between Y and Z levels, and don't be afraid to narrow things down along the way.
  • Avoid feature creep. It increases development time and takes time away from your more exciting future projects.
  • When you contract work out to other studios, they become an extension of your core team. Treat them with immediacy, courtesy and respect.
  • A professional is just that because they make the difficult look easy.
  • Maintain a news feed for your projects early on. More exposure time means more time to get new readers, and more of a chance for big media sources to take notice and write about your game.
  • Try to make every news update count. A long string of very minor updates can bore readers and clog up news feeds which may include more important things like release announcements from other studios.
  • Maintaining a developer journal with how-to's and fix-it's is a good thing. It helps other developers when they're stuck with the same problems you had, helps you track your knowledge growth, and can even make you new friends.
  • Don't ignore insightful critics. They want your game to be better and cared enough to write about how to do it.
  • Envy of other developers' successes can take fun and feelings of accomplishment away from game development. Discouragement and frustration will keep you from learning important lessons they may share, and make you think you're not as good as you are.
  • Don't work hard; work smart. If you need a tool that has already been developed, use that one. If your stuck on a problem or your project is moving too slowly, ask for help.
  • Make sure your Android apps request only the permissions they need.
  • A developer should eventually outgrow the "code-and-fix" process into something more structured and fit for large projects.
  • It's more challenging to find an audience with an original and untested concept than it is with a proven concept or clone of another game.
  • Insanity is indeed doing the same thing over and over and expecting different results.
  • The learning never stops.

    [color=#800000]The Future[/color]



    Although most of my releases were for mobile platforms, I've wanted to release a game on Steam for a long time. I'm working closely with Meta3D studios to try to make it happen with a papercraft version of Paper Cowboys. They are doing not only the art, but also the game design this time. My roles are now "programmer" and "guy who has the final say-so on certain questions."

    I still have an itch to make a sandbox simulation where people can create Rube Goldberg machines together online. It goes back to my favorite project Dominoze which I think could even be remade as a mobile puzzle game with the right team and taking into consideration all the lessons learned from the original.

    Lastly I'd like to see if Field of Heroes has a future in a collaboration with another studio. I have a general idea of how I want the game to work, and it's definitely not something I want to design or program alone.


    [color=#800000]Special Recognitions[/color]



    Eric Barth, Jeff Gordon, Jordan Pelovitz, Yisroel Goldstein, Helder Gomes, Russ McMackin, Bryan Taylor, and Jarien Strutts all helped me with art and level designs in Dominoze, so thanks again to them. Mick Rippon donated numerous songs to the project, and thanks also go to George Toderici for all the advice and web links that helped me with video engine development!

    The Hyperspace Pinball playfield was also modeled by Jeff Gordon.

    I commissioned Meta3D studios and NovyPR to do the artwork and release blast for Hamster Chase respectively; thanks to them for a great job!


    [color=#800000]Links[/color]



    Full quality images of all the game thumbnails in this article can be found at http://www.gamieon.com/blogimages/10/

    My homepage: http://www.gamieon.com
    Contact me at: http://gamieon.com/contact

    My portfolio at IndieDB: http://www.indiedb.com/members/gamieon/
    Development blog #1: http://www.indiedb.com/members/gamieon/blogs
    Development blog #2: https://www.gamedev.net/blog/1606-gamieons-journal/
    Development blog #3: http://gamasutra.com/blogs/ChristopherHaag/918299/
    Facebook: https://www.facebook.com/Gamieon
    Twitter: @gamieon
    LinkedIn: https://www.linkedin.com/pub/christopher-haag/7/650/4a2/
    Develteam: http://www.develteam.com/Developer/Gamieon
Gamieon
[color=rgb(128,0,0)]

The Issue

[/color]


I'm developing an online soccer game for UE4 which you can get from

http://github.com/Gamieon/UBattleSoccerPrototype

for now.

During game play, the soccer ball can be in one of two states: Freely moving; or in possession. When freely moving, the ball moves by physics simulation. When in possession, the ball is always in front of the possessing character.



I noticed during online testing that the ball position and velocity on the client instances would deviate from the server when freely moving. Thinking I was doing something wrong with replication, I went into the editor and tried every combination of replication flags to fix it to no avail. Some Googling on the matter did not reveal a solution.


[color=rgb(128,0,0)]

The Solution

[/color]


I resolved to just deal with the issue myself in the same way I did in my Unity projects using lessons from https://developer.valvesoftware.com/wiki/Source_Multiplayer_Networking . The server would simulate ball physics, and the clients would constantly be fed the ball orientation from the server. The clients would use interpolation/extrapolation to smoothly move their instance of the ball to where the server says it should be.


[color=rgb(128,0,0)]Physics Simulation[/color]



On the server, the soccer ball physics are simulated and collision detection handled when the ball is not in possession. On clients I ensure the physics are never simulated and that collision detection is always off like so:/** This occurs when play begins */void AMagicBattleSoccerBall::BeginPlay(){ Super::BeginPlay(); if (Role < ROLE_Authority) { // The server manages the game state; the soccer ball will be replicated to us. // Physics however are not replicated. We will need to have the ball orientation // replicated to us. We need to turn off physics simulation and collision detection. UPrimitiveComponent *Root = Cast(GetRootComponent()); Root->PutRigidBodyToSleep(); Root->SetSimulatePhysics(false); Root->SetEnableGravity(false); SetActorEnableCollision(false); } else { // Servers should add this soccer ball to the game mode cache. // It will get replicated to clients for when they need to access // the ball itself to get information such as who possesses it. AMagicBattleSoccerGameState* GameState = GetGameState(); GameState->SoccerBall = this; }}
[color=rgb(128,0,0)]Replication[/color]

There are three ball properties that must be replicated:

  • Orientation - This is the position and rotation of the ball
  • Velocity - This is used for extrapolation. If the server is slow to replicate data, the client should be able to predict where the ball is going while waiting for more data to come in.
  • Timestamp - The other properties require a context in time for proper interpolation/extrapolation. Sure the ball was at XYZ...but when was it there?

    I created a USTRUCT with these properties which I call FSmoothPhysicsState.USTRUCT()struct FSmoothPhysicsState{ GENERATED_USTRUCT_BODY() UPROPERTY() uint64 timestamp; UPROPERTY() FVector pos; UPROPERTY() FVector vel; UPROPERTY() FRotator rot; FSmoothPhysicsState() { timestamp = 0; pos = FVector::ZeroVector; vel = FVector::ZeroVector; rot = FRotator::ZeroRotator; }};
    The ball has a FSmoothPhysicsState which I define as such: /** The soccer ball orientation on the server */ UPROPERTY(ReplicatedUsing = OnRep_ServerPhysicsState) FSmoothPhysicsState ServerPhysicsState; UFUNCTION() void OnRep_ServerPhysicsState();

    and each client tracks the last twenty states (defined as PROXY_STATE_ARRAY_SIZE) in the replication function:



    void AMagicBattleSoccerBall::OnRep_ServerPhysicsState(){ // If we get here, we are always the client. Here we store the physics state // for physics state interpolation. // Shift the buffer sideways, deleting state PROXY_STATE_ARRAY_SIZE for (int i = PROXY_STATE_ARRAY_SIZE - 1; i >= 1; i--) { proxyStates = proxyStates[i - 1]; } // Record current state in slot 0 proxyStates[0] = ServerPhysicsState; // Update used slot count, however never exceed the buffer size // Slots aren't actually freed so this just makes sure the buffer is // filled up and that uninitalized slots aren't used. proxyStateCount = FMath::Min(proxyStateCount + 1, PROXY_STATE_ARRAY_SIZE); // Check if states are in order if (proxyStates[0].timestamp < proxyStates[1].timestamp) { UE_LOG(LogOnlineGame, Verbose, TEXT("Timestamp inconsistent: %d should be greater than %d"), proxyStates[0].timestamp, proxyStates[1].timestamp); } }
    [color=rgb(128,0,0)]Timestamps[/color]

    I previously wrote that the replicated properties require a context in time. Though clients gets server timestamps, a client's current time may not be exactly the same time as the server's. The clients need to know the server's time throughout the game for proper interpolation/extrapolation.

    To accomplish this, the client does the following:

    1. Get the server's time
    2. Calculate the difference between the server's time and its own time, and stores it in memory
    3. Any time the client needs to know the server's time, the client will get its own time and add the value from step 2 to it.

    I'll expand on these steps here:

    [color=#800000]Step 1[/color]

    1. The client gets its own system time and stores it in a variable we call "Tc"
    2. The client sends an RPC to the server requesting the server's system time
    3. The server gets the client RPC. The server then gets its own system time, and responds to the client with that value.
    4. The client gets the server RPC and stores the value in "Ts"
    5. Immediately after that, the client gets its own system time again, subtracts "Tc" from it, and stores the result in "Tt"

    So now we have three values:


    • Tc - The system time of the client when it sent the RPC request for step 1 to the server
    • Ts - The system time of the server when it received the RPC request from step 1
    • Tt - The total length of time it took for the client to get the server's time

      [color=#800000]Step 2[/color]

      Ts was the server's time when it received the RPC; so at the moment the client gets it, the time on the server is actually Ts + (the time it took to send Ts to the client). I'm going to estimate the time it took to send Ts to the client as Tt/2 since Tt is the duration of the entire two-RPC exchange.

      Therfore at time Tc, the time on the server was approximately (Ts - Tt/2).

      I'll repeat myself because this is important:

      Therfore at time Tc, the time on the server was approximately (Ts - Tt/2).

      Now that we know this, we can calculate the difference between the server time and client time, and store it in a new value we call "Td"

      Td = (Ts - Tt/2) - Tc


      [color=#800000]Step 3[/color]

      Now that we know Td, we can calculate the server's approximate time. Since:

      Td = (Ts - Tt/2) - Tc

      we can add Tc to both sides:

      (Ts - Tt/2) = Tc + Td

      and interpret the equation to mean:

      The server time = The client time + Td


      Here are some relevant snippets from my implementation:
      /** Gets the current system time in milliseconds *//* static */ int64 AMagicBattleSoccerPlayerController::GetLocalTime(){ milliseconds ms = duration_cast< milliseconds >( high_resolution_clock::now().time_since_epoch() ); return (int64)ms.count();}void AMagicBattleSoccerPlayerController::BeginPlay(){ Super::BeginPlay(); // Ask the server for its current time if (Role < ROLE_Authority) { timeServerTimeRequestWasPlaced = GetLocalTime(); ServerGetServerTime(); }}bool AMagicBattleSoccerPlayerController::ServerGetServerTime_Validate(){ return true;}/** Sent from a client to the server to get the server's system time */void AMagicBattleSoccerPlayerController::ServerGetServerTime_Implementation(){ ClientGetServerTime(GetLocalTime());}/** Sent from the server to a client to give them the server's system time */void AMagicBattleSoccerPlayerController::ClientGetServerTime_Implementation(int64 serverTime){ int64 localTime = GetLocalTime(); // Calculate the server's system time at the moment we actually sent the request for it. int64 roundTripTime = localTime - timeServerTimeRequestWasPlaced; serverTime -= roundTripTime / 2; // Now calculate the difference between the two values timeOffsetFromServer = serverTime - timeServerTimeRequestWasPlaced; // Now we can safely say that the following is true // // serverTime = timeServerTimeRequestWasPlaced + timeOffsetFromServer // // which is another way of saying // // NetworkTime = LocalTime + timeOffsetFromServer timeOffsetIsValid = true;}/** Gets the approximate current network time in milliseconds. */int64 AMagicBattleSoccerPlayerController::GetNetworkTime(){ return GetLocalTime() + timeOffsetFromServer;}
      I'm treating Td as a constant in my implementation. I don't expect the server and client clocks to be running at paces different enough to become significant in the time it takes to finish a game. I also don't want Td to change because the ball movement implementation expects time to always be moving forward instead of going back and forth every so often.

      You may also wonder "Why do this from APlayerController and not the ball?" Look at these requirements for clients sending RPC's to the server from

      https://docs.unrealengine.com/latest/INT/Gameplay/Networking/Replication/RPCs/index.html :

      • They must be called from Actors.
      • The Actor must be replicated.
      • If the RPC is being called from server to be executed on a client, only the client who actually owns that Actor will execute the function.
      • If the RPC is being called from client to be executed on the server, the client must own the Actor that the RPC is being called on.

        The client does not own the soccer ball, thereby failing requirement 4. The client however owns their player controller, and that object meets all the criteria.



        Client Movement

        During game play the client will get a stream of ball properties from the server. A critical thing to remember is that those properties are always out-of-date because it takes time for them to get from the server to the client. On the client, the ball is perpetually "catching up to where it is on the server." To make the ball do this smoothly, we use interpolation and extrapolation like so:/** Simulates the free movement of the ball based on proxy states */void AMagicBattleSoccerBall::ClientSimulateFreeMovingBall(){ AMagicBattleSoccerPlayerController* MyPC = Cast(UGameplayStatics::GetPlayerController(GetWorld(), 0)); if (nullptr == MyPC || !MyPC->IsNetworkTimeValid() || 0 == proxyStateCount) { // We don't know yet know what the time is on the server yet so the timestamps // of the proxy states mean nothing; that or we simply don't have any proxy // states yet. Don't do any interpolation. SetActorLocationAndRotation(ServerPhysicsState.pos, ServerPhysicsState.rot); } else { uint64 interpolationBackTime = 100; uint64 extrapolationLimit = 500; // This is the target playback time of the rigid body uint64 interpolationTime = MyPC->GetNetworkTime() - interpolationBackTime; // Use interpolation if the target playback time is present in the buffer if (proxyStates[0].timestamp > interpolationTime) { // Go through buffer and find correct state to play back for (int i=0;i.timestamp <= interpolationTime || i == proxyStateCount-1) { // The state one slot newer (<100ms) than the best playback state FSmoothPhysicsState rhs = proxyStates[FMath::Max(i - 1, 0)]; // The best playback state (closest to 100 ms old (default time)) FSmoothPhysicsState lhs = proxyStates; // Use the time between the two slots to determine if interpolation is necessary int64 length = (int64)(rhs.timestamp - lhs.timestamp); double t = 0.0F; // As the time difference gets closer to 100 ms t gets closer to 1 in // which case rhs is only used if (length > 1) t = (double)(interpolationTime - lhs.timestamp) / (double)length; // if t=0 => lhs is used directly FVector pos = FMath::Lerp(lhs.pos, rhs.pos, t); FRotator rot = FMath::Lerp(lhs.rot, rhs.rot, t); SetActorLocationAndRotation(pos, rot); return; } } } // Use extrapolation else { FSmoothPhysicsState latest = proxyStates[0]; uint64 extrapolationLength = interpolationTime - latest.timestamp; // Don't extrapolate for more than [extrapolationLimit] milliseconds if (extrapolationLength < extrapolationLimit) { FVector pos = latest.pos + latest.vel * ((float)extrapolationLength * 0.001f); FRotator rot = latest.rot; SetActorLocationAndRotation(pos, rot); } else { // Don't move. If we're this far away from the server, we must be pretty laggy. // Wait to catch up with the server. } } }}
        I want to explain the two variables used in ClientSimulatePhysicsMovement():

        interpolationBackTime - This variable means "Our instance of the ball is going to be (interpolationBackTime) milliseconds in time behind the server." In my snippet it's hard-coded to 100 because I'd like the average client ping to be at or below that. Why can't we say "well just make it 0 so the ball is always in the present?" Because remember that it takes time for the ball properties to be transmitted to the client; we can't know where it is on the server at the present. If you did set it to 0 then I think the ball would be jumping all over the screen during game play as if to say "whoops I'm supposed to be here, whoops my bad I should have been there, whoops I fell behind again..."

        extrapolationLimit - If the server suddenly stops sending data to a client for a second or more, all the client can really do is keep the ball moving in the same direction and hope it's right. You've probably seen objects freeze or "rubberband" in network games; that's because the replication was briefly interrupted on the server and the client wrongly assumed objects were at certain places before new replicated data showed otherwise.


        Results

        I did get the soccer ball to appear reasonably in sync on LAN clients with this implementation, but have not yet tested over a WAN connection with higher latency. I think there will be some more fine tuning of the code before it's ready for general release. I still feel like I unnecessarily reinvented some wheel here given how advanced the Unreal Engine is though I enjoyed writing and testing the code regardless.
Gamieon
Yesterday my game started crashing out of the blue. The output window had content that resembled this snippet from https://answers.unrealengine.com/questions/132817/attachment-replication-crashes-client-in-451.html :

[ 79]LogOutputDevice:Warning: Script Stack:Actor.OnRep_AttachmentReplicationAssertion failed: !bRegistered || AttachParent->AttachChildren.Contains(this) [File:D:\BuildFarm\buildmachine_++depot+UE4-Releases+4.5\Engine\Source\Runtime\Engine\Private\SceneComponent.cpp] [Line: 903] Attempt to detach SceneComponent 'Default Root' owned by 'BP_Bow_C_1' from AttachParent 'CharacterMesh0' while not attached. UE4Editor.exe has triggered a breakpoint.

In my case I had recently removed a component from my player pawn, so I think that was related. I double checked that things were running fine in the editor and that the pawn looked legit. I also made sure nothing more suspicious than usual appeared in the output log. Thinking the game and editor were somehow "out of sync" I started trying random things like rebuilding all from VS2013. It was the act of cooking the content in the editor, however, that made the problem go away.

So if you suddenly get random errors in DebugGame mode, try cooking the content from the editor to fix it.
Gamieon
Though I'm still new to the Unreal Editor and behavior trees, I wanted to create a primitive soccer simulation for a game I'm prototyping. You can get the code in its current form at:

https://github.com/Gamieon/UBattleSoccerPrototype




[color=#b22222]

Getting Started

[/color]


The first part of my journey was learning how "Blueprints" work in the Unreal Editor. I consider a blueprint to be a graphical representation of code. By graphical I mean both pixels-on-the-screen and boxes-connected-to-other-boxes-by-pointy-arrows. You can learn more about how they work at:

https://docs.unrealengine.com/latest/INT/Engine/Blueprints/index.html

The second part of my journey was learning how "Behavior Trees" work. Buried in Google search results full of complicated papers and tutorials that blew my mind, I managed to find this little gem:

http://www.indiedb.com/groups/indievault/tutorials/game-ai-behavior-tree

That article clicked with me and I felt like I understood the basics after just one read.


[color=#b22222]Setting the Rules[/color]



My first step into creating a soccer simulation was to establish a purpose and basic rules for the simulation:

  1. The objective is to get the soccer ball into the enemy goal.
  2. Each team has eleven players on the field at a time.
  3. Each player is confined to an area on the field which I call "action zone."
  4. Each player's purpose is to contribute to the objective for their team.
  5. A player's only interaction with the soccer ball is to kick it into the goal or to a teammate.

Seen here is the reference I chose for assigning field positions for a soccer game

http://www.sportspectator.com/fancentral/soccer/soccer_diagram.gif


[color=#b22222]Entities[/color]



With the rules established, I made a list of the different entities on the field that need to be tracked by a single player:

  • Ball
  • Enemy goal
  • Teammates
  • Enemy players

    Note the absence of the role of the friendly goal. After several failed attempts at developing the behavior tree, I decided to create a tree that was to be used by every player; everyone from the goalie to the offensive players. I'm not going for perfect; I'm going for simple until I get better at this. Since none of my tree logic factors in the friendly goal, I'm not counting it as an entity here.


    [color=#b22222]

    Binary Decision tree

    [/color]

    I'm new to behavior trees but not to basic problem solving. After several failed attempts, I came up with a simple decision tree that I could apply to every player on the field:

    [code=nocode:0]- Is the ball in a goal? Yes - Is it in your goal? Yes A. Celebrate No B. Shrug No - Do you possess the ball? Yes - Are you close to the goal? Yes - Is there an obstacle in the kick line? No C. Take a shot Yes - Is it an enemy? Yes - Is another nearby teammate not close to any enemies and unobstructed? Yes D. Pass the ball toward the teammate No E. Run around enemy toward goal No F. Run around obstacle toward goal No - Is another teammate in front of you closer to the goal, not close to any enemies and unobstructed? Yes G. Pass the ball toward the player No H. Run toward goal No - Does a player on your team have possession of the ball? Yes - Are there enemies within a close distance to the player? Yes I. Pursue enemy closest to player No J. Run in parallel direction to friendly possessor up to the goal No - Does an enemy possess the ball? Yes K. Pursue enemy No - Is an enemy in the line between you and the ball? Yes L. Pursue obstructing enemy No M. Pursue ball

    Notice how the farther down in the tree you go, the farther away you are from the purpose of the simulation which is to get the ball into the enemy goal. Here's a summary view of it in reverse order; note how it generally follows the progression of a soccer game:

    • Go after the ball
    • Pursue the enemy who possesses the ball
    • Have the team maintain ball control and work with teammates to get the ball to the goal
    • Kick the ball into the goal
    • Celebrate the goal



      [color=#b22222]

      What Does "Pursue" Mean?

      [/color]

      When a player pursues the ball, all they're doing is running to it. Once the player overlaps the ball's collision sphere, the game assigns them possession and the ball will always be in front of their feet no matter how they turn or run. The only way that a player can lose possession is if they or an enemy player kicks the ball away.

      When a player pursues an enemy, all they do is run up to them and kick the ball away if they have possession. As I plan for this game to involve on-field fighting ala League of Legends or Diablo 3, I'm purposefully not doing anything more with player pursuits until I design the battle system.


      [color=#b22222]Leaf actions (tasks)[/color]



      Once I had a decision tree I was content with, I turned my attention to the leaf actions in the tree and grouped them by purpose:

      [code=nocode:0]1. GoalFanfare (Is the ball in a goal?) A. Celebrate B. Shrug2. ScoreGoal (Do you possess the ball?) C. Take a shot D. Pass the ball toward the teammate E. Run around enemy toward goal F. Run around obstacle toward goal G. Pass the ball toward the player H. Run to goal3. DefendPossessor (Does a teammate possess the ball?) I. Pursue enemy closest to player J. Run in parallel direction to friendly possessor4. AttackPossessor (Does an enemy possess the ball?) K. Pursue enemy possessor L. Pursue obstructing enemy5. Pursue the ball (Nobody possesses the ball) M. Pursue ball
      This list helped define the general shape and traversal of my behavior tree:

      graph.png

      The behavior tree would have a root node with five children below the root. Each child node would have one or more children of its own called "leaf" nodes since they themselves have no children. The tree traversal would start at the root node, then go through the child nodes from left to right until it finds one that is true. From there all of the leaf nodes (which from hereon I'll call "tasks") for that child are traversed from left to right until an action is decided on and performed by the player.




      [color=#b22222]Spltting up Tasks[/color]



      Now that my behavior tree prototype was done, I had to make some decisions: Should I split any tasks into new subtrees with their own tasks? What functions do I need to write? Would I share data between tasks?

      I decided to start by breaking up the tasks by modularity. In Unreal Editor a task is a standalone function which you may create and use in more than one place in a behavior tree. Tasks have access to shared variables stored in a "blackboard" which any task can read or write from. I looked at what tasks I could possibly modularize:

      [code=nocode:0]1. GoalFanfare (Is the ball in a goal?) A. Celebrate B. Shrug2. ScoreGoal (Do you possess the ball?) C. Take a shot D. ** Pass the ball ** E. ** Run to goal (use Unreal's internal pathfinding to avoid obstacles) ** F. ** Run to goal (use Unreal's internal pathfinding to avoid obstacles) ** G. ** Pass the ball ** H. ** Run to goal (use Unreal's internal pathfinding to avoid obstacles) **3. DefendPossessor (Does a teammate possess the ball?) I. ** Pursue enemy ** J. Run in parallel direction to friendly possessor4. AttackPossessor (Does an enemy possess the ball?) K. ** Pursue enemy ** L. ** Pursue enemy **5. Pursue the ball (Nobody possesses the ball) M. Pursue ball

      I broke every task with ** in two: One is the modular task that can be used in multiple places in the tree, and the other is the task that calculates what data to give to that modular task. I changed my behavior tree to look like this:

      [code=nocode:0]1. GoalFanfare (Is the ball in a goal?) A. Celebrate B. Shrug2. ScoreGoal (Do you possess the ball?) C. Take a shot D1. Find a nearby teammate we can pass to D2. ** Pass the ball ** E1. Determine if an enemy is obstructing our route to the goal E2. ** Run to goal ** F1. Determine if a non-enemy actor is obstructing our route to the goal F2. ** Run to goal ** G1. Determine if there is a player closer to the goal we can pass to G2. ** Pass the ball ** H. ** Run to goal **3. DefendPossessor (Does a teammate possess the ball?) I1. Determine if an enemy is near the possessor I2. ** Pursue enemy ** J. Run in parallel direction to friendly possessor4. GetPossession (Ball is still in play but nobody on our team possesses it) K1. Determine if an enemy possesses the ball K2. ** Pursue enemy ** L1. Determine if an enemy is in the way between you and the ball L2. ** Pursue enemy ** M. Pursue ball

      I needed only two Blackboard variables for passing data from one task to another:

      • KickTargetActor (read by "Pass the ball" and "Take a shot")
      • PursuitActor (read by "Pursue enemy" and "Pursue ball")



        [color=#b22222]Task Development[/color]



        I won't bore you with how I developed the blueprint for each task here, but I will say that I tried to keep all of them small and modular where possible. I thought about posting screenshots but that would be like posting random snippets of code with no context. Instead you can see

        a screenshot of the final behavior tree here.



        beahviortree1.png

        You may notice that the child nodes have "blue things" on them. Those are Unreal Editor-specific elements called "decorators." You can use them as a switch to tell the traversal whether it should iterate through the tasks for that child node. Here's the complete blueprint for my decorator that informs the traversal whether the soccer ball is in a goal:

        decorator.png


        [color=#b22222]Task Testing[/color]



        While developing tasks I bounced back and forth between blueprinting and testing to make sure all my changes worked. It was after all the tasks were written that I got the idea to write manual "Unit Tests." I would create one scene for each behavior tree traversal to verify it worked through manual observation. This definitely helped because two of the "Unit Tests" revealed bugs that would have been much harder to pin down in a full simulation. Here are some poorly lit screenshots of:

        1. A player kicking the ball into the net
        2. A player passing to a teammate that is farther away from a row of enemies than another teammate
        3. A 2v2 clump of players pursuing the ball

        unit1.png

        unit2.png

        unit3.png


        I'm aware that in Test-Driven development one is supposed to write unit tests first rather than later...so to all you developers I've offended out there by writing them last: Deal with it! smile.png


        [color=#b22222]Final Product[/color]



        Here are some screens and a video of more test scenes and a single team on a field. The screens go in progression from the start of the simulation to the end:

        [media]
        [/media]

        f1.png

        f2.png

        f4.png

        [color=#b22222]

        Implementation concerns

        [/color]

        • In the game the tree traversal always goes through all child nodes instead of stopping at the first one whose decorator returns true. I need to fix that.
        • I created a class inherited from GameMode as a hub for global functions and variables (such as the soccer ball). I suspect I'm not supposed to do this but I don't know a better place for them.
        • In each task I cast the owning actor input variable to an AI controller, then call GetControlledPawn, then cast that result to a BotTeammate to get the actual character on the field. It seems like a lot of work to get access to that character class...
        • I really wanted the human characters and bots to have identical interfaces so I wouldn't have to do "if (bot) {} else if (player) {}" branches, but haven't figured out how yet.
        • The editor recently acquired an incessant desire to rebuild the navigation area every time I start a simulation. It happens after a fresh launch of the editor after I start modifying blueprints.
        • This: https://answers.unrealengine.com/questions/49111/bug-trigger-volume-causes-trace-hit-with-no-collis.html . I resolved my issues by having traces only look for pawns. If I ever decide to add static obstacles to the field I'll have to come back to this.



          [color=#b22222]

          What's next?

          [/color]

          Now that I'm satisfied I can develop a basic soccer simulation, the next step is to start designing the game as a whole. As I wrote previously, I intend to have opposing players fight each other for ball possession. Fighting may include melee attacks, ranged attacks, and magic. It may involve launching attacks from a distance, or even team tactics where one player freezes an opponent before the other launches a localized lightning storm at them.

          There's also the matter of letting players accumulate resources to spend on armor, weapon and skill upgrades for themselves and their bot teammates. At first I was thinking a Warcraft 3-like deal where you build structures and kill creeps...but decided it would make more sense to have creeps on the field and possibly special item shops (concession stands) on team sidelines. Regular shops could appear in-between matches. Should I have player leveling? Should I allow for instant action matches where all players start at the same level and no items for a competition of pure skill?

          There's even the matter of configuring the bot teammates: Team captains could arrange the bot positions in defensive or offensive formations as well as define the aggression level for each bot. Perhaps a team captain would prefer that human players pursue the ball while bots do nothing but attack enemy players for example.

          I should probably find some people to help me design all this; preferably those who have a lot of experience with MOBA's and balancing.
Gamieon
While in-between major projects that use the Unity game engine, I decided to give the Unreal Editor a spin to see what all the hype was about. For those of you who just want to see the cool stuff first, here's a video of my first playable Gauntlet-like dungeon crawl prototype finished in about twenty five hours of work.

[media]
[/media]

The assets were all imported from Unreal's marketplace. All I did was put everything together.


[color=#b22222]Getting Started[/color]



After getting through the first hour of "I have no idea what is going on" and then watching Unreal's tutorial videos, I started setting little goals for myself to learn how to do things. The first of these was figuring out how to turn off "Realtime" editor rendering since I didn't like my computer fans going full blast while I was idle. The second was to resign myself to do something simple yet neat looking.


[color=#b22222]

Spotlight Test

[/color]

spot.png

My first accomplishment was adding a spotlight to a third-person tutorial scene and having it follow the player character. If the character stood on top of a button, the spotlight would turn off. If they got off, the spotlight turned back on. I briefly thought about developing an evade/infiltrate kind of game, but was more interested in making my own Mineralz/LoL/Tower Defenese game that took place in the old Wild West. Lets just call it "Lone Star Guns."


[color=#b22222]

Lone Star Guns

[/color]

lsg.png

The next accomplishment was prototyping the home base for Lone Star Guns. The heart of the base was a campfire. Surrounding the base and taking up most of the playfield would be rocks that you carve out to expand your base and create additional lanes for enemy zombies to come in from (thereby relieving pressure on the default lane). For prototyping purposes, I added only a few rocks around the base. There are also three resources you can have workers "mine" from: Food (crops), wood (trees), and a mine (metal). My interest faded after making a basic inanimate scene; I felt like I was borrowing too many ideas from other games and I wasn't doing any serious development anyway. I then decided to help my friend with a prototype for his version of "Gauntlet" by creating my own prototype first.


[color=#b22222]

Gauntlet Clone

[/color]

I set a goal to make my Gauntlet prototype resemble a Diablo 3 level. This was done by creating a landscape and carving out paths in it. I failed to make the landscape look like the bottom half of a cave (I'm pretty sure it wasn't designed for that) so I did a Google search for anything related to the Unreal Editor and caves. Lucky me, I found that Unreal had a Cave Effects demo on their marketplace. It was beautiful, and I wanted those assets in my scene! As I downloaded it I also noticed the Mixamo Animation Pack for character prototyping on the marketplace as well...PERFECT.

e1.png e2.png

To keep a long story short: I replaced the landscape with a collection of rocks, added neat looking particle effects and materials all over the place, figured out how to make a flaming sword and put it in a character's hand, make the character throw fireballs, and make enemies spawn and get hit by fireballs.

After about twenty-five hours of playing with the Unreal Editor since installing it, I actually had a functional gauntlet-like prototype! I admit I took a real hack-and-slash approach to learning, but I wanted to see what I could accomplish by tinkering with the Unreal Editor at my own pace.

s2.jpg s4.jpg


[color=#b22222]

What's next?

[/color]

Though I'm tempted to finish developing a game in Unreal, I'll be going back to Unity development once the studio I'm working with finalizes the design document for the new Paper Cowboys. Until then I'll probably do one or more of the following in my free time:

  • Look at what other features UE4 has to offer and put them in my own list with two measures: One for "difficulty level" and one for "coolness factor."
  • Look at UE4's asset importing. I'd like to know more about what file formats it supports and its thought process when importing meshes with textures


  • Learn more about materials and particle systems


  • Learn more about landscape generation
  • Create some basic AI
Gamieon

The focus of this journal entry is on how I integrated In-App purchase capabilities into my Unity game. I'm not going to discuss strategies for earning money from players, or how I used the IAP assets once they were integrated.



[color=#b22222]

Unity Setup for Zaubersee

[/color]
I began by purchasing a Windows Phone 8 IAP Unity package by Zaubersee at https://www.assetstore.unity3d.com/en/#!/content/10890 to get things going. Like with other third-party Windows Phone 8 assets I've used, it didn't work out of the box. I also struggled a bit with my interpretation of the documentation. After creating a new Unity test project, importing the asset, and deploying to my Windows Phone, I got this error in the status window of the demo scene:

Exception from HRESULT: 0x805A0194

I overcame this error by submitting the test project as a beta app to the Windows Phone Dev Center. I believe the asset developer tried to explain this in the documentation, but I thought that submitting a beta version of the app was merely a suggestion.

Here's what I did to build a functional test project:


  • I created a beta version of Hamster Chase on the Windows Phone Dev Center.
  • For the beta version, I made a duplicate of every In-App product that already existed for the main version. I used the same product ID's.
  • I made a new Unity project, imported the In-App purchase asset, and built the project for Windows Phone 8.
  • I opened VS 2013 to the Windows Phone 8 project I built from the previous step, then opened WMAppManifset.xml under the Properties folder.
  • I went to the packaging tab and updated the ProductID and PublisherID values to be those of Hamster Chase Beta.
  • I made a Master build of the app, and submitted it to Windows Phone Dev Center. I made absolutely sure it was a beta, and not an app to be shown in public.
  • About an hour later I got an e-mail from Microsoft with the download link. I went there from my phone, installed the app, and the purchases worked!
  • Cleanup: From my phone, I went to the home screen, then Apps, then Games to find and uninstall the test app.

    Taking this idea a step further, I opened the VS 2013 project for the real Hamster Chase, set the product ID to be that of the beta app, and then deployed it in debug mode to the device.



    Since the test app worked well, I figured it would work the first time in my game...but it did not. The app crashed after the app was restored upon me dismissing Microsoft's purchase screen.

    My guess is that in the onWP8inAppPurchased callback, I wasn't supposed to do stuff with Unity objects like changing TextMesh text values or calling Transform.GetChild(). I proceeded to move all that code into a function called DoStuffAfterPurchaseFinished(), and then I call Invoke("DoStuffAfterPurchaseFinished", 0.2f) within the callback. The crash went away after that.

    [color=#b22222]

    Unity Setup for Prime31

    [/color]
    I was about to move on entirely when I discovered that Prime31 was offering a free Windows Phone 8 In-App package (while the offer lasted) at http://prime31.com/plugins . I've worked with Prime31's assets before, and I like their brand.

    I decided to make a test app with Prime31's IAP package. Using the lessons learned from integrating Prime31's WinPhoneAds package and the Zaubersee package; I was able to quickly get a functional Prime31 In-App demo app.

    I then imported the Prime31 package into the official Hamster Chase app, and tested it. To my surprise, I had the same crash I had with the Zaubersee asset when trying to manipulate GameObjects within the purchase completion callback. As before, the Invoke workaround made the crash go away.

    [color=#b22222]

    Conclusion

    [/color]
    In the end I got both the Zaubersee and Prime31 assets to work; but I decided to stick with the Prime31 asset primarily out of brand loyalty and the expectation of continued upkeep.
Gamieon
In one effort to monetize Hamster Chase, I wanted to have ads appear in it. It took me a while to decide where to put the ads; the articles at https://inneractive.jira.com/wiki/display/DevWiki/Ad+Placement+Strategy and http://streetfightmag.com/2012/12/14/can-mobile-advertising-be-made-less-annoying/ were helpful with my decision making. I decided to have ads appear briefly at the end of each level, and at random in the hamster cage in the form of a comic strip balloon coming out of a hamster's mouth.

[color=#b22222]

Ad Portal Setup

[/color]
I created an AdDuplex account on http://www.adduplex.com . AdDuplex treated me as both someone who wanted ads in their game, and someone who wanted to put their own ads in other games. They wouldn't let me submit my game before it was published.

I created a Microsoft pubCenter account on https://pubcenter.microsoft.com . I was able to create one "ad unit" (which is a fancy way of saying "an ad banner to appear in the game" I think), but I had trouble changing it later and adding more ad units. I was informed by an online help desk representative that I couldn't do those things until my game was published.

[color=#b22222]

Unity Setup for AdRotator

[/color]

My journey with Ad integration began with AdRotator v2 beta at http://getadrotator.com/adrotator-v2-updated-to-beta-release-of-the-v2-unity-plug-in/ . AdRotator supports multiple ad providers; a list is available at http://getadrotator.com/ .



I made a new test project in Unity and imported the AdRotator Unity package into it. The first thing I noticed was the AdRotatorDemo scene had no AdRotator components in it. I figured out which ones belonged, and added them manually. Later on I discovered the menu item to do it: GameObject => Create Other => AdRotator. I clearly glazed right over "this will appear in the game object create menu" in their documentation; but in my defense I'm used to the vendor having the demo scene all set up for me.

I was puzzled by the setup: On the pubCenter and AdDuplex portals, I could choose the size of my ads. In the AdRotatorManagement script was a dropdown where I could choose the size of the banners; but none of the selections matched the sizes I assigned in the portals! I decided to just leave all the component settings unchanged.

My attention turned to defaultAdSettingsWP8. It's the file in the Unity project where you set up all your ad portal identities. I discovered I could comment out the elements corresponding to providers that I did not sign up for, and they would not be included in the rotation of served ads. I like how the developer filled everything in with demo values; it made it easier to confirm that the values I would replace them with were formatted correctly.

I then proceeded to Build and Run the project on my phone...and of course, no ads appeared. My first inkling was that I glazed over something else important in the documentation.

I opened the VS 2013 solution and ran it again. I got at least one System.IO.FileNotFound exception. Between seeing that, and revisiting the documentation, I found that I was missing several assemblies. I made sure to have the following References in my project:

  • AdDuplex.WindowsPhone
  • AdRotator
  • AdRotator.Core
  • Microsoft Advertising SDK for Windows (Silverlight)
  • Microsoft.Advertising.Mobile
  • Microsoft.Advertising.Mobile.Common
  • Microsoft.Advertising.Mobile.UI

    I deployed the project to my phone again, and the only ads that would appear were test ads for AdDuplex. The debug log reported once that it successfully got a pubCenter ad, but I don't think it ever appeared. Subsequent attempts to get pubCenter ads failed with no error description ever since. It could have been that pubCenter simply had no ads available at that moment; I never figured out what happened in the end.

    [color=#b22222]

    Unity Setup for Prime31

    [/color]
    I was about to settle for only using AdDuplex ads when I discovered that Prime31 was offering a free Windows Phone 8 Unity package for pubCenter ads (while the offer lasted) at http://prime31.com/plugins . I've worked with Prime31's assets before, and I like their brand. I grabbed it right away and built a test app with it. There was one issue I had trying to get it working: I got this message trying to complete a purchase:

    System.UnauthorizedAccessException: Invalid cross-thread access.
    at MS.Internal.XcpImports.CheckThread()

    They quickly gave me a resolution which you can read at http://support.prime31.com/13412/windows-phone-ads-fix-prime31-uihelper-has-null-dispatcher?show=13418#a13418 .

    The test app worked fine after that; I was able to see pubCenter test ads. I understand that a provider doesn't want to feed live ads to a developer's test environment, but one of my peeves as a developer is not seeing a component work in live mode before the project is published. Right after the game was published, the test ads were replaced with live ads automatically.

    [color=#b22222]Conclusion[/color]


    In the end, I decided to run with Prime31 and pubCenter ads. I'd like to see AdRotator 2 mature a bit more before I consider using its capabilities. I don't know which ad provider is the best for my game, so I'm going to start with pubCenter. I won't be able to measure its effectiveness on Hamster Chase until the press release has been out for a while and more than a handful of people are playing it. Eventually I may try switching providers or my integration strategy to see if I can improve revenue.
Gamieon
I wanted to add Facebook integration to Hamster Chase for Windows Phone 8 in an effort to have players get word out of the game through social media in exchange for a reward.

A search on Google led me to Chillster's Facebook SDK at http://forum.unity3d.com/threads/facebook-sdk-for-unity-plus-windows-phone-8.217907/ . It was free and also fairly new. I had a fair bit of trouble getting it to do what I wanted because of limitations I wouldn't accept, and because of my interpretations of the instructions. Ultimately I got it working. Here's a walkthrough I would have presented:


[color=#a52a2a]

Facebook Setup

[/color]

1. First you need to add your Windows Phone 8 app to your Facebook developer dashboard. Do this by going to https://developers.facebook.com/ and clicking on Apps at the top. If your app doesn't exist, use Create a New App and fill the proceeding form out.

2. If your app already exists (like you wrote your game for iOS/Android first), you still need to set it up. On the left side of the app's dashboard page on Facebook is a menu item for Settings. Click on it. Hidden beneath your existing platform listings is a "+ Add Platform" button. I swear I went to this page half a dozen times and never saw that button. Click on it and add your app product ID (which you get from your Windows Phone Dev Center account) to the second line. Remove the dashes and make sure you don't have curly brackets.


[color=#a52a2a]

Phone Setup

[/color]

I had to install the Facebook app on my phone before I could use Facebook integration.


[color=#a52a2a]Unity Setup[/color]



1. Add Chillster's Facebook SDK asset to your Unity project (or better yet make a test project).

2. Look up at your Unity menu bar (File, Edit, Assets...). There should now be a Facebook menu. Go there and choose "Edit Settings" and fill those out.

3. Now go to the link I mentioned at the start of this section (http://forum.unity3d.com/threads/facebook-sdk-for-unity-plus-windows-phone-8.217907/ ), and read Chillster's official documentation for getting set up starting with step 2.1. You've already done step 2.3, so you can skip that step.


[color=#a52a2a]

Unity Usage

[/color]

My goal was to make it so users could send app requests to friends which invited them to download my game. So when I found this in the code comments:

[color=#0000cd]"... throw new UnityException("There is no Facebook AppRequest on Windows Phone 8"); ... "[/color]

I thought it was just an asset limitation. For a while I tried using FB.API() to get the job done starting with getting a friends list. I simply could not get that to work until I finally called "FB.API("me\friends"...)" (note the direction of the slash), and making sure to include the "user_friends" permission at the login. Then I tried a number of ideas to send an app request by using FB.API(); all failed. I ultimately settled for just doing a post on a player's feed by calling:

var wwwForm = new WWWForm();wwwForm.AddField("link", "http://www.gamieon.com/hamsterchase");wwwForm.AddField("linkName", "Hamster Chase for Windows Phone 8!");wwwForm.AddField("linkCaption", myCaption);FB.API("me/feed", Facebook.HttpMethod.POST, fb_OnFeedComplete, wwwForm);

It doesn't show the link name or caption in my feed; but I'm going to leave those in anyway in case they someday appear through either asset or Facebook-side updates.


[color=#a52a2a]Conclusion[/color]



I ultimately released Hamster Chase with Facebook integration. It works for posting to Facebook feeds, and it was nice to see it work without having to publish the game first (unlike other assets I integrated with). I'm sure it won't be long before future versions of Facebook integration assets are released with easier setups and more features; including app requests.
Gamieon
In a previous journal entry I described my experiences converting my Unity iOS/Android app to Windows Phone 8. Here I continue on about my experiences with combating app slowness as well as setting app properties from the generated VS 2013 project.


[color=#a52a2a]

Transparency Performance Issues Resolved

[/color]

Experience has taught me that iOS is efficient with transparent rendering; and Android not as much. When the Unity profiler reported that transparent rendering was very slow for Hamster Chase (~18ms per frame) in a very basic scene with a low polygon count, I was about to give up hope of porting any of my games entirely entirely until I discovered the problem:



I wrote a component that would smoothly fade meshes in and out. When they were invisible their renderers were enabled, but the main color's alpha value was set to zero. This turned out to be a huge performance killer as perhaps a quarter of the scene, consisting of prompts and menus, was this way.

Upon changing my component to disable the renderer when the alpha value was zero, the major performance problems went away. I still think it should have run faster regardless, but I digress.

Wondering how well another game of mine would perform, I converted and deployed a Master build of "Hyperspace Pinball" to my Windows Phone. It makes heavy use of particle systems and transparent rendering, so I expected it to get a low frame rate. After playing for just two minutes, I confirmed this to be so. It was a far cry from the very fast frame rates of every other pinball game I've ever played. I did not run the profiler or look into it further; perhaps someday I will.

Having eliminated the performance issue in Hamster Chase, all that was left to do before releasing it was to set up the splash screen, app icon, and app properties (app ID, permissions, etc.); and integrate third-party Facebook, In-App Purchase and Advertising assets.


[color=#a52a2a]

Splash Screen and Icon

[/color]

I was not able to configure the splash screen from my version of Unity, but I did find where it was located in the VS 2013 project. In the root of the project are five files:



SplashScreenImage.jpg
SplashScreenImageLandscapeLeft.jpg
SplashScreenImageLandscapeRight.jpg
SplashScreenImagePortrait.jpg
SplashScreenImagePortraitUpsideDown.jpg

As my game is landscape, I replaced the first three files with my splash screen image file. I made sure my image retained the same width, height, and orientation as the one I overwrote.

In the Assets folder I found ApplicationIcon.png, and replaced it with a png of the Hamster Chase icon with equal dimensions as well.

After subsequent project builds from Unity, none of my changes got undone.




[color=#a52a2a]

App Settings

[/color]
Further poking around in the VS 2013 project led me to WMAppManifest.xml under the Settings folder. Here I found that I could set the app capabilities, requirements, product ID and publisher ID.

Those values also remained untouched by subsequent Unity builds.


[color=#a52a2a]

Facebook, In-Apps and Ads

[/color]

Integrating each third-party component to make Hamster Chase more feature-rich was a unique challenge. I plan to write about them in subsequent journal entries with the aim of making them helpful references to other developers.

Gamieon
A couple weeks ago, a friend tipped me off to a free Microsoft Unity workshop that was held in Orlando, FL. Though reluctant at first, I decided to go. I needed to get out of my lone wolf developer cave, meet other folk, and see what Microsoft could do to help me port my mobile games to Windows Phone 8. Long story short, it was a good experience and I was on my way to getting those games ported.

Having released Hamster Chase for iOS and Android already, I figured getting it deployed to my Windows Phone would be a breeze...but it wasn't.

[color=#b22222]

Upgrading the project to Unity 4

[/color]

The first step was to make a branch of Hamster Chase for Unity 4. Right away I got a number of new compiler warnings; mostly about the GameObject.active setter being deprecated for GameObject.SetActive(). After fixing and re-testing all of the related code, I found another issue: in Unity 3.x, I would set certain objects to be "static" (motionless) objects at runtime when they wouldn't move, and then unset the static flag before they were to move again. I thought this would provide an optimization in rendering, and possibly with the physics too. In unity 4.5 at least, it would seem that once an object is static, it is always static and would never move again. I fixed this by simply never setting the static flag in the first place.

Those were the only two issues I dealt with during the upgrade process. With all the compiler warnings and static behavior fixed, I was ready to change the platform to Windows Phone 8.

[color=#a52a2a]

Fun With Frameworks

[/color]

After changing the platform, I attempted to build the project. Right away, I got errors related to my Prime31 Android & iOS plugins. Prime31 is an organization that develops plugins which enable developers to implement social network check-ins, ads and in-app purchases. It's a shame they also don't include a 'Monetization for dummies' manual with those plug-ins, but I digress. I wish I had retained the exact error messages for others to find on Google, but alas, I didn't think of it at the time. I ultimately fixed the errors by deleting all of the Prime31 plug-ins, and changing my side of the code to only look for them in the iOS and Android platforms.

My next build attempt gave me these more memorable error messages:

  • [color=rgb(17,17,17)][font=Helvetica]

    [background=rgb(254,254,254)]Error: 'WriteAllBytes' is not a member of 'System.IO.File'[/background]

    [/font][/color]
  • [color=rgb(17,17,17)][font=Helvetica]

    [background=rgb(254,254,254)]Error: type `System.Xml.XmlDocument` doesn't exist in target framework.[/background]

    [/font][/color]
  • Error: `System.Security.Cryptography.MD5CryptoServiceProvider` doesn't exist in target framework

    There are three ways you can deal with these:

    1. In Unity, go to File => Build Settings => Player Settings. In your Inspector window, expand Other Settings, and change your API Compatibility Level to .NET 2.0. [color=#ff0000](Note: I had already fixed System.IO and my MD5CryptoServiceProvider compatibility issues before trying this, but I think it should work)[/color]
    2. Find an existing implementation that you can copy into your project.
    3. Write your own code to replace the functions provided by those frameworks.

    I opted to do 3 to keep the binary size at a minimum; of course that took a fair bit of time to do.

    [color=#a52a2a]A "Successful" Build?[/color]



    BoXWIpaCEAA0ZDM.png

    After fixing all that, I managed to get Hamster Chase to deploy to an emulator. I noticed the splash screen was of Unity and not from the game; nor was there a setting to change the splash screen in the Player settings. I hope to deal with that from the Visual Studio project itself later. I was happy...

    ...and then my happiness was shattered once I got it deployed onto my new Nokia Lumia 521. I was barely getting 15 FPS on the device! The game was choppy, overlays that should have faded in instead went straight to fully visible, and popup menu animations were even choppier than the game.

    After attaching the Unity profiler to my phone via IP address (it takes like 45 seconds to connect), I pinned the main problem to a GameObject.FindObjectsOfType being called in every frame. After fixing that, the game was slightly faster. It was still far from the silky smoothness I see in most mobile games. The main culprit is now transparent rendering which is taking up over half the workload each frame. In the main menu alone it takes 18ms per frame. I had the same problem with Hyperspace Pinball; and it took months to optimize it just enough to even be releasable. I am not going through that again.

    Thinking the problem was that the VertexLit shader was slow on mobile, I decided to try my hand at writing two transparent mobile shaders:

    Unlit shader:Shader "Mobile/Transparent/Unlit" { Properties { _MainTex ("Base (RGB) Transparency (A)", 2D) = "" {} } SubShader { Pass { // Only render pixels with an alpha larger than 50% AlphaTest Greater 0.5 SetTexture [_MainTex] { combine texture } } }}
    Simple lit shader:Shader "Mobile/Transparent/Simple" { Properties { _MainTex ("Base (RGB) Transparency (A)", 2D) = "" {} _IlluminCol ("Self-Illumination color (RGB)", Color) = (1,1,1,1) } SubShader { Pass { // Only render pixels with an alpha larger than 50% AlphaTest Greater 0.5 SetTexture [_MainTex] { constantColor [_IlluminCol] combine texture * constant } } }}
    After using

    these on the most prominent main menu objects, I didn't get a visible performance gain.



    [color=#a52a2a]What's next?[/color]



    It occurs to me that Hamster Chase was developed before Unity had Sprites and Sprite Renderers. In Hamster Chase, the existing "Sprites" are rendered using regular MeshRenderers and VertexLit shaders on simple four-corner squares. I think if I changed my "Sprites" to be actual Unity Sprites, things would render faster. I'll have to ponder if and how I would accomplish that because it could easily be a ton of work.

    I still have trouble wrapping my head around the fact the game is this slow as is using out of the box shaders on such a sophisticated piece of equipment. It's notably faster on both iOS and Android; what am I missing here? I hope to find a solution and publish a follow-up journal entry on it.
Gamieon
I finally got Paper Cowboys to a playable alpha state. I originally wanted to wait until it was much more polished; but I decided this was a good way to find people interested in helping me finish the game through constructive feedback, help with PR and play testing. And besides, if something is playable, why not post it?

Paper Cowboys is available via Unity web player at http://www.playpapercowboys.com

A couple points of interest:

  • WSAD to move, Left Mouse to fire, Right Mouse for special weapon attacks if you have any.
  • There are only three levels right now. After you beat the third one, the game just stops.
  • Shoot barrels for random special weapon drops. Use Right Mouse to use.
  • Shoot hats off enemies and pick them up!
  • Shoot enemies for ammo and weapon upgrades.
  • Don't forget to go into Options from the main menu and set your profile name and color


  • It's multiplayer; so try to play with a friend! Hopefully that works...remember I'm a team of one and this has never been tested by the public until now.
  • Contact me if you'd like to be a play tester, co-designer or would like to help with PR.


    Here are some new screenshots I took; hopefully these will be among the last where there's only one player (myself).

    Unity 2014-05-05 18-33-09-67.jpg
    Unity 2014-05-05 18-33-22-29.jpg
    Unity 2014-05-05 18-33-36-22.jpg
    Unity 2014-05-05 18-33-43-82.jpg
    Unity 2014-05-05 18-34-04-56.jpg
    Unity 2014-05-05 18-34-30-19.jpg
    Unity 2014-05-05 18-34-43-04.jpg
    Unity 2014-05-05 18-35-12-32.jpg
    Unity 2014-05-05 18-35-27-13.jpg
    Unity 2014-05-05 18-35-43-98.jpg

    Unity 2014-05-05 18-40-57-28.jpg


    Unity 2014-05-05 18-41-01-04.jpg
Gamieon
Updates have been few and very far between; mainly because most of the work I've done doesn't directly result in new stuff to show everyone. I'm over that part now, and papa's got a brand new bag!

Special Weapons


Special weapons get spawned at random when players shoot barrels. If you're one of those people who plays Diablo 3 and never gets a legendary drop; don't fret. The game is designed to guarantee you a special weapon if you shoot enough barrels. Three special weapons that players can use have been implemented so far:

Airstrikes


[media]
[/media]
Nothing says "old time western" like an F-22 Raptor using laser-guided munitions to destroy outlaws. I know some purists out there will say "what is this!? why do you have an airstrike in an 1800's themed platformer!" Why? Because it's my game and I said so! Besides, how many other online western platformers have airstrikes? HOW MANY?!


Hawk


[media]
[/media]
Why stop at having cowboys kill outlaws, when you can have animals do it too? The hawk will blissfully perch atop its owner's head until it gets the command to attack. The hawk will search for the enemy farthest from the player, and dive after it. Any enemies it intersects along the way will either die or take a lot of damage.

Here is the enemy using it on the player.


Beans


[media]
[/media]

Beans beans the magical fruit...makes outlaws run and makes you toot. When you activate a can of beans, your player farts both visually and audibly. All enemy projectiles will reverse course, and all enemies will run away.



One of the proudest moments of my development career would have to be witnessing the purchase confirmation screen on audiojungle.com for the farting sound effect.
fart1.png
Followed by writing the code for it.
fart2.png


New hat drop rules


It used to be that you had a chance of getting a hat each time you kill an enemy, and one of the features I wanted to add later on was a bonus for headshots. I got an idea just a few days ago that combines both: Now you get hats by shooting the hats off of enemies. When you do, their hat flies off and falls to the ground. The player who shot it off can pick it up and put it on. If you're playing with others over the Internet, the hat will only fall off on your screen. Everyone else still has a chance to shoot it off on their running instance of the game until the enemy dies.


General content cleanup


I played through levels 1-3 and studied ways to improve all of them. I recduced the field of view slightly; this resulted in everything looking bigger and I think better. I also added more barrels to increase everyones chances of getting special drops, and shuffled some of the level 1 content around a bit. As for the rest, well, you can see for yourself in this video.


What's next?


The next update will be the announcement that I'll be calling on developers and only the most seasoned testers to help me play test the first three levels of Paper Cowboys. As it is the first alpha, it should have the most bugs. I'm therfore making it a general first-impression look-for-any-annoyances testing session. I'm sure I'll get a wealth of feedback since I've mostly worked on this project alone.

I'm also thinking about an extremely important question: When should I submit to Greenlight? I'll have to research other dev blogs and solicit other developers for answers.

As I may have mentioned before: I am very interested in getting Paper Cowboys on Steam and in a Humble Bundle. Even if I don't break even in sales, I'd like to earn my place in the "family." After two decades of casual game development without achieving that level of success, it would mean a lot to me.
Gamieon
In December 2013 I entered into a small "venture" with the Skillz team to make a simple game called Tiltz Tournament where players could compete for game coins or real money. I developed the core game, and they provided the tools for matchmaking and account management. Here I write about my experiences in hopes other Skillz developers can benefit, find solutions to issues, and avoid the mistakes I made. This entry is laid out in six parts:

  • Getting the Unity project set up for Skillz
  • Getting the XCode project set up for Skillz
  • Setting up Parameters and Tournaments on the Developer Portal
  • Completing the Skillz integration in Unity
  • Completing the Skillz Integration in XCode
  • Testing production mode


    If you're the impatient type like I am, just go to QUICK BUILDING REFERENCE to see how to build a Skillz-enabled game for your iPhone.


    Getting the Unity project set up for Skillz



    After the core game was created in Unity 3 and tested on my iPhone, I followed the instructions on the Skillz homepage to integrate their SDK into the Unity side of the game. Upon trying to import the Unity package, Unity crashed. This was because the package I got was exported from Unity 4 and is not compatible with Unity 3. My project would no longer open in Unity 3. I fixed it by doing the following:

    1. Going into Finder and deleting the SkillzDelegate prefab from the project's folder.
    2. Starting Unity
    3. Making my own Skillz prefab by:

    A. Making a new empty game object
    B. Adding the Skillz and SkillzDelegate scripts to it.
    C. In my Unity Project tab, click on Create, select Prefab.
    D. Drag and drop the game object to the prefab.

    Before continuing the integration, I wanted to make sure I could still build the project and deploy it to my iPhone. Since Skillz requires iOS 7, I had to go into my Unity project settings and make sure I maxed out my iOS version settings. Unity's deployment target only went up to 6.1, so I had to change the app deployment target to 7 from XCode later on. I also had to make sure my project was set up for iPhone only. I then proceeded to build the project from Unity so it would generate the XCode project.



    Getting the XCode project set up for Skillz



    XCode didn't open automatically because Unity 3 doesn't know how. Still, the iPhone assets were created, and I was good to move forward.

    The first thing that tripped me up in XCode was that the deployment target (at the top left next to the Play and Stop buttons) was set to the simulator, so I got a bunch of build errors. I plugged in my iPhone 4 and made sure the deployment target was my iPhone.

    I went to the General tab of the project, made sure the deployment target was iOS 7, and that the Device Orientation was only Portrait. Scrolling down further I noticed that some app icons were missing. Again, Unity 3 didn't know to put them there. I had to generate icons in the missing dimensions using The Gimp, and import them into my XCode project folder. Then I assigned them to the icons in the General tab.

    I then followed Skillz' instructions to integrate their SDK into the XCode project.

    After that, I tried building using the Command-B button. I got several linker errors indicating the std library was missing, and some Game Center-related functions were missing. A little puzzling, but I found the solutions. Under the Build Settings tab, I selected (All) and (Combined) at the top. Then I scrolled to the section called "Apple LLVM 5.0 - Language - C++." There was an entry for "C++ Standard Library." I set it to "libstdc++" and that fixed the std linker errors. After that, I went to the Capabilities section and turned on Game Center (it is bound to my Apple account so you may not have this problem).

    I then attempted to build the app again, and it succeeded. I was then able to deploy it to my iPhone 4. Of course I did not actually invoke Skillz functionality in the project, so the app behaved just as it did before.

    At the top of the screen was the pesky status bar (battery life, time, etc.). I made it go away in subsequent builds by going to info.plist, adding "View controller-based status bar" and setting it to NO.



    Setting up Parameters and Tournaments on the Developer Portal



    The next step was to set up the tournaments on the Skillz developer portal. My journey began on the page where I had to enter Parameters. It took me a while to realize that the Parameter list was a collection of every possible unique property of a game for any tournament, and the Parameter list values are the DEFAULT values that the tournament-specific parameters get populated with on the developer portal in the next page. In my game, the Parameters which defined a unique game were the duration of the game and the existence of obstacles. So on my developer portal, Tiltz Tournament has a grand total of two parameters called "TimeLimit" and "Obstacles". TimeLimit has no whitespace because I got errors trying to fetch "Time Limit" from the parameter dictionary from Skillz, and decided I didn't want to deal with it. The value of "Obstacles" is "On" because most tournaments have them turned on. The value of "TimeLimit" is "90" for the same reason.

    As for the Tournament list, I could not add or remove entries. I could only change existing ones. Furthermore, the entry fee and player counts seem to be linked. I'm cool with that. I also decided I didn't need more tournaments than they had existing; having more than eight would be overwhelming to the player I think. I ended up using 5 tournament slots for myself, and renaming the other 3 tournaments to N/A so the Skillz team knew not to include them. One of the N/A tournaments was a special developer tournament where I made "TimeLimit" a value of 5. This enabled me to test the game ending due to the clock running out without having to wait 90 seconds.

    By the way, after you fill out the Parameters and Tournament List, you go into sandbox mode automatically. Another important bit: You can ALWAYS GO BACK AND CHANGE YOUR TOURNAMENTS, PARAMETERS, AND MOST ANYTHING ELSE. I find that to be a particularly helpful facet of the Skillz developer portal.


    Completing the Skillz integration in Unity



    What threw me off the most was not understanding the flow that Skillz had intended for the game. The flow is basically this:

    1. Main Menu
    2. Skillz Interface - Game selection / matchmaking
    3. Game
    4. Skillz Interface - Game completion
    5. Skillz Interface - Game selection / matchmaking
    6. Game
    7. (repeat 4-6)
    8. Main Menu


    The main menu is the launch point for a continuous back-and-forth between your game and Skillz. If a player quits from Skillz, only then should they be taken back to your main menu.

    As I implemented the Skillz functionality into my game, I learned that the Skillz package doesn't seem to like Unity calling Application.LoadLevel from a Skillz callback; at least in Unity 3. When you write your game in Unity 3, you should make sure you have a reset function in one of your scene components so that you can effectively "reload" the scene without actually reloading it. Even if it doesn't crash for you like it did for me, you save yourself the time of reloading all the scene assets. Be sure that your reset function also pauses the music.

    One thing I was not a fan of were the developer TODO comments in the Skillz scripts where I had to write my own code. This is because if I download a new package, I could overwrite their old scripts and therefore my changes to them. I wrote my own static class with functions to be called from Skillz's callbacks to minimize any pain of re-importing their scripts.


    Completing the Skillz Integration in XCode



    After finishing the Skillz integration on the Unity side, I was ready to take a test drive in sandbox mode on my iPhone. After building and running it, and learning the lessons that I wrote about above, I was able to get it working smoothly with two exceptions.

    First, there was a bug where if you tilt your iPhone in a way ideal for landscape, and you quit the game, the Skillz interface would get all glitchy and messed up looking. I fixed this by opening Classes/AppController.mm, going to the function

    (NSUInteger)application:(UIApplication *)application supportedInterfaceOrientationsForWindow:(UIWindow *window)

    and commenting out the landscape enumerations so that they were not included in the return value.

    Secondly, I noticed my app icon was missing from the Skillz interface next to the "Go back to " button. I never did figure out how to fix that.


    Testing production mode



    Now it was almost time to make the release. I turned off sandbox mode, uploaded an App Store-provisioned .ipa file to my Skillz developer portal, clicked the Sync button on the Skillz developer portal, then clicked on the Play button in XCode to build and deploy it to my iPhone. I kept getting this error when going into Skillz: "Sign Up Error - Invalid client serv request." After going back and forth with the Skillz team, I figured out that the problem was the manner in which I installed the app onto my phone. I fixed it by deleting the app from my iPhone, and then adding the .ipa file (the one I uploaded to Skillz) to my iPhone by using XCode Organizer. After doing that, the error was gone, and testing seemed to work out.

    In subsequent builds, I got the same Sign Up error again because I had forgotten to upload and Sync my latest .ipa to the Skillz portal.

    I also asked the Skillz team to help me test because I only have one device, and they have several they could test with at the same time. Besides that, it's also in their best interests that the game is solid smile.png.

    After all that, I had Skillz help me with the app description and the app rating. I then submitted the game to the App Store.


    Post production



    The first release of my app was with the Skillz 2.x SDK. I summarily made a new build with a 3.x version of the SDK. None of the Unity-side scripts appeared to change, though I made sure all of the non-Unity assets were updated.

    I accidentally tested on a device that was not connected at the time. Once the game attempted to enter the Skillz portal, I got a notification that the device was not on the internet. Nothing happened after that for an indefinite period of time. This will be a cause of frustration for players, so in a subsequent update I will use Unity's functionality to determine whether the device is online when the player taps the play button. Keep in mind the device could still lose connection in the game (like if they're playing and get on an elevator, or they go out of wi-fi range). I informed my contact over at Skillz about it.



    QUICK BUILDING REFERENCE

    (Dec 2013)

    Here is the process I would undertake doing a build with Unity 3 from scratch in December 2013:

    1. Follow the Skillz instructions for importing Skillz assets into your Unity game (but don't import any prefabs unless you're 100% sure they're Unity 3)
    2. In Unity, make sure your build target is iPhone only and using the most recent iOS version settings possible. Make sure your orientation is Portrait.
    3. In Unity, do a Build and Run. Select the Replace option (since I assume you want to build from scratch).
    4. After Unity finishes what it's doing, open XCode to the created project if it's not there already.
    5. Follow the Skillz instructions for integrating the Skillz SDK
    6. Make sure your deployment target is iOS 7.0
    7. Make sure your orientation is Portrait.
    8. Make sure all your icons in the General tab of XCode are assigned.
    9. Make sure all your necessary capabilities are assigned in the Capabilities tab of XCode.
    10. Open Classes/AppController.mm, go to the function

    - (NSUInteger)application:(UIApplication *)application supportedInterfaceOrientationsForWindow:(UIWindow *window)

    and comment out the landscape enumerations so that they are not included in the return value.

    11. Under Build Settings, scroll to the section called "Apple LLVM 5.0 - Language - C++." There is an entry for "C++ Standard Library." Set it to "libstdc++"
    12. Go to info.plist, add "View controller-based status bar appearance" and set it to NO.
    13. Connect an iPhone to your machine and make sure XCode is set to build and deploy to it.
    14. Go to the Product menu and select Clean
    15. Click on the Play button to build and run.
Gamieon
It's been a while since my previous update, but I finally have some content to show off for the new level 1 in Paper Cowboys full! The reasons it took me so long:

  • Procrastination: I simply didn't have that creative spirit and motivation. I've been rather busy at my full time work and exercising lately.
  • Overdesign: I spent at least five hours worth of time figuring out that the game play of the 48 hour build was just fine.


    I'm still a few weeks behind; by now I wanted to have three levels finished! But now...without further delay...video of level 1 WIP!

    [media]
    [/media]



    Some of the noteworthy changes:

    • When an enemy dies, they become a stick figure ragdoll and fall to the ground.
    • Barrels and drums are subject to "regular" physics. If you shoot them they rock a little bit. If an enemy hits them they do the same.
    • Tumbleweed!
    • New buildings
    • Cleaner camera movement
    • New environmental obstacles (rocks)
    • Items will drop from enemies and barrels "randomly" with a twist: You are guaranteed an item drop after a number of failed attempts. Furthermore, you must have a hat before you can have a different weapon.


      And these under the hood changes:

      • All of the old animation classes I coded for the old version have been deprecated. I now use Unity 4's animation objects.
      • I made new objects for most everything; including players and enemies. They're easier to maintain and more versatile (One prefab can now manage the behavior of four different kinds of enemy instead of having four prefabs).


        I've also made some design decisions:



        • I'm not going to let players buy equipment with money. That would just result in players farming for cash, and the better players will always have the best gear leaving the little people behind.
        • I'm not going to have character leveling. This game needs to be kept simple...I will however consider achievements.
        • If using RPC's to indicate players firing or starting and ending their moves is too slow, I'm going to turn to an unreliable model where every player has a single game object with a network view that streams an integer where the bits indicate button presses.


          What's next?

          I haven't done network testing in weeks, and I have much catching up to do. I also need to add the transitions between levels and the end-of-level sequence.
Gamieon
I'd like to release Paper Cowboys for the PC, Mac, Linux, and for at least one console. It therefore only makes sense to plan ahead for having multiple players controlled by the same running instance of the game. Even without a console release, the idea of friends sitting around the computer with gamepads playing together can be fun.

Check out this short development video I made which demonstrates the game host bringing their player into it via keyboard, then a player joining from another computer, then the host bringing in a third player using a game controller.

[media]
[/media]

I was able to get it all working by implementing these concepts:




Players and network clients are not the same thing

To develop a game like this, you have to think carefully about what defines a player. Is it a client? No, because a client can manage inputs from multiple players; just like how an Xbox One can handle eight controllers. Is it the actual character walking on the screen? No, because the character is just the means by which a player interacts with other players and the game environment. If your character dies, the player is still in the game.

At most any given time, every running instance of the game has the list of all the instances running in the same game, as well as a list of all the players. Each player has a unique two-value key: The network ID, and the local ID. The network ID is the identifier of the running instance of the game which created the player. The server's network ID is always 0, and a client's network ID reflects the order in which they joined the game (1, 2, 3...). The local ID identifies what interface the player is using. A value of 0 means they're using a keyboard and mouse. A value of 1 means they're using joystick 1, a value of 2 means they're using joystick 2, and so on.


Players and interfaces are not the same thing

In the previous verison of Paper Cowboys, player 1 was bound to keyboard and Joystick 1 controls. Player 2 was bound to Joystick 2, Player 3 to Joystick 3, and so on. This created an unforeseen issue: What if two people wanted to play using the Keyboard and Joystick 1, respectively? The answer was that they could not. If player 1 wanted to use the keyboard, then nobody could use Joystick 1.

My solution was to have player 1 choose whether to use the keyboard or joystick 1; and to have all the controls configured per-interface rather than per-player. Most of the time, player 1 will opt to use the keyboard. A second player can join in by pressing the start button on any joystick. No matter which joystick they use, they will always be player 2. That makes sense because, after all, there are only two players. If player 1 prefers to play games with a joystick, they can opt to use it. In that case, they can still use the keyboard to bring up the game menu or chat with other players; only they will be using joystick 1 for all the character movements. Other players can join in by pressing the start button of any other joystick.

keyboardconfig2.png keyboardconfig.png



What's next?



Now that I have characters spawning in the game, my priority is getting a playable level 1 ready for the closed alpha release. This will take a great amount of care because if a player is not impressed, it may be the last level they'll ever play. I'll begin designing what content will be in the level; and then design how to make it randomly generated smile.png
Gamieon

Now that the intro and main menu concepts are done, I'm moving on to changing the networking model closer to authoritative server.



The goal is to minimize the chance for major conflicting game states (such as an explosion only happening on some clients) and to make speed and money hacks a little harder to do. It has to be done while trying to keep the game responsive and realistic (when my bullet hits the bad guy, I expect them to take damage). I also want to have the game support running as a dedicated server, which the current version does not support.

(Note: I develop in Unity, so what I write from hereon will be biased toward Unity developers)

The journey began with reading https://developer.valvesoftware.com/wiki/Source_Multiplayer_Networking and using it as a checklist for my implementation. So far, I've achieved Entity Interpolation and Input Prediction; I haven't done anything for Lag Compensation yet though it did give me some ideas. I'm also following these basic guidelines (not set in stone as I'm still learning, by the way):

  • You can't just blindly attach network components to everything in the game and call it a day. Every object has unique needs; some of them may not even need network components.
  • The server will almost ways be the one to instantiate network objects. The only exception to this are player objects that only require a visual presence, such as the player's stick figure arm rotating to show their aim.
  • The game should always immediately respond to keyboard, mouse, and joystick inputs.
  • Don't stream player inputs. Just send reliable messages when players press or depress buttons.
  • Servers and clients will both use collision detection for player-enemy contacts; but only the server will decide whether the contact results in hitpoint loss or visible damage.
  • Instantiations and buffered RPC's always get invoked first when a player joins. Minimize buffered RPC's and try to send them in the beginning of the object's lifetime if you have to; and make sure they get called in a predictable order.
  • Never trust the client.


    After a bit of work, you can see the results here. This movie was cobbled from videos taken on two different computers; one hard-wired to my FIOS connection and the other tethered from my smartphone. The video editing is imperfect, but I did my best to try to demonstrate how things look between the client and the server in a game with higher-than-desired latency.


    [media]
    [/media]




    The swinging stick figure arm follows the mouse cursor position of the owning player. It is a standalone object with its own network view where OnSerializeNetworkView will read the owning player's current rotation, and just assign it to the arm. No interpolation, no other magic involved. It is the only object in the scene; and at present the entire game, that clients can instantiate.

    The bullets that fire from the pistol are not network objects. When the server player fires, an RPC is sent to all the clients which includes the weapon ID and arm rotation; and then a local (non-networked) projectile is instantiated in the server's scene. When a client gets the RPC, they update the server player's arm rotation and instantiate a projectile in their client scene. Both the server and client's projectiles follow the rules of physics; but only the server decides if anything loses hitpoints in the process. The bullets are always launched from a position relative to where the player is standing at the time.

    When a client fires, an RPC is sent to the server with the weapon ID and arm rotation. After that, a local projectile is instantiated in the client's scene. When the server gets the RPC, it verifies that the client has the weapon and enough ammo to fire it. When it does, it RPC's a message to every other client that this one fired, and then instantiates its own projectile.

    When a client moves back and forth, the only RPC's exchanged between the server and client are the new client's velocity caused by the client pressing or depressing a button. Input Prediction makes sure the client's movements are immediate while being reasonable with the server's expectations; if the client strays too far they will get "rubberbanded" backwards as you may have seen in other games. Other clients simply use Entity interpolation to simulate the movements of the client and server players based on the data that the server gives them in OnSerializeNetworkView.


    This is my initial solution, and my comfort level is currently "uncertain." I need to see it in action before I can pass judgement. I suspect I will see reports of players shooting things but not killing them. I feel like I can do more about the projectiles, though I haven't figured out what yet. I also wonder if streaming unreliable player inputs are faster than using reliable messages; and if so, is it worth the additional traffic? After all, players are constantly moving and changing direction anyway, so maybe it won't make for that much more traffic?



    The next step



    Up to now, I've been entirely focused on engineering. I really need to map out the game design. This is the part that should be a lot of fun; but I also want to be careful about it. At one extreme, I could have a simple side scroller ala Sunset Riders with little enemy and weapon variety. At another extreme, I could have a very diverse ecology of enemies, a big weapon and item selection, leveling, skill trees, and plug-ins. Both can be fun in their own way; and though I favor the simpler scroller, there's something to be said about replayability in the presence of a leveling system and unlockable items.

    I also want to have randomly generated content in each level. For example, level 1 is a simple left-to-right walking level, but I want there to be different buildings every time. Level 2 is probably going to be a jump-the-platforms level like the waterfall level in Contra, and I want the platforms to be randomly placed.
Gamieon
It is my hope to release Paper Cowboys as a multi-player (both local and online) side scroller for the PC and console platforms in the summer of 2014. A "48 hour build" is already available on GameJolt, and the final release will have more great content, a storyline, and polish.

[media]
[/media]

A couple notes on the style:

  • All the non-text art assets were drawn in MS Paint.
  • The art style is not rough; the final product will be stick figure art through and through.


    The Intro Sequence
    The intro sequence is 90% done; I just need to convert the raster comic images to vector to improve the quality, and get some feedback on ways to make it better.

    The Play Menu
    I can easily be persuaded to change the Play Menu layout depending on player feedback. The "Quick Join" item will try to put you into an existing game with a good ping; preferably one with friends and as close to the start of the game as possible. I have not started the implementation yet; I need to look online for how other developers do it. Then there's the classic "Search For Games" which imitates a typical Steam server list and lets you filter on games. Finally, "Start New Game" lets you host a game. I plan on dedicated server support so hopefully it's not a heavily-used option.

    Paper Cowboys is not optimized to be a single player game. The only way to play single player is to host your own game with the player count set to 1. When players do join mid-game, I'll also have to make sure they aren't stuck with level 1 weapons at, say, level 7.

    The Controls Menu
    Note how the layout of the Controls menu provides for four players; three of which are gamepad only. It is my intent to let multiple people in front of one computer play the game, even a network game. There's just one problem: Only player one can use the mouse to aim and the others will always have to shoot forward unless I find a better way to handle it.

    Unity developers: Note how I even have a Controls menu at all. I'm suppressing the Unity startup window, and using my own PlayerPrefs-based system to manage user controls.

    The Next Step
    I'm currently working on the character animations for the three classes. This work includes replacing the scripts I used to animate the characters with Unity 4's animation components.

    I'm also rewriting the character movement scripts. In the current version of Paper Cowboys, the network model I use is non-authoritative. Clients tell the server where they are, and the server happily forwards that information to all the players. I want to bring Paper Cowboys closer to an authoritative model where the server validates client states to minimize cheats like speed hacks on official servers.

    Updates will come slowly as I'm also in the middle of several other collaborations, but stay tuned anyway!
Gamieon
Apologies for the terribly boring journal entry thumbnail image. Anyway...

With every new project I try to make better tools to carry into my future projects. One of them has to do with the local game configuration and PlayerPrefs. There are two issues I have with PlayerPrefs:


  • Using PlayerPrefs.Get... is slow in an Update() or an OnGUI() function (at least it was for me on mobile), and you have to grab the value in Awake() or Start() into a member variable and use that to avoid the issue.
  • No PlayerPrefs.GetBool() for yes/no toggling.

    So I decided to make my own static class that not only addresses both issues, but does so in a way that I find convenient for organization. I call this class the "ConfigurationDirector."


    The Preference Cache



    For those of you who learn by staring at code first, or just want to copy it into your project, here you go (C# version):public static class ConfigurationDirector { #region Preference Cache static Dictionary cachedFloatProps = new Dictionary(); static Dictionary cachedStringProps = new Dictionary(); static Dictionary cachedIntProps = new Dictionary(); public static float GetFloat(string prefName, float defaultValue) { if (!cachedFloatProps.ContainsKey(prefName)) { cachedFloatProps.Add(prefName, PlayerPrefs.GetFloat(prefName, defaultValue)); PlayerPrefs.SetFloat(prefName, PlayerPrefs.GetFloat(prefName, defaultValue)); } return cachedFloatProps[prefName]; } public static void SetFloat(string prefName, float newValue) { PlayerPrefs.SetFloat(prefName, newValue); if (!cachedFloatProps.ContainsKey(prefName)) { cachedFloatProps.Add(prefName, newValue); } else { cachedFloatProps[prefName] = newValue; } } public static string GetString(string prefName, string defaultValue) { if (!cachedStringProps.ContainsKey(prefName)) { cachedStringProps.Add(prefName, PlayerPrefs.GetString(prefName, defaultValue)); PlayerPrefs.SetString(prefName, PlayerPrefs.GetString(prefName, defaultValue)); } return cachedStringProps[prefName]; } public static void SetString(string prefName, string newValue) { PlayerPrefs.SetString(prefName, newValue); if (!cachedStringProps.ContainsKey(prefName)) { cachedStringProps.Add(prefName, newValue); } else { cachedStringProps[prefName] = newValue; } } public static int GetInt(string prefName, int defaultValue) { if (!cachedIntProps.ContainsKey(prefName)) { cachedIntProps.Add(prefName, PlayerPrefs.GetInt(prefName, defaultValue)); PlayerPrefs.SetInt(prefName, PlayerPrefs.GetInt(prefName, defaultValue)); } return cachedIntProps[prefName]; } public static void SetInt(string prefName, int newValue) { PlayerPrefs.SetInt(prefName, newValue); if (!cachedIntProps.ContainsKey(prefName)) { cachedIntProps.Add(prefName, newValue); } else { cachedIntProps[prefName] = newValue; } } public static bool GetBool(string prefName, bool defaultValue) { return (GetInt(prefName, (defaultValue) ? 1 : 0) == 0) ? false : true; } public static void SetBool(string prefName, bool newValue) { SetInt(prefName, newValue ? 1 : 0); } #endregion
    In short, what I do is call PlayerPrefs functions when I need values that are not cached in memory, and just read from memory at each subsequent Get. When I Set values however, I have to write to both cache and PlayerPrefs. Setting is, however, a fairly rare event.

    Doing a dictionary lookup at each frame is of course not as fast as just grabbing the preference value in Awake() or Start() into a member variable and using that member variable in Update() or OnGUI(); but I don't notice the speed hit even on an iPhone 3GS and I like knowing that the preference is always up to date so long as I use the ConfigurationDirector properly.


    Contexts



    So you need to track your player's name, their high score, the class they're using for the current game, the color of their uniform, the game difficulty level, the music volume, the IP address of the most recent server they played on....and that's just the beginning!

    I chose to bring order to that chaos by having my own system which I'll explain as a C# code snippet:public static class ConfigurationDirector { /// /// Player configuration settings /// public static class Player { /// /// Gets or sets the player name. /// /// /// The name. /// public static string Name { get { return GetString("Player.Name", ""); } set { SetString("Player.Name", value); } } /// /// Gets the default hue. /// /// /// The default hue. /// public static float DefaultHue { get { return 62f; } } /// /// Gets or sets the player hue. This is a floating precision number between and including /// 0 and 360. /// /// /// The player hue. /// public static float Hue { get { return GetFloat("Player.Hue", DefaultHue); } set { SetFloat("Player.Hue", value); } } /// /// Sets the color of the player. /// /// /// The color of the player. /// public static Color PlayerColor { get { return ColorDirector.HSL2RGB(Hue / 360.0, 0.7, 0.5); } } /// /// Gets or sets a value indicating whether this player has seen tutorial. /// /// /// true if this player has seen tutorial; otherwise, false. /// public static bool HasSeenTutorial { get { return GetBool("Player.HasSeenTutorial", false); } set { SetBool("Player.HasSeenTutorial", value); } } } /// /// Audio configuration settings /// public static class Audio { /// /// Gets the default SFX volume. /// /// /// The default SFX volume. /// public static float DefaultSFXVolume { get { return 0.5f; } } /// /// Gets or sets the SFX volume. /// /// /// The SFX volume. /// public static float SFXVolume { get { return GetFloat("Audio.SFXVolume", DefaultSFXVolume); } set { SetFloat("Audio.SFXVolume", value); } } /// /// Gets the default music volume. /// /// /// The default music volume. /// public static float DefaultMusicVolume { get { return 0.4f; } } /// /// Gets or sets the music volume. /// /// /// The music volume. /// public static float MusicVolume { get { return GetFloat("Audio.MusicVolume", DefaultMusicVolume); } set { SetFloat("Audio.MusicVolume", value); } } } /// /// Network configuration settings /// public static class NetworkSettings { /// /// Gets or sets the game name. /// /// /// The name. /// public static string GameName { get { return GetString("Network.GameName", "My Game"); } set { SetString("Network.GameName", value); } } /// /// Gets the default port. /// /// /// The default port. /// public static int DefaultPort { get { return 12345; } } /// /// Gets or sets the port. /// /// /// The port. /// public static int Port { get { return GetInt("Network.Port", DefaultPort); } set { SetInt("Network.Port", value); } } } /// /// Unlocks. /// public static class Unlocks { /// /// Determines whether unlocks are enabled /// /// /// True if unlocks are enabled /// public static bool Enabled { get { return GetBool("Unlocks.Enabled", false); } set { SetBool("Unlocks.Enabled", value); } } } }
    If I want to get the player's name for example, I do:

    string name = ConfigurationDirector.Player.Name;

    The call is generally ConfigurationDirector..

    The PlayerPrefs key name is generally "."

    Doing this has these advantages:

    • Developers can use Intellisense to look up existing preferences as they add new code instead of surfing around the project to find existing preference key strings.
    • Every preference key string is defined in a single file.
    • There is consistency between the preference key string and the call to get or set a preference (and therefore predictability); and I don't think the compiler would let you have any duplicate preference key strings if you follow that consistency.
    • If you're new to the project (or are going back to it after a while), it's a faster learning curve to implement new preference-related code than if there were PlayerPref calls scattered everywhere.


      Conclusion



      This is how I manage configurations in my recent games, and it works well for my purposes. If you're not happy with how you maintain your game's configuration, or you forgot the preference key for the player skin for the 8th time, it might be worth looking into doing something like this.
Gamieon

In case this is your first time being exposed to the project:

Domino Arena is a multi-player "party" game where you try to paint a playfield full of dominoes with your player's color, and prevent other players from doing the same. At the start of the game, one domino for every player is assigned that player's color, is knocked over, and then goes back to its original position. Any domino it makes contact with will become the same color, and fall over as well. This is the domino chain reaction that transpires during the game.



Every level has multiple domino paths and a series of transparent hemisphere-shaped "switches" at various points on the paths. If you click on a switch, the dominoes under it will disappear and effectively break the path. If you click it again, they will reappear.



Here are the levels I came up with:



l1.png l2.png
l3.png l4.png
l5.png l6.png
l7.png l8.png

As I've never written or played anything quite like it before, I'm having to come up with levels and rules for good level designs as I go along. Right now the rules are:



  • ?Whenever possible, use the Unity editor to generate domino patterns instead of doing it all by hand one domino at a time.


  • Every domino must fall in one and only one direction.


  • There must be at least one path that cannot be broken, and every player's first domino must fall on it.
  • There may be between 2 and 4 players.
  • Every player's color must be as far apart from other player colors as possible on the color wheel. For example, if I have 4 players, their positions on the color wheel should be 0, 90, 180, and 270 degrees respectively. Otherwise you may confuse your color with that of another player.


    As for the AI, I'm faking it for now:

    • When a domino touches a switch, the AI decides whether to toggle the switch. If the color of the domino touching the switch is their color, it will try to ensure there is a path. If it is an opponent's color, it will try to remove the path by making the dominoes disappear.
    • An easy AI player has a 20% chance of actually doing anything when a domino touches a switch. A hard AI player, which I've never beaten, has a 100% chance of reacting to a domino touching a switch.
    • If there are multiple AI players, and a domino touches a switch, then one random AI player is chosen to react to the switch.


      And for the graphics:

      • Any non-domino, non-border object should be dark so that it's easy to see the dominoes....but not too dark. (I swear the floors are brighter than the screenshots make them look!)
      • FSAA and bloom effects seem to somehow make things look worse, but I want to experiment with environmental render values a bit more.


        Here is a visual of me using a Unity Editor script I wrote to generate circles and lines of dominoes:

        script.jpg

        And here is a screenshot of the level introductory animation.

        intro1.png


        My goal is to have the single player beta working in a week so I can put it out there and see how players respond to it.



        I hope you enjoy the screenshots!

Gamieon
Not much to write here; the video pretty much says it all:



I decided to stay with the crystal theme, and I think the interactive tutorial does a reasonable job. The last part of it is a sandbox so that you can practice all you want.

The next step is to bring in the uLink network engine and start producing some levels with online and "fake AI" multi-player support. Eventually I'd like to also add "boosters" that randomly appear in the paths. When hit by a domino, the player or team that belongs to the domino would get an offensive or defensive perk including: Reduced button cooldowns for yourself, or screen obfuscators for your enemy.

I'll make another entry once the multi-player part is done, hopefully in 2-3 weeks.

Recommendations Requested!


Does anyone have suggestions for the music and sound effects genres? I'm thinking either techno or metal...something exciting to keep up with the pace.
Gamieon
I promised myself I would not do any more large projects without working in teams, but I never said anything about small ones. Even with the small ones however, I'm stuck with the same problem I have with all projects: I'm not that great at creative and artistic direction.

Consider my latest project "Domino Arena," possibly the smallest one I've done myself besides Paper Cowboys. It's a multiplayer "party" puzzle / action game where you have a playfield full of colored dominoes, and you manipulate places in the playfield where one domino knocks over more than one at a time such that as many dominoes as possible match your player's color.

You can see a concept video on YouTube:





I think it will take a tutorial and a little getting used to, but it could be fun. I'd at least like to pitch a beta around to see what people think when it's ready.



Now that the basic mechanics are defined, I need to figure out how the game will look. I've narrowed it down to three styles: Cartoon, "Jeweled" and semi-realism.




Cartoon



1.png

As a mobile developer, my first thought is always "cartoon" because all the popular and top selling apps that come to mind are all cartoony or at least have vibrant, pleasant art themes. Every "party" game I've played also shared similar traits. After looking at a bunch of mobile board game and Mario Party screen shots, I experimented with a scene using cell shading and six spotlights.

It's clear where all the dominoes are and everyone should be able to discern the blue from the gold dominoes...but the environment colors just don't look right to me. I'm concerned that if I make them brighter, then the dominoes will blend in more and players will have a more difficult time seeing them. If someone were to help with art direction, I bet this could work. Otherwise I can toy around with this a bit more.



Jeweled



jewel1.png

jewel2.png



During development I asked myself "what other games have game mechanics that rely on color?" The first game that came to mind was Bejewelled. After finding some gem shaders on the Unity Asset Store, I came up with a weird, wild theme of jeweled dominoes in dark scenes that keep the player's focus on the game's primary objects.

The word I would use is "bizarre." The mechanic and the style seem altogether foreign from anything I've played before...but that could be a good thing. I do like looking at the pretty colors, anyway. I could also have players "collect" the jeweled dominoes that match their color when a game is over, and have the grand total maintained on a leaderboard.



Semi-Realism



wood.png

When I'm in doubt over style, I always turn to wood textures because i find them pleasant to look at. It's hard to see in the picture, but the dominoes are reflecting on the floor.

I thought this would look better as I was working on it; and the white dominoes on wood looked fine when the simulation began....but when they got colored, they just seemed out of place with the rest of the scene to me.



Final Thoughts



For me it's a close race between cartoony and jeweled with a lean toward jeweled. If I had to decide this moment, I would make a beta with a tutorial, three multi-player jeweled levels, computer player support, and just throw it out there and see what happens. If it gets a positive response, I'd work it to completion; otherwise it's still an eye catcher I can add to my portfolio.
Gamieon
One of my ad-supported mobile games has been on the market for the better part of a year, and I'm in the process of removing ads and putting in microtransactions to see if they will bring in more income.

I'm a neophyte when it comes to designing apps around monetization; and while studying a few AAA apps doesn't make me an expert, it has given me some ideas that I'd like to try with my games and share with other developers to critique.



In Hamster Chase you can earn coins by beating levels, and then spend them later to skip levels. In the next update, players will be able to buy them, too. Here is the in-app screen I designed to appear in the game when a player wants to skip a level but does not have enough coins:



inappnew.png

These were the considerations I made in the design:

  • It appears immediately in the game when the player wants to use coins that they don't have.
  • Nowhere do you see the word "buy." I'm treating "buy" as an evil word, and also a redundant one since the price is already on the purchase button. Think about it: do you say to your friends "lets go get some dinner" or "lets go buy some dinner?" The only time I'll use "buy" is if the app has trouble fetching the price from the store portal.
  • I kept the words to a minimum, and relied more on icons and colors. From looking at it, I'm hoping a player can tell that they don't have enough coins, how many coins they need, and how many they will get for how much money.
  • The purchase button is larger than the cancel button.
  • The purchase button is a green color, and the background hue is close to being red. Reading http://www.webpronews.com/colors-that-sell-2003-01 and http://blog.kissmetrics.com/color-psychology, I infer that red color tones communicate energy, excitement, and urgency. Green is associated with life, money, "green means go" and is easiest on the eyes to process. Yes the cancel button is a deep red, but I consider that a standard color for cancelling anything.

    In-app screen design aside, here are some other ideas I'm running with in this next update:



    DO

    : Have boosters that players can purchase to win the game more easily.

    DON'T

    : Hide the fact that players can purchase boosters if they don't have any.


    DO

    :

    Let players purchase a booster immediately when they want to use one and they have none.



    DON'T

    :

    Make a player go to an entirely different place in the app to

    purchase

    something.




    DO

    :

    Consider allowing players to also earn boosters without purchasing them.



    DON'T

    :

    Give away so many free boosters that there's no point in

    purchasing

    them.




    DO

    :

    Think carefully about every detail in the appearance of an in-app purchase prompt.



    DON'T

    :

    Just throw together an in-app purchase screen with minimal effort.




    DO

    :

    Consider having more expensive boosters to let players win the game more easily than cheaper boosters.



    DON'T

    :

    Charge $37.99 for a booster.[color=#d3d3d3] [/color]


    [color=#808080]

    (Counter-point: I

    f someone is willing to pay $37.99 for it, why stop them?)

    [/color]


    DO

    :

    Let the player discover they want or need something before presenting the opportunity to purchase it.



    DON'T

    :

    Harass or pressure players into wanting something with repeated pop-ups or waiting screens.




    DO

    :

    Consider selling players non-boosters that just make the game more fun, such as hats or skins.



    DON'T

    :

    Try to sell anything to a player unless you either give them a free sample or explain what the item is for.




    DO

    :

    Study the in-app flows of popular games

    similar

    to yours to learn how players find their products, and see how they are encouraged to buy them.



    DON'T

    :

    Prioritize making money over making a genuinely fun game or having fun making one.


    [color=#808080]

    (Counter-point: I

    t's easy for me to say because this isn't my full time job)

    [/color]


    And now, my [color=#daa520]golden [/color]rule of in-apps:

    DON'T

    : Force players to buy anything to finish the game.

Sign in to follow this  
Followers 0