Not logged inGosu Forums
Forum back to libgosu.org Help Search Register Login
Up Topic Gosu / Gosu Exchange / mouse movement
- - By daIT Date 2012-06-28 04:04
Hi,

I just discovered gosu and I have a few questions about mouse movement handling : does gosu provide an effective way of restricting or detecting mouse movement ? If not, could anyone tell me how they would go about for example preventing the cursor from getting outside the boundaries of the window, whenever the window has focus (useful for scrolling in an rts-type game) ? or making an fps-type game, where the cursor stays at the center of the screen and the background moves according to the movement of the mouse ?
The only way to restrict cursor movement that I can think of would be to call Window#mouse_x= and #mouse_y= on every update, but this probably wouldn't work since the mouse obviously moves a lot faster than once every update_interval.
As for detecting mouse movement, I guess you could, every update, take the difference between the current and the previous update's mouse position, and (in my second example) move your background that much pixels ?

And one last question : does gosu provide sockets for ruby ? I didn't see any mention of it in the ruby reference but there's a "document Gosu's Sockets" entry in the ToDo list.

Thank you for your help :)
Parent - By rremedio Date 2012-06-28 04:46 Edited 2012-06-28 04:58
For the mouse thing, I guess you could draw the cursor on the last position it had before leaving the game screen and make the scrolling according to its real position (so the farther the mouse position goes, the faster will be the scrolling). Keep in mind that you don't need to draw the cursor image on the real mouse_x/y positions, you may draw it where you want.

It's a way to do it, but it wouldn't keep the player from clicking outside the window (which would make the game window lose the focus).
Parent - - By jlnr (dev) Date 2012-06-28 18:11

> The only way to restrict cursor movement that I can think of would be to call Window#mouse_x= and #mouse_y= on every update, but this probably wouldn't work since the mouse obviously moves a lot faster than once every update_interval.


mouse_x/y= are indeed built-in for that purpose, though they will work better in fullscreen mode.

For a 3D shooter (or anything similar), you would always draw the cursor at the center of the screen. On every update call, you would move the camera based on the new (real) cursor position and reset the (real) cursor to the center of the screen.

Building an RTS in windowed mode would be a little tougher. How do other games work? mouse_x/y will work seamlessly when the cursor is outside the window. For example, you can keep scrolling left as long as mouse_x is between -50 and 50 and mouse_y is between 0 and window.height.

Sockets: Ruby has its own socket classes which are probably similar to what Gosu uses in C++.
Parent - - By daIT Date 2012-07-01 03:23
The reason I was asking is because the games (or the one game?) I have seen implementing that kind of scrolling in windowed mode had an option to somehow prevent the (real, not just in-game) cursor from getting outside the window, it would just act as if the edge of the window was the edge of your screen or something.
What do you mean mouse_x/y= will work better in fullscreen mode ?
Parent - By jlnr (dev) Date 2012-07-03 11:17
I meant that the user experience will be better in fullscreen mode.

I know it is possible to restrict the cursor to a single window in Windows (forgot the function name...), but I have never seen that effect on a Mac. I don't think it is common enough to add to Gosu. It should be easy to add it for Windows via the Win32API library, though.
Parent - By Spooner Date 2012-06-29 03:18
As far as I can think, when playing in window mode, auto-scrolling usually occurs when the mouse is near the edge (or very near/over the edge in full-screen). I wouldn't implement auto-scrolling at all in a windowed game though, because it is a bit messy.

Chingu provides a wrapper for TCP/IP sockets (NetworkClient and NetworkServer, I think), though obviously that isn't too fast for a twitch game. I had some success with this in my Wrath game, so it is perfectly workable with a simple arcade game..

