LIBGDX collision with bottom part of box only - java

Im trying to get my collision using box2D in jumping game work correct but i have some problems. The player have Box Shape and Platform is just a line made with chainShape.
First problem is that i would like to enable collision only when Player touch Platform with bottom line of it's box. I tried to do that by checking the y coordinates of body but it doesnt worked becouse the diffrence beetween platform and bottom part of box while collision was about 0.5 units.
Second problem is that at the moment the collision is turning on two or three times for same platform in single touch. Here i don't have idea how i can fix it.
Actual code for collision in my code is:
#Override
public boolean shouldCollide(Fixture fixtureA, Fixture fixtureB) {
if(fixtureA == fixture || fixtureB == fixture){
return body.getLinearVelocity().y< 0; //&& (fixtureA.getBody().getPosition().y <= fixtureB.getBody().getPosition().y);
}
return false;
}
#Override
public void preSolve(Contact contact, Manifold oldManifold) {
if(contact.getFixtureA() == fixture || contact.getFixtureB() == fixture){
//System.out.println("Contact A: "+ contact.getFixtureA().getBody().getPosition().y);
//System.out.println("Contact B: "+ contact.getFixtureB().getBody().getPosition().y);
if(contact.getFixtureA().getBody().getPosition().y == contact.getFixtureB().getBody().getPosition().y)
contact.setEnabled(true);
else
contact.setEnabled(false);
}
}
//COLLISION CALCULATION
#Override
public void postSolve(Contact contact, ContactImpulse impulse) {
body.applyLinearImpulse(0, jumpPower, body.getWorldCenter().x, body.getWorldCenter().y, true);
}
Thanks in advance.

Related

Issue with EntityPlayer.posX "flickering" between values

So basically I'm trying to create a coords display mod. When accessing the player's position with posX/Y/Z (this example uses X) there is a weird "flickering" with the displayed coordinate. You can see it in this video.
#SubscribeEvent
public void playerTick(PlayerTickEvent event) {
EntityPlayer player = event.player;
posX = player.posX;
System.out.println(posX); // Used to debug, also had the issue, meaning it isn't an issue with round()
}
#SubscribeEvent
public void renderOverlay(RenderGameOverlayEvent event) {
if (event.type == RenderGameOverlayEvent.ElementType.TEXT) {
drawString(renderer, String.valueOf(round(posX, 8)), 0, 0, -1);
}
}
I think this might have something to do with me using playerTick or something, but I'm new to forge and Java and don't know what I might use instead (assuming that is the problem).
It was an issue with me using PlayerTickEvent instead of ClientTickEvent.
public void clientTick(ClientTickEvent event) {
EntityPlayerSP player = mc.thePlayer;
if (player == null) return;
posX = player.posX
}
if (player == null) return; is required because when not in game, mc.thePlayer returns null so .posX causes a crash.

How to activate a function within an loop to continue after exiting loop

i'm sure I can figure this out on my own but I feel like the way i'm writing it is already too expensive and coupled.
I am writing a simulator with a security robot and a intruder, I have a collision function, where in the 3rd if statement it checks if an intruder (rectangle of width 11) collides with an surveillance camera (arc) and if that happens then I want to activate my function for the security robot to chase the intruder.
<-- Important note: the checkShapeIntersection function is inside a timeLine event so its running constantly -->
private boolean checkShapeIntersection(Shape block) {
//Name to check for intruder and surveillance collision
String Surveillance = "Arc";
boolean collisionDetected = false;
for (Shape static_bloc : nodes) {
if (static_bloc != block) {
Shape intersect = Shape.intersect(block, static_bloc);
if (intersect.getBoundsInLocal().getWidth() != -1) {
collisionDetected = true;
//Checks of intruder collides with an arc (surveillance), the 11th width is only for intruder rectangles
if ( Surveillance.equals(block.getClass().getSimpleName()) && static_bloc.getBoundsInLocal().getWidth() == 11) {
//Activate Chase function
testRobot.chaseIntruder(static_bloc);
detected = true;
}
}
}
}
if (collisionDetected) {
block.setFill(Color.BLUE);
} else {
block.setFill(Color.RED);
}
return detected;
}
And inside my Security Robot Class
public void chaseIntruder(Shape intruder) {
destinationsList.add(new Vector2D(intruder.getLayoutBounds().getMinX(),intruder.getLayoutBounds().getMinY()));
this.updatePosition();
}
You probably want to use multi-threading here, in Java you can implement Runnable or Thread to achieve wanted functionality.
Here are some links with more info:
In a simple to understand explanation, what is Runnable in Java?
https://docs.oracle.com/javase/7/docs/api/java/lang/Runnable.html
https://docs.oracle.com/javase/7/docs/api/java/lang/Thread.html
https://docs.oracle.com/javase/tutorial/essential/concurrency/runthread.html
Hope it helps.

