teaching machines

CS 491: Meeting 7 – Smooth Movement and Projectiles

February 25, 2020 by . Filed under gamedev, lectures, spring-2020.

Dear students:

In your prototypes last week, we saw that all of our games are going to involve physical interactions between objects. At the end of our last lab we were manually positioning our players, which meant that we could walk through walls. Also, the movement was jerky. In today’s lab, we look at how we can use the physics engine, smooth out the movement, and launch projectiles from the avatar.

Smoother Motion

This is the controller that we assembed in our last lab exercise.

We assembled the controller as follows:

The firmware code we wrote might have looked something like this:

void setup() {
  pinMode(A0, INPUT);
  pinMode(A1, INPUT);
  Serial.begin(9600);
}

void loop() {
  int x = analogRead(A0) - 512;
  int y = 512 - analogRead(A1);
  Serial.print('[');
  Serial.print(x);
  Serial.print(' ');
  Serial.print(y);
  Serial.println(']');
  delay(50);
}

We connected with the controller in Unity with code that looked something like this in Update:

string line = serial.ReadLine().TrimEnd();
if (line.Length >= 2 && line[0] == '[' && line[line.Length - 1] == ']') {
  string payload = line.Substring(1, line.Length - 2);
  string[] tokens = payload.Split(' ');
  int x, y;
  int.TryParse(tokens[0], out x);
  int.TryParse(tokens[1], out y);
  if (Mathf.Abs(x) < 10) x = 0;
  if (Mathf.Abs(y) < 10) y = 0;

  transform.position += new Vector3(x, y, 0) / 1000f;
}

Get your project back to this state if it’s not already there. Comment out OnTriggerEnter2D.

Rigidbody Physics

Our first step is to let Unity’s physics engine control the position of the player. Physics will do a better job of producing realistic motion than us. Complete these checkpoints:

Does this feel any smoother? Probably not. We are still instantaneously setting the velocity, which leads to discontinuities.

Low-pass Filter

We can smooth out the velocity by blending the current velocity with the previous velocity. For example, we might take 30% of the previous velocity and 70% of the current velocity. Complete these checkpoints to enable this smoothing mechanism, which is called a low-pass filter:

When you test the game now, do you see how the movement ramps up and down? For instance, after you let go of the joystick, the player keeps moving for a few frames. But the motion’s still jerky.

Faster Read

To get rid of jerks completely, we need to read faster from the serial port. Let’s switch up our reading algorithm from reading one line at a time to reading as much as data as is available and skipping directly to the most recent [x y] message. Alter the reading algorithm to this mix of C# and pseudocode:

buffer += serial.ReadExisting()
look for last occurrence of ] in buffer
if ] appears
  look for [ that matches ]
  if [ appears
    extract out payload between [ and ]
    // split, parse, and update velocity as before
    reduce buffer to substring starting after ]
  else
    clear buffer since we don't have a complete payload

This algorithm skips over all the old payloads from the controller.

Additionally, tweak the serial port to timeout nearly immediately if there are no bytes available with this code:

void Start() {
  // ...
  serial.ReadTimeout = 1;
}

When there’s nothing to read, we now get an exception. Use this try-catch in Update to ignore it:

try {
  buffer += serial.ReadExisting();
  // ...
} catch (System.TimeoutException) {}

The motion should now be wonderfully smooth.

Projectiles

It’s common to control a player by directly setting the velocity of its Rigidbody2D. We are, after all, used to players not fully conforming to the laws of physics. But we expect more realistic behavior out of other kinds of objects. Let’s look at how the player can fire off projectiles.

Arduino

We need a fire button. The joystick has a builtin button. Complete these steps to incorporate it into your controller:

In a game with rapid fire projectiles, we might want to know if the button is currently down.

Unity

Back in Unity, we respond to a button press by creating a brand new game object and launching it with some force. Complete these steps to the projectiles flying.

That’s it. You’ve now seen two ways of using rigidbody physics to add some life to your game.

See you next time!

Sincerely,