The hobby game developer thread: Unity or otherwise!

I think old games use what are effectively bounding box methods for cameras, not interpolation. The idea is that there’s a small box around the center of the screen, and if the character is outside of it, it snaps the center to the character (if possible). Well, a little more complex than that. You don’t want to necessarily snap the center, but transform the correct direction. You want the give in different directions to be independent. So if the character is horizontally out of the box, but not vertically, you only snap camera.x to the player. If the character is vertically out of the box, only snap y. If they’re completely out, snap both.

The code would just be something like



if player.center.x > boundingBox.center.x + boundingBox.width.x/2 ||
   player.center.x < boundingBox.center.x - boundingBox.width.x/2 {
    if camera.IsValidPosition(player.center.x, camera.center.y) {
        camera.center.x = player.center.x
        boundingBox.center.x = player.center.x
    }
}

if player.center.y > boundingBox.center.y + boundingBox.height.y/2 ||
   player.center.y < boundingBox.center.x - boundingBox.height.y/2 {
    if camera.IsValidPosition(camera.center.y, player.center.y) {
        camera.center.y = player.center.y
        boundingBox.center.y = player.center.y
    }
}


You do need to spend some time tuning the size of the bounding box, too big and it will be too jarring when it moves, too small and it will be jittery, but I think it works.

If you want a bigger box and/or to do an interpolation method, I think the way to go is to add an acceleration term so that the longer the player is off-center/out of the bounding box the faster the camera tries to catch up.

Edit: This only works if your game isn’t something like Sonic, though it’s simple enough to do a state transition to another method if your character is moving fast enough.

Excellent break down of one of the kings of 2D camera controllers, Super Mario World:

Ha, I knew there was a game that only had a tolerance when you changed direction! That was my original idea, but the reference I used for my post was Sonic which seems to work the way I described, except when Sonic is going really fast. (There also seems to be some logic to prevent the camera from going up when you jump if there’s nothing to jump to).

Yeah, I kinda posted that in my blog post too. :wink: The thing is, when you implement it as is in Unity, you get a horrible jittery camera I don’t know why. My guess is frame rates (since on the SNES presumably frame rates were locked) but I don’t know…

I was trying desperately (not really) to find some description of how the Sonic camera worked, because it’s like magic. Knows when to scroll up and down, how fast to move forward and is perfectly damped. How does it do it??

No real progress that anyone can actually really see. I bought the Daikon Forge GUI asset in an asset sale, which means I can now have far fancier GUIs. All I’ve really done so far is convert my labels to OpenType fonts with a an outline and a gradient.

I’ve basically been cleaning up a lot. Unity is still pretty new to me, although I have been programming for years, so the structure of things is taking some getting used to. I’ve made the newbie error of just about every script having a reference to everything else, so that needs to be sorted. I implemented a simple Finite State Machine to organise process flow, which doesn’t do much right now but will make things more sane further down the line.

But it really does just look like some blobs flying around a screen right now.

My guess: a lot of special cases. I’m not sure if there’s logic involved (e.g. “there’s a ceiling here, don’t scroll up”), or if they literally hardcoded little trigger points where the camera hard-locks on certain axes. It wouldn’t be hard or expensive, even for a cartridge game, to just say “you passes this threshold and are therefore in a room, with all the camera state modifiers that entails.”

Cameras are hard, that’s why my first 3D game is going to be first person, and why my 2D game isn’t going to have continuous screen scrolling platforming.

Edit: For what it’s worth, the .gif on your blog doesn’t look jittery at all to me. Maybe you’re just seeing flaws that most people wouldn’t notice? That tends to happen a lot in any creative endeavor.

Ha! I knew it. Sonic uses a bounding box. It does the magical lag when Sonic is fast by having a max transition (so if you overshoot by too much it will only move 16 pixels rather than the whole screen).

And if Unity is using floats instead of pixels for its measurements, that would explain some jitteriness. Comparing floats is weird, if you represent your level and positioning information in pixels (or some integer value) and convert to floats only where you need to, you’ll probably have much better info.

Everything you never wanted to know about how Sonic’s programming works. The collision one is really interesting.

Yeah, that’s because I put it that much damping. You can tell when I reverse direction, the camera never really catches up.

Question.

