Announcement

Collapse
No announcement yet.

Elevator Style Character Movement (Should I even be trying to use Lerp?)

Collapse
X
 
  • Filter
  • Time
  • Show
Clear All
new posts

    Elevator Style Character Movement (Should I even be trying to use Lerp?)

    So I'm trying to build a simple prototype combat system to learn how to use UE4 and get a couple of ideas out of my head and into the real world. Eventually it will be this:




    The idea would be to have the player character locked to those tiles and have button presses move between those tiles precisely. So far I've managed to detach the player's view from the character, build an array of those tiles to reference and find the position of the guy, and set up a button press system to move him between those points on the array.

    When I try and hook that into a timeline and lerp setup he drifts to an arbitrary point in space rather than move to the next point in the array.

    My worry at this point is that I might be trying to implement a system that's intended for 3D space or a player character when something else would be more correct and effective. Is a lerp even the right idea for what I'm trying to do?


    Here's what I had built that was functional before I started hacking in the timeline/lerp nodes:



    Attached Files

    #2
    Hey there Stinkhorse. Great name! I also really love the way you arrange your nodes, it's very pleasing to look at. Compact and legible.

    Ok, here's the nitty-gritty. First, you should probably move your logic out of your Level Blueprint and into your Player Character's blueprint. This is because Level blueprints can't communicate through interfaces, can't turn off their ticks, or ever be culled. It's more performant to split up your functionality across specialized instanced Blueprints because you can turn off Ticks when you don't need them.

    Lerping Timelines are a great way to go. I don't know how you had them set up before, but the general idea is to have a timeline that iterates from 0 to 1 over 1 second, then you divide the return value of that by the number of seconds you want the motion to take (so you don't have to have multiple timelines, just one that does it all) and plug that into the alpha on your Lerp function. Depending on wher your Camera is, you'll want to cancel out one plane of motion. Generally in 2D, this means the X vector. Just make sure X is 0 (if your camera is facing down the X vector) and Y and Z can be whatever you want.

    For your A and B on the lerp, you'll want to take your player's position before playing the timeline for A, not his current position because that will keep moving the goalposts for the Lerp. B would be the final destination. Then just call "Set Actor Location" every Update from the Timeline and you should be golden.

    Alternatively you can use iTween (free, in signature) to handle this motion for you, where you just tell it what you're moving, from where (current location) and to where (final destination) and how many seconds it should take with an optional easing equation to smooth out the motion and that's it.

    If you're still having problems, if you can post a screenshot of the current problematic Blueprint or even better take a video of the action, I can better help.
    Procedural, modular, on-the-fly animation - iTween For UE4
    - Actors - Components - UMG - Ease In - Ease Out - Path-constrained Animation - $0

    Runtime Datatable
    -All the fun of DataTables dynamically loaded from text or Google Sheets while your game is running!

    Comment


      #3
      Oh awesome, thanks for the run down Jared! Let me get a test case built up and I'll let you know what happens.

      Comment


        #4
        Hoooo boy. I am a four year old with a power drill and a boat hull, I swear to god.

        I turned my sprite player character into a class blueprint, transferred over all the scripts, and rebuilt the associated variables locally. I also did the same for the tile object, turning it into a class, and then instanced it across the level believing that it would make it easier to reference to create an array. It's around this point that things started going really sideways. I attempted to get an array of the tiles based on their tags (which was conveniently set to 'tile') inside the player character's class blueprint, and while that didn't spit back an error it clearly didn't work because nothing happened on button press. So I figured that the tags simply aren't reading, but I didn't know how to be sure of that without checking to make sure the script itself worked, so I decoupled all the dynamic array stuff and tried to rebuild it by hand with sprite actor references. At this point I realized I can't reference the tiles, either as a blueprint class or components or their base assets. I can't create reference the player character asset in it's own blueprint. I've attempted to remake the array using most of the methods I've been able to look up and nothing seems to be working. I have a node that seems to reference things but then it tells me it has no reference on compile.

        I don't know where or when my tile array should be built, or at this point even how to. I don't know how to get my classes to talk to one another and half of them have been deleted in an attempt to regain access to dropping sprite references into my blueprints. I'm getting pretty close to scuttling this whole dumb thing and rebuilding it from scratch but that's honestly not going to help me learn anything in the long run.

        I'd throw up some screen shots but honestly very little has changed other than it's all parted out into class blueprints that refuse to talk to one another.

        Any help would be REALLY appreciated at this point.

        Comment


          #5
          Ok! A lot going on here. Let me just throw some pointers at you.

          -You can reference the player character in its own blueprint by searching "this" or "self" in the context browser.
          -There's a node called "Get All Actors of Class" that will return an array of actors of the specified class. You can get the tiles and then plug the return value into a local array. No tags needed! After getting the array, you may want to run a foreach loop on it that gets teh display name of each tile and prints it so you know your array is good.

          What base class are you using for your player? Pawn, Actor, Character? If you're using Actor, reparent (File->Reparent blueprint) the character blueprint to use Pawn or Character since they're built to take input. In the class defaults, make sure it's listening for input from Player 0 and NOT blocking input.
          Procedural, modular, on-the-fly animation - iTween For UE4
          - Actors - Components - UMG - Ease In - Ease Out - Path-constrained Animation - $0

          Runtime Datatable
          -All the fun of DataTables dynamically loaded from text or Google Sheets while your game is running!

          Comment


            #6
            Man thank you so much for the help Jared! I'm one of those people who learns best by dialogue, so even these few replies have gotten me ahead of what would have been weeks of bumping into answers in the dark.

            I'll be able to sit down Teusday evening and try some of this stuff out so I'll let you know then, in the meantime here's an image from the wiki that shows a likely example of what I was misunderstanding:



            That node that has both "target" and "sparks" looks like what I was attempting to use to call something from another blueprint. When I moused over the "target+thing" node it pulled up a tooltip that contained the location of the blueprint that the information was being pulled from, and it's target was labeled "self", so I thought I should leave it alone as it logically (to me; an idiot) was already referring to the blueprint it was pulling from. I also didn't know at that point that you could turn other blueprints into variables to reference as targets, so that'll probably be my first attempt at a fix.

            As for the character, it's a pawn currently, but the camera isn't focused on it and player controller aren't being cast to it. He was moving without the addition of a player controller, but I'm guessing that was because his controls were in the level blueprint itself? If that's the case, and he does needs some sort of player controller, how do I keep the camera detached from his movement? I eventually want the camera to be independent of the player, but casually rubberbanded to an average between his position and that of the single enemy he'll be fighting.

            The actors of class should be doable now that I know how to create variable references to other objects. I kept trying to find the class using the drop down menu under the purple pin, and then using the tag option to filter, but that obviously wasn't working correctly.

            Honestly looking back over yesterday I've got a lot to feel accomplished about. I'm getting comfortable creating referenceable blueprint classes and instancing them as objects now, busting out a variable isn't the big concern it used to be, and before I caught your post I was in the process of repurposing the constructor script from the content example levels to dynamically build out the stage based on an integer. And lastly, thanks to your help I'm right on the cusp of understanding how to get blueprints to talk to one another, which is going to be super powerful going forward!

            I also checked out your plug in, and it's definitely going into my toolbox, but I think I'd like to learn how to do it the long way around first just so I have the general concepts down. Important bits like referencing a single curve and altering it with some math on the spot are just things that I wouldn't have thought of, but clearly leverage the engine's strengths. That sort of thing.

            Once again, huge thanks, and if anything I've got up there sounds suspicious or alarming, let me know and I'll correct my implementation to match!

            Comment


              #7
              Sounds like you're getting a handle on it, that's great!

              The only thing I can pick out of your post for now that I wanna touch upon is the Player Controller. Unreal unfortunately has a lot of esoteric concepts that aren't made readily apparent what their use is. Let me try to run it down for you.

              Game Instance - an object that is persistent throughout the life of the game; that is to say that it is never destroyed until the game is quit, unlike other pieces I'll touch on. Generally this is used to hold together multiplayer games as the maps load and things of that nature. I like to use it in single-player games for variables that I'll always need to see so I don't have to keep loading and saving to a SaveGame object. I also like to put a StateMachine enum variable in here that shows what "state" the game is in, i.e. Main Menu, cutscene, in game, etc.
              Game Mode - An object that acts as the master of the current level's Player Controller, Player Pawn, Game State, Player State, etc. The docs say this is used for the "rules" of the game, but I use it to spawn objects and hold references to my important objects so if I need my player, I just get my Game Mode and Get my Player Pawn reference variable.
              Player Controller - is generally used to receive input then send instructions from that input to an appropriate pawn. This is completely optional to use, but is a good idea to use if you want to use the Player Camera Manager (which I honestly never have) or switch pawns during gameplay (which I do with some frequency).
              Pawn - you can put all of the input logic on this if you'd like. Some games work that way just as well. I personally recommend splitting input between the PC listening for instructions and sending a message to the pawn to carry out those instructions. For example, the PC hears the player tilt the thumbstick. It says, okay, if input is enabled and we're using the human pawn, we'll send a message to the human pawn to move forward. If we're using the turret pawn, we'll send a message to the turret to rotate upward. Again, you can just put the input on the pawn if you want, the PC just makes it easier to manage multiple pawns and share variables.
              Game State - this is used for networking as I understand it, and I've not had much experience with Unreal's online infrastructure yet so I don't have much to share. Sorry!
              Player State - If I understand correctly, this shares some info from the Game State but is used locally on each client in a networked game. Again, no experience here

              So right now it looks like you have a camera actor in the scene that is independent of the pawn anyway. If you're calling Set Target View with Blend or whatever it's called when the game starts, you're overriding the Player Camera Manager's auto-camera already, so you're golden whether you decide to use a Player Controller or not. Then it's just a matter of moving the camera appropriately when you need to which can be one with a boolean, VInterp or iTween, and an event to fire off that camera change event.
              Procedural, modular, on-the-fly animation - iTween For UE4
              - Actors - Components - UMG - Ease In - Ease Out - Path-constrained Animation - $0

              Runtime Datatable
              -All the fun of DataTables dynamically loaded from text or Google Sheets while your game is running!

              Comment


                #8
                YES! All of that info is exactly what I've been needing! I've been casting around for a notion of a global variable, and it looks like it's the location that it's built in that really decides that rather than it being an enshrined concept in it's own right.

                I'm going to use what little free time I have this evening to get the class blueprints rebuilt and look into a quick test bed for casting an input. On that note, the descriptions describing casting are a little unclear and I'm not super certain if a cast node:
                A) Sends information to the named blueprint where a listening node needs to be set up to catch it
                or
                B) Reaches out to make a link with another blueprint and then creates a conduit to it allowing further nodes to make and set variables that exist in that now linked blueprint.

                Comment


                  #9
                  Global variables don't really exist in Blueprints, but there are global objects that can hold variables. Your Game Instance is great for that, but your Game Mode can work too if you're fine with saving and loading those variables to and from a Save Game object throughout the game rather than just at the beginning.

                  As far as casting goes, some object references will be of a more base class (like actor) but you need a child class' stuff (like character's movement component).

                  So say you have a box that checks for collisions with other actors. When a collision happens, it'll fire off an event and give you a reference to the "other actor" that collided with it.

                  While Character inherits from Pawn which inherits from Actor (I assume you know about class inheritance as a programming concept), not all Actors are Characters or Pawns. Likewise, your custom Hero class that inherits from Character is a Character, Pawn, and Actor, but not every Actor is a Hero.

                  So you'd cast this other actor to a Hero blueprint. The impure Cast node (the one with execution pins) will ask the other actor if it is a Hero, and if it is the node will treat the other actor as a Hero (with all of its specific variables and functions) instead of as just an Actor (which doesn't have any of the functions or variables of Pawn, Character, or Hero).

                  In this case, let's say you want your Hero to be damaged when he enters a box volume. Your Hero has a custom function called "ApplyDamage()" on it that will decrease his health when it's called. The box will check for collisions every frame, and every time it senses a collision it will fire off its collision event. It will pass the actor that it collided with as well, so on that event you would cast that other actor to a Hero. If the cast is successful, then that means your box collided with the Hero and you can drag out from the cast node "As Hero" and call ApplyDamage() from that.
                  Last edited by Jared Therriault; 04-07-2015, 01:38 AM.
                  Procedural, modular, on-the-fly animation - iTween For UE4
                  - Actors - Components - UMG - Ease In - Ease Out - Path-constrained Animation - $0

                  Runtime Datatable
                  -All the fun of DataTables dynamically loaded from text or Google Sheets while your game is running!

                  Comment


                    #10
                    I spent a few years in game development as a designer, enough to pick up some terminology, but never enough to be trusted with anything significantly dangerous. I'm basically leaning on every overheard conversation from that time as hard as I can, so while I might be able to leap to what you're saying before I finish reading a paragraph it would safer to presume I'm just as entry level as every other schlub that picked up a free editor.

                    While I wasn't able to get everything to work, I did get my class blueprints rebuilt and a few scripts moved from their previous homes. Here's what I built tonight. None of it seems to work, but on the bright side it compiles again.

                    Level Blueprint



                    Player Controller Blueprint
                    That print screen script is so not even slightly the way it's supposed to be, but I couldn't find anything that broke down how to pull and convert information from an array for display, so it was all guess work.



                    Debtor Blueprint - Begin Play



                    Debtor Blueprint - Press Right



                    Debtor Blueprint - Press Left (w/Timeline Test)



                    Editor View
                    Throwing this in for good measure just in case something glaring pops up anywhere.

                    Comment


                      #11
                      Oh, and I've run into an issue where sometimes an array's output wont plug into a node of a given type, but if I delete the various objects and recreate them, suddenly everything plugs in, fine and dandy.

                      It's got me working on a solid "four lights" twitch.

                      Comment


                        #12
                        Alrighty, let's break it down per blueprint. I've got a few questions on each and a few edits on each! I'm gonna critique you like I critique my students because that's the only way I know how, so I hope I don't come across as condescending or insulting. Without further ado, let's do it.

                        Level BP - Why do you set the player character's location to be the player character's current location? I mean, on Event Begin Play it really won't hurt anything but I'm curious if there's something I'm missing as this doesn't really do anything to change the game. Additionally, what do you use the "Delta Seconds" float variable for? Do you have any other logic on your level bp? If not, you can delete that portion of the blueprint since the variable will only be visible by the level bp itself and it's doing this every Tick, so you're throwing unnecessary overhead into the works. The only thing I'd keep personally is the Set View Target with Blend node because it's easier to reference a Camera Actor from the level bp but even then it could easily be done in the Player Controller. As you can tell I'm not a fan of level blueprints

                        (Side note on level blueprints, when I first started with Unreal I used the level bp a lot too. It worked out great for a while until of course I wanted to change maps. Then I either had to recreate all of the variables in the new level bp because copy and paste only copies the nodes, not any variables or functions, or move everything out of the level bp and into a class blueprint. Now I just avoid the level bp whenever possible and use it only for temporary stuff like spawning a widget or something until I have all of my ducks in a row. Perhaps I'm just a jilted ex-boyfriend about them but I'd strongly recommend against using them. /rant)

                        Player Controller - So the reason your foreach loop isn't working here is because the loop only keeps the object in memory during the loop body. When it's completed, it doesn't pass an array element. Every UObject (the base class from which all actors and Widgets inherit from) has a function called "Get Display Name." What you'd want to do is execute print string every loop body and Get Display Name from the array element, plugging the return value from that into the print string node.
                        Click image for larger version

