Is there a way to do this (I haven't been able to get this kind of behavior with the move command, so I thought I'd ask):
//PSEUDOCODE
String hupu;
int tupu = 0;
while (tupu < 500 && hupu != "taa") {
// move an object toward another object's coordinates by ONE PIXEL
if (GetLocationName(object.x, object.y) == "target") {
hupu = "poo";
}
wait(1);
}
you can directly change the X and Y properties if an object isn't moving. You can check if it is moving, or let it stop moving before you run your code, but yes it's possible. :)
edit:
I just realized you were probably also wondering about the maths so here goes:
float vx = IntToFloat(targer.X - object.X);
float vy = IntToFloat(targer.Y - object.Y);
float n = Maths.Sqrt(vx*vx + vy*vy);
vx = vx / n;
vy = vy / n;
object.X += FloatToInt(vx, eRoundNearest);
object.Y += FloatToInt(vy, eRoundNearest);
edit2:
You're right Khris, corrected it.
FloatToInt's default rounding is eRoundDown; it should be eRoundNearest in that code, if I'm not mistaken.
Thanks for the quick replies! I've got some nasty crap going on in my head and throat ("ooh! Gooooo!"), but I'll get to testing some time in the upcoming week.
Am I doing something wrong? I decided to use a character instead of an object (cBullet). Below is the script I blatantly copy-pasted from here. For some reason the bullet first travels in a straight line for a while and only then begins to curve towards the target...
You can download the InDev game from www.whamgames.com/downloads/success/POC.rar (http://www.whamgames.com/downloads/success/POC.rar)
To test the bullet script press F, move cursor over target area and press space to shoot. The bullet travels according to the below script and stops if it encounters a wall.
cBullet.ChangeRoom(player.Room, player.x, player.y-7);
String hupu = "x";
int tupu = 0;
Display("SHOT FIRED");
while (tupu < 500 && hupu != "BLOCK") {
float vx = IntToFloat(GetViewportX() + 160 - cBullet.x);
float vy = IntToFloat(GetViewportY() + 78 - cBullet.y);
float n = Maths.Sqrt(vx*vx + vy*vy);
if (vx == 0.00 || vy == 0.00) {
tupu = 501;
} else {
vx = vx / n;
vy = vy / n;
}
cBullet.x += FloatToInt(vx, eRoundNearest);
cBullet.y += FloatToInt(vy, eRoundNearest);
hupu = Game.GetLocationName(cBullet.x - GetViewportX(), cBullet.y - GetViewportY());
tupu++;
Wait(2);
}
I guess the initial code is already flawed.
In fact, usually this is done by doing all calculations with floats and only using rounded versions of those to place the object.
Basically:
float bx = IntToFloat(cBullet.x);
float by = IntToFloat(cBullet.y);
while(...) {
// calculate path, add vx/vy to bx/by
...
cBullet.x = FloatToInt(bx, eRoundNearest);
cBullet.y = FloatToInt(by, eRoundNearest);
...
}
That way, rounding errors don't accumulate; or, as shown here, supposed sums of small values don't remain 0.
I was suddenly reminded why I suck at math... I'll try to see if I can get it working, but at the moment I'm having a hard time even grasping the math and understanding how the script I was provided works.
I'll post back if I make progress!
The math isn't that hard; the first step is to calculate the 2D vector from bullet to target:
x = target.x - bullet.x;
y = target.y - bullet.y;
In other words, calculate the x;y which you have to add to bullet's position to get to target.
A vector's length is square root of (x*x + y*y) since that equals length*length, according to Pythagoras.
In order to shrink the vector to desired length dl, divide both x and y by length (l), then multiply by dl.
dl can be thought of as speed in pixels per frame.
Wyz' code uses a speed of 1, so:
x = x / l;
y = y / l;
The resulting vector points from bullet to target and in this case has a length of one.
The final step is to add it to bullet's position every loop, thus moving it in the direction of target.
As far as I can understand this should be correct:
function Shooty() {
// First we move the bullet graphic to the player's location and reset variables
String hupu = "x";
int tupu = 0;
cBullet.ChangeRoom(player.Room, player.x, player.y-7);
// Then we reset "hupu", which keeps track of what the bullet is currently on top of
// And we reset tupu, which makes sure the bullet does not travel indefinitely
// DEBUG Display("SHOT FIRED");
// WHILE tupu is less than 500 ie. for a long enough time
while (tupu < 500) {
// vectorX and vectorY
float vx = IntToFloat(GetViewportX() + 160 - cBullet.x);
float vy = IntToFloat(GetViewportY() + 78 - cBullet.y);
float length = Maths.Sqrt((vx*vx) + (vy*vy));
// Make sure there is no division by zero
if (vx == 0.00 || vy == 0.00) {
tupu = 501;
} else {
vx = vx / length;
vy = vy / length;
}
cBullet.x += FloatToInt(vx, eRoundNearest);
cBullet.y += FloatToInt(vy, eRoundNearest);
hupu = Game.GetLocationName(cBullet.x - GetViewportX(), cBullet.y - GetViewportY());
Display("%s", hupu);
tupu++;
Wait(2);
}
But: Nope, the bullet still travels in a straight line first and only as it gets closer to its target does it begin to curve towards the correct coordinate.
I stooped so low as to try this:
cBullet.ChangeRoom(player.Room, player.x, player.y-7);
cBullet.Move(GetViewportX() + 160, GetViewportY() + 78, eNoBlock, eAnywhere);
while (cBullet.Moving == true) {
if (tupu >= 12) {
hupu = Game.GetLocationName(cBullet.x - GetViewportX(), cBullet.y - GetViewportY());
Display("%s", hupu);
}
Wait(1);
tupu++;
// Add a check to stop the cBullet from moving if it encounters a character or an object with a certain name
}
That actually works just as needed, save for the fact that I cannot track the bullets location on each pixel of movement unless the movement speed of the bullet is set as "1", which in turn looks too on-screen. If I set the movementspeed higher, the bullet can skip "through" some of the most narrow objects if they meet at an angle.
First of all, avoiding a division by zero is done by making sure that length isn't 0.
Secondly, we're back at the original problem. Like I explained, you have to store the bullet's position in two floats, add vx, vy to those and then put cBullet at the FloatToInts of them. Otherwise, rounding errors accumulate.
Ooookay... So far I've just made the variables go haywire. :o
// First we move the bullet graphic to the player's location and reset variables
String hupu = "x";
int tupu = 0;
cBullet.ChangeRoom(player.Room, player.x, player.y-7);
// VERSION 1 - PYTHAGORAS
// WHILE tupu is less than 500 ie. for a long enough time
while (tupu < 500) {
// VX and VY
float vx = IntToFloat(GetViewportX() + 160 - cBullet.x);
float vy = IntToFloat(GetViewportY() + 78 - cBullet.y);
// Bullet's location X and Y
float bx = IntToFloat(cBullet.x);
float by = IntToFloat(cBullet.y);
float length = Maths.Sqrt((vx*vx) + (vy*vy));
// Make sure there is no division by zero
if (length == 0.00) {
tupu = 501;
} else {
vx = vx / length;
vy = vy / length;
}
// Addition
bx = bx + vx;
by = by + vy;
cBullet.x += FloatToInt(bx, eRoundNearest);
cBullet.y += FloatToInt(by, eRoundNearest);
Display("%d %d", cBullet.x, cBullet.y);
if (tupu > 15) {
hupu = Game.GetLocationName(cBullet.x - GetViewportX(), cBullet.y - GetViewportY());
Display("%s", hupu);
}
tupu++;
Wait(2);
}
You added bx/by to the bullet's position; bx/by IS the bullet's position.
cBullet.x = FloatToInt(bx, eRoundNearest);
cBullet.y = FloatToInt(by, eRoundNearest);
Whoops, remnants of previous attemps I had failed to clean up.
However, even with these corrections the issue remains: if the target coordinates are, lets say 60 pixels to the right and 15 pixels down from the starting point, the bullet travels directly to the right for about 35-40 pixels and only then begins to curve towards its final target.
Just saw the other error:
Move this above the while loop:
// Bullet's location X and Y
float bx = IntToFloat(cBullet.x);
float by = IntToFloat(cBullet.y);
What's the point of having separate floats to avoid rounding errors if you set them to the rounded values every loop...? ;)
Holy crap, it seems to work! ;D
You people have once again saved my day and future games! Now that I have a working example I can study it and see if I can refine it further.
Thank you!