Jankiness and how to fix it

Creating Games? Developing something for fun?

Moderators: FourthWorld, heatherlaine, Klaus, kevinmiller, robinmiller

Post Reply
styopquoons
Posts: 4
Joined: Thu Oct 31, 2013 9:41 pm

Jankiness and how to fix it

Post by styopquoons » Fri Nov 01, 2013 12:05 am

Hello, first post. I'm a new user of LiveCode. I used to make adventure games using hypercard back in the day, and I've also made a couple using the AGS engine. Altogether I would say I have an intermediate level of coding knowledge, at least in high-level environments like this one, but nowhere near the level of a professional.

Anyway, I put together my first game to test out the livecode environment a little. It's nothing fancy, just a simple, stupid, completely unremarkable version of Bricks. I've tested it, built it as an app, and it works, but it's janky as hell. I've gone over the code up and down and I can't seem to figure out why. It seems to get especially janky when the ball or the paddle get close to the edges of the screen.

I've put the .livecode file, as well as the compiled game into a .zip file and uploaded it to my website, since I'm not sure exactly where the issue(s) lay exactly, and I don't want to clutter up the forum by posting my card and stack scripts in their entirety. If anyone out there with more coding experience than me has the time or the inclination, I would greatly appreciate it if they could look it over and tell me what could make it run better, or if there's something I did wrong or could be done better.

I apparently don't have permission to post links in this forum, so you'll have to PM me for the link, sorry. I borrowed a basic framework for a game loop from another site, which I can also send a link to if you PM me. Everything else is my own code.

In return for your help, I offer the game itself. Play it, modify it, put your own name on it and sell it; I don't care. I will probably re-use this game as maybe a minigame in a better game, or maybe have some other use for it, but this particular version I built purely to test out the LiveCode environment, and have no intention of publishing or doing anything else with it as it presently exists. I also don't care if you re-use any of my code.

Thanks in advance.
Original Music, Games, Fiction and More!

http://www.therealmuffin.net

Women and children not admitted.

styopquoons
Posts: 4
Joined: Thu Oct 31, 2013 9:41 pm

Re: Jankiness and how to fix it

Post by styopquoons » Fri Nov 01, 2013 12:15 am

Me again. I've been looking this over on this board, and I'm not even sure PMing is available here, so I'm not quite sure how I'm supposed to get links to people. You can email me I guess; sorry for the trouble. I'm a member on a lot of PHPbb systems and I tend to assume most of them have the same basic functions available.

Jeez, it won't even let me list an email. Okay, here, I think I've figured out a way to list it. Here is the original link, plus my email, and again I am sorry for all the trouble.

therealmuffin(dot)net/games/testgame.zip

quoons(@)therealmuffin(dot)net. Thanks again.
Original Music, Games, Fiction and More!

http://www.therealmuffin.net

Women and children not admitted.

jacque
VIP Livecode Opensource Backer
VIP Livecode Opensource Backer
Posts: 7393
Joined: Sat Apr 08, 2006 8:31 pm
Contact:

Re: Jankiness and how to fix it

Post by jacque » Sat Nov 02, 2013 8:19 pm

I think you're not getting responses because in order to help, we'd need to diagnose an undefined problem in an undefined location inside a whole stack. There are a few people here who might be willing to spend that amount of time, but you'll get more suggestions if the problem is well defined and can be addressed without requiring offline work. So I'd suggest:

Define what you mean by "janky". That's not a very good clue, I can only gather that something doesn't work. What is going on when it fails? How does it fail? What do you see exactly?

Post the portion of your scripts that manage (I assume) object movement. There are lots of good ways to move objects in LiveCode that HC never had. We can suggest them. Or if movement isn't the issue, tell us what is and find the part of the scripts that manages that.

Post short bits of script, only what's required to show the problem. People won't read hundreds of lines of code.

If we can see something here in the forums, you'll get fast responses. We're not so eager to volunteer to download a complete game, figure out what's wrong, and then track down where in the scripts it might be caused.
Jacqueline Landman Gay | jacque at hyperactivesw dot com
HyperActive Software | http://www.hyperactivesw.com

styopquoons
Posts: 4
Joined: Thu Oct 31, 2013 9:41 pm

Re: Jankiness and how to fix it

Post by styopquoons » Sat Nov 09, 2013 5:31 am

It's okay, I posted this without expecting to get many takers. :) It's not a huge problem for me, I'm mostly just curious as to where exactly the bugs are; I figured I would just sort of toss this out there in the wild hope that a seasoned user who was in a generous mood might feel like picking up a bit of a challenge. I've more or less moved on to other projects, I just figure if I could get this issue sorted out I'd be that much better of a script writer.

