SRL Archive - OSR Help

circle and tangent script help


g0tp0t

2010-10-04 15:09:22

i have been wanting to make a script that moves a dot in a cirlce until you click. when you click it will change the path of the dot to a circle with its center being the point you clicked. Since i am a horrible explainer i drew it out. P1 is the first click and P2 is the second click. the green dot is the dot and the black line is the path. the dotted line is just showing that the path is on a circle.

i attached the pic

Plz help =\

Feroc1ty

2010-10-13 19:16:40

This shouldn't be in the help section, but rather in the request section.

If we were to help you, you'd give us a piece of code and we'd tell you what to improve or what went wrong, but you're simply saying "hey I need this done… chop chop."


That being said, I'll help you make this script, here's something for you to start… this has one function which will take a point, a distance, and an angle, and project the original point with the given parameters.

program new;

const
degtorad = 0.0174532925;

var
stpt,tppt:TPoint;

function offset(origin:TPoint; distance,angle:extended):TPoint;
begin
result.x := Round(origin.x + distance * Cos( (angle-90) * degtorad));
result.y := Round(origin.y + distance * Sin( (angle+90) * degtorad));
end;

var ang:integer;

begin
stpt.x := 0;
stpt.y := 0;
ang := 0;
while (ang < 360) do
begin
tppt := offset(stpt,10,ang);
writeln(inttostr(tppt.x) + ',' + inttostr(tppt.y));
ang := ang + 45;
end;
end.

EDIT: So are you giving up on this function, or are you waiting for someone to fully do your work?

g0tp0t

2010-10-14 19:39:46

Sorry I don't want anyone to make this for me. I just havmt been able to find a good approach. I tried to create the same function you did but I don't know the math to get a specific point on the circle. Another problem is making the ball always spear to move at the same speed. I think ill use circumference. Illpost my current code up when I get to school tomorrow.

Sorry for sounding demanding.

Edit: I just noticed the lion under my username. I'm assuming that means I'm a simba user. =]

Feroc1ty

2010-10-14 22:38:27

What do you mean… I gave you a pretty damn good start on whatever you're trying to accomplish… I'll explain what to do and how to do it, but I won't give you the code for it, and you should be grateful as this will take me 20x longer to explain than to simply code.

Sorry I forgot to explain what my function does… I guess I'll do so here so you'll understand this all more clearly.

What it does, is takes a point (this can be your mouse middle point or whatever), and moves it x degrees in a y angle. Still don't get it? Keep what I said in mind, and here are some examples. (Keep in mind that 0/360 degrees will be to the north, aka going up on your monitor, and 90 degrees will be to the east, going toward the right of your monitor.)

Example1: if your point is (0,0), and you tell my function to move 10 points and 0/360 degrees, the returned point will be (10,0).

Example2: if your point is (0,0), and you tell my function to move 10 points and 90 degrees, the returned point will be (0,10).

You need not know of the details of how the math works in this whatsoever…



Now that you know how the function works, why not try to implement it in whatever you're trying to do?

You might be thinking… how do I do that?

Start out by creating a simple loop with a starting point, we'll call it the origin of rotation. In this loop you should have a never ending loop (which will eventually end, when we change the origin, or whatever condition it is that you want it to stop), with a single incrementing variable, the angle.

Now you have a nice a tidy little function where you'll have a constant point going around your origin in a circular motion.

You're half way there… want me to help you with the rest? I'd suggest you try to figure out how you could do this without reading farther as it will only help your brain develop thinking in a logical and sophisticated way (the programmers way.)




Now you have a point with another point constantly running around it.

This isn't what I wanted at all! I wanted it to switch in a way that resembles my nicely drawn picture, and I want it to do so when I tell it!

Okay, so… I don't know how you're gonna change the origin, but when you do so, how could you make the running point reverse the motion? Simple, instead of incrementing the angle, make the angle decrement, that will make the rotation swap.

Now I have a nice tidy function that will draw a circle, and swap locations with the rotation being reversed.

But it isn't nice at all like in my picture, the point simply jumps to my new circle!

