here's a little challenge... (SOLVED)

Started by stuh505, Thu 28/10/2004 05:02:59

Previous topic - Next topic

stuh505

I want there to be a compass on the screen which shows the correct North.Ã,  The direction of north will be a room variable.Ã,  When a new room is entered, I want the compass to rotate and point in the correct direction...using harmonically damped motion (aka, sinusoidal).

I haven't programmed in AGS for a while...but as I recall...we don't have sin functions or log so the equation couldn't be written, and we can't rotate sprites anyway.Ã,  So I'm sure any workaround would involve a sprite for each degree of rotation.Ã,  But still...I'd need the capability for playing back the animation at arbitrary starting frames, for arbitrary frame durations, in forward or reverse...

Any ideas..?

Goot

It's not going to be very easy. The best way to do it is probably to use RawDrawLine, and input all the coordinates for the middle and all the places around the edge into variables so you can just look at degree mark around the compass and have variables ready with the x and y coordinates. You'll need a function for changing the compass, which you'll run on every room load. Use a variable for where the arrow is pointing, and then have it move.

I don't know how to declare these but if you know how to make
something[something].something variables (eg. compass[50].x, where 50 is the degrees on the compass and x is the x coordinate of that spot) that would be alot easier.

Gilbert

Simple approach: just use a plugin for the floating point functions and draw the needle using the rawdraw triangles or lines, etc. functions.

Alternative approach: Draw say 36 sprites (not really, some of them are just 90 degree rotations, flipping of others) and put it in a loop.

Harder approach: try to script necessarily functionity with integer arithmetic.

There can be more.

Radiant

If you wish to stay away from plugins...

1.in another language, say QBasic since it's pretty easy, calculate sines and cosines roughly like this:
Code: ags

pi = 3.1415927
open "sincos.txt" for output as #1
for i=0 to 359
print #1,sin((i * pi) / 180)
print #1,cos((i * pi) / 180)
next i
close #1


2.then, in the AGS global script, add variables something like this:
Code: ags

int sin[360], cos[360];

and use the file read/write functions (I'd have to look up the exact syntax) to read the sin/cos data from said file.
Voila! You'd have sin[8] and cos[44] etc. to use as a pseudo-function.


Scummbuddy

yes, please tell me we all have copies of all the plug ins somewhere safe, such as ericas dissapearance and with her went her webpages and downloads, such as the math plugins. im sure someone out here has a copy. does the download link on the main page work anyways?
- Oh great, I'm stuck in colonial times, tentacles are taking over the world, and now the toilets backing up.
- No, I mean it's really STUCK. Like adventure-game stuck.
-Hoagie from DOTT

stuh505

Ok, it's not a exactly a compass, and it can't be drawn in the game...I will need to draw sprites for each angle of rotation.

You all have seemed to just gloss over the hard parts..

1.  To have torque that is proportional to the difference of the current angle and the desired new angle, that provides angular acceleration and is damped by friction...

2. To have the order of the sequence of frames to be played be determined by a function

So....I'm thinking it would probably be too difficult to implement the realistic method of acceleration into AGS, but I could live with just having constant velocity to make it rotate to the new position without any harmonic motion or damping (I don't know how to do this and I doubt anyone else does)

But that still leaves problem 2

Rui 'Trovatore' Pires

Scummbuddy - I have almost all plugins on my webpage, www.freewebs.com/skimbleshanks/, but I'm not sure if it will reset it's bandwidth on the 9th as it should, and I can't login anymore, anyway, so it's a dead page now. But I do have practically all plugins (and templates, and stuff) in my PC, if you'd like them.
Reach for the moon. Even if you miss, you'll land among the stars.

Kneel. Now.

Never throw chicken at a Leprechaun.

Radiant

1. That would be basic math. You can do vectors without problems in AGS. If you're thinking of implementing, say, Asteroids (tm), that would certainly be possible.

2. That's not so hard, simply create an array of sprite numbers, and use SetObjectGraphic. Doesn't work with characters, but if need be you can reserve object #0 in each room.

Janik

#8
Quote from: stuh505 on Thu 28/10/2004 16:39:02
1.Ã,  To have torque that is proportional to the difference of the current angle and the desired new angle, that provides angular acceleration and is damped by friction...

