Author Topic: Issue with counting frames too fast  (Read 8471 times)

Wyzemann

  • Regular
  • **
  • Posts: 26
    • View Profile
Issue with counting frames too fast
« on: 2011-03-17, 03:39:57 PM »
I am trying to set up the player to have controlled jumping (Commander Keen style). This means there is power for a certain amount of time when the jump input is pressed. However you have the option of letting off mid-jump for shorter jumps. You can also move left or right during the jump.

So I have set a parameter to read the frame at which the input is pressed. It adds an arbitrary number of frames to it and stores it to a new parameter. When it reaches that number it cuts off the power until the landing. (I've yet to determine how to prevent multiple jumps within the jump during this time but it's a start).

The jump is now controllable. The problem is that the frames advance significantly faster when you are moving left or right at the same time as jumping which means you barely get off the ground when moving, but can get pretty high when not moving horizontally.

It's almost like the counter is getting two streams of data at the same time whenever you have x motion. The FPS read at a constant rate. The counter is ticking markedly faster when the horizontal input is pressed.  I'm not sure if this is a bug or if it's user error. However if I remove the one data source there is no activity on the counter.

All of the jump handling is done from a level plan. The horizontal motion is done from the sprite definition. Everything thus far is done using basic rules without scripting.

Any suggestions would be appreciated.

bluemonkmn

  • SGDK Author
  • Administrator
  • Fanatic
  • *****
  • Posts: 2761
    • ICQ Messenger - 2678251
    • MSN Messenger - BlueMonkMN@gmail.com
    • View Profile
    • http://sgdk2.sf.net/
    • Email
Re: Issue with counting frames too fast
« Reply #1 on: 2011-03-18, 05:22:19 AM »
Hard to get a full grasp on your problem without seeing it firsthand.  I think this is some of the information I need to know:
1. What is incrementing your counter?  Can you verify that it's something that only executes once per frame (is that how it's supposed to operate?)
2. What are you referring to with terms like "streams of data" and "data source"?  Those aren't SGDK2-native terms... perhaps you are using them to refer to something you build into your project or using another term for an SGDK2 concept?
3. Your goal sounds relatively simple, have you considered the following solution?
  a. Add a parameter to the player sprite
  b. When you detect a jump, set the parameter to 1
  c. If the parameter is greater then or equal to 1, then increment the parameter value; if the jump button is still pressed, also AlterYVelocity by a very small negative amount
  d. If the parameter is greater than 40 (or some jump time limit), reset the parameter to 0.

If this doesn't help, please pose your project or a link to your project in your reply so I can take a look at it firsthand.  Attachments to post have a limit of 128 KB or 256 KB I think (if I recall correctly -- I forget which), so if it's larger than that, you'll have to make a simple example of the problem and post that or post your project elsewhere and link to it, or upload your project to the SGDK2 support site at http://sgdk2.enigmadream.com/support/

Vincent

  • SGDK2 Addict
  • Expert
  • Fanatic
  • *****
  • Posts: 612
  • Legacy of Kain: Revival is completed!!!
    • View Profile
    • Chivalrous Games
    • Email
Re: Issue with counting frames too fast
« Reply #2 on: 2011-03-18, 06:48:57 AM »
I did pretty much the jumping behavior you want to do in my game.  I kinda tried to do the same thing than you Wyzeman, but I found a much easier way to do it.  Here is my recipe:

1- Like bluemonkmn said, use a sprite parameter (I called mine IsJumping).  Set it to 1 when you input the jump button and set it to 0 the next time your character SnapsToGround or RidesAPlatform.
2- When your character jumps, on the initial input only for the jump button (right after or before you set the IsJumping parameter to 1) input a negative dy to your character powerful enough to reach the desired max height of a jump.

At this stage, your character jumps at max height whenever you press the jump button but only when it is on the ground.  The character always jumps at the same height whether you hold down the jump button or not.  Nothing in this behavior influences horizontal inputs, so you can still control horizontal direction during your jump.  And now for the last step, breaking the jump when the players release the jump button.