I guess to clarify the exact problem I'm having, "janky" refers to both the ball and the paddle moving slowly and choppily. This problem seems to get worse when either one gets closer to the edges of the screen; when ball and paddle are closer to the center it moves pretty much fine. Again, I am not sure if the problem is related directly to the movement of the ball or the paddle, or if it's related to something else entirely, as I wrote a lot of functions for this script. However, here is the part of the script that controls movement of the paddle:

Code: Select all

on moveBox
   if keysdown() = 65361 then
       set the left of the graphic "box" to the left of the graphic "box" - 15
       if the left of the graphic "box" < the left of image "cover"  then
          set the left of the graphic "box" to the left of the card "level1"
       end if
   end if
   if keysdown() = 65363 then
       set the right of the graphic "box" to the right  of the graphic "box" + 15
       if the right  of the graphic "box" > (the right  of the image "Cover") then
           set the right  of the graphic "box" to the right  of the image "Cover"
       end if
   end if
end moveBox
The paddle is defined as a graphic called "Box". The borders of the screen are set to an image called "Cover".

Here is the code pertaining to the ball movement:

Code: Select all

on moveBall
   if ballMoving is true then
      if ballDirection is "up" then
         set the top of the graphic "ball" to the top of the graphic "ball" - 10
         set the left of the graphic "ball" to the left of the graphic "ball" - ballAngle
      end if
      if ballDirection is "down" then
         set the bottom of the graphic "ball" to the bottom of the graphic "ball" + 10
         set the left of the graphic "ball" to the left of the graphic "ball" + ballAngle
      end if
   else
      set the left of the graphic "ball" to the left of the graphic "box" - 58
      set the right of the graphic "ball" to the right of the graphic "box" -54
   end if
end moveBall
Again, the ball is a graphic called "ball". The angle is determined by a local variable called "ballAngle"

This is the code that determines what happens if the ball hits either the borders of the screen, or the paddle itself. It also checks to see if the ball is touching any of the bricks, the number of which is defined based on the local variable "numberOfBricks".

Code: Select all

on detectCollisions
   put 1 into counter
   repeat while counter < numberOfBricks
      checkIntersection format ("brick%u", counter)
      add 1 to counter
   end repeat
   if the left of graphic "ball" < the left of image "Cover" then
      put ballAngle - ballAngle * 2 into ballAngle
   end if
   if the right of graphic "ball" > the right of image "Cover" then
      put ballAngle - ballAngle * 2 into ballAngle
   end if
   if the top of the graphic "ball" < the top of card "Level1" then
      put ballAngle - ballAngle * 2 into ballAngle
      put "down" into ballDirection
   end if
   if intersect (graphic "ball",graphic "box") then
      put (the right of graphic "ball" - the left of graphic "box") / 2 into ballHitLocation
      
      if ballHitLocation < 41 then
         put 2 into ballAngle
         if ballHitLocation < 37 then put 4 into ballAngle
         if ballHitLocation < 27 then put 6 into ballAngle
         if ballHitLocation < 17 then put 8 into ballAngle
         if ballHitLocation < 12 then put 11 into ballAngle
      end if
      if ballHitLocation > 43 then
         put -2 into ballAngle
         if ballHitLocation > 52 then put -4 into ballAngle
         if ballHitLocation > 62 then put -6 into ballAngle
         if ballHitLocation > 72 then put -8 into ballAngle
         if ballHitLocation > 77 then put -11 into ballAngle
      end if
      
      put "up" into ballDirection
   end if 
   if the bottom of the graphic "ball" > the bottom of the card "Level1" then
      subtract 1 from lives
      stopGame
      resetGame
      startGame
   end if
end detectCollisions
Finally, this is the checkIntersection function that is called from within detectCollisions.

Code: Select all

on checkIntersection theGraphic
   if the visible of graphic theGraphic is true and intersect (graphic "ball", graphic theGraphic) then
      if the theType of graphic theGraphic is solid then
         set the theType of graphic theGraphic to basic
         set the backgroundColor of graphic theGraphic to SlateGray1
      else
         set visible of graphic theGraphic to false
         checkWinGame
      end if
      
      put (the theValue of graphic theGraphic * multiplier) into datAss
      add datAss to score
      add datAss to scoreTracker
      put ballAngle - ballAngle *2 into ballAngle
      if ballDirection is "up" then put "down" into ballDirection
      else put "up" into ballDirection
   end if