Name:	Capture.PNG
Views:	1
Size:	49.3 KB
ID:	1072078

                        Debtor BP Begin Play - Like your level bp, you're setting your pawn's position to be its current position. There may be a reason for this, but I just don't know. Instead of using the variable you created for "debtor" you can just use "Get a reference to self" to ensure that you'll always be referencing the debtor and won't end up with a broken reference. I say this because there doesn't seem to be anywhere that you tell the engine what the debtor is. Lastly, you make a Current Tile Array twice, once in the Player Controller and once here. You only really need one and you can reference it from the other blueprint. It probably won't hurt performance much to have two arrays with the same information, but it does take up unnecessary memory. I think the pawn works better than the player controller for that since the Player Controller never references the current tile while the pawn references it a lot, so you can save yourself the overhead of Get Player Controller->Cast to My Player Controller->Get Current Tile Array.

                        I would have begin play be like this (this pic is missing the part where you populate the current tile array; this should come after that):
                        Click image for larger version

Name:	Capture.PNG
Views:	1
Size:	109.5 KB
ID:	1072080
                        Just set the tile index you want to start with (which this assumes to be 2 on every level) then set your debtor's location to be the location of the tile plus your pawn's Z box extent. The box extent is the distance from the center of the actor to the very top of it, or its half-height. You can open up structs (a vector is a struct of three floats) by right-clicking on a struct pin and choosing "Split Struct Pin." I do it this way in case you ever need to change your pawn in the future. It may never happen, but it's better to be prepared for any contingency, in my opinion.

                        Debtor Press Right - Unless you will have no more than 7 tiles in any given scene, you should make the branch check more like this:
                        Click image for larger version