Have been playing around with 2 problems for the last several days. Just wondering if anybody else has done the same and found any good resources? I know I can ask on coding blogs, but the Dope just feels better.

  1. Interception Functions for guided missiles. I have a basic tracking function that directs to a targets current location, but it obviously misses often when the target is moving and swings around and usually misses again until the 3rd or 4th pass. Most of the code I’ve found for using intercept math is kind of a pain and my calc/trig days are pretty far behind me.

  2. Rotation clamps for ball turrets with 90 degree limits on XYZ rotation. Am working on a space game and don’t want gun ports turning around and shooting their own ship. I’ve found a lot on single axis clamps, but it seems rough and crude repeating for XYZ. Plus I’ve run into the quaternion/euler spiderwebs. Seems like it should be easy, but the blogs I’m finding on the web have very disparate answers.

As background as mentioned in prior posts, I’m a newb to coding and just started using Unity a few weeks ago. If only it were more like excel :slight_smile: or not… cause then it would be work and not fun.

Look into Steering Behaviors, that’s one simple example in 2D but you should be able to find plenty of examples.

You probably don’t want to rotate your cannons in 3 dimensions. I’m having trouble imagining a cannon that would use all three. The only examples I’m coming up with would definitely not do 90 degrees in each direction. There are multiple ways to do this, the easiest is probably with a scenegraph. Can you describe (or post pictures of) your cannon? There are multiple ways I can think of, but it depends on the exact sort of turret you use.

Now that I have time – for a missile, I think the trick is to make it move really, really fast. Seeking should be more “perfect” the faster the seeking object moves. It’s natural for it to miss when going too slowly, in fact, it’s a feature in a lot of games.

As for the turret, well, it’s way easier with pictures.

Let’s have a cannon facing down the Y axis:

The plane behind it is our “ship”.

Now let’s move it 90 degrees around the “Y-axis”

As you can see, nothing happens. It’s still perpendicular to the ship. (Okay, it moved a little, but that’s because I didn’t have it snapped to the Y-axis properly, in principle it won’t move).

Now we’ll rotate it about the X-axis:

Everything is as expected. Now let’s do it about the Z-axis:

It works normally. These two rotations don’t affect each other. In fact, I did the rotation again in Blender and made a picture, but it didn’t look any different so I scrapped it.

What have we learned from this? If your cannon is facing down a given axis, the rotation is simple: keep track of its rotations in the two other axes and clamp them, individually, to 90 and -90 degrees. If you use Euler angles this is equivalent to (pseudocode):


// Where z and x are some input angles you want to clamp
zAngle = clamp(-90,90, z);
xAngle = clamp(-90,90,x);
myRotation = Quaternion.Euler(0,0,zAngle) * Quaternion.Euler(xAngle, 0, 0);


Apologies if this isn’t perfect Unity, I don’t use Unity, but I think those are the functions it uses. Except clamp, which is just the function:



float Clamp(min float, max float, input float) {
   if (input < min) {
      return min;
   } else if (input > max) {
      return max;
   } else {
       return input;
    }
}


Remember, it doesn’t matter which order the x and z rotations are in for this example.

Now for the second type of cannon you might mean, what I would call the “turret cannon”.

This is the type of cannon you’d see on towers, where it’s a “swivel” sort of cannon, where the turret swivels around and then you adjust the exact firing angle for range.

Let’s say we want to fire 45 degrees (max distance), swiveled to 90 degrees to the right of where we’re currently shooting.

Well, let’s swivel the dome first:

So far so good. Now let’s rotate the cannon be 90 degrees along the z-axis and then do the x rotation!

Succe… er… oops. Remember, rotating along the axis the cannon is already pointing towards does nothing. This introduces us to a nice fact: Euler angles are order dependent. However, in the first example, it didn’t matter due to mathy properties we don’t need to get into.

Let’s rotate the other way around, 45 degrees about x, THEN 90 degrees about y:

Success!

In this case, we only need to clamp rotation in one direction: the x direction. We just have to make sure to compose our rotation in the right order.



zRotation = Quaternion.Euler(0,0,zAngle);
domeRotation = zRotation;
xAngle = clamp(x);
xRotation = Quaternion.Euler(xAngle,0,0);
cannon.Rotation = zRotation * xRotation;


There is one tricky part here: didn’t I say to do x first? Well, vector math is a bit silly, the thing on the righthand-most side is applied first. So x is done first in this example, despite it intuitively being opposite.

Now you might say “that’s great, but this cannon is part of my ship, how do I get it there? Right now it’s just at some central axis, not very helpful” The answer is: the steps above work fine. Just do them FIRST. You may or may not have heard about the “model view projection” (or MVP) model. In this model, you move everything into the world, then transform it with respect to the camera, then warp it so it looks right. Unity will take care of the V and P part for you, so you’re only worrying about M.