Okay, why could this be? There's only four values that we input into the function, a point which holds two values, the distance, and the angle.

We have already discussed the angle part, but not in it's full extent, as the motion will simply reverse, it wont be connected and smooth like in your picture. If you want this to happen, we have to make sure your function will make the dot run around the new origin at the opportune moment.

To do this, we'll have to figure out the angle between your old origin, and your new one. This should be simple, get the angle between those two and store the value. Proceed to make your dot run around the old origin until the opportune angle (the stored angle), and than swap, also swapping the incrementation/incrementation of the loop.

Now you have a nice and tidy function which will run around the origin, and when you set a new origin, it will keep running around the origin until the opportune angle, and finally jump to the new origin.

It still jumps thought, just the jump isn't at random times now, only when it's close to the other origin… zzz…

Why could this be… Remember what values your function takes? Point, Angle, Distance. We've covered the angle, but distance is still unadjusted… The point still jumps because no matter where your new origin is, it will run at same old distance it did around the old origin, and that's not what we want it to do.

What you want to happen, is calculate the distance between the old and the new origins, and subtract the old distance from them. This will give you the radius of the new path for your little dot to run around; we do this because at the opportune time, your running dot will be closest to the new origin it could be, and because we don't want him to jump around, we'll make him use the distance of his current location and the new origin.


I hope this will help you as it took me 20 minutes to write, please attempt to do what I explained, and post your code if you have any problems.

I know some parts might seem a little confusing solely because I didn't properly introduce origin and "running dot"(lol!) with variable names, but it should be understandable.

Edited it a bit to removed some redundancy and make this wall of text more easy to read.

g0tp0t

2010-10-15 13:22:01

… i said im not asking for code but help approaching this, im not lazy, and thanks for helping with words instead of code, its more helpful even though it takes longer. lol.

Im on a pc right now so im working on this and ill post what i have soon.

EDIT: i read my post and it sounded mean, i didnt mean it that way, sorry. lol

i need an onclick event, how do i use that?

program new;
var b:TBitmap;cx,cy,bc,fc,s:integer;cw:boolean;a,r:extended;

const
sx=300;
sy=300;
procedure ScriptTerminate;
begin
FreeBitmap(b);
end;
procedure dp(x,y,size,col:integer);
var ix,iy:integer;
begin
for ix:= floor(-1*size/2) to ceil(size/2) do
for iy:= floor(-1*size/2) to ceil(size/2) do
FastSetPixel(b,x+ix,y+iy,col);
DrawBitmapDebugImg(b);
end;
function offset(origin:TPoint; distance,angle:extended):TPoint;
begin
result.x := Round(origin.x + distance * Cos( (angle-90) * 0.0174532925));
result.y := Round(origin.y + distance * Sin( (angle+90) * 0.0174532925));
end;

begin
ClearDebugImg;
DisplayDebugImgWindow(sx,sy);
b := CreateBitmap(sx,sy);
r:= 100
cx:= round(sx/2);
cy:= round(sy/2);
bc:=clBlack;
fc:=clAqua;
s:=3;
while not iskeydown(VK_RCONTROL) do
begin
wait(10);
if cw then
begin
a:=a+1;
dp(offset(point(cx,cy),r,a-1).x,offset(point(cx,cy),r,a-1).y,s,bc);
dp(offset(point(cx,cy),r,a).x,offset(point(cx,cy),r,a).y,s,fc);
end else
begin
a:=a-1;
dp(offset(point(cx,cy),r,a+1).x,offset(point(cx,cy),r,a+1).y,s,bc);
dp(offset(point(cx,cy),r,a).x,offset(point(cx,cy),r,a).y,s,fc);
end;

end;
end.

i need to figure out how to use an onclick event now.

EDIT: nvm im using a form but i need to draw a bitmap to it. how do i draw a bitmap to a form?

EDIT: new fail code =\

program new;
var vv:TVariantArray;f:tform;b:TBitmap;cx,cy,bc,fc,s:integer;cw:boolean;a,r:extended;