How to make one way platform on which i can come down if button pressed

So, what i want:
If my player's body linear velocity.y > 0 then move through platform.
If my player's body colliding with platform and button "DOWN" pressed, move down through it
What i've tried:
switch (fixA.getFilterData().categoryBits | fixB.getFilterData().categoryBits) {
case Game.PLATFORM_BIT | Game.PLAYER_BIT:
if (playerBody == contactEntityA.getBody()) {
if (playerBody.getBody().getPosition().y <
contactEntityB.getBody().getPosition().y + .5 || playerController.isDownPressed()) { // .5 is half height of platform body
contact.isEnabled = false;
}
} else {
if (playerBody.getBody().getPosition().y <
contactEntityA.getBody().getPosition().y + .5 || playerController.isDownPressed()) { // .5 is half height of platform body
contact.isEnabled = false;
}
}
break;
}
My problem is:
Box2d doesn't make contacts if body doesn't move for a few seconds. So after some time, contact doesn't occur and i can't move down.
Try sensors in box 2D so that it will not collide with any object and surely it will accept events.
when you need physical aspects then it is better to use box2D
You could try something like this:
object DisableContact: ContactListener {
override fun beginContact(contact: Contact) {
}
override fun endContact(contact: Contact) {
}
override fun preSolve(contact: Contact, oldManifold: Manifold?) {
val playerBody = contact.fixtureA.body!! // need to identify if fixtureA or fixtureB is the player body
if (playerBody.linearVelocity.y < -3.5f) {
contact.isEnabled = false
}
}
override fun postSolve(contact: Contact, impulse: ContactImpulse?) {
}
}
Simple hack helped me. I'm just applying little velocity to a body each frame.
playerBody.applyLinearImpulse(0f, .000001f, .5f, .5f, true);
I'm not sure that is the best solution, write me please if you know how to do better.

Prevent bat from moving out of bounds in breakout game?

I'm working on a breakout game for an assignment and for part 2 of it I need to include code that stops the bat from being moved out of the boundaries. I'm pretty sure that I need to use an if statements but I don't know what exactly I should put inside the brackets for else (something that will enable the bat to move). I
This is the code in particular I'm talking about.
if (dist < 0)
{
}
else
{} // move
if ((dist + 150)> 600)
{
}
else
{} // move
(Part 2 is in the ModelBreakout class).
There are lots of classes and just so many different parts of the code that are to do with the movement of the bat and I don't know what to use for this part, I would appreciate a hint of what I need to do!
Edit: I removed all of the classes because people were complaining. If you would like to view the classes go to this page and scroll down to the title Mini project: The BreakOut game.
Thanks for any help. I'm not looking for anyone to do my work for me, I would just like some guidance, I've worked out that I need to do an if statement, I'm just not sure of what I need to put inside it.
TL;DR.
I recently created a similar game. Here's how I implemented it.
Racket Class
protected static final float MIN_X = 10;
protected static final float MAX_X = 590;
public void moveLeft()
{
if (x > MIN_X)
{
x -= 5;
}
}
public void moveRight()
{
if (x < MAX_X)
{
x += 5;
}
}
Player extends Racket
public void process(int key)
{
if (key == KeyEvent.VK_KP_LEFT || key == KeyEvent.VK_LEFT)
{
moveLeft();
}
else if (key == KeyEvent.VK_KP_RIGHT || key == KeyEvent.VK_RIGHT)
{
moveRight();
}
}
Edit: This is not the complete classes. It's just some items lifted from them. There's a key listener added to the game which passes the key to Player.process().
Edit 2: Updated my code. Your width is set to 600 so the boundaries can be 10 and 590. This should work for you
Looking at the classes there are built in methods for each object on the screen, so you could do something like this:
If( Bat.GetX() < 0 ) {
Bat.moveX( *INSERT THE X HERE* )
}
And you also could do a the same thing for the max width. Also if you do a simple fix like this make sure to change the refresh rate of the screen, otherwise you will see the bat Jumping to the new position.

