0
\$\begingroup\$

This is my first time posting here. Through the tutorials and videos I can find regarding developing games using libgdx. I thought I would start with something that was relatively simplistic, a Megaman game. I have a rudimentary engine up and running, but I have been having some difficulty accurately representing the physics of Megaman.

I found this thread that lists out the physics of the original:

http://sprites-inc.co.uk/showthread.php?tid=388

One other issue I have had is that, in testing, I found that after jumping, if you continually hit the jump button('S'), you can slow your fall. I have been unable to find a way of stopping that.

Any assistance or information would be greatly appreciated.

Megaman class:

package com.mygdx.game;

import com.badlogic.gdx.graphics.g2d.Sprite;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.graphics.g2d.Batch;
import com.badlogic.gdx.math.Vector2;
import com.badlogic.gdx.maps.tiled.TiledMapTileLayer;
import com.badlogic.gdx.maps.tiled.TiledMapTileLayer.Cell;
import com.badlogic.gdx.InputProcessor;
import com.badlogic.gdx.Input.Keys;


public class Megaman extends Sprite implements InputProcessor
{
/**the movement velocity*/
private Vector2 velocity = new Vector2();

private float speed = 60 * 1.375f;

private float gravity = 60 * .25f;
private boolean canJump;

private TiledMapTileLayer collisionLayer;

public Megaman(Sprite sprite, TiledMapTileLayer collisionLayer)
{
    super(sprite);
    this.collisionLayer = collisionLayer;

}

@Override
public void draw(Batch spriteBatch)
{
    update(Gdx.graphics.getDeltaTime());
    super.draw(spriteBatch);
}

public void update(float delta)
{
    // apply gravity
            velocity.y -= gravity * delta;

            // clamp velocity
            if(velocity.y > speed)
                velocity.y = speed;
            else if(velocity.y < -7.0f)
                velocity.y = -7.0f;

            // save old position
            float oldX = getX(), oldY = getY();
            boolean collisionX = false, collisionY = false;

            // move on x
            setX(getX() + velocity.x * delta);

            if(velocity.x < 0) // going left
                collisionX = collidesLeft();
            else if(velocity.x > 0) // going right
                collisionX = collidesRight();

            // react to x collision
            if(collisionX) {
                setX(oldX);
                velocity.x = 0;
            }

            // move on y
            setY(getY() + velocity.y * delta * 5f);

            if(velocity.y < 0) // going down
                canJump = collisionY = collidesBottom();
            else if(velocity.y > 0) // going up
                collisionY = collidesTop();

            // react to y collision
            if(collisionY) {
                setY(oldY);
                velocity.y = 0;
            }
}

public Vector2 getVelocity() {
    return velocity;
}

public void setVelocity(Vector2 velocity) {
    this.velocity = velocity;
}

public float getSpeed() {
    return speed;
}

public void setSpeed(float speed) {
    this.speed = speed;
}

public float getGravity() {
    return gravity;
}

public void setGravity(float gravity) {
    this.gravity = gravity;
}

public TiledMapTileLayer getCollisionLayer() {
    return collisionLayer;
}

public void setCollisionLayer(TiledMapTileLayer collisionLayer) {
    this.collisionLayer = collisionLayer;
}

@Override
public boolean keyDown(int keycode) {
    switch (keycode)
    {
    case Keys.W:
        if(canJump) {
            velocity.y = 60 * 4.75f;
            canJump = false;
        }
        break;
    case Keys.A:
        velocity.x = -speed;
        break;
    case Keys.D:
        velocity.x = speed;
        break;
    }
    return true;
}

@Override
public boolean keyUp(int keycode) {
    switch (keycode)
    {
    case Keys.W:
        velocity.y = 0;
        break;
    case Keys.A:
    case Keys.D:
        velocity.x = 0;
        break;
    }
    return true;
}

@Override
public boolean keyTyped(char character) {
    return false;
}

@Override
public boolean touchDown(int screenX, int screenY, int pointer, int button) {

    return false;
}

@Override
public boolean touchUp(int screenX, int screenY, int pointer, int button) {
    return false;
}

@Override
public boolean touchDragged(int screenX, int screenY, int pointer) {
    return false;
}

@Override
public boolean mouseMoved(int screenX, int screenY) {
    return false;
}

@Override
public boolean scrolled(int amount) {
    return false;
}

private boolean isCellBlocked(float x, float y) {
    Cell cell = collisionLayer.getCell((int) (x / collisionLayer.getTileWidth()), (int) (y / collisionLayer.getTileHeight()));
    return cell != null && cell.getTile() != null && cell.getTile().getProperties().containsKey("blocked");
}

public boolean collidesRight() {
    for(float step = 0; step < getHeight(); step += collisionLayer.getTileHeight() / 2)
        if(isCellBlocked(getX() + getWidth(), getY() + step))
            return true;
    return false;
}

public boolean collidesLeft() {
    for(float step = 0; step < getHeight(); step += collisionLayer.getTileHeight() / 2)
        if(isCellBlocked(getX(), getY() + step))
            return true;
    return false;
}

public boolean collidesTop() {
    for(float step = 0; step < getWidth(); step += collisionLayer.getTileWidth() / 2)
        if(isCellBlocked(getX() + step, getY() + getHeight()))
            return true;
    return false;

}

public boolean collidesBottom() {
    for(float step = 0; step < getWidth(); step += collisionLayer.getTileWidth() / 2)
        if(isCellBlocked(getX() + step, getY()))
            return true;
    return false;
}


}