const
sx=300;
sy=300;
procedure ScriptTerminate;
begin
FreeBitmap(b);
end;
procedure dp(x,y,size,col:integer);
var ix,iy:integer;
begin
for ix:= floor(-1*size/2) to ceil(size/2) do
for iy:= floor(-1*size/2) to ceil(size/2) do
begin
f.canvas.MoveTo(x+ix,y+iy);
f.canvas.LineTo(x+ix,y+iy);
end;
end;
function offset(origin:TPoint; distance,angle:extended):TPoint;
begin
result.x := Round(origin.x + distance * Cos( (angle+90) * 0.0174532925));
result.y := Round(origin.y + distance * Sin( (angle-90) * 0.0174532925));
end;
procedure initform;
begin
f.SHOWMODAL;
end;
begin
b := CreateBitmap(sx,sy);
r:= 100
cx:= round(sx/2);
cy:= round(sy/2);
bc:=clBlack;
fc:=clAqua;
s:=3;
f.CREATENEW(nil);
ThreadSafeCall('initform',vv);
while not iskeydown(VK_RCONTROL) do
begin
wait(10);
if cw then
begin
a:=a+1;
dp(offset(point(cx,cy),r,a-1).x,offset(point(cx,cy),r,a-1).y,s,bc);
dp(offset(point(cx,cy),r,a).x,offset(point(cx,cy),r,a).y,s,fc);
end else
begin
a:=a-1;
dp(offset(point(cx,cy),r,a+1).x,offset(point(cx,cy),r,a+1).y,s,bc);
dp(offset(point(cx,cy),r,a).x,offset(point(cx,cy),r,a).y,s,fc);
end;
end;
end.

Feroc1ty

2010-10-15 16:53:31

To be honest I never used scar for any drawing functions (or any functions besides moving mouse and clicking keyboard whatsoever), but doesn't it come with a help file that shows all functions available… that should have something helpful in it.

Sorry I can't help you on that one, either wait for someone with knowledge in drawing to respond or read up some tutorials.

g0tp0t

2010-10-16 20:44:09

Lol.

that's the problem with simba right now. there are no tutorials and the wiki is underdeveloped.

on top that, simba is different enough to have to be relearned a little.

g0tp0t

2010-10-17 10:45:18

Double post to be deleted for bump

Your explanation was great. I was bad at explaining. I thought I would need to find the point that the two circles we'd tangent to each other… That was making this more complex than it needed to be thoug. Your idea of subtracting radius from distance is perfect. I should have thought of that. Lol

g0tp0t

2010-10-17 17:03:28

http://paste.villavu.com/show/SvIC78i6rMGKyDsCXT79/

im stuck at making the point transition smoothly. i cant figure out how to get the slope of when it will transition smoothly =\

Feroc1ty

2010-10-17 18:25:18

Your code keeps crashing for me and it's hard to understand another programmers code, so fix the crashing and I'll help you with the run-time error that you're having.

g0tp0t

2010-10-17 20:50:57

It crashesbecause the dp function is not in a try except end statement. Add theory and you'll see hoe messed up itis lol.

Feroc1ty

2010-10-17 22:37:57

As I said it's hard to understand other peoples code, I'm no genie, either fix your run-time error or at least comment your shit so I can understand whats happening instead of wasting an hour trying to do so myself.

EDIT: Also, after I run the code and it crashes, every time I try to run it again the debug IMG box is hidden under loads of bullshit, so I have to restart Simba every time…

EDIT: I'm cooking up a script right now, so wait till I post what I have and than you can tell me if this is what you wanted.

i luffs yeww

2010-10-17 23:47:00


var //Give meaningful names to all variables if you can.
vv: TVariantArray;
f: TForm;
b: TBitmap;
cx, cy, bc, fc, s: Integer;
cw: Boolean;
a, r: Extended;

const
sx = 300; //Give better names.. StartX and StartY if anything.
sy = 300; //Really only use letters like this if they don't mean anything and
//are only used for loops or something.. for i := 0 to 10 do
//is fine, but if you use i as anything important or anything, name
//it something that makes sense and is memorable.

