Getting Ideas
My kids have been bugging me about creating another game that they can play. I already have RPS SHOOT which is a twist on the classic Rock, Paper, Scissors game that they enjoy, but that game is nearly a year old now. Kids get bored easily and always want a shiny new thing to play with after all. My daughter is not able to read that well yet so I knew I needed to do something without many words. I thought about the games my kids like to play. Some of their current favorites are UNO, Go Fish, Memory and Yahtzee. They also love to play hide and seek (especially when I pretend to be bad at looking). Last year, I had been playing around with some protoypes using HTML Canvas to try to make a more traditional game on the platform. I looked at PixiJS which seemed promising but was a bit overkill for what I wanted to do. Perhaps I’ll revisit that in the future for other games.
The beginning
For my admin account, I have a GameType of Experiments
where I can easily play around with ideas. It does all the required game setup for websockets, game creation and allows players to join etc. Basically it’s just a sandbox area for me to experiment in. I originally started with a game concept of “tag” where you’d move your avatar around the screen and try to bump into the other players. One player would be “it” and the others would try to run away. I added a virtual joystick on the player screens and sent the directional data over the websockets. I also added a “boost” feature that had a ‘cooldown’ so you could speed away. This was a bit naive for how this type of a game should function. The player clients shouldn’t be constantly sending location data. It should to be sent on some fixed interval (game tick) but that also requires maintaining location data on the player side. It worked alright but it had some latency and of course spammed the websocket layer. It definitely wouldn’t be something that would scale very well. It was around that time I thought it might be fun to create hiding spots so you could hide when playing tag. That triggered the idea of making a hide and seek game with one player testing their memory.
Map content
From the beginning, I knew I wanted to use a 2.5D top down perspective as it fit pretty well with my current avatars. It’s basically the normal view for old school RPGs. Think of games like The Legend of Zelda: A Link to the Past or Chrono Trigger from the Super Nintendo era. Here’s a few examples of the perspective:
Building examples


Avatar examples



I thought it would be easy to move the avatars around and “hide” them behind the buildings. This is easily accomplished via the z-index attr in css for layering.
Movement
The joystick movement from my original “tag” idea offered more freedom, but added quite a bit more complexity. I decided to create a simple UI for the hiders so they could just tap on the hiding spots to move their avatars. The host screen would have the actual map, and the player screens a grid-like structure of the hiding spots (in roughly the same location space-wise). They could tap a location, and the avatar would move from their current location, to the new one. You can also interrupt the movement if the avatar is still moving to shift them to a new location.
Example map

Player hiding controls

Since the whole map itself doesn’t look that great on a phone screen, I wanted to create a similar layout for the hiders so they had larger hiding spots to click on to move their avatar. I’m still deciding whether players will see the map on their phones. I may need to revisit it after some real-world play testing. I’d likely need to do a “full-screen” mode where the player can rotate their devices to landscape to see a larger map.
Scaling and positioning
The map is basically just a 2D grid. It was fairly easy to just use a X/Y coordinate system with the HTML canvas. The map image has a fixed size, but I would need to apply scaling based on the size of the screen since a game can be hosted from any browser window and also via a Chromecast or other Smart TV. That also means I will need to recalculate the positions of the “hiding spots” based on the size of the rendered map and also the positions of the players. Luckily with a fixed aspect-ratio of the map and a bit of math, it is relatively easy to fix. Small code snippet incoming:
const containerX = screenSize.width * scaling; //IMAGE_WIDTH * SCALING; const X_SCALE = containerX / IMAGE_WIDTH; const containerY = containerX / IMAGE_RATIO; // 850 * SCALING; const Y_SCALE = containerY / IMAGE_HEIGHT; const spriteSize = containerY / 13; ... const setPlayerCordWithScale = useCallback( (playerId: number, coord: Coordinate) => { if (coord) { //Offsets are so the sprite is roughly in the middle of the hiding spot const xOffset = (coord.width * xScale) / 2 - spriteSize / 2 ; const yOffset = (coord.height * yScale) / 2 - spriteSize / 2; setPlayerX(playerId, coord.x * xScale + xOffset); setPlayerY(playerId, coord.y * yScale + yOffset); } }, [xScale, yScale, spriteSize, setPlayerX, setPlayerY] );
In short, it is recalculating the actual rendered size of the map image and providing separate X and Y scale variables to use when recalculating player positions and hiding spot locations in relation to the map.
Wrapping up
I’ve already tested some of the concepts with my kids and we’ve had a good laugh. I added in some logic so you can play with AI players as well. They will only participate as hiders in this game. Making some kind of “seeker AI” didn’t seem worthwhile. I’m hoping to finalize the game for alpha testers in the next couple weeks. I still need to make the frontend a bit flashier, add some sounds/animations, and create a simple tutorial. If you’ve made it this far, thanks for reading. Did I get something wrong? Let me know at [email protected]