Game Development Community

MAKING A PROJECTILE: EXTREMELY DESPERATE!!!!!

by Tyler Slabinski · in Torque Game Builder · 04/11/2009 (11:14 am) · 25 replies

This is VERY annoying... I am trying to get an imagemap at these points:

X: -44.000
Y: -9.500

And with speeds of:

$arrowX
$arrowY

Look at the below script, it is a click-drag-shoot sort of projectile. And I am trying to make the sprite appear in the function shootArrow(); and it is being executed at onMouseUp.

//Get the position vector of the mouse when pressed and turn them into variables.

function t2dSceneWindow::onMouseDown(%this, %modifier, %worldPosition, %clicks)
{
     $startPosition = %worldPosition; //Vector for when mouse is clicked

     $dX = getWord(%worldPosition, 0); //X position when mouse is pressed down.
     $dY = getWord(%worldPosition, 1); //Y position when mouse is pressed down.
}

//Get the position vector of the mouse when released and turn them into variables.

function t2dSceneWindow::onMouseUp(%this, %modifier, %worldPosition, %clicks)
{
     $endPosition = %worldPosition;

     $rX = getWord(%worldPosition, 0); //X position when mouse is released.
     $rY = getWord(%worldPosition, 1); //Y position when mouse is released.

     //Execute the functions for getting the angle and power. Then creating the velocity for the arrow.
     convertAngle();
     convertPower();
     convertVelocity();

     //Launch the arrow.
     shootArrow();
}

function convertAngle()
{
     %xSlope = ($dX - $rX);
     %ySlope = ($dY - $rY);

     $angle = mRadToDeg(mAtan(%xSlope, %ySlope)); //Get the arctan of the slopes. Then convert it to degrees.
}

function convertPower()
{
     $distance = t2dVectorDistance($startPosition, $endPosition); //Get the distance between the click and the release.

     //Keep the power from going over 30.
     if($distance > 30)
     {
          $power = 30;
     }
     else
     {
          $power = $distance;
     }
}

function convertVelocity()
{
     //Get the power for how far the arrow will go.
     if ($angle > 90)
     {
          $arrowX = (90 - ($angle - 90)) * ($power / 10);
     }
     else
     {
          $arrowX = $angle;
     }

     //Get the height for the arrow.
     if ($angle != 90)
     {
          $arrowY = ($angle - 90) * ($power / 10);
     }
     else
     {
          $arrowY = 0;
     }
}

function shootArrow() {
     %arrow = new t2dStaticSprite()
     {
          scenegraph = SceneWindow2D.getSceneGraph();
          position = "-44.0 -9.5";
          imageFile = "silverBolt.png";
          class = "silverBolt";
    	  CollisionActiveSend = "1";
          CollisionActiveReceive = "1";
          CollisionPolyList = "-0.250 -0.250 0.250 -0.250 0.250 0.250 -0.250 0.250";
          ConstantForce = "0.000 20.000";    
          ConstantForceGravitic = "1";    
          mountID = "20";
	};
	%arrow.setLinearVelocityX($arrowX);
	%arrow.setLinearVelocityY($arrowY);
}
Page «Previous 1 2
#1
04/11/2009 (11:40 am)
I recently had to solve this problem to get a sprite to rotate to the same degree as the analog stick was pushed. Here's how I solved it:

%rotationAngle = mRadToDeg(mAtan(%this.leftX, -%this.leftY));
%this.setRotation(%rotationAngle);

-----------------------------------------------------------
In the code above,
%this.leftX = (destVectorX - originX)
%this.leftY = (destVectorY - originY) * -1 (applied -1 to Y to get the analog input to match up to standard grid coords)


Hope this helps.
#2
04/11/2009 (12:15 pm)
I am not familiar with that function. I am trying to just get the angle of something. Here is the equation:

%slope = (%dY - %uY)/(%dX - %uX)

%dY and %dX are the coordinates of the mouse when the left mouse button is pressed down.
%uY and %uX are the coordinates of the mouse when released.

