HUD button width and height questions

Started by stewbasic, January 30, 2014, 11:51:27 AM

Previous topic - Next topic

stewbasic

I want a button at the top of the screen that the player can click. I can use SetScreenMode(TRUE) to keep it the right place and size, and the difference between CurrentPixelCoords and GetMousePosition tells me how far the mouse is from the button center. The problem is, the latter two commands output map pixel coords, not screen pixel coords. That is, if the player zooms out without moving the mouse, the difference increases. So I need to convert map pixel coords to screen pixel coords to compare to the button size.

I have a hacky way to do this, by creating an invisible dummy core at the corner of the button, and using its map coords to figure out the button size in map coords:


# RestartButton.crpl
$width:400.0
$height:60.0

once
AddScriptToUnit(Self "Label.crpl")
# Hack: Gives us the size of the button in map pixel coords, rather than screen pixel coords
CreateUnit("CRPLCORE" 20 20) ->corner
AddScriptToUnit(<-corner "Corner.crpl")
@GameLoaded
endonce

if(GetMouseButtonDown(0))
CurrentPixelCoords ->cy ->cx
GetMousePosition
<-cy sub abs GetUnitAttribute(<-corner CONST_PIXELCOORDY) <-cy sub abs lt swap
<-cx sub abs GetUnitAttribute(<-corner CONST_PIXELCOORDX) <-cx sub abs lt and
if TRUE ->clicked SetText("CLICK") endif
endif

:GameLoaded
SetScriptVar(Self "Label.crpl" "labelText" "Restart challenge")
SetScreenMode(TRUE)
SetScreenCoordX(0.5)
SetScreenPixelCoordY(ScreenHeight <-height div(2) sub)
SetScriptVar(<-corner "Corner.crpl" "px" ScreenWidth sub(<-width) div(2))
SetScriptVar(<-corner "Corner.crpl" "py" ScreenHeight sub(<-height))
SetImage(Self "bg" "Custom0")
SetImageScale(Self "bg" <-width div(24) <-height div(24))
ShowTraceLog

# Corner.crpl
once
@GameLoaded
endonce

:GameLoaded
SetScreenMode(TRUE)
SetUnitAttribute(Self CONST_CREATEPZ FALSE)
SetUnitAttribute(Self CONST_TAKEMAPSPACE FALSE)
SetUnitAttribute(Self CONST_SUPPORTSDIGITALIS FALSE)
SetUnitAttribute(Self CONST_NULLIFIERDAMAGES FALSE)
SetUnitAttribute(Self CONST_COUNTSFORVICTORY FALSE)
SetScreenPixelCoordX(<-px)
SetScreenPixelCoordY(<-py)
SetImage(Self "Main" "CustomEmitter") # For debugging
# SetImage(Self "Main" "None")

# Label.crpl
$labelText:""

once
@GameLoaded
endonce

:GameLoaded
SetUnitAttribute(Self CONST_CREATEPZ FALSE)
SetUnitAttribute(Self CONST_TAKEMAPSPACE FALSE)
SetUnitAttribute(Self CONST_SUPPORTSDIGITALIS FALSE)
SetUnitAttribute(Self CONST_NULLIFIERDAMAGES FALSE)
SetUnitAttribute(Self CONST_COUNTSFORVICTORY FALSE)
SetImage(Self "Main" "None")
SetText(<-labelText)


1) Is there a better way to do this?
2) If I replace

SetScreenPixelCoordX(<-px)
SetScreenPixelCoordY(<-py)

by

SetScreenPixelCoords(<-px <-py)

the Y coordinate ends up wrong. Why?
3) If I replace

SetImageScale(Self "bg" <-width div(24) <-height div(24))

by

SetImageScaleX(Self "bg" <-width div(24))
SetImageScaleY(Self "bg" <-height div(24))

it gets the wrong size in both directions (and when I reload it does some weird resizing after 1 tick). Why?

