I'm using AndEngine and Box2d to make a game. Sprites/bodies are randomly generated and placed on the scene. I know I can calculate the areas and see if they overlap, but this seems taxing. Is there an easy way to detect if a sprite/body is being created inside of another? Something like:
boolean outside = false;
while(!outside){
try{
randx = random.nextInt(650) + 25;
randy = random.nextInt(400) + 25;
sprite = new Sprite(randx,randy,spriteTR,getVertexBufferObjectManager())
scene.attachChild(sprite);
outside = true;
}catch(){}
Or will a try/catch not work?
Yes, what you need to do is to create both sprites, and then do your collision detection. There is an easy way to do this and a more complex way through box2d.
The easy way:
sprite1.collidesWith(sprite2);
Which should return true if the two sprites are in contact with each other.
Through Box2d you would use something called a ContactListener to detect collision.
ContactListener contactListener = new ContactListener()
{
#Override
public void beginContact(Contact contact)
{
}
#Override
public void endContact(Contact contact)
{
}
#Override
public void preSolve(Contact contact, Manifold oldManifold)
{
}
#Override
public void postSolve(Contact contact, ContactImpulse impulse)
{
}
};
Inside beginContact, you will want to do your code for randomizing the locations of the sprites again (or whatever other algorithm you want to employ). The other methods give you additional functionality, for example you can employ endContact when the two objects stop overlapping each other.
For more information and a detailed tutorial see: http://www.andengine.org/forums/tutorials/contact-listener-t5903.html
Related
When I switch screens it lags and takes a really long time to load it on android, but on desktop launcher it does it instantly.
An example of a screen that takes a long time load is the level screen, it goes there from the main menu.
This is the code in the LevelScreen it takes a really long time load this, Is there any reason for this?
public class LevelScreen extends MenuBase {
private GameMain mGameMain;
public LevelScreen(GameMain main) {
super(main, GameInfo.LEVEL_SCREEN_NAME);
this.mGameMain = main;
main.ply.showAds(false);
}
#Override
protected Actor createActors() {
Table container = new Table();
container.setDebug(GameInfo.TABLE_DEBUG);
container.setFillParent(true);
container.setBackground(new TextureRegionDrawable(new TextureRegion(new Texture(AssetPaths.BLUE_BACKGROUND))));
Table table = new Table();
table.setBackground(new TextureRegionDrawable(new TextureRegion(new Texture(AssetPaths.BLUE_BACKGROUND))));
table.setDebug(GameInfo.TABLE_DEBUG);
final ScrollPane scroll = new ScrollPane(table, uiSkin);
table.pad(GameInfo.HUD_HEIGHT).defaults().space(10);
for (int i = 1; i < 8; i++) {
table.row();
final TextButton button = new TextButton("Level " + i, uiSkin, SkinStylePath.LIGHT_BUTTON_LONG);
table.add(button).padRight(50f);
button.addListener(new ClickListener() {
public void clicked(InputEvent event, float x, float y) {
System.out.println("click " + x + ", " + y);
}
});
System.out.println(GameManager.getInstance().scoreUnlockList(i));
System.out.println("GameManager.getInstance().mGameData.getUpToWhichLevelIsUnlocked() = " + GameManager.getInstance().mGameData.getUpToWhichLevelIsUnlocked() +
"\n GameManager.getInstance().mGameData.isLevel7Unlocked() " + GameManager.getInstance().mGameData.isLevel7Unlocked());
if (GameManager.getInstance().mGameData.getUpToWhichLevelIsUnlocked() < i) {
// for the levels we haven't unlocked write this next to it.
table.add(new Label("get over " + GameManager.getInstance().scoreUnlockList(i) + " points to unlock this level", uiSkin, SkinStylePath.ARVO_WHITE_WITH_BLACK_OUTLINE_22));
//disable all the buttons that we haven't unlocked that level for
button.setDisabled(true);
}
final int finalI = i;
button.addListener(new ChangeListener() {
#Override
public void changed(ChangeEvent event, Actor actor) {
clickSound(randomNumberGenerator()).play(GameManager.getInstance().mGameData.getSoundFxVolume());
playLevel(finalI, button);
}
});
}
scroll.setFlickScroll(true);
scroll.setFadeScrollBars(true);
scroll.setSmoothScrolling(true);
container.add(scroll).expand().fill();
container.row();
return container;
}
#Override
protected void createAnotherActor(Stage mStage) {
Texture handTexture;
handTexture = mAssetManager.get(AssetDescriptors.HAND);
Image handImage = new Image(handTexture);
handImage.setPosition(560, 100);
SequenceAction sequenceAction = new SequenceAction(GameManager.getInstance().handMoveSequence(0.3f, false), Actions.moveTo(560f, 560f, 0.8f));
handImage.addAction(sequenceAction);
if (GameManager.getInstance().mGameData.getUpToWhichLevelIsUnlocked() >= 3) {
mStage.addActor(handImage);
}
}
void playLevel(int levelNumber, TextButton levelTextButton) {
GameManager.getInstance().selectLevel(levelNumber);
mGameMain.setScreen(new NutritionQuiz(mGameMain, levelTextButton.getText().toString()));
}
#Override
public void show() {
}
}
All I can do is guess to what's slowing your game down.
The first thing I see is container.setBackground(new TextureRegionDrawable(new TextureRegion(new Texture(AssetPaths.BLUE_BACKGROUND)))); Every time you switch screens, this method is called. The thing that takes the longest in that line is probably new Texture(AssetPaths.BLUE_BACKGROUND). Doing that is much better than having static resources but it takes a long time.
One thing you could do is use a Skin. This is libgdx's way of organizing sprites, fonts, and almost anything else. It can be hard to refactor the code to make it use a skin, but in the end, it is worth it. If used correctly, instead of having multiple files with sprites, all the sprites would be compiled into a master like file so only one file would have to be loaded.
Here's an example of how I use it. As you can see, I have a skin.atlas, skin.json, skin.png. Luckily for you, you don't have to create these manually. How to use TexturePacker Is also useful as well.
If you really don't want to refactor your game into using skins, you can always store Drawables in a single object and pass that object around to each Screen so it's not loading sprites whenever the screen is changed.
Please provide code of MenuBase, because it is impossible to see something from your inherited class.
Possible solutions to find performance lack:
1) Try to profile your code step by step. Create any time counter class and check each method you call after calling next screen.
2) Try to remove all extra code from your affected classes. If you have actors create method - don't call it. You have main.ply.showAds(false); - try to remove it at first, I guess this code calls something from external library. It is easily able to slow down your app.
As for #retodaredevil answer - methods like new Texture, TextureRegion, etc do not make something bad. I have interface with hundreds of such method calls and I don't see any impact on loading time by that.
I am making a game in which my player is a UFO, and when the player collides with other game objects, I need the game objects to be attached or floated in the air below the player (UFO), like original UFO. I tried to attach them as a child, but it didn't worked.
I made one script as below:
if (coll) {
distance = Vector2.Distance (this.transform.position, player.transform.position);
if (distance < 2) {
this.transform.parent = encaixe.transform;
this.transform.localPosition = new Vector2 (0f, 1.2f);
this.transform.localRotation = Quaternion.identity;
encaixe.rigidbody2D.gravityScale=0;
}
}
In using this script, the gameobject is attaching, but the player is not moving as like original. The game object is pulling down or up forcefully.
Please suggest to me how to do this.
I know that this Thread is rather old, but maybe someone might come across this question and is in need of an answer.
You can actively set the Object's Position and Rotation to the UFO's on Collision.
Something like the following (pseudocode):
private bool hasCollided = false;
void OnCollisionEnter()
{
hasCollided = true;
}
void LateUpdate()
{
if (hasCollided)
{
followPlayer();
}
}
void followPlayer()
{
//update position and rotation
}
I've been building a game for some time, and just realized I did something very wrong the whole time, and still don't really know better.
I have a control class, my MainActivity, which pretty much only does the following:
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
operator=new Operator(getBaseContext());
setContentView(R.layout.activity_main); //<- framelayout with the view and two buttons on top
}
//Buttons:
public void shoot(View view) {
operator.shoot(view.getId());
}
public void pause(View view) {
AndronXView.running=!AndronXView.running;
}
Then there is my View, which draws Actors and makes my workerthread compute everything:
public MyView(Context context, AttributeSet attrs) {
super(context, attrs);
animHandler = new Handler();
animHandler.postDelayed(loadLvl1, 5000);
arrayOfActors = operator.getActors(); //simplyfied to one array
if(arrayOfActors==null)
arrayOfActors=new Actor[0]; //if op hasn't loaded yet, prevent NPE in onDraw
//stripped of unimportant color and size computing stuff
}
protected void onDraw(final Canvas canvas){
//Should I copy player before doing this? Never got problems here so far.
canvas.drawBitmap(operator.player.getCurrentGraphic(), operator.player.getX(), operator.player.getY(), null);
for(Actor actor:arrayOfActors) {
canvas.drawBitmap(actor.getCurrentGraphic(), actor.getX(), actor.getY(), null);
}
if (running) {
operator.run(); //Compute. Realized my mistake here and changed the inside, wait for it.
animHandler.postDelayed(r, Operator.FRAME_RATE); //r=invalidate();
animHandler.post(loadActors); //get Arrays from op
}else animHandler.post(wait);
}
Runnable wait = new Runnable() {
#Override
public void run() {
if (running)
animHandler.post(r);
else animHandler.postDelayed(this, Operator.FRAME_RATE);
}
};
#Override
public boolean onTouchEvent(#NonNull MotionEvent event){
int action = event.getAction();
if(action==MotionEvent.ACTION_DOWN || action==MotionEvent.ACTION_MOVE){
operator.player.setSpeed((event.getX()-operator.player.getHorizontalMid())
/AndronX.PLAYER_MOVE_LAG,
(event.getY()-operator.player.getVerticalMid())/AndronX.PLAYER_MOVE_LAG);
}
return true;
}
And then there is my Operator, extending Thread, which computes movement and interactions of the actors in the background:
public Operator(Context baseContext) {
this.player = new Player(baseContext); //context to load drawable from ressource
arrayListOfActors=new ArrayList<>();
//Looper.prepare(); //it crashed and said only one Looper/Thread
//Looper.loop(); //so I removed it
opHandler = new Handler();
}
#Override
public void run() {
opHandler.post(gameStep); //before, I had the whole processing inside this run().
}
private Runnable gameStep = new Runnable(){
player.move();
computeEveryMemberOf(arrayListOfActors); //much computing happens here, usually
//contains 1-30 Actors that get cross-referenced
arrayOfActors = arrayListOfActors.toArray(new Actor[arrayListOfActors.size()]);
}
public Actor[] getActors(){
return arrayOfActors;
}
Before, I had the computign directly in my operators run() method, which I realized made the background thread useless. I#m not sure though if this is the right way, should I let the operator loop itself, would the two threads kinda stay in sync? Does it even matter?
Or should I go run(){ sleep(FRAME_RATE); compute();}?
Edit: A big problem arose, and I'm not sure if it's because of this, so I really need an answer here how to do this the right way.
With every step, I move some actors a little bit up or down, in a cosinus wave like speed (like it's projection to an axis), and currently, the actual movement doesn't get through to the view, they just jump from max to min and back, although they do it in the desired speed(looks like extreme lag).
Actually you can see for yourself what this problem is: https://dl.dropboxusercontent.com/u/28278772/AndronX.apk
I need to destroy one of the body's after collision in JBox2D android game. I found that JBox2D world become locked when body's become in contact. I wanted to destroy one of the body after collision. Can i get any call back after world released lock ?. I found an option that adding the body's into an array for destroying it. But when to destroy the body ?. I am not using andengine/libgdx in this game. Find my collision listener class below,
private class CollisionListener implements ContactListener {
#Override
public void beginContact(Contact contact) {
Object fixtureA = contact.getFixtureA().getUserData();
Object fixtureB = contact.getFixtureB().getUserData();
Body mBodyA = contact.getFixtureA().getBody();
Body mBodyB = contact.getFixtureB().getBody();
if (fixtureA instanceof Bullet) {
destroyBalloonBody(mBodyB);
}
if (fixtureB instanceof Bullet) {
destroyBalloonBody(mBodyA);
}
}
#Override
public void endContact(Contact contact) {
}
#Override
public void postSolve(Contact contact, ContactImpulse contactImpulse) {
}
#Override
public void preSolve(Contact contact, Manifold manifold) {
}
}
public void destroyBalloonBody(Body balloon){
//Can i start a new thread which is having a loop until the world become release for destroying the body
//Or
//Do i need to add the body to a deletionArrayList to destroy it.
}
I believe the problem is that you are trying to remove the body during a collision callback.
From the Box2D Manual:
It is tempting to implement game logic that alters the physics world
inside a contact callback. For example, you may have a collision that
applies damage and try to destroy the associated actor and its rigid
body. However, Box2D does not allow you to alter the physics world
inside a callback because you might destroy objects that Box2D is
currently processing, leading to orphaned pointers.
That is to say, you should not destroy bodies inside of a collision callback.
You should store off the references to the bodies you wish to destroy and destroy them using the World reference after the update cycle.
Was this what you needed?
I was trying to make the enemies in my game go up and down; since I'm using a physic body with a Sprite on it I can't use entity modifiers, so I decided give the body a little push using the .setLinearVelocity(float x, float y) method every time its sprite reach a certain point in the screen.
With just one body works great, but I need to have other enemeis (same sprite, different body) spawning every 5 seconds and doing the same thing, but I don't know how to track them... I mean, I don't know how to control if each body reaches the Y location independently from one another...
For example, right now the code is like this:
private void add_Box_Face()
{
float random_x = (float) (28 + (int)(Math.random() * ((this.CAMERA_WIDTH - 28*2) + 1)));
final Body rectangle_face_body;
final Sprite rectangle_face = new Sprite(random_x, this.y, this.mRectangleFaceTextureRegion, this.getVertexBufferObjectManager());
rectangle_face_body = PhysicsFactory.createBoxBody(this.m_PhysicsWorld, rectangle_face, BodyType.DynamicBody, this.BOX_FIXTURE_DEF);
rectangle_face_body.setUserData("target");
//I give the body a initial push
rectangle_face_body.setLinearVelocity(0, -5);
//I register an update handler to the sprite to control if it reaches a certain Y value
rectangle_face.registerUpdateHandler(new IUpdateHandler()
{
#Override
public void onUpdate(float pSecondsElapsed)
{
if (rectangle_face.getY() >= y-50)
{
//Here I just use a flag so that later on below I can do the push
MyApp.this.setLinearVelocity = true;
}
}
#Override
public void reset()
{
// TODO Auto-generated method stub
}
});
//Here I register the physic connector and if the flag permits it, I push the body up
this.m_PhysicsWorld.registerPhysicsConnector(new PhysicsConnector(rectangle_face, rectangle_face_body, true, false)
{
#Override
public void onUpdate(float pSecondsElapsed)
{
super.onUpdate(pSecondsElapsed);
if(MyApp.this.setLinearVelocity)
{
rectangle_face_body.setLinearVelocity(0, -3);
MyApp.this.setLinearVelocity = false;
}
}
});
this.mscene.attachChild(rectangle_face);
}
With the code like this the first body do what is planned, it moves up and down but as soon as another body pops up, it falls down and the other body goes up because the boolean setLinearVelocity is always set to true, so there is a costant push upwards; when a third body comes in, the second body falls down as well and this last one takes its place going up
With this code I didn't expect much else... but I don't know what else I can try... how can I control this?
Thanks in advance :)
EDIT: Added working code in an anwser below
I suggest you separate the code for the enemy from the code for the update handler. Create a class Enemy that will contain the Sprite and Body, hold your Enemies in an array and override the onUpdate method of your PhysicsWorld so that it goes through the array of Enemies and does what you want to all of them.
Here's a code snippet showing a very simple way of doing this:
mEngine.registerUpdateHandler(new IUpdateHandler() {
#Override
public void reset() {}
#Override
public void onUpdate(float pSecondsElapsed) {
for (Enemy e : enemies) {
e.checkPositionAndBounce();
}
}
});
Please note that this may not a very good idea as this code will probably run on a thread different to the one of the physics engine, which could cause all sorts of problems. A better way would be overriding the onUpdate method of PhysicsWorld:
#Override
public void onUpdate(final float pSecondsElapsed) {
super.onUpdate();
for (Enemy e : enemies) {
e.checkPositionAndBounce();
}
}
If you are unsure of what the first snippet means, look up "anonymous inner class".
Ok, here's the final working code (I didn't create a method to check the position or a class for the enemies just because right now I'm just messing around with the mechanics; I'll create a new project when I'm ready to really start):
this.m_PhysicsWorld = new PhysicsWorld(new Vector2(0, SensorManager.GRAVITY_EARTH), false)
{
#Override
public void onUpdate(float pSecondsElapsed)
{
super.onUpdate(pSecondsElapsed);
for(int i = 0; i <= MyApp.this.mSpriteCounter; i++)
{
if (rectangle_face[i].getY() >= y-50)
{
final PhysicsConnector spritePhysicsConnector = m_PhysicsWorld.getPhysicsConnectorManager().findPhysicsConnectorByShape(rectangle_face[i]);
spritePhysicsConnector.getBody().setLinearVelocity(0, -3);
}
}
};
In this code rectangle_face[] is an array of Sprites; each sprite is created like this:
private void add_Box_Face()
{
float random_x = (float) (28 + (int)(Math.random() * ((this.CAMERA_WIDTH - 28*2) + 1)));
final Body rectangle_face_body;
rectangle_face[this.mSpriteCounter] = new Sprite(random_x, y, this.mRectangleFaceTextureRegion, this.getVertexBufferObjectManager());
rectangle_face_body = PhysicsFactory.createBoxBody(this.m_PhysicsWorld, rectangle_face[this.mSpriteCounter], BodyType.DynamicBody, this.BOX_FIXTURE_DEF);
rectangle_face_body.setUserData("target");
rectangle_face_body.setLinearVelocity(0, -5);
this.m_PhysicsWorld.registerPhysicsConnector(new PhysicsConnector(rectangle_face[this.mSpriteCounter], rectangle_face_body, true, false));
this.mscene.attachChild(rectangle_face[this.mSpriteCounter]);
}
That's it, thanks again for the help :)