Function params, triggers and calls

0 favourites
  • 12 posts
From the Asset Store
Game Triggers is as versatile as a Swiss army knife, and will be a great resource for any type of game you're creating.
  • I've made a function that tracks activity on different input devices (keyboard & controllers) and saves them into an array. I then take and compare the values to determine which key is down. Being a function I cannot use triggers so all values are saved on "Is button down" and then I use "Trigger once while true" to simulate "On button pressed".

    I've had a few major issues, but I managed to solve them. However, I've been banging my head the last few days trying to figure out why I cannot use the same function (with a single parameter) to track multiple objects and inputs. Even though I did it from scratch I don't quite understand how everything works so I might be talking nonsense right now so I'll try to explain it with an example.

    Here's the file: https://www.dropbox.com/s/0p9eu81286cwi ... .capx?dl=0

    Since there's a lot of event's I'll try to explain really quickly:

    • The "Controls" group is where I setup the keyboard key codes, the actual function that tracks inputs and which keys are active (there's nothing wrong with it, no need to go any further).
    • The "Players" group is where I setup a basic example (see how some events have "Trigger once"? That's to simulate the built in "On button pressed" trigger)
    • The "Connect" group is just to attach the Player function to the given objects

    To control Player 0 use A and D

    To control Player 1 use LeftArrow and RightArrow

    Now for the actual problem - if you press A a couple of times you'll see Player0 moving a few pixels to the left. If you repeat this with the LeftArrow the Player1 will do much of the same. However if you hold on A and press the LeftArrow Player1 will go left as if the "trigger once" does not exist.

    I know it has something to do with the way the Player function is designed and/or called, but I really have no clue where.

    Any ideas?

    I'm attaching an image just in case:

  • I know it has something to do with the way the Player function is designed and/or called, but I really have no clue where.

    Any ideas?

    Not really sure what the problem is. but I downloaded the Capx and is a bit confused as it must be the most complicated control setup I have ever seen

    What exactly are you trying to achieve?

    Why do you store all the activity in an array?

  • The idea is to do all this with a single function:

    1. Handle all gamepads (potentially 4x less code)

    2. Choose which buttons to be active (potentially 4x less code + save CPU)

    3. Map keyboard buttons to match all gamepads buttons

    At first I was simulating "On button pressed" directly into the "Controls" function by adding a Z-index to the "Controls" array (0 for "Is Pressed and 1 for "Is Down"), but that doubled and even tripled the CPU time so I went with a simply XY array instead.

    The activity is stored in an array so it can be easily set as condition, for example "Value at (X,Y) > 0" will mean that the button is pressed (That is the same as using the built in gamepad "Is button down" condition).

    To understand the problem run the capx and do this: "if you press A a couple of times you'll see Player0 moving a few pixels to the left. If you repeat this with the LeftArrow the Player1 will do much of the same. However if you hold on A and press the LeftArrow Player1 will go left as if the "trigger once" does not exist." This should not happen. It means that while Player0 button is pressed the function continues to return TRUE and Player1 instead of moving a pixel to the left and stopping is shooting through the screen.

  • To understand the problem run the capx and do this: "if you press A a couple of times you'll see Player0 moving a few pixels to the left. If you repeat this with the LeftArrow the Player1 will do much of the same. However if you hold on A and press the LeftArrow Player1 will go left as if the "trigger once" does not exist." This should not happen. It means that while Player0 button is pressed the function continues to return TRUE and Player1 instead of moving a pixel to the left and stopping is shooting through the screen.

    I think your have a picking problem some where, so the players get mixed up. However I can't seem to figure out where it goes wrong. Anyway you have some code in your program that doesn't really do anything.

    Function Parameter 0 = Function.Param(0) I assume this should compare towards the function "Control"? However you never return any value from this function. In case its not that function, then you might as well remove the check as it doesn't do anything.

    But overall, I would strongly consider redesigning the way you want the control system to work. The way I would do it is something like this:

    1. Make a separate event for each direction or button. So one for Left, Right, Up, Down whatever you need.

    2. Make a function for each direction/button, that requires the Player_number as input and in these function you apply the actual functionality. Like Platform.Simulate Pressing Left etc. Which is to avoid problems and confusion with function return values etc. Which aint really needed. Its a lot easier to work with simple functions that handles very specific things rather than making functions taking care of a lot of things.

    All this will be a lot less code than you currently have and doesn't require an array. My guess is that unless you need the array and to make the controls the way you are for some very specific reasons. You are causing a lot more problems for yourself than you have to and there is a big chance if you need to change it later on for whatever reason, you might run into some huge problems. Besides that redesigning it, will most likely be faster than solving the one you currently have set up, and a lot easier to maintain.

    Anyway think that the best advice I can give you.

  • Are you ACTIVATING your groups? I can see your group A, B, X, Y, etc deactivated that could cause problem

  • nimos100

    You are right. But I don't think the problem comes from the "Controls" group/function. I really don't think that it is that complicated. Just pull inputs from devices and store them in an array.

    It's the "Player" function (yes there were 2 conditions that didn't do anything - leftovers from previous testing). I think it's not comparing enough stuff and needs more conditions, that's all.

    Look at this (it's the exact same function, but Player0 and Player1 branches are split and it works just fine):

    Lordshiva1948

    Yes I am. All button groups are deactivated by default (no reason to run them all for a game that requires 3 buttons for example). On layer start I enable only the ones which are required. I don't really see how this could affect anything unless there is some kind of a bug in Construct 2?

  • nimos100

    You are right. But I don't think the problem comes from the "Controls" group/function. I really don't think that it is that complicated. Just pull inputs from devices and store them in an array.

    It's the "Player" function (yes there were 2 conditions that didn't do anything - leftovers from previous testing). I think it's not comparing enough stuff and needs more conditions, that's all.

    Look at this (it's the exact same function, but Player0 and Player1 branches are split and it works just fine):

    As I said it was just my advice to you. Of course you can make it whatever way you think is best and it will most likely end up working.

    The reason I gave you that advice is because as your project grows, you are really not interested in "complicated" solutions, you aim for the most simple, optimized solution that you can make, because it makes it so much easier to troubleshoot, add and change later on when you might not have focused on the controlling parts for a while. So you want to be able to quickly go back and read the code and quickly find out where you have to change things. As I wrote in the first post, I think you are making a very complicated solution and its even hard for you to troubleshoot it, so imagine someone having to do it, that don't know the thoughts behind it.

    Looking at the screenshot to give you an example:

    You call the function "Player" which then calls another function called Control, so I assume that you aim to add something else to this function such as Shooting etc? Because otherwise it would be better to simply call the function "Controls" directly from where you call Function Player.

    You then depending on the Player parameter (0,1,2,3) duplicate the same functionality, only difference is whether the passed parameter is (0,1,2,3). But before that you call the function "Controls" which doesn't really handle all the controls, but only part of it, the actual control is done in Function Player depending on a value in the array.

    But in each of these events (Value at (Function.Param(0),0) > 0) etc. You have the simulate behaviours. But your code doesn't make sure that for instant (Value at (Function.Param(0),0) > 0) and (Value at (Function.Param(0),20) > 0) and (Value at (Function.Param(0),21) > 0 can't all be true at the same time. So if the array screws up then the movement will bug as well.

    So what im saying is if you for instant have a function called "Player Move Left", then already at this point you know what the function does. Its doesn't handle anything else. So to make it work you just need to pass the correct Player and all of them can use the same code.

    Function Player Move Left
    Pick Platformer.Player = Function.Param(0)
    Platformer Simulate Pressing Left
    [/code:3l9nmrgh]
    
    This would be able to handle left movement for all players. So the only thing you have to do, is to add events like:
    
    [code:3l9nmrgh]
    On key press A
    Function.call("Player Move Left", <Player nr, that is linked to this control>)
    [/code:3l9nmrgh]
    
    And that would be it. No need to store anything in arrays or anything, its very easy to read the code and it does exactly what you would expect. 
    
    I can read your code, but going through all the values stored in the array, following all the function calls. Making sure that the value in array actually match what it should etc. Just take to long time that I think you are making things a lot more difficult for yourself than it needs to be, you have to troubleshoot and track so much code to figure out where it goes wrong. 
    
    Ps. You don't need a Trigger once in functions, as it will automatically only trigger once, when you call it. But anyway, its not causing the problem, its just that it makes no difference whether its there or not.
  • I agree it's a big excessive, but I've done much more complicated stuff (JS, PHP, etc) and was able to keep up with them. I haven't fully caught up with the capabilities of Construct and that's why I've so much trouble. After all I've no more than 2 weeks (combined) experience in "game making"

    Imagine this scenario with your suggestion:

    4 players assigned to a single object that differs only by instance variables have to control each one with their controller and/or keyboard. You'll need the following code:

    Function "Move Left"
    Function "Move Right"
    Function "Jump"
    
    // Function Param 0 on all of them is instance variable "Player"
    //Then you'll need to call these functions for each Player, so you either have to do it manually
    
    Get "Object" with "Player" = 0
        On Gamepad "0" Button "D-pad Left"  Pressed
            OR
        On Keyboard "A" Pressed
            -> Call function "Move Left"
        On Gamepad "0" Button "D-pad Right"  Pressed
            OR
        On Keyboard "D" Pressed
            -> Call function "Move Left"
        On Gamepad "0" Button "A"  Pressed
            OR
        On Keyboard "Space" Pressed
            -> Call function "Jump"
    
    // Then repeat 3 more times for the other players
    // Or use a Loop
    
    For each "Object"
         On Gamepad "Object.Player" Button "D-pad Left"  Pressed
            OR
        On Keyboard "A" Pressed
            -> Call function "Move Left"
    // but oh, it doesn't work...
    // First we're assigning key button A as "left" for all players, so if we really want to go with this approach we still need to use an array and call "left" by Object.Player as X and keyboard key codes as Y
    // Second and to be fair more importantly, you cannot have triggers inside a loop, so the whole idea is out the window
    [/code:wly9mfde]
    
    I think you're missing the point that every gamepad key has a key on the keyboard that mimics it. You CAN do it manually, but it will be a lot of repeating code and if something needs to be change it'd be a headache.
    
    I really need to take a break...    I'll leave everything for the weekend or even a whole week and come back to it with fresh mind later. Thanks @nimos100 for the great suggestions!
  • 4 players assigned to a single object that differs only by instance variables have to control each one with their controller and/or keyboard. You'll need the following code:

    > Function "Move Left"
    Function "Move Right"
    Function "Jump"
    
    // Function Param 0 on all of them is instance variable "Player"
    //Then you'll need to call these functions for each Player, so you either have to do it manually
    
    Get "Object" with "Player" = 0
        On Gamepad "0" Button "D-pad Left"  Pressed
            OR
        On Keyboard "A" Pressed
            -> Call function "Move Left"
        On Gamepad "0" Button "D-pad Right"  Pressed
            OR
        On Keyboard "D" Pressed
            -> Call function "Move Left"
        On Gamepad "0" Button "A"  Pressed
            OR
        On Keyboard "Space" Pressed
            -> Call function "Jump"
    
    // Then repeat 3 more times for the other players
    // Or use a Loop
    
    For each "Object"
         On Gamepad "Object.Player" Button "D-pad Left"  Pressed
            OR
        On Keyboard "A" Pressed
            -> Call function "Move Left"
    // but oh, it doesn't work...
    // First we're assigning key button A as "left" for all players, so if we really want to go with this approach we still need to use an array and call "left" by Object.Player as X and keyboard key codes as Y
    // Second and to be fair more importantly, you cannot have triggers inside a loop, so the whole idea is out the window
    [/code:1hxotwd5]
    
    I think you're missing the point that every gamepad key has a key on the keyboard that mimics it. You CAN do it manually, but it will be a lot of repeating code and if something needs to be change it'd be a headache.
    
    I really need to take a break...    I'll leave everything for the weekend or even a whole week and come back to it with fresh mind later. Thanks @nimos100 for the great suggestions!
    

    Im not sure I fully understand the issue. Because does it matter which player is using which device? If I understand you correct. There are 4 players in total, 2 players are using the keyboard and 2 are using gamepads?

    But since the keyboard and the gamepads use different inputs, i don't really see what the problem is. You make a control set for each of them, sort of like you have done already. Controller 1 to 4.

    Group Controller 1 and 2 will always be keyboard

    Group controller 3 and 4 will always be gamepads

    But whether a player presses A on the keyboard to move left or a gamepad they use the same action right?

    But you are correct that you will need 4 groups for the controlling of the players to figure out which type of input is getting used. That being keyboard or one of the gamepads. But you will only have to set this up once. All the functions etc can be reused. But you already have this in your current design so why is that any different?

    [quote:1hxotwd5]First we're assigning key button A as "left" for all players

    This confuses me a bit, all players can't push the same button at once or what do you mean?

  • You don't want to use trigger once in a loop or function. Trigger once makes the event only run if it didn't run last tick. If you use it in an event that runs more than once in the same tick then it has weird results.

    Say you start pressing D and right together on tick count 10. The function is called for the first player. It checks if that last tick that the trigger once ran was tick count 9 and if not then the event runs and it updates the last tick count to the current tick count (= 10).

    Then the function is called again for the next player. Again it checks if this event last ran on tick count 9 which it didn't because it last ran on tick count 10 and so it runs for the second player as well. So on tick count 10 you press D and right and both players move to the right.

    On the next tick (tick count 11), the function is called for the first player and it checks if the last tick count was 10, which it was, so it doesn't run again for player 1 and player 1 doesn't move. The last tick count is updated to 11. Then the function is called for player 2 and it checks if the last tick count was 10, which it isn't any more so the event runs and player 2 moves to the right.

    And so on. Player 1 moves to the right only on the first tick and player 2 keeps moving every tick which is the behaviour that you see.

  • Try Construct 3

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

    Try Now Construct 3 users don't see these ads
  • nimos100 That's not quite how it works. 4 players can be:

    4 on gamepad 0 on keyboard

    3 on gamepad 1 on keyboard

    2 on gamepad 2 on keyboard

    1 on gamepad 3 on keyboard

    0 on gamepad 4 on keyboard

    That said, it is not always practical, but it's a possibility.

    Then the other plus is that you can assign Player to Movement functions. Imagine a title screen where you choose a character. Some characters move up and down, others move left and right. With my setup you can tell how a character moves with the Controls function and then assign a Player (e.g. gamepad index) to it. So with one controller you can be either one character.

    ramones thank you very much for clearing this out for me. Now that I know I can't use Trigger once in functions, I'll look for another way to simulate the "On Pressed" condition.

    I've something in mind and I'll test it tomorrow to see if it works and post it here.

  • Alright, I figured it out!

    Since "Trigger once" is actually triggered every tick, that means that it is incapable of memorizing whether a button has been pressed or not. However an array can remember that

    So I've created another array called "Active" that is pretty much the same as "Controls":

    "Controls"

    • A cell is 0 by default
    • When a button is pressed it becomes 1
    • When it's released the cell becomes 0 again

    "Active"

    • A cell is 0 by default
    • When a button is pressed it becomes 1
    • When it's released the cell becomes 0 again

    Now I can actually compare both:

    Controls - Active - State

    0 - 0 - no button pressed (default)

    1 - 0 - button is pressed, but could also be down

    1 - 1 - button is definitely down (pressed will not trigger again)

    0 - 1 - button is released (pressed has been reset)

    So the script goes like this:

    if(controls[0,0] != 0) {
        if(active[0,0] == 0) {
            // do something like move left
            active[0,0] = 1;
        }
    } else {
        active[0,0] = 0;
    }
    [/code:1jn16bma]
    
    An example image:
    [img="https://40.media.tumblr.com/3dd749d159c2d5647112712db649abae/tumblr_nvcb5yj4ji1tbcgxno1_1280.jpg"]
    
    Now I'm 95% positive I can merge "Controls" and "Active" arrays into one and shove the logic directly into the "Controls" function itself which will simplify things by a whole lot.
Jump to:
Active Users
There are 1 visitors browsing this topic (0 users and 1 guests)