Andengine - Shooting bullets in front of rotating gun - android

Hello I searched in the forum,but coudn't find a helpful answer.
I'm making a game with AndEngine and I'm stuck for 3 days on shooting from rotating sprite.
That is my code and how I rotate the gun.I tried here to shoot a bullet ,but it shoots from a wrong starting point I would want to shoot a bullet from the end of the gun.
#Override
public boolean onSceneTouchEvent(Scene pScene, TouchEvent pSceneTouchEvent) {
if(pSceneTouchEvent.isActionMove()){
final float dX = pSceneTouchEvent.getX() - machine.getX();
final float dY = pSceneTouchEvent.getY() - machine.getY();
float angle = (float) Math.atan2(dX,dY);
float rotation = MathUtils.radToDeg(angle) + 1;
machine.setRotation(rotation - 90);
Log.d("BUG",machine.getRotation() + "");
if(machine.getRotation() >= 84 ){
machine.setRotation(84);
}
if(machine.getRotation() <= -54 ){
machine.setRotation(-54);
}
final int incrementXValue = 15;
long sElapsed = System.currentTimeMillis() - lastFire;
if(bulletsAmout > 0 && sElapsed > cooldownBetweenShoot * cdModd){
e = new Entity(0,machine.getY());
e.setRotation(getRotation());
SceneManager.getInstance().getCurrentScene().attachChild(e);
float x2 = (float) (machine.getSceneCenterCoordinates()[0] + machine.getWidth() /2 * Math.cos(machine.getRotation()));
float y2 = (float) (machine.getSceneCenterCoordinates()[1] + machine.getWidth() /2 * Math.sin(machine.getRotation()));
float realX = (float) (Math.toRadians(x2) + machine.getWidth());
realY = (float) Math.toRadians(y2);
bullets = new Sprite(realX,realY, resourcesManager.bulletRegion.deepCopy(), vbom){
protected void onManagedUpdate(float pSecondsElapsed) {
float currentX = this.getX();
this.setX(currentX + incrementXValue);
super.onManagedUpdate(pSecondsElapsed);
}
};
bullets.setScale(0.06f);
e.attachChild(bullets);
projectilesToBeAdded.add(bullets);
bulletsAmout--;
lastFire = System.currentTimeMillis();
setBulletsText(bulletsAmout);
resourcesManager.pistolSound.play();
}
return true;
}
return false;
}

Assuming you are using GLES2-AnchorCenter:
You can position the bullet by setting it to the position of the end of the gun that you can get by calling gun.convertLocalToSceneCoordinates(gunMuzzleX, gunMuzzleY).
Then set the bullets rotation to the rotation of the gun.
apply velocity to the bullet. Calculate the speed-vector as follows FloatMath.sin(rotationOfBulletInRadians) * speed and FloatMath.cos(rotationOfBulletInRadians) * speed.
Be aware that you have to pass the rotation in radians to the sin and cos function NOT in degrees!

So I found how to fix that.
The problem is in this line of code :
e = new Entity(0,machine.getY());
Should be :
e = new Entity(machine.getX() - (machine.getHeight() / 2),machine.getY())

Related

Android Gyroscope for tilting

