Monday 29 February 2016

PUN shooter #15 - Core experience fixes

Even a simple shooter without perks may need fixing.

I temporarily disabled battle mode because it felt broken. I don't want it to stay down for long though, because it can be fixed.

This put the emphasis back on survival mode which at the moment is the most accessible game mode.

Note: When a player enters, they should see a notification if the game is 'empty' at least until we can substitute some kind of fun.

One issue with survival mode is that the progression implicit to battling other players is not obvious enough:
  • A player should see their rank when they enter the game.
  • I think we'll be showing a leaderboard with daily ranks when a player lose (should also be visible from the main menu)
  • A player should see notices, or a short narrative, possibly during or after they battle enemies they encountered before. For example: "This guy is a wimp, he's only ever won x times" or "This is the guy that done you in last time. Time for payback" or "You got busted xx times today".
Also, it looked like the ranking system was broken (but not the number of win/losses) but this is unconfirmed. Maybe data gets deleted when replacing the web player or clearing the history?

Too many players are asking for mouse look and overall more conventional controls.

Sunday 28 February 2016

PUN shooter #14 - Multimap

Now I have 4 maps but not sure how I want to make them available: If all users choose their own map, the probability that two users are in the same room is now 1/N where N is the number of maps.

: D

But then again, I need a simple way to open the maps for showcasing and testing. So, I implemented an option to join a specific room (numbered in the menu). Now I want players who just choose 'Survival' to join a non empty room if possible (otherwise, pick a random room)
It's possible to just try joining rooms (since the names are known in advance) but this isn't gonna play nice with my workflow where loading the target level and joining a room are the same thing.

So, I connect to the network from the game menu and check rooms.

Before starting a game, we need to disconnect from the server, or vary connection logic to avoid a redundant connection attempt.

Since there wouldn't be much benefit to showing these options at this stage, they are only available when SHIFT is pressed.

Try the latest build [here]

Programmatically handling button clicks

Since Unity 5 we have buttons that the designer can hard-wire to component (no-arg) functions. Usually this may be a good thing. But not always.

  • Sometimes you want to bind a button dynamically.
  • Or you may want to pass a parameter to the target function
  • Or just add code to a button.
A handy script allowing you to bind a button to a message dynamically. By default the message is delivered to the named object, this can be customised for delivering to children or ancestors. If no object name is specified, delivery uses the button object as a starting point (useful to implicitly deliver upwards to a 'panel controller')

Variants show how to load a numbered level upon clicking a button:

Also check this Q&A for how to remove listeners and more.

Saturday 27 February 2016

PUN shooter #13 - Experimenting with assets and level design

Textured Assets

From a workflow point of view, textured assets are a drag. Here's an example using an arbitrary scene downloaded from the Unity Store.
  • Web player export over 10 minutes (maybe) 15 (My laptop is 5 years old; happy birthday)
  • Player size inflated from ~4mb to 180mb. This won't load successfully never mind slow.
Stripping textures off the asset put size down to 24mb but this unsurprisingly doesn't look great.

Not this time.

Muddling through level design

I had a crazy level design session today. The bottom line, though, is that I was trying to move too fast whereas, when it comes to level design, patience literally pays off.

Since there are plenty things that can go wrong when integrating new assets, trying to put together too much stuff at once is a recipe for disaster. On the other hand, taking the time to do things correctly is helpful because working elements are easy to reuse.

Unity notes

I've been toying with a little utility to work with materials. Lessons learned:

  • The names of materials are distinct from their filenames. Gets amusing after you renamed materials programatically.
  • Not putting third party assets in version control is dangerous.

Friday 26 February 2016

PUN shooter #12 - Playtest debrief

A couple of days back I tested the game with friends around the world (literally). Overall we had a little fun and the following requests came out:

  • Jumping - I'm guessing this came from the design of the map which kind of forced a (non jumping) player to run anti-clockwise.
  • Classic FPS controls - A predictable request.
  • Frame rate and Ping - Because we had one player in Brazil whose connection is apparently much slower than ours, but we don't have a way to quantify that.
  • In-game sound control
  • Chat feature - I'm not taking this too seriously though I suspect that I don't really have a choice in this area.
I also noted that players go missing from the leaderboards; worse, it looks like race conditions may occur when trying to start a battle, so two players may each be trying to start their own instead of playing together.

Tuesday 23 February 2016

A bird eye view of back-end services for games a.k.a Parse Alternatives

As I look set to release my first multiplayer games within 2 months time (much less for the web builds) I've been looking at Parse alternatives - in other words, Back-end-as-a-service (BaaS) with Unity support.

What are we looking at today? Services that fit the following description:
  • Free up to X
  • Cloud (server-side) storage and code.
  • Unity aware
  • Easy to use and well documented
  • No-nonsense approach to storing data, JSON oriented.
  • Free up to 1m API calls/month.
  • Server-side custom Java