The %slope is the slope of those coordinates.

I need to find the arctan of %angle.

Here is an idea of what I need to do:

www.mathopenref.com/coordslope.html

I so far have no idea how to do that in Torque. Any help?
#3
04/11/2009 (12:20 pm)
Hi Tyler,

The mAtan(x1-x2, y1-y2) function will give you the arctan between two points. Then I use mRadToDeg to convert the result radian value to degrees to get the angle between the two.

I just use it to get the angle from the origin to the dest coordinates that I receive via analog input. That is how I set the rotation angle on my sprite.

Is that what you're looking for?
#4
04/11/2009 (12:29 pm)
So I would do this:

%angle = mAtan($startPosition, $endPosition);
mRadToDeg(%angle);

Sounds simple enough.
#5
04/11/2009 (12:42 pm)
Well I made a few typos. But this seemed to work:

function t2dSceneWindow::onMouseDown(%this, %modifier, %worldPosition, %clicks)    
{    
     $dX = getWord(%worldPosition,0);  
     $dY = getWord(%worldPosition,1); 
}      
      
function t2dSceneWindow::onMouseUp(%this, %modifier, %worldPosition, %clicks)    
{    
     $rX = getWord(%worldPosition,0);  
     $rY = getWord(%worldPosition,1); 

     convertAngle();  
}

function convertAngle()
{
     %xSlope = ($dX - $rX);
     %ySlope = ($dY - $rY);

     %angle = mRadToDeg(mAtan(%xSlope, %ySlope));
     echo(%angle);
}

Now I just need to use this to create a linearVelocityX and linearVelocityY for a projectile to shoot in that direction.
#6
04/11/2009 (12:45 pm)
Nice! Good luck!
#7
04/11/2009 (6:16 pm)
Now I have a new problem:

//Get the position vector of the mouse when pressed and turn them into variables.

function t2dSceneWindow::onMouseDown(%this, %modifier, %worldPosition, %clicks)
{
     $startPosition = %worldPosition; //Vector for when mouse is clicked

     $dX = getWord(%worldPosition, 0); //X position when mouse is pressed down.
     $dY = getWord(%worldPosition, 1); //Y position when mouse is pressed down.
}

//Get the position vector of the mouse when released and turn them into variables.

function t2dSceneWindow::onMouseUp(%this, %modifier, %worldPosition, %clicks)
{
     $endPosition = %worldPosition;

     $rX = getWord(%worldPosition, 0); //X position when mouse is released.
     $rY = getWord(%worldPosition, 1); //Y position when mouse is released.

     //Execute the functions for getting the angle and power. Then creating the velocity for the arrow.
     convertAngle();
     convertPower();
     convertVelocity();

     //Launch the arrow.
     shootArrow();
}

function convertAngle()
{
     %xSlope = ($dX - $rX);
     %ySlope = ($dY - $rY);

     $angle = mRadToDeg(mAtan(%xSlope, %ySlope)); //Get the arctan of the slopes. Then convert it to degrees.
}

function convertPower()
{
     $distance = t2dVectorDistance($startPosition, $endPosition); //Get the distance between the click and the release.

     //Keep the power from going over 30.
     if($distance > 30)
     {
          $power = 30;
     }
     else
     {
          $power = $distance;
     }
}

function convertVelocity()
{
     //Get the power for how far the arrow will go.
     if ($angle > 90)
     {
          $arrowX = (90 - ($angle - 90)) * ($power / 10);
     }
     else
     {
          $arrowX = $angle;
     }

     //Get the height for the arrow.
     if ($angle != 90)
     {
          $arrowY = ($angle - 90) * ($power / 10);
     }
     else
     {
          $arrowY = 0;
     }
}

