0
\$\begingroup\$

With a little help I have managed to create a 2D planet with working gravity that constantly pulls a character towards its center. The only problem now is that I am completely stumped on how to make it so the user is able to make this character traverse the planet as one would expect rather than the simple up/down/left/right we are used to in natural platformers.

It should be noted the planet being traversed will have platforms/layers to jump and fall onto, so the moving and jumping should be in relation to the center of the planet, where the center of the planet acts as "down" would in a traditional platformer (which is why I seem to think I need a complicated way to create this kind of natural movement).

I had the idea of recalculating a new left and right direction to move in every time position is changed but the logic I have to work out to achieve this is beyond my knowledge.

Is this the only way to go or should I try tackling the problem differently? I hope not because I don't think I'd be able to achieve this otherwise.

This is my current code showing how the gravity works, with a simple placeholder for movement that just allows the character to move up/down/left/right on the screen:

public function moveChar(event:Event):void
    {
            if (leftPressed)
            {
                character.x -= mainSpeed;
            }
            if (rightPressed)
            {
                character.x += mainSpeed;
            }
            if (upPressed)
            {
                character.y -= mainSpeed;
            }
            if (downPressed)
            {
                character.y += mainSpeed;
            }
        }

public function gravity():void
{
    //tan2(planet.y - player.y, planet.x - player.x)
    angle = Math.atan2((planet1.y + 2245) - (character.y+5), (planet1.x+2245) - (character.x+5));
    gravityX = Math.cos(angle) * gravitationalAcceleration;
    gravityY = Math.sin(angle) * gravitationalAcceleration;

    //distance = Math2.Pythagoras(planet1.x + 50, planet1.y + 50, character1.x + 5, character1.y + 5);
    distance = Math.sqrt((yDistance * yDistance) + (xDistance * xDistance));

    //Calculate the distance between the character and the planet in terms of x and y coordinate
    xDistance = (character.x + 5) - (planet1.x + 2245);//320 to 50
    yDistance = (character.y + 5) - (planet1.y + 2245);//320 to 50

    //Make sure this distance is a positive value
    if (xDistance < 0) {
        xDistance = -xDistance;
    }
    if (yDistance < 0) {
        yDistance = -yDistance;
    }

    //Update the current velocity before new velocity is calculated
    initialXVelocity = finalXVelocity;
    initialYVelocity = finalYVelocity;

    //Send the character into the correct direction
    character.x += gravityX;
    character.y += gravityY;

    //Basic collision detection of the surface, basic stop of gravity
    if (distance <= planet1Radius) {
    trace("hit!");

    if (planet1.x - 2180 < character.x - 5) { //320 to 50
        character.x -= gravityX*1.025;
    }
    else {
        character.x += gravityX*1.025;
    }
    if (planet1.y - 2180 < character.y - 5) { //320 to 50
        character.y -= gravityY*1.025;
    }
    else {
        character.y += gravityY*1.025;
    }
    } else {
    trace(" no hit!");
    }
}

edit1: I now have this code thanks to @DMGregory:

var characterPosition:Point = new Point();
var planetPosition:Point = new Point();
characterPosition.x = character.x;
characterPosition.y = character.y;
planetPosition.x = planet1.x;
planetPosition.y = planet1.y;

var localUp = normalize(characterPosition - planetPosition);
var localRight = new vector2( -localUp.y, localUp.x);

However, I have trouble understanding the syntax I should be using here, and also for when I need to move the character. Should it look something like this:

if (rightPressed)
{
    character.x += localRight;
{
if (leftPressed)
{
    character.x -= localLeft;
{ 
\$\endgroup\$
  • \$\begingroup\$ ...this code is pretty confused. You're calculating the offset from player to planet (with some odd magic numbers) twice - once in your (trig based!?) gravity calculation, once in your distance calculation. You're making your distance components positive when you only ever use them in squared form so that's irrelevant, and you're using them to detect collision before you've updated position, so you overshoot the collision before detecting it. And the collision resolution looks extremely dicey. I'd recommend a complete overhaul. Ping me on chat/Twitter and I can walk you through it. \$\endgroup\$ – DMGregory Apr 12 '16 at 13:01
0
\$\begingroup\$

The math for calculating this local basis in 2D is actually pretty straightforward:

  localUp = normalize(myPos - planetCenter);
  localRight = new vector2(-localUp.y, localUp.x);

This gives you two perpendicular vectors of unit length, which you can use to apply movement to your character toward/away from the planet or around it tangentially.

Edit: as in my previous answer, I'm using vector notation for simplicity. To break it down into componentwise math:

localUpX = myPosX - planetCenterX;
localUpy = myPosY - planetCenterY;
var distanceFromCenter : Number = Math.sqrt(localUpX * localUpX + localUpY * localUpY);

// Normalization
localUpX /= distanceFromCenter;
localUpY /= distanceFromCenter;

localRightX = -localUpY;
localRightY = localUpX;

Using this, you'd update your movement logic something like...

if (leftPressed)
{
    character.x -= localRightX * mainSpeed;
    character.y -= localRightY * mainSpeed;
}

If you're unable to translate between vector notation and componentwise operations like this, then I strongly advise that you take some time to learn a little linear algebra, also called vector math. It's used a ton in games, so familiarity with it will let you do a lot more, and understand a lot more of how game developers talk about solving problems. There are free tutorials & courses online (check Khan Academy or Coursera for instance). Also, my offer in the comments above stands, if you want some coaching on fixing the rest of this code.

| improve this answer | |
\$\endgroup\$
  • \$\begingroup\$ Thank you for the answer. I am having trouble with the syntax I should be using though. I have edited into my question what I have learned so far. I also seem to have trouble importing what is necessary to use normalize() and vector2(). (call to a possibly undefined method) \$\endgroup\$ – Denver Thomas Apr 13 '16 at 10:38
  • \$\begingroup\$ @DenverThomas Updated to show the underlying math steps. Just be wary of cutting-and-pasting code you don't understand - it will quickly accrete into an unmaintainable mess unless you take the time to really grok what it's doing and integrate your code properly. \$\endgroup\$ – DMGregory Apr 13 '16 at 12:28
  • \$\begingroup\$ Thank you for the all the help, I understand the logic here and have adapted the logic into my own code! I am going to take your advice on furthering my learning of linear algebra, which seems to be my main problem (along with leaving remnants of failed experiments in my code :P). \$\endgroup\$ – Denver Thomas Apr 17 '16 at 1:04

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.