Custom Cursor [Solved!!]
by Jesse Allen · in Torque 2D Beginner · 01/03/2014 (4:52 am) · 5 replies
This one's quite lengthy so please bear with me. I do feel that it covers a lot of good material though, and the bottom part of this post is basically a walkthrough of an alternative (that I still use).
I was having trouble getting the default Windows cursor to go away so that I could use a custom cursor, so I did some searching about the issue. I found this thread, in which Amjad and Simon were able to find a solution by recompiling the source:
Cursor Bitmap Thread
I followed Simon's linked repository changes, in order, so that I made each change. Over the course of the thread he makes a few changes to the same files, so I wanted to be sure that I was changing the relevant lines in the source files. This did, indeed, end up working for me (almost). I used Visual Studio 2013 Express, and while it yelled at me a couple times about not having 2012 tools installed a quick project update fixed that. So, I recompiled the solution and added a line to my main.cs:
I also created a new guiProfile:
It worked! The default Windows platform cursor was gone, and my new image was there for my cursor. But there is one remaining problem that I can't sort out:
Any suggestions? Since this problem involved changing some lines in the source (which I'm fairly certain I've done correctly), I wasn't sure if possibly there were other source changes that needed to happen? Something that would be sure to 'hide' the default Windows cursor even if certain input events are happening?
Alternative
I've been using a sprite with a function to make it stick to the mouse onTouchDragged. This is okay, but leads to strange rendering in some cases. To be honest, I rather like the creative freedoms this option gives me in-game because I can have the mouse sprite change 'onHover' of certain scene elements (Come to think of it I can probably do the same with a guiSpriteCtrl but that requires option 1 above to work i.e. no platform cursor peeking out during input events). Here's the way I'm handling the position of the sprite for anyone reading along:
First go ahead and make this variable (World is the name of my module):
Then you can use this:
Alright, cool? Well, almost. What you'll notice using this is that if you push any GuiDialogs your cursor sprite is going to hang up and you won't have a cursor to use to interact with the GuiDialog you just pushed. So you'll want to be sure in your toggleGuiDialog() that you 'turn on' your default cursor and 'turn off' your World.trackMouse(cursor sprite). You'll want to do something like this (here's what I use to toggle an in-game Options menu:
Alright, so now you should have a custom sprite to move around as a mouse cursor while the scene is active. If you open up the gui menu, your default cursor shows up and the cursor sprite goes away. Nice.
The only problem with this alternative is that if the scene camera moves (my camera is mounted to the player at the moment) the cursor will stick where it was. Once the user moves the mouse again, the cursor sprite will reappear in a position relative to where it was when the user last moved the mouse. In other words:
This is actually sort of 2 problems in 1 relating to the use of custom mouse cursors. I could see myself using both of these alternatives, depending on the desired results. But of course, in order to do so, I need to clear up a couple things:
The default Windows platform cursor needs to never show up, even if certain input events happen.
The onTouchDragged() function above needs some sort of work to take into account if the player (camera) moves.
As usual, any help will be appreciated. Thanks in advance for any sort of assistance that can be lended. As you can see I've expended quite a bit of time into this particular issue and I'd just like to see it settled. Cheers!
I was having trouble getting the default Windows cursor to go away so that I could use a custom cursor, so I did some searching about the issue. I found this thread, in which Amjad and Simon were able to find a solution by recompiling the source:
Cursor Bitmap Thread
I followed Simon's linked repository changes, in order, so that I made each change. Over the course of the thread he makes a few changes to the same files, so I wanted to be sure that I was changing the relevant lines in the source files. This did, indeed, end up working for me (almost). I used Visual Studio 2013 Express, and while it yelled at me a couple times about not having 2012 tools installed a quick project update fixed that. So, I recompiled the solution and added a line to my main.cs:
Canvas.setcursor(GameCursor);
I also created a new guiProfile:
if(!isObject(GameCursor)) new GuiCursor(GameCursor)
{
hotSpot = "4 4";
renderOffset = "0 0";
bitmapName = "./images/gameCursor";
};It worked! The default Windows platform cursor was gone, and my new image was there for my cursor. But there is one remaining problem that I can't sort out:
- If I click or right-click and hold down the mouse button, the default Windows platform cursor shows up.
- It will disappear as soon as I release the mouse button.
- Also the Windows platform cursor will briefly reveal itself onHover of gui buttons.
Any suggestions? Since this problem involved changing some lines in the source (which I'm fairly certain I've done correctly), I wasn't sure if possibly there were other source changes that needed to happen? Something that would be sure to 'hide' the default Windows cursor even if certain input events are happening?
Alternative
I've been using a sprite with a function to make it stick to the mouse onTouchDragged. This is okay, but leads to strange rendering in some cases. To be honest, I rather like the creative freedoms this option gives me in-game because I can have the mouse sprite change 'onHover' of certain scene elements (Come to think of it I can probably do the same with a guiSpriteCtrl but that requires option 1 above to work i.e. no platform cursor peeking out during input events). Here's the way I'm handling the position of the sprite for anyone reading along:
First go ahead and make this variable (World is the name of my module):
World.trackmouse = true;
Then you can use this:
function SandboxWindow::onTouchDragged(%this, %touchID, %worldPosition)
{
// Finish if not tracking the mouse.
if ( !World.trackMouse )
return;
// Update cursor position.
World.CursorObject.Position = %worldPosition;
}Alright, cool? Well, almost. What you'll notice using this is that if you push any GuiDialogs your cursor sprite is going to hang up and you won't have a cursor to use to interact with the GuiDialog you just pushed. So you'll want to be sure in your toggleGuiDialog() that you 'turn on' your default cursor and 'turn off' your World.trackMouse(cursor sprite). You'll want to do something like this (here's what I use to toggle an in-game Options menu:
function toggleOptions(%make)
{
// Finish if being released.
if ( !%make )
return;
// Is the menu awake?
if ( GameOptionsDialog.isAwake() )
{
// Yes, so deactivate it.
if ( $enableDirectInput )
activateKeyboard();
Canvas.popDialog(GameOptionsDialog);
Canvas.hideCursor();
World.trackMouse = true;
return;
}
// Activate it.
if ( $enableDirectInput )
deactivateKeyboard();
World.trackMouse = false;
Canvas.pushDialog(GameOptionsDialog);
Canvas.showCursor();
}Alright, so now you should have a custom sprite to move around as a mouse cursor while the scene is active. If you open up the gui menu, your default cursor shows up and the cursor sprite goes away. Nice.
The only problem with this alternative is that if the scene camera moves (my camera is mounted to the player at the moment) the cursor will stick where it was. Once the user moves the mouse again, the cursor sprite will reappear in a position relative to where it was when the user last moved the mouse. In other words:
- So long as the user is constantly moving the mouse, the positioning function I posted above will work just perfectly.
- So long as the camera is not moving (player stopped), the player can move or stop moving the mouse just fine. It all looks normal.
- As soon as the camera moves at all, my positioning function doesn't take this into account at all so the results are undesirable.
This is actually sort of 2 problems in 1 relating to the use of custom mouse cursors. I could see myself using both of these alternatives, depending on the desired results. But of course, in order to do so, I need to clear up a couple things:
The default Windows platform cursor needs to never show up, even if certain input events happen.
The onTouchDragged() function above needs some sort of work to take into account if the player (camera) moves.
As usual, any help will be appreciated. Thanks in advance for any sort of assistance that can be lended. As you can see I've expended quite a bit of time into this particular issue and I'd just like to see it settled. Cheers!
About the author
Skilled Artist and Musician. Intermediate Torque Developer.
#2
(Completely Unrelated for Richard)
@ Richard, that Inventory module of yours is quite a piece of work. I have learned a ton from that module over the past few days. I encountered a small bug where you could replicate the inventory icons but I sorted it out. All I had to do was this:
In inventoryGridContainer.cs:
Here I just commented out one line, not sure if it's needed for future plans but for me it stopped the replication of icons perfectly.
Anyways, thanks a lot man this has made my life tons easier with figuring out how I might get my own Inventory working. The buying and selling code is also pretty much perfect for some other ideas I had in mind for the project. Brilliant stuff, thanks so much for sharing!
01/03/2014 (7:21 am)
Hi Richard, thanks for the quick reply. I'm not familiar with using a 2nd scene for gui scene objects, although I can see the potential here. Like you've said, though, I'm not sure how I'd get my picking operations to work on the actual game scene.(Completely Unrelated for Richard)
@ Richard, that Inventory module of yours is quite a piece of work. I have learned a ton from that module over the past few days. I encountered a small bug where you could replicate the inventory icons but I sorted it out. All I had to do was this:
In inventoryGridContainer.cs:
Here I just commented out one line, not sure if it's needed for future plans but for me it stopped the replication of icons perfectly.
function IGCDynamicButton::onMouseDown(%this, %id, %mousePoint)
{
echo(" @@@ IGCDynamicButton::onMouseDown(" @ %this @ ", " @ %id @ ", " @ %mousePoint @ ")");
%position = %mousePoint;
%halfParentWidth = %this.sprite.Extent.x / 2;
%halfParentHeight = %this.sprite.Extent.y / 2;
%position.x -= %halfParentWidth;
%position.y -= %halfParentHeight;
//Inventory.createDraggingControl(%this.sprite, %position, %mousePoint, %this.sprite.Extent);
}Here I realized that the createDraggingControl() that was making the icon was being called in multiple locations. Removing this one seemed appropriate. I also seem to recall another reference to the same function that may be able to removed, but I hadn't dug through it all again to check.Anyways, thanks a lot man this has made my life tons easier with figuring out how I might get my own Inventory working. The buying and selling code is also pretty much perfect for some other ideas I had in mind for the project. Brilliant stuff, thanks so much for sharing!
#3
This may seem a little redundant at first glance, ordering the Canvas to hide the cursor twice, but it is absolutely necessary. I believe that what is really going on here is the order to hide the cursor in the AppCore module is actually nuking the Windows Platform cursor initially. Then when the call to setCursor() takes place later it sort of 'resets' the cursor, so you have to nuke it again prior to re-rendering it i.e. Canvas.showCursor();
Anyhow this is 100% working on my end so I'm a happy camper. I'm now able to have my custom cursor as a 'true' GUI element that goes over the top of GUI panels. Cheers, hope this all helps people in the future!
01/03/2014 (2:31 pm)
Guys, believe it or not I found a fix for this!! No source modifications required, just have to jump through a couple hoops with TorqueScript! I've got it working now, so that I can use whatever custom cursor I want directly by calling it from the canvas. Here's how it's done:- In the AppCore module, open the main.cs.
- Add in this line someplace:
Canvas.hideCursor();
Canvas.setCursor(%GameCursor); Canvas.hideCursor(); Canvas.showCursor();%GameCursor is, of course, your custom cursor.
This may seem a little redundant at first glance, ordering the Canvas to hide the cursor twice, but it is absolutely necessary. I believe that what is really going on here is the order to hide the cursor in the AppCore module is actually nuking the Windows Platform cursor initially. Then when the call to setCursor() takes place later it sort of 'resets' the cursor, so you have to nuke it again prior to re-rendering it i.e. Canvas.showCursor();
Anyhow this is 100% working on my end so I'm a happy camper. I'm now able to have my custom cursor as a 'true' GUI element that goes over the top of GUI panels. Cheers, hope this all helps people in the future!
#4
And that hide-then-show trick is cool - who'd'a thunk it?
01/03/2014 (2:58 pm)
Oh, good catch - the dragging control is supposed to be created in onMouseDragged() obviously and not there in onMouseDown(). Thanks!And that hide-then-show trick is cool - who'd'a thunk it?
#5
About the cursor, I'm glad that I'm starting to solve many problems on my own. Even moreso, I'm glad that this particular cursor bug can be considered 'solved'. I've dug through countless postings here about this problem, and now it can be laid to rest.
01/04/2014 (4:38 am)
It was my genuine pleasure to find and solve that Inventory module bug Richard. So good I could help in some way, that module is great and deserves any bugfixes that may come its way!About the cursor, I'm glad that I'm starting to solve many problems on my own. Even moreso, I'm glad that this particular cursor bug can be considered 'solved'. I've dug through countless postings here about this problem, and now it can be laid to rest.
Torque Owner Richard Ranft
Roostertail Games
It would be better to get this sorted out engine-side. This sort of mouse cursor shenanigans has plagued T2D/T3D for some time now.