2. To have the order of the sequence of frames to be played be determined by a function

So....I'm thinking it would probably be too difficult to implement the realistic method of acceleration into AGS, but I could live with just having constant velocity to make it rotate to the new position without any harmonic motion or damping (I don't know how to do this and I doubt anyone else does)
Hmm... I'm taking computational physics this semester, so let's see... You're describing essentially a damped pendulum:

define:

theta = difference between current angle and north
s = dtheta/dt, the angular speed

so your equations are

dtheta/dt = s
ds/dt = F*sin(theta) - R*s

where F = your force of attraction
and R = a coefficient of damping.

So when direction changes, your theta_0 is modified, and then you will integrate the equation numerically with a certain time step. The simplest algorigtm is this:

s(1) = s(0) + ds/dt * timestep
theta(1) = theta(0) + s(0) * timestep

and loop until s(n) is close enough to 0 (that is, the pendulum has been damped enough)

I'd recommend writing the program outside of AGS at first, just outputting s and theta as a function of time, to make sure it works before adding the graphics.

This isn't the most precise integration method, but I won't go into the 4th-order Runge Kutta method right nowÃ,  ;D
Play pen and paper D&D? Then try DM Genie - software for Dungeons and Dragons!

stuh505

Quote1. That would be basic math. You can do vectors without problems in AGS. If you're thinking of implementing, say, Asteroids (tm), that would certainly be possible.

I wouldn't really call differential equations basic math, but I suppose if you are an engineering whiz you could say that if you wanted to...

and it doesn't seem to me that AGS can really "do math" without problems when you consider that it does not support any math functions, and you need to use roundabouts and approximations for them all.

Quote2. That's not so hard, simply create an array of sprite numbers, and use SetObjectGraphic. Doesn't work with characters, but if need be you can reserve object #0 in each room.

Ah, ok....so in layman's terms, you're suggesting that I write the function for theta(t) which will choose the correct sprite number, and then put it in a loop with a delay in the loop using a nested counting loop to wait some number of milliseconds, and run that loop which updates the sprite image until theta(t) = theta(t-1).   got it.

Quoteand use the file read/write functions (I'd have to look up the exact syntax) to read the sin/cos data from said file.
Voila! You'd have sin[8] and cos[44] etc. to use as a pseudo-function.

The AGS file read seems to only grab the entire contents and read it into a string buffer.  In which case, might as well just write the entire contents into a defined string in AGS, right?  But isn't there a 255 cap on AGS strings?  Also, wouldn't I need to then define the string something lke this for example:

"sin1_.02 sin2_.03 sin3_.05" etc

then the function for sin(x) would be more like
searchstr = "sin" + x + "_";

then use StrContains to find the location of this index...

then use StrGetCharAt to write a function that could grab a substring out of a string...

and use this function to grab the next 3 digits after the index found, and then turn that into an int...

but this is all assuming that the entire string size fits in the allotted memory

or did you have something simpler in mind?

Quotedtheta/dt = s
ds/dt = F*sin(theta) - R*s

why not write it all in terms of theta?  there's only 1 equation here...I'm not really sure how you got it though

never tried writing a differential equation as a recursive one..

Quotetheta(1) = theta(0) + s(0) * timestep

Is this what you mean?

theta(t) = theta(t-1) + s(t-1) * timestep

I think it would be easier to loop until theta(t) = theta(t-1)

but how would s (dtheta/dt) work in this recursive equation?

sorry for not understanding right away...its been a while since I took this stuff

I'm not sure if this is right...

i know that the equation describing its motion would be

theta(t) = Ae^(-Bt)cos(Ct) + D

where D = the angle that represents north

but this wouldn't quite be the equation that would model it's motion...

Janik

#10
Quote from: stuh505 on Thu 28/10/2004 21:28:51
Is this what you mean?

theta(t) = theta(t-1) + s(t-1) * timestep

Yes, if you have t as an integer. But you have to calculate the speed s

QuoteI think it would be easier to loop until theta(t) = theta(t-1)

That's equivalent to waiting for the speed to drop to 0, yes.

Quotebut how would s (dtheta/dt) work in this recursive equation?
You need to recalculate the speed s for each step,

theta(t) = theta(t-1) + s(t-1) * timestep
s(t) = s(t-1) + FUNCTION(s, theta) * timestep

where FUNCTION(s, theta) = ds/dt = F*sin(theta) - R*s

Note the cosine instead of the sine, that was an error above. Scratch that, sine is correct.

Quotei know that the equation describing its motion would be

theta(t) = Ae^(-Bt)cos(Ct) + D

where D = the angle that represents north

And B is the pendulum frequency, A is its amplitude. That is a correct result in the small-angle approximation. If your pendulum's amplitude is too large, then theta(t) is more complex. To put it in the case of a compass, if you only turn a few degrees at a time this works. In practice it's probably close enough even for large angles.

If you rotate past 90 degrees, however, the needle will have a different behavior: it will start out slow, accelerate more and more until reaching 90 degrees, and keep accelerating (with friction this may actually be decelerating) but slower.

Play pen and paper D&D? Then try DM Genie - software for Dungeons and Dragons!

Radiant

Okay, I got a bit carried away with that. Sure, it's advanced math if you want (actually I'm a compusci major so we have a bit of a different definition there :) )
I wasn't talking differential equations, just talking vector addition / multiplication.

