Yesterday was quite fun (not).
As I previously mentioned, my current control scheme is to move the mouse left/right and the ship moves left/right (from the perspective of the pilot). Being that it’s an overhead view AND a radial motion (360 degrees) it leads to an inversion. When the ship is on the top half of the screen (i.e. North of the black hole/circle) it moves isomorphically to the mouse motion, as a player expects. If a player is expecting the mouse to move in a rotational manner instead, this means that when the ship hits the bottom half of the screen (i.e. South side of the blackhole/circle), it’s inverse to the expectation of the player. They would expect a leftward movement to move the ship left on the screen, whereas from the pilot’s view, it’s still a rightward movement. I wanted to implement a 360 control due to some complaints of the control scheme as it currently is.
So yesterday I began that. The first code I found was specifically for rotating an object around it’s own pivot point/center, to follow the mouse’s rotation. This will actually come in handy later for another game I think I’d like to make (if I ever get to it. Let’s focus on having one game created before I kick the bucket). It was easily implemented and worked really nice (after I got the kinks worked out). I then attempted to implement the function to rotate around the black hole using this information.
It didn’t work so easily. I finally hit upon some solutions that are very close, but not quite what I need.
See, when I started this project there was no Unity2D. All the stuff is 3D. This is actually kind of cool, because it’s actually a really easy to use and well documented system that I have already seen some cool effects happen via “happy accidents”, even though I am not currently using any of them. Unfortunately, this means that certain things require an extra bit of work to mesh with the 3D world (I believe that the newer versions of unity that now have proper 2d support built-in don’t have such issues, or at least reduce them).
So, for instance, if I have a point in 3d space on the screen and I want to work the angle in two dimensions, and also with the mouse’s position on the screen, there is a function that I have to use to map the 3d position of the object onto the screen in pixels/coordinates, and then manipulate that (in particular, I need to compare my Mouse_X and Mouse_Y coordinates to the object’s location in 3d space then mapped onto the screen coordinates and figure out the angle).
Doing this was fine and it allowed me to rotate the object around its own axis. When I tried the rotataround function I had a few issues:
1) The object never fully settled when it approached the angle of the mouse. Sometimes it did, but sometimes it would bounce a little left or right and never settle on it. This is due to the code I had to check for whether the object angle was equal to the object angle. I was rounding the values of the angles before moving the object.
My solution to this was to check if it was within a given range of that angle, and then slowly reduce the motion speed so that it would eventually go to a movement of 1 degree to move. The reason I don’t do this initially is because then it means that the motion is reaaaaaaaaaaaaaaaaaaallllly slow. So I set the movement speed to something like 1000, which gives it a fairly nice quick rotation, but it also means that it is difficult to get it to narrow in on the correct angle, and if you’re only within a couple degrees, you might be hopping over that point without ever landing on it. Slowing it down once I get close means that I can narrow in on that angle.
That seemed to solve the problem as far as I can tell.
2) Another curious issue that was occurring, and still is, was that I’d have duplicate objects flickering as if the object was moving so fast across the screen and jumping between two locations. Now that I got issue one solved, it seemed to be reduced, but not fully gone. I notice that if I retain my mouse distance from the object it works properly, but after a certain level of proximity to the rotating object, it does this “split” effect. It’s kind of cool looking, but definitely NOT what I want to be going on.
I realized that this is probably due to the fact that, currently my mouse is still set to detect its angle of rotation via the object, not the center of the screen which is where I am actually trying to get the angle from. I believe that as I move closer to the object itself, something is happening there, possibly with the fact that the angles are counted in floats (and that I am rounding to nearest integer value), so, perhaps I am getting closer and closer, and the accuracy of my angle goes up in relation to the object (I have much less wiggle room – literally) The larger the circle I move around, the more I can move without bumping out of a degree of motion.
This might be corrected if I round the value of the angle in a different location than where I am rounding it currently.
However, that’s a fudge. I think I need to link the mouse’s pivot location to the center of the screen. In fact, I tried doing that…
In the original rotation code (not the rotatearound() function which rotates around an external object; but the code that has the object rotate around its own pivot point), you subtract the object’s X and Y positions from the mouse’s X and Y positions in order to get the difference and calculate the angle. I can’t give you the math off the top of my head. However, the point being, is that I did something like this:
rotation_X = Mouse_X - Object_X
rotation_Y = Mouse_Y - Object_Y
Then did some stuff with the ATAN2 function that calculates stuff and returns the angle I need.
Well, I think to myself, clearly if I’m subtracting the object’s positions, and the blackhole object/center I’m actually trying to rotate around is located at <0,0,0>, I should be able to remove the subtraction and I should be fine, just use the Mouse_X and Mouse_Y values by themselves. But it wasn’t working. I gave up for the night.
Today, as I sat upon my philosophers throne (yeah, you know… the toilet), I pondered the issue and realized where I was going wrong.
Remember that bit about translating from 3D to 2D for the screen coordinates? Well I wasn’t doing that with the center/black hole object (in my test project, I don’t have a black hole object, but that doesn’t matter, it’s just as I said above <0,0,0>).
Since I wasn’t mapping that to the screen coordinates, the coordinates were all wrong, and thus weren’t allowing the rotation to work properly.
What I need to do is use that projection of the 3D to screen coordinates function applied to the position vector of the center of the game world around which my ship is rotating, and THAT should be subtracted from my MOUSE_X and MOUSE_Y coordinates in order to give me a proper pivot point for the mouse, and from there, hopefully everything should work well.
I hate feeling so stupid, and when I can’t work something out, it feels as though it’s my own idiocy because I never had anything beyond 2 algebra classes and geometry – never had Trigonometry or anything beyond that, and you know… It’s not like that stuff is fresh in my head being some 20+ years ago as is…
So it gets frustrating and I feel defeatist at times, but then when I find a solution I feel so proud, especially if I was able to arrive at it on my own without an external input.
Of course, tonight is the real test when I attempt to implement this and see if my theory holds up.
If it does, I think I’ll let the user select the mode of input they prefer. I think this also will now let me add in gamepad/controller input (using the PC-360 controller) since it’s essentially the same thing. But at least I can let the user try left-right or rotational modes of play. The left/right can actually work well with a spinner control as well (my friend wants to try it with a spinner control for his arcade cabinet, I think that’d be pretty fun).
CROSSING MY FINGERS!