Thanks in advance for your help first.
I have found so many examples using Gyroscope. But I couldn't find adequate one for me.
I'd like to make a simple quiz game that do actions when I tilt VM to 90 degrees forward and backward. Many examples said I might use "pitch" value of Gyroscope. Could you give some advices for me??
I have done a similar thing where i need draw a rectangle with includes nearby places and must point it to the place and show details.
public void onSensorChanged(SensorEvent event) {
final Handler handler = new Handler();
switch (event.sensor.getType()) {
case Sensor.TYPE_ACCELEROMETER:
mAcceleromterReading =
SensorUtilities.filterSensors(event.values, mAcceleromterReading);
break;
case Sensor.TYPE_MAGNETIC_FIELD:
mMagnetometerReading =
SensorUtilities.filterSensors(event.values, mMagnetometerReading);
break;
float[] orientation =
SensorUtilities.computeDeviceOrientation(mAcceleromterReading, mMagnetometerReading);
if (orientation != null) {
float azimuth = (float) Math.toDegrees(orientation[0]);
if (azimuth < 0) {
azimuth += 360f;
}
// Convert pitch and roll from radians to degrees
float pitch = (float) Math.toDegrees(orientation[1]);
float roll = (float) Math.toDegrees(orientation[2]);
if (abs(pitch - pitchPrev) > PITCH_THRESHOLD && abs(roll - rollPrev) > ROLL_THRESHOLD
&& abs(azimuth - azimuthPrev) > AZIMUTH_THRESHOLD) { // && abs(roll - rollPrev) > rollThreshold
if (DashplexManager.getInstance().mlocation != null) {
mOverlayDisplayView.setHorizontalFOV(mPreview.getHorizontalFOV());
mOverlayDisplayView.setVerticalFOV(mPreview.getVerticalFOV());
mOverlayDisplayView.setAzimuth(azimuth);
mOverlayDisplayView.setPitch(pitch);
mOverlayDisplayView.setRoll(roll);
// Update the OverlayDisplayView to red raw when sensor dataLogin changes,
// redrawing only when the camera is not pointing straight up or down
if (pitch <= 75 && pitch >= -75) {
//Log.d("issueAR", "invalidate: ");
mOverlayDisplayView.invalidate();
}
}
pitchPrev = pitch;
rollPrev = roll;
azimuthPrev = azimuth;
}
}
computeDeviceOrientation method
public static float[] computeDeviceOrientation(float[] accelerometerReading, float[] magnetometerReading) {
if (accelerometerReading == null || magnetometerReading == null) {
return null;
}
final float[] rotationMatrix = new float[9];
SensorManager.getRotationMatrix(rotationMatrix, null, accelerometerReading, magnetometerReading);
// Remap the coordinates with the camera pointing along the Y axis.
// This way, portrait and landscape orientation return the same azimuth to magnetic north.
final float cameraRotationMatrix[] = new float[9];
SensorManager.remapCoordinateSystem(rotationMatrix, SensorManager.AXIS_X,
SensorManager.AXIS_Z, cameraRotationMatrix);
final float[] orientationAngles = new float[3];
SensorManager.getOrientation(cameraRotationMatrix, orientationAngles);
// Return a float array containing [azimuth, pitch, roll]
return orientationAngles;
}
onDraw method
#SuppressLint("DrawAllocation")
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
// Log.d("issueAR", "onDraw: ");
// Log.d("issueAR", "mVerticalFOV: "+mVerticalFOV+" "+"mHorizontalFOV"+mHorizontalFOV);
// Get the viewports only once
if (!mGotViewports && mVerticalFOV > 0 && mHorizontalFOV > 0) {
mViewportHeight = canvas.getHeight() / mVerticalFOV;
mViewportWidth = canvas.getWidth() / mHorizontalFOV;
mGotViewports = true;
//Log.d("onDraw", "mViewportHeight: " + mViewportHeight);
}
if (!mGotViewports) {
return;
}
// Set the paints that remain constant only once
if (!mSetPaints) {
mTextPaint.setTextAlign(Paint.Align.LEFT);
mTextPaint.setTextSize(getResources().getDimensionPixelSize(R.dimen.canvas_text_size));
mTextPaint.setColor(Color.WHITE);
mOutlinePaint.setStyle(Paint.Style.STROKE);
mOutlinePaint.setStrokeWidth(mOutline);
mBubblePaint.setStyle(Paint.Style.FILL);
mSetPaints = true;
}
// Center of view
float x = canvas.getWidth() / 2;
float y = canvas.getHeight() / 2;
/*
* Uncomment line below to allow rotation of display around the center point
* based on the roll. However, this "feature" is not very intuitive, and requires
* locking device orientation to portrait or changes the sensor rotation matrix
* on device rotation. It's really quite a nightmare.
*/
//canvas.rotate((0.0f - mRoll), x, y);
float dy = mPitch * mViewportHeight;
if (mNearbyPlaces != null) {
//Log.d("OverlayDisplayView", "mNearbyPlaces: "+mNearbyPlaces.size());
// Iterate backwards to draw more distant places first
for (int i = mNearbyPlaces.size() - 1; i >= 0; i--) {
NearbyPlace nearbyPlace = mNearbyPlaces.get(i);
float xDegreesToTarget = mAzimuth - nearbyPlace.getBearingToPlace();
float dx = mViewportWidth * xDegreesToTarget;
float iconX = x - dx;
float iconY = y - dy;
if (isOverlapping(iconX, iconX).isOverlapped()) {
PointF point = calculateNewXY(new PointF(iconX, iconY + mViewportHeight));
iconX = point.x;
iconY = point.y;
}
nearbyPlace.setIconX(iconX);
nearbyPlace.setIconY(iconY);
Bitmap icon = getIcon(nearbyPlace.getIcon_id());
float width = icon.getWidth() + mTextPaint.measureText(nearbyPlace.getName()) + mMargin;
RectF recf=new RectF(iconX, iconY, width, icon.getHeight());
nearbyPlace.setRect(recf);
float angleToTarget = xDegreesToTarget;
if (xDegreesToTarget < 0) {
angleToTarget = 360 + xDegreesToTarget;
}
if (angleToTarget >= 0 && angleToTarget < 90) {
nearbyPlace.setQuadrant(1);
mQuad1Places.add(nearbyPlace);
} else if (angleToTarget >= 90 && angleToTarget < 180) {
nearbyPlace.setQuadrant(2);
mQuad2Places.add(nearbyPlace);
} else if (angleToTarget >= 180 && angleToTarget < 270) {
nearbyPlace.setQuadrant(3);
mQuad3Places.add(nearbyPlace);
} else {
nearbyPlace.setQuadrant(4);
mQuad4Places.add(nearbyPlace);
}
//Log.d("TAG", " - X: " + iconX + " y: " + iconY + " angle: " + angleToTarget + " display: " + nearbyPlace.getIcon_id());
}
drawQuadrant(mQuad1Places, canvas);
drawQuadrant(mQuad2Places, canvas);
drawQuadrant(mQuad3Places, canvas);
drawQuadrant(mQuad4Places, canvas);
}
}
It doesnot contain full code, but you may understand how pitch and azimuth with roll is used.. Best of luck

Libgdx: Moving a rotated perspective camera

I am developing an android app which visualize the map of an environment and currently i am using libgdx to draw the map, also like any map application the user should be capable of zoom, rotate and moving the map,
I have developed a GestureHandler class which implements GestureListener interface and interacts with a PerspectiveCamera(since i will use 3d components in the future):
#Override
public boolean pan(float x, float y, float deltaX, float deltaY) {
float tempX = (mapView.getCamera().position.x - deltaX * 0.5f);
float tempY = (mapView.getCamera().position.y + deltaY * 0.5f);
mapView.getCamera().position.set(
MathUtils.lerp(mapView.getCamera().position.x, tempX, mapView.getCamera().fieldOfView / 100),
MathUtils.lerp(mapView.getCamera().position.y, tempY, mapView.getCamera().fieldOfView / 100),
mapView.getCamera().position.z);
mapView.getCamera().update();
return false;
}
float initialDistance = 0;
float initialAngle = 0;
float distance = 0;
private void zoom(Vector2 initialPointer1, Vector2 initialPointer2, Vector2 pointer1, Vector2 pointer2)
{
initialDistance = initialPointer1.dst(initialPointer2);
float iDeltaX = initialPointer2.x - initialPointer1.x;
float iDeltaY = initialPointer2.y - initialPointer1.y;
initialAngle = (float)Math.atan2((double)iDeltaY,(double)iDeltaX) * MathUtils.radiansToDegrees;
if(initialAngle < 0)
initialAngle = 360 - (-initialAngle);
distance = initialPointer1.dst(pointer2);
float deltaX = pointer2.x - initialPointer1.x;
float deltaY = pointer2.y - initialPointer1.y;
newAngle = (float)Math.atan2((double)deltaY,(double)deltaX) * MathUtils.radiansToDegrees;
if(newAngle < 0)
newAngle = 360 - (-newAngle);
//Log.e("test", distance + " " + initialDistance);
//Log.e("test", newAngle + " " + initialAngle);
float ratio = initialDistance/distance;
mapView.getCamera().fieldOfView = MathUtils.clamp(initialZoomScale * ratio, 1f, 100.0f);
Log.e("zoom", String.valueOf(mapView.getCamera().fieldOfView));
mapView.getCamera().update();
}
#Override
public boolean pinch(Vector2 initialPointer1, Vector2 initialPointer2, Vector2 pointer1, Vector2 pointer2) {
zoom(initialPointer1, initialPointer2, pointer1, pointer2);
float delta1X = pointer2.x - pointer1.x;
float delta1Y = pointer2.y - pointer1.y;
newAngle = (float)Math.atan2((double)delta1Y,(double)delta1X) * MathUtils.radiansToDegrees;
if(newAngle < 0)
newAngle = 360 - (-newAngle);
System.out.println("new "+newAngle);
if(newAngle - currentAngle >= 0.01000f)
{
System.out.println("Increasing");
mapView.getCamera().rotate(0.5f,0,0,1);
}
else if(newAngle - currentAngle <= -0.010000f) {
System.out.println("DEcreasing");
mapView.getCamera().rotate(-0.5f,0,0,1);
}
if(Math.abs(newAngle - currentAngle) >= 0.01000f)
{
currentAngle = newAngle;
}
return true;
}
Everything is fine until as far as i don't rotate the camera, just like this unsolved similar question after rotating the camera, movements will be affected by applied rotation.Any help specially sample codes?
Edit:
After lots of efforts i finally solved it,
As Tenfour04 said in his answer i had to use two separate matrices for transformation and rotations, and finally set the result of their multiplication to view matrix of camera using:
camera.view.set(position).mul(orientation);
Also the most important thing is to set the Transformation Matrix of my batch to camera.view:
batch.setTransformationMatrix(camera.view)
Instead of applying the gestures directly to the camera, apply them to a pair of Matrix4's that you use to store the orientation and position separately. Then in the render method, multiply the two matrices and apply them to your camera's view.
In the render() method:
camera.view.set(orientation).mul(position); //Might need to swap orientation/position--don't remember.
camera.update();
Your zoom method is fine because field of view affects the camera's projection matrix rather than its view matrix.

How to determine positions to draw lines on a screen with AndEngine

I have a screen (480x800), M(mx, my) is a static point, and N(nx,ny) is a dynamic point on screen. Position of N(nx, ny) depends position of touch. I want to determine position of P(?,?) and Q(?,?) to draw line 1 and line 2. line 2 is reflective line 1.
This is my code:
private Line l2;
#Override
public boolean onSceneTouchEvent(final Scene pScene,
final TouchEvent pSceneTouchEvent) {
if (this.mPhysicsWorld != null) {
switch (pSceneTouchEvent.getAction()) {
case TouchEvent.ACTION_DOWN:
// Get position
p1x = pSceneTouchEvent.getX();
p1y = pSceneTouchEvent.getY();
return true;
case TouchEvent.ACTION_MOVE:
// Remove instance of the old line
mScene.detachChild(l2);
p3x = pSceneTouchEvent.getX();
p3y = pSceneTouchEvent.getY();
Rectangle testR = new Rectangle(CAMERA_WIDTH / 2,
CAMERA_HEIGHT / 2, 20, 20,
getVertexBufferObjectManager());
l2 = new Line(CAMERA_WIDTH / 2, CAMERA_HEIGHT / 2, p3x, p3y,
getVertexBufferObjectManager());
l2.setColor(new Color(223f / 255f, 118f / 255f, 43f / 255f));
l2.setLineWidth(5);
mScene.attachChild(l2);
return true;
}
return false;
}
return false;
}
If you have other ways to resolve my issue. Please share with me. Thanks.
I didn't program with AndEngine for a while, but this isn't about AndEngine so I can give you a psedu code to solve your problem.
1) Check that nx < mx
2) Calculate the slope of line 1 :
line1slope = (my-ny)/(mx-nx)
3) Find P coordinates using the equation : y-y1 = m(x-x1)
Where m = line1slope
y1 = my
x1 = mx
y = 480 (P's y coordinate) ( if line1slope > 0 then y = 0)
And then you can find your x ( which is P's x coordinate)
line2slope = -1 * line1slope because they are reflective
Now again you need to find Q (You know the X = 0 so you need to find only the Y coordinate)
using the equation : y-y1 = m(x-x1)
Where m = line2slope
y1 = py
x1 = px
x = 0
And then you can find your y coordinate(which is Q's y coordinate)
Hope it helps.

How to keep a circle inside another circle android view control

I am trying to create a pad-like view in android. I got a circle that follows user's gestures and I am using distance to keep the circle of going outside the main circle of the pad control.
My problem is I want the circle to keep following the gesture, but to stay inside of the main circle. I am using the formula for finding a point using angle and radius, but it does some funky stuff.
I am translating the canvas, so that the center of the main circle is at 0, 0.
Here is the code:
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
canvas.translate(this.mainRadius, this.mainRadius);
canvas.drawCircle(0, 0, this.mainRadius, this.debugPaint);
canvas.drawCircle(this.handleX, this.handleY, this.handleRadius, this.handlePaint);
}
private void translateHandle(MotionEvent event) {
int x = (int) (event.getX() - this.mainRadius);
int y = (int) (event.getY() - this.mainRadius);
double distance = distanceFromCenter(x, y);
if (distance <= this.maxDistance) {
this.handleX = x;
this.handleY = y;
} else {
float angle = (float) Math.toDegrees(Math.atan2(y, x));
if (angle < 0)
angle += 360;
this.handleX = (int) ((this.mainRadius - this.handleRadius) * Math.cos(angle));
this.handleY = (int) ((this.mainRadius - this.handleRadius) * Math.sin(angle));
}
//onTranslateHandle(distance);
}
And here is the funky stuff in a gif image:
I cannot verify this change into your code snippet but do hope it gives some idea how to proceed further anyway;
private void translateHandle(MotionEvent event) {
float x = event.getX() - this.mainRadius;
float y = event.getY() - this.mainRadius;
double distance = distanceFromCenter(x, y);
if (distance > this.maxDistance) {
// If distance is i.e 2.0 and maxDistance is 1.0 ==> adjust is 0.5
// which repositions x and y making distance 1.0 maintaining direction
double adjust = this.maxDistance / distance;
x = (float)(x * adjust);
y = (float)(y * adjust);
}
this.handleX = (int)x;
this.handleY = (int)y;
}
I can update the answer where needed if this does not give any useful results.

Following a straight line (via Path?)

I'm working on a game which will use projectiles. So I've made a Projectile class and a new instance is created when the user touches the screen:
#Override
public boolean onTouch(View v, MotionEvent e){
float touch_x = e.getX();
float touch_y = e.getY();
new Projectile(touch_x, touch_y);
}
And the Projectile class:
public class Projectile{
float target_x;
float target_y;
Path line;
public Projectile(float x, float y){
target_x = x;
target_y = y;
line = new Path();
line.moveTo(MyGame.mPlayerXPos, MyGame.mPlayerYPos);
line.lineTo(target_x, target_y);
}
}
So this makes a Path with 2 points, the player's position and and touch coords. My question is - How can you access points on this line? For example, if I wanted to get the x,y coords of the Projectile at the half point of the line, or the point the Projectile would be at after 100 ticks (moving at a speed of X pixels/tick)?
I also need the Projectile to continue moving after it reaches the final point.. do I need to use line.addPath(line) to keep extending the Path?
EDIT
I managed to get the Projectiles moving in a straight line, but they're going in strange directions. I had to fudge some code up:
private void moveProjectiles(){
ListIterator<Projectile> it = Registry.proj.listIterator();
while ( it.hasNext() ){
Projectile p = it.next();
p.TimeAlive++;
double dist = p.TimeAlive * p.Speed;
float dx = (float) (Math.cos(p.Angle) * dist);
float dy = (float) (Math.sin(p.Angle) * dist);
p.xPos += dx;
p.yPos += -dy;
}
}
The Angle must be the problem.. I'm using this method, which works perfectly:
private double getDegreesFromTouchEvent(float x, float y){
double delta_x = x - mCanvasWidth/2;
double delta_y = mCanvasHeight/2 - y;
double radians = Math.atan2(delta_y, delta_x);
return Math.toDegrees(radians);
}
However, it returns 0-180 for touches above the center of the screen, and 0 to -180 for touches below. Is this a problem?
The best way to model this is with parametric equations. No need to use trig functions.
class Path {
private final float x1,y1,x2,y2,distance;
public Path( float x1, float y1, float x2, float y2) {
this.x1 = x1;
this.y1 = y1;
this.x2 = x2;
this.y2 = y2;
this.distance = Math.sqrt( (x2-x1)*(x2-x1)+(y2-y1)*(y2-y1));
}
public Point position( float t) {
return new Point( (1-t)*x1 + t*x2,
(1-t)*y1 + t*y2);
}
public Point position( float ticks, float speed) {
float t = ticks * speed / distance;
return position( t);
}
}
Path p = new Path(...);
// get halfway point
p.position( 0.5);
// get position after 100 ticks at 1.5 pixels per tick
p.position( 100, 1.5);
From geometry, if it's a straight line you can calculate any point on it by using polar coordinates.
If you find the angle of the line:
ang = arctan((target_y - player_y) / (target_x - player_x))
Then any point on the line can be found using trig:
x = cos(ang) * dist_along_line
y = sin(ang) * dist_along_line
If you wanted the midpoint, then you just take dist_along_line to be half the length of the line:
dist_along_line = line_length / 2 = (sqrt((target_y - player_y)^2 + (target_x - player_x)^2)) / 2
If you wanted to consider the point after 100 ticks, moving at a speed of X pixels / tick:
dist_along_line = 100 * X
Hopefully someone can comment on a way to do this more directly using the android libs.
First of all, the Path class is to be used for drawing, not for calculation of the projectile location.
So your Projectile class could have the following attributes:
float positionX;
float positionY;
float velocityX;
float velocityY;
The velocity is calculated from the targetX, targetY, playerX and playerY like so:
float distance = sqrt(pow(targetX - playerX, 2)+pow(targetY - playerY, 2))
velocityX = (targetX - playerX) * speed / distance;
velocityY = (targetY - playerY) * speed / distance;
Your position after 20 ticks is
x = positionX + 20 * velocityX;
y = positionY + 20 * velocityY;
The time it takes to reach terget is
ticksToTarget = distance / velocity;
Location of halp way point is
halfWayX = positionX + velocityX * (tickToTarget / 2);
halfWayY = positionY + velocityY * (tickToTarget / 2);

Categories

Resources