Monthly Archives: February 2017

Making a game in Unity 3D

Published / by robsws / Leave a Comment

Contrary to what I planned before, I decided to go back to Unity and take on a 3D project this time.

The main reason I hadn’t decided to do this earlier was feeling like I would need to create 3D assets. Having dabbled with importing 3D assets before via the asset store, I was a little daunted by how I would even begin to integrate these into my own game. Therefore, I decided to make acquiring and using an asset package from the asset store a key goal for my next project so that 3D projects no longer felt as daunting to take on in the future. I decided to limit myself to the downloaded assets and try not to get tempted to start making any art of my own.

I eventually settled on downloading the 3D Platformer Game Kit as it seemed to have all the basic assets I would need for a classic 3D platforming game. On downloading, I was surprised at how much functionality was already included on top of the models and animations. In fact, I was a little disappointed as I was hoping to have to code some of the movement and physics myself as a learning exercise. As a direct consequence of this, I decided that a project goal should be to make significant changes to the movement logic already present within the package, if not replacing it all completely by the end.

Whilst thinking about how I could modify the movement logic, I had the idea of moving the character automatically around waypoints in the level, similar to something like Myst but from a third person perspective. Moving around the level could then be some kind of turn-based puzzle, where the player must avoid predictable enemy AI and collect items before making it to the exit. Since this would make most of the existing movement code obsolete (as it is designed for a freely moving platformer), I decided it would be an ideal mechanic to try and implement.

Although this idea meets all my personal goals, I am concerned about whether the final game will be fun to play. First of all, if the game is a puzzle game at heart, it may frustrate the players not to have a full view of the level at any one time so that they can formulate a plan for making it through. However, this obfuscation might also add to the fun, as some players may enjoy exploring the level and noting down routes. Secondly, I will need to be careful to make movement times between the waypoints fairly quick as it may be frustrating not to be able to execute puzzle solutions quickly as soon as the player knows exactly what they need to do.

My rough project plan is as follows:

  • Implement basic mechanics – adjust the existing asset code to implement movement between waypoints rather than free movement.
  • Refactor existing code – remove any code that has become unnecessary to the new movement system.
  • Implement enemies – add enemies and different kinds of enemy AI. The AI should never be random as the player should be able to puzzle their way through. Basic AI should include patrolling enemies and enemies who react to seeing you.
  • Implement items – add collectible items in levels. My current idea is to have the level complete-able having picked up only one collectible, but in order to unlock more levels the player will need more further down the line.
  • Implement game mechanics – add support for multiple levels and have a way to end levels. I want all levels to exist in the same world and be visible from other levels, but performance may be a limitation as the game grows larger.
  • Add some levels – design a small number of basic levels. Hopefully at this point this should just be a case of dragging and dropping prefabs into Unity, so the challenge here will be more of a puzzle design challenge, especially with so few core game mechanics.
  • Add UI and menus – add the finishing touches such as UI elements, music and a menu screen.

At this point I could probably end the project, but if I want to continue, I have some other ideas:

  • Implement advanced mechanics – keys and doors within levels, switches, moving platforms etc.
  • Add more levels – add more levels introducing the new mechanics gradually.
  • Re-skin the game – at this point I may have had a better idea for the general story/aesthetic of the game, so I may want to switch out the models/animations/textures I have for some that better fit in with this theme.
  • Play test – ask some friends to play the game and give feedback on all aspects. I will most likely do this at earlier points as well.

Of course my main goals here are still learning goals, but I’m excited to see whether a fun game can emerge out of that!

Xbox gamepad support for GoPiGo with RPC

Published / by robsws / Leave a Comment

The first thing I wanted to do after finishing building my GoPiGo robot was to try and set it up with a gamepad so that I could manually drive it around. It seemed that the work had already been done for me here, as one of the example python scripts included with the software implements the ability to connect a PS3 controller and send commands with bluetooth. However, having discovered that it seems the current version (at time of writing) of the GoPiGo software can’t make use of the built in bluetooth I decided to try and make it work anyway.

Since what I really wanted to do was make my Xbox One gamepad work with the robot rather than a PS3 controller, I decided on having the controller connected to my PC rather than the Pi directly. Then, the plan was to send commands to the Pi over WiFi rather than directly through bluetooth. On the Pi, a python server would run that would listen for commands over the network and move the robot accordingly. On the PC, a python client would interface with the Xbox controller and send on input information to the server.

Reading gamepad input

Reading input from the gamepad actually turned out to be very simple using a library called PyGame. Whilst this does a whole lot more than just reading gamepad input, it abstracts away the details nicely and works out of the box for a variety of standard gamepads, including my Xbox One gamepad.

The first thing I did was try and use the gamepad input to simply move a sprite around the PyGame window. Initially, the sprite moved far too quickly, but I soon able to identify that the frame rate was the problem. I wasn’t capping the frame rate in any way, and without the speed of the sprite being frame-rate-independent the sprite was lost off the edge of the screen almost immediately after moving. As I wasn’t planning on using the gamepad input for anything within the PyGame window for this project, I fixed the problem simply by capping the frame rate as 60fps.

clock.tick(60)

PyGame triggers JOYAXISMOTION events when the analog sticks on the gamepad are moved, which contain data about where they actually moved. Now I just needed to send this data to the robot itself and interpret it as robot movements.

# Get joypad input
 if event.type == JOYAXISMOTION:
   if event.axis == 0:
     speed[0] = int(event.value * 10)
   elif event.axis == 1:
     speed[1] = int(event.value * 10)

Sending commands over the network

Although there are plenty of options for transferring the input data from the PC to the Pi, I decided on using RPC as it seemed the simplest option via the XMLRPC python library.

All I had to do was make a new proxy object on the PC client to represent the Pi server and call the exposed “move_robot(turn, forward)” function on it to transfer the input data to the Pi. The JOYAXISMOTION event triggers twice for vertical and horizontal movements of an analog stick respectively, so the values of the two parameters were simply the values returned by these two events. Horizontal movements would turn the robot left and right, and vertical movements would accelerate or decelerate the robot.

# Initialise RPC
server = xmlrpc.client.ServerProxy("http://192.168.1.103:8000")

...

server.move_robot(speed[0], speed[1])

The Pi client simply had to define the move_robot function,  publish it as an RPC function and then listen for calls to the function from the client.

server.register_function(move_robot, "move_robot")
server.serve_forever()

Moving the robot

With the axis values successfully being transferred across the network, I needed to interpret these into commands for the robot. The GoPiGo python API provides a lot of functions for manipulating the wheels in different ways, but since I had high fidelity analog data about how fast the robot should turn or move forward, all I really wanted to do was control the speed of each wheel individually. However, the functions that do that don’t accept negative values, so you can’t move the robot backwards with just those. I had to tell the robot which general direction to move in to begin with based on the vertical axis value.

# throttle
 if forward < 0:
   fwd()
 elif forward > 0:
   bwd()
 else:
   stop()

With that out of the way, I set the base line speed to the absolute value of the vertical stick and figure out how much to turn based on the absolute value of the horizontal stick.

set_speed(abs(forward)*speed_multiplier)
# turning
  if turn < 0:
    # turn left
    set_right_speed(abs(forward) + abs(turn) * turn_multiplier)
    set_left_speed(abs(forward) - abs(turn) * turn_multiplier)
  elif turn > 0:
    # turn right
    set_right_speed(abs(forward) - abs(turn) * turn_multiplier)
    set_left_speed(abs(forward) + abs(turn) * turn_multiplier)

And that was it! I was able to drive the robot around using the analog stick on the Xbox One gamepad, albeit through the medium of my PC.