Libgdx Box2d Jumping through - libgdx

I want to make a jump like in the Mario game. When you are under the platform and you jump, you can then pass through the collider.
When a player's velocity is going down, colliders should wake up. I know that I should use ContactListener, but when I'm using the contact.setEnable(false) method nothing happens.
My contact listener (ground checker works perfectly)
world.setContactListener(new ContactListener() {
#Override
public void beginContact(Contact contact) {
if(contact.getFixtureA().getBody().getUserData() == "ground" && contact.getFixtureB().getUserData() == "groundChecker"){
character.isGrounded = true;
System.out.println(" Colliding");
}
}
#Override
public void endContact(Contact contact) {
}
#Override
public void preSolve(Contact contact, Manifold oldManifold) {
}
#Override
public void postSolve(Contact contact, ContactImpulse impulse) {
}
});
What and where should I put to get effect like this.
enter image description here
enter image description here
Collider should have only one side, have somebody deal with it?

Found a solution I hope it will be helpfull.
world.setContactListener(new ContactListener() {
#Override
public void beginContact(Contact contact) {
//setting isGrounded boolean variable in our character class, but we need to check "player" velocity, because we don't want to enable jumping when only ground will passed througt
if(contact.getFixtureA().getBody().getUserData() == "ground" && contact.getFixtureB().getUserData() == "groundChecker" && (contact.getFixtureB().getBody().getLinearVelocity().y < 0 || contact.getFixtureB().getBody().getLinearVelocity().y == 0)){
character.isGrounded = true;
}
}
#Override
public void endContact(Contact contact) {
}
#Override
public void preSolve(Contact contact, Manifold oldManifold) {
//we have to disable contact when our "player" fixture collide with "ground" fixture
if(contact.getFixtureA().getBody().getUserData() == "ground" && contact.getFixtureB().getUserData() == "player"){
contact.setEnabled(false);
}
//and we need to disable contact when our "groundChecker" will collide with "ground" and we need to check what velocity.y of player body is, when it is bigger than 0 contact should be falsed
if(contact.getFixtureA().getBody().getUserData() == "ground" && contact.getFixtureB().getUserData() == "groundChecker" && contact.getFixtureB().getBody().getLinearVelocity().y > 0){
contact.setEnabled(false);
}
}
#Override
public void postSolve(Contact contact, ContactImpulse impulse) {
}
});
We have to disable contact when our "player" fixture collide with "ground" fixture.
Like this.
if(contact.getFixtureA().getBody().getUserData() == "ground" && contact.getFixtureB().getUserData() == "player"){
contact.setEnabled(false);
}
And we need to disable contact when our "groundChecker" will collide with "ground" and we need to check what velocity.y of player body is, when it is bigger than 0, contact should be falsed.
if(contact.getFixtureA().getBody().getUserData() == "ground" && contact.getFixtureB().getUserData() == "groundChecker" && contact.getFixtureB().getBody().getLinearVelocity().y > 0){
contact.setEnabled(false);
}
Here is a demo of the above solution:

Related

libGDX contact script not working

This contact script is not being called when any 2 bodies come into contact with each other. I have tried simply calling the method whenever any object bodies come into contact but that does not work either.
world.setContactListener(new ContactListener() {
#Override
public void beginContact(Contact contact) {
Fixture f1 = contact.getFixtureA();
Fixture f2 = contact.getFixtureB();
Body b1 = f1.getBody();
Body b2 = f2.getBody();
if((b1.getUserData() == "player" && b2.getUserData() == "Enemy") || (b1.getUserData() == "player" && b2.getUserData() == "Enemy")) {
player.death();
hud.death();
}
}
#Override
public void endContact(Contact contact) {
}
#Override
public void preSolve(Contact contact, Manifold oldManifold) {
}
#Override
public void postSolve(Contact contact, ContactImpulse impulse) {
}
});
Make sure that the player and enemy bodies are defined as Dynamic Body.
Check your collision filtering.
Check if the body is active.
Also check if you properly set the userdata of each body.

Libgdx, how to catch back key, when stage is the input Processor

