Centralising entity animation detection to screen

danno

Moderator
Staff member
Basically this boss death at 1 min 15 seconds

https://www.youtube.com/watch?v=FgwKd1wCss0

entity starts animation from anywhere, loops until center of screen is detected then final stage of animation or alternative animation or video is played.

I've found out how to spawn entities into the center of screen but nothing on animation detection in relation to screen, any ideas guys?


 
Oh that one! walking to certain coords than perform other animation there.

I usually have enemy or boss leap to certain coords instead to get more precise result and efficient animation. Efficient = The leap and the other animation in single animation.
Walking is different than leaping. Leaping usually has no velocity limit so enemy or boss could leap with high velocity when they are far from destinated coords to reach it.
However not with walking as walking usually has defined speed/velocity. Because of that, it's hard to set finite frames for enemy/boss and hard to figure out when exactly they will reach the coords. If they are far, they could play more frames than if they were close.

Hmmm... I forgot if I've ever coded walk to coords before but I know the logic so it shouldn't be hard to recode it :).
 
Danno, you can get the middle of the screen using this logic:

Code:
void self = getlocalvar("self"); //Get calling entity.
int Screen = openborvariant("hResolution")/2; // Get screen width divided by 2
int XPos = openborvariant("xpos"); // Get camera x position
int Width = (openborvariant("PLAYER_MIN_Z")+(openborvariant("PLAYER_MAX_Z") - openborvariant("PLAYER_MIN_Z"))/2)+1; // Get playable area size center

That +1 at the end is to prevent division by 0 (for 2d stages)
Then you move your character to the point you want.

Here are two functions I use to center things on screen:
Code:
void bmtcenter()
{		// centers the entity on the screen		
		// Douglas Baldan - 06/10/2014
    void self = getlocalvar("self"); //Get calling entity.
	int Screen = openborvariant("hResolution")/2; // Get screen width divided by 2
    int XPos = openborvariant("xpos"); // Get camera x position
    int Width = openborvariant("PLAYER_MIN_Z")+(openborvariant("PLAYER_MAX_Z") - openborvariant("PLAYER_MIN_Z"))/2; // Get playable area size center
    changeentityproperty(self, "position", Screen+XPos-20, Width+1, 0);

}
Code:
void bmtcenter2()
{		// centers the entity on the screen	without Y position	
		// Douglas Baldan - 2018/09/03
    void self = getlocalvar("self"); //Get calling entity.
	int Screen = openborvariant("hResolution")/2; // Get screen width divided by 2
    int XPos = openborvariant("xpos"); // Get camera x position
    int Width = openborvariant("PLAYER_MIN_Z")+(openborvariant("PLAYER_MAX_Z") - openborvariant("PLAYER_MIN_Z"))/2; // Get playable area size center
    changeentityproperty(self, "position", Screen+XPos-20, Width+1, NULL());

}

Just get your character position:
Code:
getentityproperty(self, "x"); //Get X location
getentityproperty(self, "z"); //Get Z location

Set a velocity
Code:
changeentityproperty(self, "velocity",  Vx, Vz, Vy);
(define Vx, Vz and Vy first, or pass NULL() in Y velocity)

And compare if your character position is equal to the ones you want.
If yes, reset velocity (and maybe change its animation)
Code:
  changeentityproperty(self, "velocity", 0, 0, 0);

Tip: I would suggest you to use a threshold, so the position won't be pixel perfect.
 
danno, if I understand what you want correctly, you might also try cracking open the old Golden Axe Remake. Utunnels had an AI script that would take over the player characters and have them walk to a spot.

DC
 
I had a look at Utunnels script
Code:
float abs(float f)
{
    if(f>0) {return f;}
	else {return -f;}
}

