Jump to content

BabylonJS 2.5 Challange - jppresents progress & blog [combat text & more 27.02.2017]


jpdev
 Share

Recommended Posts

Edit 10: New "blog"-post: New post 27.2.2017

Edit 9: New "blog"-post: New post 25.2.2017

Edit 8: New "blog"-post: New post 21.2.2017

Edit 7: Gameplay Video: Video

Edit 6: New "blog"-post: New post 8.2.2017

Edit 5: New "blog"-post: New post 1.2.2017

Edit 4: New "blog"-post: New post 21.1.2017

Edit 3: New "blog"-post: New post 14.1.2017

Edit 2: New "blog"-post: New post 6.1.2017

Edit 1: New "blog"-post: New post

--

Hi BabylonJS-Community,

Last friday I joined the Babylon.js 2.5 challenge.

I decided to post my progress here. Maybe this will motivate others to join the challenge and I hope it will keep me motivated to finish the project I came up with. Also there might be some tips or things I find out that might help others.

Here is my vision:

A cooperative multiplayer action roleplaying game that is real time and is designed for a play session of about 15 minutes.
It should offer content to a single player as well as a challenge that is only beatable by three or more players.
This way you can just open up the game and try it out, if you like it you can coordinate with friends or people from the html5gamedevs board to beat the multiplayer part.

Since I am going to make everything from scratch things will be created as simple as possible.
This means: flat shaded low poly blender models.

Here is what I have so far:

gameplay.gif

The blue girl is the heroine the players control. The yellow slime is the first enemy, controlled by the server.
The slimes idle around, if a player comes too close they begin to follow and attack the player once they are in range.
Upon loosing all health the player dies.
The green & red highlight at the end is the mouse over effect that is going to be used to indicate targets and if they are friendly or not.

Some info on the tech:

node.js server (using "ws" for websockets) that controls all gameobjects
babylon 2.5 client using the browser webSocket object for communication
Communication is done via sending JSON objects over the websocket.

Since I struggled a bit putting text on billboards, here is a small playground showing my solution:

Nameplate Playground

I also ran into a small hickup with the highlight layer, using the it together with cloned meshes:
Cloning a mesh does not generate a new unique id. If you add one cloned mesh to the highlight array all clones will be highlighted.
The solution I found:  Set unique Ids (mesh.id = …) for all cloned meshes.
 

That's it for now. Hopefully I will have more to show next week.

 

Link to comment
Share on other sites

@Sebavan 

Thank you :)

I am using blender and with the babylonJS exporter plugin.

The slime is basically a ico-sphere with a mouth. The girl I modelled in Blender using two refrence images with front and side view.