procedure ScriptTerminate;
begin
FreeBitmap(b);
end;
//Col never used.
procedure dp(x, y, Size, Col: Integer); //dp == DoPoint? Name your functions better.
var
ix, iy: Integer;
begin //Why these numbers/formulas?
for ix := Floor(-1 * Size / 2) to Ceil(Size / 2) do
for iy := Floor(-1 * Size / 2) to Ceil(Size / 2) do
begin
f.Canvas.MoveTo(x + ix, y + iy);
f.Canvas.LineTo(x + ix, y + iy);
end;
end;

function Offset(Origin: TPoint; Distance, Angle: Extended): TPoint; //GetOffset or something.. Names are important.
begin //Also, where are these numbers from? You may know, but you should make it more clear.
Result.x := Round(Origin.x + Distance * Cos((Angle + 90) * 0.0174532925)); //I'd use a const for the floating point number..
Result.y := Round(Origin.y + Distance * Sin((Angle - 90) * 0.0174532925)); //" "
end;

procedure InitForm;
begin
f.SHOWMODAL;
end;

begin
b := CreateBitmap(sx, sy); //b == bitmap?
r := 100; //r == Radius?
cx := Round(sx / 2); //cx == CenterX?
cy := Round(sy / 2); //cy == CenterY?
bc := clBlack; //bc == BackgroundColor?
fc := clAqua; //fc == ForegroundColor?
s := 3; //s == Size?
f.CREATENEW(nil); //Error: Could not call proc
ThreadSafeCall('initform', vv); //Never do anything with vv?
while not(IsKeyDown(VK_RCONTROL))do
begin
Wait(10);
if(cw)then //Never use cw anywhere, so it will never be true.
begin
Inc(a); //Use variables for long things like this.. provides much better readability.
dp(Offset(Point(cx, cy), r, a - 1).x, Offset(Point(cx, cy), r, a - 1).y, s, bc);
dp(Offset(Point(cx, cy), r, a).x, Offset(Point(cx, cy), r, a).y, s, fc);
end else
begin
Dec(a); //Above
dp(Offset(Point(cx, cy), r, a + 1).x, Offset(Point(cx, cy), r, a + 1).y, s, bc);
dp(Offset(Point(cx, cy), r, a).x, Offset(Point(cx, cy), r, a).y, s, fc);
end;
end;
end.

Still doesn't compile.. Pot, you really need to work on standards and naming of variables.

Feroc1ty

2010-10-18 01:49:56

program new;

// My imagebox variable, and the size constants
var
imgbox:TBitmap;

const
imgboxx = 500;
imgboxy = 500;

// Draws a point on the image with the given color
procedure drawpoint(point:TPoint;color:integer);
begin
FastSetPixel(imgbox, point.x, point.y, color);
DrawBitmapDebugImg(imgbox);
end;

// Offsets a point from a point x distance at y angle
// Note: this function now takes radians instead of degrees because
// of unnecessary conversion between the two when using angles
function offset(origin:TPoint; distance,angle:extended):TPoint;
begin
result.x := Round(origin.x + distance * Cos( (angle) ));
result.y := Round(origin.y + distance * Sin( (angle) ));
end;

// calculates a distance between two points
function pdistance(pointa,pointb:TPoint):integer;
begin
result := Round(Sqrt( Pow(pointa.x-pointb.x,2) + Pow(pointa.y-pointb.y,2) ))
end;

// calculates the angle between two points, returns a radian
function pangle(pointa,pointb:TPoint):extended;
begin
result := ArcTan2(pointb.y-pointa.y,pointb.x-pointa.x)
end;

// same as last function, but adds 180 degrees
function cangle(pointa,pointb:TPoint):extended;
begin
result := ArcTan2(pointb.y-pointa.y,pointb.x-pointa.x)
if result > 0 then
result := result - 3.141592
else
result := result + 3.141592;
end;

// a function to make the code look cleaner, basically it calculates
// the distance between two numbers on the number line and checks
// if the value is equal to or less than the third argument, returns a boolean
function iscloseenough(a,b,c:extended):boolean;
begin
if Abs(a-b) <= c then
result := true
else
result := false;
end;