3- Still on the sprite behavior, add a condition that looks for jump button input press with parameter InitialInput only to false and add a "and" condition to "IsJumping = 1".  This way you know all the time during the jump if the jump button is pressed.  But we want to know the opposite.  So switch the 1st condition to listening to button input to not (check the "not" check box).  This way we know, all along the jump if the player releases the jump button at any time.  Within this condition, set the dy of your character to "0".

So at any time during the jump, if the player releases the jump button, the jump breaks and the character starts to fall.

All those rules are in the sprite definition, so you don't have to rewrite them in each map you do.

So to, sum it up, in pseudo code (you can do all of this by rules) it looks like this:

1 : If jump buttonPressed(initial only = true)
2 : and IsJumping = 0
3 :   IsJumping = 1
4 :   dy = -10
5 : end

6 : if snaptoground(1)
7 : or IsRidingPlatform
8 :   IsJumping = 0
9 : end

10: if not jump buttonPressed(initial only = false)
11: and IsJumping = 1
12:   dy = 0
13: end

Your horizontal code for inputs goes wherever and is not influenced by the jump behavior.

I hope this helps!
« Last Edit: 2011-03-18, 07:03:43 AM by Vincent »
Legacy of Kain: Revival completed!
http://lokrevival.webs.com

See also my company website:
http://chivalrousgames.com

Vincent

  • SGDK2 Addict
  • Expert
  • Fanatic
  • *****
  • Posts: 612
  • Legacy of Kain: Revival is completed!!!
    • View Profile
    • Chivalrous Games
    • Email