Anyway. While AGS can't do floating point (at least, not without a plugin), it can do fixed point. This basically means that you use integers, but in a different order of magnitude. Assume the screen is 320000 by 200000 pixels. Calculate anything you want in integers. Then divide everything by 1000 to get coordinates for the actual screen.

As to the file I/O... you're correct that AGS doesn't read textual numerical values very well. You could write them there as raw integers, then read them using FileReadRawInt() one after the other.
Or, I suppose, you could do FileReadLine into a string (assuming the line contains just a single value) then use StringToInt to put the numerical value into an array.

The string trick wouldn't work well, most AGS strings are capped at 200.

hth.

stuh505

Quotetheta(t) = theta(t-1) + s(t-1) * timestep
s(t) = s(t-1) + FUNCTION(s, theta) * timestep

where FUNCTION(s, theta) = ds/dt = F*sin(theta) - R*s

It looks like your definition of s(t) uses s(t) as an input parameter, so I don't really see how that works..

I think maybe the direct equation would be easier,

Quote
Quotei know that the equation describing its motion would be

theta(t) = Ae^(-Bt)cos(Ct) + D

where D = the angle that represents north

And B is the pendulum frequency, A is its amplitude. That is a correct result in the small-angle approximation. If your pendulum's amplitude is too large, then theta(t) is more complex. To put it in the case of a compass, if you only turn a few degrees at a time this works. In practice it's probably close enough even for large angles.

If you rotate past 90 degrees, however, the needle will have a different behavior: it will start out slow, accelerate more and more until reaching 90 degrees, and keep accelerating (with friction this may actually be decelerating) but slower.

Well, it's not really right...but I have fixed it like this:

theta_n = theta north
theta_s = theta start

theta(t) = int((theta_n - theta_s)*e^(-w*t)*cos((theta_n - theta_s)*t) + theta_n)

then I can draw 360 sprites and store them in slot numbers 0-360 in the sprite manager...and use SetObjectGraphic and that should work out fine..

However...still need a way to get cos(angle)

Janik

You could use the Taylor expansion (I think that is how processors do this internally)

cos x = 1 - x^2/2! + x^4/4! - x^6/6! + ...

However you may run into trouble with integer overflow. Also, x is in radians so you'll need floating point or some fixed point scheme.
Play pen and paper D&D? Then try DM Genie - software for Dungeons and Dragons!

Isegrim

#14
fuzzpilz did a floating-point-math plugin some time ago.
it's linked in here, but I don't know if the link still works.
It's a little awkward to handle, but it works. I'd recommend to use taylor-approximations for sin and cos instead of the provided ones, though...
This post was generated automatically and therefore bears no signature.

stuh505

#15
alright, i was thinking about taylor approximations...that wont be a problem then.

the only thing I'm still not sure about then is how to do the animation without freezing the game.Ã,  I need to put in a wait command between each re-draw, but the Wait(x) command puts up the hourglass. How can I allow this animation to happen without interrupting gameplay?Ã, 

