www.jpct.net

jPCT - a 3d engine for Java => Support => Topic started by: AGP on November 06, 2008, 05:40:52 pm

Title: Ship Lasers After Rotation
Post by: AGP on November 06, 2008, 05:40:52 pm
The way the ship flies forward is it's always chasing targetCone. After the following method flips firing to true, the game loop makes the lasers chase after the laserTarget variables using the very same method that always works for the ship. What's weird is that the following code only works before the ship is rotated. Then, for some bizarre reason, the laserTargets start showing up in the wrong place. It's worth mentioning that the laser cylinders are ALWAYS aligned to the ship, but they end up flying sideways after the first rotation.

Code: [Select]
      private void fireLasers() {//SETS IT UP, THEN FLIPS firing TO TRUE SO THAT THE GAME LOOP TAKES IT FROM THERE
targetCone.calcCenter();
laser1 = Primitives.getCylinder(16, 4f, 20f);
laser1.build();
laser1.translate(laserDummy1.getTransformedCenter());
align(laser1, wing1);
// laserTarget1 = Object3D.createDummyObj();
laserTarget1 = Primitives.getBox(10, 1);
align(laserTarget1, targetCone);
moveTowards(laserTarget1, targetCone.getTransformedCenter(), 1f);
theWorld.addObject(laser1);
laser2 = Primitives.getCylinder(16, 4f, 20f);
laser2.build();
laser2.translate(laserDummy2.getTransformedCenter());
align(laser2, wing2);
theWorld.addObject(laser2);
// laserTarget2 = Object3D.createDummyObj();
laserTarget2 = Primitives.getBox(10, 1);
laserTarget2.build();
moveTowards(laserTarget2, targetCone.getTransformedCenter(), 1f);

laser1.addChild(laserTarget2);
laser2.addChild(laserTarget1);
theWorld.addObject(laserTarget1);
theWorld.addObject(laserTarget2);
laser1.setAdditionalColor(Color.red);
laser2.setAdditionalColor(Color.red);
System.out.println("Laser to Ship Distance: "+calculateDistance(xWing, laser1));
firing = true;
      }
Title: Re: Ship Lasers After Rotation
Post by: EgonOlsen on November 06, 2008, 08:43:27 pm
i don't quite understand what is targetCone, laserTarget and all that...maybe a screen shot would help to clarify. Apart from that and taking a quick look at the code, i find it questionable that the laserTargets get the cone's rotation matrix. That way, they are sharing the same matrix. Is that intentionally?
Title: Re: Ship Lasers After Rotation
Post by: AGP on November 06, 2008, 09:21:12 pm
Oh, the rotation matrix thing wasn't supposed to be there. That was a stupid shot in the dark. The code wasn't working long before that. The target cone is like the crosshair of a gun. It is by following it that the ship flies. If you look around your mailbox you'll find an old screenshot of this. But all it is is a crosshair.

And laserTarget is just that: the direction at which the laser flies. It's just an object meant to be chased by the laser. The game loop calls moveTowards(laser1, laserTarget1, .2f), which moves the laser1 cylinder 20% of the way towards laserTarget1 (but since laserTarget1 is added as its child, laserTarget1 moves away by the same amount).
Title: Re: Ship Lasers After Rotation
Post by: paulscode on November 06, 2008, 11:48:30 pm
To me, this setup seems logical in theory.  I'd like to see the code for methods align() and moveTowards() though, just to rule out the possiblity of a problem there.
Title: Re: Ship Lasers After Rotation
Post by: AGP on November 07, 2008, 12:43:44 am
Voilá.