Re: Issue with counting frames too fast
« Reply #3 on: 2011-03-18, 07:01:52 AM »
Ah, just remembered something (I'm doing this by memory, so I might forget other things), between rule 11 and 12, you also have to check if your character dy<0, other wise, it's just gonna stay suspended in the air.  So it looks like this:

11:    and IsJumping = 1
11.5: and dy < 0
12:     dy = 0

I think that's it.
Legacy of Kain: Revival completed!
http://lokrevival.webs.com

See also my company website:
http://chivalrousgames.com

Wyzemann

  • Regular
  • **
  • Posts: 26
    • View Profile
Submitted sample and clarification
« Reply #4 on: 2011-03-18, 08:05:25 AM »
As of now the game is about as simple as it can be so I simply uploaded it as is to the link you suggested. Right now all I have is a player sprite, a couple of tiles, and some counter displays, and I'm trying to make it behave.

I am grateful for the solutions you guys have proposed. I am looking forward to implementing them ASAP. The counters are just for display (troubleshooting) since I don't know how to draw parameter data directly. They aren't being used to control anything. The rules that affect the behavior of the game are tied directly to the sprite's parameters.

I apologize for using abstract terms. I think it would be easier just to look at what has been done. The counter is tied to the player sprite parameter which is tied to m_ParentLayer.m_Player1.frame. The counter is updated as long as the up input is pressed.

For me this is somewhat of a black box. I understand this is supposed to provide the frames of the animation being displayed in sequence, which I suppose should be at the framerate of the game. (Which I have limited to 30 fps).

It's like it's getting pulsed 30 times per second by whatever pulses it when the jump animation is playing (one data source), and then when there is a horizontal input it's getting pulsed by an additional whatever so it gets too many pulses per unit time. Of course this is speculation and I'll let you be the judge. The bottom line is it is behaving an in unexpected way that could have implications for other things as well.

Thanks a bunch,

Chris

bluemonkmn

  • SGDK Author
  • Administrator
  • Fanatic
  • *****
  • Posts: 2761
    • ICQ Messenger - 2678251
    • MSN Messenger - BlueMonkMN@gmail.com
    • View Profile
    • http://sgdk2.sf.net/
    • Email
Re: Issue with counting frames too fast
« Reply #5 on: 2011-03-18, 08:30:03 AM »
I can't look at the project at the moment (hopefully I will remember when I get home), but I can provide some more tips.
1. You can get past the black box problem and debug your project if you download C# Express (for free) from http://www.microsoft.com/visualstudio/en-us/products/2010-editions/visual-csharp-express.  SGDK2 outputs project files so you can load and debug the project.  (It outputs the project in an old format so you'll have to go through the project upgrade process if you get C# Express 2010, but that's pretty simple and quick.)  Then you should be able to step through the code if that helps.
2. You can output debug information about parameters with a function called (I think) LogDebugValue.

bluemonkmn

  • SGDK Author
  • Administrator
  • Fanatic
  • *****
  • Posts: 2761
    • ICQ Messenger - 2678251
    • MSN Messenger - BlueMonkMN@gmail.com
    • View Profile
    • http://sgdk2.sf.net/
    • Email
Re: Issue with counting frames too fast
« Reply #6 on: 2011-03-18, 08:33:36 AM »
Does your sprite animate when moving horizontally and not otherwise?  If so, I wonder if something about the way you tied the counter to the sprite's frame is causing it to change faster when the sprite is animating.  (Frame does not change when the sprite is not animating, for example because it is not moving horiziontally, but changes significantly in proportion to the speed that the sprite is moving if you tied animation speed to horizontal velocity.)
« Last Edit: 2011-03-18, 08:38:03 AM by bluemonkmn »

bluemonkmn

  • SGDK Author
  • Administrator
  • Fanatic
  • *****
  • Posts: 2761
    • ICQ Messenger - 2678251
    • MSN Messenger - BlueMonkMN@gmail.com
    • View Profile
    • http://sgdk2.sf.net/
    • Email
Re: Issue with counting frames too fast
« Reply #7 on: 2011-03-18, 04:37:59 PM »
I looked at the project and I see you have rules that are causing the counter to increment twice per frame when you are jumping and moving horizontally.   The AnimateJump rule will cause the counter to increase when you are jumping.  AnimateL and AnimateR will cause it to increase when you are moving left or right.  So if you are doing both at the same time, it will increase twice as fast.

Wyzemann

  • Regular
  • **
  • Posts: 26
    • View Profile
Re: Issue with counting frames too fast
« Reply #8 on: 2011-03-18, 07:00:24 PM »
That's cool. I didn't think that would overlap like that. My intention was to apply those to only the L and R sprite states, and had no idea that could happen.
 
I am interested in getting set up with the C# compiler and will get that running soon. Unfortunately it looks like my time will be more and more limited each day as I am in the process of moving out of state and approaching the deadline for vacating.

Thanks for your input,

Chris

Wyzemann

  • Regular
  • **
  • Posts: 26
    • View Profile
Problem fixed
« Reply #9 on: 2011-03-19, 08:57:54 PM »
I integrated Vincent's strategy into my logic and cleaned things up a bit by consolidating everything back into the Sprite definition.

Setting dx to 0 mid jump is much more elegant than using a timer to block an input. I also reconfigured the animation to prevent the double framerate problem in case I use timers in the future. The only thing I had a problem with was using the "snaptoground" method. It seems to work intermittently and requires a high threshold to function at all (around 12). I tried implementing the "IsOnTile" method and that does not work either, ven when I set to detect all solid tiles. It's a mystery.
 
The only thing that does work for me is the "Blocked" method and it works consistently.
So far progress is very slow and I'm learning through trial and error, and of course, your suggestions.

bluemonkmn

  • SGDK Author
  • Administrator
  • Fanatic
  • *****
  • Posts: 2761
    • ICQ Messenger - 2678251
    • MSN Messenger - BlueMonkMN@gmail.com
    • View Profile
    • http://sgdk2.sf.net/
    • Email
Re: Issue with counting frames too fast
« Reply #10 on: 2011-03-19, 09:44:31 PM »
IsOnTile will likely never return true for a solid tile because sprites generally don't overlap solid tiles.  That's what IsOnTile is for -- checking what tiles the sprite is overlapping.  The Blocked function is better for determining if the player is able to jump.  That's what the sample game uses for determining if the player should be able to jump (in combination with IsRidingPlatform).  Also, I wrote a function for my own project called "IsAgainstTile" for checking tiles around the sprite rather than overlapping the sprite.  You could add this to a new file in your project's "SourceCode" folder and then it would be available for you to use in the sprite rule editor too if you want it:

Code: [Select]
public abstract partial class SpriteBase : GeneralRules
{
   /// <summary>
   /// Determines if a tile at the sprite's current position is a member of the specified category.
   /// </summary>
   /// <param name="Category">Tile category against which the tile will be checked.</param>
   /// <param name="RelativePosition">The sprite may be on multiple tiles at once. This parameter
   /// indicates which part of the sprite to look at, and gets the tile from the layer at
   /// the specified position.</param>
   /// <returns>True if the specified point in the sprite is on a tile in the specified category, false otherwise.</returns>
   [Description("Examines the tile on the layer at the sprite's current position and determines if it is a member of the specified category. The RelativePosition parameter determines which part of the sprite to use when identifying a location on the layer, and Direction determines which direction from that point to check. (TouchTiles is not necessary for this function.)")]
   public bool IsAgainstTile(TileCategoryName Category, RelativePosition RelativePosition, Direction Direction)
   {
      Debug.Assert(this.isActive, "Attempted to execute IsAgainstTile on an inactive sprite");

      System.Drawing.Point rp = GetRelativePosition(RelativePosition);
      switch(Direction)
      {
         case Direction.Up:
            rp.Offset(0, -1);
            break;
         case Direction.Right:
            rp.Offset(1, 0);
            break;
         case Direction.Down:
            rp.Offset(0, 1);
            break;
         case Direction.Left:
            rp.Offset(-1, 0);
            break;
      }
      return layer.GetTile((int)(rp.X / layer.Tileset.TileWidth), (int)(rp.Y / layer.Tileset.TileHeight)).IsMember(Category);
   }
}

In my project, SnapToGround is after ReactToSolidity and before MoveByVelocity.  If you don't have it there, or if you have other rules in between, they might interfere with SnapToGround's ability to function properly.

Have you looked at how the player sprite in the sample game works to see what you might learn from that?

Wyzemann

  • Regular
  • **
  • Posts: 26
    • View Profile
Learning from player example
« Reply #11 on: 2011-03-20, 08:24:45 AM »
I actually did learn from the player example, but now that I look at it again I am understanding more since I've learned a lot since I started.
In fact I wouldn't have got past going left and right without it. The player example is much simpler. My player now has different states for jumping and switches left and right states in the air, and now, thanks to Vincent, the jump can be interrupted based on the input being released.

I will be glad to try out your suggestions and new rule and see how they all work, probably some time this evening. Next I will work on adding some new animations for climbing and shooting and see how I can make those work.

Chris

Vincent

  • SGDK2 Addict
  • Expert
  • Fanatic
  • *****
  • Posts: 612
  • Legacy of Kain: Revival is completed!!!
    • View Profile
    • Chivalrous Games
    • Email
Re: Issue with counting frames too fast
« Reply #12 on: 2011-03-20, 11:25:25 AM »
Hey Chris!

I'm glad you found my code useful!  Likfe bluemonkmn said, SnapToGround works well after ReactToSolid.  I wasn't aware of the existence of IsOnTile or Blocked.  Are these new functions?

Legacy of Kain: Revival completed!
http://lokrevival.webs.com

See also my company website:
http://chivalrousgames.com

Wyzemann

  • Regular
  • **
  • Posts: 26
    • View Profile
Trying out different methods
« Reply #13 on: 2011-03-20, 02:29:24 PM »
I was able to get bluemonkmn's code "Against Tile" to work nicely, but am still not able to get the SnapToGround method working consistently. I have uploaded my project if you would like to check it out. The offset must be set at at least 12 before there is a result.

In the project the character will not jump unless the ground is detected using the rule called "OnLanding". You should be able to get it to fail when you turn and jump (while on the ground) simultaneously, but not every time.

Chris


bluemonkmn

  • SGDK Author
  • Administrator
  • Fanatic
  • *****
  • Posts: 2761
    • ICQ Messenger - 2678251
    • MSN Messenger - BlueMonkMN@gmail.com
    • View Profile
    • http://sgdk2.sf.net/
    • Email
Re: Issue with counting frames too fast
« Reply #14 on: 2011-03-21, 06:29:03 AM »
I wasn't aware of the existence of IsOnTile or Blocked.  Are these new functions?

They have been around for at least a few releases.  I can't remember when I added them, so they're not very new.  I do remember Durnurd pointing out some issue related to the Blocked function, but I can't remember if it was a problem with the way Blocked worked (meaning I needed a new function) or if it was a problem in another function that caused me to add this new "Blocked" function.  But that was probably a year ago if not more.