I was wrong about what the problem was. The event handlers worked fine, and everything works now. I found the answer on http://gloss.ouroborus.net/, and the relevant paragraph is cited below. I apologize for asking a misleading question. I would delete the question but I don't see a way to do that.
from gloss.ouroborus.net:
Q: On my MacBook Pro under OSX, gloss programs freeze after displaying the first few frames.
A: This can happen on dual GPU systems when the OS switches from the integrated GPU (baked into the processor) to the discrete one (separate from the main processor). The gloss program can sometimes draw a few frames before getting stuck, otherwise it just shows a black window. This is probably a bug in OSX not switching the graphics context properly. The work-around is to disable automatic GPU switching under System Preferences / Energy Saver.
Original question:
I wrote a game in Haskell Gloss which uses mouse click and keyboard handlers. It compiles and runs fine on a PC, but, while it compiles and loads on an Apple and presents the game screen, the mouse and keyboard handlers malfunction. The mouse handler recognizes that the mouse button has been been clicked, but reports the same pair of numbers for the mouse position no matter where the mouse is. The keyboard handler does not work for 's' and 'f', but the escape key DOES work.
Here are the handlers:
mousehandle::Event->(Board,Board)->IO(Board,Board)
mousehandle (EventKey (MouseButton LeftButton) Down _ pt#(x,y))
(board,solved) =
return (board',solved)
where
board' = if candidates == [] then board
else rotateCell board (fst (head candidates))
candidates = getCandidates (x,y) board
mousehandle (EventKey (Char 's') Down _ _ ) (board1, board2) = return (board2, board1)
mousehandle (EventKey (Char 'f') Down _ _ ) (board1, board2) = do
print "filename?"
ans <- getLine
games2File [board1, board2] ans
return (board1, board2)
mousehandle (EventKey (SpecialKey KeyEsc) Down _ _) _ = exitSuccess
mousehandle _ x = return x
I know what the returned mouse position coordinates are for each click because a trace in the function getCandidates prints them out to the console.
The computer is a Mac Book Pro. The Haskell used is GHC 7.6.3, installed as part of the full Haskell Platform. Gloss was installed with "cabal install gloss".
Any suggestions would be welcome.
Related
I'm making a simple LTK game in Common Lisp and would like to have the player character jump upon pressing space. However, the window is constantly updating, so I cannot wait for user input. I want to check each frame whether the space key is pressed. Despite much googling, I couldn't find the way to do this in Lisp. All I found are traditional I/O prompts that stop the flow of the program.
Thanks for any help.
Are you using a Tk canvas? Maybe you could bind event handlers to key presses?
(with-ltk ()
(let ((canvas (make-canvas nil)))
(grid canvas 1 1)
(bind canvas
"<Left>"
(lambda (e)
(message-box "Left" "Click" "okcancel" "info")))
(focus canvas)))
When you receive a key press, you can set a variable that you inspect when processing a frame.
This works fine for one button, but binding e.g. both the up arrow and the left arrow for movement only registers one at a time. Is there a way to fix that?
Here is a more detailed example. Tk can bind on KeyPress and KeyRelease events. You only need to manage the pressed/unpressed state of the key you want to observe, and set the right variables accordingly.
(with-ltk ()
(let ((canvas (make-canvas nil))
(x 50)
(y 50)
(speed 5)
(w 10)
(h 10)
(dx 0)
(dy 0))
(grid canvas 1 1)
(macrolet
((on (event expr)
(check-type event string)
(let ((evar (gensym)))
`(bind canvas ,event
(lambda (,evar)
(declare (ignore ,evar))
,expr)))))
(on "<KeyPress-Left>" (decf dx))
(on "<KeyPress-Right>" (incf dx))
(on "<KeyRelease-Left>" (incf dx))
(on "<KeyRelease-Right>" (decf dx))
(on "<KeyPress-Up>" (decf dy))
(on "<KeyPress-Down>" (incf dy))
(on "<KeyRelease-Up>" (incf dy))
(on "<KeyRelease-Down>" (decf dy)))
(focus canvas)
(let ((rectangle (create-rectangle canvas x y 10 10)))
(labels ((game-loop ()
(incf x (* dx speed))
(incf y (* dy speed))
(set-coords canvas rectangle (list x y (+ x w) (+ y h)))
(after 50 #'game-loop)))
(game-loop)))))
The first part of the above function creates a canvas and binds event handlers for KeyPress/KeyRelease events for Left, Right, Down and Up keys. This is a bit verbose, but is simple enough for an example. Alternatively, you could bind only on "<KeyPress>" and "<KeyRelease>" events (no additional key in the string), and use a table indexed by the keycode of your key event.
The second part is the game loop, where both deltas dx and dy are actually used to move the rectangle; at the end of the game loop, after ensures the game loop is run again after some time.
Event handlers do not directly manipulate canvas elements, they are only used to translate UI events to game logic changes. You have to be careful about how and when events happen. For example, the first version of the above used to do:
(on "<KeyPress-Left>" (setf dx -1))
(on "<KeyPress-Right>" (setf dx 1))
(on "<KeyRelease-Right>" (setf dx 0))
(on "<KeyRelease-Left>" (setf dx 0))
But that was wrong because the sequence press-left, press-right and release-right would make the rectangle stop.
I am learning how to use the Gloss library to make some animations in Haskell.
Consider the code below which animates a circle that shrinks and expands its radius with time.
import Graphics.Gloss
import Graphics.Gloss.Interface.Pure.Game
type Radius = Float
type RealTime = Float
data World = World Radius RealTime
main :: IO ()
main
= do let initWorld = World 100.0 0
let windowSize = (800,800)
let windowPosition = (200,200)
putStrLn "Before play"
play (InWindow "Wobbling Circle" windowSize windowPosition)
white 40 initWorld renderWorld handleEvent stepWorld
putStrLn "After play"
renderWorld :: World -> Picture
renderWorld (World rad rtime ) = Pictures [ Circle rad ]
handleEvent :: Event -> World -> World
handleEvent _ = id
stepWorld :: Float -> World -> World -- wobbling circle
stepWorld _ (World _ rtime) = World (100 * sin rtime) (rtime+0.1)
I compiled this code with ghc --make -O2 -threaded Main.hs on an Ubuntu 14.04 machine.
When I run the code, the "Before play" statement is printed out and then the animation starts as expected. However, when I close the animation window, the code terminates immediately without printing the "After Play" statement. Why is that?
Presumably you are using the GLUT backend (the default). Take a look at some of the source code for gloss (exactly as it appears with comments):
instance Backend GLUTState where
initBackendState = glutStateInit
initializeBackend = initializeGLUT
-- non-freeglut doesn't like this: (\_ -> GLUT.leaveMainLoop)
exitBackend = (\_ -> System.exitWith System.ExitSuccess)
....
When it exits the main loop, gloss will call exitBackend, whatever it is. For GLUT, that simply calls System.exitWith which naturally will terminate your program. The more sensible thing to do would be to call leaveMainLoop but as the comment in the code says, implementations of glut other than freeglut don't work well with that function (why? who knows. This is what the authors of gloss claim).
Your potential solutions are to use freeglut specifically and modify the source code of gloss to change exitBackend; or use the GLFW backend, which doesn't have this problem.
Using the gnuplot module, after I plot a graph I get put into the gnuplot console. Is there a way to stop this happening? I never use it, and it's annoying to have to type exit after closing each graph, especially when I'm testing a sequence of plots.
For example:
module Main where
import Graphics.Gnuplot.Simple
main = do
let xs = linearScale 100 (-10, 10) :: [Float]
plotFunc [] xs sin
plotFunc [] xs cos
I'm using Windows 7 x64 and the Haskell Platform 2013.2.0.0 if that makes a difference.
Try the following:
bind Close "exit gnuplot"
It should do the trick!
See here for bind details if you aren't familiar: bind reference
I have a program which performs a long-going calculation where the result is shown as a plot.
I am currently using Chart-0.14 for this. I want to show the partial results, and update during calculations.
Graphics.Rendering.Chart.Gtk.updateCanvas :: Renderable a -> DrawingArea -> IO Bool seems to do that, but I do not find any way to get a DrawingArea from the plot. The function renderableToWindow :: Renderable a -> Int -> Int -> IO () does not return anything (and furthermore it does not return before the window is closed).
I would like to do something like the following:
main = do
drawingArea = forkRenderableToWindow (toRenderable $ plotLayout $
plot [0,0.1..10] sin "sin(x)") 640 480
updateCanvas (toRenderable $ plotLayout $ plot [0,0.1..10] sin "sin(x)") drawingArea
How should I do this? Would I need to reimplement the functions in Graphics.Rendering.Chart.Gtk with a version that returns the DrawingArea and in some way (how would I do this? forkIO?) returns immediately without closing the window?
You are looking for createRenderableWindow and then you need to use the GTK operations to work on the given Window - I don't think the Chart package exports any higher level operations on Windows.
EDIT2: So ignore the below - it doesn't work even with GUI initilization. My comment was a guess based on types.
EDIT:
Here is some example code. Understand, I'm just piecing things together based on the types. There might be better ways to do things if you ask someone who actually knows the library.
Below we use:
createRenderableWindow - this was the crux of my answer
castToDrawingArea - This is needed to get a DrawingArea from the Window type provided by GTK. These casts are taking place of C++ OO inheritance, I think.
widgetShowAll - because we haven't actually displayed the window, we best do that. I stole this function after looking at the source for renderableToWindow.
updateCanvas - I just saw this in the haddock documentation and figured it is why you wanted a DrawingArea in the first place.
Now for the code:
import Graphics.Rendering.Chart.Gtk
import Graphics.Rendering.Chart.Renderable
import Graphics.UI.Gtk.Misc.DrawingArea
import qualified Graphics.UI.Gtk as G
main = do
win <- createRenderableWindow emptyRenderable 400 400
let draw = castToDrawingArea win
G.widgetShowAll win
updateCanvas emptyRenderable draw
It would seem a simple task, but I'm looking at a couple pair tens forums and haven't found the solution. How can I get the current mouse position in LWUIT?
Only here it is:
PointerInfo a = MouseInfo.getPointerInfo ();
Point point = new Point (a.getLocation ());
But it is not suitable for JavaME.
Are there other ways?
In LWUIT you can register your Form with the pointerListener : yourForm.addPointerPressedListener(this); , then you implement the code of the public void pointerPressed(int x, int y) method. And the x and y are the position you are looking for. So you must click the screen to obtain these values , that is the device is a tactile one.