How to control NPC animation from GUI button click (Unreal) - unreal-blueprint

I have a number of animation sequences connected to an ENUM Blend Pose node. I can manually switch this enum value in the Anim Preview panel.
Now I wish to control this enum value from a bunch of buttons added to a User Widget. The widget is instantiated within the Level BP.
When I edit the onClick events on the buttons, I do not know how to get a reference to my enum variable (which I have exposed as Public in the Anim Blueprint's settings).
Essentially, each button is designed to change this variable to a unique value, which then should cause the appropriate animation to play within the Blend Pose.
How do I let the Widget have access to that variable? Or vice versa, how could I create a variable on the blueprint that can be used to set the Enum value on the Blend Pose?
Please note that I am using the visual blueprint editor, not C++ at this time.

I am coming from a 100% C++ background, so I may have some options on my mind that are not entirely working in BP, but we'll get to that.
I would not use the level blueprint at all for anything. Instead use your GameMode or GameState for spawning the UserWiget. The GameMode and GameState are accessible via the GetGameMode node. Keep in mind that in multiplayer scenarios, only the GameState is available to all while the GameMode can only be accessed by the host or dedicated server, but that is probably irrelevant for you.
After spawning the widget assign it to a public variable of its type, so you can get it from the outside.
In your actor (not animation blueprint) you can access the GameMode easily using the GetGameMode node. You have to cast it to your specific GameMode to get to the variable of the widget. For the GameState use GetGameState.
Now you have multiple options to connect everything together. You could for example pass your actor to the UI and store it as a variable there. The UI can then simply call a custom function like "SetAnimationState" that you create on the actor for each button. Your actor can pass the enum value down to the animation blueprint. Using your skeletal meshes GetAnimInstance node.
This is one simple way I can think of. You could also work with an event dispatcher that broadcasts whenever a button is pressed and your actor is subscribed to it to get notified.
I hope any of this helps.

Building on #MaxPlay's answer, here's my final (possibly sub-optimal) solution with images for posterity. I'll probably stumble upon this answer in a few years like I do with some of my other SO posts from years ago ;)
First, the Anim BP on my Actor (note that this is not the player's pawn but just another mesh in the world) which just sets up the Blend Poses, using an Enum.
It's really vitally important here to make sure the variable that holds the Enum is made public. You do that by clicking the eye icon next to the variable name. If you don't do this, no external class (blueprint) gets to read or set the value of that variable.
This is a screen grab of the variables portion of the Anim BP's properties panel.
And here's that Enum, which you can create as a blueprint. I've used it to have a nice textual reference that has semantic meaning. Also makes it easier to link to the buttons later.
Now we get into the heart of the matter - the Actor Blueprint. I just wrapped this blueprint around my Skeletal Mesh Asset by selecting it in the viewport and then using the Blueprint menu to convert it.
In the image below you can see the Details panel of that Actor Blueprint, showing how it composes the Anim BP
Next is the magic step!
I created a function on the Actor Blueprint that other blueprints can call with 1 parameter - the ENUM that I defined earlier. The goal of this function is as a public setter on the Anim BP's public variable. I wasn't able to expose this public variable outside the hierarchy, so this gets around that visibility issue by delegating the responsibility for setting the Anim BP's variable to its Actor BP.
Since the Actor Blueprint has a reference internally to its Skeletal Mesh's currently assigned animation blueprint, and that Anim BP's variable has been made public, it gets to set it directly.
The goal is to pass a reference to this Actor BP to the Widget so the Widget's buttons can call this method (function) at a later time.
Over on the Widget side, I'm exposing a variable, cast as that specific animation blueprint (so that the Widget knows about the SetAnimFromEnum method). I'll be setting that variable in a moment.
Before I do, here's how the Widget Blueprint is set up - very simply, each button calls the same SetAnimFromEnum() method and just passes a different value from the enum.
If you had a million buttons, this would not be efficient and you might want to invest in a bit more complex blueprinting (I'm not yet at that level) - ideas here are to somehow parse the name / label of the button and derive the appropriate enum from it, or revert to an integer-based Blend Pose node and add a property to each button, etc.
And finally, the glue that holds it all together: the Actor Blueprint that instantiates the widget. This is the part I don't like in my solution - in my mind, the widget shouldn't be so tightly coupled (composed) with the Actor BP. But I would have had to jump through more hoops if using the Global GameMode or GameState Blueprints, and this is just a proof-of-concept so I'm keeping it simple, if slightly messy.
The Animation Blueprint below shows me instantiating the Widget and using the return value to both add it to the Viewport, as well as then accessing the widget's public variable designed to hold a reference to this Actor Blueprint and setting it. That creates the link between these two blueprints allowing the Widget to then call a method on the Actor.

Related

Godot: How to disable/overwrite inherited function?

I am trying to come up with an efficient way to organize clickable menus for the objects in my game. I made a Menu class, from which all possible menus inherit:
class_name Menu extends Control
#contains functions (for buttons) that all menus have in common
func open_menu():
pass
func close_menu():
pass
To make a menu specific to buildings, I inherit all functionalities from the Menu class:
class_name BuildingMenu extends Menu
# contains functions specific to all buildings
func upgrade_building():
pass
func delete_building():
pass
# ... many more ...
Now here's the problem: My HQ is literally just another building with a few extras and the main difference that it can't be deleted, so I'm thinking of inheriting from BuildingMenu. Is there a way to disable the inherited delete_building() function in the HQMenu script?
class_name HQMenu extends BuildingMenu
func delete_building():
# overwriting inherited function like this does not work...
# ... some HQ specific stuff here ...
I could just inherit from Menu and then copy paste everything from BuildingMenu except the delete_building() method, but this seems somewhat clumsy because now I have to edit two files if I want to change/add any building functions.
What is the correct way to do this?
SOLUTION:
Thanks to the suggestion by Thearot I've decided to move the delete_building() function into a new class from which all the regular (non HQ) buildings inherit:
Now here's the problem: My HQ is literally just another building with a few extras and the main difference that it can't be deleted, so I'm thinking of inheriting from BuildingMenu. Is there a way to disable the inherited delete_building() function in the HQMenu script?
This sounds like a violation of Liskov Substitution Principle. From a purely object oriented point of view, it would be preferible to make another class for a subset of buildings with what they have in common, than to have one building inherit from another if it has to disable some methods.
If your base class for all buildings implies that some buildings have to disable some methods, then it does not really have the methods common for all building, it has some extra ones.
To be clear, here I'm suggesting to add another extra intermediary class, and that way you don't have to delete nor duplicate methods.
If that is not an option for you… Congratulations! you have made a mess system complex enough that some kind of component based system begins to make sense. But don't jump the line, don't fret, it is OK.
If I understand correctly you have some contextual menus that show different options depending on what is selected or what you click on, right?
That means that the options are variable. Thus, use a variable. Add an Array field that has the names of the methods that should be linked to the menu. Then have the menu system discover the options by reading that Array, and connecting to functions with the names specified there.
And how you do add or remove options? You add them or remove them form the Array. Simple. You can populate the Array in _init.
To be clear, you can check if an object has a method with has_method. You call a method by name with call, or - of course - you could connect signals to them with connect (if prefer to populate an static menu for the object instead of having a dynamic one). Yes, I'm suggesting late binding.

as3 how can i prevent that a new instance is created by entering a frame?

i am working with several nested movieclip objects in a project. but i get into trouble with the buttons i created and implemented in the nested movieclips:
to describe it in a simple way:
I have a main movieclip with five frames, including two buttons with listeners to browse between the frames. Then inside of one Frame I have another movieclip with its own buttons. i instanciated it by hand not through code and gave it a specific name like "nestedMc".
Now I dont want to build the Listeners for those buttons inside the class of the nested movieclip class but in its parent class, which works fine until i then goto another frame in the main movieclips timeline and come back.
obviously every time flash enters a frame its contents get created anew (and therefore get new instance names). I could now try solve this through filling the frames via code.
But maybe there is another way to make sure the frame contains the same instance everytime i enter?
Timeline scripting is a dirty business, and really, a carry-over compatibility layer for Actionscript 2 projects. Whenever possible, I highly recommend not doing it, and simply keeping all of your code in your document class. As you're experiencing, timeline code causes headaches.
Consider instead just creating both states of your Stage (it sounds like that's what your two buttons are jumping between) and simply hiding them offstage or setting their alpha to zero and their mouseEnabled state to false. Furthermore, if the purpose of your frames is to play animation (a tween), consider instead switching to a much more powerful suite such as TweenLite. Moving an object over a hundred pixels (smoothly) can be as easy as:
TweenLite.to(redBall, 3, {x:100});
Now, if you're manually adding these items to the stage, as long as the object is a dynamic one, you can assign an instance name to it which will be saved between frame loads. Be aware the object name is not the same as the instanced name. For example:
var redBall:Ball = new Ball();
redBall.name = "bubbles";
The object's name is Ball, but it's represented as a variable called redBall. Its actual DisplayList name will likely be ambiguous (such as "Instance71"), and I can manually define it as "bubbles". 3 different names for the same object, all very different and necessary.
Even if you give the object a displayList name, you may not be able to reference it through code unless you enable Automatically declare stage instances, which basically creates on each object a pointer to the displayList object.
That said, you can always fetch the object by other means. Obviously, your buttons are always appearing, but you're trying to find a very specific object on the stage. At this point, we can use getChildByName() or getChildAt().
Hope that helps.
-Cheers

AS3 How to communicate between frames

I have been writing a game in timeline code. I want the different frames (rooms) in the game to be able to share information between each other. Of course, timeline code is limited to the frame it is written in.
After doing quite a bit of reading ("Foundation Game Design with Flash" and a number of articles, tutorials, forums etc) I decided to employ a document class. This did not work either. It seems it only works for frame one but not the rest of the frames (I have four).
How can I have frame four respond to something that happpened in frame one? For example, if the player achieves something in frame one, I want a movie clip in frame four to be visible.
If You are writing your code on the timeline, My suggestion would be to create two layers in the timeline, one for 'frame-actions' - in this layer you insert the code specific to a single frame (will work when the movieclip is stopped on that particular frame).. And also create one more layer called global-actions (for the entire timeline). Only the first frame will be a key frame and there should be empty frames till the end of the timeline.
In this layer actions write the code that you want to access from any keyframe in the same timeline.
If you define a variable in the actions which are written for the whole timeline (global-actions) then that will be available on all the frames.
Now if you want to go to a different frame based on some action, just write some functions in the layer which contains global actions and call that particular function through the frame actions. To go to a different frame use the 'gotoAndStop(frameNumber)' function of flash.
I want to tell you that while it will work, I would not recommend using it in this way.
HTH.
You can use static variables - these are variables which are linked to a class, rather than an instance of it.
Suppose your document class was called Document.as, and you wanted a variable, playerLives, to be visible from any part of the program.
Declare it inside Document.as:
public static var playerLives:int = 3;
You can then reference this directly from anywhere else in your code with:
Document.playerLives
(note that the variable is a member of the class itself, not an instance of it).
You could use a dedicated Statics class to hold these variables if you want to keep your document neat, or attach them to the relevant classes (eg Player.lives)
I've not used timeline/frames for some years but I believe this is how I used to do it!
NB Statics will be fine for your purposes but they are, in some ways, an equivalent to the _global variable in AS2 (at least, they can be used in the same manner) - many would not approve of their use, or over-use, as they are freely accessible from anywhere in your program (thus anathema to the OO concept of encapsulation), but personally I try not to worry about it in small cases - the most important thing to know about the rules of any design pattern is when they can be broken!
They are also slightly slower to access than instance members, but you won't notice this unless you are constantly accessing/changing them (making things like player velocity, which will need to be referenced/changed every frame, static, is not a good idea).
Hope this helps.
You may find the simplest way to link everything with the document class is to move your four frames into a movieclip together and have that on the first frame, then interact with that movieclip.
E.g. in the document class, where the movieclip instance on the timeline is called 'game'.
game.gotoAndStop(4);
game.objectToDisplay.visible = true;
If you encounter reference errors in the IDE then you can avoid these by using [] notation to refer to the properties of game, e.g. game["objectToDisplay"].visible = true;
Note that it's not really best practice to do this, but it will at least help you to finish that first game which is really more important at this stage in your learning. Afterwards, if you want to learn more then I'd recommend "The Essential Guide to Flash Games" by Jeff Fulton from 8bitrocket.com - it will teach you how to use the document class effectively.

use class to handle mutiple nested movieclips and their specific events

I have a menu with five buttons. Menu is visible all the time. there is click event for each menu item. which slides corresponding movie clip from left to right. each movie clip has different nature events and respective animation and activity. for example tab 1 brings the video page. and within that movie clip I have video events like play pause volume and on complete etc. events and code. tab 2 has button group for Time and another button group Features. depending on user selection code will calculate and show value on a animated counter. tab 3 has button group for Time and button group Source. as per the user selection it will calculate and show the values as animated graph. and so on.
Right now I have all the individual tab movie clip has its own time line code for its own events. and some crossover variables and references with other tabs. Everything is working as expected. No problem. I know time line code is not the best way to do any complex project.
So, I would like to get the entire coding as one class or more classes if that is the correct way.
I am beginner as far as class logic. I have already created Main as document class and could control the general navigation of tabs and their initial look. But stuck at tab specific button events and other such unique events for the specific tab.
Any help is greatly appreciated. Thanks in advance.
any similar example or suggestions.
First of all, thanks a lot for a prompt response. It seems like I am not even a beginner. I need to read a lot and probalbly grasp all fundamental concepts thoroughly. I have gone through both the links suggested in your comments. I am trying to digest the stuff slowly. I do not have any formal informal education regarding OOP or any sort of programming. To be honest, I have hard time understanding the code you have suggeted. Not because of your code but because of my level of caliber. I will have to spend some time to make myself clearer regarding events and sequence etc. different tab contents are as movieclips to main timeline and already placed on stage. It comes and goes to its corresponding tab button click event. I am not marking your answer as yes because I still need to my own homework based on your suggestion. Thanks a lot once again. I am sure I will ask few more questions later.
This is how I would design it:
I'd have a Menu Class, which only contains the buttons and "converts" clicks on them into more specific events. That might look something like this:
public Class Menu extends Sprite {
protected var buttons:Vector. = new Vector.();
public function Menu() {
super();
var loops:int = numChildren;
for (var i:int=0; i<loops; i++) {
var button:SimpleButton = getChildAt(i) as SimpleButton;
if (button) {
buttons[buttons.length] = button;
button.addEventListener(MouseEvent.CLICK, broadcastMenuEvent);
}
}
}
public function broadcastMenuEvent(e:Event):void {
var button:DisplayObject = e.currentTarget as DisplayObject;
dispatchEvent(new Event(button.name, true));//bubbling, can catch at any level
}
}
The way this is built, you can change the events that are being dispatched simply by changing the name you give the instance of the button on stage. Note that you need to apply Menu as the Base Class and not the Class for this to work if you have "declare instances automatically" unchecked, because doing it that way allows the compiler to generate those instance names for you in a way your base Class doesn't have to know about.
At this point, you can then deal with those events in another place--whether it's your main document Class or whether you have a separate Controller.
I would define each of the Views you described as a separate Class as well. If you have objects coming and going on the stage, you can use one of the techniques described here to handle that. Otherwise, it's fairly straightforward to address your timeline instances from the base Class instead of timeline code. Again, you can listen for those events in the main document Class or a dedicated Controller--the main point is to make sure your Views are not making any important decisions and usually they should not be editing data.
You can choose to have your Main Document orchestrate how the tabs get added and removed (I'm a big fan of using the timeline with goToAndStop, but not everyone shares this preference), or, again, you can separate this logic out to a dedicated Controller. I would suggest that if it's possible to generalize how your Views work to have them implement a single Interface. That way, you can give them a single instance name and manage them all with the same getter/setter pair (assuming you go the timeline route).
Note the Flash compiler isn't terribly sophisticated in this regard, so if you do this and your Views extend different parent Classes, you'll get compiler warnings. Just ignore these--they don't mean anything.
The thing you shoud try to root out of your code completely is the part where Views are referencing each other. The only time it's acceptable for one View to know about another is when it's a parent knowing about its child. Even then, try to have as little specific knowledge as possible. Notice in the Menu View I wrote as an example, the parent only knows there may be some SimpleButtons, but it has no specific knowledge of where they are on stage, what, specifically, is in them, or even what there instance names are.
Instead of having your Views know about one another, have a third party (which, again, you can choose to use the main Document Class for or not) that transfers requests for state changes (in the form of events) from one to another.

How to updating JLayeredPane while the JFrame is running ? java

Having read many tutorials, articles and questions, I am still have confusions about updating the GUI. Plus there are numerous related questions here on this website and still no luck - even though I think my problem is very simple.
Basically, I have a JFrame that has a JLayeredPane as its root container. And I have some layers of JPanels inside it.
The main issue is with updating a particular JPanel in this JLayeredPane. And for this particular Panel, I have implemented an update method that changes the contents inside it.
updatePanel(int para)
//doesn't remove this panel
//removes some existing labels and replaces it with new ones
Once I create the whole Frame, obviously just calling this method won't show any change displayed the frame.
private void static main (String[] args){
WindowFrame frame = new WindowFrame()//WindowFrame extends JFrame
frame.updatePanel(2);
.....
.....
}
And that's where I am stuck. I want to update the contents as the frame is displayed.
I saw these methods mentioned by people but due to nature of problems, I couldn't fully grasped the concepts. Plus the documentation on these methods isn't really helping - at least to me.
revalidate()
validate()
repaint()
How/when should these methods should be called? Or is this not the right way of what I should be doing, given these methods and the problem I am trying to solve?
Thank you for your time.
Basically you need two methods:
revalidate()
This method does the same as invalidate() but in AWT event dispatching thread (i will just call it Swing thread later on)). It updates container and all of its ancestors (parent containers in which this one is placed) layouting.
Basically if you either move something inside this container or place/remove components inside of it you should call this method (or invalidate in case you are performing it in Swing thread, for example inside any Mouse/Action listener body or just inside).
repaint()
This method forces component, all its sub-components (if it has them) and parent container (basically if this component is NOT opaque) to update what they are "painting".
Usually you don't need this method since all standard Swing components know when to repaint themselves and they do it on their own (that ofcourse depends on components UIs and some other things). This method might be useful in case you have your own specific components with some unique painting-way (for e.g. some custom selection over the components) and in some rare problematic cases with standard components.
Also the way this method acts depends on the components placement (due to some Swing painting optimizations) - if you have some massive repaints rolling you'd better optimize them to repaint only those parts (rects) that you actually need to repaint. For example if you change the component bounds inside any container the best choice is either to repaint its old bounds rect and new bounds rect OR repaint rect that contains both of those bounds, but not the whole container to avoid repainting uninvolved in the action components.
So, basically in your case after some changes with panels you should call revalidate on their container (or invalidate) followed by repaint (in case revalidate leaves some visual artefacts) again for the container.
Guess i didn't miss anything and i hope that now you know the basic meaning of those methods.
revalidate at the end of your update method like so .
updatePanel(int para){
.....
.....
this.revalidate(); //of course this refer to the panel
parent.revalidate(); // parent refer to the window
}