Maidens of the Kaleidoscope

~Hakurei Shrine~ => Rika and Nitori's Garage Experiments => Topic started by: Drake on February 22, 2010, 06:38:54 PM

Title: Useful Miscellaneous Code Snippets
Post by: Drake on February 22, 2010, 06:38:54 PM
We need a thread like this.


Format:
Code: [Select]
Name
[i]Description of function[/i]
-Parameter1: Description of parameter
-Parameter2: Description of parameter
[code]code goes here[/code ] (remove space)



ToFormatString
Returns a number as a string without decimals and added commas for thousand, million marks etc.
Code: [Select]
function ToFormatString(n){
let dummystring = ToString(n);
let dummystring2 = "";
loop(7){
dummystring = erase(dummystring,(length(dummystring)-1));
}
ascent(i in 0..length(dummystring)){
if((length(dummystring)-i)%3==0 && i!=0){
dummystring2 = dummystring2 ~ ",";
}
if(i==0){
dummystring2 = ToString(dummystring[0]);
}else{
dummystring2 = dummystring2 ~ ToString(dummystring[i]);
}
}
return dummystring2;
}
Title: Re: Useful Miscellaneous Code Snippets
Post by: Iryan on February 22, 2010, 07:08:51 PM
Great idea for a thread and a very useful piece of code.

*thumbsup*


So, I think I'll make an addition, a piece of code that I created on request for someone in the Q&A thread. Someone else provided another solution to the problem (actually I think it was you  :V), but this one works too, so anyways:

GetPointToLine(ox, oy, p1x, p1y, p2x, p2y);

This function returns the (minimum) distance between a specific point and a specific line. Note that it will return either a positive or a negative value, depending on which side of the line your point is located. I left it this way since this can be useful for several things, and if you want the absolute value you can simply use (| |) brackets, anyways.

Parameters:

ox, oy: Coordinates of the seperate point.
p1x, p1y: Coordinates of one point that lies on the line.
p2x, p2y: Coordinates of another point that lies on the line.

Interchanging the p1 and p2 coordinates switches the output from positive to negative (and vice versa).

Code: [Select]
function GetPointToLine(ox, oy, p1x, p1y, p2x, p2y){

let anorm=atan2(p1y-p2y, p1x-p2x)-90;
let n1=cos(anorm);
let n2=sin(anorm);

let dist= ( (ox-p1x)*cos(anorm)+(oy-p1y)*sin(anorm) )/(( (n1)^2 + (n2)^2 )^0.5) ;

return dist;
}


On popular demand, here a function that requires the function above to function:


GetPointInRectangle(ox, oy, pcx, pcy, recl, recw, align);

This function checks wether or not a given point lies within a given rectangle. Returns true if it is and false if it isn't.

Parameters:

ox, oy: Coordinates of the seperate point.
pcx, pcy: Coordinates of the center of the rectangle.
recl, recw: Length and width of the rectangle.
align: the alignment of the rectangle, i.e. the angle the longer side points at.

Code: [Select]
function GetPointInRectangle(ox, oy, pcx, pcy, recl, recw, align){

let dist1;
let dist2;
let isit=false;

dist1=(| GetPointToLine(ox, oy, pcx, pcy, pcx+cos(align), pcy+sin(align)) |);
dist2=(| GetPointToLine(ox, oy, pcx, pcy, pcx+cos(align+90), pcy+sin(align+90)) |);

if( (dist1<0.5*recw)&&(dist2<0.5*recl) ){ isit=true; }

return(isit);
}
Title: Re: Useful Miscellaneous Code Snippets
Post by: Suikama on February 23, 2010, 01:12:11 AM
wait
Stalls for n number of frames
Only usable in tasks. Make sure to have "yield;" somewhere in your @MainLoop.
Code: [Select]
function wait(n){loop(n){yield;}}
:smug:
Title: Re: Useful Miscellaneous Code Snippets
Post by: AweStriker Nova on February 23, 2010, 02:07:27 AM
GetDistance(x1,y1,x2,y2)
Code: [Select]
function GetDistance(x1,y1,x2,y2){
return(((x2-x1)^2+(y2-y1)^2)^(1/2))
}
gets the distance between point (x1,y1) and point (x2,y2).
Title: Re: Useful Miscellaneous Code Snippets
Post by: Blargel on February 23, 2010, 07:04:35 AM
A few angle related functions that might be helpful.

NormalizeAngle(angle)

Converts the passed in angle into an angle between 0 and 360, not including 360.
Examples: NormalizeAngle(540) = 180, NormalizeAngle(-270) = 90, NormalizeAngle(360) = 0.

Code: [Select]
function NormalizeAngle(angle){
  angle %= 360;
  if(angle<0){ angle += 360; }
  return angle;
}



IsSameAngle(angle1, angle2)

Checks if angle1 is the same angle as angle2. Returns true if they are, false if they are not.
Makes use of the NormalizeAngle function above.
Examples: IsSameAngle(0, 360) = true, IsSameAngle(-90, 270) = true, IsSameAngle(-30, 30) = false.

Code: [Select]
function IsSameAngle(angle1, angle2){
  angle1 = NormalizeAngle(angle1);
  angle2 = NormalizeAngle(angle2);
  return angle1==angle2;
}



AngularDistance(angle1, angle2)

Gets the smallest angle between angle1 and angle2. Will always return a number between -180 and 180, not including -180. A positive number means the shortest way from angle1 to angle2 goes clockwise, a negative number means the shortest way goes counterclockwise. Also uses the NormalizeAngle function from above.
Examples: AngularDistance(90, 180) = 90, AngularDistance(180, 90) = -90, AngularDistance(1, 359) = -2.

Code: [Select]
function AngularDistance(angle1, angle2){
  let distance = NormalizeAngle(angle2 - angle1);
  if(distance>180){ distance-=360; }
  return distance;
}



That last one may seem weird to you, but it's pretty handy for homing bullets that need to decide if they should turn left or right.
Title: Re: Useful Miscellaneous Code Snippets
Post by: Azure Lazuline on February 23, 2010, 07:42:29 AM
ObjEffect_SetAlpha(obj,vertices,alpha)

Since Obj_SetAlpha doesn't work with effect objects, you need to loop through each vertex with ObjEffect_SetVertexColor instead. That's boring, so I made a function for it. obj is the object to apply it to, vertices is the number of vertices of the object, and alpha is the alpha value to set it to. You can also easily modify this to allow color setting in addition to alpha.

Code: [Select]
function ObjEffect_SetAlpha(obj,vertices,alpha){
let k=0;
loop(vertices){
ObjEffect_SetVertexColor(obj,k,alpha,255,255,255);
k++;
}
}
Title: Re: Useful Miscellaneous Code Snippets
Post by: Blargel on February 23, 2010, 09:16:17 AM
Oh right object related stuff. I made a few creation functions that automatically set all the initial behaviors because typing out those Obj_SetPosition, Obj_SetSpeed, Obj_SetAngle, and all that gets annoying when you do it a lot.

ObjShot_Create(x, y, speed, angle, graphic, delay)

Creates a shot object while setting up all the initial values. It then returns the object ID so you can do manipulations with it later.
Code: [Select]
function ObjShot_Create(x, y, speed, angle, graphic, delay){
  let obj = Obj_Create(OBJ_SHOT);
  Obj_SetPosition(obj, x, y);
  Obj_SetSpeed(obj, speed);
  Obj_SetAngle(obj, angle);
  ObjShot_SetGraphic(obj, graphic);
  ObjShot_SetDelay(obj, delay);
  return obj;
}



ObjLaser_Create(x, y, angle, length, width, graphic, delay)

Creates a laser object while setting up all the initial values. It then returns the object ID so you can do manipulations with it later.
Code: [Select]
function ObjLaser_Create(x, y, angle, length, width, graphic, delay){
  let obj = Obj_Create(OBJ_LASER);
  Obj_SetPosition(obj, x, y);
  //Obj_SetSpeed is skipped because it is ignored by laser objects.
  Obj_SetAngle(obj, angle);
  ObjLaser_SetLength(obj, length);
  ObjLaser_SetWidth(obj, width);
  ObjShot_SetGraphic(obj, graphic);
  ObjShot_SetDelay(obj, delay);
  return obj;
}



ObjSinuateLaser_Create(x, y, speed, angle, length, width, graphic, delay)

Creates a curvy laser object while setting up all the initial values. It then returns the object ID so you can do manipulations with it later.
Code: [Select]
function ObjSinuateLaser_Create(x, y, speed, angle, length, width, graphic, delay){
  let obj = Obj_Create(OBJ_SINUATE_LASER);
  Obj_SetPosition(obj, x, y);
  Obj_SetSpeed(obj, speed);
  Obj_SetAngle(obj, angle);
  ObjSinuateLaser_SetLength(obj, length);
  ObjSinuateLaser_SetWidth(obj, width);
  ObjShot_SetGraphic(obj, graphic);
  ObjShot_SetDelay(obj, delay);
  return obj;
}

EDIT: Fixed a few mistakes I just noticed. Was typing these from memory rather than copy-pasting.
Title: Re: Useful Miscellaneous Code Snippets
Post by: AweStriker Nova on February 25, 2010, 04:22:38 AM
Object Sinuates have their own SetLength and SetWidth functions, though. They work fine:

Code: [Select]
ObjSinuateLaser_SetWidth(obj,width);
ObjSinuateLaser_SetLength(obj,length);
Title: Re: Useful Miscellaneous Code Snippets
Post by: Blargel on February 25, 2010, 06:12:01 AM
Yeah I noticed that, but didn't want to edit it again to annoy people to death with NEW markers next to the thread when there really isn't anything new. Editing it now, lol.
Title: Re: Useful Miscellaneous Code Snippets
Post by: Helepolis on February 25, 2010, 10:07:20 AM
Suikama =.= I send you a pm but either you missed it or ignored it :V

' Wait '  is an official function in Dnh that halts the dialogue for x-amount of frames. Either type lower capital w or change the name. FAST BEFORE I GUGNIR YOU.
Title: Re: Useful Miscellaneous Code Snippets
Post by: Suikama on February 25, 2010, 03:58:56 PM
Just don't use it during dialogues then :V

But fine >_>
Title: Re: Useful Miscellaneous Code Snippets
Post by: Naut on February 25, 2010, 08:55:50 PM
GetPointToLine(ox, oy, p1x, p1y, p2x, p2y);

hngh