There are some very good blender tutorials on rigging in blender on youtube, before doing the girl character I watched this: https://www.youtube.com/watch?v=Q9f-WVs3ghI 
(But my character isn't as advanced - for example I did not use IK-Constraints, I just position all bones)

 

Link to comment
Share on other sites

Here my first update on the progress:

Let's start with a gameplay gif that shows what is new and followed by some explanations and things I learned.

fight.gif

Explanation/description:

The green bar is the beginning of a UI, it's the player healthbar. It's rendered with canvas2D, see below for a playground.
The red bar is also part of the ui, it's the target healthbar & name. Also canvas2D and it's only rendered when a target is selected.
Target selection: The current targert can be selected by left or right clicking on it, rightclick also initiates combat (for now). The target is marked with a "targetMarker". (A plane with a circle on it, scaled to the targets size and placed slightly above its origin)
Lower left corner: The chatbox, so communitcation is possible. It's a div for the text and a html-textinput. You can set the focus to the textbox by pressing "return" while playing. Sending your message with "return" also returns the focus to the game.
The "action" you see: jp & someone engage the three slimes in hand to hand combat. (Nothing is in any way tuned for gameplay, I am just creating & testing the mechanics.
Monsters can now die and respawn (and so can players).
 

A few things that are implemented but not really visible:
The enemies collide with each other. This was important because 2 or more enemies following a player around tended to end up in the exact same position overlapping each other completly. That didn't look and feel god. For the players I decided against collision with other players or enemies for now, just because it feels bad to get stuck. So you can run through enemies but of course they will attack you while you do that.

Some technical and information on things I learned:

I played around creating the healthbar in a playground, if you want to have a look at how it's done (spoiler: pretty simple): http://babylonjs-playground.com/#2AVSFH#124

I had a "bad" experience with blender - I lost an animation/action, because I forgot to "sticky" it by pressing the "F" (force?) button after creating it. So a tip for everyone doing multiple animations (actions) not just one timeline in blender: Always remember to press the "F" right after creating the animation. (I think the problem is, if you switch to another animation on your model and then save and reload the "unbound" animation is removed because blender deems it no longer in use.)

I also ran into a synchronization problem.
My server and client both move objects around, for example: The player wants to move to a new position. The server moves the player and the client does too. The server then tells the client perdiodically where the player "really" is and the client adjust (the sever is always right). But the problem was client calculated speed was at least 33% higher than the server speed. Despite client and server calculating the speed taking into account the time between calculations (60 times a second on the client side, every 20ms on the server side).

I added a debug-sphere to indicate the player position every time a paket from the server arived, this clearly showed the problem, the player on the client was outrunning the server by alot:

serverdesync.gif

 

It took me a while to understand why, in the end it was easy:
While the frame rate on the client is perfect 60 frames per second (unless the perfomance drops) on the server side things are different. On the server I use "setInterval(callback, 20) and then caculated everything thinking that 20ms will pass between the calls. Turns out it's about 29 to 32 ms between calls to the function. (And the functions takes less than one ms to run, so it's not because of too much todo on the server side.) The fix was then easy: Just messure the time between calls and adjust all calculations according to the time that has actually passed.
I guess I will have to do this on the client side too, to support clients with less than perfect framerate, for now I just use the constant 1/60 (and if the framerate drops the position is adjusted by what the server says.)

Outlook/things planned for this week/weekend:

On the open meadow it's not possible to design an encounter other than single enemies or groups of them, so I want to look into world layout/objects with collision, to be able to implement a dungoen with different rooms so there is something to progress through.

And then just auto-attacking things is boring, so the plan is to implement skills with certain cooldowns or cast times.
The plan for now is to add a skill bar that shows the skills and their cooldown.
As a startingpoint I plan to add a instant single target damage attack and a area of effect damage attack.

Link to comment
Share on other sites

Pretty cool! You seem to make good progress and the game looks already pretty cool. I imagine it a hack'n'slay Diablo like gamplay (which I love!). It's very interesting to hear about the problems you had to solve to get there. Make sure to keep us updated how things are working out! :D

Link to comment
Share on other sites

  • 2 weeks later...

A new (small) update, as I sadly haven't gotten a lot done the past few days.

I managed to at least get some environment into the game:

world.gif

Yes, that is the smallest "map" ever.. because right now it's an array written into the server-code by hand - the plan is to be able to create the map using tiled. The resulting .tmx file should be loaded when the server starts.
At least collision with the obstacles is working on client and server side.

Just for fun I made a quick time lapse of how the tree got into the game:

 

I also managed to build a small login screen where you can choose your name & class when logging into the game:

login.png

This one (like the chat box) is html over the babylon canvas.

As for the skills I wanted to add to the game, I only managed to get a skillbar working with canvas 2d, but no skills yet.
I hope the skill bar and working skills will be part of the next update.

One last thing I learned was the difference between instancing and cloning meshes (or at least, that there are differences):

Both share geometry, but instancing shares more (materials can not change etc.) - and if you try to merge geometry on instanced meshes chrome crashes with “out of memory” so it seems to be able to merge you have to clone the meshes.


 

So the goals haven't changed much since the last update:

- improve "map" support by loading a tiled map on the server side

- get skills into the game

Link to comment
Share on other sites

Hi BabylonJS community, here is another update for my challange project:

Let's start with a bit of deployment - the game can't be run locally forever, or no one will ever see it:

So I want my game to run on a vserver using apache & node.
NodeJS will only handle the websocket request. All pages, scripts and resources will be served by the apache.
Just as a challange (and maybe to allow it to work with some firewalls) websockets and websever should both run on port 80.
I finally found the magic apache 2.4 configuration:

 

 RewriteEngine On
 RewriteCond %{HTTP:Upgrade} =websocket [NC]
 RewriteRule /(.*)           ws://localhost:3001/$1 [P,L]

 

This allows the apache to server pages normally on port 80 but if an Upgrade to websocket-mode is received everything gets routed internally to port 3001.
So my gameserver in node is running internally on port 3001.
To work this requires apache 2.4 and mod_proxy and mod_proxy_wstunnel. (For debian users this means you need "jessie", wheezy's apache is not up to date enough.)

In the last update I had a hand coded 20 x 10 array holding indexes for map data - this works, but I want to be able to edit the map in a nice way. So now the map can be edited in free map editor "tiled".
Natively tiled stores the created maps in ".tmx" files. The content is actually a pretty nice xml, so you I can access it this way in my nodeJS server:

Step 1: Get the correct module to read xml files:

import xml2js = require('xml2js');

Step 2: Use the module to read the tiled map and get to the map info & map data:

let parser = new xml2js.Parser();
fs.readFile(__dirname + '/data/world.tmx', function(err, data) {
   parser.parseString((<any>data), function (err, result) {
       let width = result.map.$.width;
       let height = result.map.$.height;
       let data =result.map.layer[0].data[0]._;
	…
}

 

That was painless (worst part finding the typescript definitions for the xml2js. I can’t seem to find anything on the DefinitelyTyped github repo, I blame github user interface...).

The data is a csv representation of the map tiles. You can choose csv in tiled when creating the new map, parsing this into an number array in JS was no problem.

 

As a bonus I now use tiled not only to define the map but also place enemies and the player spawn point. I do this using an object layer in the tiled map and when loading the map the name of the object defines what's happening, the coordinates of the object define where. For example the big "slime" boxes mean, that in the center of the box a slime is spawned and the box area is the area the slime it roams.

 

Here is what this looks like in tiled:

tiled.png

 

The upper left part of this map as it looks in game:

ingame.png

 

 

I also tested if the game runs in all browsers that are currently installed on my system, so I had a big in game meeting with myself:

browsertesting.png

 

The result is amazing, the performance seems to differ a bit, but it runs in all four! - big thanks to the babylonJS team :)

 

And the latest addition to the game is finally the skill bar, you can already see it in the browser screenshots above.

It's implemented using canvas2D, the icons are 50x50 pixels and drawn in inkscape - I was surprised how hard it is to come up with icons, let alone make them not ugly.

 

The skills are clickable and you can also use them by pressing the corresponding button, clicking and keypresses highlight the used skill. All done with canvas2D.
The features are: The buttons are clickable by mouse and also by keybind. The keybind is indicated on the button. Cooldowns are visualized by graying out part of the button.
Activating a button highlights it as feedback to the user. The skills can have a cooldowns, but they don’t have to. Which skills are available and which cooldown they have (if any) is all decided by the server.

In this gif you see the test-skill "wave" with a cooldown, and then the attack ability without a cooldown:

skillbar.gif

 

Okay, that is it for this update. I am still having fun with the project and at this point I am sure that by the end of the challenge there will be a playable result for everyone to try out.
How "deep" the game play will be is a question of available time and motivation until the end of February.

 

Also: any feedback is very welcome!

Link to comment
Share on other sites

You did a good job. congratulations.

I am curious to know how you solved the latency problem between the server and the client you are talking about here:

http://www.html5gamedevs.com/topic/27183-babylonjs-25-challange-jppresents-progress-blog-update-14012017/?do=findComment&comment=156774

With you of code to show to see how this has been resolved.

Link to comment
Share on other sites

23 minutes ago, Dad72 said:

I am curious to know how you solved the latency problem between the server and the client you are talking about here: [...]

Hi,

Thank you for your interest.

That actually was not a latency problem. It was caused by me not realizing the real time that passed between calculation ticks on the server.
(I thought that setInterval would trigger the function in exactly the given amount of milliseconds but in fact that's not true - so my fix was to keep track of the time difference between server ticks and setting the distance traveled according to that.)

For the actual latency, the server is actually ahead of the clients in my game:

When you click to move in the client A, the client just sends this command to the server (without starting to move the character).
Upon receiving the move command, the server sends a message to all clients, that the player object of clientA now moves. (The server begins to move it, all clients begin to move it when receiving the message). When the object reaches it's destination (or is block or anything like that) the server sends another message to everyone.

The messages contain all info about the object, so clients that got out of sync for any reason can fix that. To not have stuff "jump" around on fixing the positions, the client calculates how much he is off and fixes smoothed out over a few frames. (So the object more or less slides into the corrected position instead of warping there.)

I don't have any fancy latency detection and calculations. I think it's still fine, because while the game is realtime it is not relying on totally exact positions on every client.

Link to comment
Share on other sites

1 hour ago, jpdev said:

That actually was not a latency problem. It was caused by me not realizing the real time that passed between calculation ticks on the server.

I know that a couple of users on this board, myself included, are using Node-Gameloop:

http://timetocode.tumblr.com/post/71512510386/an-accurate-nodejs-game-loop-inbetween-settimeout

https://www.npmjs.com/package/node-gameloop

Link to comment
Share on other sites

Time for the weekly update :)

I have been working further towards the goal of having different skills in the game.
So now there is casting complete with a cast time, cast bar and an effect on the target of the cast:

heal.gif

You can also cancel your casts by moving or pressing esc. Pressing the button again won't cancel it to allow for "button mashing" to recast as fast as possible.

When creating the cast bar I noticed that parts of my ui were not behaving correctly when the browser window is resized. Upon investigation and debugging I found the reason: 
When using canvas2D and placing something on a fullscreen canvas with marginAlignment, never set x or y on that object, as this will disable correct realignment on window size change.

For anyone curious here is a playground for the heal effect on the target: http://babylonjs-playground.com/#1SKP0W#0
All that's needed to get the final effect is setting a circle texture on the planes.

Yesterday I was in the mood to try a bit of modelling in blender, here is the new enemy I have created:

modelling.gif

It's some kind of scopiony monster that will roam the world and sting anyone who comes too close. I decided to name them "Scry".

 

 

Link to comment
Share on other sites

Thank you Delakosh & joshcamas for the praise.

In reply to the idea that this could be a community thing: I fear this project is a long way of from something that can be easily extended. Since it is my first attempt to create a multiplayer game it lacks structure and uses many "hacks", just because I make it up as I go along.

Anyway, here is my newest update:

The fighter character has learned to charge at enemies. I started with this playground with the goal to create something like a heatwave/shockwave:  http://babylonjs-playground.com/#JNOJX#4

I improved on it a little when adding it to the game, this is what a charge looks like:

charge.gif

Next up I finished the healers skills. They consist of a normal heal with moderate casttime and no cooldown, an instant heal with no casttime at all and a group heal with a longer casttime and a cooldown.

Here are the heals "in action":

heals.gif

 

When experimenting with the charge effect I came across this thread:

I now finally understand the difference between hasAlpha and adding a opacityTexture:
hasAlpha: This is 1 bit transparency. A pixel is either fully see-though or completly solid. (alpha test)
opacityTexture: Smooth alpha values from the texture are used. (alpha blending)

Next I made a playground to add an effect to a swiping attack for the fighter character. It deals damage around the character.
http://www.babylonjs-playground.com/#OJCYN#0

When put ingame the swipe attack now looks like this:

swipe.gif

Notice that it is completly overpowered in this version - you will not be able to just swipe a bunch of enemies and kill them in one hit.

Link to comment
Share on other sites

@gryff & @hunts:
At least in my case (maybe because I don't know any better) the server stuff in itself isn't all that different from just writing a normal gameloop that moves objects around. It's even in the same language, since I use nodeJS for the serverside.
The next thing it's about getting the stuff to the clients (not complex either, since you can just serialize a bunch of objects with a simple call to JSON.stringify and get them back on the client side with JSON.parse).
Now it's the clients job to represent the server objects to the user.

For me the complexity (and bugs.. lots and lots of bugs) come in at these points:
- On the server side: not sending everything all the time to the clients (tracking on the serverside what has changed and only sending those objects)
- On the client side: haveing things keep moving while waiting for the next message from the server (server says playerA is moving from (10, 20) to (20,20) - the server will only mention this player again, when he reaches 20,20 or he cancels his move or does something else - so now the client has to animate the player moving there on its own, with the same speed that the server moves stuff)

That pretty much describes what is going on in an abstract way. When the game is done I will most likely release the source code (which is a mess, keep in mind this an experiment).

 

@Deltakosh:
Thank you again for the encouragement - I feel the need to say: The goal & scope of this game is to provide something to play for a few minutes that requires 3+ players that coordinate a little. I say this so nobody expects a mmo-experiance or something like it.

With that out of the way, here is a small update:

The last fighter skill is something to press when there is a lot of damage incomming (or maybe when the healer is busy running away from something) to keep you alive a little bit longer. It's an energy shield. Here is the playground I used to come up with an effect for the shield: http://babylonjs-playground.com/#LFUNT#1

Also the scry mentioned in an earlier update got (kind of sloppy) walk & death animations and is now in the game.

Here is a fighter using all skills, first a charge and then swipe & shield to fight a scry:

shield.gif

I have started working on the third and last character class, the caster.
Here is the full team:

team.png

 

Last weekend I had a friend visiting and we took about 20 minutes to test the game, he played the healer and I played the fighter.
It quickly became obvious, that as a healer you need to see the health bars of everybody and a better way of targeting who you want to heal.
He also found a bug where the healer would attack other players if you first attacked a monster and then heal a player.

All those things are really hard to notice when solo testing the game, which shows how important it is to get help testing multiplayer games.

Link to comment
Share on other sites

4 hours ago, jpdev said:

When the game is done I will most likely release the source code

@jpdev : TY!!.

Watching the shots above, I keep thinking of a line from the song, "Lady With The Blue Dress" :

Quote

Don't try to be cute with me

cheers, gryff :) 

Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Loading...
 Share

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...