I'm using AndEngine to make a game for the Android platform. I need to detect if a circular body contacts a circular sprite. To do this, I'm calculating the centers and radii of both and using pythag to determine if they are indeed touching. However, I keep getting a nullpointerexception when I try to get the x coordinate of my body. spriteNum increases every time the screen it touched and a sprite is created. Any ideas why? My code:
public class grow implements Runnable{
Sprite sp;
Body body[] = new Body[100];
public grow(Sprite sprite){
sp = sprite;
}
#Override
public void run() {
float radf, rads; //fill radius/stationary radius
float[] fill; //fillx/stationaryx
float fx=0, fy=0, sx, sy;
while(down){
//Log.e("Tag","Running thread. Down = "+Boolean.toString(down));
yourSprite[spriteNum].setScale(scale += 0.1);
fill = yourSprite[spriteNum].getSceneCenterCoordinates();
fill[0]=fx;
fill[1]=fy;
radf=yourSprite[spriteNum].getHeightScaled()/2;
Log.e("Fill X before for",Float.toString(fx));
if(spriteNum>0)
for(int x=0;x<spriteNum;x++){
rads=yourSprite[x].getHeightScaled()/2;
sx = body[x].getWorldCenter().x; //Null pointer exception
sy = body[x].getWorldCenter().y;
if(Math.sqrt(Math.pow((fx-sx),2)+Math.pow((fy-sy),2))<(radf+rads))
down = false;
Log.e("Fill x",Float.toString(fx));
Log.e("Stat x",Float.toString(sy));
}
try {
Thread.sleep(75);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
body[spriteNum] = PhysicsFactory.createCircleBody(mPhysicsWorld, yourSprite[spriteNum], BodyType.DynamicBody, FIXTURE_DEF);
mPhysicsWorld.registerPhysicsConnector(new PhysicsConnector(yourSprite[spriteNum], body[spriteNum], true, true));
if(body[0]!=null)
Log.e("Body created","not null"); //This says it's not null, but when I did the same thing just inside of my for() loop and it did say it was null
}
I guess it's because you have initialized body array Body body[] = new Body[100] but not individual Body elements in it. So when you access body[x] it returns null. You should also initialize body elements in array. Something like:
for(int i=0; i<body.length; i++) {
// probably some cod here..
body[i] = new Body(..);
// probably some cod here..
}
Another cause that came into my mind for your problem is, you said:
spriteNum increases every time the screen it touched and a sprite is
created.
So it can be possible that you have initialized some body elements on startup and then when sprite count increases you do not create new elements in body array, so when you try body[0] it is not null but for new sprites for which body elements may not have been initialized you get null and thus NPE.
Related
I am using Androidplot to display real time data. The real time data is dynamic and the x axis is time. The domain is a fixed timespan. Because the values could be any double, rangeStepMode is set to subdivide the y-axis. The issue is that when all the values are the same, the plot does not draw correctly.
You can see in the image that there are no range grids or labels.
From this related question:
This happens because Androidplot does not have enough information to automatically calculate what a reasonable domain/range scale would be from a single point.
This makes sense, and the linked solution of setting a non-zero range boundary works but instead of an arbitrary range like miny - 1to maxy + 1, I'd like for there to be only one labeled range line in these cases across the middle of the screen.
My Activity:
public class SimpleXYPlotActivity extends Activity {
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.simple_xy_plot_example);
XYPlot plot = (XYPlot) findViewById(R.id.plot);
Number[] series1Numbers = new Number[]{
1,
1,
};
XYSeries series1 = new SimpleXYSeries(SimpleXYSeries.ArrayFormat.Y_VALS_ONLY, "Series1", series1Numbers);
LineAndPointFormatter series1Format = new LineAndPointFormatter(Color.RED, Color.GREEN, null, null);
plot.addSeries(series1, series1Format);
StepMode stepMode = StepMode.SUBDIVIDE;
int stepValue = 10;
plot.setRangeStepMode(stepMode);
plot.setRangeStepValue(stepValue);
}
}
My Layout:
<com.androidplot.xy.XYPlot
android:id="#+id/plot"
style="#style/APDefacto.Dark"
android:layout_width="match_parent"
android:layout_height="match_parent"
ap:rangeStep="5"
ap:rangeStepMode="subdivide"
ap:domainStep="1"
ap:domainStepMode="increment_by_val"
/>
What I've tried
The following works on the simple xy example, but when I try setting it within minmax in my time series class, the thread drawing the domain gridlines gets into a very long loop as it calculates xPix to be very very large. This also isn't a very solution for situations where I have multiple series. Any ideas on how I can get the results I want?
Double minY = null;
Double maxY = null;
for (Double aDouble : series1Numbers) {
if (minY == null) {
minY = aDouble;
} else {
minY = Math.min(minY, aDouble);
}
if (maxY == null) {
maxY = aDouble;
} else {
maxY = Math.max(maxY, aDouble);
}
}
if (minY.equals(maxY)) {
plot.setUserRangeOrigin(minY);
plot.setRangeBoundaries(0, 2 * maxY, BoundaryMode.FIXED);
plot.setRangeStepMode(StepMode.INCREMENT_BY_PIXELS);
plot.setRangeStepValue(Double.POSITIVE_INFINITY);
} else {
plot.setUserRangeOrigin(0);
plot.setRangeBoundaries(minY, maxY, BoundaryMode.FIXED);
plot.setRangeStepMode(StepMode.SUBDIVIDE);
plot.setRangeStepValue(5);
}
This wont get rid of the CPU overhead but you can use PlotUtils.minMax to find these values for you
If implementing and using FastXYSeries is a possibility for you then the overhead of using minMax drops away too, as the calculation only ever gets done when your XYSeries data changes.
I am relatively new to Android and i want to create an array that increases in size and i declared an array like this:
private Sprite something[]; //sprite is my custom class that does sprites
And i want to add elements like this, but it gives me error...
something[i++] = new Sprite(spriteSheet,numRows,numColumns,true,x,y);
//i is number of elements and Sprite(...) is the constructor
Can someone tell me what i am doing wrong here, and why i get the zygote error and a null pointer exception?
Thanks!
Java doesn't really work like Javascript does. Arrays have fixed size, as per something = new Sprite[10]; where the element indices of something are 0 to 9.
The functionality you want can however be achieved using List<Sprite> something = new ArrayList<Sprite>();, and then something.add(new Sprite(spriteSheet, numRows, numColumns, true, x, y));.
EDIT:
Iteration of an ArrayList works like this:
List<Sprite> sprites = new ArrayList<Sprite>();
for(Sprite sprite : sprites)
{
sprite.print();
}
However, the following statement:
List<Sprite> sprites = new ArrayList<Sprite>();
for(Sprite sprite : sprites)
{
sprites.remove(sprite);
}
Will throw a ConcurrentModificationException.
Therefore, you can either use an iterator manually:
List<Sprite> sprites = new ArrayList<Sprite>();
Iterator<Sprite> iterator = sprites.iterator();
while(iterator.hasNext())
{
Sprite sprite = iterator.next();
...
iterator.remove();
}
Or, personally when I need to modify the elements on the list during iteration, I use the following:
List<Sprite> sprites = new ArrayList<Sprite>();
for(int i = 0; i < sprites.size(); i++)
{
Sprite sprite = sprites.get(i);
...
sprites.remove(i--);
}
Although if I remember correctly, the iterator is the recommended approach.
how to get x and y coordinates of sprit2 when sprite1 collides with it i use collision update handler. my requirement is when sprite 1 collide with sprite2 it attach with sprite2 on that point where it collides?
Thanks.
try using the Box2D extension for andengine. you basically attach physics bodies to sprites. then you use a contact listener to take care of collision events. here is how you would get the contact points of the collision in the listener...
protected ContactListener createContactListener() {
return new ContactListener() {
public void beginContact(Contact contact) {
Vector2[] contactPoints = contact.getWorldManifold().getPoints();
for(int i = 0; i < contactPoints.length; i++) {
...
}
...
}
}
}
I'm trying to create a simple test for Box2d, Cocos2d, and Android. All I need is to put one body on the screen, and have it respond to gravity. I looked everywhere and there are good tutorials for non-Android applications but none of them has gravity on Android working. Can anyone help?
This is the code I'm using. I took it, and modified lightly from here: http://www.expobrain.net/2012/05/12/box2d-physics-simulation-on-android/
For creating the world:
World world = new World(new Vec2(2.0f, 8.0f), false);
And this is how I create the body:
public void setupBallBody() {
CGSize size = CCDirector.sharedDirector().winSize();
CGPoint pos = CGPoint.make(size.width / 1.2f, size.height / 1.2f);
// Create Dynamic Body
BodyDef bodyDef = new BodyDef();
bodyDef.type = BodyType.DYNAMIC;
bodyDef.position.set(screenToWorld(pos));
ballBody = world.createBody(bodyDef);
MassData md = new MassData();
md.mass = 5;
ballBody.setMassData(md);
// Create Shape
CircleShape ballShape = new CircleShape();
ballShape.m_radius = SMILE_RADIUS;
// Create fixture
FixtureDef ballFixture = new FixtureDef();
ballFixture.shape = ballShape;
ballFixture.density = SMILE_DENSITY;
ballFixture.friction = SMILE_FRICTION;
ballFixture.restitution = SMILE_RESTITUTION;
// Assign fixture to Body
ballBody.createFixture(ballFixture);
// Set sprite
final CCSprite ballSprite = CCSprite.sprite("ball.jpg");
ballSprite.setPosition(pos);
addChild(ballSprite, 0);
ballBody.setUserData(ballSprite);
}
This is my "tick" method (which I'm not sure is part of what makes gravity working but I include it here for completeness.)
public void tick(float dt) {
synchronized (world) {
world.step(1/60, 10, 10);
}
// Update sprites
for (Body b = world.getBodyList(); b != null; b = b.getNext()) {
if(b == ballBody) {
CCSprite ballSprite = (CCSprite)ballBody.getUserData();
if(ballSprite != null) {
ballSprite.setPosition(worldToScreen(ballBody.getPosition())));
ballSprite.setRotation(-1.0f * (float)Math.toDegrees((ballBody.getAngle())));
}
}
}
}
My guessing here is this line may be the problem.-
world.step(1/60, 10, 10);
step function handles the bodies positions based on the time passed since last step. You're doing an integer division 1/60, which result is 0. Try 1.0f / 60.0f instead.
Otherwise, you're telling your world that 0 milliseconds passed since the last step, so bodies will always remain at their initial position.
However, it's not good practice to 'hardcode' your time step. You better pass to your world step the delta time your receiving.-
world.step(dt, 10, 10);
Also, you may simplify your loop to work for any body with an attached CCSprite, like this.-
for (Body b = world.getBodyList(); b != null; b = b.getNext()) {
CCSprite sprite = (CCSprite)b.getUserData();
if(sprite != null) {
sprite.setPosition(worldToScreen(b.getPosition())));
sprite.setRotation(-1.0f * (float)Math.toDegrees((b.getAngle())));
}
}
I'm creating an android app using Andengine. One part of the app requires users to select a few sprites from a group of sprites on the screen, which causes the selected sprites to turn a different color (ie, moving to the next tile). I declared them all as animated sprites and I'm using the same texture for each one. The problem is that once I select a sprite, every sprite moves to the next tile, not just the one I selected. How do I make just the one sprite change?
Here's where I setup the textures and whatnot:
private Texture mGreenTextureAtlas;
private TiledTextureRegion mGreenBallFaceTextureRegion;
#Override
public void onLoadResources() {
/* Textures. */
...
this.mGreenTextureAtlas = new Texture(32, 32, TextureOptions.BILINEAR_PREMULTIPLYALPHA);
...
TextureRegionFactory.setAssetBasePath("gfx/");
/* TextureRegions. */
...
this.mGreenBallFaceTextureRegion = TextureRegionFactory.createTiledFromAsset(this.mGreenTextureAtlas, this, "green_ball.png", 0, 16, 2, 1); // 64x32
this.mEngine.getTextureManager().loadTextures(this.mCueTextureAtlas, this.mGreenTextureAtlas , this.mBackgroundTexture, this.mPocketTexture);
}
Here's where I actually create the sprites and apply the textures:
face = new AnimatedSprite(pX, pY, this.mGreenBallFaceTextureRegion);
body = PhysicsFactory.createCircleBody(this.mPhysicsWorld, face, BodyType.DynamicBody, FIXTURE_DEF);
encapsed = new Encapsulator(body, face, Encapsulator.AVOID_BALL, mFaceCount);
ballsList.add(encapsed);
I encapsulate each sprite, it's body, and some other data into an object that I made, and then add that object into an ArrayList.
Here is the onTouch event handler.
#Override
public boolean onAreaTouched( final TouchEvent pSceneTouchEvent, final ITouchArea pTouchArea,final float pTouchAreaLocalX, final float pTouchAreaLocalY) {
if(pSceneTouchEvent.isActionDown()) {
final AnimatedSprite face = (AnimatedSprite) pTouchArea;
for(int i=0; i<ballsList.size(); i++)
{
if(face.equals(ballsList.get(i).animatedFace))
{
ballsList.get(i).toggleType(face);
System.out.println("Ball " + ballsList.get(i).id + " is now " + ballsList.get(i).type);
}
}
return true;
}
return false;
}
Finally, here is the toggleType method in the Encapsulator class that's responsible for moving to the next tile:
public void toggleType(AnimatedSprite face)
{
if(this.type == AVOID_BALL)
{
this.type = HIT_BALL;
face.nextTile();
}
else if(this.type == HIT_BALL)
{
this.type = AVOID_BALL;
face.setCurrentTileIndex(0);
}
}
Sorry if this is a bit long-winded. Any help is appreciated.
I did some more googling and came across a solution. I had to use the textureregion.clone() method when creating the sprites. I found the solution at this link:
http://www.andengine.org/forums/development/two-sprites-sharing-the-same-tiledtextureregion-t4339.html