Board Game Mechanics (Chess, Checkers, Hitman GO, ...)

Hi everyone,

In brief: Does somebody out there have advice on how to work out the piece movement of, let’s say, chess? Not bothering with click-detection and the like, but simply “on Keypress, move piece to the square next to it”.

Longer version: For an assignment, I’m trying to reproduce a boardgame in the style of Hitman GO (Btw., highly recommend that one :smile:). These are tasks that I defined as being necessary:

A. Find Engine
B. Create 3D Models in Blender
C. Give the piece (I start with one controllable piece) the ability to “hop” a chess-board-like area.
D. Get “enemies” to wait for their turn, “walk” while detecting wether they can hop forward or have to adjust course (again, like in Hitman GO). During their turn, the player is “blocked”.
E. Get enemies to “watch out”, detecting wether the player is standing somewhere straigt in front of them. (View is blocked if there are obstacles in the way…)

Here’s how far I, knowing Javascript to a certain extent (2 years of fiddling, simple webapps and games with the create.js library) got:

A. Thought Playcanvas would be suitable. 3D, relatively simple (!?) and mobile export looked promising.
B. That’s running on the side, also troubles there, but I will work stuff out.

C. THAT is my current trouble… I first worked with arrays of coordinates, and moving the piece using translate(X,Y,Z) to some “goal”-coordinate. That worked, but it looked pretty unnatural, plus I couldn’t use the physics, if two pieces “met” for example. Felt somewhat overly complicated…
Tried with applyImpulse(). But that would leave me not being able to exactly say where the piece will go, pieces falling over (sometimes, due to friction etc.) and the pieces not knowing their position…

D. I didn’t find a way for the player piece to tell the others “Your turn”. Tried events (That didn’t work), script communication as in the tutorials seems to be restricted to the own entity.
E. Didn’t even bother looking into that yet…

Now, any help (almost…) to any of the points mentioned would be highly appreciated, although C. definitely is my biggest trouble at the moment. Would love to discuss ways with the community, or even team up or the like.

Have a nice day!

Greg

@C. You have many options that could work very well. One would be to use impulses to move the pieces, all the while restricting the x and z angular factors and temporarily disabling the rigid bodies on all other pieces. This would yield a more natural feel yet avoid topples and collisions with other pieces.

So, first up. Don’t use the physics engine for this. It will make your life much more complicated and add a lot of processing overhead that you don’t need.

Second, the best way to think about this is to work out the data that you need to store. Then you can add a layer of animation and prettiness on top of that.

Your data set is a grid of board locations, each board location:

  • contains an X,Y co-ordinate
  • can have connections to other locations. (possibly 0 if it’s inaccessible location)
  • can contain a piece

Then you have your player. Who knows:

  • which grid location they are in.
  • their current state (waiting for input or moving between locations)

And each enemy piece knows:

  • which grid location they are in
  • which grid location they are facing/watching

You can use this data to run your main game loop nice and easily with no need for physics.

e.g.

Rendering:

You can render the board (like in Hitman GO). By looping through the grid locations. For each location that has at least one connection, draw its location ( e.g. a little circle) and its connections (e.g. lines from our location halfway to next location, other half will be drawn by other connection).

Moving

When you receive player input this tells you a new target grid location to move to. You change the state of the player to “moving” so it won’t accept more input. Then, while the player is “moving” you animate it from its current location to the new location. The simplest case would be just to set the player location to be the new target position. To make this nicer you can use lerping or tweening/easing to smooth out the movement. Or you could fully animate the movement in Blender (though watch out, be sure to make sure you animate “in place” other wise it will get much more complicated). I would think you can use a simple tween to get nice looking movement.

When the animation is complete you are at your new location. Update the player position and the grid location to be the new location.

Kill Enemies

At the same time as moving, you need to check if the new location is already occupied by a piece. You just need to check the grid location to see if it already has a piece in it. If it does you do the “kill” animation on that piece and remove it from the location.

Enemy Watching
Finally when the player is in the new location. You check all the grid locations with an enemy and see if they are watching the location the player is now in. If any of them are. You do the “player die” animation and restart the level.

Events

Have a main game.js script which tracks the current game state. The state can be:

