fisholith's Recent Forum Activity

  • Hi all,

    Is there a way to give a playing sound multiple tags?

    tl;dr (preemptively) - C2 doesn't support this as far as I can tell, and I have a partial solution but its got issues, so I figured it was worth asking.

    Goal:

    I'm looking to create a tag system for audio, such that when I play a sound, I can add multiple tags to that sound, allowing later access to all currently playing sounds that share a given tag, like "ambiance" or "water".

    Problem:

    Presently the C2 Audio object allows you to specify a "tag" when playing a sound, but you can only provide a single string. And you can only lookup playing sounds by matching that exact string. So I couldn't, for instance, get a list of all playing sounds with tags containing the substring "ambiance" or "water".

    Why I'm interested:

    There are a few reasons.

    More flexible interaction with sounds:

    I would like to be able to access a playing sound by either its exact name ("footStep03"), or by its sample-set name ("footStep"), or by its category ("player"). Likewise, it would be nice to be able to trigger "On ended" events in response to sounds with specific tags.

    More flexible Menu control over sounds:

    I'd like to be able to make an audio menu with volume sliders for different categories of sound, for instance "Music", "Voice", "Ambience", "Sound effects", and "User interface". In particular, for sounds that are currently playing, like any actively looping ambience, adjusting the slider in the menu would need to affect the sounds while they were playing, rather than "next time" they get played.

    My current partial solution:

    So far I've got something that sort of works, but with some ugly side effects.

    I'm using a custom "playSound" function I created via the function object. The function will play a sound and tag it with a unique numeric ID, that increments with each call. At the same time, a key with that same ID will be added to a dictionary, and the associated value will be a comma separated list of the tag strings I want to attach to that sound.

    This allows me to access playing sounds by looping through the dictionary and searching for specific tag strings in the values. Each value is tokenized (comma delimited) into individual tag strings. Because each key links back to a single unique sound, this system can map an arbitrary number of tag strings to individual playing sounds.

    Removal issue:

    There is a problem, though. I can't trigger the removal of a sound entry from the dictionary when the sounds stops playing. The reason is that there is no way to use the "On ended" event generically, as C2 requires you to name the exact tag of the sound that is ending. I would need to check to see if *any* sound is ending, and then remove the ending sound's dictionary entry in response. (You can do this kind of generic detection with the Keyboard object, and the Gamepad object, but not the Audio object.)

    System Wait:

    I can't quite use System Wait with the duration of the sound as the wait time, because System Wait is slaved to the timescale, so I could get weird behavior whenever the game was paused.

    Timeout dictionary:

    I could potentially save the expected end time in a 2nd timeout dictionary, and every few seconds loop through it to see if any entry's time is up. Basically periodic garbage collection. Though that seems a bit ugly, and might cause a periodic performance hit. Maybe not, I don't know.

    "On ended" inside a loop:

    One weird possibility that might work, depending on how C2 handles loops and triggered events, is to create a "For Each Key" loop and then use that to check every key (sound ID) in the "On ended" event, every tick. I don't think that should work if the "On ended" event is a true triggered event, but if it's a "fake" triggered event (as described in the C2 plugin SDK documentation) then it might. Even if it does, that doesn't sound very efficient.

    Suggest feature:

    I could suggest multiple tags for audio as a feature. I think it would be pretty handy, but I have no idea if interest would be wide spread enough to make it a worthwhile implementation.

    Mod Audio object:

    This is what I looking into now. Building a modified version of the Audio plugin. The downside is that my modified version would not get updated with the rest of C2, and that would probably become a bigger and bigger problem as time goes on.

    If you got this far, I appreciate you taking your time to read through this, sorry about the length.

    Thanks in advance for any replies, and any suggestions are welcome.

  • No problem,

    As for sharing to social media, I'm not sure off hand. You might be able to do something like that by adding one of the "Platform Specific" objects to your project. I believe Construct 2 has a Facebook object and a Twitter object, and either of those might have the functionality you're looking for.

  • Hey uzet1,

    If the entire game environment fits inside the game window:

    You could use the action System > "Snapshot canvas".

    If the environment is larger than the game window:

    You could zoom out until it fits, and then snapshot it, though this won't give you a 1-to-1 resolution image of your world, but it might be a nice way to create a map.

    Alternatively, you might be able to use the 3rd party Canvas object. I've never used it, but if you can make it as large as the world, and then paste the world into it, you might be able to save the Canvas as an image. Again, I've never used it so I don't know if you can.

    You may not be able to paste things off-screen into the Canvas, but you might be able to solve this by scrolling the screen chunk-by-chunk across the world pasting as you go.

  • Hey Prazon,

    Hopefully I'm interpreting this right, it sounds like there are 14 different selectable characters in the game, and you have a generalized character rig setup that has a spot for the selected character in the middle, and then 4 boxes situated around the character, representing attack zones to the left, right, top, and bottom of the character.

    You want a control input, like Towards + C, to trigger a unique action depending on the chosen character.

    Two options come to mind, global variables is one, and a callback function system is the other. The global variable method is easier but a little less flexible, though it should still work just fine in this case.

    Global variables:

    You can use a global variable to store the name of the character chosen by the player, and only trigger that character's attack if their name is found in the global.

    e.g.

    * Event: If keyboard pressed Left + C.

    * * SubEvent: If global characterName = "lulu". -- Action: Call function "luluShield".

    * * SubEvent: If global characterName = "veigar". -- Action: Call function "veigarStun".

    * * SubEvent: If global characterName = "teemo". -- Action: Call function "teemoSelfDestruct".

    Callback functions:

    You can create a Dictionary object, that maps control input events (Dictionary keys) to function names (Dictionary values). At the point that a player selects a character, you can populate the Dictionary with the chosen character's functions. These functions will execute the character's actions.

    e.g.

    * Event: Player chooses "lulu".

    Actions:

    Add to Dictionary key = "Left+C", value = "luluShield" .

    Add to Dictionary key = "Right+C", value = "luluSpeedUp".

    etc ...

    * Event: If keyboard pressed Left + C. -- Action: Call function ( Dictionary.getValue( "Left+C" ) ).

    Note: Dictionary.getValue( "Left+C" ) will return "luluShield", which we added earlier, and so the action evaluates to [Call function ( "luluShield" ).]

    * Event: On function "luluShield". -- Action: Execute the stuff that's supposed to happen when Lulu uses her shield ability.

    Hope that helps.

  • Hey iac249,

    You could try breaking the doorway into 2 parts, with the near side and top in the foreground, and the far side and bottom in the background, as shown in the image below. By "foreground" and "background" I simply mean Z order relative to the character.

    [attachment=0:3epux70b][/attachment:3epux70b]

  • Hey AeleaS,

    Two possibilities come to mind that might work.

    To set the angle of the arrow, you can either use the "Set angle towards position" action, or you can just use the "Set angle" action and as the parameter use a handy built in system expression in Construct2 called angle() which will get the angle between two points.

    e.g.

    • angle( 0 , 0 , 100 , 100) = 45
    • angle( Obj.X , Obj.Y , Mouse.X , Mouse.Y ) = The angle of a line from Obj to Mouse.

    Fixed length arrow - (uses one sprite)

    1. Create a sprite arrow pointing right (0 degrees).

    2. Place the hotspot at the tail of the arrow. (This should be the middle of the left edge of the image.)

    3. Set the arrow sprite to the position of the billiard ball (or whatever you're interacting with), and set the angle of the arrow to the angle you want.

    e.g. Below I'll assume we want the arrow to go from a billiard ball to the mouse cursor.

    Event:

    * Every Tick.

    Actions:

    * Set Arrow to position of BilliardBall.

    * Set Arrow angle to look at coord ( Mouse.X , Mouse.Y ).

    Resizable length arrow - (uses two sprites)

    To create an arrow that can change length, you can create the arrow in two parts.

    1. Create the tail, by making a simple 4x4 pixel block filled with a solid color.

    2. Place the hotspot at the left center edge of this sprite.

    3. Create an image point named "headAttachPoint" at the right center edge.

    4. Now create a new sprite that looks like an arrow head pointing right, and place the hotspot at the left edge.

    5. Put the Arrow tail and arrow head sprites in a Construct2 "container".

    6. In the event editor add the following events:

    e.g. Below I'll assume we want the arrow to go from a billiard ball to the mouse cursor.

    Event:

    * Every Tick.

    Actions:

    * Set ArrowTail to position of BilliardBall.

    * Set ArrowTail angle to look at coord ( Mouse.X , Mouse.Y ).

    * Set ArrowTail width to distance( Self.X , Self.Y , Mouse.X , Mouse.Y ) // This sets the arrow length.

    * Set ArrowHead to position of ArrowTail, at image point "headAttachPoint".

    * Set ArrowHead angle to ArrowTail angle.

    Hope that helps out.

  • You can also use the "distance(x1,y1,x2,y2)" expression in a condition to verify that the touch is a certain distance from the character, as it sounds like you are also interested in triggering the effect only when close enough to the character.

  • Hey RenatoB,

    There are quite a few ways to do this, so I'll give a simple example, that will hopefully be a good starting point. But more complex setups are certainly possible.

    Body:

    1. Create a Sprit object for your character.

    2. In the image editor, create an image for your character, but leave the eye area blank (i.e. skin colored).

    3.Still in the image editor for the character's body, click the "Image point" button on the left-hand toolbar. (Second from bottom, and looks like a crosshair.)

    You should get an extra side window titled "Image points".

    4. In the "Image points" window, add two image points, named "eyeLeft" and "eyeRight". Select the "eyeLeft" image point and click on your character image, to place the image point where the left eye should go. Do the same for the "eyeRight" image point.

    Eyes:

    5. Create a Sprit object to act as an eye. The eye will be a white circle, with a black pupil circle, however the pupil circle will be positioned to the right of center, as if the eye is looking to the right.

    6. For the eye Sprite object, add an text instance variable named "attachPoint". (We will use this variable to name the image point that the eye is supposed to attach to.)

    7. Make a copy of the eye Sprite, so you have two eyes.

    8. For one of the eyes, set its "attachPoint" variable to "eyeLeft" (without quotes)

    9. For the other eye, set its "attachPoint" variable to "eyeRight" (without quotes)

    Positioning eyes:

    10. Open the event editor, and add the following event:

    Event:

    * Every tick.

    Actions:

    * Eye: Set Eye position to position of Character, at image point Eye.attachPoint.

    Explanation: For each Eye, we are setting the Eye to be positioned on the Character, at one of the Character's 2 image points. We get the name of the appropriate image point from the Eye's "attachPoint" instance variable, the one we made earlier. So, the Eye with the attachPoint variable set to "eyeLeft" will attach to the Character's "eyeLeft" image point. Same idea for the other Eye and "eyeRight".

    You can try running the game at this point to make sure the eyes are getting positioned correctly.

    Aiming eyes:

    11. add the following event:

    Event:

    * Every tick.

    Actions:

    * Eye: Set Eye angle to look at position, <whatever position you want them to look at>.

    Hope that helps.

  • No problem, happy to help.

    Okay, I think what is happening is that you actually are successfully deleting an array item, right before you jump to a new layout, but when the next layout starts, that new layout is running the "On start of layout" events (lines 17 & 18 in your image), and that is re-clearing and re-filling the array.

    I'll refer to the process of clearing and then filling the array as "initializing" the array.

    You'll need a way of initializing the array only once during the whole game.

    Two solutions come to mind.

    Solution 1: You could initialize the array on a unique layout that only runs once, like the title screen of the game.

    Solution 2: You could keep the initialization on start of layout, (the way you have it now), and add a global variable to disable initialization after the first time the array is initialized.

    Solution 2 - explained:

    To disable initialization after the first time the array gets initialized, you can create a global number variable "gb_initLayoutArray", with a starting value of 1.

    As the last step of the initialization process, set "gb_initLayoutArray" to 0.

    Finally, in the "On start of layout" events, add the condition, "gb_initLayoutArray" = 1.

    Now those "On start of layout" events should only run once.

    And if you ever need to initialize the array again later, just set the "gb_initLayoutArray" back to 1, and on the next layout you'll restart with a full "deck" of layout cards in your array again.

    (The "gb_" in the variable name is just my way of indicating that a variable is global "g", and should be treated like a Boolean "b". It doesn't mean anything special to Construct.)

    Let me know if that fixes it.

  • Hey andreyin.

    If I'm not mistaken, dt is the amount of time (in seconds) that has passed since the last tick. So, if your game runs at 60 frames (ticks) per second, then dt will always be a value around 0.0166 (i.e. 1/60). It may fluctuate a little, if you get some lag between frames.

    So every tick, lerp( 0 , 30 , 3 * dt ) evaluates to approximately ...

    = lerp( 0 , 30 , 3 * 0.0166 )

    = lerp( 0 , 30 , 0.0498 )

    = 1.494

    So if 1.494 looks like it could be the value you were getting, then that may be the issue.

    To get gradual changes in a value, you can use two variables, a Target variable that stores the desired target value, and a Follower variable that continually computes a time-smoothed version of the Target's value. The Follower variable essentially just gradually approaches the value stored in the Target variable.

    I actually just posted an explanation of this Target/Follower setup with a list of events in another topic.

    The example I give there shows a linear follower setup, but I generally use multiplicative follower setups in my projects, since the follower can be set every tick with only one event.

    (Some day ... some day I will get that 4th egg.)

  • Hey Leaufai,

    The following might do what you're looking for.

    In your layout, place a layer above all your other layers.

    Add the "Adjust HSL Mask" effect to this layer. (You can click the layer in the layer panel and edit it's properties in the properties panel.)

    Set the layer's "Transparent" property to "No".

    You should now be able to post-process the entire game with the "Adjust HSL Mask" effect.

    To smoothly fade in an fade out the effect, create two number variables.

    "targetSatValue"

    "followSatValue"

    We'll use these to control the effect's saturation parameter.

    In this example, I'll use functions as the triggers for starting and stopping the desaturation effect, but you could use anything you want.

    * On function "desatOn": Set "targetSatValue" to 100.

    * On function "desatOff": Set "targetSatValue" to 0.

    * Every tick, if followSatValue < targetSatValue: Add 1 to "followSatValue".

    * Every tick, if followSatValue > targetSatValue: Subtract 1 from "followSatValue".

    * Every tick: Set "Adjust HSL Mask" param 1 (the saturation) to "followSatValue".

    (Actions in italics.)

    When the function "desatOn" is called, the targetSatValue is set to 100, and the followSatValue will begin gradually counting up to the target. When the targetSatValue is set to 0, then followSatValue will count back down to the new target value.

    Hope that helps.

  • Try Construct 3

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

    Try Now Construct 3 users don't see these ads
  • No problem. Glad it worked out.

fisholith's avatar

fisholith

Member since 8 Aug, 2009

Twitter
fisholith has 1 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