void main()
{
	int j;
    void pp = getlocalvar("selectedplayer");
	int end = getlocalvar("end");

	for(j=0; j<3; j++)
	{
		void pother = getplayerproperty(j, "ent");
		if(pother!=NULL())
		{
			if(getentityproperty(pother, "animationid")==openborconstant("ANI_IDLE"))
			{
				changeentityproperty(pother, "velocity", 0, 0, 0);
				changeentityproperty(pother, "noaicontrol", 1);
			}
		}
	}

    if(getglobalvar("a_npc")!=NULL() && getentityproperty(getglobalvar("a_npc"), "a") <=1 )
    {
        changeentityproperty(getglobalvar("a_npc"), "velocity", 0, 0, 0);
        changeentityproperty(getglobalvar("a_npc"), "noaicontrol", 1);
        changeentityproperty(getglobalvar("a_npc"), "animation", openborconstant("ANI_IDLE"));
    }
    if(getglobalvar("g_npc")!=NULL() && getentityproperty(getglobalvar("g_npc"), "a") <=1 )
    {
        changeentityproperty(getglobalvar("g_npc"), "velocity", 0, 0, 0);
        changeentityproperty(getglobalvar("g_npc"), "noaicontrol", 1);
        changeentityproperty(getglobalvar("g_npc"), "animation", openborconstant("ANI_IDLE"));
    }
    if(getglobalvar("t_npc")!=NULL() && getentityproperty(getglobalvar("t_npc"), "a") <=1 )
    {
        changeentityproperty(getglobalvar("t_npc"), "velocity", 0, 0, 0);
        changeentityproperty(getglobalvar("t_npc"), "noaicontrol", 1);
        changeentityproperty(getglobalvar("t_npc"), "animation", openborconstant("ANI_IDLE"));
    }

	if(end==NULL() && pp!=NULL() )
	{
		int x = getentityproperty(pp, "x");
		int z = getentityproperty(pp, "z");
		if(x<=1352 && x>=1348 && z<=224)
		{
			changeentityproperty(pp, "animation", openborconstant("ANI_IDLE"));
			changeentityproperty(pp, "velocity", 0, 0, 0);
			changeentityproperty(pp, "direction", 1);
			//other
			setglobalvar("release", 1);
			setlocalvar("end", 1);
		}
		else
		{
			int vz = 0;
			int vx = 0;
			int dx = 1350 - x;
			int dz = 224 - z;
			if(dx !=0 || dz!=0) 
			{
				if(z>223) {vz = dz/(abs(dx) + abs(dz)) * 0.6;}
				if(x>1351 || x<1349) {vx = dx/(abs(dx) + abs(dz)) * 0.6;}
			}
			changeentityproperty(pp, "velocity", vx, vz, 0);
			if(x<1350){changeentityproperty(pp, "direction", 1);}
			else {changeentityproperty(pp, "direction", 0);}
		}

	}
	else if(end==NULL() && pp==NULL() && getentityproperty(getglobalvar("adder"), "animating")==0)
	{
		int i;
		for(i=0; i<3; i++)
		{
			void p = getplayerproperty(i, "ent");
			if(p!=NULL())
			{
				if(getentityproperty(p, "animationid")==openborconstant("ANI_IDLE"))
				{
					changeentityproperty(p, "animation", openborconstant("ANI_UP"));
					changeentityproperty(p, "velocity", 0, 0, 0);
					changeentityproperty(p, "noaicontrol", 1);
					setlocalvar("selectedplayer", p);
					playmusic("data\\music\\conclu~1.bor", 0);
					break;
				}
			}
		}
	}

}
but its more stage specific and requires an invisble entity to call, I kinda need a one size fits all for 2d stages too

I'll explain more, I'd like player to do a transformation into another entity so when you press the transformation button they jump into the centre of the screen and then transform, at first I was going the walk them into the screen but I think jump will work better as it can be used as an evasive move also

Code:
anim  freespecial3   #beast mode
@script
  if(frame == 0){
    void self = getlocalvar("self");
	int x = getentityproperty(self, "x");
    int z = getentityproperty(self, "z");
	int Screen = openborvariant("hResolution")/2;
    int Dir = getentityproperty(self, "direction");
	int XPos = openborvariant("xpos");
	int Width = (openborvariant("PLAYER_MIN_Z")+(openborvariant("PLAYER_MAX_Z") - openborvariant("PLAYER_MIN_Z"))/2)+1;


    if(Dir==0){
	  changeentityproperty(self, "position", Screen+XPos-20, Width+1, NULL());
    } else {
	  changeentityproperty(self, "position", Screen+XPos-20, Width+1, NULL());
    }
  }
@end_script
loop      0
delay     100
offset    63 104
weaponframe	8 1
jumpframe 0 2 2
landframe 1 
frame     data/chars/jam/j1.png
delay     10
frame     data/chars/jason/l.png
delay     10
frame     data/chars/jason/m2.png
frame     data/chars/jason/m3.png
frame     data/chars/jason/m5.png
delay     40
frame     data/chars/jam/m4.png
delay     7
frame     data/chars/jam/m5.png
delay     150
frame     data/chars/jam/m4.png
@cmd   playwebm "data/vids/red.webm" 1
frame     data/chars/jam/i3.png

I've been playing around with what O Ilu posted but the effect is more teleport like instead of jumping into the middle of the screen, almost there just missing a small detail
 
