Sinusoid Motion

Sinusoid Motion via Script

O Ilusionista said:
so, what are you waiting for? :)
I could do all of those, but I have no time for that :(

Ok, little by little I will post them all.
The more complex it is certainly the parabolic motion!

EDIT: and vertical boomerang (with sin/cos func)
 
@White Dragon:
I tested your code, but its not working.
If I use it in @script ... @end_script, the cyclone appears at the left of the screen, with no speed (it got stuck there)
iEIcC78.png


If I move it to ondrawscript, it appears where Storm is, but again with no movement
tVBRLTv.png
 
Rotation/Sinusoid in openBOR

Code:
ondrawscript @script
void main() {
	void self = getlocalvar("self");
	float radius = 18; // circle radius
	float speed = 0.3;
	int dir = 1; // rotation sense
	float angle = 90; // angle to start

	int arc = rotate(self,radius,speed,dir,angle);

	// to self rotate object too
	//changedrawmethod(self, "reset", 1);
	//changedrawmethod(self, "enabled", 1);
	//changedrawmethod(self, "rotate", arc);
 }

  int rotate(void self, float radius, float speed, int dir, int angle) {
	float x = getentityproperty(self, "x");
	float z = getentityproperty(self, "z");
	float a = getentityproperty(self, "y");
	float base = getentityproperty(self, "base");
	float teta;
        int elapsed_time = openborvariant("elapsed_time");

	if ( getlocalvar("x") == NULL() ) setlocalvar("x", x);
	if ( getlocalvar("y") == NULL() ) setlocalvar("y", y);

	if ( getlocalvar("arc") == NULL() ) setlocalvar("arc", angle);
	else setlocalvar("arc", getlocalvar("arc")+dir*(speed));
	if ( getlocalvar("arc") >= 360 ) setlocalvar("arc", 0);
	else if ( getlocalvar("arc") < 0 ) setlocalvar("arc", 359);

	teta = getlocalvar("arc");
	teta %= 360;
	if(teta < 0) teta += 360;

	x = getlocalvar("x") - radius*cos(teta);
	y = getlocalvar("y") - radius*sin(teta);

        changeentityproperty(self, "tosstime", elapsed_time+10) ;
        changeentityproperty(self, "position", x, NULL(), y) ;

	return getlocalvar("arc");
  }
@end_script
 
I haven't tested yet, but I've found a uncomplicated method  ;D

UPDATE

We don't need to use elapsed_time anymore, since it won't never start as the same value.

@script
    void self = getlocalvar("self");
    int counter;

        float x,z;

        if(frame==0)
        {
            counter = 0;
        }
        if (frame>0)
        {
            x = -sin(counter/1.45)*2;
            z = -cos(counter/1.45)/3;
            changeentityproperty(self, "velocity", x, z, 0) ;
            counter +=5;
        }
@end_script

Works like a charm! The movement always starts on the same spot.
the trick is: using the values above for sin and cos, the smaller is the "counter" value, the bigger is the radius of the circle.

Side notes:
a) if you use -sin and -cos (negative), the movement will be counter clockwise. if you use sin and cos, the movement is clockwise

b) if the last operation is not the same for both axis (in the previous exemple, x uses "*2" and Z uses "/3"), the movement will be an elipse. If they are the same, it will be circular.


downside of this method:
a) the effect is directly affected by the frame delay. On the example above, I use 3 as delay, for a "counter" of 5. If you use slower delay (like 6), you need to change the "counter" too (for example, 10).

b) if you spawn multiple entities using this codes, I dunno why, but the values sums each other. The more entities using this code at the same time, the quicker will be the move. Maybe is because of the "counter" value.
 
If it were me, I'd make this a self contained function run on update. For speed control, monitor elapsed time, and whenever X amount time passes, reset the counter and the timer.

Use an index variable to turn it "on" or "off" (like the Shadow Trail Scripts), and set that as needed wherever.

This should solve the problems you are running into with it being an embedded entity script, and also make the speed consistent.

DC
 
I'm glad you finally figured out to modify velocity instead of position to attain sinusoid motion. Both methods are good.
If you don't care or don't need very smooth sinusoid motion, using velocity is decent way

I've used sinusoid motion for Giant Bat in CV Collab mod:

anim idle
@script
    void self = getlocalvar("self"); //Get calling entity
    int Dir = getentityproperty(self, "direction");
    float Fram = (getentityproperty(self, "animpos") + 1)*0.0833;
    float Vx = 1;
    float Vy = 3*cos(Fram*360);
   
    if(Dir==0){
      Vx = -Vx;
    }

    changeentityproperty(self, "velocity", Vx , 0, Vy);
@end_script
loop 1
delay 10
offset 20 64
bbox 11 52 21 17
attack 11 34 21 57 10 1 1 0 0
frame data/chars/gbat/bigbat1.png
frame data/chars/gbat/bigbat2.png
frame data/chars/gbat/bigbat3.png #
frame data/chars/gbat/bigbat1.png
frame data/chars/gbat/bigbat2.png
frame data/chars/gbat/bigbat3.png #
frame data/chars/gbat/bigbat1.png
frame data/chars/gbat/bigbat2.png
frame data/chars/gbat/bigbat3.png #
frame data/chars/gbat/bigbat1.png
frame data/chars/gbat/bigbat2.png
attack 0 0 0 0 0 0 0 0 0
frame data/chars/gbat/bigbat3.png