rENet provides a Ruby wrapper for the ENet library, which uses UDP and is significantly faster (I'm trying this in my latest game, though I haven't got too far with the networking side yet - I'll be applying the things I learned from Wrath here, I think :P )
Parent - - By ProudPops Date 2015-01-25 15:59 Edited 2015-01-25 16:28
Sorry for replying to an old post. I came across it on google while looking for a way to lock the mouse to a game window. I noticed that there weren't many answers on how to do it so I figured I would share how I got it done. I'm new to ruby, gosu and programming in general so bear with me if my code isn't the best. I had to use functions built into windows but it's actually pretty easy. I used FFI to do that but if you prefer something else that may work too.

require 'ffi'

#Create a struct class. This will be what you use to store the rectangle coordinates of your window.
class Rect < FFI::Struct
  layout :left,   :long,
     :top,     :long,
     :right,  :long,
     :bottom, :long
end

#Make a module that contains the windows functions needed to
#1. Get the handle of the game window.
#2. Get the handle of the foreground window (the window the user is using).
#3. Get the coordinates of the game window.
#4. Lock the cursor to the game window.

module User32
  extend FFI::Library

  ffi_lib 'user32'
  ffi_convention :stdcall

  attach_function :getActiveWindow, :GetActiveWindow,[], :pointer
  attach_function :getForegroundWindow, :GetForegroundWindow,[], :pointer
  attach_function :getWindowRect, :GetWindowRect,[ :pointer, :pointer ], :bool
  attach_function :clipCursor, :ClipCursor,[ :pointer ], :bool
end

#I made a class that with an update method.
#It makes sure you aren't in fullscreen mode and that it only locks the mouse when the game is the active window.
#It also only locks the mouse to the client section of the window (window - borders).

class MouseTrap
  include User32
 
  def initialize
    @window_rect = Rect.new
    @client_rect = Rect.new
  end

  def update(window)
    if !(window.fullscreen?) then
      @win_handle = User32.getActiveWindow()
      @active_handle = User32.getForegroundWindow()
      if (@win_handle == @active_handle) then
        User32.getWindowRect(@win_handle, @window_rect)
        @border = ((@window_rect[:right] - @window_rect[:left]) - window.width) / 2
        @client_rect[:left] = @window_rect[:left] + @border
        @client_rect[:right] = @client_rect[:left] + window.width
        @client_rect[:bottom] = @window_rect[:bottom] - @border
        @client_rect[:top] = @client_rect[:bottom] - window.height
        User32.clipCursor(@client_rect)
      end
    end
  end
end

#In the initialize section of you game window you can do something like...
@mouse_trap = MouseTrap.new

#In the update section you can do...
@mouse_trap.update(self)
Parent - - By jlnr (dev) Date 2015-01-25 22:25
Thanks for sharing this! Some code feedback-

You can safely delete the MouseTrap#initialize method. You can set instance variables even if they have never been used or declared in initialize.

In fact, you don't need instance variables at all :) You can simply use local variables in #update(window) (basically delete all the @ signs).

window.width is not necessarily the width of the window in pixels. If you try to create a 8000x6000px Gosu::Window, Gosu will automatically scale the window down to fit on the screen. However, window.width will still return 8000 so that your calculations stay intact. This would break your script.
You can use GetClientRect instead to retrieve the size of the window's contents in pixels.
Parent - By ProudPops Date 2015-01-26 14:28
Thanks for the advice. I appreciate it!
- - By daIT Date 2012-07-04 05:54
Alright, thank you everyone :). Since I have decided that my first little game would be a kind of RTS thingy, I'll just stick to fullscreen.

So I have been messing around with some isometric tiles and all that, and ran into another question : is it possible to use Gosu's scaling features with non-square tiles (so the tilable attribute when instanciating the Gosu::Image is no use) ? I think everyone knows what happens when stretching each tile individualy :)

I have tried to hack my way around by using the Window#record method : my idea was to record the map as one Gosu::Image and then scale that, but I found out that this actually has exactly the same effect since #record actually returns a Gosu::Macro and not a Gosu::Image.
After looking into it, I found out that the Chingu library has a "retrofy" feature that scales an image without interpolating it. That might be one way to do it, but it seemed like kind of a shame after my previous theoretically-perfect (:D) idea.

So there you go, any suggestion would be greatly appreciated !

PS: I am quite new to programming (this is actually my first "real" program), so I'm hoping my questions are not too pointless... :)
Parent - By jlnr (dev) Date 2012-07-05 06:08
I think you can just duplicate the lowest pixels of each tile so that they actually overlap a little. The CptnRuby example does this for square tiles too and it looks ok. Then you just need to draw them from the bottom up.
Up Topic Gosu / Gosu Exchange / mouse movement

Powered by mwForum 2.29.7 © 1999-2015 Markus Wichitill