Clean0nion

It might be because the Y axis in map coords is inverted, but is not inverted in pixel coords.

Grayzzur

It's the 3rd coordinate set, C0 -- there are the Map coordinates, individual cells, Pixel coordinates, for the pixels on the map, and Screen coordinates, which relate to the window itself and is dependent on zoom level.

The elegant solution would be to appeal to Virgil for some extra CRPL commands, such as a GetMouseScreenPosition, etc.

Also, I believe you need to re-set size and position for Screen coordinate placed items in the :awake function to have it persist through a save/load.
"Fate. It protects fools, little children, and ships named 'Enterprise.'" -William T. Riker

knucracker

In the upcoming will be:
GetMouseScreenPosition
GetMouseScreenPixelPosition

Each returns a pair of coordinates. 

GetMouseScreenPosition returns floats where 0,0 is the lower left corner of the screen and 1,1 is the upper right hand corner.  Values can be outside the bounds if the mouse cursor is outside the game window.

GetMouseScreenPixelPosition returns ints where 0,0 is the lower left corner of the screen and Screen_Width, Screen_Height are the upper right hand corner.  Screen_Width and Height are the pixel resolution of the game window (so something like 1024x768)

If somebody would like to add these guys to the Wiki, that would be awesome.

stewbasic

Quote from: Grayzzur on January 30, 2014, 12:19:15 PM
Also, I believe you need to re-set size and position for Screen coordinate placed items in the :awake function to have it persist through a save/load.
Doesn't :GameLoaded take care of this? Actually what is the difference between :awake and :GameLoaded? Anyway it seems to persist...

Quote from: virgilw on January 30, 2014, 07:00:54 PM
In the upcoming will be:
GetMouseScreenPosition
GetMouseScreenPixelPosition

Each returns a pair of coordinates. 

GetMouseScreenPosition returns floats where 0,0 is the lower left corner of the screen and 1,1 is the upper right hand corner.  Values can be outside the bounds if the mouse cursor is outside the game window.

GetMouseScreenPixelPosition returns ints where 0,0 is the lower left corner of the screen and Screen_Width, Screen_Height are the upper right hand corner.  Screen_Width and Height are the pixel resolution of the game window (so something like 1024x768)

If somebody would like to add these guys to the Wiki, that would be awesome.
That would certainly be easier! I'll make some wiki pages for them.

btw questions 2) and 3) still confuse me; I expect the two alternatives to be identical in both cases.

knucracker

#5
I had to go study this myself (and have updated the wiki a little bit).

:Awake and :GameLoaded are very similar.  The both get called on a core at game load time.  :Awake gets called at the moment the core is created.  That means it will get called before the initialization "loading" screen disappears at game start time.  :GameLoaded waits till afterwards.  So if you want to pop up a message dialog at game load time or play a sound, then :GameLoaded is a good place to do that.  Otherwise the sound will play while the game appears to be loading.

Note that GameLoaded won't get called on cores that are dynamically created at run time but Awake will.  However, if you have a dynamically created core with a script that has a :GameLoaded in it, that will get called if the game is saved and loaded.

So Awake happens as soon as a core is 'created' whether that be at the game load or when one is created during game time.  GameLoaded happens immediately after a game load is finished on any core that happens to be in the saved mission that was loaded.

Final note, you can check the GetUpdateCount to tell when GameLoaded or Awake is happening at the very beginning or not.  GetUpdateCount will return 0 on any core that is brand new.  So after a save and load, GetUpdateCount will return something greater than 0 inside GameLoaded and Awake.

All horribly confusing, I know.  For the longest time Awake was all that existed.  I created GameLoaded when I did the credits mission so that I could show the opening conversation AFTER the game loading screen was finished.

As for question 2.... Big time typo bug on my part.  Will be fixed in tomorrow's build.  Wished I had paid closer attention and fixed that 30 minutes ago...