I've been playing around with what O Ilu posted but the effect is more teleport like instead of jumping into the middle of the screen, almost there just missing a small detail
For sure it is - its for what I use. I told you you could use that logic and then build what you need after it :)
 
Bloodbane said:
Oh that one! walking to certain coords than perform other animation there.

I usually have enemy or boss leap to certain coords instead to get more precise result and efficient animation. Efficient = The leap and the other animation in single animation.
Walking is different than leaping. Leaping usually has no velocity limit so enemy or boss could leap with high velocity when they are far from destinated coords to reach it.
However not with walking as walking usually has defined speed/velocity. Because of that, it's hard to set finite frames for enemy/boss and hard to figure out when exactly they will reach the coords. If they are far, they could play more frames than if they were close.

Hmmm... I forgot if I've ever coded walk to coords before but I know the logic so it shouldn't be hard to recode it :).
Allow me to express my humble opinion about this issue. If you set an Invisible  entity in a specific coordinate, for example, it has an aggressiveness of attack16, and every time the player walks to the location of the entity, it will be attack. 16 attack, then let the player's pain16. stop.
 
This is my effect i,
Only used @cmd target,@cmd dash script,
After the enemy dies, the invisible subject will appear, and it will ask the protagonist to show a
@cmd target,@cmd dash script animation

When the protagonist is hit, an animation will be generated according to the attack attribute to make the protagonist stop moving and standing.

but. hitflash  must be free
this  hitflash  (Make it so that there is no image or sound effect)


 
xyz555 thanks your solution works but only at certain locations of the stage, my issue is to have it work on keypress inside an animation and also be in the middle of the screen O illu posted a great way to find the middle of the screen, I'm just trying to figure out the logic inside an entity jump animation.... I think using an invisible entity is the best way to do it though, so what I'm going to try at some point over the weekend is this

Player has invisible entity binded to him ( castlevania familiar style ) that spawns on keypress and attacks player and sends player to location
 
Ah so that's what you want danno ! I think I've seen similar effect before in some games but forgot which games and which character  :-[.

Anyways, I've tinkered bomb tossing scripts from my 2D games and managed to code something to make entity toss itself to center of screen:
Code:
anim	idle
@script
    if(frame==1){
      void self = getlocalvar("self");
      float x = getentityproperty(self, "x");
      float y = getentityproperty(self, "a");
      float Tx = openborvariant("xpos") + openborvariant("hResolution")/2;
      float Ty = openborvariant("vResolution")/2;
      float Vx; float Vy;
      int Time = 100; // 100 centiseconds = time from start to reach destination 

      Vy = 0.05*Time +  (Ty - y)/Time;
      Vx = (Tx-x)/Time;

      tossentity(self, Vy, Vx);
    }
@end_script
	delay	1
	offset  10 10
	frame	data/chars/misc/shots/jolt.png
	delay	100
	frame	data/chars/misc/shots/bolt2.png # jumping part
	delay	10
	frame	data/chars/misc/shots/boltH1.png # played after reaching center of screen
	frame	data/chars/misc/shots/boltH2.png
	frame	data/chars/misc/shots/boltH3.png
	frame	data/chars/misc/shots/boltH1.png
	frame	data/chars/misc/shots/boltH2.png
	frame	data/chars/misc/shots/boltH3.png
	@cmd	suicide
	frame	data/chars/misc/empty.gif

This entity will jump to center of screen at 2nd frame and will reach it at 3rd frame.

HTH
 
That's great Bloodbane for 2D stages, I added a little more code for 2.5 stages

Code:
@script
    if(frame==1){
      void self = getlocalvar("self");
      float x = getentityproperty(self, "x");
      float z = getentityproperty(self, "z");
      float y = getentityproperty(self, "a");
      float Tx = openborvariant("xpos") + openborvariant("hResolution")/2;
      float Ty = openborvariant("ypos") + openborvariant("vResolution")/2;
      float Vx; float Vy; float Vz;
      int Time = 60; 
      int Pz = (openborvariant("PLAYER_MIN_Z")+(openborvariant("PLAYER_MAX_Z") - openborvariant("PLAYER_MIN_Z"))/2)+1;


      Vy = 0.02*Time +  (Ty - y)/Time;
      Vx = (Tx-x)/Time;
      Vz = (Pz-z)/Time;

      tossentity(self, Vy, Vx, Vz);
    }
@end_script

Thanks for helping me with this guys, very much appreciated Damon Caskey  O Ilusionista  Bloodbane  xyz555
 
Back
Top Bottom