Normally, M is just one thing “I have a ship with some heading at some location” and you simply rotate and translate accordingly. However, if we introduce something called a scenegraph we can make everything really simple.

The idea is that we split the “model” into several steps: the object transformation, the “owner” transformation, and then the world (“model”) transformation.

The object transformation is what we did above. We’ll call this objectTransform. The owner transform is what we do to get it to the right place as if the model was at 0,0 facing its default direction. So if you were at the ship’s center, the cannon was rotated 90 degrees around the z axis and at the coordinates (5,5,0), the owner transform would be:


rotation = Quaternion.Euler(0,0,90);
translation = Translate(5,5,0); // Don't know what the unity for a translation matrix is
cannon.Position = translation * cannon.Position;
cannon.Rotation = rotation * cannon.Rotation;


That’s it!

Now what about the model transform? That’s just whatever you were already doing for the “owner”. If the ship is at (0,12,15), and facing at 30 degrees in the Y direction;


translation = Translate(0,12,15);
rotation = Quaternion.Euler(0,30,0);
cannon.Position = translation * cannon.Position;
cannon.Rotation = rotation * cannon.Rotation;


Which is exactly identical to the above! :slight_smile:

In fact, with this sort of hierarchy, you can model an arbitrary number of ownership properties. Want that ship docked in a moving carrier? Transform the cannon with the ship and the ship with the carrier. Want that carrier orbiting a planet? Then transform that mess with the planet. Just do it in order. In fact, the design is harder than the math. Figuring out exactly which component or object to apply this intermediate transformations from is much harder than the transformations themselves, but that’s ultimately up to whatever is most comfortable for you.

I hope that helped, I’m happy to clarify anything.

I should mention: it may seem scary at first knowing which order to do rotations in, but it’s actually intuitive. I use my forearm to do the calculations (I point my forearm in a direction and rotate). If I need more freedom, I just grab an empty paper towel tube.

Point it in the direction you want and rotate along one axis at a time. Just make sure you label your x,y, and z in your head ahead of time and make sure they match up with the corresponding axes in your game.

Actually, disregard the scenegraph stuff for two reasons:

One, by setting up a parent/child relationship Unity does it for you. Two: it won’t work because it has no idea what order to multiply the rotations and positions in. All you need are the model transforms from the first 2/3 of my post.

Don’t you dare go there.

… and put on my robe and wizard hat

Anyone having issues with the mesh colliders?

I’m starting with a humble project - a CCG. I’m using the built in physics API’s to interact with the cards and the table and the user, etc. But for some reason my mesh colliders are off. My cards always fall about 1/2 way into the table. I’m using a primitive collider for the table since it IS a primitive. I’ve solved the issue by moving the collider mesh up and out of the table object by a small amount so that the center is just above the surface of the table.

But it’s going to suck if I’m going to have to do the same thing for every other interactive object…

Kinthalis, does the table also have a mesh collider? Mesh colliders can interact weirdly with other mesh colliders.

Possible solution 1: You might check the Convex box in the inspector of both the cards and the table.
Possible solution 2: Don’t use a mesh collider. Use a cube collider (modifying it to be rectangular and card-shaped) or use a bunch of non-mesh colliders together for the table.
Possible solution 3: The game engine thinks that the pivot point of your card is at its center. It therefore puts the pivot point (center) of your card on the table, leaving half the card inside the table. Move that pivot point so that it’s on the bottom face of the card.

Also, keep in mind that you can attach an empty game object (EGO) to your card/table and have that EGO use a simpler collider. That way, you retain a collider which has about the same shape as your card/table while being less resource intensive and, depending on circumstances, easier to manage. Doesn’t make much of a difference for simple objects but can be quite useful for complex objects because you don’t need your collider to follow every millimetre of your object’s shape.

Does Unity use a hierarchy? I would expect it to wrap convex hulls in simple cubes or capsules. The way it usually goes is first it checks all the simple broad-phase objects, and if it’s in them, it does a second check against the expensive mesh, which drastically reduces the cost of the complex check (or rather, it drastically reduces the number of complex checks it needs to do). It should make convex hulls no big deal, from a computation standpoint. I’d expect Unity to do that automatically, but I have to admit I’m not certain.

eta: I mesh colliders are convex hulls.