Adventure Game Studio

AGS Support => Beginners' Technical Questions => Topic started by: Revae on Sat 05/01/2013 09:12:32

Title: Using SayAt function after walking [SOLVED]
Post by: Revae on Sat 05/01/2013 09:12:32
Weird thing I can't seem to get to work.  I have a character with a very tall hat, and due to this I'd like his text to appear lower than normal (so it's over his head, not his hat).  So I've been using SayAt for this, and it generally works fine... until now (dun dun dun).

The camera pans up to him in a window.  I have him say something from the window.  Camera pans down.  He moves Then walks left and speaks again.  Like this: 

Code (AGS) Select

function room_FirstLoad(){

player.Walk(205, 1772, eBlock, eWalkableAreas);
player.Say("Feynman!  Come down!  It's important!");

int xpos7 = 0;
int ypos7 = 1035;
while (ypos7 > 125) {
  SetViewport(xpos7, ypos7);
  Wait(1);
  xpos7 = xpos7+5;
  ypos7 = ypos7-5;
}

cFeynman.Walk(1840, 688, eBlock, eWalkableAreas);
cFeynman.FaceCharacter(cPlayer, eBlock);
cFeynman.SayAt(cFeynman.x, cFeynman.y -350, 400,"I have a doorbell ya know!");
cFeynman.SayAt(cFeynman.x, cFeynman.y -350, 400,"I'll be right down...");
cFeynman.Walk(2044, 688, eBlock, eWalkableAreas);

while (ypos7 <= 1035){
  SetViewport(xpos7, ypos7);
  Wait(1);
  xpos7 = xpos7-5;
  ypos7 = ypos7+5;
}

cFeynman.x=1174;
cFeynman.y=1790;

cFeynman.Walk(550, 1780, eBlock, eWalkableAreas);

cFeynman.SayAt(cFeynman.x, cFeynman.y -350, 400,"Okay...");
cFeynman.SayAt(cFeynman.x, cFeynman.y -350, 400,"What did you want now?");
}


But when he says "Okay..." it's off screen somewhere instead of over his head.  I can't see where it's ending up so I can't really tell what's going on exactly.

Would changing his position with "cFeynman.x=1174;" and "cFeynman.y=1790;" affect this or maybe the camera pan?  I'm kinda at a loss.

Also:  Is there any way that I can have the position of his text permanently set instead of using SayAt every time?  It's not a big deal, but it'd be nice to know.  :P
Title: Re: Using SayAt function after walking
Post by: Armageddon on Sat 05/01/2013 09:28:07
Say at is a pretty bad way to do this, I'd suggest cutting his hat from all his sprites and making the hat it's own character that follows the player exactly. If it's a cutscene you could just make a new character that says it in the one scene?
Title: Re: Using SayAt function after walking
Post by: Revae on Sun 06/01/2013 06:22:00
It is a cutscene, but I'd rather not have to make a new character every time my camera moves on this guy.  But if there is no other way then I'm going to have to...  Just want to explore my options first.

Making the hat a separate character sounds crazy hard since my walk cycles and every other animation are relatively high frame-rate (by AGS standards).  I can easily see this causing problems.  I'd like to figure out a better system anyway because I may have to use it on other characters down the line, and having their speaking animations synced up to their hats/wings/whateveriuse doesn't sound too practical.

I'm trying to keep my frame count down as well (as much as possible) since hitting 30,000 is actually a concern, and rendering out 2 images for every frame of animation on certain characters could impact that.

I may still go with making it a new character if need be...  I've actually used objects for certain character animations too when it seems like the best way.  Thanks.
Title: Re: Using SayAt function after walking
Post by: geork on Sun 06/01/2013 10:27:53
Despite having been here for a while, I've never, ever used viewports before, so unfortunately I can't be much specific use. However, I'm guessing shifting it from the camera's original position has something to do with it...in the manual, under SayAt, it states:
QuoteNOTE: This function does not support Whole-Screen speech.
I'm guessing what you'd have to do is to add a Viewport factor when calling SayAt, something like:
Code (AGS) Select
cFeynman.SayAt(cFeynman.x + GetVieportX(), cFeynman.y -350 + GetViewportY(), 400,"Okay..."); //Could be this...
cFeynman.SayAt(cFeynman.x - GetVieportX(), cFeynman.y -350 - GetViewportY(), 400,"What did you want now?");//Or this...

Again, take all this with a pinch of salt, it's perfectly possible that you have to take away the Viewport, not add it.
Unfortunately I'm in a bit of a rush, but I hope one of those solutions does it (again, apologies if it's a waste of time, I've never used Viewports before)
Title: Re: Using SayAt function after walking
Post by: Khris on Sun 06/01/2013 11:26:03
Since character coordinates are room coordinates and SayAt seems to require screen coordinates, the viewport coords have to be subtracted.

I'd use an extender function:
Code (ags) Select
void SayY(this Character*, String text) {
  int x = this.x - GetViewportX();
  int y = this.y - GetViewportY();
  if (this == cFeynman) y -= 350;
  this.SayAt(x, y, 400, text);
}


Now you can call: cFeynman.SayY("Okay...");

edit: corrected typo
Title: Re: Using SayAt function after walking
Post by: Revae on Fri 11/01/2013 02:39:15
@Khris

Using that I get a "SayY is not a public member of "Character"" error.
Title: Re: Using SayAt function after walking
Post by: Khris on Fri 11/01/2013 11:52:31
You have to import the function in the header of the script where you put it.
Specifically, add the function to the top of GlobalScript.asc, then add this line to GlobalScript.ash:
Code (ags) Select
import void SayY(this Character*, String text);

If you've done it correctly and type "cFeynman." into a script, the auto-complete window should list SayY, along with the icon having a yellow arrow.
Title: Re: Using SayAt function after walking
Post by: Revae on Sat 12/01/2013 01:41:27
I thought I'd done that.  Maybe I just typo'd it or something.  I'll test it out again...
Title: Re: Using SayAt function after walking
Post by: Revae on Sat 12/01/2013 08:07:32
Alright.  I think I've got exactly what I'm looking for now.  Here's what I did:

Code (AGS) Select

void SayY(this Character*, int textHeight, String text){ //Text height declared for use on other characters
  int x = this.x - 200-GetViewportX(); //subtracting 200 as well because "SayAt" width messes with the
                                       //coordinates
  int y = this.y - GetViewportY();
  textHeight = y - textHeight;
  this.SayAt(x, textHeight, 400, text);
}

calling:
cFeynman.SayY(220,"Okay...");

Works pretty perfectly.  Didn't change it drastically from Khris' recommendation, but I should be able to use it whenever my characters heads don't match up with their sprite heights.

Thanks!  I appreciate it.

Edit: And I did typo the header file.  It says "import void SayY(this Character*, int textHeight, String text);" now...  In case anyone needs to know in the future.