end checkIntersection
I suspect that if the problem is anywhere, it's in one of these areas. However, like I said, I wrote a lot of script, so it could be elsewhere. Anyway, like I said, I don't expect anyone to break their brain over this, but if anyone can see any obvious problems or would like to take a deeper look at this for whatever reason, let me know. Thanks.
Original Music, Games, Fiction and More!

http://www.therealmuffin.net

Women and children not admitted.

jacque
VIP Livecode Opensource Backer
VIP Livecode Opensource Backer
Posts: 7393
Joined: Sat Apr 08, 2006 8:31 pm
Contact:

Re: Jankiness and how to fix it

Post by jacque » Sat Nov 09, 2013 10:03 pm

Okay, that helps a lot. When you get jerky motion it is usually because there is too much going on in the script, so you get delays. Motion scripts need to be sparse and optimized to contain the fewest possible commands that get the job done. One of the most time-expensive operations is redrawing the screen, it is very slow relatively speaking, and your script redraws constantly. So the single most important optimization you can make is to lock the screen, do all the movement in one pass, and then unlock the screen. The most likely place for this to happen (I think, judging from what I see here) would be to issue a "lock screen" in whatever handler starts the ball and paddle movement, and "unlock screen" after all those operations have completed.

Another minor optimization is to make sure that all if-then clauses use "else if" instead of multiple "if"s where possible. Instead of this:

Code: Select all

if keysdown() = 65361 then
     -- stuff
end if
if keysdown() = 65363 then
  -- stuff
end if
Use this:

Code: Select all

if keysdown() = 65361 then
     -- stuff
else if keysdown() = 65363 then
  -- stuff
end if
In the original, both "if" blocks are always checked. In the second example, there's a 50% chance that only one will get checked. This is pretty minor, but since the script is calling out to another semi-expensive function "keysdown()" you want to avoid as many of those as possible. In fact, you shouldn't be using keysdown() in this handler. It would be better to check the key in the calling script and just pass that as a variable:

Code: Select all

on moveBox pKey
  if pKey = 65361 then
    set the left of the graphic "box" to the left of the graphic "box" - 15
    if the left of the graphic "box" < the left of image "cover"  then
      set the left of the graphic "box" to the left of the card "level1"
    end if
  else  if pKey = 65363 then
    set the right of the graphic "box" to the right  of the graphic "box" + 15
    if the right  of the graphic "box" > (the right  of the image "Cover") then
      set the right  of the graphic "box" to the right  of the image "Cover"
    end if
  end if
end moveBox
But this can still be improved. I'm not sure what handler calls "moveBox" but the most logical way would be to use an arrowKey handler. The arrowKey message automatically passes the key name as "left", "right", etc. so you don't even need to check anything to get that. If you trap the arrowKey message, and call moveBox using the parameter it sends, then you won't need the numerical key numbers in moveBox, you can use "left" or "right" in the "if" statements:

Code: Select all

on arrowKey pWhich
  moveBox pWhich
end arrowKey
Moving on... MoveBox is inefficient because it requires a redraw after every command. If the screen is locked that's not a problem, but you can speed it up a little more by passing a parameter, calculating the final position, and doing only one repositioning rather than two. This also reduces the number of instructions:

Code: Select all

on moveBox pKey
  if pKey = "left" then
    set the left of graphic "box" to max(the left of img "cover",the left of graphic "box" - 15)
  else if pKey = "right" then
    set the right of graphic "box" to min(the right of img "cover",the right  of graphic "box" + 15)
  end if
end moveBox
Note that no object references include "the". Use "graphic 'box'" rather than "the graphic 'Box'". The additional "the" may be slowing down the engine while it tries to figure out if you mean a custom property or an object.

See if any of this helps. You may want to see if you can optimize moveBall too.

Finally, check out the "move" command in the dictionary, something HyperCard didn't have. You may be able to replace some of your code with a simple "move" command which does a lot of the calculations for you.
Jacqueline Landman Gay | jacque at hyperactivesw dot com
HyperActive Software | http://www.hyperactivesw.com

styopquoons
Posts: 4
Joined: Thu Oct 31, 2013 9:41 pm

Re: Jankiness and how to fix it

Post by styopquoons » Fri Nov 15, 2013 6:42 am

Thank you for all of this. I've tried implementing the changes you mentioned and it seems to be helping. I think I'm going to need to tinker around with this a bit more before I'll be completely satisfied, but there was definitely a notable improvement just from streamlining a couple of the scripts. The move command I'm definitely going to have to play with a bit. Thanks again.
Original Music, Games, Fiction and More!

http://www.therealmuffin.net

Women and children not admitted.

Post Reply