IDLE - waiting for player input
ENEMY_TURN - ignore player input, enemies are moving
PLAYER_TURN - ignore player input, player is moving

Use application events to communicate between scripts. e.g. there are game events

app.fire("game:state", PLAYER_TURN); // tell everyone the current game state

and player events

app.fire("player:turnend"); // player tells everyone that move is complete
app.fire("player:kill", enemy); // player tells everyone that it killed this enemy
app.fire("player:die"); // player died

Anyway, hope that helps.

3 Likes

Thank you so so much, @dave !!

I had actually already implemented this, but X and Y -arrays within the player, which made things a bit tedious… It was only after your reply that I understood:
A. that I could append scripts to the “root”, not only to entities…
B. How custom events work. The user manual had confused me a bit there, and I was trying to bind entities to some event node or what not… “app.on” within figurines, “app.fire” to, well, fire events. In a short test session everybody console.log’ged their part, I’ll stick with that.

Further, I want to thank you for the tip concerning the neighbouring fields, I’ll implement that as multidimensional array, 'connections[field][array-of-neighbours-of-field].
You were right, I’ll not focus on the aesthetics for now, a cylinder hopping blocks in the void isn’t a problem, as physics shall not bother me any further. I had already written a short “move-to-fieldnumber-X”-method, I’m going to refine it. The pieces then hover to other points steadily, which looks strange, but with the right sound (later) they could act as the chess pieces from Harry Potter (if I remember rightly, that’s how they moved). Or, with a vertical “hop”-animation, they could just do that sweet parabola-movement, a bit like the apple thrown upwards in a moving train known from physics books.

But aesthetics aside, I have two short questions following your answers.

  1. game.js AND token.js knowing the position of tokens smells like data redundancy… Maybe an OOP, blackbox-ish approach (entities only giving data through methods) would be more suitable, with game.js simply accessing them as needed…
  2. You mentioned tweening… Is there a tweening method? Of the sort of jquery’s tweening? Or is translate-til-there the way to go?

Cheers!

Grég

Three short questions, actually… Sorry @dave :wink:

If I have the mainscript (game.js) attached to the “root” (top node) in the Editor, how do I then access its methods, for example “canImove()”, from a different entity (the player token)?
The Manual only describes accessing scripts of the same entity, doesn’t it?

Would appreciate an answer, or a short description/link to such of the “playcanvas DOM”…

Greg

A. that I could append scripts to the “root”, not only to entities…

You can also add library scripts in Script Priorities which are not attached to any entities. Useful if you have general purpose libs.

B. How custom events work. The user manual had confused me a bit there, and I was trying to bind entities to some event node or what not… “app.on” within figurines, “app.fire” to, well, fire events. In a short test session everybody console.log’ged their part, I’ll stick with that.

Using the app object as a central message passing system is quite a neat way of managing script communication. You can also listen and fire events on this (i.e. the script instance) or this.entity (the entity)

  1. game.js AND token.js knowing the position of tokens smells like data redundancy… Maybe an OOP, blackbox-ish approach (entities only giving data through methods) would be more suitable, with game.js simply accessing them as needed…

Possibly, though I’d have game.js storing the master set of data for the entire grid. Then the player stores its actual position (x,y,z) and it’s grid index (which as you say is technically duplicated data). You could skip the grid index and look it up from game.js, but I suspect it’s easier just to store a single number in the token, which will save iterating the data set everytime you need to look up some information from the game.js. You probably do want game.js to store what token is in which slot though as that will make checking for collisions/kills a lot easier.

There are a couple of 3rd party tween libraries that are pretty good. TweenJS and GreenSock TweenLite both work well. Download the minified version and drop it into your asset panel. Then add it to the Script Priorities to load it as a library.

1 Like

Getting references to Entities is can be done either by searching the hierarchy:

var entity = app.root.findByName("My Entity Name");

Or using a script attribute which is assigned in the Editor

pc.script.attribute("myEntity", "entity", null);

Once you have an Entity, you can get script instances from the script component, then you can call methods on that. In this case “script_name” is the name defined at the top of the script in the pc.script.create function.

entity.script.script_name.method();

As mentioned above though, firing “application events” i.e. app.fire("eventname") is a good way to communicate between scripts without explicitly storing references to entities. As with everything, both types of communication can be useful.

1 Like