I have a class called AbstractGameScreen with the following signature:
public abstract class AbstractGameScreen extends InputAdapter implements Screen { ... }
All my screens extend this abstract class. Now the problem i am encountering is that in screens that use stages i already set the stage to be the inputprocessor. But if i do so, the keyUp method doesn't execute on back-key being pressed anymore. if i set the screen to be inputprocessor instead, the stage doesn't work. how do i work around this problem?
public class MenuScreen extends AbstractGameScreen {
#Override
public void show() {
stage = new Stage(new StretchViewport(Constants.VIEWPORT_GUI_WIDTH, Constants.VIEWPORT_GUI_HEIGHT));
Gdx.input.setInputProcessor(stage);
Gdx.input.setCatchBackKey(true);
instructionsVisible= false;
rebuildStage();
}
#Override
public boolean keyUp (int keycode) {
// Back to Menu
if (keycode == Input.Keys.ESCAPE || (keycode == Input.Keys.BACK && instructionsVisible)) {
instructionsVisible=false;
layerInstruction.setVisible(false);
layerControls.setVisible(true);
}
else
{
Gdx.app.exit();
}
return false;
}
In this case you need two InputProcessors- the Stage and your AbstractScreen. The way you do this is create a new InputMultiplexer object and configure it something like this:
InputMultiplexer multiplexer = new InputMultiplexer();
multiplexer.addProcessor( stage );
multiplexer.addProcessor( this ); // Your screen
Gdx.input.setInputProcessor( multiplexer );

Removing all rectangles in rectangle array(LIBGDX)

Hi guys so I created a simple game with a flying helicopter in which you need to dodge the missiles. I want to remove all missiles that are created in the screen if gameOver boolean is true. What is happening is it's only removed if the helicopter dies because of hitting the missile, but if it dies by hitting the ground the "game over" message shows but the missiles are not removed!
I tried using
if(heliR.overlaps(missiles)){gameOver=true; Iter.remove; }
But like what I said all missiles are only removed if I died by hitting missile, can anyone help me in this?
Here is my code:
#Override
public void create()
{
batch = new SpriteBatch();
camera=new OrthographicCamera();
camera.setToOrtho(false,800,480);
restart=TimeUtils.nanoTime();
click=TimeUtils.nanoTime();
//fonts
font=new BitmapFont();
font1=new BitmapFont();
font2=new BitmapFont();
font.setColor(Color.RED);
font1.setColor(Color.BLACK);
font2.setColor(Color.WHITE);
font.setScale(3);
font1.setScale(1);
font2.setScale(2);
//score
points=0;
lastScore=TimeUtils.nanoTime();
//background
Texture texture=new Texture(Gdx.files.internal("background.png"));
background=new TextureRegion(texture,0,0,800,480);
//logo
logo=new Texture(Gdx.files.internal("logo.png"));
logoR=new Rectangle();
logoR.x=230;
logoR.y=240;
logoR.width=230;
logoR.height=100;
//helicopter
heli=new Texture(Gdx.files.internal("helicopter.png"));
heliR=new Rectangle();
heliR.x=280;
heliR.y=400;
heliR.width=heli.getWidth()-15;
heliR.height=heli.getHeight()-15;
//Sounds
heliSound=Gdx.audio.newSound(Gdx.files.internal("helicopter.wav"));
heliLanding=Gdx.audio.newSound(Gdx.files.internal("helicopter_landing.wav"));
collision=Gdx.audio.newSound(Gdx.files.internal("collision.wav"));
//missile
missileImg=new Texture(Gdx.files.internal("missile.png"));
missiles=new Array<Rectangle>();
}
public void spawnMissile(){
Rectangle missile=new Rectangle();
missile.y=MathUtils.random(60,400);
missile.x=mX;
missile.width=missileImg.getWidth()-15;
missile.height=missileImg.getHeight()-10;
missiles.add(missile);
lastMissile=TimeUtils.nanoTime();
velocity=250;
}
#Override
public void render()
{
Gdx.gl.glClearColor(1, 1, 1, 1);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
camera.update();
batch.begin();
batch.draw(background,backGroundX-800,0,800,480);
batch.draw(background,backGroundX,0,800,480);
batch.draw(heli,heliR.x,heliR.y);
if(justStart==false && gameOver==false){
font2.draw(batch,"Points:"+points,345,480);}
//missile
for(Rectangle missile: missiles){
batch.draw(missileImg,missile.x,missile.y);
}
//game over
if(gameOver==true){
heliR.y=250;
heliR.x=330;
font.draw(batch,"Game Over",280,400);
font1.draw(batch,"[Long press on the screen to restart]",275,230);
font1.draw(batch,"Your points:"+points,348,250);
if(Gdx.input.isTouched()){
longClick+=1;
if(longClick==35){
gameOver=false;
points=0;
longClick=0;
heliR.y=300;
heliR.x=30;
}
}else{
if(TimeUtils.nanoTime()- click > 2000000){longClick=0;}
}
}
//starting game
if(justStart==true){
heliR.y=250;
heliR.x=330;
font2.draw(batch,"Touch the screen to start",230,230);
batch.draw(logo,logoR.x,logoR.y);
font1.draw(batch,"Developed by:Monzterr",5,15);
if(Gdx.input.isTouched()){
justStart=false;
heliR.y=300;
heliR.x=30;
}
}
batch.end();
//game physics
if(justStart==false&&gameOver==false){
//missile
if(TimeUtils.nanoTime()-lastMissile > 1000000000){spawnMissile();}
Iterator <Rectangle> iter=missiles.iterator();
while(iter.hasNext()){
Rectangle missile= iter.next();
missile.x-=velocity*Gdx.graphics.getDeltaTime();
if(missile.x<=-10){iter.remove();}
if(missile.overlaps(heliR)){
gameOver=true;
collision.play();
}
if(gameOver==true){
iter.remove();
}
}
//background
backGroundX= backGroundX-100*Gdx.graphics.getDeltaTime();
if(backGroundX<=0){
backGroundX=800;
}
//score
if(TimeUtils.nanoTime()-lastScore>2000000000){
points=points+1;
lastScore=TimeUtils.nanoTime();
}
//gravity
if(Gdx.input.isTouched()){
heliR.y+=5;
//heliLanding.play();
}else{
heliR.y-=5;
//heliLanding.pause();
}
}
//borders
if(heliR.y>=400){
heliR.y=250;
}
if(heliR.y<=56){
heliR.y=56;
gameOver=true;
mX=800;
collision.play();
}
}
#Override
public void dispose()
{
}
#Override
public void resize(int width, int height)
{
}
#Override
public void pause()
{
}
#Override
public void resume()
{
}
Sorry for messy code I just started learning programming last week.
You are checking if gameOver == true twice - one on the (almost) beginning of the render() method
//game over
if(gameOver==true){
heliR.y=250;
...
and second time under following condition
//game physics
if(justStart==false&&gameOver==false){
...
but you are removing iterator only in the second one
if(gameOver==true){
iter.remove();
}
fixing it should fix your problem. Consider also do you need two checks if gameOver is true (I believe you not - you can handle both situations in the first one)
You are changing gameOver to true in the middle of looping through all your enemies, and only removing them from within the loop, so only the enemies after the one that caused the game over will be removed. Replace iter.remove() with break (to jump out of the loop which is now unnecessary to finish). And then add a line after the loop:
if (gameOver) missiles.clear();
This removes everything from the array.

How do I create a keyboard shortcut (like Ctrl+C) in a Windows Store app

I want to create keyboard shortcuts in my application, for instance Ctrl+C for copy. Also I want to ignore that shortcut if a TextBox has focus.
First you need a way to check if control key is pressed. CoreWindow.GetKeyState will do the job but might be a little bit tricky to use so I created an helper class:
public class ModifierKeys
{
#region ShiftIsDown property
public static bool ShiftIsDown
{
get
{
return (Window.Current.CoreWindow.GetKeyState(VirtualKey.Shift) & CoreVirtualKeyStates.Down) != 0;
}
}
public static bool OnlyShiftIsDown
{
get
{
return ShiftIsDown && !AltIsDown && !ControlIsDown;
}
}
#endregion
#region AltIsDown property
public static bool AltIsDown
{
get
{
return (Window.Current.CoreWindow.GetKeyState(VirtualKey.Menu) & CoreVirtualKeyStates.Down) != 0;
}
}
public static bool OnlyAltIsDown
{
get
{
return !ShiftIsDown && AltIsDown && !ControlIsDown;
}
}
#endregion
#region ControlIsDown property
public static bool ControlIsDown
{
get
{
return (Window.Current.CoreWindow.GetKeyState(VirtualKey.Control) & CoreVirtualKeyStates.Down) != 0;
}
}
public static bool OnlyControlIsDown
{
get
{
return !ShiftIsDown && !AltIsDown && ControlIsDown;
}
}
#endregion
#region NoModifierKeyIsDown property
public static bool NoModifierKeyIsDown
{
get
{
return !ShiftIsDown && !AltIsDown && !ControlIsDown;
}
}
#endregion
}
Now in OnNavigateTo/From in your page subscribe/unsubscribe on key down events:
protected override void OnNavigatedTo(NavigationEventArgs e)
{
/*...*/
Window.Current.CoreWindow.KeyDown += CoreWindow_KeyDown;
}
protected override void OnNavigatedFrom(NavigationEventArgs e)
{
/*...*/
Window.Current.CoreWindow.KeyDown -= CoreWindow_KeyDown;
}
The CoreWindow_KeyDown will then looks something like this:
void CoreWindow_KeyDown(CoreWindow sender, KeyEventArgs args)
{
var focusedElement = FocusManager.GetFocusedElement();
if (args.KeyStatus.WasKeyDown == false && ModifierKeys.OnlyControlIsDown &&
!(focusedElement is TextBox)
)
{
if (args.VirtualKey == VirtualKey.X)
{
/*...cut...*/
}
else if (args.VirtualKey == VirtualKey.V)
{
/*...paste...*/
}
else if (args.VirtualKey == VirtualKey.C)
{
/*...copy...*/
}
}
}

CCScrollView with CCControlButton. How to control the touch area?

I have CCScrollView with container with CCControlButtons, when the buttons scroll out of the visible CCScrollView area, They are also can be touched too. How can I control the area ?
Inspired by Tomasz's answer, I created an alternative solution, also inheriting from CCControlButton:
bool ScrollableButton::isTouchInside(CCTouch *touch) {
return !dragging && CCControlButton::isTouchInside(touch);
}
bool ScrollableButton::ccTouchBegan(CCTouch *touch, CCEvent *event) {
dragging = false;
return CCControlButton::ccTouchBegan(touch, event);
}
void ScrollableButton::ccTouchMoved(CCTouch *touch, CCEvent *event) {
if (!dragging && ccpDistance(touch->getLocation(), touch->getStartLocation()) > 25) {
dragging = true;
}
CCControlButton::ccTouchMoved(touch, event);
}
void ScrollableButton::ccTouchEnded(CCTouch *touch, CCEvent *event) {
CCControlButton::ccTouchEnded(touch, event);
dragging = false;
}
void ScrollableButton::ccTouchCancelled(CCTouch *touch, CCEvent *event) {
CCControlButton::ccTouchCancelled(touch, event);
dragging = false;
}
The secret sauce is the override of the isTouchInside function, which will return false even if the touch is inside, but was moved. This way, the button will also release its "zoomed" state as soon as you start scrolling.
It also adds a small tolerance factor, so if the touch moves just a little, it's still considered a "click". This factor is hardcoded at 25 in the example above.
My problems:
There is a scrollView with many buttons (items). Above it there are 2 function buttons (return, start).
When I scroll down item buttons overlie function buttons. When I swallow all touches above my scrollview I will lose my function buttons. So I have to find another solution.
When I start draging scroll view a item button is pressed. When I ended the button action will be execute. This is very annoying.
But there is the solution. I have created new CCControlButton. It checks whether was clicked outside scrollview or was dragged. The button is used for items buttons.
bool ControlButtonForScrolling::checkIfTouchIsInsideScrollView(CCTouch *pTouch)
{
CCPoint touchLocation = pTouch->getLocation(); // Get the touch position
touchLocation = _scrollView->getParent()->convertToNodeSpace(touchLocation);
CCRect bBox=_scrollView->boundingBox();
bool result = bBox.containsPoint(touchLocation);
return result;
}
bool ControlButtonForScrolling::ccTouchBegan(CCTouch *pTouch, CCEvent *pEvent)
{
bool isInside = this->checkIfTouchIsInsideScrollView(pTouch);
if (isInside) {
return CCControlButton::ccTouchBegan(pTouch, pEvent);
}
else
{
return false;
}
}
void ControlButtonForScrolling::ccTouchMoved(CCTouch *pTouch, CCEvent *pEvent)
{
CCControlButton::ccTouchMoved(pTouch, pEvent);
_scrollWasDragged = true; // information about dragging is stored to prevent sending action
}
void ControlButtonForScrolling::ccTouchEnded(CCTouch *pTouch, CCEvent *pEvent)
{
// this method is a copy of CCControlButton::ccTouchEnded except lines with _scrollWasDragged
m_eState = CCControlStateNormal;
m_isPushed = false;
setHighlighted(false);
if (!_scrollWasDragged)
{
if (isTouchInside(pTouch))
{
sendActionsForControlEvents(CCControlEventTouchUpInside);
}
else
{
sendActionsForControlEvents(CCControlEventTouchUpOutside);
}
}
_scrollWasDragged = false;
}