function shootArrow(%this)
{
     %this = new t2dParticleEffect()
     {
          effectFile = "~/data/particles/SilverBolt.eff";
          useEffectCollisions = "1";
          effectMode = "INFINITE";
          effectTime = "0";
          canSaveDynamicFields = "1";
          class = "silverBolt";
          size = "1.000 1.000";
          FlipY = "1";
          CollisionActiveSend = "1";
          CollisionActiveReceive = "1";
          CollisionPolyList = "-0.250 -0.250 0.250 -0.250 0.250 0.250 -0.250 0.250";
          ConstantForce = "0.000 20.000";
          ConstantForceGravitic = "1";
          mountID = "20";
   };
   %this.silverBolt.shoot();
}

function silverBolt::shoot(%this, %effect)
{
     %this.setLinearVelocityX(%this.arrowSpeedX);
     %this.setLinearVelocityY(%this.arrowSpeedY);

     %this.setPositionX(-44.000);
     %this.setPositionY(-9.500);
}

I am trying to get a particle effect to launch with speeds of arrowSpeedX and arrowSpeedY (for X and Y), and a starting position of -44 and 9.5.

It is the last 2 functions that don't work. I believe someone can tell me what's wrong.

Any help?
#8
04/12/2009 (9:51 am)
Let me rephrase my question:

How do I add a projectile in script? I am not good at making games through script, and I would like to know how I make a porjectile with the above stats?
#9
04/12/2009 (12:27 pm)
You need to specify the t2dSceneGraph onto which your object will be rendered.

scenegraph = SceneWindow2D.getSceneGraph();

So your shootArrow function should look like this:

function shootArrow(%this)  
{  
     %this = new t2dParticleEffect()  
     {  
          scenegraph = SceneWindow2D.getSceneGraph();
          effectFile = "~/data/particles/SilverBolt.eff";  
          useEffectCollisions = "1";  
          effectMode = "INFINITE";  
          effectTime = "0";  
          canSaveDynamicFields = "1";  
          class = "silverBolt";  
          size = "1.000 1.000";  
          FlipY = "1";  
          CollisionActiveSend = "1";  
          CollisionActiveReceive = "1";  
          CollisionPolyList = "-0.250 -0.250 0.250 -0.250 0.250 0.250 -0.250 0.250";  
          ConstantForce = "0.000 20.000";  
          ConstantForceGravitic = "1";  
          mountID = "20";  
   };  
   %this.silverBolt.shoot();  
}
#10
04/12/2009 (1:51 pm)
game/gamescripts/Bow.cs (95): Unable to find object: '' attempting to call function 'shoot'

95th line:

%this.silverBolt.shoot();
#11
04/12/2009 (5:34 pm)
It should just be %this.shoot();
#12
04/12/2009 (5:41 pm)
Well it doesn't give me any errors... It just doesn't do anything.

I am getting really angry at my script at the moment.

I want to get a particle effect appear at this point:

X: -44.000
Y: -9.500

I want that particle effect to go at this speed:

$arrowX
$arrowY

How would I make a function like that happen when my mouse is released? This is one of the only things I need to fix before I can get through my game.
#13
04/12/2009 (5:58 pm)
Try:

function shootArrow(%this)  
{  
     %silverBolt = new t2dParticleEffect()  
     {  
          effectFile = "~/data/particles/SilverBolt.eff";  
          useEffectCollisions = "1";  
          effectMode = "INFINITE";  
          effectTime = "0";  
          canSaveDynamicFields = "1";  
          class = "silverBolt";  
          size = "1.000 1.000";  
          FlipY = "1";  
          CollisionActiveSend = "1";  
          CollisionActiveReceive = "1";  
          CollisionPolyList = "-0.250 -0.250 0.250 -0.250 0.250 0.250 -0.250 0.250";             ConstantForce = "0.000 20.000";  
          ConstantForceGravitic = "1";  
          mountID = "20";  
   };  
   %silverBolt.shoot();
}  
  
function silverBolt::shoot(%this, %effect)  
{  
     %this.setLinearVelocityX($arrowX);
     %this.setLinearVelocityY($arrowY);
  
     %this.setPositionX(-44.000);
     %this.setPositionY(-9.500);

     %this.playEffect();
}
#14
04/12/2009 (6:07 pm)
t2dParticleEffect::playEffect() - Cannot Play; no emitters!