Code: [Select]
      private void align(Object3D from, Object3D to) {
// THIS IS EGON'S: As Javadocs state: The default align method doesn't take parent objects into
// account...This method takes parents into account.
float scale = from.getScale();
from.setScale(1);
Matrix matrix = to.getWorldTransformation();
float[] dm = matrix.getDump();
for (int i = 12; i < 15; i++) {
      dm[i] = 0;
}
dm[15]=1;
matrix.setDump(dm);
from.setRotationMatrix(matrix);
from.setScale(scale);
      }

      protected void moveTowards(Object3D toMove, SimpleVector direction, float amount) {
SimpleVector origin = toMove.getTransformedCenter();
float deltaX = (direction.x -origin.x)*amount;
float deltaY = (direction.y -origin.y)*amount;
float deltaZ = (direction.z -origin.z)*amount;

toMove.translate(deltaX, deltaY, deltaZ);
      }
Title: Re: Ship Lasers After Rotation
Post by: paulscode on November 07, 2008, 02:04:44 am
I do understand that the idea here is to match "from's" orientation to that of "to", taking into account "to's" parent's rotation matrix.  I assume the reason you need to be able to do this is because the two guns rotate independantly from the ship, correct?

Just to make sure I am on the same page, I assume laserDummy1 is a child of wing1, and targetCone is a child of the ship object, correct?

Just looking over this, everything looks good to me, only thing I would make sure of is that the align method is doing what it is supposed to.  That's the only part I couldn't figure out from your code (although if Egon wrote it, I'm sure it is fine).

A different way to write the align() method would be to take all the rotation matrices from the parents and apply them to direction vectors, then use those to create a new rotation matrix.  I can write you some sample code for this, if my explanation doesn't make sense ;D
Title: Re: Ship Lasers After Rotation
Post by: AGP on November 07, 2008, 02:51:16 am
Yes, laserDummy1 and 2 are a child of their wings, and targetCone is a child of the ship. All I really want is for the lasers to fly straight towards the target, but the lasers move much faster than the ship, obviously, and have to pass the targetCone. You have to keep in mind the fact that the ship rotates around any and all axis. And align works fine (the lasers are always aligned). What doesn't work is that the laserTargets show up in weird places.
Title: Re: Ship Lasers After Rotation
Post by: paulscode on November 07, 2008, 04:36:34 am
You've probably already tried this, but if not, I thought of some diagnostic type tests to run.

1) Try making the targetCone some visible object, and have the ship rotate around in various directions to see if the targetCone moves correctly in relation to the ship like it is supposed to.

2) If that works, then next try making the laserTargets visible objects.  See if they show up on top of the targetCone position like they should.  Do this with the ship stationary, but rotated at various angles BEFORE generating the laserTargets.

3) If that works, do the same thing, but this time rotate the ship AFTER generating the laserTargets.  See if they move or if they remains stationary like they are supposed to.

These tests might help pinpoint where in your code the problem is cropping up from.
Title: Re: Ship Lasers After Rotation
Post by: AGP on November 07, 2008, 06:18:33 am
1) TargetCone is ALWAYS visible. It's a crosshair.
2) In the posted code, the laserTargets are visible and showing up in weird places.
3) They remain stationary if I don't flip the firing variable. They're not supposed to be stationary otherwise.

I don't really think it's my code to be perfectly honest, but I appreciate you trying to help.
Title: Re: Ship Lasers After Rotation
Post by: EgonOlsen on November 07, 2008, 12:25:26 pm
Please tell me, if i got it right now: laserTarget (or cone?) is a kind of crosshair located in front of the ship or the laser itself!? It's a child object of laser and hence part of the ship...just put somewhere in front of it? If the ship rotates, the laser (which are child objects of some other ship part) stay in place, but the target/cone doesn't. Correct?
Title: Re: Ship Lasers After Rotation
Post by: paulscode on November 07, 2008, 01:44:20 pm
1) TargetCone is ALWAYS visible. It's a crosshair.
2) In the posted code, the laserTargets are visible and showing up in weird places.
3) They remain stationary if I don't flip the firing variable. They're not supposed to be stationary otherwise.

I don't really think it's my code to be perfectly honest, but I appreciate you trying to help.

Seems like the laserTargets are not being moved to the correct spot initially?  i.e. the following code is not doing what it is supposed to do?