edit - I think SetTimer is my answer

stuh505

#16
Yes!Ã,  I got it working!Ã,  This looks really beautiful...:)

Here is what the completed function looks like.Ã,  It was much more of a pain than I thought...especially determining the distance between two random numbers between 0-360 because of the whole modulo thing...wasted way too much time trying to figure that out!


function MoveCompass(int cobject, int cfirstsprite, int timer)
Ã,  //PRE: fticks is a global float for time that is reset on room load
Ã,  //Ã,  Ã,  Ã, fstart is a global float for starting degrees that is set to previous compass rotation on room load
Ã,  //Ã,  Ã,  Ã, cobject is the object on this room that represents the compass
Ã,  //Ã,  Ã,  Ã, cfirstsprite is the # of the first compass sprite (out of 359 total sprites)
Ã,  //Ã,  Ã,  Ã, timer is the timer that this function should use
Ã,  //POST: compass is moved a small amount, and a timer is set to move again if more movement is waiting
{
Ã,  if (IsTimerExpired(timer))
Ã,  {
Ã,  Ã,  //define constants
Ã,  Ã,  int fe = ints_to_float(2,718);
Ã,  Ã,  int ffreq = ints_to_float(0,-100);
Ã,  Ã,  int fstep = ints_to_float(0,050);
Ã,  Ã,  int fnorth = angle_from_degrees(int_to_float((GetRoomProperty("CompassNorth")-1)*45));
Ã, 
Ã,  Ã,  //set fstart if this is the first frame of animation
Ã,  Ã,  if (fstart==-1)
Ã,  Ã,  Ã,  fstart = angle_from_degrees(int_to_float(GetObjectGraphic(cobject)));Ã, 
Ã, 
Ã,  Ã,  //find magnitude of angle between the starting and north direction with correct sine
Ã,  Ã,  int fdiff, fdifftest;
Ã,  Ã,  fdiff = fsub(fstart, fnorth);
Ã,  Ã,  fdifftest = fsub(fsub(fnorth, angle_from_degrees(int_to_float(360))),fstart);
Ã, 
Ã,  Ã,  if (fless(fabs(fdifftest),fabs(fdiff)))
Ã,  Ã,  Ã,  fdiff = fdifftest;
Ã,  Ã, 
Ã,  Ã,  fdifftest = fadd(fsub(angle_from_degrees(int_to_float(360)), fstart), fnorth);

Ã,  Ã,  if (fless(fabs(fdifftest),fabs(fdiff)))
Ã,  Ã,  Ã,  fdiff = fdifftest;
Ã,  Ã, 
Ã,  Ã,  //compute new compass angle
Ã,  Ã,  int fang = fmul(fdiff, fticks);
Ã,  Ã,  int famp = fmul(degrees_from_angle(fdiff),pow(fe, (fmul(ffreq,fticks))));
Ã,  Ã,  int fres = float_to_int(fadd(fmul(famp, (cos(fang))),degrees_from_angle(fnorth)));
Ã, 
Ã,  Ã,  //set to proper range of sprites
Ã,  Ã,  fres = fres + cfirstsprite;
Ã, 
Ã,  Ã,  //make sure new angle is mod 360
Ã,  Ã,  while (fres>(cfirstsprite+359))
Ã,  Ã,  Ã,  fres=fres-360;
Ã,  Ã,  while (fres<cfirstsprite)
Ã,  Ã,  Ã,  fres=fres+360;Ã,  Ã, 

Ã,  Ã,  //update compass graphic
Ã,  Ã,  SetObjectGraphic(cobject,fres);

Ã,  Ã,  //if not reached total damping, continue--go until amplitude=0
Ã,  Ã,  if (fcomp(famp,0)!=0){
Ã,  Ã,  Ã,  Ã, SetTimer(timer,1);
Ã,  Ã,  Ã,  Ã, fticks = fadd(fticks,fstep);
Ã,  Ã,  } else {
Ã,  Ã,  Ã,  fticks = 0;
Ã,  Ã,  Ã,  fstart = -1;
Ã,  Ã,  Ã,  Display("done");
Ã,  Ã,  }
Ã,  }
}

SMF spam blocked by CleanTalk