I'm trying to draw the line via button.
public void paintComponent(Graphics g)
{
super.paintComponent(g);
g2 = (Graphics2D) g;
g2.setColor(Color.BLACK);
g2.setStroke(new BasicStroke(2));
for (int i=0;i<18;i++)
{
g2.draw(new Line2D.Double(2+i*20, 0, 2+i*20, 260));
g2.draw(new Line2D.Double(0, 2+i*20, 360, 2+i*20));
}
g2.setColor(Color.RED);
}
public void drawDiagonallyLineDownLeft()
{
int newXCoord=xDrawCoord+20;
int newYCoord=yDrawCoord+20;
g2.drawLine(xDrawCoord, yDrawCoord, newXCoord, newYCoord);
xDrawCoord=newXCoord;
yDrawCoord=newYCoord;
repaint();
}
The drawDiagonallyLineDownLeft method paints Line. I tried to use it in constructor and it works ok.
Here is listener of JButton
public void actionPerformed(ActionEvent arg0)
{
panel.drawDiagonallyLineDownLeft();
panel.revalidate();
panel.repaint();
}
It also works ok. I printed message in Console in method, at it was printed ok. But there is no line, when I press the button. I think, that I should refresh it somehow, I used all methods I know, but it still doesn't works.
When you call repaint all drawing are erased, you have to paint in the method paintComponent(Graphics g)
paintComponent(Graphics g) is called automatically in some cases (window resize ect.)
Related
I've been working on converting some blueprint logic over to C++. One of the things I have is a button. The button can be pressed in VR and has a delegate that is called to notify any registered functions that the button press occurred. Here is how the delegate is declared in the AButtonItem.h class.
#pragma once
#include "BaseItem.h"
#include "ButtonItem.generated.h"
DECLARE_DYNAMIC_MULTICAST_DELEGATE(FButtonItemPressedSignatrue);
UCLASS()
class AButtonItem : public ABaseItem
{
GENERATED_BODY()
protected:
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = Touch)
float myMaxButtonPress;
public:
UPROPERTY(EditAnywhere, Category = Callback)
FButtonItemPressedSignatrue ButtonItem_OnPressed;
};
The delegate's broadcast function is then being called when the button is pressed like so:
ButtonItem_OnPressed.Broadcast();
(This function should defiantly be called because I have a debug statement that prints right before the call. Its also important to note this was all working when it was blueprint logic.)
Here is where I try to register with the delegate and how I declared the function that will be called:
WeaponMaker.h:
UFUNCTION()
void OnNextBladeButtonPressed();
WeaponMaker.cpp:
void AWeaponMaker::BeginPlay()
{
Super::BeginPlay();
TArray<USceneComponent*> weaponMakerComponents;
this->GetRootComponent()->GetChildrenComponents(true, weaponMakerComponents);
for (int componentIndex = 0; componentIndex < weaponMakerComponents.Num(); componentIndex++)
{
if (weaponMakerComponents[componentIndex]->GetName().Equals("NextBladeButton") == true)
{
myNextBladeButton = (AButtonItem*)weaponMakerComponents[componentIndex];
break;
}
}
if (myNextBladeButton != NULL)
{
myNextBladeButton->ButtonItem_OnPressed.AddDynamic(this, &AWeaponMaker::OnNextBladeButtonPressed);
}
}
I put a breakpoint and a print statement in the function OnNextBladeButtonPressed so I should immediately know when it works but its never happening. I also re-created the blueprint itself from scratch but still no luck. Sometimes on compile I get a crash due to the InvocationList being invalid but I haven't found much info on that issue either. Bottom line is, OnNextBladeButtonPressed is not getting called when it should be.
Edit: Here is where I call the broadcast function in my AButtonItem code. It seems to be getting called since i see the UE_LOG output in the console:
void AButtonItem::Tick(float deltaTime)
{
FTransform buttonWorldTransform;
FVector buttonLocalSpacePos;
FVector ownerLocalSpacePos;
FVector localDiff;
float buttonPressAmount;
if (myHasStarted == true)
{
Super::Tick(deltaTime);
if (myButtonComponent != NULL)
{
if (myPrimaryHand != NULL)
{
//Get the world space location of the button.
buttonWorldTransform = myButtonComponent->GetComponentTransform();
//Convert the location of the button and the location of the hand to local space.
buttonLocalSpacePos = buttonWorldTransform.InverseTransformPosition(myInitialOverlapPosition);
ownerLocalSpacePos = buttonWorldTransform.InverseTransformPosition(myPrimaryHand->GetControllerLocation() + (myPrimaryHand->GetControllerRotation().Vector() * myPrimaryHand->GetReachDistance()));
//Vector distance between button and hand in local space.
localDiff = ownerLocalSpacePos - buttonLocalSpacePos;
//Only interested in the z value difference.
buttonPressAmount = FMath::Clamp(FMath::Abs(localDiff.Z), 0.0f, myMaxButtonPress);
localDiff.Set(0.0f, 0.0f, buttonPressAmount);
//Set the new relative position of button based on the hand and the start button position.
myButtonComponent->SetRelativeLocation(myButtonInitialPosition - localDiff);
//UE_LOG(LogTemp, Error, TEXT("buttonPressAmount:%f"), buttonPressAmount);
if (buttonPressAmount >= myMaxButtonPress)
{
if (myHasBeenTouchedOnce == false)
{
//Fire button pressed delegate
if (ButtonItem_OnPressed.IsBound() == true)
{
ButtonItem_OnPressed.Broadcast();
AsyncTask(ENamedThreads::GameThread, [=]()
{
ButtonItem_OnPressed.Broadcast();
});
}
myHasBeenTouchedOnce = true;
myButtonComponent->SetScalarParameterValueOnMaterials("State", 1.0f);
Super::VibrateTouchingHands(EVibrationType::VE_TOUCH);
}
}
}
else
{
//Slowly reset the button position back to the initial position when not being touched.
FVector newPosition = FMath::VInterpTo(myButtonComponent->GetRelativeTransform().GetLocation(), myButtonInitialPosition, deltaTime, 10.0f);
myButtonComponent->SetRelativeLocation(newPosition);
}
}
}
}
First of all:
UPROPERTY(EditAnywhere, Category = Callback)
FButtonItemPressedSignatrue ButtonItem_OnPressed;
This should be:
UPROPERTY(BlueprintAssignable, Category = Callback)
FButtonItemPressedSignatrue ButtonItem_OnPressed;
For convenience.
Secondly the tick function may be called before begin play is executed for a number of reasons. Your even't won't be broadcasted if the game hasn't begin play yet. So to avoid just add a check in your tick function.
if(bHasBegunPlay)
{
// .. your logics ...
}
Sometimes on compile I get a crash due to the InvocationList being invalid but I haven't found much info on that issue either. Bottom line is, OnNextBladeButtonPressed is not getting called when it should be.
I don't see any issue in the code from the question. At my glance, the issue could be in different location. I would suspect that AWeaponMaker had been deleted at moment of broadcasting.
I'm working on a new project and an implementing a basic scene change. I have the different scenes setup as their own classes, with the intialisation function being used to create and reposition different SFML objects. I saw this answer and have written my scene switcher similarly:
// Create scene monitoring variable
int scene[2];
scene[0] = 0; // Set current scene to menu
scene[1] = 0; // Set scene change to no
...
// Check for scene change
if(scene[1] == 0) {
// Run tick function based on current scene
switch(scene[0]) {
case 0:
// Main menu - run tick function
menu.tick();
}
}
if(scene[1] == 1) {
// Reset scene that you've changed to
switch(scene[0]) {
case 0:
// Main menu - reset it
menu = Menu(window, scene); // <-- Reinitialise menu here
}
// Set change variable to 0
scene[1] = 0;
}
You can see the full code on the github repository.
However, this doesn't seem to work properly - as soon as a scene change is made, the screen goes blank. The class is reintialised (I added a cout to check), the draw function is still run and mouse clicks are still processed, yet nothing appears in the window.
Am I doing something wrong here?
Doing things that way can lead into leak memory errors. I suggest you a different approach: the StateStack
How this works?
The basics of having a StateStack object is store each possible state of your game/app into a stack. This way, you can process each one in the stack order.
What is an State?
An State is something that can be updated, drawn and handle events. We can make an interface or an abstract class to make our screens behave like a State.
Which are the advantages?
With a stack structure, you can easily control how your different scenes are going to handle the three different processing methods. For instance. If you have a mouse click while you're in a pause menu, you won't that click event to reach the menu state or the "game" state. To achieve this, the solution is really easy, simply return false in your handleEvent method if you don't want the event go further this particular state. Note that this idea is also expandable to draw or update methods. In your pause menu, you won't update your "game" state. In your "game" state you won't draw tour menu state.
Example
With this points in mind, this is one possible way of implementation. First, the State interface:
class State{
public:
virtual bool update() = 0;
virtual bool draw(sf::RenderTarget& target) const = 0;
// We will use a vector instead a stack because we can iterate vectors (for drawing, update, etc)
virtual bool handleEvent(sf::Event e, std::vector<State*> &stack) = 0;
};
Following this interface we can have a example MenuState and PauseState:
MenuState
class MenuState : public State{
public:
MenuState(){
m_count = 0;
m_font.loadFromFile("Roboto-Regular.ttf");
m_text.setFont(m_font);
m_text.setString("MenuState: " + std::to_string(m_count));
m_text.setPosition(10, 10);
m_text.setFillColor(sf::Color::White);
}
virtual bool update() {
m_count++;
m_text.setString("MenuState: " + std::to_string(m_count));
return true;
}
virtual bool draw(sf::RenderTarget &target) const{
target.draw(m_text);
return true;
}
virtual bool handleEvent(sf::Event e, std::vector<State*> &stack){
if (e.type == sf::Event::KeyPressed){
if (e.key.code == sf::Keyboard::P){
stack.push_back(new PauseState());
return true;
}
}
return true;
}
private:
sf::Font m_font;
sf::Text m_text;
unsigned int m_count;
};
PauseState
class PauseState : public State{
public:
PauseState(){
sf::Font f;
m_font.loadFromFile("Roboto-Regular.ttf");
m_text.setFont(m_font);
m_text.setString("PauseState");
m_text.setPosition(10, 10);
m_text.setFillColor(sf::Color::White);
}
virtual bool update() {
// By returning false, we prevent States UNDER Pause to update too
return false;
}
virtual bool draw(sf::RenderTarget &target) const{
target.draw(m_text);
// By returning false, we prevent States UNDER Pause to draw too
return false;
}
virtual bool handleEvent(sf::Event e, std::vector<State*> &stack){
if (e.type == sf::Event::KeyPressed){
if (e.key.code == sf::Keyboard::Escape){
stack.pop_back();
return true;
}
}
return false;
}
private:
sf::Font m_font;
sf::Text m_text;
};
By the way, while I was doing this, I notice that you must have the fonts as an attribute of the class in order to keep the reference. If not, when your text is drawn, its font is lost ant then it fails. Another way to face this is using a resource holder, which is much more efficient and robust.
Said this, our main will look like:
Main
int main() {
// Create window object
sf::RenderWindow window(sf::VideoMode(720, 720), "OpenTMS");
// Set window frame rate
window.setFramerateLimit(60);
std::vector<State*> stack;
// Create menu
stack.push_back(new MenuState());
// Main window loops
while (window.isOpen()) {
// Create events object
sf::Event event;
// Loop through events
while (window.pollEvent(event)) {
// Close window
if (event.type == sf::Event::Closed) {
window.close();
}
handleEventStack(event, stack);
}
updateStack(stack);
// Clear window
window.clear(sf::Color::Black);
drawStack(window, stack);
// Display window contents
window.display();
}
return 0;
}
The stack functions are simple for-loop but, with the detail that iterate the vector backwards. This is the way to imitate that stack behavior, starting from top (size-1 index) and ending at 0.
Stack functions
void handleEventStack(sf::Event e, std::vector<State*> &stack){
for (int i = stack.size()-1; i >=0; --i){
if (!stack[i]->handleEvent(e, stack)){
break;
}
}
}
void updateStack(std::vector<State*> &stack){
for (int i = stack.size() - 1; i >= 0; --i){
if (!stack[i]->update()){
break;
}
}
}
void drawStack(sf::RenderTarget &target, std::vector<State*> &stack){
for (int i = stack.size() - 1; i >= 0; --i){
if (!stack[i]->draw(target)){
break;
}
}
}
You can learn more about StateStacks and gamedev in general with this book
In my current LWJGL application I am using the GLFW window input handler which I have set up a class to handle called Keyboard.java which extends GLFWKeyCallback. I have correctly set up my keyboard input class but when I click on a key if i do not click if fast enough (very quickly) then it registers as multiple clicks. I have presented some documentation below:
Keyboard Class
public class Keyboard extends GLFWKeyCallback {
//Variables
public static boolean keys[] = new boolean[65536];
#Override
public void invoke(long window, int key, int scancode, int action, int mods) {
keys[key] = action == GLFW_PRESS;
}
}
Implementation
public static void handleInput() {
if (Keyboard.keys[GLFW_KEY_SPACE]) {
System.out.println("Space");
glfwPollEvents();
}
}
The above method is implemented in the main game loop and is called once a frame.
Result
Initialised LWJGL Version: 3.1.2 build 29
Space
Space
Space
Space
The above: "Space" should be outputted every time that I click space but when I click it relatively fast, Then i get the above result of many "spaces".
Conclusion: Is it possible for a click of space to be registered only once no matter how long you hold it. Thanks
In your handleInput() function, you are testing to see if Keyboard.keys[GLFW_KEY_SPACE] is true, and if it is, you execute the statement. The problem is that this test only becomes false when you stop hitting space, which could take seconds to happen.
My suggestion: once you tested for Keyboard.keys[GLFW_KEY_SPACE], make it false.
public static void handleInput() {
if (Keyboard.keys[GLFW_KEY_SPACE]) {
Keyboard.keys[GLFW_KEY_SPACE] = false;
System.out.println("Space");
glfwPollEvents();
}
}
I am fairly new to Cocos2d-x v3 and Recently I was attempting to use the listener key press functionality in order to get my Sprite to move with the animations I have created for it. All the code Compiles with no error, but when the game runs if I press the specified Key in the switch case the window is suspend and it brings me to the action.h header file and highlights the "void setTarget" method of the class where it states error "this was a nullptr" perhaps I forgot to initialize a variable somewhere?
My header looks like so:
#ifndef __HELLOWORLD_SCENE_H__
#define __HELLOWORLD_SCENE_H__
#include "cocos2d.h"
using namespace cocos2d;
class HelloWorld : public cocos2d::Layer
{
private:
Sprite* sarah;
Animate* walking;
Action* action;
public:
static cocos2d::Scene* createScene();
virtual bool init();
void menuCloseCallback(cocos2d::Ref* pSender);
CREATE_FUNC(HelloWorld);
void onKeyPressed(EventKeyboard::KeyCode keyCode, Event *eventer);
void onKeyReleased(EventKeyboard::KeyCode keyCode, Event *eventer);
Sprite* GetSprite();
Animate* GetAnimation();
}
#endif // __HELLOWORLD_SCENE_H__
and the part in my cpp that is causing me problems looks like so:
void HelloWorld::onKeyPressed(EventKeyboard::KeyCode keyCode, Event * event){
auto action1 = event->getCurrentTarget()->getActionByTag(1);
auto node = event->getCurrentTarget();
switch (keyCode){
case EventKeyboard::KeyCode::KEY_LEFT_ARROW:
action1->setTarget(node);
node->runAction(action1);
default:
break;
}
}
void HelloWorld::onKeyReleased(EventKeyboard::KeyCode keyCode,Event *event) {
auto action1 = event->getCurrentTarget()->getActionByTag(1);
auto node = event->getCurrentTarget();
Vec2 loc = event->getCurrentTarget()->getPosition();
switch (keyCode){
case EventKeyboard::KeyCode::KEY_UP_ARROW:
action1->getTarget()->stopActionByTag(1);
node->setPosition(--loc.x, --loc.y);
default:
break;
}
}
sarah = Sprite::create("standing.png");
sarah->setAnchorPoint(Vec2(0, 0));
sarah->setPosition(100, 100);
Vector<SpriteFrame*> walkingframeskleft;
walkingframeskleft.reserve(3);
walkingframeskleft.pushBack(SpriteFrame::create("walk2.png", Rect(0, 0, 65, 81)));
walkingframeskleft.pushBack(SpriteFrame::create("walk3.png", Rect(0, 0, 65, 81)));
walkingframeskleft.pushBack(SpriteFrame::create("walk4.png", Rect(0, 0, 65, 81)));
Animation* walkinganimation = Animation::createWithSpriteFrames(walkingframeskleft, .1f);
walking = Animate::create(walkinganimation);
action = RepeatForever::create(walking);
action->setTag(1);
this->addChild(sarah);
auto listener = EventListenerKeyboard::create();
listener->onKeyPressed = CC_CALLBACK_2(HelloWorld::onKeyPressed,this);
listener->onKeyReleased = CC_CALLBACK_2(HelloWorld::onKeyReleased,this);
this->getEventDispatcher()->addEventListenerWithSceneGraphPriority(listener, sarah);
return true;
}
in my switch cases i only have the left arrow set up since i just wanted to test if a key would work to begin with
As far as I can tell, your error is caused by the fact that your action is null at the moment when you try to run it.
That is because:
After you create your action with this line:
action = RepeatForever::create(walking);
The action gets added to the autorelease pool. So, if you don't use it immediately(run it on a sprite) action->release(); will be called on it which will delete it. So, when you are creating actions that you will want to use later(or reuse) in your code, be sure to manually retain them after creation and release them when you are sure you won't use them again:
action = RepeatForever::create(walking);
action->retain();
This way your action won't be released(deleted) until you call release() yourself.
I have a wxwidget application that uses dragandrop and when I close the application, it crashes on this line:
virtual ~wxDropTargetBase()
{ delete m_dataObject; }
I setup the drapand drop in this way:
MainWindow::MainWindow() : MainWindowTemplate(NULL), m_fileDropTarget(textSourceFolder)
{
// connect events
this->Connect(wxEVT_IDLE, wxIdleEventHandler(MainWindow::OnIdle));
// set window minimum size - work around bug that ignores outer border and sets min size slightly too small
wxSize minSize = sizerOuter->GetMinSize();
minSize.SetWidth(minSize.GetWidth() + 16);
minSize.SetHeight(minSize.GetHeight() + 16);
SetMinSize(minSize);
Layout();
// set file drop target
SetDropTarget(&m_fileDropTarget);
}
and the source code for my
class MyFileDropTarget : public wxFileDropTarget
{
public:
MyFileDropTarget(wxTextCtrl *textCtrl)
{
m_fileTextCtrl = textCtrl;
}
virtual bool wxFileDropTarget::OnDropFiles (wxCoord x, wxCoord y, const wxArrayString &filenames)
{
if (filenames.size() > 0)
{
m_fileTextCtrl->SetValue(filenames.Item(0));
return true;
}
return false;
}
private:
wxTextCtrl *m_fileTextCtrl;
};
what is the problem and how I can fix it?
It looks like your m_fileDropTarget is an object, in which case it is deleted twice, as when you call SetDropTarget() it takes ownership of the pointer passed to it.