My effect has an emmiter though...
#15
04/12/2009 (8:12 pm)
As to why the effect is saying that it can't find your emitter, I'm not sure, you might try loading the effect file after you create the object, like this:

%silverBolt.loadEffect( "~/data/particles/SilverBolt.eff");

Sometimes it seems like TGB has trouble loading files right out of the initialization datablock.

But I probably would recommend against you using a particle emitter in this case. Here's why:

1. Looking at the example game you're trying to emulate that you posted in another thread, it looks like you are only going to be firing off a couple of projectiles. Particles are much better suited to when you need a whole lot of something on the screen.

2. Again, looking at the game you are trying to emulate, I'm guessing that you're going to want to leave the arrows up on the playfield to show where they all land. Particles have a short lifespan, you give the emitter a set amount of time, and the particle gets deleted after the time passes. So no matter how long you set for the particle lifespan, there's still a chance that the arrow could get deleted before you want it to.

3. When a particle collides with something, it doesn't give you a lot of information. You can only know that one of your particles collided. You don't know where, or which one, or what it hit. Again, I'm guessing this isn't what you would like to have happen.

If you're determined to use a particle emitter to handle your projectiles, then you should read this, it will tell you everything you need to know about how to aim a particle emitter, and how to set the velocity, etc. Particles are fantastic in their right place, but I think that this particular case is a poor match for them.

What I would recommend instead is using a t2dStaticSprite. It's a lot easier to get them going in a direction you want given a velocity vector. You could do something like this:

function shootArrow() {
	%arrow = new t2dStaticSprite() {
		scenegraph = SceneWindow2D.getSceneGraph();
		position = "-44.0 -9.5";
		imageFile = "your image file";
		CollisionActiveSend = "1";
		CollisionActiveReceive = "1";
		CollisionPolyList = "-0.250 -0.250 0.250 -0.250 0.250 0.250 -0.250 0.250";
		ConstantForce = "0.000 20.000";    
		ConstantForceGravitic = "1";    
		mountID = "20";
	};
	%arrow.setLinearVelocityX($arrowX);
	%arrow.setLinearVelocityY($arrowY);
}
#16
04/12/2009 (10:03 pm)
I wanted to use a static sprite, don't get me wrong.

Though if I did, it would have been like this:

img2.imageshack.us/img2/1619/epicfailedarrow.png
I want to create a projectile that is ballistic (not sure what it is called, but it is called ballistic in TGE):

img13.imageshack.us/img13/1559/epicwinarrow.png
If you show me how to do that, then please tell me... Or I may need to use the particle effect.
#17
04/13/2009 (7:18 am)
Will a particle rotate as it moves? That's pretty cool.

There's a couple of ways you could get a static sprite to rotate as it moves through an arc.

1. You could use the onTimer method to periodically check the velocity of the projectile, and adjust its rotation accordingly. So at the bottom of your shoot arrow method, add a line like this:

%arrow.setTimerOn(100);

That will cause your onTimer method to get called every 100 milliseconds, or about 10 times a second. Then you'd define the onTimer method like this:

function silverBolt::onTimer(%this) {
  %velocity = %this.getLinearVelocity();
  //use velocity to calculate proper rotation for projectile
  //set the rotation for the projectile
}

Also, if you used the shoot arrow method I described in an above post, you would need to add this line to the new t2dStaticSprite section:

class = "silverBolt";

Because I forgot to add that line in when I was typing it up, and the arrow projectile would need to have the class set.

I think that's the easiest way, and the safest way, if it doesn't rotate often enough, you could change the number in the setTimerOn method. When the arrow finally collided with something, you would want to call the setTimerOff() method, so that it wouldn't keep trying to rotate the arrow.

Another method you could use, although this would be more tricky to get right, would be to use the setAutoRotation method. When you create the arrow, call setAutoRotation, with an angle, and the arrow will automatically rotate. You'd have to do some calculations to figure out how much the arrow should rotate each frame, and I'm not sure how you'd approach that, but it could be done.