State Management - [Switching States, Replaying the Game]

How to effectively switch states?Whenever I press the replay button, the two states shows alternatively (win & play). I believe that was an infinite loop but Eclipse does not print any errors.
When I tried this, it results to null.Thus, ending the game.
Could this be the answer? But I don't understand his Update(). What to put exactly there?will that overwrite the update of the state class?
Here is my code:
stateID(2) is the Wins.java
PlayGround.java
public static boolean bouncy = true;
public void update(GameContainer gc, StateBasedGame sbg, int delta) throws SlickException{
//if the user is successful, show winner state
if(!bouncy){
sbg.enterState(2);
}
//moves the image randomly in the screen
new Timer(10,new ActionListener(){
public void actionPerformed(ActionEvent e)
{
posX = (r.nextInt(TestProject4.appGC.getWidth()-75));
posY = (r.nextInt(TestProject4.appGC.getHeight()-75));
}
}).start();
}
public void mousePressed(int button,int x,int y){
//if the user pressed the mouse button And
//if the user's coordinates is inside the hit area(rect)
if((button == 0) && (rect.contains(x, y))){
Toolkit.getDefaultToolkit().beep();
bouncy = false;
}
}
Wins.java
#Override
public void update(GameContainer gc, StateBasedGame sbg, int delta)throws SlickException {
//replay game
if(backToGame == true){
sbg.enterState(state);
}
}
public void mousePressed(int button,int x,int y){
//if the user clicks the replay button
if(button == 0){
if((x>160 && x<260)&&(y>280 && y<320)){
if(Mouse.isButtonDown(0)){
backToGame = true;
state = 1;
}
}
//exit button
if((x>=360 && x<460)&&(y>280 && y<320)){
if(Mouse.isButtonDown(0)){
System.exit(0);
}
}
}
}
I think you switch between both states again and again because both GameState objects are still in the same "state" (variables have still the same values) when you switch back.
Try:
if(!bouncy){
bouncy = true; // next time we are in this game state it will not trigger immediately
sbg.enterState(2);
}
if(backToGame == true){
backToGame = false; // same here
sbg.enterState(state);
}
Previous answer:
Please check your if statement:
if((x>160 && x<180)||(y>280 && y<320)){
You are checking whether the mouse is between some x coordinates OR some y coordinates.
I think you want to check whether the mouse is between some x AND some y coordinates:
if((x>160 && x<180)&&(y>280 && y<320)){
Your code has two methods mousePressed() one in PlayGround.java and the other in Wins.java.
The application is clearly using the Playground.java Code.
Adding the button detection code into the PlayGround.java may solve the problem.
Other wise explicitly calling the mousePressed() method in Wins from PlayGround.java
may work as well.
Adding comments help.
It can show your train of thought for a project, Helps others to try and see what you are doing.
In fleshing out a complex method I comment excessively at first, weeding out obvious comments through iterations of debugging and code review.
I also helps when others are viewing your code.
Remember There are no stupid comments, only stupid people.

Categories

Resources