Name:	Capture.PNG
Views:	1
Size:	34.5 KB
ID:	1072082
                        So now it will check how many tiles there are in the scene, subtract 1 (because arrays are 0-based) and will only then move if the current index is less than the last index.

                        You can also use the "Last Index" property on the array which is the same as Length - 1, I just didn't think of it when I took the screenshot. It isn't a thing in most programming languages, it's just a nice blueprint feature.

                        Debtor Press Left - This looks great! The only thing that jumps out at me is that you're setting the current tile index to be itself +1 every time the Timeline updates, so depending on your frame rate you could end up with a current tile index of over 60 after a second.

                        Debtor Both Presses - This stuff applies to both press left and press right. You should increment the current tile index right after checking the branch. This way you are sure to do it only once and you won't have to add or subtract from the current tile when you're getting the tile's location. Also the do once macro isn't really needed if you're resetting it when the key is released. Pressing a key down only fires once for each time you do it; it isn't continuous. Do once is great if you have to do some logic on Tick or something but you only want to run it one time or if you only want a button press to trigger something one time, not multiple times.

                        As for your other post, I'm not sure exactly what the problem is without seeing it. Can you post a screenshot of the error tooltip you get when you hover the pin over the other pin?

                        A few ideas that come to mind that may or may not apply: Arrays can not plug into single pins, only array pins; use a get node if it's a single pin. Alternatively, if you have an array pin already plugged into another array input pin, cut the connection, then try to plug in another array it will not work because it's still listening for that particular array. You'll have to recreate the nodes in that situation.
                        Last edited by Jared Therriault; 04-07-2015, 11:06 AM.
                        Procedural, modular, on-the-fly animation - iTween For UE4
                        - Actors - Components - UMG - Ease In - Ease Out - Path-constrained Animation - $0

                        Runtime Datatable
                        -All the fun of DataTables dynamically loaded from text or Google Sheets while your game is running!

                        Comment


                          #13
                          I accidentally voted this thread as a 1 star when I was aiming for 5, sorry about that. This is a really good read, I appreciate both of your inputs on this topic.

                          Unpopular Minion on the Play Store (Released: January 31, 2016)

                          Comment


                            #14
                            Originally posted by Distul View Post
                            I accidentally voted this thread as a 1 star when I was aiming for 5, sorry about that. This is a really good read, I appreciate both of your inputs on this topic.
                            Lol I was wondering what the heck that 1 star was about
                            Procedural, modular, on-the-fly animation - iTween For UE4
                            - Actors - Components - UMG - Ease In - Ease Out - Path-constrained Animation - $0

                            Runtime Datatable
                            -All the fun of DataTables dynamically loaded from text or Google Sheets while your game is running!

                            Comment


                              #15
                              Originally posted by Distul View Post
                              I accidentally voted this thread as a 1 star when I was aiming for 5, sorry about that. This is a really good read, I appreciate both of your inputs on this topic.
                              Haha oh man, No it's cool Distul, I am definetly one star material but thank you for any stars you might give!
                              If anyone else ever benefits from my bumbling at the kindergarten level that would be a consolation.

                              Comment

                              Working...
                              X