Search the nearest sprite - Andengine - Android - android

I have a trouble when I try locate the sprite more near of my player. I have a little map and side scroll. only have a grow and a player on middle. He can looks and walk left or right, and if your player looks left and you press "shot", I search on my linkedlist of mobs a the most near Mob of my player and I do this mob receibe the damage.
I have this code:
- mobs is my linkedlist of mobs. (Extends of AnimatedSprite)
This is my first game, and I dont know if there are a better method of do this, this dont search the more near, only the first element of my list, any idea? :)
public void shot(){
float playerx = player.getX();
Mob target = mobs.element();
if(player.getDireccion()==Entidad.DIR_IZQUIERDA){//If direction if left
for(Mob z:mobs){
if(z.getX()<playerx &&
z.getX()>target.getX())
target= z;
}
}else if(player.getDireccion()==Entidad.DIR_DERECHA){//If direction is right
for(Mob z:mobs){
if(z.getX()>playerx && z.getX()<target.getX())
target= z;
}
}
target.recibeDaƱo();//receibe damaget (loss life basically)
if(objetivo.getVida()<=0){ //These delete body and sprite of the game
final Mob eliminar = target;
eliminarZombie(eliminar,this);
mobs.remove(target);
System.gc();
}
}
Sorry my english.

loop over all enemies and calculate the distance which is
distance = x2 - x1
where x2 is the x attribute of the enemy and x1 is the x attribute of the player
only take into account the positive distances if you are facing right , and only take the negative distances if you are facing left
then chose the smallest absolute value of the distance
so it's something like this
float shortest = 1000; //just put a large number here
for(Mob z:mobs){
distance = z.x - player.x;
if((player.getDirection == Direction.RIGHT) && distance > 0 && distance < shortest){
//set the target to the current mob and change the value of the shortest
}
if((player.getDirection == Direction.LEFT) && distance < 0 && Math.abs(distance) < shortest){
//same as above
}
}
//damage the target here and remove it
just notice that I didn't take care of the case where the target is right on top of the enemy and the distance == 0
your code should work too , but instead of looping over the list twice , it's better to loop once
other notes on your code are:
don't call System.gc(), not a good idea
if you want to remove an item from a linked list , remove it on updateThread using this.runOnUpdateThread() and give it a runnable [if you don't do it this way your game will crash randomly]
you might also use an iterator to go over the items , then use .remove() to remove the latest item you reached , it's thread safe

Related

How to bounce two moving objects

I'm making a ConSumo game from the arcade machine in Bully. Basically there's an enemy wrestler that move in a straight line and will bounce the player back if collided. I can't seem to figure out the logic in the angle to bounce the player when collided with an enemy wrestler.
I tried calculating the collision angle using the arctan of (player.centerY - enemy.centerY)/(player.centerX - player.centerY) and then adding 180 degree to mirror the angle.
double angle = Math.atan(((player.getCenterY() - enemies[i].getCenterY())/ (player.getCenterX() - enemies[i].getCenterX())));
angle = Math.toDegrees(angle);
angle += 180;
angle = Math.toRadians(angle);
player.addX(Math.cos(Angle) * strength);
plyaer.addY(-(Math.sin(angle) * strength));
I tried to just make the player bounce back on the same angle(i know this is not the ideal result, but i want to at least get the hang of it first, if you can suggest the better ways, i will appreciate it) but it only works on one or two side of the collision, and the other sides seem to pull the player through the enemy instead of bouncing it back.
Maybe you can try the physics approach which is taking into account conservation of impulse and conservation of energy.
Basically, the player, with mass mp, has velocity [vp; 0] and enemy, with mass me, player has velocity [ve; 0]. So no y components because they move horizontally only. Now at the time of collision t = t_col assume the center of mass of the player has coordinates [xp, yp] and the enemy's center of mass has coordinates [xe, ye] (you can always tweak them to make sure there is a greater bouncing-off effect, by making the y coordinates much more different if you wish).
Conservation of momentum tells us that the velocities of the two objects, call them [Vp, Wp] and [Ve, We] right after the collision are calculated as follows
[Vp; Wp] = [vp; 0] + (1/mp)*[I1; I2];
[Ve; We] = [ve; 0] - (1/me)*[I1; I2];
where, as is typically assumed that the impact is normal to the surface of the objects, the vector [I1; I2] can be taken to be aligned with the vector connecting the two centers: [xp - xe; yp - ye]. Combining this information with the conservation of energy, one can calculate the magnitude of the said vector and find that
k = (mp*me/(mp+me)) * (vp - ve)*(xp - xe) / ((xp - xe)^2 + (yp - ye)^2);
I1 = k*(xp - xe);
I2 = k*(yp - ye);
So basically, at time of collision you have as input:
the position and velocity of the player: [xp; yp], [vp; 0]
the position and velocity of the enemy: [xe; ye], [ve; 0]
the mass of the player mp and the mass of the enemy me
Then calculate
k = (mp*me/(mp+me)) * (vp - ve)*(xp - xe) / ((xp - xe)^2 + (yp - ye)^2);
I1 = k*(xp - xe);
I2 = k*(yp - ye);
Vp = vp + (1/mp)*I1;
Wp = (1/mp)*abs(I2);
Ve = ve - (1/me)*I1;
We = (1/me)*abs(I2);
Observe that I used abs(I2) which is the absolute value of I2. This is because for one of the two objects the y-component of the velocity after collision is going to be positive (so no difference there), but for the other one will be negative. For the negative one, we can also add the fact that the object may bounce off the ground immediately after collision (so collision with object and then collision with the ground). So we use the reflection law, kind of like the way light is reflected by a mirror.
After collision, at time t = t_col the parabolic trajectories of the two players (before they land back on the ground) will be
xp(t) = xp + Vp * (t - t_col);
yp(t) = yp + Wp * (t - t_col) - (g/2) * (t - t_col)^2;
xe(t) = xe + Ve * (t - t_col);
ye(t) = ye + We * (t - t_col) - (g/2) * (t - t_col)^2;
If you want angles:
cos(angle_p) = Vp / (Vp^2 + Wp^2);
sin(angle_p) = Wp / (Vp^2 + Wp^2);
cos(angle_e) = Ve / (Ve^2 + We^2);
sin(angle_e) = We / (Ve^2 + We^2);
where angle_p is the angle of the player and angle_e is the angle of the enemy.

Compass - Track number of full 360 degree rotations

Suppose a person is using this compass, and beginning from 90 degrees they start rotating either clockwise or counterclockwise. What's the best way to keep count of how many full 360 degree rotations they complete? Assuming they'll be rotating either only clockwise or only counterclockwise from beginning to end.
I kept coming up with solutions where if the beginning bearing is, for example, 90 degrees I keep checking the next bearing when the sensor data changes, and if it's consistently moving in one direction I know they're rotating. And if they keep rotating in that direction and make it back to 90 degrees, that counts as one rotation. My way seems very convoluted and inefficient and I'm having a hard time coming up with a better way.
In this scenario, I'd be expecting multiple full rotations.
I'd appreciate any help. Thank you!
I found this related answer and am trying to put together a code sample for that. If someone has already done something similar, please post it!
#Override
public void onSensorChanged(SensorEvent event)
{
switch(event.sensor.getType())
{
case Sensor.TYPE_GRAVITY:
{
mValuesAccelerometer = lowPass(event.values.clone(), mValuesAccelerometer);
break;
}
case Sensor.TYPE_MAGNETIC_FIELD:
{
mValuesMagneticField = lowPass(event.values.clone(), mValuesMagneticField);
break;
}
}
boolean success = SensorManager.getRotationMatrix(
mMatrixR,
mMatrixI,
mValuesAccelerometer,
mValuesMagneticField);
if (success)
{
SensorManager.getOrientation(mMatrixR, mMatrixValues);
float azimuth = toDegrees(mMatrixValues[0]);
float pitch = toDegrees(mMatrixValues[1]);
float roll = toDegrees(mMatrixValues[2]);
if (azimuth < 0.0d)
{
//The bearing in degrees
azimuth += 360.0d;
}
}
}
If you're sure that they'll be moving in only 1 direction, to optimize your code you can have checkpoints for degrees instead of continuously monitoring if they're still moving in the right direction.
Here's a rough algo to do that
//You noted 90 degree as starting point
// checkpoint 1 will be 180 keep it as a boolean
// now you've reached 180 if the meter gets to 180 before going to next checkpoint
// which is 270 then make 180 false. it means they turned back.
// if they make it to 270 then wait for 0 degrees and do the same.
// if they make it back to 90 like that. You got a rotation and hopefully
// a bit of complexity is reduced as you're just checking for 4 checkpoints
I don't have any code handy at the moment.
This is a tracking problem with a reading that overflows. You need to keep track of the last reading and hope the user doesn't do more than a half turn between each reading.... (because of the Nyquist theorem)
Here is the basic pseudo code.
var totalChange = 0;
var lastAzimuth = -1000;
function CountTurns(az)
{
if (az > 180) az -= 360; // do this if your azimuth is always positive i.e. 0-360.
if (lastAzimuth == -1000)
{
lastAzimuth = az;
}
diff = az - lastAzimuth;
if (diff > 180)
diff -= 360;
if (diff < -180)
diff += 360;
lastAzimuth = az;
totalChange += diff;
return totalChange / 360;
}
Create 3 integers
int rotationCount=0
int currentDegrees=0
int previousDegrees=89
not a java programmer so i dont know how you handle the onSensorChanged event but basically perform a check within a while loop
while (currentDegrees + 90 < 360)
{
if (currentDegrees + 90 == 0)
{
if (previousDegrees == 359)
{
rotationCount = rotationCount + 1
}
}
else if (currentDegrees + 90 == 359)
{
if (previousDegrees == 0)
{
rotationCount = rotationCount - 1
}
}
previousDegrees = currentDegrees + 90
}
sorry about the syntax, this is just an example of how to do so..
Visualize what I will say and you'll definitely hit your goal in no time.
As you don't need to think of the full 360 degree, but you can take half of that and use the signs differences to your advantage.
Take a look at this figure :
We have a circle that is divided to two sides (left and right).
The left side will take negative 180 degree. (West Side).
The right side will take positive 180 degree. (East Side).
Current positing will be always 0 as (North) and positive 180 as (South).
IF the compass goes positive (meaning goes to the right direction)
Then add +1 on each turn.
IF the compass goes negative (meaning goes to the left direction).
Then subtract -1 on each turn
IF the compass hit OR is 0, then it's current position (NORTH).
IF the compass hit OR is 90, then it's (East).
IF the compass hit OR is 180, then it's (South)
IF the compass hit OR is -90, then it's (West).
This will turn out that whenever the person goes East, the counter will add +1 until it reaches 180, Then it'll change from positive to negative, which will subtract -1 on each turn until it reaches 0. That would be a full 360 rotation.

Revolute joint in libgdx is not rotating back(not working) when limit reaches.How to control revolute joint based on user touch

I have been searching how to control revolute joint in libgdx with box2d based on user touch and revolute joint is being stopped after it reached upper angle.Is there any way to control revolute joint ?
`
jd = new RevoluteJointDef();
jd.initialize(bodyPivot, boxBody, anchor);
jd.lowerAngle = 0.75f * (float)3.14; // -90 degrees
jd.upperAngle = 0.75f * (float)3.14; // 45 degrees
jd.collideConnected=false;
jd.enableLimit = true;
jd.maxMotorTorque = 1000.0f;
jd.enableMotor=false;
jd.motorSpeed = 0f*(float)3.14;
rj = (RevoluteJoint) world.createJoint(jd);`
I tried using rj.enableMotor(true) but It didn't work
When you create a joint the current relative angle between the bodies is taken to be zero when it comes to specifying the limits.
If the joint keeps rotating in the same direction all the time then the limits don't actually change, because the new starting point is now zero as far as the limits are concerned.
jointDef.upperAngle = MathUtils.PI;
jointDef.lowerAngle = 0;//the position when joint was created
But if the joint is supposed to rotate back to the original position before coming down, it would be something like:
jointDef.upperAngle = atTop ? 0 : MathUtils.PI;
jointDef.lowerAngle = atTop ? -MathUtils.PI : 0;
I found answer from here

Tile based collision works perfect except against blocks with position.y == 0

I'm working on a simple platformer and I've been through a couple of collision systems before finally finding the solution that has thus far been as stable as I could hope for. That is until the player collides with a block whose CENTER position in the y axis equals 0. It's very wierd although I suspect it's only in the y axis because I check the x movement/collision first. I have no idea.
I do a simple AABB type collision check/response where I apply the x velocity first then if overlap, reposition player so that right player bound = left block bound bringing them out of overlap. I then go through the same with the y axis taking the player vertical direction to work out whether player has hit bottom side or top side of block. The only controls are jump as the player has an acceleration force in positive x hence the player will never travel left.
The problem is that the player moves off the blue dotted block but when it hits the red dotted one a collision is detected in the Y axis thus the player gets moved up out of overlap but then when the next frame executes the player's velocity in x is added as usual but a collision gets registered and it then positions the player to the left of the red block. The next frame detects a collision with the blue block and thus it positions the player on top of it as shown below.
The setup up below makes the player loop this sequence over
Info:
player.centerPosition = (2, 2)
player.width = 0.5f
player.height = 0.8f
blueBlock.centerPosition = (1, 1)
redBlock.centerPosition = (4, 0)
block.width = 3
block.height = 1
private void checkBlockCollision(float deltaTime) {
List<GameObject> colliders = grid.getPotentialColliders(player);
int len = colliders.size();
for (int axis=0;axis<2;axis++) { // 0 = X-axis, 1 = Y-axis
if (axis == 0) {
player.position.add(player.velocity.x*deltaTime, 0);
player.updateBounds();
} else {
player.position.add(0, player.velocity.y*deltaTime);
player.updateBounds();
}
for (int i=0;i<len;i++) { // Cycle through all blocks found in broad phase
GameObject collider = colliders.get(i);
if (OverlapTester.overlapRectangles(player.bounds, collider.bounds)) {
if (axis == 0) {
player.position.x = collider.position.x - (Player.PLAYER_WIDTH + collider.bounds.width)/2;
player.velocity.x = 0f;
Log.d("TAG", "Move player LEFT");
} else {
if (player.velocity.y > 0) {
player.position.y = collider.position.y - (Player.PLAYER_HEIGHT + collider.bounds.height)/2;
player.velocity.y = -player.velocity.y*0.333f;
Log.d("TAG", "Move player DOWN");
} else {
player.position.y = collider.position.y + (Player.PLAYER_HEIGHT + collider.bounds.height)/2;
player.velocity.y = 0;
player.state = Player.PLAYER_STATE_GROUNDED;
Log.d("TAG", "Move player UP");
}
}
}
} // end for loop colliders
} // end for loop axis
} // END METHOD
If anyone can shed some light on what the truck is going on here that would be amazing.
Thanks for reading and I can provide any further info or source to anyone interested.
Marios Kalogerou
SOLUTION:
I found a quick and dirty fix to the my problem. I just simply moved the player up an extra 0.001 units and this actually seperated the objects. Strange that since other blocks worked fine. Thanks again if you read through that and I hope my solution helps anyone with similar issues.

2D Rectangle Collision detection in Android

I have many images that I need to place on a canvas over a long period of time so that they look random. However, I don't want any of the images to overlap with each other. My solution so far is to randomly place the image somewhere on the canvas. If it overlaps I'll generate a new random location to try.
Now the tricky part is to see if where I am about to place the image is going to overlap with another image.
I was going to make a large array of 1's and 0's and manually mark off where I put the images. However, I was wondering if anyone knew of a way to "auto detect" using a method if where I am about to place an image will overlap with an existing image? Or if there is a way to do collision detection using some Android function?
Checking to see if two rectangles overlap is really simple, just use Rect.intersect()
Check out the Rect docs for more information:
http://developer.android.com/reference/android/graphics/Rect.html
Although I would recommend you try something different than what you have described above. In the beginning the probability of a collision will be very low. However as the screen fills up the probability of a collision will rise. This result in a lot of collisions and wasted computational power.
You should use something more efficient, off the top of my head you could try something like this:
Split the screen into a grid of size MxN
Keep a list of all unpopulated grid locations
Pick a random grid location for a new image i
Pick a random width and height for image i
If i intersects a grid location that is already populated or it if goes off the screen shrink it
Draw i
If all grid locations are taken quit, else go to 3
A simple 2D isinbox function could be:
bool IsInBox(int x1, int y1, int width1, int height1, int x2, int y2, int width2, int height2) {
int right1 = x1 + width1;
int right2 = x2 + width2;
int bottom1 = y1 + height1;
int bottom2 = y2 + height2;
// Check if top-left point is in box
if (x2 >= x1 && x2 <= right1 && y2 >= y2 && y2 <= bottom1) return true;
// Check if bottom-right point is in box
if (right2 >= x1 && right2 <= right1 && bottom2 >= y2 && bottom2 <= bottom1) return true;
return false;
}
Not sure if works though xd
Or you could use Rect.Intersect()

Categories

Resources