Looks as flexible as Gamedonia; the downside for me would be Java instead of Javascript but this is very contingent to... me not wanting to run Eclipse on a crammed laptop.

Note: AppWarp looks to be part of App42 as an offering more specifically geared towards game development.

BrainCloud
  • JSON
  • Mongo
  • Free up to 100 DAU (~3000 MAU; $30 => ultd DAU and 6m API calls )
BrainCloud has an emphasis on statistics and monetisation. This on top of looking well documented and flexible enough, makes it at least as (if not more) attractive as GameDonia (below).

  • NoSQL DB (Mongo)
  • Free up to 10k MAU 
  • Server-side custom JS
I'm not entirely bought in because I don't understand how to store global/match properties.

Maybe just a first impression, Gamedonia looks easy to use and their docs are really straightforward.

Heroic Labs
  • Server side JS
  • Free up to 10K MAU
Offer looks comprehensive.
Pitch: social features, advanced leaderboards.

  • Server side JS
  • Free, mostly
References
A little terminology

MAU = Monthly Active Users.
DAU = Daly Active Users

Monday 22 February 2016

PUN shooter #11 - Battle Royale 2/2 (implementation)

The first steps towards implementing a new game mode have been mundane:
  • Add buttons in the menu
  • Add a static field indicating which game mode we are playing (for now, all modes go to the same scene. Will cause quirks later but... later).
  • Disable the KO sequence that would normally bring a player back to the menu. Part of the idea of the battle royale (a la Counter Strike I guess) is that defeated players do not respawn. The crux is not to let them re-enter the same room they just lost in; in the meantime, encouraging them to remain "part of the game" in interesting ways is on the plan.
The next step was to implement the other side of a 'battle mode': a battle should not start until all players are onboard. Took more time than I expected.

Replacing materials

In battle mode, defeated players do not disappear. Instead, they become ghosts. This required replacing all materials and I discovered something unexpected while doing this: Renderer.materials returns a copy of the materials array. This means that replacing a material in that array is ineffective. For changes to take effect, the returned array must be re-assigned to renderer.materials.

RPC note

Sometimes writing 'networked features' can be as easy as tagging a method [PunRPC] and calling PhotonView.RPC(...) but there's a catch: before that even works, the other side must have a copy of the invoked component. At times this may catch you off-guard. For example, the KO sequence in my case is handled by a component local to the KO'd player but the effects of KO should be visible everywhere. an RPC into a [PunRPC]'d function of that component will fail.

Photon Notes