The final method I can think of, is that you could calculate what the final angle of the arrow will be, and use the setRotationTarget method. Although I think calculating the final rotation, and how long it should take to get there, could be pretty tricky.

There might be other ways of doing it. Torque has a rigid body physics simulator, but I haven't played with it so I don't know if that would work, or how you would get it working. But this is how I would do it.
#18
04/13/2009 (11:47 am)
I was thinking of using the timer, but this is going to be for the iPhone, and I don't want too many actions going at once.

It should be easy though. I just need to reverse my math and set the rotation.

I will most likely make this a resource, because I know many other people will like this.
#19
04/13/2009 (6:26 pm)
Ok, first I am trying to make the object appear before I try the rotation.

This is my script so far:

//Get the position vector of the mouse when pressed and turn them into variables.

function t2dSceneWindow::onMouseDown(%this, %modifier, %worldPosition, %clicks)
{
     $startPosition = %worldPosition; //Vector for when mouse is clicked

     $dX = getWord(%worldPosition, 0); //X position when mouse is pressed down.
     $dY = getWord(%worldPosition, 1); //Y position when mouse is pressed down.
}

//Get the position vector of the mouse when released and turn them into variables.

function t2dSceneWindow::onMouseUp(%this, %modifier, %worldPosition, %clicks)
{
     $endPosition = %worldPosition;

     $rX = getWord(%worldPosition, 0); //X position when mouse is released.
     $rY = getWord(%worldPosition, 1); //Y position when mouse is released.

     //Execute the functions for getting the angle and power. Then creating the velocity for the arrow.
     convertAngle();
     convertPower();
     convertVelocity();

     //Launch the arrow.
     shootArrow();
}

function convertAngle()
{
     %xSlope = ($dX - $rX);
     %ySlope = ($dY - $rY);

     $angle = mRadToDeg(mAtan(%xSlope, %ySlope)); //Get the arctan of the slopes. Then convert it to degrees.
}

function convertPower()
{
     $distance = t2dVectorDistance($startPosition, $endPosition); //Get the distance between the click and the release.

     //Keep the power from going over 30.
     if($distance > 30)
     {
          $power = 30;
     }
     else
     {
          $power = $distance;
     }
}

function convertVelocity()
{
     //Get the power for how far the arrow will go.
     if ($angle > 90)
     {
          $arrowX = (90 - ($angle - 90)) * ($power / 10);
     }
     else
     {
          $arrowX = $angle;
     }

     //Get the height for the arrow.
     if ($angle != 90)
     {
          $arrowY = ($angle - 90) * ($power / 10);
     }
     else
     {
          $arrowY = 0;
     }
}

function shootArrow() {
     %arrow = new t2dStaticSprite()
     {
          scenegraph = SceneWindow2D.getSceneGraph();
          position = "-44.0 -9.5";
          imageFile = "silverBolt.png";
          class = "silverBolt";
    	  CollisionActiveSend = "1";
          CollisionActiveReceive = "1";
          CollisionPolyList = "-0.250 -0.250 0.250 -0.250 0.250 0.250 -0.250 0.250";
          ConstantForce = "0.000 20.000";    
          ConstantForceGravitic = "1";    
          mountID = "20";
	};
	%arrow.setLinearVelocityX($arrowX);
	%arrow.setLinearVelocityY($arrowY);
}

This seems to not do anything. Not any error in console, just nothing. I even tried replacing:

imageFile = "silverBolt.png";

With:

imageFile = "silverBoltImageMap";

Nothing happens, not even an error.
#20
04/13/2009 (7:06 pm)
Two things, I know I said imageFile when I gave you that code, but I double checked, and it's supposed to be imageMap. Second, make sure that you created an imageMap for the silver bolt in the gui.

So, the code should be

imageMap = "silverBoltImageMap";

I hope that works for you.
Page «Previous 1 2