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.
Related
I'm developing an application in Java to help me land my first job as a junior developer. It's a chess game with a GUI that both human players click on from the same machine.
When it's, say, white's turn to move, the application calls white's getMove(Interface interaction) method until a valid MoveAttempt is returned. Here's the getMove(Interface interaction) method of HumanPlayer:
public MoveAttempt getMove(Interface interaction) {
while(!interaction.selectionMade()) {
}
byte pieceFile = interaction.getPenultimateFile();
byte pieceRank = interaction.getPenultimateRank();
byte toFile = interaction.getUltimateFile();
byte toRank = interaction.getUltimateRank();
return new MoveAttempt(pieceFile, pieceRank, toFile, toRank, getIsWhite());
}
penultimateFile, penultimateRank, ultimateFile and ultimateRank are supposed to store the file (column) and rank (row) of the last two chess tiles clicked. This is achieved through this actionPerformed(ActionEvent event) which Interface has because it implements ActionListener
public void actionPerformed(ActionEvent event) {
LocalizedButton button = (LocalizedButton) event.getSource();
if(penultimateFile == -1) {
penultimateFile = button.getFile();
penultimateRank = button.getRank();
}
else {
ultimateFile = button.getFile();
ultimateRank = button.getRank();
}
}
and by calling this method before each call to getMove(Interface interaction)
public void resetClicks() {
penultimateFile = -1;
penultimateRank = -1;
ultimateFile = -1;
ultimateRank = -1;
}
So the idea is that a move attempt is not made until someone has clicked on two chess squares which is why I have a while loop indefinitely calling selectionMade():
public boolean selectionMade() {
return penultimateFile != -1 && penultimateRank != -1 && ultimateFile != -1 && ultimateRank != -1;
}
This didn't work---pieces didn't move---so in an attempt to see what was happening I put this print statement
System.out.println(interaction.getPenultimateFile() + ", " +
interaction.getPenultimateRank() + ", " +
interaction.getUltimateFile() + ", " +
interaction.getUltimateRank());
into the while loop to see what was going on and now it works---pieces move---except I may have encountered times in which it didn't work but I last I tried I couldn't get it to fail.
I don't want to print anything to the console; what should I do in lieu of having this while loop?
Edit: Putting boolean lol = 0 just above the loop and lol = !lol in the loop doesn't allow the code to work. Neither does calling doNothing().
Edit: Here's the source code: https://github.com/JosephBGriffith/Chess
Right now only the pawns work because I have other bugs that I need to fix. En passant works except the opponent piece doesn't get eliminated.
I would invert the control, so that the UI pushes moves to the game, rather than the game trying to pull moves from the UI.
So your game class might have:
class Game {
boolean move(int fromFile, int fromRank, int toFile, int toRank) { ... }
...
}
If the move wasn't legal (e.g. if it was the other player's turn) then move returns false and the move doesn't occur. That is, the internal state of the Game is unchanged.
And your actionPerformed method becomes:
public void actionPerformed(ActionEvent event) {
LocalizedButton button = (LocalizedButton) event.getSource();
if(penultimateFile == -1) {
penultimateFile = button.getFile();
penultimateRank = button.getRank();
}
else {
game.move(penultimateFile, penultimateRank, button.getFile(), button.getRank());
penultimateFile = -1;
}
}
You could use the return value of move to provide some feedback to the user if the move is illegal.
Something to note about this suggestion is that move is executed on the Swing event thread. In theory this is bad practice, although unless your move method is very slow it won't matter.
Read https://docs.oracle.com/javase/tutorial/uiswing/concurrency/index.html and consider whether you want to use invokeLater.
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.
Could anyone tell me why this is returning the error
'AL lib: (EE) alc_cleanup: 1 device not closed'
//mouseJoint collision callback
private QueryCallback queryCallback = new QueryCallback() {
#Override
public boolean reportFixture(Fixture fixture) {
if(fixture.getBody() == chest){
//add to remove list
bodiesToRemove.add(chest);
}
if (fixture.testPoint(tmp.x, tmp.y)){
reportFixture = fixture.getBody();
}
if (!fixture.testPoint(tmp.x, tmp.y))
return false;
//assigning bodyB to fixture
jointDef.bodyB = fixture.getBody();
jointDef.target.set(fixture.getBody().getWorldCenter());
//jointDef.target.set(tmp.x, tmp.y);// initial target point coincide with body anchor
joint = (MouseJoint) world.createJoint(jointDef);// creating the join the physics world
return false;
}
};
//main rendering loop
public void render(float delta) {
// TODO Auto-generated method stub
//code clears the screen with the given RGB colour (black)
Gdx.gl.glClearColor( 0f, 0f, 0f, 1f );
Gdx.gl.glClear( GL20.GL_COLOR_BUFFER_BIT );
stage.setCamera(camera);
stage.act(Gdx.graphics.getDeltaTime());
camera.position.x= chest.getPosition().x;
camera.update();
stage.draw();
world.step(1 / 60f, 8, 3);
renderer.render(world, camera.combined);
/////////////////////////////////////////////////////////////////
// this is the code that is causing the error when I try to delete a body
if(bodiesToRemove != null){
for(int i = 0; i <bodiesToRemove.size; i++){
Body b = bodiesToRemove.get(i);
if(b != null){
world.destroyBody(b);
b.setUserData(null);
b = null;
}
bodiesToRemove.clear();
}
}
////////////////////////////////////////////////////////////
}
////////////////////////////////////////////////////////////////////////////
I've changed this and it work's(pasted below), if anyone would like to explain the right way to do this or if this is the correct way that would be helpful.
I just added a boolean to prevent it from destroying the joint
// ////////////////// TOUCH EVENT ///////////////////////////////
//Called when a finger was lifted or a mouse button was released.
#Override
public boolean touchUp(int screenX, int screenY, int pointer, int button) {
//If no mouseJoint do nothing
System.out.println("touch" + (screenY*0.01f));
System.out.println("touch" + (screenX*0.01f));
if (joint == null)
return false;
//When user is not touching Screen destroy the
//mouseJoint/set to null
if(ran == false){
world.destroyJoint(joint);
joint = null;}
ran = false;
return true;
}
////////////////////////////////
/////////////////////////////////
if(!world.isLocked() && world.getBodyCount() > 0 ){
for(int i = 0; i <bodiesToRemove.size; i++){
Body b = bodiesToRemove.get(i);
if(b == null){
bodiesToRemove.removeIndex(i);
continue;
}
world.destroyBody(b);
ran = true;
bodiesToRemove.removeIndex(i);
}
}else{
bodiesToRemove.clear();
}
////////////////////////////////////////////////////////////
Box2D throws some odd errors, this is not one of them.
I assume you are using LibGDX, basically what is happening is a crash due to Box2D (I also assume it pops up saying "java or whatever has stopped responding"), this error you are seeing is thrown when the app exits while OpenAL is closing streams and cleaning up resources. Don't worry about that too much.
Ensure you are checking of the world is locked before destroying bodies, it usually throws an error and prints a clear message telling you this, depending on the way you are removing bodies.
if(!world.isLocked())
// do clean up code here
You don't need to clean up the variable inside local scope, or clear the userdata inside the body as the body as it will no longer exist in reference (unless you have it stored somewhere else).
So the proper code would be something like this:
if(!world.isLocked()){
for(int i = bodiesToRemove.size - 1; i--){
Body b = bodiesToRemove.get(i);
if(b == null){
bodiesToRemove.removeAt(i);
continue;
}
world.destroyBody(b);
bodiesToRemove.removeAt(i);
}
}
You are also clearing a list during iteration, not a good idea.
EDIT
The only other thing I can think of that is causing this problem is trying to delete a body that is not actually in the worlds body list.
Try the following:
// Ensure world is not locked AND that there is even bodies in the world
if(!world.isLocked() && world.getBodyCount() > 0){
for(int i = bodiesToRemove.size - 1; i--){
Body b = bodiesToRemove.get(i);
if(b == null){
bodiesToRemove.removeAt(i);
continue;
}
world.destroyBody(b);
bodiesToRemove.removeAt(i);
}
}else{
// There is no bodies in the world, so the bodies in our list are just
// random memory hogs, leave them for the GC by clearing the list
bodiesToRemove.clear();
}
EDIT
As stated by the OP, the problem lies with this block of code:
private QueryCallback queryCallback = new QueryCallback() {
#Override
public boolean reportFixture(Fixture fixture) {
if(fixture.getBody() == chest){
//add to remove list
bodiesToRemove.add(chest);
}
if (fixture.testPoint(tmp.x, tmp.y)){
reportFixture = fixture.getBody();
}
if (!fixture.testPoint(tmp.x, tmp.y))
return false;
//assigning bodyB to fixture
jointDef.bodyB = fixture.getBody();
jointDef.target.set(fixture.getBody().getWorldCenter());
//jointDef.target.set(tmp.x, tmp.y);
joint = (MouseJoint) world.createJoint(jointDef);
return false;
}
};
More specifically, this line:
joint = (MouseJoint) world.createJoint(jointDef);
The query callback is triggered during a world step. In Box2D, you can not create or destroy bodies, fixtures, and joints during the world step.
You have to create it outside this method, the simplest way to do it is via a flag. Set a flag to true and store the instance of the fixture somewhere and handle it outside in the game loop using said flag and fixture.
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.
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.