(http://i641.photobucket.com/albums/uu134/Nautth/gptl.png)

Green area indicates affected region. Obviously the upper diagram is the intended result, however your function will yield the lower diagram. Any way to adjust your code so that I can just get the first result, Iryan?

also lol I mispelled the function




Title: Re: Useful Miscellaneous Code Snippets
Post by: Iryan on February 25, 2010, 09:03:41 PM
This function returns the (minimum) distance between a specific point and a specific line.

p1x, p1y: Coordinates of one point that lies on the line.
p2x, p2y: Coordinates of another point that lies on the line.
http://en.wikipedia.org/wiki/Line_%28geometry%29 (http://en.wikipedia.org/wiki/Line_%28geometry%29)

A line stretches into infinity. Obviously the lower diagram was the intended result. What you are looking for is the distance to a line segment.

I could try to get the math of that, too, but that won't be easy, and over here I have to go to sleep in a bout an hour, so my concentration might not be the best... and when I'm scripting while tired, I do stupid stuff like confusing x and y axis with one another. This has been established by experiment. :V

Bah, I'm going to try it anyways.

Also, what your text implied you want to create is not what is shown in your diagram. The green area would look more like this:

  _______
(________)

Ie., a rectangle with half a circle attached on each end.
Title: Re: Useful Miscellaneous Code Snippets
Post by: Naut on February 25, 2010, 09:43:14 PM
A line stretches into infinity. Obviously the lower diagram was the intended result. What you are looking for is the distance to a line segment.

I meant my intended result.

Also, what your text implied you want to create is not what is shown in your diagram. The green area would look more like this:

  _______
(________)

Ie., a rectangle with half a circle attached on each end.

I know, I'm lazy. I found a workaround anyway, so I'm still abusing your code.
Title: Re: Useful Miscellaneous Code Snippets
Post by: Iryan on February 25, 2010, 10:04:03 PM
Reformated the post.

GetPointToLineSegment(ox, oy, p1x, p1y, p2x, p2y);

Returns the distance between a given point and a given line segment. For reference, look at the picture Naut posted.

Parameters:

ox, oy: Coordinates of the seperate point.
p1x, p1y: Coordinates of one point that lies on the line.
p2x, p2y: Coordinates of another point that lies on the line.


Code: [Select]
function GetPointToLineSegment(ox, oy, p1x, p1y, p2x, p2y){

let distance;

let va=atan2(p1y-p2y, p1x-p2x);
let vx=cos(va);
let vy=sin(va);

let anorm=va-90;
let n1=cos(anorm);
let n2=sin(anorm);

// ->n = [cos(anorm), sin(anorm)] = [n1, n2]

// g:  [ox-p1x, oy-p1y]*[n1, n2]=0;

// a*->v + b*->n = o->p1/2

let b= ( (oy-p1y-ox*vy/vx+p1x*vy/vx)/(n2-n1*vy/vx) );

let a= ( (ox-p1x-n1*b)/vx  );

if( a<0){
let b= ( (oy-p2y-ox*vy/vx+p2x*vy/vx)/(n2-n1*vy/vx) );
let a= ( (ox-p2x-n1*b)/vx  );

if(a>0){ distance=( (ox-p1x)*cos(anorm)+(oy-p1y)*sin(anorm) )/(( (n1)^2 + (n2)^2 )^0.5);
} else{
distance=( (ox-p2x)^2 + (oy-p2y)^2 )^0.5;
}
} else{
distance=( (ox-p1x)^2 + (oy-p1y)^2 )^0.5;

}
distance=(|distance|);

return distance;
}
Title: Re: Useful Miscellaneous Code Snippets
Post by: Naut on February 25, 2010, 10:14:49 PM
ty ilu
Title: Re: Useful Miscellaneous Code Snippets
Post by: Blargel on February 26, 2010, 11:55:08 AM
GetPlayerMoveAngle

Returns the angle the player is moving at. Based off of button inputs so if the player is at the edge of the screen, it may or may not suit your purposes. Good for player scripts with shots that need to be directable based off of which way the player is moving. Returns NULL if the player is not moving.
Code: [Select]
function GetPlayerMoveAngle {
  let angle = NULL;
  if(GetKeyState(VK_DOWN)==KEY_HOLD){
    if(GetKeyState(VK_RIGHT)==KEY_HOLD){
      angle = 45;
    }
    else if(GetKeyState(VK_LEFT)==KEY_HOLD){
      angle = 135;
    }
    else {
      angle = 90;
    }
  }
  else if(GetKeyState(VK_UP)==KEY_HOLD){
    if(GetKeyState(VK_RIGHT)==KEY_HOLD){
      angle = 315;
    }
    else if(GetKeyState(VK_LEFT)==KEY_HOLD){
      angle = 225;
    }
    else {
      angle = 270;
    }
  }
  else if(GetKeyState(VK_RIGHT)==KEY_HOLD){
    angle = 0;
  }
  else if(GetKeyState(VK_LEFT)==KEY_HOLD){
    angle = 180;
  }
  return angle;
}
Title: Re: Useful Miscellaneous Code Snippets
Post by: Prime 2.0 on February 27, 2010, 08:33:27 AM
GetPlayerMoveAngle

Does Danmakufu support joystick/analogue control? Because that code of yours sure doesn't.  :V
Title: Re: Useful Miscellaneous Code Snippets
Post by: Blargel on February 27, 2010, 08:44:52 AM
Does Danmakufu support joystick/analogue control? Because that code of yours sure doesn't.  :V

Danmakufu only detects 8 directions so... I'm pretty sure this will work fine.
Title: Re: Useful Miscellaneous Code Snippets
Post by: Suikama on February 27, 2010, 06:32:40 PM
Danmakufu only detects 8 directions so... I'm pretty sure this will work fine.
Does Touhou only support 8 directions as well?
Title: Re: Useful Miscellaneous Code Snippets
Post by: Azure Lazuline on February 27, 2010, 07:23:14 PM
Yes, I know that all official games (and Danmakufu) only support 8 directions.
Title: Re: Useful Miscellaneous Code Snippets
Post by: Prime 2.0 on February 27, 2010, 08:38:48 PM
Yes, I know that all official games (and Danmakufu) only support 8 directions.

Really? I thought PCB and on had omnidirectional support when using a joystick.
Title: Re: Useful Miscellaneous Code Snippets
Post by: Blargel on February 28, 2010, 04:03:17 PM
Hmmmm, I have reason to believe that the GetPointToLineSegment code isn't working correctly. I dunno how to test it, but it wasn't working right when I used it. I have some code that I Googled out and converted to Danmakufu code and it seems to work better:

Code: [Select]
function GetPointToLineSegment(cx, cy, ax, ay, bx, by){

  let distanceLine;
  let distanceSegment;

  let r_numerator = (cx-ax)*(bx-ax) + (cy-ay)*(by-ay);
  let r_denomenator = (bx-ax)*(bx-ax) + (by-ay)*(by-ay);
  let r = r_numerator / r_denomenator;
 
  let px = ax + r*(bx-ax);
  let py = ay + r*(by-ay);
 
  let s =  ((ay-cy)*(bx-ax)-(ax-cx)*(by-ay) ) / r_denomenator;
 
  let distanceLine = absolute(s)*(r_denomenator^0.5);
 
  let xx = px;
  let yy = py;
  if (r>=0 && r<=1){
    distanceSegment = distanceLine;
  }
  else {
    let dist1 = (cx-ax)*(cx-ax) + (cy-ay)*(cy-ay);
    let dist2 = (cx-bx)*(cx-bx) + (cy-by)*(cy-by);
    if(dist1 < dist2){
      xx = ax;
      yy = ay;
      distanceSegment = dist1^0.5;
    }
    else {
      xx = bx;
      yy = by;
      distanceSegment = dist2^0.5;
    }
  }
  return distanceSegment;

}
Title: Re: Useful Miscellaneous Code Snippets
Post by: Iryan on February 28, 2010, 04:24:29 PM
Hmmmm, I have reason to believe that the GetPointToLineSegment code isn't working correctly. I dunno how to test it, but it wasn't working right when I used it. I have some code that I Googled out and converted to Danmakufu code and it seems to work better:
  :o

Could you please show me the (relevant part of the) script where the error occured?

Through testing around, I figured out that, probably due to dividing by approximately zero, the script ceases to work for the case p1x=p2x . Was that the case with your script, maybe?


Edit: Fixed version of my code is here.
The error I noticed won't turn up anymore. Though I have to say that the values will have inaccuracies of less than 0.01 pixels if the angle of the line lies between 89.999 and 90.001 (or 269.999 and 270.001).

Code: [Select]
function GetPointToLineSegment(ox, oy, p1x, p1y, p2x, p2y){

let distance;

let va=atan2(p1y-p2y, p1x-p2x);
let vx=cos(va);
let vy=sin(va);

let anorm=va-90;
let n1=cos(anorm);
let n2=sin(anorm);

    if(floor(10000*(|vx|))!=0 ){

let b= ( (oy-p1y-ox*vy/vx+p1x*vy/vx)/(n2-n1*vy/vx) );

let a= ( (ox-p1x-n1*b)/vx  );

if( a<0){
let b= ( (oy-p2y-ox*vy/vx+p2x*vy/vx)/(n2-n1*vy/vx) );
let a= ( (ox-p2x-n1*b)/vx  );

if(a>0){ distance=( (ox-p1x)*cos(anorm)+(oy-p1y)*sin(anorm) )/(( (n1)^2 + (n2)^2 )^0.5);
} else{
distance=( (ox-p2x)^2 + (oy-p2y)^2 )^0.5;
}
} else{
distance=( (ox-p1x)^2 + (oy-p1y)^2 )^0.5;

}
distance=(|distance|);

    } else{

let uy=(p1y+p2y-(|p1y-p2y|))/2;
let ly=(p1y+p2y+(|p1y-p2y|))/2;

if(oy<=uy){
distance=( (p1x-ox)^2 + (uy-oy)^2 )^0.5;
}
if(oy>=ly){
distance=( (p1x-ox)^2 + (ly-oy)^2 )^0.5;
}
if(oy>uy&&oy<ly){
distance=(| p1x-ox |);
}

    }

    return distance;
}
Title: Re: Useful Miscellaneous Code Snippets
Post by: Blargel on February 28, 2010, 06:17:17 PM
I'm not entirely sure what the problem was. I was trying to find the distance from the enemy to a line drawn from the player to a point 80 pixels away from the player. I noticed being strange while the line was drawn at a 270 degree angle when I did if(GetPointToLineSegment(enemyx, enemyy, GetPlayerX, GetPlayerX, endx, endy) < 16). That condition never became true for some odd reason, even if I purposely made the line intersect the enemy. If I increased 16 to 32, it would become true sometimes, but noticeably smaller than it should be.
Title: Re: Useful Miscellaneous Code Snippets
Post by: Iryan on February 28, 2010, 06:26:15 PM
Ah, so it was this peculiar problem. But now that I have fixed it, my code takes up more space then yours. Daaaymn.

Though I'd really like to understand the math behind your code. Either it uses some formulas and theorems which I am not aware of, or it only uses the respectie equations it in a solved form in which I can not perceive them anymore...
Title: Re: Useful Miscellaneous Code Snippets
Post by: Blargel on March 01, 2010, 06:42:32 AM
There was a giant explanation that I skipped through while converting it to Danmakufu code. It wasn't hard to convert anyway. :V

You can read it here (http://www.google.com/url?sa=t&source=web&ct=res&cd=1&ved=0CAkQFjAA&url=http%3A%2F%2Fwww.codeguru.com%2Fforum%2Fprintthread.php%3Ft%3D194400&rct=j&q=distance+point+line+segment&ei=vmGLS_yqIoj8sgOmhJGGAw&usg=AFQjCNGUY6oGLu726tUUHkRRR_Xi97-joQ&sig2=GShdjl4Tcr0gExlL3YBLbw).

I just read a little and I think it uses linear algebra lololol.
Title: Re: Useful Miscellaneous Code Snippets
Post by: Iryan on March 01, 2010, 03:09:29 PM
There was a giant explanation that I skipped through while converting it to Danmakufu code. It wasn't hard to convert anyway. :V

You can read it here (http://www.google.com/url?sa=t&source=web&ct=res&cd=1&ved=0CAkQFjAA&url=http%3A%2F%2Fwww.codeguru.com%2Fforum%2Fprintthread.php%3Ft%3D194400&rct=j&q=distance+point+line+segment&ei=vmGLS_yqIoj8sgOmhJGGAw&usg=AFQjCNGUY6oGLu726tUUHkRRR_Xi97-joQ&sig2=GShdjl4Tcr0gExlL3YBLbw).

I just read a little and I think it uses linear algebra lololol.
Yay! Thanks for the-

Waitaminute... I just realized I don't really understand english math vocabulary.

Blah, thanks anyways.  :V
Title: Re: Useful Miscellaneous Code Snippets
Post by: AweStriker Nova on March 05, 2010, 03:31:01 AM
Somehow this topic ended up on the second page.

Since programmers can be lazy (and we are), here's the standard code to bounce an object bullet:
Code: [Select]
if(Obj_GetX(obj)<=GetClipMinX||Obj_GetX(obj)>=GetClipMaxX){
Obj_SetAngle(obj,180-Obj_GetAngle(obj));
}
if(Obj_GetY(obj)<=GetClipMinY||Obj_GetY(obj)>=GetClipMaxY){
Obj_SetAngle(obj,360-Obj_GetAngle(obj));
}
Title: Re: Useful Miscellaneous Code Snippets
Post by: Blargel on March 05, 2010, 05:39:05 PM
Dunno if this belongs here or not but...

ShootShape

Shoots a geometric shape from the specified point. (x, y) is the point to spawn the shape, speed is the speed the corners move at, angle is the angle one of the corners will shoot at, graphic and delay are pretty self explanatory, corners is the number of corners, and bullets is the number of bullets per side.

As an example with the corners and bullets parameters, if you put 4 for corners and 10 for bullets, you will get a square that has 10 bullets per side.

Code: [Select]
task ShootShape(x, y, speed, angle, graphic, delay, corners, bullets){
  let Corners = [];
  let SideBullets = [];
  ascent(i in 0..corners){
    let obj = Obj_Create(OBJ_SHOT);
    Corners = Corners ~ [obj];
   
    Obj_SetPosition(obj, x, y);
    Obj_SetSpeed(obj, speed);
    Obj_SetAngle(obj, angle+i*(360/corners));
    ObjShot_SetGraphic(obj, graphic);
    ObjShot_SetDelay(obj, delay);
   
    Obj_SetAlpha(obj, 0);
    Obj_SetCollisionToPlayer(obj, false);
    Obj_SetAutoDelete(obj, false);
  }
 
  ascent(i in 0..corners){
    if(i==corners-1){
      let Side = BulletLine(Corners[i], Corners[0]);
      SideBullets = SideBullets ~ [Side];
    }
    else {
      let Side = BulletLine(Corners[i], Corners[i+1]);
      SideBullets = SideBullets ~ [Side];
    }
  }
 
  while(length(SideBullets) > 0){
    descent(i in 0..length(SideBullets)){
      if(SideBullets[i] == [0]){
        SideBullets = erase(SideBullets, i);
      }
      else {
        let tempArray = SideBullets[i];
        descent(j in 1..length(tempArray)){
          if(Obj_BeDeleted(tempArray[j])){
            tempArray = erase(tempArray, j);
          }
        }
        SideBullets[i] = tempArray;
      }
    }
    yield;
  }
 
  ascent(i in 0..corners){
    Obj_Delete(Corners[i]);
  }
 
  function BulletLine(obj1, obj2){
    let SideBullets = [0];
    let DummyArray = [0];
    ascent(i in 0..bullets){
      let obj = Obj_Create(OBJ_SHOT);
      SideBullets = SideBullets ~ [obj];
      DummyArray = DummyArray ~ [0];
     
      ObjShot_SetGraphic(obj, graphic);
      ObjShot_SetDelay(obj, delay);
    }
    RealTask;
    return SideBullets;
   
    task RealTask {
      while(SideBullets != DummyArray){
        let x1 = Obj_GetX(obj1);
        let y1 = Obj_GetY(obj1);
        let x2 = Obj_GetX(obj2);
        let y2 = Obj_GetY(obj2);
        let distance = ((x1-x2)^2 + (y1-y2)^2)^0.5;
        let interval = distance/bullets;
        let angle = atan2(y2-y1, x2-x1);
        descent(i in 1..length(SideBullets)){
          if(Obj_BeDeleted(SideBullets[i])){
            SideBullets[i] = 0;
          }
          else {
            let xo = Obj_GetX(SideBullets[i]);
            let yo = Obj_GetY(SideBullets[i]);
           
            Obj_SetPosition(SideBullets[i], x1+cos(angle)*interval*i, y1+sin(angle)*interval*i);
           
            let xn = Obj_GetX(SideBullets[i]);
            let yn = Obj_GetY(SideBullets[i]);
            let newangle = atan2(yn-yo, xn-xo);
           
            Obj_SetAngle(SideBullets[i], newangle);
          }
        }
        yield;
      }
    }
  }
}
Title: Re: Useful Miscellaneous Code Snippets
Post by: Blargel on April 06, 2010, 03:45:34 AM
These functions should be useful to anyone who has to make a large amount of rectangular effect objects.



ObjEffect_InitializeRect(texture, layer)
Initializes an effect object with 4 vertices with the specified texture and on the specified layer.

Code: [Select]
function ObjEffect_InitializeRect(texture, layer){
  let obj = Obj_Create(OBJ_EFFECT);
  ObjEffect_SetTexture(obj, texture);
  ObjEffect_SetLayer(obj, layer);
  ObjEffect_SetPrimitiveType(obj, PRIMITIVE_TRIANGLEFAN);
  ObjEffect_CreateVertex(obj, 4);
  return obj;
}

ObjEffect_SetXYRect(id, left, top, right, bottom)
Sets the 4 XY vertices for an effect object created with the initialize function above.

Code: [Select]
function ObjEffect_SetXYRect(id, left, top, right, bottom){
  ObjEffect_SetVertexXY(id, 0, left, top);
  ObjEffect_SetVertexXY(id, 1, right, top);
  ObjEffect_SetVertexXY(id, 2, right, bottom);
  ObjEffect_SetVertexXY(id, 3, left, bottom);
}

ObjEffect_SetUVRect(id, left, top, right, bottom)
Sets the 4 UVvertices for an effect object created with the initialize function above.

Code: [Select]
function ObjEffect_SetUVRect(id, left, top, right, bottom){
  ObjEffect_SetVertexUV(id, 0, left, top);
  ObjEffect_SetVertexUV(id, 1, right, top);
  ObjEffect_SetVertexUV(id, 2, right, bottom);
  ObjEffect_SetVertexUV(id, 3, left, bottom);
}

ObjEffect_SetColor
Sets the alpha and color of all of an effect object's vertices in one go. You have to tell it how many vertices are in the effect though.

Code: [Select]
function ObjEffect_SetColor(id, vertexes, a, r, g, b){
  ascent(i in 0..vertexes){
    ObjEffect_SetVertexColor(id, i, a, r, g, b);
  }
}
Title: Re: Useful Miscellaneous Code Snippets
Post by: Drake on April 10, 2010, 09:21:11 PM
DeleteShotInCircleEx(type, item, x, y, initradius, maxradius, accel)
Expands a circle of a specified radius at point (x,y) to maximum specified radius. Bullets in the circle are either deleted or turned to items. Can also activate player invincibility.

Code: [Select]
task DeleteShotInCircleEx(item, type, x, y, initradius, maxradius, grow, invincibility){
let currentradius = initradius;
while(currentradius!=maxradius){
if(item){
DeleteEnemyShotToItemInCircle(type,x,y,currentradius);
}else{
DeleteEnemyShotInCircle(type,x,y,currentradius);
}
currentradius+=grow;
if(invincibility){SetPlayerInvincibility(2);}
yield;
}
if(invincibility){SetPlayerInvincibility(0);}
}
Title: Re: Useful Miscellaneous Code Snippets
Post by: RavenEngie on April 16, 2010, 07:11:10 PM
RoughlyEqualTo
Sometimes you're off by a tiny amount, and danmakufu doesn't pick up on it when you need to see if two numbers are equal. This is a bugger to sort out, sometimes.
num1 , num2 : The two numbers you want to compare
errormargin : How far apart they've to be to be considered 'equal' (Use something with a decimal point and a few zero's in front. Otherwise it'll be ridiculous. :V)
Examples :
RoughlyEqualTo(4.5, 4.4999, 0.0125) = true
RoughlyEqualTo(20, 10, 1) = false
RoughlyEqualTo(2, 1, 50) = true  (Don't. :V)
Code: [Select]
function RoughlyEqualTo(num1, num2, errormargin)
{
    if(num1 >= num2 - errormargin && num1 <= num2 + errormargin)
    {
        return true;
    } else
    {
        return false;
    }
}
Title: Re: Useful Miscellaneous Code Snippets
Post by: Blargel on April 16, 2010, 10:05:18 PM
I know I'm being really anal about this, but this sort of unnecessary stuff really bugs me.  :V
Code: [Select]
function RoughlyEqualTo(num1, num2, errormargin){
    return absolute(num1-num2) <= errormargin;
}

The big offender in my mind was how you used an if else construction when a comparison already gives you true or false, but I also had a simpler way to do the math.



EDIT: More geometry. With terrible function names, but I have no idea what the hell I should call them.

YOnLineFromX(x1, y1, x2, y2, x3)
Gets the y-coordinate of the point that has an x-coordinate of x3 and that is on the line defined by the points (x1, y1) and (x2, y2). Returns y2 if x1 is equal to x2.

Code: [Select]
function YOnLineFromX(x1, y1, x2, y2, x3){
  let a_numerator = y2-y1;
  let a_denominator = x2-x1;
  if(a_denominator==0){
    return y2;
  }
  else {
    let a = a_numberator/a_denominator;
    let xDist = x3-x2;
    let yDist = xDist*a;
    let y3 = y2+yDist;
    return y3;
  }
}


XOnLineFromY(x1, y1, x2, y2, y3)
Gets the x-coordinate of the point that has a y-coordinate of y3 and that is on the line defined by the points (x1, y1) and (x2, y2). Returns x2 if y1 is equal to y2.

Code: [Select]
function XOnLineFromY(x1, y1, x2, y2, y3){
  let a_numerator = y2-y1;
  let a_denominator = x2-x1;
  if(a_numerator==0){
    return x2;
  }
  else {
    let a = a_numberator/a_denominator;
    let yDist = y3-y2;
    let xDist = yDist/a;
    let x3 = x2+xDist;
    return x3;
  }
}
Title: Re: Useful Miscellaneous Code Snippets
Post by: RavenEngie on April 17, 2010, 10:10:22 PM
I know I'm being really anal about this, but this sort of unnecessary stuff really bugs me.  :V

The big offender in my mind was how you used an if else construction when a comparison already gives you true or false, but I also had a simpler way to do the math.

Yes. Yes you are.
And gimme a break. I'm recovering from an incredibly over-exaggerated serious bout of the flu. Hell, I can't even beat my own scripts these days.
'Sides, I didn't know about that absolute thingy.

But meh, learned something new there.
Title: Re: Useful Miscellaneous Code Snippets
Post by: Naut on May 10, 2010, 03:02:45 AM
old code
Title: Re: Useful Miscellaneous Code Snippets
Post by: Drake on May 10, 2010, 03:34:51 AM
Just going to add "No bitching about how simple the hitbox is" here. Take it, change image, screw around with code. Do it yourself. It's an outline, basically.
Title: Re: Useful Miscellaneous Code Snippets
Post by: Naut on May 15, 2010, 06:10:21 PM
Improved the hitbox code a bit, since Drake said it was too simple >: |



Here's some code to add in a working Touhou-style hitbox to your player characters, simply by copy/pasting.

Save this image in the same directory as your player script as thHitbox.png (alternatively, change the image pathname in the script):
(http://i641.photobucket.com/albums/uu134/Nautth/thHitbox.png)

Copy and paste this code inside script_player_main (preferably towards the beginning of it):
Code: [Select]
let objHitbox = NULL;
let objHitboxCopy = NULL;
let objHitboxGraphic = GetCurrentScriptDirectory~"thHitbox.png";
let objHitboxScale = 0;
let objHitboxAngle = 0;
let objHitboxAngleVel = 103;
let objHitboxCopyScale = 1.45;

sub CreateHitbox{
LoadGraphic(objHitboxGraphic);
objHitbox = Obj_Create(OBJ_EFFECT);
ObjEffect_SetTexture(objHitbox, objHitboxGraphic);
ObjEffect_SetRenderState(objHitbox, ALPHA);
ObjEffect_SetLayer(objHitbox, 4);
ObjEffect_SetPrimitiveType(objHitbox, PRIMITIVE_TRIANGLEFAN);
ObjEffect_CreateVertex(objHitbox, 4);
ObjEffect_SetVertexUV(objHitbox, 0, 0, 0);
ObjEffect_SetVertexUV(objHitbox, 1, 63, 0);
ObjEffect_SetVertexUV(objHitbox, 2, 63, 63);
ObjEffect_SetVertexUV(objHitbox, 3, 0, 63);
ObjEffect_SetVertexXY(objHitbox, 0, -32, -32);
ObjEffect_SetVertexXY(objHitbox, 1, 32, -32);
ObjEffect_SetVertexXY(objHitbox, 2, 32, 32);
ObjEffect_SetVertexXY(objHitbox, 3, -32, 32);
objHitboxCopy = Obj_Create(OBJ_EFFECT);
ObjEffect_SetTexture(objHitboxCopy, objHitboxGraphic);
ObjEffect_SetRenderState(objHitboxCopy, ALPHA);
ObjEffect_SetLayer(objHitboxCopy, 4);
ObjEffect_SetPrimitiveType(objHitboxCopy, PRIMITIVE_TRIANGLEFAN);
ObjEffect_CreateVertex(objHitboxCopy, 4);
ObjEffect_SetVertexUV(objHitboxCopy, 0, 0, 0);
ObjEffect_SetVertexUV(objHitboxCopy, 1, 63, 0);
ObjEffect_SetVertexUV(objHitboxCopy, 2, 63, 63);
ObjEffect_SetVertexUV(objHitboxCopy, 3, 0, 63);
ObjEffect_SetVertexXY(objHitboxCopy, 0, -32, -32);
ObjEffect_SetVertexXY(objHitboxCopy, 1, 32, -32);
ObjEffect_SetVertexXY(objHitboxCopy, 2, 32, 32);
ObjEffect_SetVertexXY(objHitboxCopy, 3, -32, 32);
}

sub DrawHitbox{
if(GetKeyState(VK_SLOWMOVE)==KEY_PUSH || GetKeyState(VK_SLOWMOVE)==KEY_HOLD){
if(GetKeyState(VK_SLOWMOVE)==KEY_PUSH){
objHitboxCopyScale = 1.45;
}
if(objHitboxAngleVel>3){
objHitboxAngleVel -= 5;
}
if(objHitboxScale<1){
objHitboxScale += 0.2;
}
if(objHitboxCopyScale>1){
objHitboxCopyScale-=0.05;
}
objHitboxAngle += objHitboxAngleVel;
ObjEffect_SetAngle(objHitbox, 0, 0, objHitboxAngle);
ObjEffect_SetScale(objHitbox, objHitboxScale, objHitboxScale);
ObjEffect_SetAngle(objHitboxCopy, 0, 0, -objHitboxAngle);
ObjEffect_SetScale(objHitboxCopy, objHitboxCopyScale, objHitboxCopyScale);
Obj_SetPosition(objHitbox, GetPlayerX, GetPlayerY);
Obj_SetPosition(objHitboxCopy, GetPlayerX, GetPlayerY);
}else{
if(objHitboxScale>0){
objHitboxScale -= 0.2;
}else{
objHitboxScale = 0;
}
if(objHitboxCopyScale>0){
objHitboxCopyScale -= 0.2;
}else{
objHitboxCopyScale = 0;
}

objHitboxAngleVel = 103;
ObjEffect_SetAngle(objHitbox, 0, 0, objHitboxAngle);
ObjEffect_SetScale(objHitbox, objHitboxScale, objHitboxScale);
ObjEffect_SetAngle(objHitboxCopy, 0, 0, -objHitboxAngle);
ObjEffect_SetScale(objHitboxCopy, objHitboxCopyScale, objHitboxCopyScale);
}
}

Put this in @Initialize:
Code: [Select]
CreateHitbox;

Put this in @DrawLoop:
Code: [Select]
DrawHitbox;

Hooray you now have a Touhou-style hitbox!

(http://i641.photobucket.com/albums/uu134/Nautth/zenhitbox.jpg)
Title: Re: Useful Miscellaneous Code Snippets
Post by: Henry on May 16, 2010, 02:42:38 PM
I had a try on the reflect function on Touhou Wiki add find that it has bugs which automatically delete lasers when it's head merely pass the border.

Therefore, here is a revised version of that function. Additional features also added.
Parameters:
v stands for velocity, that is speed in daily language  :D
maxLen is the length of laser it is the "max" due to lengthening effect present
delay is the time interval between call of function and firing of laser, esp. useful when a spiral pattern is produced.
count is the number of time of allowed reflection.


Usage:
Call TReflectionalLaser only, the other 2 functions just helps this function and has no meaning when used alone.

Here is the code:
Code: [Select]
task TReflectionLaser(x, y, v, angle, maxLen, width, graphic, delay, count){
   //adjust the angle
   while(angle>=180){angle-=360;}
   while(angle<-180){angle+=360;}

   loop(delay){yield;}
   //bullet object
   let obj=Obj_Create(OBJ_LASER);

   //initial settings
   Obj_SetPosition(obj, x, y);
   Obj_SetAngle(obj, angle);
   ObjLaser_SetWidth(obj, width);
   ObjShot_SetGraphic(obj, graphic);
   Obj_SetAutoDelete(obj, false);
   ObjLaser_SetSource(obj, false);
   TReflectionLaser_Lengthen(obj, maxLen, v);
   TReflectionLaser_Move(obj, x, y, v, angle);

   while(!Obj_BeDeleted(obj)){
      if(x>GetClipMaxX&&x+maxLen*cos(angle)>GetClipMaxX||x<GetClipMinX&&x+maxLen*cos(angle)<GetClipMinX||y<GetClipMinY&&y+maxLen*sin(angle)<GetClipMinY){Obj_Delete(obj);}
      x=Obj_GetX(obj);
      y=Obj_GetY(obj);
      // reflection detection
      if(angle<0 && y<GetClipMinY && x>GetClipMinX && x<GetClipMaxX){
         //ceil
         if(count>0){TReflectionLaser(x, y, v, -angle, maxLen, width, graphic, 0, count-1);}
         break;
      }else
      if(((-90<angle && angle<90) && x>GetClipMaxX)||((angle<-90 || 90<angle) && x <GetClipMinX) && y>GetClipMinY && y<GetClipMaxY){
         //wall
         if(count>0){TReflectionLaser(x, y, v, 180 - angle, maxLen, width, graphic, 0, count-1);}
         break;
      }
      yield;
   }
}

//lengthen the object laser
task TReflectionLaser_Lengthen(obj, maxLen, v) {
   let len=0;
   let max=floor(maxLen/v);
   let i=0;
   while(!Obj_BeDeleted(obj)) {
      //When the length is negative,
      //the laser extends backward.
      ObjLaser_SetLength(obj, -len);
      yield;
      if(i<max){
         len+=v;
         i++;
      }else
      if(i==max){
         ObjLaser_SetLength(obj, -maxLen);
         break;
      }
   }
}

// move the object laser
// Since Obj_SetSpeed is ignored in case of object laser,
// the motion needs to be controlled by Obj_SetPosition.
task TReflectionLaser_Move(obj, x, y, v, angle) {
   let vx=v*cos(angle);
   let vy=v*sin(angle);
   while(!Obj_BeDeleted(obj)){
      Obj_SetPosition(obj, x, y);
      yield;
      x+=vx;
      y+=vy;
   }
}
Title: Re: Useful Miscellaneous Code Snippets
Post by: Naut on May 16, 2010, 06:33:13 PM
lol nope
Title: Re: Useful Miscellaneous Code Snippets
Post by: Blargel on May 25, 2010, 11:11:30 AM
GetPreviousScriptDirectory
Gets the directory that the current script's directory is in. Example: if the script is in "script\folder1\folder2\hi.txt", it'll return "script\folder1\"

Code: [Select]
function GetPreviousScriptDirectory(){
  let current = GetCurrentScriptDirectory();
  current = erase(current, length(current)-1);
  while(current[length(current)-1] != '\'){
    current = erase(current, length(current)-1);
  }
  return current;
}



GetPreviousScriptDirectoryEx
Similar to the previous function, but now you can specify how many levels to go up. Putting 1 will have the same effect as the last function. Putting 0 will return the exact same thing as GetCurrentScriptDirectory().

Code: [Select]
function GetPreviousScriptDirectoryEx(num){
  let current = GetCurrentScriptDirectory();
  loop(num){
    current = erase(current, length(current)-1);
    while(current[length(current)-1] != '\'){
      current = erase(current, length(current)-1);
    }
  }
  return current;
}
Title: Re: Useful Miscellaneous Code Snippets
Post by: Drake on May 25, 2010, 05:27:01 PM
ilu blargel

You people better use that.
Title: Re: Useful Miscellaneous Code Snippets
Post by: Chronojet ⚙ Dragon on June 09, 2010, 05:54:28 AM
Code: (Stage functions) [Select]
function WaitForNoEnemy { while(GetEnemyNum!=0) { yield; } }
function WaitToNumOfEnemy(num) { while(GetEnemyNum!=num) { yield; } }
function WaitForFrames(framestowait) { loop(framestowait) { yield; } }
function WaitForNoBomb { while(OnBomb) { yield; } }
function WaitForAlive { while(OnPlayerMissed) { yield; } }
function WaitForDead { while(!OnPlayerMissed) { yield; } }
function WaitForNoInvincibility { while(GetTimeOfSuperNaturalBorder != 0 && GetTimeOfPlayerInvincibility != 0) { yield; } }
function WaitForNoEvent { while(OnEvent) { yield; } }

Seriolusly, no one ever bothered? :getdown:
Title: Re: Useful Miscellaneous Code Snippets
Post by: Chronojet ⚙ Dragon on June 13, 2010, 05:53:02 PM
Is there a function to get the largest value in a number array?

/me needs it for a "thing" he's making for a certain other project
Title: Re: Useful Miscellaneous Code Snippets
Post by: Iryan on June 13, 2010, 06:09:45 PM
Is there a function to get the largest value in a number array?

/me needs it for a "thing" he's making for a certain other project
Shouldn't be a problem.

Edit: Fixed the code.

Function name: ArrMax(array);

Use: Returns the highest value of all the values in the chosen array.

Parameters: array = name of the array




Code: [Select]
function ArrMax(array){
let n = 0;
let value=array[0];
while( n<length(array) ){
if(array[n]>value){ value=array[n]; }
n++;
}
return(value);
}
Title: Re: Useful Miscellaneous Code Snippets
Post by: Chronojet ⚙ Dragon on June 13, 2010, 10:25:29 PM
Shouldn't be a problem.

Edit: Fixed the code.

<code description>
<long code>

OH YES.
/me goes to make mini PMD-related thing

EDIT: Wait, wait, wait.
What will happen if there are two or more "largest values"?
Title: Re: Useful Miscellaneous Code Snippets
Post by: Iryan on June 14, 2010, 12:31:46 AM
Look at the code, it is not that huge or difficult, and you will be able to answer that question yourself.

Why would that make a difference? Or did you actually want the function to return the spot in the array that holds the largest value instead of the value itself?  :/
Title: Re: Useful Miscellaneous Code Snippets
Post by: Naut on June 16, 2010, 06:12:48 AM
LineToLinePoint
Eight parameters. Returns the intersection point between two lines formed by four points. First two parameters are the coordinates of a point on line one, second two parameters a different coordinate on line one. Next four parameters are the coordinates of points on line two. Returns an array [x, y]. Remember that a line is infinite, this code does not use line segments, so the line will stretch past the points you specify.

Code: [Select]
function LineToLinePoint(let x1, let y1, let x2, let y2, let x3, let y3, let x4, let y4){
let point = [0, 0];
point[0] = ( ((x1*y2 - y1*x2)*(x3 - x4) - (x1 - x2)*(x3*y4 - y3*x4)) / ((x1 - x2)*(y3 - y4) - (y1 - y2)*(x3 - x4)) );
point[1] = ( ((x1*y2 - y1*x2)*(y3 - y4) - (y1 - y2)*(x3*y4 - y3*x4)) / ((x1 - x2)*(y3 - y4) - (y1 - y2)*(x3 - x4)) );
return point;
}

Can be used something like this:

let point = LineToLinePoint(100, 240, 500, 240, 224, 100, 224, 500);
CreateShot01(point[0], point[1], 3, 90, RED01, 10);


Spawns a bullet on the intersection point between the two lines made up by (100, 240), (500, 240) and (224, 100), (224, 500). The intersection point would be (224, 240).

Works great if you need to find the point at which an object installation laser collides with another line (http://www.shrinemaiden.org/forum/index.php?topic=2412.msg363562#msg363562), or something of that sort.
Title: Re: Useful Miscellaneous Code Snippets
Post by: Kylesky on June 16, 2010, 11:44:41 AM
Quote
*insert naut's megacode here*
NICE!!!
I've been looking for/trying to figure out something like this :]

EDIT: :/ that code's giving me a headache XD don't want to even analyze it... 2 questions though
1)what returns when the 2 lines don't intersect (i.e. parallel)
2)what returns when the 2 lines are the same lines/on top of each other
???

EDIT2(so I don't double post): Some random functions :V


ObjShot_Reflect(id, dist)
Basic reflection code for object bullets. dist is a number determining how past the edges of the screen will the bullet reflect, since different people like reflecting them at different distances. (Must be called every frame)
Code: [Select]
function ObjShot_Reflect(id, dist){
    if(Obj_GetX(id)<GetClipMinX-dist || Obj_GetX(id)>GetClipMaxX+dist){Obj_SetAngle(id, 180-Obj_GetAngle(id));}
    if(Obj_GetY(id)<GetClipMinY-dist || Obj_GetY(id)>GetClipMaxY+dist){Obj_SetAngle(id, 0-Obj_GetAngle(id));}
}

InField(x, y)
Detects if the said point is on the screen.
Code: [Select]
function InField(x, y){
if(x<GetClipMaxX && x>GetClipMinX && y<GetClipMaxY && y>GetClipMinY)
{
return true;
}else{
return false;
}
}

and expanding Naut's LineToLinePoint function

SegmentToSegmentCollision
Detects if 2 segments intersect.
Code: [Select]
function SegmentToSegmentCollision(let x1, let y1, let x2, let y2, let x3, let y3, let x4, let y4){
    let PoI=LineToLinePoint(x1, y1, x2, y2, x3, y3, x4, y4);
    if(Collision_Line_Circle(x1, y1, x2, y2, 1, PoI[0], PoI[1], 1)==true && Collision_Line_Circle(x3, y3, x4, y4, 1, PoI[0], PoI[1], 1)==true){
        return true;
    }else{
        return false;
    }
}

SegmentToSegmentPoint
If the 2 segments intersect, it returns the point of intersection. If they don't, it returns an array [-1000, 1000]. (yes, that was a random value)
Code: [Select]
function SegmentToSegmentPoint(let x1, let y1, let x2, let y2, let x3, let y3, let x4, let y4){
    if(SegmentToSegmentCollision(x1, y1, x2, y2, x3, y3, x4, y4)==true){
        return LineToLinePoint(x1, y1, x2, y2, x3, y3, x4, y4);
    }else{
        return [-1000, -1000];
    }
}

Haven't tested some of them, but if my logic's right, they should work...

EDIT3:
LineToLinePointB
I THINK I fixed it up to "fit" my 2 functions better and to remove dividing by 0. (maybe wrongly, or not 100% of the time...)
Code: [Select]
function LineToLinePointB(let x1, let y1, let x2, let y2, let x3, let y3, let x4, let y4){
        let slope=(y1-y2)/(x1-x2);
        let slopeb=(y3-y4)/(x3-x4);
let point = [0, 0];
        if(slope==slopeb || x1-x2==0 || x3-x4==0){
            return [-1000, 1000];
        }else{
          point[0] = ( ((x1*y2 - y1*x2)*(x3 - x4) - (x1 - x2)*(x3*y4 - y3*x4)) / ((x1 - x2)*(y3 - y4) - (y1 - y2)*(x3 - x4)) );
    point[1] = ( ((x1*y2 - y1*x2)*(y3 - y4) - (y1 - y2)*(x3*y4 - y3*x4)) / ((x1 - x2)*(y3 - y4) - (y1 - y2)*(x3 - x4)) );
    return point;
        }
}
Title: Re: Useful Miscellaneous Code Snippets
Post by: Iryan on June 19, 2010, 10:36:30 AM
Gnahahahahaha!

Although testing is a little difficult, I am ~90% certain that his code here is functional:

Function name: EllipseCollision(px, py, x, y, r, s, ang);

What it does: Checks if the point (px|py) is inside the defined ellipse. Returns "true" if it is and "false" if it isn't.

Parameters:

px, py: coordinates of the seperate point
x, y: center of the ellipse
r: maximum radius
s: minimum radius
ang: angular alignment of the ellipse



Code: [Select]
function EllipseCollision(px, py, x, y, r, s, ang){
if(
( ( (y+((r^2 - s^2)^0.5)*sin(ang) - py)^2 + (x+((r^2 - s^2)^0.5)*cos(ang) - px)^2 )^0.5
+( (y-((r^2 - s^2)^0.5)*sin(ang) - py)^2 + (x-((r^2 - s^2)^0.5)*cos(ang) - px)^2 )^0.5 )< 2*r){
return(true);
} else{ return(false);
}
}

 :dragonforce:
Title: Re: Useful Miscellaneous Code Snippets
Post by: Flyer on July 20, 2010, 12:48:17 PM
Microthread that making curving laser look smoothly.

task Beam( parameters ){ // Microthread that controls the movement of a curving laser.
   let obj=Obj_Create(OBJ_SHOT);
   CurveLaserBase02(obj,parameters); // curving laser effects will appear following the movement of an object "obj".
   while(!Obj_BeDeleted(obj)){
      // Put codes that control bullet movement you want.
      yield;
   }
}

task CurveLaserBase02(let object,let X,let Y,let spd,let wid,let ang,let grap,let killtime){ // Microthread that set basic parameters and commands to draw laser graphic.
   Obj_SetPosition(object,X,Y); // Set a starting position of laser.
   Obj_SetSpeed(object,spd); // Set a starting speed of laser.
   Obj_SetAngle(object,ang); // Set a starting angle of laser.
   ObjShot_ToItem(object,false);
   ObjShot_SetBombResist(object,true);
   while(!Obj_BeDeleted(object)){
      EffectForLaser02(object,Obj_GetX(object),Obj_GetY(object),Obj_GetSpeed(object),wid,Obj_GetAngle(object),grap,killtime);  // Create laser effect every 2 frames until starting bullet (microthread Beam) disappears.
      wait(1);
      yield;}
}

task EffectForLaser02(let obj1,let X,let Y,let spd,let wid,let ang,let grap,let killtime){ // Microthread that draws laser graphic.[/i]
   let obj=Obj_Create(OBJ_LASER); // Creates laser graphic object.
   let alpha=0;
   let length=(int(200/3*spd))/10; // Laser graphic length. If this parameter is too long, laser will look like chainsaw when spinning or so. If too short, laser will look like a rosary.
   let width=wid;
   Obj_SetPosition(obj,X,Y);
   Obj_SetAngle(obj,ang);
   ObjShot_SetGraphic(obj,grap);
   ObjLaser_SetSource(obj,false);
   ObjLaser_SetLength(obj,0); // If this parameter is not set 0, front tip of a laser will look too sharp.
   ObjLaser_SetWidth(obj,width);
   Obj_SetCollisionToPlayer(obj,true);
   Obj_SetAutoDelete(obj,true);
   ObjShot_ToItem(obj,false);
   ObjShot_SetBombResist(obj,true);
   Obj_SetAlpha(obj,alpha);
   loop(5){ // First 5 frames. This also makes front tip of a laser look smoothly.
      alpha+=(255)/5;
      Obj_SetAlpha(obj,alpha);
      yield;}
   Obj_SetAlpha(obj,alpha);
   ObjLaser_SetLength(obj,length);
   let tAngle=Obj_GetAngle(obj1);
   Obj_SetAngle(obj,(ang+tAngle)/2); // To make the line of a laser smoothly.
   let fac=Collision_Line_Circle(Obj_GetX(obj),Obj_GetY(obj),Obj_GetX(obj)+spd*4*cos(Obj_GetAngle(obj)),Obj_GetY(obj)+spd*4*sin(Obj_GetAngle(obj)),ObjLaser_GetWidth(obj)*0.5,GetPlayerX,GetPlayerY,6); // There was a error that laser don't hit characters, so I had to add this parameter. This parameter determines whether your character hit by this laser.
   let k=0;
   let wi=0;
   let gtime=0;
   loop(killtime-5){
      if(fac && GetTimeOfPlayerInvincibility==0){ShootDownPlayer;} // Bang! You're dead. Not when you're using a bomb or just ressurected.
      k++;
      wi=int(width*(0.75+0.25*cos(k*90/(killtime-5)))); // Just adjusting the width of a laser to look pretty.
      Obj_SetAlpha(obj,alpha);
      ObjLaser_SetLength(obj,ObjLaser_GetLength(obj));
      ObjLaser_SetWidth(obj,wi);
      yield;}
   Obj_Delete(obj);
}
Title: Re: Useful Miscellaneous Code Snippets
Post by: Fujiwara no Mokou on August 16, 2010, 09:18:27 PM
Load all Graphics/Images
-This is a very useful function if you want to load a large number of images (300+) for a cinematic/effect/whatever you want that requires a lot of images.
(example- 0001.png, 0002.png, 0003.png ...2401.png, 2042.png)
-Replace all strings/paths and/or variables to the desired directories.
-'PLAYING' those effects uses a similar function to this one. Note however, that delays due to lowered frames per second may be caused by a large number of object effects all present at once.
-You can prevent this delay by using only one object to do all of the animation (refreshing the Obj_SetTexture(string); directory and XY/UV vertices by using a loop in the object) and timing each frame by real-time-que instead of frame-sequential (you can do this by pairing the image number with the GetTime; function)


-if you need help recording a video-to-PNG, iwisoft Video Converter is a free program with no watermark that can do the job. You can get the link HERE (http://www.easy-video-converter.com/download/videoconverter.exe)

Code: [Select]
task load{

let totalnumberofpictures=9999;
let imgnum=1;
let numberofdigitsneeded=6; ////for the parameter of the name '000001.png', which is in the 'PNG' folder


   while(imgnum<=totalnumberofpictures){
   let arrnum=0;
   let string=""~ToString(imgnum);
   let loadstring="";

   
   loop((numberofdigitsneeded-1)-floor(log10(imgnum))){ loadstring=loadstring~ToString('0'); }  ////here, the correct number of zeros are added to loadstring before the number (ex. '0'1, '00'2, '0000'4) to get the correct parameter name of the image

   while(string[arrnum]!='.'){   loadstring=loadstring~ToString(string[arrnum]);   arrnum++; }  ///here, the actual number  is added to loadstring. (ex. 0'1', 00'2', 0000'4')

    LoadGraphic(GetCurrentScriptDirectory~"PNG\EFFECT_"~loadstring~".png");      imgnum++;  } ///LoadGraphic function is called. In this first loop, it's path would be "PNG\EFFECT_000001.png"

  //////if you have 100+ pictures loading and the game freezes, give it time. It will unfreeze and play like normal when the task is done.

}
[/code ]
Title: Re: Useful Miscellaneous Code Snippets
Post by: Areylie on September 01, 2010, 02:43:19 AM
GetPreviousScriptDirectory
Gets the directory that the current script's directory is in. Example: if the script is in "script\folder1\folder2\hi.txt", it'll return "script\folder1\"

(code here)

GetPreviousScriptDirectoryEx
Similar to the previous function, but now you can specify how many levels to go up. Putting 1 will have the same effect as the last function. Putting 0 will return the exact same thing as GetCurrentScriptDirectory().

(code here)

Fixed this for you:
Code: [Select]
function GetPreviousScriptDirectory()  {
return GetCurrentScriptDirectory()~"..\";
}
function GetPreviousScriptDirectoryEx(i) {
let s = GetCurrentScriptDirectory();
loop(i) { s = s~"..\"; }
return s;
}
Title: Re: Useful Miscellaneous Code Snippets
Post by: Azure Lazuline on September 01, 2010, 04:32:53 AM
While that works in some situations, it doesn't in others. I really don't want to go into the technical detail, but take it from me that if you use that version instead of Blargel's, you'll eventually run into some problems if you're using graphics loaded from a different directory (loading ..\img\graphic.png from a script in a folder named "stage," then calling ..\img\graphic.png from a script in a folder named "boss" will NOT work). Blame it on Danmakufu's bad path handling.
Title: Re: Useful Miscellaneous Code Snippets
Post by: Areylie on September 01, 2010, 09:54:41 AM
Yes, yes. Danmakufu refers to images by file path, blah blah. Fixed.

Code: [Select]
function BindTexture(target,file,width,height) {
    LoadGraphic(file);
    CreateRenderTarget(target,next_power(width),next_power(height));
    let rt = SetRenderTarget(target);
    SetTexture(file);
    SetGraphicRect(0,0,width,height);
    DrawGraphic(width/2,height/2);
    SetRenderTarget(rt);
    function next_power(n) {
        let t = 1;
        while(t<n){t*=2;}
        return t;
    }
}
Title: Re: Useful Miscellaneous Code Snippets
Post by: Azure Lazuline on September 01, 2010, 06:26:10 PM
Using ..\ in general is a bad idea. I guess it's time to go into the technical detail. Assume your folder setup is like this:

script
    |-bosses
    |      '-boss.txt
    |
    |-stages
    |      '-stage.txt
    |
    '-images
          '-image.png

Then, in stage.txt, you call LoadGraphic(GetCurrentScriptDirectory~"..\images\image.png");. The path is stored as "script\stages\..\images\image.png". Then, in boss.txt, you SetTexture(GetCurrentScriptDirectory~"..\images\image.png");, which presumably is the exact same graphic that you loaded. However, Danmakufu sees this as  "script\bosses\..\images\image.png", which is NOT the same as the path of the graphic you loaded. Therefore, it does not know that graphic is loaded, and the texture is not set. Blargel's GetPreviousScriptDirectory function fixes this issue, while yours does not.
I'm sorry if I sound harsh here, but I pretty much tore my hair out over this issue. I don't want others to have the same problems.
Title: Re: Useful Miscellaneous Code Snippets
Post by: Marco on September 01, 2010, 09:24:25 PM
I used Kimoblager's GetPlayerMoveAngleto move the boss, but it can go outside the field do I correct the script:
Code: [Select]
function GetPlayerMoveAngle {
  let angle = NULL;
  if(GetKeyState(VK_DOWN)==KEY_HOLD){
    if(GetKeyState(VK_RIGHT)==KEY_HOLD){
     if((GetEnemyY < 464)&& GetEnemyX <416){   angle = 45;
    }}
    else if(GetKeyState(VK_LEFT)==KEY_HOLD){
if((GetEnemyY < 464)&& GetEnemyX >32){
      angle = 135;
    }}
    else {if(GetEnemyY < 464){
      angle = 90;
    }}
  }
  else if(GetKeyState(VK_UP)==KEY_HOLD){
    if(GetKeyState(VK_RIGHT)==KEY_HOLD){if((GetEnemyY > 16)&& GetEnemyX <416){
      angle = 315;
    }}
    else if(GetKeyState(VK_LEFT)==KEY_HOLD){if((GetEnemyY > 16)&& GetEnemyX >32){
      angle = 225;
    }}
    else {if(GetEnemyY > 16){
      angle = 270;
    }}
  }
  else if(GetKeyState(VK_RIGHT)==KEY_HOLD){if(GetEnemyX <416){
    angle = 0;
  }}
  else if(GetKeyState(VK_LEFT)==KEY_HOLD){if(GetEnemyX >32){
    angle = 180;
  }}
  return angle;
}
THIS CODE IS NOT MINE IS (feel good) BLAGER'S!
Still I havn't do anything special but.... maybe can be useful...
Title: Re: Useful Miscellaneous Code Snippets
Post by: Kylesky on September 02, 2010, 11:32:39 AM
I used Kimoblager's GetPlayerMoveAngleto move the boss, but it can go outside the field do I correct the script:
Code: [Select]
blah blah blah
}
THIS CODE IS NOT MINE IS (feel good) BLAGER'S!
Still I havn't do anything special but.... maybe can be useful...

you bwoke it :/

change all the GetEnemyX to GetPlayerX and GetEnemyY to GetPlayerY... you're getting the player's position, not the boss' :V
Title: Re: Useful Miscellaneous Code Snippets
Post by: GenericTouhouFailure on September 05, 2010, 11:57:16 AM
I am bored :V
Using CREATESHOTA? Lazy to play Sound Effects?

Code: [Select]
task PlayDelaySE(se,delay){
        loop(delay){yield;}
        PlaySE(se);
}
Example: PlayDelaySE("se\se1UP.wav",20);
This waits 20 frames then plays the 1up sound effect.


Wanna make your score counter run up gradually? (like the stage clear bonuses or something)
Code: [Select]
task AddScoreEx(amount,increment){
        let c = 0;
        while(c<amount){
                AddScore(increment);
                c+=increment;
                yield;
        }
        if(c-amount>0){
                AddScore(c-amount);
        }
}
eg: AddScoreEx(23000000,100000);
This increases the score by 10000 each frame until 23000000 points are added to score.

DISCLAIMER: HAVE NOT TESTED THIS CODE SO IT MAY CONTAIN MISTAKES.
Title: Re: Useful Miscellaneous Code Snippets
Post by: tatsu011 on September 10, 2010, 08:35:14 AM
Heres some functions that I am suprised havent been seen neither on the Wiki nor in this thread (yet)
Code: [Select]
Obj_GetAngleToPlayer(obj);
Obj_SetAngleToPlayer(obj);
Code: [Select]
function Obj_GetAngleToPlayer(obj) {
return atan2(GetPlayerY - Obj_GetY(obj), GetPlayerX - Obj_GetX(obj));
}

Code: [Select]
Obj_SetAngleToPlayer(obj) {
Obj_SetAngle(obj, Obj_GetAngleToPlayer(obj);
}

Easier code = Less math to remember
Title: Re: Useful Miscellaneous Code Snippets
Post by: GenericTouhouFailure on September 10, 2010, 11:34:17 AM
No drawing functions?




ANIMATE YOUR ZUN Sprite (Works if any sprite is in the same format as ZUN's too, taken from Helepolis's tutorial)
Should be fixed now
Code: [Select]
let ZUN_f = 0;
let ZUN_f2 = 0;
task ZUNimate(sprite){
SetTexture(sprite);
SetRenderState(ALPHA);
SetAlpha(255);
SetGraphicAngle(0,0,0);
SetGraphicScale(0.9,0.9);
DrawGraphic(GetX,GetY);
}
task ZUNimateMain{
if(GetSpeedX()>0){
if(ZUN_f2<10){SetGraphicRect(0,64,64,128);}
if(ZUN_f2>=10 && ZUN_f2<20){SetGraphicRect(64,64,128,128);}
if(ZUN_f2>=20 && ZUN_f2<30){SetGraphicRect(128,64,192,128);}
if(ZUN_f2>=30){SetGraphicRect(192,64,256,128);}
ZUN_f2++;
}
if(GetSpeedX()<0){
if(ZUN_f2<10){SetGraphicRect(0,64,64,128);}
if(ZUN_f2>=10 && ZUN_f2<20){SetGraphicRect(64,64,128,128);}
if(ZUN_f2>=20 && ZUN_f2<30){SetGraphicRect(128,64,192,128);}
if(ZUN_f2>=30){SetGraphicRect(192,64,256,128);}
ZUN_f2++;
SetGraphicAngle(180,0,0);
}
if(int(GetSpeedX())==0){
if(ZUN_f<10){SetGraphicRect(0,0,64,64);}
if(ZUN_f>=10 && ZUN_f<20){SetGraphicRect(64,0,128,64);}
if(ZUN_f>=20 && ZUN_f<30){SetGraphicRect(128,0,192,64);}
if(ZUN_f>=30 && ZUN_f<40){SetGraphicRect(192,0,256,64);}
ZUN_f2 = 0;
}
ZUN_f++;
if(ZUN_f==40){ZUN_f=0;}

}

call ZUNimate(imgBoss) in DRAWLOOP and and ZUNimateMain in mainloop (got to test this)

Custom version of last spell.
This one Ends the spell only after 75 frames instead of ending on bullet contact. (not tested)
Code: [Select]
task lastspell{
yield;
c = false;
ForbidBomb(true);
loop{
if(OnPlayerMissed && !c){
c = true;
loop(75){ yield;}
AddLife(-GetLife);
ExtendPlayer(1);
break;
}

yield;
}
}
Title: Re: Useful Miscellaneous Code Snippets
Post by: Azure Lazuline on September 10, 2010, 06:06:51 PM
That ZUNimate function has one mistake - you're incrementing a variable in DrawLoop, which means the animation will always increment once per drawn frame. In other words, if you set frameskip to 1, the animation will play at half speed, and if you hold spacebar to fastforward, the animation will continue playing at normal speed even while everything else goes extremely fast. You'll need to do the changes to ZUN_f and ZUN_f2 in a separate function that's called from MainLoop.
Title: Re: Useful Miscellaneous Code Snippets
Post by: GenericTouhouFailure on September 10, 2010, 11:09:11 PM
That ZUNimate function has one mistake - you're incrementing a variable in DrawLoop, which means the animation will always increment once per drawn frame. In other words, if you set frameskip to 1, the animation will play at half speed, and if you hold spacebar to fastforward, the animation will continue playing at normal speed even while everything else goes extremely fast. You'll need to do the changes to ZUN_f and ZUN_f2 in a separate function that's called from MainLoop.
oh. Didn't know that.
Thanks.
Changing now....
Title: Re: Useful Miscellaneous Code Snippets
Post by: Iryan on September 16, 2010, 12:02:38 AM
HA! Finally!

Here, have some code that creates an effect object that causes bulges in the background similar to what happens behind the bosses from SA onwards.


BulgeBackground(image, nx, ny, dmax, dfac);

Call in @Initialize to create an SA-like bulge at the position of the player in a given image drawn over the playing field.
Processor heavy depending on the parameters.

image = path of the image, duh.
nx, ny = number of rows and columns in the effect object. The higher the numbers, the smoother the background, but also more slowdown. Due to danmakufu's bad array handling, should not exceed 10/15.
dmax = maximum buldge of any given vertex. Should not exceed (width_of_playing_field / nx) or (height_of_playing_field / ny).
dfac = value between 0 and 1. Determines the crassness of the buldge edge. A good value is ~0.98.

Code: [Select]
    task BulgeBackground(image, nx, ny, dmax, dfac){

        let dx=(GetClipMaxX-GetClipMinX)/nx;
        let dy=(GetClipMaxY-GetClipMinY)/ny;

        let du=480/nx;                                 //width of the image goes here
        let dv=640/ny;                                //height of the image goes here

        let vertnum=floor(ny/2)*4*nx + floor(0.5+ny/2)*(2*nx+2) +1 -ny;

        yield;yield;

        let obj = Obj_Create(OBJ_EFFECT);


            ObjEffect_SetRenderState(obj,ALPHA);
            ObjEffect_SetTexture(obj, image);

             ObjEffect_SetPrimitiveType(obj, PRIMITIVE_TRIANGLESTRIP);
             ObjEffect_CreateVertex(obj, vertnum);

        Obj_SetPosition(obj, GetClipMinX, GetClipMinY);

        let xar=[];
        let yar=[];

        let by=0;

        while(by<=(ny)){
            if(by%2==0){
                ascent(i in 0..(2*nx+2)){
                    xar=xar~[floor(i/2)];
                    yar=yar~[by + i%2 ];
                }
            }else{
                ascent(i in 0..(4*nx)){
                    xar=xar~[nx - (i%2 + floor(i/4) ) ];
                    yar=yar~[by + floor(i/2)%2 ];
                }
            }

            by++;
            if(by<(ny)){ xar=erase(xar, length(xar)-1); yar=erase(yar, length(yar)-1); }
        }

        let td=0;
        let ta=0;

        let ophi=rand(0, 360);

        while(Obj_BeDeleted(obj)==false){

            ophi+=7;

                ObjEffect_SetLayer(obj,1);

            ascent(i in 0..vertnum){

                td= ((GetClipMinX + xar[i]*dx - GetPlayerX)^2 + (GetClipMinY + yar[i]*dy - GetPlayerY)^2)^0.5;                    // Change to GetX and GetY to
                ta= atan2(GetClipMinY + yar[i]*dy - GetPlayerY, GetClipMinX + xar[i]*dx - GetPlayerX);                          // center the bulge on the boss and not the player

                ObjEffect_SetVertexXY(obj, i, xar[i]*dx + cos(ta)*dmax*(dfac^td)*(4+sin(ophi+ta*6))/5 , yar[i]*dy + sin(ta)*dmax*(dfac^td)*(4+sin(ophi+ta*6))/5);

                ObjEffect_SetVertexUV(obj, i, xar[i]*du, yar[i]*dv);

                ObjEffect_SetVertexColor(obj, i, 255, 255-255*(dfac^td), 255-255*(dfac^td), 255-255*(dfac^td));

            }
            yield;
        }
    }

I remember Azure telling me that creating a render target, drawing the actual background on the render target and then using the render target as the image for the effect object is possible. If so, then this would enable you to generate the bulge in the actual background, and not just in one image.


For those who are interested, I have attached an image on how the vertices are aligned in the object. 20% of the vertices are redundant, but they are still necessary because of the shape of the object, otherwise interferences occur when the grid is distorted.
Title: Re: Useful Miscellaneous Code Snippets
Post by: Iryan on October 04, 2010, 06:11:35 PM
Inspired by a certain post in the request thread, I made a more generalized version of the one requested:

Function: GetLineBorderPoint(px, py, tx, ty)

What it does: returns [a, b], which are the coordinates of the point of intersection between the playing field's border and a ray from one point in the direction of another point.

Parameters:

px, py: source point
tx, ty: target point

Code: [Select]
function GetLineBorderPoint(px, py, tx, ty){

let ta = atan2(ty-py, tx-px);

if( ta>= atan2(GetClipMinY - py, GetClipMinX - px) && ta<=  atan2(GetClipMinY - py, GetClipMaxX - px)){
return [px - (GetClipMinY-py)*tan(ta+90), GetClipMinY];
}
if( ta>= atan2(GetClipMinY - py, GetClipMaxX - px) && ta<=  atan2(GetClipMaxY - py, GetClipMaxX - px)){
return [GetClipMaxX, py + (GetClipMaxX-px)*tan(ta)];
}
if( ta>= atan2(GetClipMaxY - py, GetClipMaxX - px) && ta<=  atan2(GetClipMaxY - py, GetClipMinX - px)){
return [px - (GetClipMaxY-py)*tan(ta-90), GetClipMaxY];
}
if( ta> atan2(GetClipMaxY - py, GetClipMinX - px) || ta<  atan2(GetClipMinY - py, GetClipMinX - px)){
return [GetClipMinX, py + (GetClipMinX-px)*tan(ta+180)];
}
}
Title: Re: Useful Miscellaneous Code Snippets
Post by: Chronojet ⚙ Dragon on October 05, 2010, 05:31:04 AM
Function: GetLineBorderPoint(px, py, tx, ty)

Perfect for MASTER SPAAAAAAAAAAAAA(ry lasers that spawn bullets from the sides of the screen. :V
Title: Re: Useful Miscellaneous Code Snippets
Post by: Chronojet ⚙ Dragon on November 03, 2010, 10:48:52 PM
Secant, Cosecant, and Cotangent functions. :\

Code: [Select]
function sec(n) { return 1/cos(n); }
function csc(n) { return 1/sin(n); }
function cot(n) { return 1/tan(n); }
Title: Re: Useful Miscellaneous Code Snippets
Post by: GenericTouhouFailure on November 26, 2010, 01:24:47 PM
GetPointInDirection(300,300,10,60);
would return the point 10 pixels away from 300 300 at a 60 degree angle (for spawning bullets or items in circles away from centerpoint of boss.
Code: [Select]
function GetPointInDirection(x,y,r,a){
let rx = x+r*cos(a);
let ry = y+r*sin(a);
return [rx,ry];
}
function GetPointInDirectionFromBoss(r,a){
return GetPointInDirection(GetX,GetY,r,a);
}
function GetPointInDirectionFromPlayer(r,a){
return GetPointInDirection(GetPlayerX,GetPlayerY,r,a);
}
quite useless for someone who has already memorized cos/sin whatever but i'll just post this here.
Title: Re: Useful Miscellaneous Code Snippets
Post by: Drake on November 26, 2010, 02:30:19 PM
oh god so many letters that would be so confusing
and then you'd have brackets everywhere holy god
Title: Re: Useful Miscellaneous Code Snippets
Post by: ChiyuriKitashirakawa on November 29, 2010, 08:53:39 PM
Homing angles for the lazy!
GetRelativeAngleToPlayer gets the angle between the point of coords (objX,objY) to the player. Think of it like a GetAngleToPlayer that works on any point of the field instead of (GetX,GetY).
GetRelativeAngleToTarget does the same, but instead of using the player as a target, it uses the point (tarX,tarY).
Code: [Select]
function GetRelativeAngleToPlayer(objX,objY){
return GetRelativeAngleToTarget(objX,objY,GetPlayerX,GetPlayerY)
}
function GetRelativeAngleToTarget(objX,objY,tarX,tarY){
if (objX > tarX){ return 180 - atan2((|objY-tarY|),(| objX-tarX |));}
return atan2((|objY-tarY|),(| objX-tarX |));
}
Title: Re: Useful Miscellaneous Code Snippets
Post by: Drake on November 30, 2010, 12:06:31 AM
Simple revision for less typing and naming standards and cleanliness etc.

Code: [Select]
function Obj_GetAngleToPlayer(obj){
    return Obj_GetAngleToPoint(obj,GetPlayerX,GetPlayerY)
}

function Obj_GetAngleToPoint(obj,tarX,tarY){
    if (Obj_GetX(obj) > tarX){
        return 180 - atan2((|Obj_GetY(obj)-tarY|),(| Obj_GetX(obj)-tarX |));
    }
    return atan2((|Obj_GetY(obj)-tarY|),(| Obj_GetX(obj)-tarX |));
}
Title: Re: Useful Miscellaneous Code Snippets
Post by: Arcorann on December 02, 2010, 10:02:44 AM
I was looking at the GetPointToLine function and wondering "Why do we need this trig?"...

So, here's my version:
Code: [Select]
   function GetPointToLine(ox, oy, p1x, p1y, p2x, p2y){

      let dist= ( (oy-p1y)*(p2x-p1x)-(ox-p1x)*(p2y-p1y) )/(( (p2x-p1x)^2 + (p2y-p1y)^2 )^0.5) ;

      return dist;
   }

This should give the same result, including sign, as the original by Iryan.
Title: Re: Useful Miscellaneous Code Snippets
Post by: Azure Lazuline on December 09, 2010, 03:07:10 AM
WrapText
Splits one string into multiple, only breaking at spaces. "Text" is the text input (obviously), "spaces" is the maximum number of characters on one line. Returns an array of strings, one entry per line. The ^ character can force a line-break.

Code: [Select]
function WrapText(text, spaces){
text=text~" ";
let strings=[];
let numstrings=0;
let k=0;
let lastletter=1;
while(length(text)>0&&lastletter>0){
lastletter=0;
k=0;
while(k<spaces&&k<length(text)){
if(text[k]==' '){lastletter=k;}
if(text[k]=='^'){
text[k]=' '; //add a newline
k=spaces;
}
k++;
}
strings=strings~[text[0..lower(lastletter,length(text))]];
text=text[lower(lastletter+1,length(text))..length(text)];
numstrings++;
}

return strings;
}
Title: Re: Useful Miscellaneous Code Snippets
Post by: Drake on January 24, 2011, 02:52:55 AM
Naut I hate you :(

GetAscii

Should be self-explanatory. Input character and either "NUMBER" or "LOWER" for speed purposes, receive ascii value.

Code: [Select]
function GetAscii(char,type){
alternative(type)
case("NUMBER"){
alternative(char)
case('0'){return 48;} case('1'){return 49;} case('2'){return 50;} case('3'){return 51;}
case('4'){return 52;} case('5'){return 53;} case('6'){return 54;} case('7'){return 55;}
case('8'){return 56;} case('9'){return 57;}
}
case("LOWER"){
alternative(char)
case('a'){return 97;} case('b'){return 98;} case('c'){return 99;} case('d'){return 100;}
case('e'){return 101;} case('f'){return 102;} case('g'){return 103;} case('h'){return 104;}
case('i'){return 105;} case('j'){return 106;} case('k'){return 107;} case('l'){return 108;}
case('m'){return 109;} case('n'){return 110;} case('o'){return 111;} case('p'){return 112;}
case('q'){return 113;} case('r'){return 114;} case('s'){return 115;} case('t'){return 116;}
case('u'){return 117;} case('v'){return 118;} case('w'){return 119;} case('x'){return 120;}
case('y'){return 121;} case('z'){return 122;}
}
}

If someone wants to expand it, cool. I personally don't.
Title: Re: Useful Miscellaneous Code Snippets
Post by: Blargel on January 25, 2011, 01:30:50 AM
Uh, Drake?

Code: [Select]
GetAscii(character){
    return character+0;
}

Seriously. If you want to go from ascii to character, that's another story. You'll need to do that alternative nonsense unless there's a better way I'm not thinking of right now.

Btw, to people who don't know, the parameter would be 'a' if you wanted the ascii for a and not "a". Single quotes not double.
Title: Re: Useful Miscellaneous Code Snippets
Post by: Drake on January 25, 2011, 01:39:56 AM
but but but dnh crashed the last time i did that

why does it work now

:C
Title: Re: Useful Miscellaneous Code Snippets
Post by: Blargel on March 26, 2011, 09:10:17 AM
Stealing code from other people and then converting it to Danmakufu. Wooo

Collision_Box_Box

Determines if two rectangles are intersecting with each other. Returns true if they are and false if they are not.

cx1, cy1 is the center coordinates of rectangle 1.
w1, h1 is the width and height of rectangle 1.
r1 is the rotation of rectangle 1.

The other 5 parameters are the same except for rectangle 2.

Code: [Select]
function Collision_Box_Box(cx1, cy1, w1, h1, r1, cx2, cy2, w2, h2, r2){
    let rectA = CalculateCorners(cx1, cy1, w1, h1, r1);
    let rectB = CalculateCorners(cx2, cy2, w2, h2, r2);

    let axisList = [
        rectA[1] - rectA[0],
        rectA[1] - rectA[2],
        rectB[0] - rectB[3],
        rectB[0] - rectB[1]
    ];
   
    ascent(i in 0..4){
        if(!IsAxisCollision(axisList[i])){
            return false;
        }
    }
   
    return true;
   
   
    function CalculateCorners(cx, cy, width, height, rotation){
        if(rotation == 0){
            return [
                [cx-width/2, cy-height/2],
                [cx+width/2, cy-height/2],
                [cx+width/2, cy+height/2],
                [cx-width/2, cy+height/2]
            ];
        }
        else {
            let angles = [
                atan2(height/-2, width/-2)+rotation,
                atan2(height/2, width/-2)+rotation,
                atan2(height/2, width/2)+rotation,
                atan2(height/-2, width/2)+rotation
            ];
            let distance = (height^2 + width^2)^0.5/2;
            return [
                [cx+cos(angles[0])*distance, cy+sin(angles[0])*distance],
                [cx+cos(angles[1])*distance, cy+sin(angles[1])*distance],
                [cx+cos(angles[2])*distance, cy+sin(angles[2])*distance],
                [cx+cos(angles[3])*distance, cy+sin(angles[3])*distance]
            ];
        }
    }
   
   
    function IsAxisCollision(axis){
        let rectAScalars = [
            GenerateScalar(rectA[0], axis),
            GenerateScalar(rectA[1], axis),
            GenerateScalar(rectA[2], axis),
            GenerateScalar(rectA[3], axis)
        ];
        let rectBScalars = [
            GenerateScalar(rectB[0], axis),
            GenerateScalar(rectB[1], axis),
            GenerateScalar(rectB[2], axis),
            GenerateScalar(rectB[3], axis)
        ];
       
        let rectAMin = ArrayMin(rectAScalars);
        let rectAMax = ArrayMax(rectAScalars);
        let rectBMin = ArrayMin(rectBScalars);
        let rectBMax = ArrayMax(rectBScalars);

        if(rectBMax <= rectAMax && rectBMax >= rectAMin)
        {
            return true;
        }
        else if (rectAMax <= rectBMax && rectAMax >= rectBMin)
        {
            return true;
        }

        return false;
    }
   
   
    function GenerateScalar(corner, axis){
        let num = (corner[0] * axis[0]) + (corner[1] * axis[1]);
        let denom = (axis[0] * axis[0]) + (axis[1] * axis[1]);
        let divisionResult = num / denom;
       
        let cornerProjected = [divisionResult * axis[0], divisionResult * axis[1]];
       
        let scalar = (axis[0] * cornerProjected[0]) + (axis[1] * cornerProjected[1]);
        return scalar;
    }
}

function ArrayMin(array){
    let min = array[0];
    ascent(i in 1..length(array)){
        if(array[i] < min){ min = array[i]; }
    }
    return min;
}

function ArrayMax(array){
    let max = array[0];
    ascent(i in 1..length(array)){
        if(array[i] > max){ max = array[i]; }
    }
    return max;
}

I nested CalculateCorners, IsAxisCollision, and GenerateScalar because nothing should really be using those besides the collision function itself. ArrayMin and ArrayMax are also used by the collision function but those are probably useful elsewhere too so I left them unnested.
Title: Re: Useful Miscellaneous Code Snippets
Post by: CK Crash on May 21, 2011, 03:39:52 AM
Bumping because Naut said so.

Wavy background effect

Code: [Select]
task WavyBG(imgBG,HScroll,VScroll)
{
let obj = Obj_Create(OBJ_EFFECT);
let s = 0;

Obj_SetPosition(obj,0,0);
ObjEffect_SetTexture(obj,imgBG);
ObjEffect_SetPrimitiveType(obj,PRIMITIVE_TRIANGLESTRIP);
ObjEffect_SetLayer(obj,0);
ObjEffect_CreateVertex(obj,32);

while(!Obj_BeDeleted(obj))
{
ascent(i in 0..16)
{
ObjEffect_SetVertexUV(obj,i*2,HScroll,i*32+s*VScroll);
ObjEffect_SetVertexUV(obj,i*2+1,512+HScroll,i*32+s*VScroll);
ObjEffect_SetVertexXY(obj,i*2,GetClipMinX+sin(s+i*16)*64-64,sin(s+i*5)*64 + i*40-64);
ObjEffect_SetVertexXY(obj,i*2+1,GetClipMaxX+sin(s+i*16)*64+64,sin(s+i*5)*64 + i*40-64);
}
s++;
yield;
}
}

Load the image first, then call this function in @Initialize.
Title: Re: Useful Miscellaneous Code Snippets
Post by: Darkness1 on May 29, 2011, 04:30:07 PM
Function for objects: TurnToPoint.

Four Parameters, which are id, speed, PointX and PointY.

Makes an object bullet/laser turn till it points at a certain point at the playing field. Doesn't loop by itself. Speed is the speed it turns at. Inputting a negative value for speed gives you awkward results. Id is (obviously) the id of the object.


EDIT: Improved version by Blargel.
Code: [Select]
function TurnToPoint(id, speed, PointX, PointY){
    let current_angle = Obj_GetAngle(id);
    let target_angle = atan2(PointY-Obj_GetY(id), PointX-Obj_GetX(id));
    let adist = AngularDistance(current_angle, target_angle);

    if(absolute(adist) < speed){
        Obj_SetAngle(id, target_angle);
    }
    else {
        if(adist > 0){
            Obj_SetAngle(id, Obj_GetAngle(id)+speed);
        }
        else if(adist < 0){
            Obj_SetAngle(id, Obj_GetAngle(id)-speed);
        }
    }
}


Title: Re: Useful Miscellaneous Code Snippets
Post by: Something XutaWoo-y on May 30, 2011, 02:22:43 AM
atan2 gets -180 to 180. Bullets are usually given 0 to 360.

Also, depending on the situation the bullets could be +360. Meaning that they would have to spin even more. Although these problems probably shouldn't be fixed by that function. Maybe another function that goes with it.
Title: Re: Useful Miscellaneous Code Snippets
Post by: Arcorann on May 30, 2011, 06:50:42 AM
Blargel did a few angle functions on the first page. (http://www.shrinemaiden.org/forum/index.php/topic,5164.msg263249#msg263249) Using them:

Code: [Select]
function TurnToPoint(id, speed, PointX, PointY){ //Use a positive value for speed!
    adist = AngularDistance(Obj_GetAngle(id),atan2(PointY-Obj_GetY(id),PointX-Obj_GetX(id)))
    if(adist<0){
        Obj_SetAngle(id, Obj_GetAngle(id)-speed);}
    if(adist>0){
        Obj_SetAngle(id, Obj_GetAngle(id)+speed);}
    }
Title: Re: Useful Miscellaneous Code Snippets
Post by: Darkness1 on May 30, 2011, 01:44:26 PM
Blargel did a few angle functions on the first page. (http://www.shrinemaiden.org/forum/index.php/topic,5164.msg263249#msg263249) Using them:

Code: [Select]
function TurnToPoint(id, speed, PointX, PointY){ //Use a positive value for speed!
    adist = AngularDistance(Obj_GetAngle(id),atan2(PointY-Obj_GetY(id),PointX-Obj_GetX(id)))
    if(adist<0){
        Obj_SetAngle(id, Obj_GetAngle(id)-speed);}
    if(adist>0){
        Obj_SetAngle(id, Obj_GetAngle(id)+speed);}
    }

It works as wanted, but when i try it my lasers start to vibrate :( (Yeah, i got no clue why).
Title: Re: Useful Miscellaneous Code Snippets
Post by: Arcorann on May 31, 2011, 12:11:42 AM
Yes, I think I see the problem. When the angular distance is less than the speed it still turns with the full value. Try this:
Code: [Select]
function TurnToPoint(id, speed, PointX, PointY){ //Use a positive value for speed!
    adist = AngularDistance(Obj_GetAngle(id),atan2(PointY-Obj_GetY(id),PointX-Obj_GetX(id)))
    if(absolute(adist)<=speed){
        Obj_SetAngle(id, Obj_GetAngle(id)-adist);}
    if(adist<-speed){
        Obj_SetAngle(id, Obj_GetAngle(id)-speed);}
    if(adist>speed){
        Obj_SetAngle(id, Obj_GetAngle(id)+speed);}
    }
Title: Re: Useful Miscellaneous Code Snippets
Post by: Darkness1 on May 31, 2011, 11:46:42 AM
Still nothing. But i experimented with the two ways you did it and the best i could get was this:
Code: [Select]
function TurnToPoint(id, speed, PointX, PointY){
let adist = AngularDistance(Obj_GetAngle(id),atan2(PointY-Obj_GetY(id),PointX-Obj_GetX(id)));

    if(absolute(adist)<=speed && adist<0){
        Obj_SetAngle(id, Obj_GetAngle(id)-adist);}

    if(absolute(adist)<=speed && adist>0){
        Obj_SetAngle(id, Obj_GetAngle(id)+adist);}

    if(adist<0 && adist<speed){
        Obj_SetAngle(id, Obj_GetAngle(id)-speed);}

    if(adist>0 && adist>speed){
        Obj_SetAngle(id, Obj_GetAngle(id)+speed);}

    }

No more vibration, but it looks weird when the turning goes negative (counter-clock).
Title: Re: Useful Miscellaneous Code Snippets
Post by: Blargel on May 31, 2011, 08:34:16 PM
Code: [Select]
function TurnToPoint(id, speed, PointX, PointY){
    let current_angle = Obj_GetAngle(id);
    let target_angle = atan2(PointY-Obj_GetY(id), PointX-Obj_GetY(id));
    let adist = AngularDistance(current_angle, target_angle);

    if(absolute(adist) < speed){
        Obj_SetAngle(id, target_angle);
    }
    else {
        if(adist > 0){
            Obj_SetAngle(id, Obj_GetAngle(id)+speed);
        }
        else if(adist < 0){
            Obj_SetAngle(id, Obj_GetAngle(id)-speed);
        }
    }
}

Pretty sure this is correct. If it still looks weird, you might have something else interfering with the rotation.
Title: Re: Useful Miscellaneous Code Snippets
Post by: Darkness1 on June 01, 2011, 05:38:41 AM
Code: [Select]
function TurnToPoint(id, speed, PointX, PointY){
    let current_angle = Obj_GetAngle(id);
    let target_angle = atan2(PointY-Obj_GetY(id), PointX-Obj_GetY(id));
    let adist = AngularDistance(current_angle, target_angle);

    if(absolute(adist) < speed){
        Obj_SetAngle(id, target_angle);
    }
    else {
        if(adist > 0){
            Obj_SetAngle(id, Obj_GetAngle(id)+speed);
        }
        else if(adist < 0){
            Obj_SetAngle(id, Obj_GetAngle(id)-speed);
        }
    }
}

Pretty sure this is correct. If it still looks weird, you might have something else interfering with the rotation.

First when i tested this, i thought i didn't work as well, but it was just a little typing mistake. It now works, thanks!
Title: Re: Useful Miscellaneous Code Snippets
Post by: Darkness1 on June 15, 2011, 11:47:51 AM
Sorry for the double post, but:

A new version of the last function, TurnToAngle(id, speed, angle).

Three Parameters, which are id, speed and angle.

Makes an object bullet/laser turn till it's angle is equal to the number input as the parameter angle. Doesn't loop by itself. Speed is the speed it turns at. Inputting a negative value for speed gives you awkward results. Id is the id of the object.

Code: [Select]

function TurnToAngle(id, speed, angle){
    let current_angle = Obj_GetAngle(id);
    let target_angle = angle;
    let adist = AngularDistance(current_angle, target_angle);

    if(absolute(adist) < speed){
        Obj_SetAngle(id, target_angle);
    }
    else {
        if(adist > 0){
            Obj_SetAngle(id, Obj_GetAngle(id)+speed);
        }
        else if(adist < 0){
            Obj_SetAngle(id, Obj_GetAngle(id)-speed);
        }
    }
}
Title: Re: Useful Miscellaneous Code Snippets
Post by: Blargel on July 09, 2011, 01:38:58 AM
GetPointInRectangle(ox, oy, pcx, pcy, recl, recw, align);

This function checks wether or not a given point lies within a given rectangle. Returns true if it is and false if it isn't.

Parameters:

ox, oy: Coordinates of the seperate point.
pcx, pcy: Coordinates of the center of the rectangle.
recl, recw: Length and width of the rectangle.
align: the alignment of the rectangle, i.e. the angle the longer side points at.

Code: [Select]
function GetPointInRectangle(ox, oy, pcx, pcy, recl, recw, align){

let dist1;
let dist2;
let isit=false;

dist1=(| GetPointToLine(ox, oy, pcx, pcy, pcx+cos(align), pcy+sin(align)) |);
dist2=(| GetPointToLine(ox, oy, pcx, pcy, pcx+cos(align+90), pcy+sin(align+90)) |);

if( (dist1<0.5*recw)&&(dist2<0.5*recl) ){ isit=true; }

return(isit);
}

Making a (possibly) more optimized version of this for someone on IRC. Same parameters. I may have swapped the length and width parameters because Iryan has weird ass naming sense :V

Code: [Select]
function GetPointInRectangle(ox, oy, pcx, pcy, recl, recw, align){
    //Applying transformations to point instead of rectangle
    let distance = ((ox-pcx)^2+(oy-pcy)^2)^0.5;
    let angle = atan2(oy-pcy, ox-pcy)-align;
    let new_ox = cos(angle)*distance;
    let new_oy = sin(angle)*distance;

    //Checking if transformed point is within rectangle that is now axis-aligned and centered on origin
    return (absolute(new_ox) <= recl/2 && absolute(new_oy) <= recw/2);
}
Title: Re: Useful Miscellaneous Code Snippets
Post by: Chronojet ⚙ Dragon on August 16, 2011, 04:32:27 AM
I'm going to update Blargel's ShootShape function (http://www.shrinemaiden.org/forum/index.php/topic,5164.msg273821.html#msg273821). Like Blargel, I don't know if this belongs here or not.



Code: [Select]
function ShootShape(spawnX, spawnY, v, angle, num, bside, graphic, delay) {
ascent(i in 0..num) {
let sx = spawnX+cos(angle+i*360/num); let sy = spawnY+sin(angle+i*360/num); let sxN = spawnX+cos(angle+(i+1)*360/num); let syN = spawnY+sin(angle+(i+1)*360/num);
CreateShot01(spawnX, spawnY, v*(((sx-spawnX)^2+(sy-spawnY)^2)^0.5), atan2(sy-spawnY,sx-spawnX), graphic, delay);
ascent(j in 0..bside) {
let toAngle = atan2(syN-sy,sxN-sx); let toDist = (((sxN-sx)^2+(syN-sy)^2)^0.5); let sx2 = sx+toDist/bside*j*cos(toAngle); let sy2 = sy+toDist/bside*j*sin(toAngle);
CreateShot01(spawnX, spawnY, v*(((sx2-spawnX)^2+(sy2-spawnY)^2)^0.5), atan2(sy2-spawnY,sx2-spawnX), graphic, delay);
}
}
}

ShootShape
Shoots an outward shape function.

Parameter list:
spawnX, spawnY: spawning coordinates of the shape
v: velocity of corner bullets
angle: angle one of the corner bullets is aimed at
num: number of corners in the shape
bside: number of bullets in a side of the shape
graphic: bullet graphic used by the shape's bullets
delay: frames of delay given to each bullet

Example:
ShootShape(GetX, GetY, 3, GetAngleToPlayer, 3, 15, RED01, 10);
   This looks like the boss shoots a 3-sided shape (a triangle) with 15 bullets on each side, at the player.
Title: Re: Useful Miscellaneous Code Snippets
Post by: Rosen on September 03, 2011, 07:29:07 AM
LSegmentIntersectPoint returns the point of intersection, if the 2 given segments intersect. If they don't intersect, it returns an array [-1,-1].
Can be used in any script version.

Segment 1: (x1,y1), (x2,y2).
Segment 2: (x3,y3), (x4,y4).

Code: [Select]
function LSegmentIntersectPoint(let x1, let y1, let x2, let y2, let x3, let y3, let x4, let y4) {

let d = (x2 - x1)*(y3 - y4) - (x3 - x4)*(y2 - y1);

if (d == 0) { return [-1,-1]; }

let d1 = (x3 - x1)*(y3 - y4) - (x3 - x4)*(y3 - y1);
let d2 = (x2 - x1)*(y3 - y1) - (x3 - x1)*(y2 - y1);

let t1 = d1 / d;
let t2 = d2 / d;
let point = [0,0];
if (t1 >= 0 && t1 <= 1 && t2 >= 0 && t2 <= 1) {
point[0] = t1*x2 + (1-t1)*x1;
point[1] = t1*y2 + (1-t1)*y1;
return point;

} else {
return [-1,-1];
}

}
Title: Re: Useful Miscellaneous Code Snippets
Post by: Chronojet ⚙ Dragon on December 07, 2011, 01:54:18 AM
CreateLaser01Copy

Just use like CreateLaser01. Modify as needed.

Code: [Select]
task CreateLaser01Copy(lX, lY, lSpeed, lAngle, lLength, lWidth, lGraphic, lDelay) {
let objT = Obj_Create(OBJ_SHOT);
Obj_SetPosition(objT, lX, lY);
ObjShot_SetGraphic(objT, lGraphic);
ObjShot_SetDelay(objT, lDelay);
Obj_SetAlpha(objT, 0);
loop(lDelay) { yield; }
let doCreate = Obj_BeDeleted(objT); Obj_Delete(objT); if(!doCreate) {
let obj = Obj_Create(OBJ_LASER);
Obj_SetPosition(obj, lX, lY);
Obj_SetAngle(obj, lAngle);
ObjShot_SetGraphic(obj, lGraphic);
ObjLaser_SetWidth(obj, lWidth);
ObjLaser_SetSource(obj, false);
ObjShot_SetBombResist(obj, false);
ObjLaser_SetLength(obj, 0);
while(!Obj_BeDeleted(obj)) {
if(ObjLaser_GetLength(obj)<lLength){
ObjLaser_SetLength(obj, ObjLaser_GetLength(obj)+lSpeed);
} else {
Obj_SetPosition(obj, Obj_GetX(obj)+lSpeed*cos(lAngle), Obj_GetY(obj)+lSpeed*sin(lAngle));
}
if(ObjLaser_GetLength(obj)>lLength){ ObjLaser_SetLength(obj, lLength); }
yield;
}
}
}
Title: Re: Useful Miscellaneous Code Snippets
Post by: MMX on December 07, 2011, 02:39:31 PM
CreateSprite

Very usefull function that creates simple square sprite with given size and texture. It returns an effect object id wich may be processed to change it's properties as usual.

Code: [Select]
function CreateSprite(texture, width, height){
let obj=Obj_Create(OBJ_EFFECT);

ObjEffect_SetTexture(obj,texture);
ObjEffect_SetRenderState(obj,ALPHA); // by default. May be changed later

ObjEffect_SetPrimitiveType(obj,PRIMITIVE_TRIANGLESTRIP);
ObjEffect_CreateVertex(obj, 4);

ObjEffect_SetVertexXY(obj,0,-width/2,-height/2);
ObjEffect_SetVertexXY(obj,1,width/2,-height/2);
ObjEffect_SetVertexXY(obj,2,-width/2,height/2);
ObjEffect_SetVertexXY(obj,3,width/2,height/2);

ObjEffect_SetVertexUV(obj,0,0,0);
ObjEffect_SetVertexUV(obj,1,width,0);
ObjEffect_SetVertexUV(obj,2,0,height);
ObjEffect_SetVertexUV(obj,3,width,height);

return obj;
}
Title: Re: Useful Miscellaneous Code Snippets
Post by: MMX on December 08, 2011, 02:59:09 AM
Oops. I've read the topic's rules so this post doesnt fit here (also doublepost). Moderator, please delete this.
Title: Re: Useful Miscellaneous Code Snippets
Post by: ShedPH93 on February 10, 2012, 04:35:47 PM
ReflectionAngle
Returns the angle of reflection, given the angle of incidence and the angle of the "mirror".
Code: [Select]
function ReflectionAngle (angle, mirror)  {
   return 2*mirror-angle; }
Title: Re: Useful Miscellaneous Code Snippets
Post by: MMX on February 18, 2012, 02:03:27 PM
LinesIntersect
Code: [Select]
function LinesIntersect(x1,y1,x2,y2,x3,y3,x4,y4){
let intpoint=[0,0];
let ua=((x4-x3)*(y1-y3)-(y4-y3)*(x1-x3))/((y4-y3)*(x2-x1)-(x4-x3)*(y2-y1));
let ub=((x2-x1)*(y1-y3)-(y2-y1)*(x1-x3))/((y4-y3)*(x2-x1)-(x4-x3)*(y2-y1));
if(ua>0 && ua<1 && ub>0 && ub<1){
intpoint[0]=x1+ua*(x2-x1);
intpoint[1]=y1+ua*(y2-y1);
}else{
intpoint[0]=9999;
intpoint[1]=9999;
}
return intpoint;
}

Checks if two line segments defined by their endpoints intersect, and if they do returns coordinates of intersection point. First i made it to return false when there's no intersection, but returning the same array with some nonsense values is easier to process later.

(http://paulbourke.net/geometry/lineline2d/lineline1.gif)

Algorithm taken from this site http://paulbourke.net/geometry/lineline2d/
Title: Re: Useful Miscellaneous Code Snippets
Post by: fondue on October 28, 2012, 12:26:35 PM
uh-oh necrobump

waitUntil
Code: [Select]
function waitUntil(condition){ while(!condition) { yield; } }
Halts the current task/function/sub until the requirements (k) are met.haven't tested it myself though yet orz

e: Thanks to kyuu for making it shorter~
Title: Re: Useful Miscellaneous Code Snippets
Post by: CK Crash on October 30, 2012, 08:39:19 AM
uh-oh necrobump

waitUntil
Code: [Select]
function waitUntil(condition){ while(!condition) { yield; } }
Halts the current task/function/sub until the requirements (k) are met.haven't tested it myself though yet orz

e: Thanks to kyuu for making it shorter~
Pretty sure this won't work. The expression will be evaluated immediately as true or false, which will make the function yield infinitely or not at all. Condition is its own variable, it just starts with a different value depending on what arguments you give the function.
Code: [Select]
function Add(var2) {var2 += 4;}

let var1 = 4;
Add(var1);
//var1 still equals 4 after running the function, var2 copies the value of var1 without changing it

Not that you can't use a function to conditionally wait:
Code: [Select]
let waitSwitch = false;
function WaitForSwitch(){
     while(!waitSwitch){yield;}
}

@MainLoop{
     if(condition){waitSwitch = true;}
     else{waitSwitch = false;}
     yield;
}
Title: Re: Useful Miscellaneous Code Snippets
Post by: Sparen on April 15, 2013, 11:40:17 PM
Simple revision for less typing and naming standards and cleanliness etc.

Code: [Select]
function Obj_GetAngleToPlayer(obj){
    return Obj_GetAngleToPoint(obj,GetPlayerX,GetPlayerY)
}

function Obj_GetAngleToPoint(obj,tarX,tarY){
    if (Obj_GetX(obj) > tarX){
        return 180 - atan2((|Obj_GetY(obj)-tarY|),(| Obj_GetX(obj)-tarX |));
    }
    return atan2((|Obj_GetY(obj)-tarY|),(| Obj_GetX(obj)-tarX |));
}

Code: [Select]
function Obj_GetAngleToPoint(obj,tarX,tarY){
  if(Obj_GetX(obj) > tarX && Obj_GetY(obj) < tarY){
    return 180 - atan2((|Obj_GetY(obj)-tarY|),(| Obj_GetX(obj)-tarX |));
  }
  if(Obj_GetX(obj) > tarX && Obj_GetY(obj) >= tarY){
    return 180 - atan2((tarY-Obj_GetY(obj)),(| Obj_GetX(obj)-tarX |));
  }
  if(Obj_GetX(obj) < tarX && Obj_GetY(obj) >= tarY){
    return atan2((tarY-Obj_GetY(obj)),(| Obj_GetX(obj)-tarX |));
  }
  return atan2((|Obj_GetY(obj)-tarY|),(| Obj_GetX(obj)-tarX |));
}

I felt the need to supply this version because the version that Drake posted does not work if you are located above the bullet (as far as my scripts went).

@Mods: I know this thread is dead. But I don't want someone else to wonder why their code doesn't work. Sorry if it's not supposed to be here.
@Drake: If my code's wrong, then PM me or something and I'll fix it. I've tested it though (in all four quadrants), so it should work fine.
Title: Re: Useful Miscellaneous Code Snippets
Post by: Drake on April 16, 2013, 03:26:01 AM
I'm actually not even sure why I bothered OKing that function, never mind trying to clean it up.
Obj_GetAngleToPoint() and Obj_GetAngleToPlayer()
Code: [Select]
function Obj_GetAngleToPlayer(obj){
return Obj_GetAngleToPoint(obj, GetPlayerX, GetPlayerY);
}

function Obj_GetAngleToPoint(obj, tX, tY){
return (atan2(tY - Obj_GetY(obj), tX - Obj_GetX(obj)) + 360) % 360;
}
is enough.



Also, if anyone finds the debug window awkward to use:
DebugText() and SetDebugText()
Display arbitrary values at the bottom of the screen.
The line numbers are essentially self-sorting and it doesn't display empty lines so writing on lines like 4, 0, 1, 80 is fine even though you should never actually do that.
Only limit to the number of lines is the maximum array size, but you'll hit the top of the screen before that, obviously.

Run DebugText() in the @DrawLoop and call SetDebugText() to write some value on some line.
Code: [Select]
function DebugText(){
SetFontColor(255, 255, 255, 255, 255, 255);
let temp = GetCommonDataDefault("DEBUG_TEXT", []);
let j = 0;
descent(i in 0..length(temp)){
if(temp[i] != ""){
DrawText(temp[i], 36, 450 - j*14, 12, 255);
j++;
}
}
}

function SetDebugText(line, string){
let temp = GetCommonDataDefault("DEBUG_TEXT", []);
if(line >= length(temp)){
while(line > length(temp)){
temp = temp ~ [""];
}
SetCommonData("DEBUG_TEXT", temp ~ [ToString(string)]);
}else{
temp[line] = ToString(string);
SetCommonData("DEBUG_TEXT", temp);
}
}

For example,
SetDebugText(0, "Angle:" ~ ToString(Obj_GetAngleToPlayer(obj)));
SetDebugText(1, [GetPlayerX, GetPlayerY]);
SetDebugText(2, [Obj_GetX(obj), Obj_GetY(obj)]);

outputs:
(http://i.imgur.com/7iIqGW1.png)
Title: Re: Useful Miscellaneous Code Snippets
Post by: Fujiwara no Mokou on October 08, 2017, 08:27:39 AM
Just throwing this out here:
There's a lot of SetAngleX/SetAngleY/SetAngleZ functions in ph3, but that's a bit.... restrictive.
How about the ability to rotate about any arbitrary axis instead?

Unfortunately, no such function exists natively, but luckily we can convert arbitrary axis-angle rotation to Euler angles, then feed that output to the SetAngle functions to achieve the same desired effect.
Here's the math for it (note that <x,y,z> is the axis vector with <0,0,0> as the source):
Code: [Select]
function toEuler(let x, let y, let z, let angle)
{
let s=sin(angle);
let c=cos(angle);
let t=1-c;
        let yaw;
        let pitch;
        let roll;

//  normalize the axis
let magnitude = power(x*x + y*y + z*z, 0.5);
if (magnitude==0)
        {
            // error
            return 0;
        }
x /= magnitude;
y /= magnitude;
z /= magnitude;

if ((x*y*t + z*s) > 0.998)
        {
                // north pole singularity detected
yaw = 2*atan2(x*sin(angle/2), cos(angle/2));
roll = 90;
pitch = 0;
}
else if ((x*y*t + z*s) < -0.998)
        {
                // south pole singularity detected
yaw = -2*atan2(x*sin(angle/2), cos(angle/2));
roll = -90;
pitch = 0;
}
        else
        {
    yaw = atan2(y * s- x * z * t , 1 - (y*y+ z*z ) * t);
    roll = asin(x * y * t + z * s) ;
    pitch = atan2(x * s - y * z * t , 1 - (x*x + z*z) * t);
        }
        return [ yaw, pitch, roll ];
}