fisholith's Recent Forum Activity

  • Hey Freemium, <img src="{SMILIES_PATH}/icon_e_smile.gif" alt=":)" title="Smile">

    I'm not sure off hand if you're interested in info on animation in Construct 2's editor, or info on character animation in general, but hopefully some of what follows may help. <img src="{SMILIES_PATH}/icon_e_smile.gif" alt=":)" title="Smile">

    C2 Animations

    In Construct 2, when you double click a sprite to open the image editor, there are two other windows that open with it, the "Animation frames" window, and the "Animation" window. The Animation window shows a list of the animation sequences you've created for your sprite. Initially the list should only contain one animation named "Default", but you can Right-Click in the Animation window and (from the context menu) choose "Add animation".

    In the Animation window, if you click on an animation, you can edit its speed and other properties in the "Properties" panel.

    You can also Right-Click on an animation to rename it or duplicate it.

    So for a typical sprite character, you might want to make several animations for standing, walking, jumping, falling, attacking, and so forth.

    Then in the event editor, you can add actions to switch between animations.

    e.g. When the player holds the left or right move key, set the sprite's animation to "walking", and when left and right aren't being held, set animation to "standing".

    A little oversimplified, but same basic idea. <img src="{SMILIES_PATH}/icon_e_smile.gif" alt=":)" title="Smile">

    Sprite sheets for reference

    As for the more general side of character animation, it might help to take a look at sprite animation work from existing games.

    The Spriters-Resource is an open database of actual sprite animation sheets from a wide array of games from many systems. It's organized by game system, then by letter, and then often by character or asset type within the game.

    e.g.

    Super Mario World:

    http://www.spriters-resource.com/snes/smarioworld/

    Mario...

    Exploring sprite sheets

    A little off topic, you can find some interesting things by looking through various sprite sheets.

    For instance, In Super Mario Kart, some interesting optimizations can be seen in the sprite collections that make up a character.

    As you can see in the image above, there are 8 different distance levels for a character, and for farther distances, fewer angles are used.

    Likewise, you may notice that there are 12 angles for the close-up distances. If you look closely you'll see that 8 of those images represent the first 90 degree span, (facing away to facing sideways), and the last 4 represent the last 90 degree span, (facing sideways to facing the viewer). I would guess that there are half as many images representing angles facing towards the viewer, because in a race game, if a character is very close to you, they'll most likely be heading the same direction you are, and so they'll most often be facing away from the viewer.

    I think that's kinda neat. :D

  • Is there a good way to scroll layers in any direction, independently of each other?

    For instance, in Super Mario World, in some of the castles, there was a parallax background layer, a game layer, and a moving blocks layer that would sweep from side-to-side sinusoidally. That moving blocks layer's offset in the screen was not just a simple scaled version of the camera coordinates.

    In C2 I can't find an action that allows you to scroll individual layers to any location you want.

    Or if you think of the "camera" as being the thing that is scrolling, I can't find an action that allows you to offset a layer relative to its default starting point.

    Going back to the Mario Castle example, if you could specify layer offset via expression it might look like this:

    • layer_background.X = scrollx * 0.5
    • layer_game.X = scrollx
    • layer_movingBlocks.X = scrollx + ( sin( time ) * sweepDistance )

    The best workaround I've found so far is a bit of a jury rig.

    If, at the start of the layout, I set the "camera" scroll point to the coordinate ( scrollx-100 , scrolly-100 ), then the parallax rate of each layer is effectively that layer's offset in pixels. (I use "-100" instead of "-1" because the scroll rates are given in percentage form.)

    I hope I'm not missing something really obvious, but I can't find anything built-in to use in place of this workaround.

  • Is there a simple way to copy a family from one project to another?

    For instance, if I create a family that handles advanced particle behavior, can I later copy it into another project?

    The only way I know of at the moment is to, in the new project, exactly replicate the family with all the instance variables, effects, and behaviors by hand, and then copy the relevant event code, first by copying top level event sheet variables into a new events sheet, and then copying all the other events over, so as to avoid the missing variables error message.

    Currently I save most of my projects as single files, but I'm curious if it might be possible to copy families and other objects between projects by just dragging and dropping files between project folder structures, or maybe copying blocks of xml or something.

    Any advice or suggestions much appreciated.

  • I don't know of any differences off hand.

    When you import a sound file into Construct2, at the bottom of the import window there is an "OGG/AAC encoding quality" option box. If, this time around, you used a different setting for the quality, you might be hearing a difference from that. If so, you can delete the music files out of C2's Sound or Music folder and re import with higher quality settings. For music I usually use the max audio quality 192-kbps unless I know for a fact that it will cause a problem.

    I did a blind test, playing a song either by C2's music system or the audio system at random, and I could not hear any difference, or predict which was which at all.

    I used 192-kbps for the import quality. I wrote the song I used to do the test, so hopefully if there was going to be a difference I would have noticed. Then again, if I can't find a difference when specifically looking for one, even if there is a difference in there somewhere, it's not likely to be that noticeable.

  • Hey Dalal,

    Two possible approaches come to mind.

    Import the music as a sound

    You can import the music into the sound folder, and play it as if it were a sound, which would cause it to behave like a sound file for playback rate purposes. This also means the music would not be streamed though, so the end user would have to wait for the song to fully download before the game would start. If the song is short that shouldn't be that much of a problem, and if your distributing to desktop it's really not a problem. This is probably worth trying at least, to see if it adds an unacceptably long wait to the loading time of the game. My guess is that it won't change the loading time very much, as long as it's not a 10 minute song.

    Multiple files for each music variation

    If the music only ever has to play at the original rate and one other rate, (e.g. for a MarioKart normal-lap vs final-lap type of situation) then you could actually save a second copy of the music at the alternate rate, and include both copies in your game, switching to the alternate as needed.

    Obviously this method is not so good if you want a smooth transition of the playback rate, or a bunch of different playback rates.

  • Hey sadsack,

    In a graphic editor that can save png files, you'll want to select all pixels that match the background color, and delete them.

    Below are instructions for doing this in both Photoshop, and in Pixlr (a free online Photoshop-like editor).

    The instructions are almost identical for both programs.

    Photoshop

    In Photoshop, you can do this with the "Magic Wand" tool:

    • With the image open in Photoshop, double-click the image's layer in the layer panel to convert it from a background layer to a normal layer. (Background layers can't have transparency.)
    • Choose the Magic Wand tool, and in the options bar (top of screen), disable "contiguous" and "Anti-alias", and set "Tolerance" to "0".
    • On the image, click the background color to select all pixels matching that color.
    • Press delete to remove them. This leaves a transparent hole where they were.
    • Save the modified image as a png to preserve the transparency.

    Pixlr

    In Pixlr, you can do this with the "Wand" tool:

    • Choose the Wand tool, and in the options bar (top of screen), disable "contiguous" and "Anti-alias", and set "Tolerance" to "0".
    • On the image, click the background color to select all pixels matching that color.
    • Press delete to remove them. This leaves a transparent hole where they were.
    • Save the modified image as a png to preserve the transparency.

    Result

    Since I walked through the process in both programs to make sure I wasn't forgetting anything important, I ended up with the resulting image, which I figured I might as well include.

    [attachment=0:23rp6ggf][/attachment:23rp6ggf]

  • Good suggestion lennaert,

    I don't know if you're familiar with lerp() ThunderLion, but Lennaert is using it in his formula above to smooth out changes in the layoutScale over time.

    "lerp()" is a super handy function, which I'll try to explain a bit below. It can be found in the System's expressions in the math section, or you can just type "lerp()" in an expression.

    lerp()

    The lerp() function helps you pick numbers between a starting value and an ending value.

    So lerp() answers the following kind of question...

    Suppose you're on a road, starting at the 300 mile marker, and you're travelling to the 400 mile marker.

    Once you've travelled 50% of the way to your destination, what mile marker are you standing next to?

    Well, 50% of the way from 300 to 400, you'd be right in between them at 350.

    lerp( start , end , percentage )

    (The percentage in this case is expressed as 0 to 1, instead of 0% to 100%)

    lerp( 300 , 400 , 0.50 ) returns 350.

    Here are some examples:

    e.g. Some different percentages.

    lerp( 300 , 400 , 0.75 ) = 375

    lerp( 300 , 400 , 1.00 ) = 400

    lerp( 300 , 400 , 0.00 ) = 300

    e.g. Starting with a big number and ending at a small one.

    lerp( 400 , 300 , 0.75 ) = 325

    e.g. Some different values.

    lerp( 3 , 4 , 0.50 ) = 3.5

    lerp( -10 , 10 , 0.50 ) = 0

    lerp( -10 , 10 , 0.25 ) = -5

    lerp( -10 , 10 , 0.75 ) = 5

    e.g. Percentages outside the 0to 1 range.

    Using a percentage larger than 1.0, (i.e. larger than 100%), returns a number as if you overshot your destination and just kept travelling at the same speed.

    lerp( 300 , 400 , 1.50 ) = 450

    lerp( 300 , 400 , 2.00 ) = 500

    lerp( 300 , 400 , -0.50 ) = 250

    lerp( 300 , 400 , -0.75 ) = 225

    lerp( 300 , 400 , -1.00 ) = 200

    Using lerp() to smooth out a value over time

    In lennaert's example, he's using the lerp() function to make the layoutScale value change over time smoothly, from the value it currently is, to the value it currently should be.

    Suppose that layoutScale is currently 1, but you've moved to the corner, so it currently should be 2.

    If we want layoutScale to smoothly move from it's current value to a target value, instead of just setting it directly to the target value (not smooth), we can move it part way to the target value every tick.

    Let's move layoutScale's current value half way to the target value each tick.

    (A little fast, but it makes the example numbers easier to follow.)

    So we should expect to see the following, if we start at "1" and head for a target of "2".

    Tick 0: layoutScale = 1.00

    Tick 1: layoutScale = 1.50

    Tick 2: layoutScale = 1.75

    Tick 3: layoutScale = 1.875

    etc...

    We get closer and closer to 2 every tick.

    How can we use lerp() to do this?

    Every tick: Set layoutScale to lerp( layoutScale , 2 , 0.5 ).

    The first tick layoutScale will get set from 1 to 1.5.

    On the second tick layoutScale will get set from 1.5 to 1.75.

    etc...

    The only problem with the above lerp() is that we don't want the target to always be "2", so we can replace it with the formula that tells us what the zoom should currently be based on player position in the layout.

    Every tick: Set layoutScale to lerp( layoutScale , layoutScaleTargetValue , 0.5 ).

    If you want the approach speed to be slower you can use a smaller percentage.

    Every tick: Set layoutScale to lerp( layoutScale , layoutScaleTargetValue , 0.1).

    Frame (tick) rate independence

    So far so good, but notice that the speed we approach the target value is partly dependant on the number of ticks.

    With an approach rate of 50%, after 2 ticks we're 75% of the way to the destination. The problem is, it doesn't matter if we are playing the game at 30 ticks (frames) per second or 120 ticks per second, it always takes 2ticks.

    Imagine we use a small approach rate percentage, so that the value transition takes 60 ticks to get all the way (99.9%) to the destination, If the game runs at 60 ticks per second, the transition will take 1 second, but if the game runs at 30 ticks per second, the transition will take 2 seconds, because the transition still takes 60 ticks, and now the ticks are occurring half as often.

    What we need is a way to double the lerp()'s approach percentage, when the time between ticks doubles, (e.g. when the game slows down due to CPU load).

    We need to make the approach percentage proportional to the time between ticks.

    Fortunately, Construct gives us a variable "dt" (delta time) which gives us the time between the current tick and the last tick, in seconds, which is exactly what we need.

    So we just multiply the approach percentage by dt, to get the tick rate proportionality we're looking for.

    Every tick: Set layoutScale to lerp( layoutScale , layoutScaleTargetValue , 0.5 * dt ).

    Remember though that "dt" is tick time in seconds, so at 60 ticks per second dt will usually be about 1/60 ~= 0.0167, which is a smallish number. So you may need to compensate by adjusting the constant part of your original approach percentage, (i.e. the "0.5" in our case).

  • No problem.

  • Hey ThunderLion,

    One way you might do this is by changing the zoom level based on the player's distance from the center of the layout.

    You can get the distance between points with C2's built-in distance() function.

    e.g. Below is the distance from the center of the layout to the player:

    distance( layoutWidth / 2 , layoutHeight / 2 , Player.X , Player.Y )

    let's call this "playerDistance".

    Below is the distance from the center of the layout to a corner of the layout, (the max possible distance from the center):

    distance( 0 , 0 , layoutWidth / 2 , layoutHeight / 2 )

    let's call this "maxDistance".

    If the layout is 1000 x 1000 pixels, then the farthest you can get from the middle is 500 px at the middle of a layout edge, and about 700 px in the layout corner.

    (The 700 in this case comes from distance( 0 , 0 , 1000 , 1000 ) ~= 707 ~= 700.)

    So the maxDistance would be about 700.

    Thus, your playerDistance value is going to range from 0 (when the player is in the middle) to 700 (when the player is in the corner), roughly.

    So, if you divide your playerDistance by maxDistance, you get a result that ranges from 0 to 1. (i.e. 0/700 to 700/700)

    Lets call this "normalizedDistance".

    You can set your zoom level to 100 + ( 100 * normalizedDistance )

    With the player in the center of the layout, that expression becomes:

    zoom = 100 + ( 100 * 0 ) ... = 100 + ( 0 ) ... = 100

    With the player in the corner of the layout, that expression becomes:

    zoom = 100 + ( 100 * 1 ) ... = 100 + ( 100 ) ... = 200

    This means your zoom level will smoothly go from 100% to 200%, as the player goes from the center to the corner of the level.

    So the final formula would be:

    zoom = 100 + ( 100 * ( distance( layoutWidth / 2 , layoutHeight / 2 , Player.X , Player.Y ) / distance( 0 , 0 , layoutWidth / 2 , layoutHeight / 2 ) ) )

    Thinking of it in terms of the intermediate variables I described above, the expression evaluates as follows:

    zoom = 100 + ( 100 * ( distance( layoutWidth / 2 , layoutHeight / 2 , Player.X , Player.Y ) / distance( 0 , 0 , layoutWidth / 2 , layoutHeight / 2 ) ) )

    zoom = 100 + ( 100 * ( playerDistance / maxDistance ) )

    zoom = 100 + ( 100 * ( normalizedDistance ) )

    zoom = Some number ranging from 100 to 200 depending on the player's distance from the center of the layout.

  • Ah, I see what you mean.

    And also, thanks.

  • Try Construct 3

    Develop games in your browser. Powerful, performant & highly capable.

    Try Now Construct 3 users don't see these ads
  • I could be wrong, but I think, in C2 terms, the items that get placed on a layout are "instances" of an object type. So if you copy an instance of an object, you get another instance of that same object type.

  • Depending on the complexity of the detection you want to do, instead of using dedicated detector objects, you could try using the "Is overlapping at offset" condition. It will temporarily move your object to an offset from it's current position and test to see if it's overlapping something there, then move the object back to it's original position before any other events run.

fisholith's avatar

fisholith

Member since 8 Aug, 2009

Twitter
fisholith has 2 followers

Connect with fisholith

Trophy Case

  • 15-Year Club
  • Forum Contributor Made 100 posts in the forums
  • Regular Visitor Visited Construct.net 7 days in a row
  • RTFM Read the fabulous manual
  • Email Verified

Progress

19/44
How to earn trophies