TestMap class:

package com.mygdx.game;

import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.Screen;
import com.badlogic.gdx.graphics.GL20;
import com.badlogic.gdx.graphics.OrthographicCamera;
import com.badlogic.gdx.graphics.g2d.Sprite;
import com.badlogic.gdx.graphics.Texture;
import com.badlogic.gdx.maps.tiled.TiledMap;
import com.badlogic.gdx.maps.tiled.TmxMapLoader;
import com.badlogic.gdx.maps.tiled.renderers.OrthogonalTiledMapRenderer;
import com.badlogic.gdx.maps.tiled.TiledMapTileLayer;

public class TestMap implements Screen
{
private TiledMap map;
private OrthogonalTiledMapRenderer renderer;
private OrthographicCamera camera;

private Megaman megaman;    


@Override
public void render(float delta)
{
    float dt = Math.min(Gdx.graphics.getDeltaTime(), 1 / 60f);
    Gdx.gl.glClearColor(0, 0, 0, 1);
    Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);

    renderer.setView(camera);
    renderer.render();
    renderer.getBatch().begin();
    megaman.update(dt);
    megaman.draw(renderer.getBatch());
    renderer.getBatch().end();
}

@Override
public void resize(int width, int height)
{
    camera.viewportWidth = width;
    camera.viewportHeight = height;
    camera.setToOrtho(false, width, height);
    camera.update();
}

@Override
public void show()
{
    map = new TmxMapLoader().load("maps/test2.tmx");

    renderer = new OrthogonalTiledMapRenderer(map);

    camera = new OrthographicCamera();
    megaman = new Megaman(new Sprite(new Texture("img/Megaman/megaman_idle.png")), (TiledMapTileLayer) map.getLayers().get(0));
    megaman.setPosition(14 * megaman.getCollisionLayer().getTileWidth() , (megaman.getCollisionLayer().getHeight() -  22) * megaman.getCollisionLayer().getTileHeight());

    Gdx.input.setInputProcessor(megaman);

}

@Override
public void hide()
{
    dispose();
}

@Override
public void pause()
{

}
@Override
public void resume()
{

}

@Override
public void dispose()
{
    map.dispose();
    renderer.dispose();
    megaman.getTexture().dispose();
}
}
\$\endgroup\$
0
\$\begingroup\$

The problem with your code is here:

@Override
public boolean keyUp(int keycode) {
switch (keycode)
{
case Keys.W:
    //when W is released, set Y velocity to 0
    velocity.y = 0;
    break;
case Keys.A:
case Keys.D:
    velocity.x = 0;
    break;
}
return true;
}

While canJump is a boolean that checks if the character has jumped, I assume you want the megaman style of jumping, so that as soon as you let go of the button, you start falling, but we need to track if the user has let go of the button this jump, like this:

@Override
public boolean keyUp(int keycode) {
switch (keycode)
{
case Keys.W:
    if (released == true)
    {
        //when W is released, set Y velocity to 0
        velocity.y = 0;
        released = false;
        break;
    }
case Keys.A:
case Keys.D:
    velocity.x = 0;
    break;
}
return true;
}

if(velocity.y < 0){ // going down
    canJump = collisionY = collidesBottom();
    released = collidesBottom();
}
\$\endgroup\$
2
  • \$\begingroup\$ That is what the "canJump" variable is for? You can only jump if canJump is set to true. When 'w' is hit it sets canJump to false and isn't reset to true until Megaman hits a solid surface under him It isn't a matter of jumping again mid-jump. Just that if you hit 'w' midjump the fall slows \$\endgroup\$
    – John Vanek
    Feb 13 '16 at 4:33
  • \$\begingroup\$ I expanded upon my answer, does that explain it a better? \$\endgroup\$
    – ChrisUC
    Feb 13 '16 at 12:51

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.