As for question 3... looks like another goof up on my part.  It's more subtle but I'll get it fixed for tomorrow as well.

Clean0nion

Quote from: virgilw on January 30, 2014, 07:00:54 PM
In the upcoming will be:
GetMouseScreenPosition
GetMouseScreenPixelPosition

Each returns a pair of coordinates. 

GetMouseScreenPosition returns floats where 0,0 is the lower left corner of the screen and 1,1 is the upper right hand corner.  Values can be outside the bounds if the mouse cursor is outside the game window.

GetMouseScreenPixelPosition returns ints where 0,0 is the lower left corner of the screen and Screen_Width, Screen_Height are the upper right hand corner.  Screen_Width and Height are the pixel resolution of the game window (so something like 1024x768)

If somebody would like to add these guys to the Wiki, that would be awesome.
So I suppose we can make a thing that auto-pauses the game when the player's doing something else? That could be useful, not to mention annoying

Grayzzur

Quote from: Clean0nion on January 31, 2014, 03:22:36 AM
So I suppose we can make a thing that auto-pauses the game when the player's doing something else? That could be useful, not to mention annoying
But you can't auto-un-pause when the mouse comes back (CRPL doesn't run when paused), so it would lean more towards just annoying.
"Fate. It protects fools, little children, and ships named 'Enterprise.'" -William T. Riker

Annonymus

Actually some form of CRPL must run while the game is paused because I've seen text on a core appear and disappear when i moused over it in pause.
If a topic started by me is in the wrong place feel free to move it at anytime.

knucracker

Popup text is an internal feature that appears on mouse over.  It is set via crpl but crpl doesn't control when it appears and disappears.  When the game is paused, many things are still going on.  'Paused' means that units aren't being updated per game loop.  So their logic is just suspended.  But rendering, interface handling, etc. are all still active.  CRPL is processed by a CRPL Towers game update logic.  So when paused, scrpits don't evaluate.

I considered adding a callback function that would get called while the game was paused... but it sounded like it might be ripe for abuse.

Relli

Quote from: virgilw on January 31, 2014, 09:51:08 AM
Popup text is an internal feature that appears on mouse over.  It is set via crpl but crpl doesn't control when it appears and disappears.  When the game is paused, many things are still going on.  'Paused' means that units aren't being updated per game loop.  So their logic is just suspended.  But rendering, interface handling, etc. are all still active.  CRPL is processed by a CRPL Towers game update logic.  So when paused, scrpits don't evaluate.

I considered adding a callback function that would get called while the game was paused... but it sounded like it might be ripe for abuse.
I wanted to make a menu that popped up and paused the game while the player was choosing, 'cuz it was probably gonna be really big on the screen. Would that be possible to do? Or would it be unable to register what button was hit while paused?

knucracker

Once the game is paused, you can't do anything in CRPL.

However, if by letting the player choose something you mean select between two options you can do with with the built in message dialog support. 

Look here:
http://knucklecracker.com/wiki/doku.php?id=crpl:docs:showmessagedialog

Grayzzur wrote some very good docs for this and how to get the callback.  Note that you can pause the game after showing the message and the game will auto unpause after the choice is made.

Relli

Quote from: virgilw on January 31, 2014, 10:04:55 AM
Once the game is paused, you can't do anything in CRPL.

However, if by letting the player choose something you mean select between two options you can do with with the built in message dialog support. 

Look here:
http://knucklecracker.com/wiki/doku.php?id=crpl:docs:showmessagedialog

Grayzzur wrote some very good docs for this and how to get the callback.  Note that you can pause the game after showing the message and the game will auto unpause after the choice is made.
Thank you, but sadly I need way more than two choices. I'll just go with my backup plan. Shrink it as much as possible and shove it in the bottom left corner. Done right (don't hold your breath), it may actually look like it belongs there.

knucracker

I split the discussion on paused operations out into a separate thread for discussion...