I got a 3D spaceship that moves forward and backward in the 3D scene correctly but the rightward and leftward movements are not right and what the A and D buttons do seem to vary with the camera position. This is the listener code which works for buttons W (forward) and S (backward) while buttons A and D don't do exactly what they should.
When I start the 3D space scene the steering of the spaceship is working and the buttons A and D move the spaceship left and right but after a changed the camera and rotated the view, the buttons A and D are still opposite directions but not to the left and right but depend on the camera's position.
public void onAnalog(String name, float value, float tpf) {
// computing the normalized direction of the cam to move the node
int movement = 80000;
int rotation = 1;
direction.set(cam.getDirection()).normalizeLocal();
if (name.equals("moveForward")) {
direction.multLocal(movement * tpf);
ufoNode.move(direction);
}
if (name.equals("moveBackward")) {
direction.multLocal(-movement * tpf);
ufoNode.move(direction);
}
if (name.equals("moveRight")) {
direction.crossLocal(Vector3f.UNIT_Y).multLocal(movement * tpf);
ufoNode.move(direction);
}
if (name.equals("moveLeft")) {
direction.crossLocal(Vector3f.UNIT_Y).multLocal(-movement * tpf);
ufoNode.move(direction);
}
if (name.equals("rotateRight") && rotate) {
ufoNode.rotate(0, 1 * tpf, 0);
}
if (name.equals("rotateLeft") && rotate) {
ufoNode.rotate(0, -1 * tpf, 0);
}
if (name.equals("rotateUp") && rotate) {
ufoNode.rotate(0, 0, -1 * tpf);
}
if (name.equals("rotateDown") && rotate) {
ufoNode.rotate(0, 0, 1 * tpf);
}
}
Can you help me and tell me what should be done to fix the right and left movements? The entire code is
public class SpaceStation extends SimpleApplication implements AnalogListener,
ActionListener {
private PlanetAppState planetAppState;
private Geometry mark;
private Node ufoNode;
private Node spaceStationNode;
private Node jumpgateNode;
private Node jumpgateNode2;
private BetterCharacterControl ufoControl;
CameraNode camNode;
boolean rotate = false;
Vector3f direction = new Vector3f();
private BulletAppState bulletAppState;
public static void main(String[] args) {
AppSettings settings = new AppSettings(true);
settings.setResolution(1024, 768);
SpaceStation app = new SpaceStation();
app.setSettings(settings);
// app.showSettings = true;
app.start();
}
#Override
public void simpleInitApp() {
// Only show severe errors in log
java.util.logging.Logger.getLogger("com.jme3").setLevel(
java.util.logging.Level.SEVERE);
bulletAppState = new BulletAppState();
bulletAppState.setThreadingType(BulletAppState.ThreadingType.PARALLEL);
stateManager.attach(bulletAppState);
bulletAppState.setDebugEnabled(false);
DirectionalLight sun = new DirectionalLight();
sun.setDirection(new Vector3f(-.1f, 0f, -1f));
sun.setColor(new ColorRGBA(0.75f, 0.75f, 0.75f, 1.0f));
rootNode.addLight(sun);
// Add sky
Node sceneNode = new Node("Scene");
sceneNode.attachChild(Utility.createSkyBox(this.getAssetManager(),
"Textures/blue-glow-1024.dds"));
rootNode.attachChild(sceneNode);
// Create collision test mark
Sphere sphere = new Sphere(30, 30, 5f);
mark = new Geometry("mark", sphere);
Material mark_mat = new Material(assetManager,
"Common/MatDefs/Misc/Unshaded.j3md");
mark_mat.setColor("Color", ColorRGBA.Red);
mark.setMaterial(mark_mat);
// Add planet app state
planetAppState = new PlanetAppState(rootNode, sun);
stateManager.attach(planetAppState);
// Add planet
FractalDataSource planetDataSource = new FractalDataSource(4);
planetDataSource.setHeightScale(900f);
Planet planet = Utility.createEarthLikePlanet(getAssetManager(),
293710.0f, null, planetDataSource);
planetAppState.addPlanet(planet);
rootNode.attachChild(planet);
// Add moon
FractalDataSource moonDataSource = new FractalDataSource(5);
moonDataSource.setHeightScale(300f);
Planet moon = Utility.createMoonLikePlanet(getAssetManager(), 50000,
moonDataSource);
planetAppState.addPlanet(moon);
rootNode.attachChild(moon);
moon.setLocalTranslation(new Vector3f(10f, 10f, 505000f));//-950000f, 0f, 0f);
// add saucer
ufoNode = (Node) assetManager.loadModel("usaucer_v01.j3o");
ufoNode.setLocalScale(100f);
ufoNode.setLocalTranslation((new Vector3f(1000f, -1000f, 328000f)));
jumpgateNode = (Node) assetManager.loadModel("JumpGate.j3o");
jumpgateNode.setLocalScale(10000f);
jumpgateNode.setLocalTranslation((new Vector3f(10f, 10f, 708000f)));
spaceStationNode = (Node) assetManager.loadModel("SpaceStation.j3o");
spaceStationNode.setLocalScale(4000f);
spaceStationNode.setLocalTranslation((new Vector3f(10000f, -10f, 425000f)));
jumpgateNode2 = (Node) assetManager.loadModel("JumpGate.j3o");
jumpgateNode2.setLocalScale(10000f);
jumpgateNode2.setLocalTranslation((new Vector3f(10f, 10f, 798300f)));
/* This quaternion stores a 180 degree rolling rotation */
// Quaternion roll180 = new Quaternion();
// roll180.fromAngleAxis(FastMath.PI, new Vector3f(0, 0, 1));
/* The rotation is applied: The object rolls by 180 degrees. */
// ufoNode.setLocalRotation(roll180);
rootNode.attachChild(jumpgateNode);
rootNode.attachChild(jumpgateNode2);
rootNode.attachChild(spaceStationNode);
// creating the camera Node
camNode = new CameraNode("CamNode", cam);
// Setting the direction to Spatial to camera, this means the camera
// will copy the movements of the Node
camNode.setControlDir(ControlDirection.SpatialToCamera);
// attaching the camNode to the teaNode
ufoNode.attachChild(camNode);
// setting the local translation of the cam node to move it away a bit
camNode.setLocalTranslation(new Vector3f(-40, 0, 0));
// setting the camNode to look at the teaNode
camNode.lookAt(ufoNode.getLocalTranslation(), Vector3f.UNIT_Y);
// disable the default 1st-person flyCam (don't forget this!!)
ufoControl = new BetterCharacterControl(100000f, 80000f, 5000f);// (2, 4, 0.5f);
// radius (meters), height (meters), gravity (mass)
//ufoNode.addControl(ufoControl);
//rootNode.attachChild(ninjaNode);
//bulletAppState.getPhysicsSpace().add(ufoControl);
//getPhysicsSpace().add(ufoControl);
rootNode.attachChild(ufoNode);
flyCam.setEnabled(false);
registerInput();
}
private PhysicsSpace getPhysicsSpace() {
return bulletAppState.getPhysicsSpace();
}
public void registerInput() {
inputManager.addMapping("moveForward", new KeyTrigger(keyInput.KEY_UP),
new KeyTrigger(keyInput.KEY_W));
inputManager.addMapping("moveBackward", new KeyTrigger(
keyInput.KEY_DOWN), new KeyTrigger(keyInput.KEY_S));
inputManager.addMapping("moveRight",
new KeyTrigger(keyInput.KEY_RIGHT), new KeyTrigger(
keyInput.KEY_D));
inputManager.addMapping("moveLeft", new KeyTrigger(keyInput.KEY_LEFT),
new KeyTrigger(keyInput.KEY_A));
inputManager.addMapping("toggleRotate", new MouseButtonTrigger(
MouseInput.BUTTON_LEFT));
inputManager.addMapping("rotateRight", new MouseAxisTrigger(
MouseInput.AXIS_X, true));
inputManager.addMapping("rotateLeft", new MouseAxisTrigger(
MouseInput.AXIS_X, false));
inputManager.addMapping("rotateUp", new MouseAxisTrigger(
MouseInput.AXIS_Y, true));
inputManager.addMapping("rotateDown", new MouseAxisTrigger(
MouseInput.AXIS_Y, false));
inputManager.addListener(this, "moveForward", "moveBackward",
"moveRight", "moveLeft");
inputManager.addListener(this, "rotateRight", "rotateLeft", "rotateUp",
"rotateDown", "toggleRotate");
// Toggle mouse cursor
inputManager.addMapping("TOGGLE_CURSOR", new MouseButtonTrigger(
MouseInput.BUTTON_LEFT), new KeyTrigger(KeyInput.KEY_SPACE));
inputManager.addListener(actionListener, "TOGGLE_CURSOR");
// Toggle wireframe
inputManager.addMapping("TOGGLE_WIREFRAME", new KeyTrigger(
KeyInput.KEY_T));
inputManager.addListener(actionListener, "TOGGLE_WIREFRAME");
// Collision test
inputManager.addMapping("COLLISION_TEST", new MouseButtonTrigger(
MouseInput.BUTTON_RIGHT));
inputManager.addListener(actionListener, "COLLISION_TEST");
}
public void onAnalog(String name, float value, float tpf) {
// computing the normalized direction of the cam to move the node
int movement = 80000;
int rotation = 1;
direction.set(cam.getDirection()).normalizeLocal();
if (name.equals("moveForward")) {
direction.multLocal(movement * tpf);
ufoNode.move(direction);
}
if (name.equals("moveBackward")) {
direction.multLocal(-movement * tpf);
ufoNode.move(direction);
}
if (name.equals("moveRight")) {
direction.crossLocal(Vector3f.UNIT_Y).multLocal(movement * tpf);
ufoNode.move(direction);
}
if (name.equals("moveLeft")) {
direction.crossLocal(Vector3f.UNIT_Y).multLocal(-movement * tpf);
ufoNode.move(direction);
}
if (name.equals("rotateRight") && rotate) {
ufoNode.rotate(0, 1 * tpf, 0);
}
if (name.equals("rotateLeft") && rotate) {
ufoNode.rotate(0, -1 * tpf, 0);
}
if (name.equals("rotateUp") && rotate) {
ufoNode.rotate(0, 0, -1 * tpf);
}
if (name.equals("rotateDown") && rotate) {
ufoNode.rotate(0, 0, 1 * tpf);
}
}
public void onAction(String name, boolean keyPressed, float tpf) {
// toggling rotation on or off
if (name.equals("toggleRotate") && keyPressed) {
rotate = true;
inputManager.setCursorVisible(false);
}
if (name.equals("toggleRotate") && !keyPressed) {
rotate = false;
inputManager.setCursorVisible(true);
}
if (name.equals("TOGGLE_CURSOR") && !keyPressed) {
if (inputManager.isCursorVisible()) {
inputManager.setCursorVisible(false);
} else {
inputManager.setCursorVisible(true);
}
}
if (name.equals("TOGGLE_WIREFRAME") && !keyPressed) {
for (Planet planet : planetAppState.getPlanets()) {
planet.toogleWireframe();
}
}
if (name.equals("COLLISION_TEST") && !keyPressed) {
CollisionResults results = new CollisionResults();
Ray ray = new Ray(cam.getLocation(), cam.getDirection());
// Test collision with closest planet's terrain only
planetAppState.getNearestPlanet().getTerrainNode()
.collideWith(ray, results);
System.out.println("----- Collisions? " + results.size() + "-----");
for (int i = 0; i < results.size(); i++) {
// For each hit, we know distance, impact point, name of
// geometry.
float dist = results.getCollision(i).getDistance();
Vector3f pt = results.getCollision(i).getContactPoint();
String hit = results.getCollision(i).getGeometry().getName();
System.out.println("* Collision #" + i);
System.out.println(" You shot " + hit + " at " + pt + ", "
+ dist + " wu away.");
}
if (results.size() > 0) {
// The closest collision point is what was truly hit:
CollisionResult closest = results.getClosestCollision();
// Let's interact - we mark the hit with a red dot.
mark.setLocalTranslation(closest.getContactPoint());
rootNode.attachChild(mark);
} else {
// No hits? Then remove the red mark.
rootNode.detachChild(mark);
}
}
}
private ActionListener actionListener = new ActionListener() {
public void onAction(String name, boolean pressed, float tpf) {
if (name.equals("TOGGLE_CURSOR") && !pressed) {
if (inputManager.isCursorVisible()) {
inputManager.setCursorVisible(false);
} else {
inputManager.setCursorVisible(true);
}
}
if (name.equals("TOGGLE_WIREFRAME") && !pressed) {
for (Planet planet : planetAppState.getPlanets()) {
planet.toogleWireframe();
}
}
if (name.equals("COLLISION_TEST") && !pressed) {
CollisionResults results = new CollisionResults();
Ray ray = new Ray(cam.getLocation(), cam.getDirection());
// Test collision with closest planet's terrain only
planetAppState.getNearestPlanet().getTerrainNode()
.collideWith(ray, results);
System.out.println("----- Collisions? " + results.size()
+ "-----");
for (int i = 0; i < results.size(); i++) {
// For each hit, we know distance, impact point, name of
// geometry.
float dist = results.getCollision(i).getDistance();
Vector3f pt = results.getCollision(i).getContactPoint();
String hit = results.getCollision(i).getGeometry()
.getName();
System.out.println("* Collision #" + i);
System.out.println(" You shot " + hit + " at " + pt + ", "
+ dist + " wu away.");
}
if (results.size() > 0) {
// The closest collision point is what was truly hit:
CollisionResult closest = results.getClosestCollision();
// Let's interact - we mark the hit with a red dot.
mark.setLocalTranslation(closest.getContactPoint());
rootNode.attachChild(mark);
} else {
// No hits? Then remove the red mark.
rootNode.detachChild(mark);
}
}
}
};
}
Going off your last comment, I am posting this as an answer (although I'm not exactly sure what to use as a cross vector.
When retrieving the cross vector, we are looking to get a perpendicular to the straight line out the front of the craft, and the vertical line that is perpendicular to the straight line, going vertically through the center of the craft.
I assume that direction is our forward-direction vector, in which case (regardless of view) we want to cross this with the vertical line that goes through the center of the craft. The crossLocal of these two vectors would be a perpendicular line to both, either going out of the left or right of the craft (regardless of camera or craft orientation).
for my code fix, I will assume craftSkewer is an imaginary skewer that runs through the center of the craft, vertically.
direction.crossLocal(craftSkewer.UNIT_Y).multLocal(movement * tpf);
I think the reason this works initially is due to the UNIT_Y returning 0 - But after moving craft or camera, it is recalculated incorrectly?
Related
I'm try the rotate the AR object in place use quaternion.axisAngle, but it's not working.
I just want to make a object rotate in place, like this.
This is my code.
//Right Rotation
ImageButton.OnTouchListener controll_BtnRigntRoation = new ImageButton.OnTouchListener() {
#Override
public boolean onTouch(View controllRightDown, MotionEvent event) {
if (controllRightDown == mRightRoation) {
ma.initModel();
for (int i=0; i<ma.infoArray.size(); i++) {
if (ma.infoArray.get(i).getNode().isSelected()) {
int finalI = i;
ma.arFragment.getArSceneView().getScene().addOnUpdateListener(frameTime -> {
Quaternion r1 = Quaternion.axisAngle(new Vector3(0, 0, 1), frameTime.getStartSeconds()* 180); //y 방향으로는 안됨..
ma.infoArray.get(finalI).getNode().setLocalRotation(r1);
});
}
}
}
return false;
}
};
Please help me.
You most likely want to use a transformable node - this will allow you do the type of rotation I think you are looking for:
https://developers.google.com/sceneform/reference/com/google/ar/sceneform/ux/TransformableNode
Example of use:
var newAnchorNode:AnchorNode = AnchorNode(newAnchor)
anchorNode.setParent(arFragment.getArSceneView().getScene());
var transNode = TransformableNode(arFragment.transformationSystem)
//Rotate the node - i.e set the direction it is 'looking'
transNode.setLookDirection(Vector3(0f, xPoint, yPoint), topDirection)
//Set it's parent to the anchor you created and set
//the renderable
transNode.setParent(anchorNode);
transNode.setRenderable(renderable);
That sounds extremely philosophical doesn't it?
Anyways, I have a rather complex problem.
My main_activity class gathers all of the Zombies like so:
//Testing Runnable (used to compare the first zombie with the player)
private Runnable updateLocations = new Runnable(){
#Override
public void run(){
try {
while(true) {
image_player.getLocationInWindow(pLoc);
Zombie zoms = zombieCollection.next();
if(!zoms.equals(null)){
zoms.getZombieImage().getLocationInWindow(zLoc);
}
System.out.println("Zombie: x = " + zLoc[0] + "; y = " + zLoc[1]);
System.out.println("Player: x = " + pLoc[0] + "; y = " + pLoc[1]);
Thread.sleep(500);
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
};
My zombie class gathers information like so:
public class Zombie{
float X, Y;
int Width, Height;
Direction fdirc;
ImageView zImage;
Player player;
boolean dead;
int[] zLoc;
public Zombie(ImageView zImage, Player player){
zLoc = new int[2];
zImage.getLocationOnScreen(zLoc);
this.zImage = zImage;
this.X = zLoc[0];
this.Y = zLoc[1];
this.Width = zImage.getWidth();
this.Height = zImage.getHeight();
this.fdirc = Direction.EAST;
this.player = player;
this.dead = false;
Thread thread = new Thread(this.startZombieChase);
thread.start();
}
public ImageView getZombieImage(){
return zImage;
}
private Runnable startZombieChase = new Runnable() {
#Override
public void run() {
try {
while(!dead) {
moveTowardsPlayer();
Thread.sleep(10);
updateZombie.sendEmptyMessage(0);
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
};
private Handler updateZombie = new Handler(Looper.getMainLooper()) {
public void handleMessage(android.os.Message msg) {
/** Because the zombie should always be on top! **/
zImage.getLocationOnScreen(zLoc);
zImage.bringToFront();
zImage.setX(X);
zImage.setY(Y);
}
};
private void moveTowardsPlayer(){
int player_x = player.getPosition()[0];
int player_y = player.getPosition()[1];
l("Where is it in zombie class : player - " + player_x + " " + player_y + "zombie - " + X + " " + Y);
float compareX = player_x - (int)X;
float compareY = player_y - (int)Y;
// Y is closer, so we're moving horizontally.
if(Math.abs(compareX) < Math.abs(compareY)){
//Moving North
if(player_y > Y){
Y+=1;
}
//Moving South
else if(player_y < Y){
Y-=1;
}
}
// X is closer, so we're moving vertically.
else{
//Moving East
if(player_x > X){
X+=1;
}
//Moving West
else if(player_x < X){
X-=1;
}
}
}
public void l(Object string){
System.out.println("Log - " + string);
}
}
The problem I'm having is that it will move relative to a number (So, it does move relative to something) but, not the correct thing.
logcat tells me this:
Where is it in zombie class: player - 750 451 zombie - 750 451
Where it is in main_activity: player - 750 451 zombie - 792 619
Could anyone help me understand what I'm doing wrong?
The entire project is located here.
Zombies that moves away from the Brainz, must be an ill Zombie. We can't have that, now can we?
To have a function that moves the Zombie towards the non-zombie, you use a function, but that function makes use of variables that are not arguments, and there fore hard to find out where they come from. I'd go with something like this: (this is a bit verbose, but clearly shows what is happening)
/*
* Function to update the position of the Zombie, aka walk to the Player.
* #player_pos - Where's the Brainz at?
* #zombie_pos - Where am I?
* Might want to build it overloaded with an option for the speed.
*
* #return - We return the new Zombie pos.
*/
private double [] moveTowardsPlayer(double [] player_pos, double [] zombie_pos) {
// To make sure we don't override the old position, we copy values. (Java stuff)
double [] player_pos_old = player_pos.clone();
double [] zombie_pos_old = zombie_pos.clone();
// Let's get the new X pos for the Zombie
double left_or_right = player_pos_old[0] - zombie_pos_old[0]; // pos number is right, neg is left
double zombie_pos_new_x;
if (left_or_right > 0) { // Right
zombie_pos_new_x = player_pos_old[0] + zombie_speed;
} else { // Left - this way we make sure we are always getting nearer to the Brainz.
zombie_pos_new_x = player_pos_old[0] - zombie_speed;
}
// TODO: do the same for the Y pos.
// Bring it together
double [] zombie_pos_new = {zombie_pos_new_x, zombie_pos_new_y};
// One step closer to the Brainz!
return zombie_pos_new;
}
And use like:
double [] zombie_pos = moveTowardsPlayer([2, 2], [5, 4]);
this.X = zombie_pos[0]; // I'd advice to keep these together as one var.
this.Y = zombie_pos[1]; // But it's your game.
And then figure out when the Zombie gets the Brainz (or the Bullet)
this here is not correct:
if(!zoms.equals(null)){
if you are trying to check that zoms is not pointing to a null reference then do
if(zoms != null ){
In my game I have a Bullet class, which is in charge of making a new bullet every time the gun is fired. Upon creation the bullet is added to the Bullets class, which is in charge of keeping track of said bullet, along with the rest of the bullets. I have come across a strange behavior:
After killing an enemy, and then shooting once more, the new bullet has the following traits:
The bullet is the same one (as in the same code id) as the bullet
that killed the enemy. (I.E. if the id was:
com.badlogic.gdx.physics.box2d.Body#fc7157f, then it will be the
exact same id.)
The bullet will appear stuck in place, it's sprite not moving, but according to the game it will have a velocity, but the position remains the same. The only visible movement is when you enable the Box2DDebugRenderer, you can see the body move downwards until hitting the ground at which point he "teleports" back up and slowly falls back down.
The number of stuck bullets are equal to the number of enemies killed.
This is the bullet class:
public class Bullet {
private Body bullet;
public Bullet(final float force, final int bulletDmg, final Weapon weapon,
final World world) {
System.out.println("Position " + weapon.getPosition() + ", Angle: "
+ weapon.getAngle());
final BodyDef bulletDef = new BodyDef();
bulletDef.type = BodyDef.BodyType.DynamicBody;
bulletDef.angle = weapon.getAngle();
bulletDef.position.set(
weapon.getPosition().x
+ (float) (2.5 * MathUtils.cos(weapon.getAngle())),
weapon.getPosition().y
+ (float) (2.5 * MathUtils.sin(weapon.getAngle())));
bulletDef.angle = weapon.getAngle();
PolygonShape bulletShape_1 = new PolygonShape();
bulletShape_1.setAsBox(0.34375f, 0.34375f);
CircleShape bulletShape_2 = new CircleShape();
bulletShape_2.setPosition(new Vector2(0.34375f, 0));
bulletShape_2.setRadius(0.34375f);
final FixtureDef bulletFixture_1 = new FixtureDef();
bulletFixture_1.density = 1f;
bulletFixture_1.shape = bulletShape_1;
bulletFixture_1.friction = 0.25f;
bulletFixture_1.restitution = 0.75f;
final FixtureDef bulletFixture_2 = new FixtureDef();
bulletFixture_2.density = 1;
bulletFixture_2.shape = bulletShape_2;
bulletFixture_2.friction = 0.25f;
bulletFixture_2.restitution = 0.75f;
final Timer creationTimer = new Timer();
creationTimer.scheduleTask(new Task() {
#Override
public void run() {
if (!world.isLocked()) {
System.out.println(bullet);
bullet = world.createBody(bulletDef);
bullet.createFixture(bulletFixture_1);
bullet.createFixture(bulletFixture_2);
System.out.println(bullet);
bullet.applyForceToCenter(
force * MathUtils.cos(weapon.getAngle()), force
* MathUtils.sin(weapon.getAngle()), true);
Sprite sprite = new Sprite(new Texture(
"sprites\\Weapon\\bullet_standard.png"));
sprite.setSize(1.03125f, 0.6875f);
sprite.setOrigin((float) (sprite.getWidth() / 2 - 0.12f),
(float) (sprite.getHeight() / 2));
bullet.setUserData(sprite);
Bullets bullets = Bullets.getInstance(world);
bullets.addBullet(bullet);
bullets.setDmg(bulletDmg);
System.out.println("Create bullet number: " + bullet);
creationTimer.stop();
}
}
}, 0, 1);
creationTimer.start();
}
}
I have been facing this for quite some time now and can't figure out the problem, I would love some assistance with this. Thanks in advance!
Update 1:
I do not reuse any of the bullets created.
This is the code that handles collision with the enemy:
public void onCollision(final Body collidedBody, final String bodyHit,
final int index) {
assert instance != null;
final Timer timer = new Timer();
timer.scheduleTask(new Task() {
#Override
public void run() {
if (!world.isLocked()) {
Circles circles = Circles.getInstance();
if (bodyHit.equalsIgnoreCase("ground")) {
if (bulletGroundCollision.get(index) == 5) {
if (bullets.get(index) != null) {
world.destroyBody(bullets.get(index));
bullets.removeIndex(index);
bulletGroundCollision.removeIndex(index);
}
} else
bulletGroundCollision.set(index,
(bulletGroundCollision.get(index) + 1));
} else if (bodyHit.equalsIgnoreCase("enemy")) {
Circle enemy = circles
.findAccordingToCode(collidedBody);
enemy.damaged(bulletDmg);
System.out.println("Hit at: "
+ bullets.get(index).getPosition());
if (bullets.get(index) != null) {
world.destroyBody(bullets.get(index));
bullets.removeIndex(index);
bulletGroundCollision.removeIndex(index);
}
} else if (bodyHit.equalsIgnoreCase("player")) {
if (bullets.get(index) != null) {
world.destroyBody(bullets.get(index));
bullets.removeIndex(index);
bulletGroundCollision.removeIndex(index);
}
Square square = Square.getInstance(world);
square.damaged(bulletDmg);
}
timer.stop();
}
}
}, 0, 1);
timer.start();
}
The code for the bullet creation is already posted as the bullet class.
bullets - is an Array of bodies that are the bullets.
bulletGroundCollision - is an Array of ints which keeps track of how many times a bullet at i position (i.e. index), hit the ground.
Update 2
I had noticed that after the bullet gets stuck, the collision with the bullet does not happen according to the body, instead it is only when there is a collision with the sprite that a collision is triggered.
Your code is somewhat hard to read. However you need to make sure that after your enemy is dead, you need to update your bullet class again with the update method in your bullet class.
boolean enemyDead;
if(damage<=0)
{
bulletClass.updateBulletLocation();
}
I doesn't look like it to me that you are updating your bullet class after you kill the enemy, and because of this, the bullet stays where it is.
I am trying to create an Object that given an Image and Point it will trace the inside edge of that Image.
For simplicity the edges will always be of RGB Color Black.
i Define enums of RIGHT DOWN LEFT UP (Clockwise)
I start at Point p.
I move through the Pixels in the Image based on the current Direction starting with RIGHT.
if this is not a border Pixel i move my Direction back one step anti Clockwise. e.g (Left->DOWN)
if i cannot move my chosen direction i move to next direction.
i add the Point to my border array.
i do this till we return to the first border Pixel.
Thats the Plan...
So far i hit a snag when i have to go from UP to RIGHT but back to RIGHT again immediately after in order to keep the direction focused on the edge rather than turn back into the Image.
Ive tried using a boolean flag if UP is used, Directing the Next direction for right to be UP and Not DOWN.
Any guidance would be much appreciated.
I have the full Code below.
CODE:
package edgedection;
import static edgedection.EdgeDection.testImage;
import java.awt.Color;
import java.awt.Point;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.util.ArrayList;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.imageio.ImageIO;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JLabel;
/**
*
* #author Fionán
*/
public class EdgeDection {
/**
* #param args the command line arguments
*/
static BufferedImage testImage = null;
{
try {
testImage = ImageIO.read(this.getClass().getResourceAsStream("testImage2.png"));
} catch (IOException ex) {
Logger.getLogger(EdgeDection.class.getName()).log(Level.SEVERE, null, ex);
}
}
static enum DIRECTION {
RIGHT, DOWN, LEFT, UP, NOMOVE
}
BufferedImage bi;
int borderColor = Color.black.getRGB();
DIRECTION facing;
Point p;
ArrayList<Point> borders;
boolean upFlag = false;
int x = p.x;
int y = p.y;
public static void main(String[] args) {
int x = 150;
int y = 60;
//forcing instance for loading Images only.
EdgeDection test= new EdgeDection();
JFrame show = new JFrame();
show.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JLabel picLabel = new JLabel(new ImageIcon(testImage));
show.add(picLabel);
show.pack();
show.setVisible(true);
EdgeDection dector = new EdgeDection(testImage, new Point(x, y));
dector.start();
dector.highLightEdge();
show.repaint();
}
boolean canMove(DIRECTION d, Point p) {
switch (d) {
case RIGHT:
return bi.getRGB(p.x + 1, p.y) != borderColor;
case DOWN:
return bi.getRGB(p.x, p.y + 1) != borderColor;
case LEFT:
return bi.getRGB(p.x - 1, p.y) != borderColor;
//Deafult is up
case UP:
return bi.getRGB(p.x, p.y - 1) != borderColor;
default:
return false;
}
}
public EdgeDection(BufferedImage bi, Point p) {
this.facing = DIRECTION.RIGHT;
this.bi = bi;
this.p = p;
this.borders = new ArrayList<>();
}
public EdgeDection() {
}
DIRECTION getDirection() {
return null;
}
void addBorder(Point p) {
if(borders.isEmpty()){
x = p.x;
y = p.y;
}
borders.add(p);
}
void start() {
do {
System.out.println("Checking " + p.x + " " + p.y + facing);
if (canMove(facing, p)) {
if (upFlag) {
facing = DIRECTION.UP;
// p =new Point(p.x+1,p.y);
}
p = NextPointByDirection();
if(!upFlag) stepBackDirection();
if(upFlag)upFlag=false;
} else {
addBorder(p);
setNextDirection();
System.out.println("going " + facing + " border array size = "+ borders.size());
System.out.println("Up Flag status "+upFlag);
}
} while (facing != DIRECTION.NOMOVE && (p.x != x || p.y != y));
}
private void stepBackDirection() {
switch (facing) {
case RIGHT:
if(upFlag) {facing = DIRECTION.UP;}else{
facing = DIRECTION.RIGHT;
}
break;
case DOWN:
facing = DIRECTION.RIGHT;
break;
case LEFT:
facing = DIRECTION.DOWN;
break;
case UP:
facing = DIRECTION.LEFT;
}
}
private void setNextDirection() {
switch (facing) {
case RIGHT:
facing = DIRECTION.DOWN;
if (upFlag) {
facing = DIRECTION.UP;
upFlag = false;
}
return;
case DOWN:
facing = DIRECTION.LEFT;
return;
case LEFT:
facing = DIRECTION.UP;
return;
case UP:
upFlag = true;
facing = DIRECTION.RIGHT;
// upFlag = true;
// if (canMove(facing, new Point(p.x + 1, p.y - 1))){
// p = new Point(p.x + 1, p.y - 1);
//
// } ;
//
// if (upFlag) {
// facing = DIRECTION.RIGHT;
// }
}
}
private Point NextPointByDirection() {
// if (upFlag) {
// facing = DIRECTION.UP;
// upFlag = !upFlag;
// }
switch (facing) {
case RIGHT:
return new Point(p.x + 1, p.y);
case DOWN:
return new Point(p.x, p.y + 1);
case LEFT:
return new Point(p.x - 1, p.y);
default:
return new Point(p.x, p.y - 1);
}
}
private void print() {
for (Point p : borders) {
System.out.print(p.x + " " + p.y + " ");
}
}
void highLightEdge() {
for (Point p : borders) {
bi.setRGB(p.x, p.y, Color.RED.getRGB());
}
}
}
For anyone interested , i solved this problem with the use of a Stack.
pre-populate the stack with the order of directions to take.
Start moving in a direction.
if it can move direction is popped from stack
else
Hit a border
push that direction to the stack
add The border to the Set of borders
if border is already in set break loop else
turn 90 degree relative to the direction
I create a rectangle for my "line", it's a rotating 'laser sight'
public Rectangle getLaserBox() {
float lOriginX = (leon.getPosition().x + 0.27f);
float lOriginY = (leon.getPosition().y + 0.7f);
float lEndX = lOriginX + (float)Math.cos((leonAimLaserSprite.getRotation())/57) * 5f;
float lEndY = lOriginY + (float)Math.sin((leonAimLaserSprite.getRotation())/57) * 5f;
Rectangle laserBox = new Rectangle(lOriginX, lOriginY, lEndX, lEndY);
return laserBox;
}
Then I have a method that checks for overlap of the rectangles and is supposed to shorten the 'laser sight' sprite if overlap is detected. I call the laserCol() method in my render method for now (I know I'm breaking MVC, just trying to get it working), and my laserWidth is applied as the width of the laser sprite.
private float laserWidth;
public void laserCol() {
Vector2 laserOrigin = new Vector2(leon.getPosition().x + 0.55f, leon.getPosition().y + 0.7f);
boolean laserIsCol = false;
for (Tile t : world.getTiles()) { //pulling in tiles as t, from world method getTiles()
laserWidth = laserOrigin.dst(t.getPosition().x + 0.1f, t.getPosition().y + 0.7f);
if (Intersector.overlapRectangles(getLaserBox(), t.getBounds())) {
laserIsCol = true;
}
}
if (laserIsCol) {
for (Tile t : world.getTiles()) { //pulling in tiles as t, from world method getTiles()
laserWidth = laserOrigin.dst(t.getPosition().x, t.getPosition().y + t.getBounds().y);
}
}
if (!laserIsCol) {
laserWidth = 8f;
}
}
But as you can see in the screenshot, the laser does not shorten. I've looked at other examples but can't seem to understand a better way to do this.
So after adding the single object which I called thing in my code, I decided to check my sprite boundingbox I created and it looked like this.
After that, I changed some code, and am trying to use a ray, I've gotten it to work somewhat but it's not as close as I'd like, any suggestions?
public Ray getLaserRay() {
lOriginX = (leon.getPosition().x + 0.27f);
lOriginY = (leon.getPosition().y + 0.7f);
lEndX = lOriginX + (float)Math.cos((leonAimLaserSprite.getRotation())/57) * 10f;
lEndY = lOriginY + (float)Math.sin((leonAimLaserSprite.getRotation())/57) * 10f;
laserO = new Vector3(lOriginX, lOriginY, 0);
laserD = new Vector3(lEndX, lEndY, 0);
Ray laserRay = new Ray(laserO, laserD);
return laserRay;
}
private float laserWidth;
public void laserCol() {
Vector2 laserOrigin = new Vector2(leon.getPosition().x + 0.55f, leon.getPosition().y + 0.7f);
boolean laserIsCol = false;
if (Intersector.intersectRayBoundsFast(getLaserRay(), thing.getBB())) {
laserIsCol = true;
}
if (laserIsCol) {
laserWidth = laserOrigin.dst(thing.getPosition().x, thing.getPosition().y);
}
if (!laserIsCol) {
laserWidth = 10f;
}
}
I ended up using 2 line segments to get the collision detection to work. I made one for the laser sight, and one for my object(enemy), that extended from the lower x point to the top x point. Basically the same code except I used the segment intersector from libgdx.
Anyone have an idea of how to make a bullet or damage happen at laser sight spot?
Without having more information I just can guess, but I assume the problem might be that you're calculating the width using all the tiles in your list/array. Instead, you should just use the tile the laser collides with to calculate the width.
Something like this:
laserWidth = 8f; //default if no collision is found
for (Tile t : world.getTiles()) { //pulling in tiles as t, from world method getTiles()
if (Intersector.overlapRectangles(getLaserBox(), t.getBounds())) {
laserWidth = laserOrigin.dst(t.getPosition().x, t.getPosition().y + t.getBounds().y);
break;
}
}
Please note that I just reused your code, I don't know if this is correct or if there are some wrong calculations in it. As I said in my comment, you should debug the calculations and look where they start to get wrong.