var rotation:boolean;

// another function to make the code look cleaner and more understandable
// not much to explain here, just increases or decreases the angle, if radians
// overlap it fixes them
procedure adjustangle(var ang,inc:extended);
begin
if rotation then
ang := ang + inc
else
ang := ang - inc;
if (ang > 3.141592) then ang := ang - 6.282185;
if (ang < -3.141592) then ang := ang + 6.282185;
end;

var
start:integer;

// made this function to test if the script works, you can place whatever here,
// or put the condition straight into the main loop of your program, i just
// like to keep all of my code clean
function condition():boolean;
begin
result := false;
if ((GetSystemTime - start) > 5000) then
begin
writeln('condition met!');
result := true;
start := GetSystemTime+30000;
end;
end;

// all of my main loop variables are here, as you can see I like to place
// my variables just before they are used, so they don't confuse you on
// where they belong
var
radius:integer;
angle,increment:extended;
origin,origin2,temp:TPoint;
switch:boolean;


begin

// Defaults vars are initialized
radius := 40;
angle := 0;
increment := 0.030;
rotation := true;
switch := false;

start := GetSystemTime();

// Origin point defaults to middle of debug img
origin := Point(imgboxx/2,imgboxy/2);

// Since I don't know how you're gonna get the other point this ones randomized
origin2 := Point(Random(250)+125, Random(250)+125);

// Display debug image window and create bitmap
DisplayDebugImgWindow(imgboxx,imgboxy);
imgbox := CreateBitmap(imgboxx,imgboxy);

// Where all the action happens, most of the runtime is here in this forever loop
while (true) do
begin
sleep(5);
// draws a pixel at the offset position of origin
drawpoint(offset(origin,radius,angle),clWhite);
// adjusts the angle (my code is 10x cleaner than yours right here :P)
adjustangle(angle,increment);
// checks for condition to switch
if condition and not(switch) then
begin
switch := true;
end;
// if the switch is set to true, the script will begin looking for
// opportunities to make the transition to drawing the next circle
if switch then
begin
if iscloseenough(angle, cangle(origin,origin2), 0.05) then
begin
// the condition is met, new angle is set, radius changed, origin set to the
// new origin, rotation is reversed from whatever it was, and switch is once again
// false
angle := cangle(origin,origin2);
radius := pdistance(origin,origin2) - radius;
origin := origin2;
rotation := not(rotation);
switch := false;
end;
end;
end;

end.

The code should work, as you can see for some reason my condition keeps repeating itself after it's met although it should only repeat every 5 seconds, and that's the thing I won't fix as your code will definitely have a different condition.

Tell me how it works out.

g0tp0t

2010-10-18 07:54:23

my problem with scripting is trying to organize. i fail. Thats why ive been making useless programs like this. lol

Feroc1ty

2010-10-18 17:59:12

From: g0tp0t
my problem with scripting is trying to organize. i fail. Thats why ive been making useless programs like this. lol


What about the code that did absolutely nothing?

lol

g0tp0t

2010-10-26 16:27:27

I don't understand what u meant? Lol

Feroc1ty

2010-10-26 19:16:44

From: g0tp0t
I don't understand what u meant? Lol


There's a lot of crap in your original code that did absolutely nothing lol.

g0tp0t

2010-10-27 13:53:15

maybe thats why i couldnt organise. lol

your script jumps alot. do you know why?

g0tp0t

2010-10-27 14:13:38

i figured out how to fix it. you had the cangle backwards.

pasted here: "Bpv91YQaiJjmrMJH8ctN"

Feroc1ty

2010-10-27 19:07:57

So what did you end up using the code on? I'm interested as to what on earth could this be useful for, as the only time I've ever used polar offset was to create missile projectiles when I was creating spells for a game.

g0tp0t

2010-10-27 21:39:27

im making a swing game.you get the ball through a course without touchign the walls. you click to creat a new origin point;

Feroc1ty

2010-10-28 01:16:05

Ah, that actually makes perfect sense :P.