Code: [Select]
laserTarget1 = Primitives.getBox(10, 1);
align(laserTarget1, targetCone);
moveTowards(laserTarget1, targetCone.getTransformedCenter(), 1f);

I would set up a test case to be absolutely sure if this part does what it is supposed to or not.  If the problem is not there, it must be coming from somewhere after this code is run, so work from there and try to check every step along the way.  I know that isn't much help, but I agree with you that your code seems like it should work, so you have to rule out everything, even the stuff that doesn't look like it should be a problem.
Title: Re: Ship Lasers After Rotation
Post by: AGP on November 07, 2008, 03:22:22 pm
Egon, laserCone is the crosshair. In the fireLasers() method I posted, you see the lasers themselves are created at the location of laserDummy (sorry if some of it seems redundant or at least confusing). LaserCone is a visible crosshair, always in the right place, laserDummy are invisible dummy objects that are part of the ship (and are always in the right place). Laser targets (supposed to be invisible but for the purposes of debugging aren't) show up in the right places (directly in front of the lasers) ONLY until the ship is rotated.

Paulscode (is your name Paul?), unfortunately, there's not a lot to test. The game loop is VERY simple. If (firing) moveTowards(laser1, laserTarget1, .2f); kind of simple.
Title: Re: Ship Lasers After Rotation
Post by: EgonOlsen on November 07, 2008, 04:54:56 pm
You should create a test case for this. What exactly do the laserTarget-objects when the ship rotates?
Title: Re: Ship Lasers After Rotation
Post by: AGP on November 07, 2008, 05:31:54 pm
They show up in different places, like the sides of the ship. So the lasers, which again are aligned perfectly to the ship, fly sideways.
Title: Re: Ship Lasers After Rotation
Post by: paulscode on November 07, 2008, 11:07:58 pm
It seems to me that the laserTarget objects should always start out at the location of targetCone.  Wherever they are initially placed, they should not move again (unless firing is true, in which case the laser and laserTarget start moving away from the ship).  Each part of the setup needs to be tested seperately.

Test case #1
So the first thing to make sure of is that every time the following code is run:
Code: [Select]
laserTarget1 = Primitives.getBox(10, 1);
align(laserTarget1, targetCone);
moveTowards(laserTarget1, targetCone.getTransformedCenter(), 1f);

Then the laserTarget is place at the location of targetCone.  Is this happening?  Don't wory about firing the laser yet, just make sure the laserTargets are being initially placed in the correct location when the ship is at various rotations.

Test case #2
If there were no problems in test case #1, the next thing to test is ship rotations after the laserTargets have been created, but before firing is set to true.  Place some laserTargets, then rotate the ship to make sure they stay where they are supposed to.

From your description of the problem, It sounds like the actual firing part works, so the thing you need to narrow down is if the laserTargets are being initially placed in the wrong location, or if they are for some reason shifting position when the ship rotates after they have been created.
Title: Re: Ship Lasers After Rotation
Post by: AGP on November 08, 2008, 01:03:42 am
Test case #1: It's not happening. I already tested it without flipping firing to true. The second I rotate the ship I get weird locations for laserTarget. And again, what's odd is that the ship always flies towards targetCone (meaning it's not targetCone.getTransformedCenter()).
Title: Re: Ship Lasers After Rotation
Post by: paulscode on November 08, 2008, 04:40:33 am
Test case #1: It's not happening.

This must mean that the problem is either in the align() or moveTowards() methods, right?

To rule out a problem in the align method, how does the orientation of laserTarget look?  You mentioned that it sometimes appears beside the ship.  In that case, is the laserTarget rotated the same way as targetCone or is it "sideways"?
Title: Re: Ship Lasers After Rotation
Post by: AGP on November 08, 2008, 05:40:04 am
If you notice, that line is more indented than the other ones: it was an attempted (and obviously failed) solution. But you make a good point: maybe neither the align method nor not aligning are working. Maybe I need to align differently. I'll try to answer your question and get right back to you.
Title: Re: Ship Lasers After Rotation
Post by: paulscode on November 08, 2008, 07:34:48 am
I created a test applet to try and recreate the problem using the code as posted above.
http://www.paulscode.com/source/ShipFireProblem/ (http://www.paulscode.com/source/ShipFireProblem/)

As you can see from this applet, both test cases I listed in my last post are successful.  This means that the align() and moveTowards() methods work fine.  The problem must be coming from somewhere else in your code, after you have placed the laser and laserTarget.

What else is happening behind the scenes in your program (how is the ship being rotated, etc)?  This really is a puzzling bug!

I also uploaded the source code for the above applet, but I doubt it will help much.  It is basically everything previously posted here plus methods to create the ship object and  rotate it with the mouse, etc:
http://www.paulscode.com/source/ShipFireProblem/ShipFireProblem.java (http://www.paulscode.com/source/ShipFireProblem/ShipFireProblem.java)


-- UPDATE --
When I created the above applet, I accidentally left out the following line:
Code: [Select]
laser1.addChild( laserTarget1 );
When I went back and added this line, the exact problem you described is showing up.  Here is another test applet demonstrating (exactly the same code as the last applet, except this time laserTarget is a child of laser1):
http://www.paulscode.com/source/ShipFireProblem/ShipFireProblem2.html (http://www.paulscode.com/source/ShipFireProblem/ShipFireProblem2.html)
Source:
http://www.paulscode.com/source/ShipFireProblem/ShipFireProblem2.java (http://www.paulscode.com/source/ShipFireProblem/ShipFireProblem2.java)

As you can see in this case, the laser is placed in the correct spot, but not laserTarget (as you described).  You can also see that the orientation of the laserTarget is correct, only it's position is wrong.

OK, so here is what APPEARS to be the source of the problem (still could be something else, of course).  It looks like the calls to "translate" are not being executed immediately.  They are happening later (perhaps when the frame is rendered), AFTER laserTarget has been assigned as a child to laser.  So when that first laser translation happens (to place it on top of the laserDummy), it drags the laserTarget along with it.
Title: Re: Ship Lasers After Rotation
Post by: paulscode on November 08, 2008, 08:55:19 am
A quick look at the javaDoc for the translate() method:
Quote
Translates ("moves") the object in worldspace by modifying the translation matrix. The translation will be applied the next time the object is rendered.
This is definitely the source of your problem.

You'll have to rethink how laser firing works in your game, in order to take into account that translations do not happen immediately.

One way to do this would be to remove that line where you add the laserTarget as a child to laser.  For that matter, do not create a laserTarget object at all.  Instead, create a SimpleVector for the firing direction:
Code: [Select]
            firingVector = targetCone.getTransformedCenter().calcSub( laserDummy1.getTransformedCenter() );

Then in your firing method, use the following to move the laser:
Code: [Select]
                SimpleVector targetPoint = laser1.getTransformedCenter();
                targetPoint.add( firingVector );
                moveTowards( laser1, targetPoint, 0.2f );

I used this code in the test applet, which works nicely:
http://www.paulscode.com/source/ShipFireProblem/ShipFireProblem3.html (http://www.paulscode.com/source/ShipFireProblem/ShipFireProblem3.html)
Source:
http://www.paulscode.com/source/ShipFireProblem/ShipFireProblem3.java (http://www.paulscode.com/source/ShipFireProblem/ShipFireProblem3.java)
Title: Re: Ship Lasers After Rotation
Post by: EgonOlsen on November 08, 2008, 10:12:18 am
A quick look at the javaDoc for the translate() method:
Quote
Translates ("moves") the object in worldspace by modifying the translation matrix. The translation will be applied the next time the object is rendered.
This is definitely the source of your problem.
Well, that's just bad wording. What i meant was, that the object won't move on screen until you render it. But that's only natural...i should remove this comment. If you translate something, getTransformedCenter() and similar methods immediately reflect the change. If you add something as a child, it inherits the translations of its direct and indirect parents. Maybe that is the problem here. Anyway, if laserTarget's purpose is to define a firing direction only, i agree that it would be better to calculate that by using some direction vectors instead of adding an invisible object for it and take the difference vector. Maybe that's the reason why i never really understood what laserTarget was about...
Title: Re: Ship Lasers After Rotation
Post by: paulscode on November 08, 2008, 10:27:18 am
If you add something as a child, it inherits the translations of its direct and indirect parents. Maybe that is the problem here.
Ah, that makes sense.  So the parent's translations were being applied to the child, even though those translations were done before the child was added.  The resulting behavior (and the solution) is the same, just a different cause than the one I came up with  ;D
Title: Re: Ship Lasers After Rotation
Post by: AGP on November 08, 2008, 03:39:57 pm
Paul, thank you very much. That direction vector will come in handy for the future. And I guess I missed re-reading the docs. I appreciate your time.
Title: Re: Ship Lasers After Rotation
Post by: AGP on November 08, 2008, 05:13:50 pm
Now how would you make it so that the lasers don't stop mid-air (just keep going until they're out of sight, assuming they don't hit anything)?
Title: Re: Ship Lasers After Rotation
Post by: paulscode on November 08, 2008, 05:27:31 pm
There are a few ways you could do that.  One way might be to stick them into a List, and have the firing method iterate through it to move them.  They could be removed from the world (and the list) after a certain amount of time or distance, or when they hit something.

I would create a new laser class that has the laser Object3D, the firing direction SimpleVector, the time (or frame number) that it was created (or distance traveled), and a boolean for if it has collided with something.  That would give the firing method enough information to move the laser or remove it, and start a collision animation of some sort if the boolean is true.
Title: Re: Ship Lasers After Rotation
Post by: AGP on November 08, 2008, 05:45:23 pm
No, what I meant was that my lasers stop mid-air at what looks like twice the distance between the laserDummy and the targetCone. For some reason, in your applet the laser keeps going, but my code is just like yours as far as I can tell:

Code: [Select]
if (instance.firing) {
      SimpleVector firingVector1 = instance.targetCone.getTransformedCenter().calcSub(instance.laserDummy1.getTransformedCenter());
      SimpleVector firingVector2 = instance.targetCone.getTransformedCenter().calcSub(instance.laserDummy2.getTransformedCenter());

      SimpleVector target1 = instance.targetCone.getTransformedCenter();
      target1.add(firingVector1);

      SimpleVector target2 = instance.targetCone.getTransformedCenter();
      target2.add(firingVector2);
System.out.println("Target2 vector length: "+target2.length());

      instance.moveTowards(instance.laser2, target1, .2f);
      instance.moveTowards(instance.laser1, target2, .2f);
}
Title: Re: Ship Lasers After Rotation
Post by: paulscode on November 08, 2008, 06:07:54 pm
You need to add the firing vector to the laser's position instead of the targetCone's position.  This will give the point in worldspace that the laser should be flying towards.

Code: [Select]
      SimpleVector target1 = instance.laser1.getTransformedCenter();
      target1.add(firingVector1);

      SimpleVector target2 = instance.laser2.getTransformedCenter();
      target2.add(firingVector2);
                                    System.out.println("Target2 vector length: "+target2.length());

The other thing I did differently, is that I didn't calculate the firingVectors inside of the firing method.  The way you are doing it, I immagine that if the ship were to rotate after the laser started flying, the laser would change direction mid-flight.  The firingVectors should be calculated when the laser is first created, and not change afterwards (unless you wanted to add in some type of homing behavior to the laser)
Title: Re: Ship Lasers After Rotation
Post by: AGP on November 08, 2008, 10:50:43 pm
Absolutely right. Sloppy (or stupid, you decide) me. Thanks for holding my hand a little bit on this one. I appreciate it.
Title: Re: Ship Lasers After Rotation
Post by: paulscode on November 08, 2008, 11:19:13 pm
LOL, np.  I am going to use a laser + targetCone setup like this in my game when I get around to working on shooting guns, so thanks for the concept.