<> Avatar rotation felt 'snappy' (going in brusque increments like a clock hand). Reducing interpolation speed makes rotation smoother (too slow isn't good either since the rotation lag becomes too obvious)

<> Photon provides player 'names' which are the nicknames we're after for our leaderboards. Network-wise it appears that setting the player name via PhotonNetwork.playerName is the way to go (read them normally via PhotonPlayer.name)

<> After all wanted players have joined a match, close the room via PhotonNetwork.room.open = false, PhotonNetwork.room.visible = false

Preventing confusion between battle rooms and the 'main' room.

With several game modes, letting players join whatever room available may cause errors. For now I resolved this by having all 'survival' players entering/creating a named, while battle rooms are randomly created.

Sunday 21 February 2016

Pun Shooter #9 - Animation? Shoot...

Since yesterday I've been wondering how we should add shooting animations to our game. One route is I ask the original asset author to create them. Another is I try to do this with my appointed go-to Blender animator. Finally, we might animate shooting procedurally.

Back to the source?

Right now I'm unsure about the asset author's availability. Another thing to consider is the number of animations we might need. Say, what would please me?

  • Light gun (single)
  • Light gun (dual)
  • Medium (single handed) automatic weapon
  • Heavy weapon (Bazooka, Missile launcher)

Plus, at least some of these (light/medium) should have a running variant. Yea that's a lot.


The Blender way?

How about ordering from my Blender animator? Chill but I'm not sure how to do a Unity (fbx) <=> Blender (.blend/.fbx) round trip. I can export somewhat usable rigs and models from Unity, but so far no luck getting them to play nice with the original Mecanim setup.

(Bear in mind I'm trying to add animations to an existing set, not developing a new set from scratch).

Procedural animation


I did some preliminary testing with procedurally animating the little guys' arms. Initially it was frustrating  but, if nothing else overriding transforms in LateUpdate (this has to be done at every frame) does work.

References

A Unity blog post addresses animation assets - quite possibly out of date.

PUN shooter #10 - Multiplayer matches 1/2 (design considerations)

It looks like I'm settling on a name for the current game mode : practice. This nails the issue - the experience provided by just logging in and shooting anybody else that happens to be logged in or not is inconsequential. So I decided to implement a "Battle Royale" mode but let's just call it matches.

Improvised matches

An improvised match is when several players happen (randomly or maybe not so randomly) to be online and decide to start a match together. This is expected to work best when you and your friends get online to play together.

Later I imagine that private matches could be made available. Private matches can work with secret rooms but I visualise it better as having a list of connected friends, and starting pretty much as described above.

Scheduled matches

Scheduled matches are expected to work better as a means to get a limited audience together. The idea is that, at any point in time there may not be enough people logged in to start a fun match. But if there are matches say, every 1 hour or every 20 minutes, people are encouraged to come at the appointed time. Although it may not fully beat a lack of players (which is what I expect initially) it can help.

Maybe it would work better if people can pre-register but for now I will allow a 15-30 minutes window to pre-register, which essentially is trying to do the same thing.

Improvised matches look like more work but I feel that players may like them more so I will start with that.

PUN Shooter #8 - Run & Gun

Gun in hand

What I needed was a solution to automatically equip the same prefab to any of my 6-8 characters which all look about the same.

I literally put the gun in the hands of the first avatar. Then I recorded the (local, relative to the hand bone) position of the gun and the name of the target bone and made a handy script that can setup the gun at the correct position for any avatar.


Moving the character’s arm

I decided to go procedural (read the previous post to understand why) so what I do is override the arm's transform inside LateUpdate. One reason it's so easy (and the result somewhat tolerable) is the simple, cartoony art-style. One advantage: works whether the actor are running or standing idle.

Minimally we need the bone name and want to move this bone towards the shooting target. Initially I used “transform.forward”, however a bone's "forward" vector may be something else.


So much for procedural animation.

Saturday 20 February 2016

PUN Shooter #7 - Design talk

We had a fun play-test session after the recent updates. Afterwards I decided on things that needed improvement.

Reduce 'camping' opportunities

One suggestion was to avoid avatars re-spawning too close to each other. This could mean a somewhat bigger map but also more opportunities to take cover.

Somewhat debatably the freedom to shoot unlimited bullets as fast as your finger permits is also an issue. My proposed solution to that would be allow bullets to run out quickly (e.g. 6 shots) and drop loot.

On the same line I'm thinking we should introduce HP with a super-slow recovery rate, and the possibility to sleep to recover much faster (sleep in the middle of a death match? you betcha!).

About HP and sleep, bear in mind that I hope to keep everything quick paced, about 3-15 minutes per match.

More convincing bullets

At the moment our bullets are huge (originally intended to be fireballs). Right now I don't want faster-than-your-eyes-can-see bullets, maybe a gun shooting mmh... ping pong balls? would be fine.

Allow jumping

I'm being asking for this. Though I might oblige I know from experience that jumping can introduce a variety of complications.

A genuine 'battle royale' mode

Not entirely sure why, a mode where several players enter at the same time and play against each other till the last one standing feels like a must have.

Friday 19 February 2016

PUN shooter #6 - Somewhere fun

The "mountain" scene was by fear the weakest element in my multiplayer shooting game so I replaced it with a nice looking asset by Pavel Novak.


Play [here]

Wednesday 17 February 2016

PUN shooter #5 - Leaderboards?

For my leaderboards I'm thinking of trying Playfab.

These guys haven't got to the point of making everything easy peasy.

  • Docs (Sleek css but more like a reference API).
  • A video introduction to their leaderboards (Over 30 minutes of click-y sound!)
Let's see if I can get to the end of that horrible video.

...

Well. Maybe not.

The next thing I did is start counting hits and losses and store that in player preferences. To do this I confirm hits using RPCs. Why? Because it happens that a player get hit on a machine but their proxy don't get hit on another. Bad? Depends on how often it happens; so far not very often.

Players in the same room broadcast their rankings to each other. This allowed me to implement client side leaderboards, which for my use is enough (on iOS I would definitely go with Apple's leaderboards but that is another story).

PUN shooter #4 - More drama

In the last 4 sessions I added the following:

  • A game menu
  • UI elements to 'dramatise' the re-spawn process
  • Sound effects and music
  • A credits section.
Nothing too hard or complex here, even though getting all this done has been a long day's work.


You can try the game [here]

Tuesday 16 February 2016

PUN shooter #3 - Footprints and footsteps.

In the past couple of days I worked on scripts for footprints and footsteps. Also, proxies didn't play animation.

<> Velocity and collisions may report incorrectly for kinematic bodies updated over the network.

The tricky part was getting a good enough answer to the simple question, "is the avatar walking". This breaks down into "is the avatar moving" and "is the avatar grounded".


Since collisions report inaccurately we can't use OnCollisionStay() to tell us an avatar is grounded. Instead, use raycasting.

Surprisingly, speed reported via position sampling proved inaccurate enough that I had to average readings over time to get acceptable results.

Sunday 14 February 2016

PUN shooter #2 - Player prefabs, Web Player and WebGL

Customising player prefabs (~2 hours)

Today I focused on providing a different character for each player.
My asset provides Mecanim prefabs. Let's not convert everything to legacy and use this. No need to setup a state machine. Mecanim's Animator does support Play(string).

My setup uses model/view decoupling. So what I send to PhotonNetwork.Instantiate() is the model prefab (containing the logic), then I select a view prefab (containing the mesh and animations) and instantiate that locally.

So, how to make this view the same across the network? Well. PhotonNewtork.Instantiate() allows an object[] as parameter. This you can retrieve from PhotonView as InstantiationData upon handling OnPhotonInstantiate. 

WebGL build (~2 hours)

For better and for worse, it's the future.
In the meantime, WebGL is new tech. Neither Photon nor UNET totally play nice with it
(See Q&A here).
  • Photon chat will generate an error (comment out the code is okay... if you don't use Photon chat I guess).
  • Uncheck 'run in background'
  • Uncheck 'strip engine code'
At the time of writing, my Photon/WebGL builds crash in Safari and Chrome.
Also, a WebGL build takes 20 minutes on my 6 years old laptop. 

Never mind bugs that may or may not be fixable, it would take a fair amount of automation to smooth this enough for daily or even weekly builds so I guess I'll stick to the deprecated (before the new stuff even works?) web player.

Web Player (~20 minutes)

You can try it [here] (bring your friends)

Saturday 13 February 2016

Pun shooter #1 - Shooting

In the past couple of days I've been making a basic shooter. Caveats.

Transform sync doesn't work. Why?

  • If using a rigid body, ensure kinematic is on for the proxy (but you should still see some sync regardless.
  • Remember to add the NetworkTransformView to PhotonView.
Collisions not working

Kinematic proxies aren't good at generating collisions. Why? Because if you receive say, 10 positions per second, and an object bounces on the remote, the proxy may interpolate towards the new direction without picking up the actual collision.



I realised this while dealing with physical projectiles. This time around I decided to Network-Instantiate projectiles but adding physics locally via script attached to the bullet prefab.

Ghost bullets

What we create with PhotonNetwork.Instantiate(...) must be destroyed with PhotonNetwork.Destroy(...). A symptom of doing otherwise (for example, destroy all local copies of an object) is that entering clients will "replay" previously instantiated objects.

Input methods

After I put a little game together we got to try it on two laptops simultaneously. One of the laptops didn't respond to key strokes. Investigating, we found that a foreign input method was conflicting with game input.

Tuesday 9 February 2016

From uNet to PUN #2

Yesterday I tried setting up player objects via network instantiation. Something, however, didn't feel right. Took me a while to realise that the build was setting up for UNET, not PUN.

Most networking APIs require that we filter input (or adjust prefab config) to avoid every player controlling everybody else's. PUN uses PhotonView.isMine for this. Since I don't know what makes a prefab 'mine' I guess being the client calling Network.Instantiate is what does it.

with tweaks, PhotonTransformView works well. In my case physics are important, my setup:


I set remote prefabs to kinematic otherwise local physics interact (poorly) with remote sync.

Spawn location

For generating spawning positions, I used the player joining order
(calling PhotonNetwork.otherPlayers.Length inside OnJoinedRoom).

Exit a game session

In Photon, Disconnect() appears to correctly exit the 'room' and disconnect the client.

Time spent: ~2-3 hours

From uNet to PUN #1

Recently I created a simple multiplayer app using UNET (Unity Networking 5.x). Strictly speaking UNET is not production ready so I decided to give Photon Unity Networking (P.U.N) a try.

Time spent: approximately 2 hours

I downloaded the free PUN asset.


Migrating from UNET, I duplicated my UNET scene to be on the safe side. Then I created a Multiplayer object with PUN and UNET network controllers. Looks like this:

  • Multiplayer
    • PUN
    • UNET

I'm curious to see whether I can create a hybrid setup, so that I can 'easily' switch between solutions.

The quick start doc proved to be out of date but error messages are clear and the APIs look well structured so I quickly got a connection up and running.




Note - Photon also provide a Unity client SDK for their 'Realtime' service. Don't confuse these two, notably when browsing APIs and docs.

The next step obviously is to setup a player object. Like in UNET and other similar APIs this is done via network instantiation. Here the quick start let me down a bit so I used the Paladin Studios tutorial instead.

It's kind of funny to see how my network controller is looking more and more like UNET's NetworkManager.

Easy state Sync

I wanted to replicate my initial setup with UNET so I went to shop for the TransformView. With a PhotonView and a (configured) TransformView on my Avatar, I hope to get position and rotation in sync.