Big Bat flies forward while moving up/down in sinusoid manner
(After rereading the script, I realized that I could've avoided typing 1/12 in decimals, oh well time for script update :) )

As for using sinusoid motion for boomerang, it might work but for Castlevania Holy Cross, I simply use this script:

anim idle
@script
    void self = getlocalvar("self"); //Get calling entity
    int Vx = getentityproperty(self, "speed");
   
    if(frame==3){
      changeentityproperty(self, "speed", Vx-0.125);
    }
@end_script
loop 1
delay 3
offset  13 13
attack  2 2 22 22 5 0 0 0 0
frame data/chars/misc/subweap/cross1.png
frame data/chars/misc/subweap/cross2.png
frame data/chars/misc/subweap/cross3.png
attack  0
frame data/chars/misc/subweap/cross4.png

It's not sinusoid motion but the effect is good enough to hit enemy multiple times with Holy Cross ;) ;)

Back to topic, this motion is cool, I'm going to implement it to some enemies in mods I'm working on :D

@ Goliath: I believe Medusaheads in castlevania series fly in sinusoid manner too. You can use sinusoid motion for simple enemies in your mod i.e enemies which simply flies to left or right ignoring players
 
Bézier Curve in openBOR

html5-canvas-bezier-curves-diagram.png

quad_bezier.jpg

240px-B%C3%A9zier_3_big.gif


PARAMS:
t = time [0,1] (from 0 to 1);
n = type of bezier curve (ex. cubic = 3, quadratic = 2, linear = 1)
c# = coordinates (x OR z OR y) -> Ex.: x0,x1,x2,x3 | x0 is START, x3 is END, x1,x2 are intermediate.

Code:
/*
 * PARAMS:
 * t = time [0,1] (from 0 to 1);
 * n = type of bezier curve (ex. cubic = 3, quadratic = 2, linear = 1)
 * c# = coordinates (x OR z OR y) -> Ex.: x0,x1,x2,x3 | x0 is START, x3 is END, x1,x2 are intermediate.
 */
float bezier_curve(float t, int n, float c0, float c1, float c2, float c3, float c4, float c5, float c6, float c7, float c8, float c9) {
    float i = 0, b = 0;
    float coeff = 0, coord = 0;
    /// x = x0*(1-t)^3 + 3*x1*t*(1-t)^2 + 3*x2*t^2*(1-t) + x3*t^3
    /// x = x0*(1-t)^5 + 5*x1*t*(1-t)^4 + 10*x2*t^2*(1-t)^3 + 10*x3*t^3*(1-t)^2 + 5*x4*t^4*(1-t) + x5*t^5*(1-t)^0
    /*
    Binomial Coefficient: (n k) = n!/(k!*(n-k)!) --> Example: n!/(k!*(n-k)!) -> 5!/(2!*(5-2)! -> 120/2*6 -> 120/12 -> 10
    */

    for (i = 0; i <= n; ++i) {
        if      (i == 0) coord = c0;
        else if (i == 1) coord = c1;
        else if (i == 2) coord = c2;
        else if (i == 3) coord = c3;
        else if (i == 4) coord = c4;
        else if (i == 5) coord = c5;
        else if (i == 6) coord = c6;
        else if (i == 7) coord = c7;
        else if (i == 8) coord = c8;
        else if (i == 9) coord = c9;
        if ( coord == NULL() ) break;

        coeff = fact(n)/(fact(i)*fact(n-i));
        b += coeff*coord * exp(1-t,n-i) * exp(t,i);
    }

    return b;
}

int fact(int n) {
  int f = 1;

  n = abs(n);
  while ( n > 1) {
    f = f*n;
    n--;
  }

  return(f);
}

int exp(int base, int exp) {
    int i = 0;
    int result;
    int sign = 1;

    if ( base < 0 ) sign = -1;
    base = abs(base);
    exp = abs(exp);
    result = base;

    if ( exp == 0 ) return 1;
    for ( i = 0; i < exp-1; ++i ) {
        result *= base;
    }
    result *= sign;

    return result;
}

float abs(float num) {
    if (num < 0) num *= -1;

    return num;
}

TEST SCRIPT:
If you want to test it write in your script event this debug example:
Code:
void main() {
    void self = getlocalvar("self");

    if ( openborvariant("in_level") && getlevelproperty("type") != 2 && getentityproperty(self,"animationid") != openborconstant("ANI_SPAWN") ) {
        if ( getlocalvar("bezier_time") <= 1 || getlocalvar("bezier_time") == NULL() ) {
            float t = getlocalvar("bezier_time"),x,z;
            float minz = openborvariant("player_min_z");
            float speed = 0.002;

            if (t == NULL()) setlocalvar("bezier_time",0);
            else setlocalvar("bezier_time",getlocalvar("bezier_time")+speed);
            if ( getlocalvar("bezier_time") < 0 ) setlocalvar("bezier_time",0);
            if ( getlocalvar("bezier_time") > 1 ) setlocalvar("bezier_time",1);
            t = getlocalvar("bezier_time");

            x = bezier_curve(t,3,30,80,160,210);
            z = bezier_curve(t,3,minz+60,minz+120,minz+150,minz+100);
            changeentityproperty(self,"position",x,z,NULL());

            drawstring(10,100,0,"t: "+t);
            drawstring(10,110,0,"x: "+x);
            drawstring(10,120,0,"z: "+z);
        }
    }
}

Smooth movements!! Sweet!

Ps. You can extend the bezier_curve func from cubic to N just adding coord params!
 
Trying this but get this error:

Script compile error: can't find function 'sin'
 
O Ilusionista said:
You OpenBOR version is very outdated (for what you posted in other topic, you are using a 2 years old version).

Yeah i now it´s old but I though maybe is an error cos BloodBane used it in his Contra mod.
 
O Ilusionista said:
You can see at my videos that the code works :)

XD, ok thanks for your great support.
Don´t you have that sin function from there¿?
 
I was askinig if you know how to write the sin function, to implement it on the current BOR version i´m using, nothing more. :)
 
Back
Top Bottom