Forum
You're absolutely right, but you don't have to have an account to use Pastebin. :)
Calling pygments as an external script would probably be the way to go if you really wanted to do it. I think this is what GitHub does.
I used to be pretty competent in Perl but I haven't touched it in a long time since I found Ruby. Hmm.
Oh jeeze, I'm pretty sure I've even used the attachment feature before and I completely forgot about it. Thanks for catching my mistake, sir!
On the other hand, I think Pastebin is a useful service and it can't hurt to let people know about it. :)
Oh dear, you should put your patch on
Pastebin if it's too large for a forum post. It even has syntax highlighting! For patches, even.
No, scratch that, I completely forgot about forum attachments, as Julian has pointed out.
Well, that's pretty much your one choice if you want Ruby in the browser. jRuby doesn't work too well as an applet yet.
It might be doable with Silverlight and IronRuby but it would require rewriting Gosu from the ground up, in C#, using DirectX calls instead of OpenGL. It would be a really cool project (and, for once, we'd have a good platform for browser games), but it kind of sounds like more trouble than it's worth.
Ohh, that makes more sense. Actually, yeah, that would be a really cool effect.
See the comment I was responding to for a mention of bloom and blur; I'm not sure how it would be done with this, just that it was mentioned. :P
Hmm, I'd think it would be pretty slow to do that every frame. Your best bet for bloom and blur would probably be to use a shader.
Well, you'd still need to move the sensor object, right? If you're using a "viewport" or "camera" object then I suppose you could use a CP::BB to hold the scrolling position and do something like this:
class Viewport
def scroll_to x, y
@bb.l, @bb.t = x, y
end
def visible_objects space
shapes = space.active_shapes_hash.query_by_bb @bb
magically_get_objects_from shapes
end
def apply &draw_block
$window.translate -@bb.x, -@bb.y, &draw_block
end
end
class MyWindow < Gosu::Window
def draw
@viewport.apply do
@viewport.visible_objects(@space).each { |obj| ... }
end
end
end
Perhaps I misunderstand your problem, though!
Oh, huh, using a sensor to detect which objects need to be drawn is pretty clever, but isn't there a function to do a bounding box query for that? I mean, I know the C api has cpSpaceBBQuery
. The declaration looks like this:
void cpSpaceBBQuery(cpSpace *space, cpBB bb, cpLayers layers, cpGroup group, cpSpaceBBQueryFunc func, void *data);
It would also be faster than using a rectangular polygon sensor. The only downside is that if you intend to rotate the camera then the BB query is right out—but you can also do shape queries I think?
Come to think of it, I don't know whether the Ruby bindings actually expose this or not.
Probably not unless you're making a library for a very specific kind of game world. Chipmunk uses a sparse spatial hash for its broad phase collision detection (and other spatial queries), but obviously the way it's done doesn't translate too well to a tile based game unless you're willing to calculate a set of edges from your tilemap—which is not difficult but neither is it particularly straightforward. And then most tile based games probably don't want realistic physics, so you're leaving the major focus of Chipmunk unused then.
Most game logic beyond drawing and input seems to be pretty specialised and general solutions aren't usually that useful in my experience, but maybe I'm doing it wrong.
Sounds like spatial hashing? I have used this to great success.
A joke, of course. Haskell and Ruby both have reputations for being "too slow" for this and that among people who don't use them.
Bahaha, yeah. TeX is big trouble, always. :D
Haha, that sounds like a hell of a workflow and I'm curious what it looks like. Got a screen shot to demonstrate?
Don't mind me; I'm just letting my imagination go wild here. You might say I'm addicted to bad ideas. :)
Mostly I'm just idly musing. I think it would be overkill to do anything but the simplest word wrapping algorithm in this case unless you're really, really particular about your game's typesetting. In which case, Gosu's Font class is probably not your first choice for text display anyway. :) I wonder what it would take to draw a PDF from OpenGL...
Besides, TeX itself is a massive behemoth of a system. I have the full texlive distribution with installed and it apparently weighs in at a staggering 2.13 GB. The basic version alone is 276.4 MB. I'd hate to inflict that on my audience. :) If I really wanted super-fancy typsetting in my game, I'd definitely do as you suggest and ship it pre-formatted.
As to bindings, I don't think there is a library interface, but I could be wrong.
On the other hand, you've just put some terrible, awesome ideas in my head and now I'm researching PDF rendering.
Yeah, you're right, and I doubt an RPG message box is going to need fancy TeX-style O(n**x) wrapping besides. The simple algorithm as I implemented it seems to run fast enough on a standard Lorem Ipsum text and it looks about as good as I'd expect for a game.
The real magic would be getting a fast implementation in Haskell, which I understand is also notoriously slow. ;P
I hacked together a class inspired by yours that has word wrapping and padding. Speed is characters per second. I haven't actually bothered to enforce height and it will probably hang if you enter a word that's wider than the box; I haven't tested it thoroughly.
class MessageBox
attr_accessor :speed
attr_reader :text, :font, :padding
def initialize text, options = {}
@x, @y = options[:pos] || [0, 0]
@w, @h = options[:size] || [$window.width, $window.height / 3]
@speed = options[:speed] || 40
self.padding = options[:padding] || 8
self.font = options[:font]
self.text = text
@last_update = Gosu.milliseconds / 1000.0
end
def text= text
@reveal = 0
@text = text
calculate_wrap
end
def font= font
if font
@font = font
else
@font = Gosu::Font.new $window, Gosu.default_font_name, 16
end
calculate_wrap
end
def padding= padding
@padding = padding
calculate_wrap
end
def finish
@reveal = @text.length
end
def update
old_time, new_time = @last_update, Gosu.milliseconds / 1000.0
dt = new_time - old_time
@last_update = new_time
@reveal += @speed * dt
end
def draw
x, y = @x + @padding, @y + @padding
@wrap.each do |range|
if range.last > @reveal
trunc_range = range.first ... @reveal.floor
@font.draw @text[trunc_range], x, y, Float::INFINITY
break
else
@font.draw @text[range], x, y, Float::INFINITY
end
y += @font.height
end
end
protected
def calculate_wrap
return unless @font and @text and @padding
box_width = @w - @padding * 2
@wrap = []
first_index = 0
last_index = test_index = @text.index(/\s|$/)
while test_index
if @font.text_width(@text[first_index ... test_index]) >= box_width
@wrap << (first_index ... last_index)
first_index = last_index + 1
end
last_index = test_index
test_index = @text.index /\s|$/, last_index + 1
end
@wrap << (first_index .. last_index)
@wrap
end
end
Sorry for the lack of comments. Again, quick hack. It's yours if you want it, although I'd appreciate a small credit in that case. :)
Many console RPGs don't have word wrapping! Since the text and its container are static, line breaks are hard coded. Makes editing the text later a pain, though.
The simplest word wrap algorithm is pretty straightforward but it seems like there's no good way to do it except brute force so your time complexity is probably stuck at O(n); even worse for "prettier" algorithms.
You are insane. Take this as a compliment, please.
Event Machine is really awesome but I'm afraid I haven't found a good way to integrate with Gosu. You'll have to resort to multithreading (one for Gosu, one for EventMachine) and you need to make sure not to make any Gosu calls on any but the main thread. :(
Insulting the developer isn't the best way to get what you want, sir. ;)
I don't see why it matters that the dependencies are different across platforms. I feel this is roughly equivalent to bitching about Transmission requiring Gtk and using Gnome desktop notifications on Linux, but using Cocoa and Growl on OS X, where each is the optimal solution for its respective platform but not for the other.
In the end, the goal is to have just that—the best for each platform. High-level feature parity is a nice plus, but having a common base is the big goal. How would it benefit you personally if the dependencies were the same everywhere? Libraries need to be handled separately for each platform anyway.
Well, color me curious. What sort of diabolical schemes have you got in store?
I've just remembered that Ruby 1.9 has Fibers, which are kind of like the old green threads but more awesome. Fiber#yield
and Fiber#resume
seem to do exactly what I wanted my push_state
and pop_state
methods to do. Hmmmmm, I might have to poke around.
I doubt I'll end up using this, but who knows. :)
This is why I (kind of) love Objective-C. :)
One thing: I'd recommend publishing a list of delegate methods that your delegate implements so we, the unwitting users of your library don't accidentally trample them and wonder what's going on when something weird breaks.
I think I get the gist of what you're doing, but I'm only vaguely familiar with Haskell so it's not totally transparent. My understanding is that you're doing the waiting in the callback and the inContinuationStyle function otherwise returns immediately, correct?
The no serialisation requirement wouldn't be a particular problem for me (at least not as I envision it currently) since I don't plan to serialise game states directly. The game state is created anew and it loads a map object (and later an entity list) from there.
On the other hand, I'm pursuing another route right now because continuations and two-way thread communication truly are headache fuel. I'm certainly interested to hear your ideas, though. :)
Would also be useful for (as Julian's example above) implementing dialogs that can be called synchronously. That was the main thing I wanted to do with it, actually. Something like this wholly fictional piece of code:
def button_down id
if user_clicked_set_input_button?
@button_map = call_state SetInputState
else
@button_map.do_stuff id
end
end
I suppose you could do that! But then you're basically delegating loading your images back to your owning object just like I suggested. :)
Note that this is cute, but it won't work for images loaded with Gosu::Image.load_tiles
. There's no obvious way to get around that one with a monkey patch, either, and if you do then I can promise it will be ugly. I'd recommend implementing the marshalling code in the player object and handling the image loading yourself.
Julian, you read my mind. I was just discovering for myself that clipping didn't nest and didn't respect transforms. Thank you! :D
flush and needs_cursor? are nice too! I already have a needs_cursor? callback waiting in my framework for you to release it.
Oh, and I am liking the Facebook page as we speak. My profile is pretty much empty so no real privacy concerns there.
The bigger question is actually pretty easy to answer, but difficult for me to describe. Better to show you with an example from my own code.
# Recursively tests whether +point+ falls within one of the container's
# subviews. Returns the first subview that tested positively, +self+ if
# no subviews contain the point, or +nil+ if the container does not
# contain the point.
def point_query point
if frame.include? point
# query each subview and return the first non-nil result
point -= frame.offset
@subviews.each do |subview|
found_view = subview.point_query point
return found_view if found_view
end
# fall back on self if no subview contains the point
self
else
nil
end
end
If blocks didn't behave this way, then that return statement would basically be a no op. The block would return, the enumerator would move on to the next item in @subviews
and the method would eventually return self. If I wanted to return the result of the subview's point_query
, I'd have to write something significantly nastier using a catch/throw or something. I'm sure if it worked that way I'd figure something out.
Let me know if you're not convinced this is the right way to do it. :)
Ick, that's probably for the best. I wonder if there's a cleaner way to implement it with C. It could probably be made less ugly with Apple's C blocks if they make it into the standard… Well, a little less ugly anyway.
I've discovered that some aspects of Ruby's C API are really nice, but there are some things that just make me cringe. Plus it's kind of cluttered with a lot of redundant macros and stuff that aren't even namespaced.
The tangled mess of C code? It is the implementation of ensure, straight from Ruby's source. The Ruby code at the bottom? It's a clarification of what the C code does. :)
Yeah, that's what the rb_ensure(…)
nonsense is that I posted below the problem code. I guess I forgot to change the topic after I peeked at Gosu's source. :D
For the curious, this is its signature in Ruby 1.9.2:
VALUE rb_ensure(VALUE(*)(ANYARGS),VALUE,VALUE(*)(ANYARGS),VALUE);
For the masochistic, here's its source code:
VALUE
rb_ensure(VALUE (*b_proc)(ANYARGS), VALUE data1, VALUE (*e_proc)(ANYARGS), VALUE data2)
{
int state;
volatile VALUE result = Qnil;
PUSH_TAG();
if ((state = EXEC_TAG()) == 0) {
result = (*b_proc) (data1);
}
POP_TAG();
/* TODO: fix me */
/* retval = prot_tag ? prot_tag->retval : Qnil; */ /* save retval */
(*e_proc) (data2);
if (state)
JUMP_TAG(state);
return result;
}
That "fix me" comment is a little unnerving. Anyway, from this we can at least figure out which parameters do what. If Ruby's ensure block were somehow implemented using Ruby's ensure block, it might look something like this:
def rb_ensure b_proc, data1, e_proc, data2
result = nil
begin
result = b_proc.call data1
ensure
e_proc.call data2
end
return result
end
Wanna see something messed up?
translate (@scroll_x, @scroll_y) { return }
Oops, now everything else gets translated too. Here's how to fix it.
rb_ensure(rb_yield, Qnil, hypotheticalPopTransformWrapperThatAcceptsAnInstanceOfGraphics, (VALUE)&($self->graphics() ) );
How ugly is that? :D Forgive the parentheses, but I'm never sure whether & binds more tightly than -> or not!
Nah, I don't mean it like that. Think about RAD systems for games and how they tend to have some kind of scripting language that interacts asynchronously with your game objects.
Take RPG Maker '98 or 2000, because a lot of people know them: the event editor allowed you to, say, move the player character ten squares north, rotate counterclockwise, move three squares west and then face south, and you could either wait for that action to complete or start moving another character while that action is still in progress.
That's what I mean, and it won't come 'till much later if it ever does. Don't you worry your heart about me getting mired in threads. :D
Yeah, I suppose I should just get used to doing things asynchronously. It's the wave of the future or something. :) It's just that some things are difficult to do that way.
When it comes time, I'll probably run high level game logic in a second thread and use a message queue to act on it, but I won't be interacting with Gosu directly then. This is gonna be fun.
Time to viciously rip the threads from my code! I'll keep the Worker/Task classes I created, though. :D
Well, I figured out this clever trick for game states. Think Chingu if you aren't sure what I mean by game states.
I wanted to have push_state(state)
stop execution of the current state right there and let the new state take over immediately. Then when I call pop_state(return_value)
, the original push_state
call would return whatever was passed to pop_state
to the original game state. Everybody still with me? :)
I hacked something together using callcc to save a continuation and then throw an exception to get out of the current state and move on to the next tick. After popping the top state back off the stack, it would call the continuation and do its magic. It worked beautifully.
Except that it causes a deadlock after the next tick ends because it tries to unlock a mutex that isn't locked. This is on OS X; it might work on other platforms, but I doubt it. So much for that brilliant idea! Well, callcc is dangerous and yucky anyway.
Then inspiration struck yet again: I would implement it by spawning a new thread and having push_state
block until that thread exited. The code to do it this way ended up being much cleaner and didn't rely on attaching hidden things to my game states that could get lost. I know that drawing on a non-main thread with Gosu causes things to get a little weird, so I made sure that my draw methods would always be called on the main thread. Nobody needs to switch states in draw and they shouldn't.
This worked beautifully as well. In fact, I was able to load fonts and images in my new threads and do all sorts of neat stuff. Except, actually, no, I can't load images in secondary threads either. My first game state was the only one loading images and the code that does that was being called on the main thread after all. Oops. So, I just got a segfault after modifying one of my examples in a way that caused images to be loaded on one of those other threads.
Damn and curses—my hopes and dreams are shattered. Hey Julian, any way you could make image loading thread safe? :) I'd try to hack at it myself, but I could never get the Ruby extension to build.
Weeelll, this isn't a general Ruby help forum, but I happen to know the answer since I have experience with Nokogiri. You want to call m.content
to get the text content.
Except, actually, you could replace your results << …
line with results << m.to_s
and this will give you the full link HTML.
Aha, I read it the same way Julian did, sorry!
Mostly it's just laziness on my part. I haven't bothered to learn how to distribute gems yet—I suppose I should get on that soon. :) The good news is that there's no C extension to compile so dropping the source code into your project should work.
Oh, you shouldn't have to interact with Nokogiri directly for this—it just needs to be installed because gosu-tmx uses it. That said,
the Nokogiri web site has a pretty extensive API documentation and links to pretty much any other information you might need.
Thanks, I hope it's not too confusing. I thought it was a pretty clever way of doing it, although it did make the transforms system more complex to implement. Too complex for me to get it working well on my own, anyway. :)
That's right—Gosu's drawing process is kind of different to what a lot of people seem to be used to.
Whenever you call one of the draw methods, what is actually happening behind the scenes is Gosu creates a DrawOp object that holds, references to, say, the current transformation stack, the image and whatever else you provided. This DrawOp object is inserted into what is essentially a priority queue, sorted by Z order.
After your Window#draw
method returns, or whenever you call gl { … }
, the DrawOp queue is flushed. This is when the actual drawing is done: each item is popped off the queue—starting at the back and working forward—transformations are applied and the image is drawn to the screen.
So no, nothing is actually drawn to the screen during your draw method. :)
That's good news, but I do wonder why OpenGL rendering was giving you trouble. Do you have problems with any other OpenGL applications?
Oh dear, I hadn't counted on problems with Tiled itself. It looks like you might have a bad graphics card or bad drivers, but I'm afraid troubleshooting graphics problems on Linux isn't my specialty. I had a problem like this with my Mac for a while where new windows would sometimes come up with scrambled graphics when the GPU was too hot and then the system would deadlock, but it was fixed with a firmware update later on.
My first suggestion is to try rebooting and hope for the best. If you're using a notebook, you could try propping it up on something solid to get as much clearance around the vents as possible. Double check that you've got the latest drivers too.
Other than that, I'm not sure what to do. :(
What exactly is the problem you're having with the map drawing code? Is it too slow with large maps? That problem can be solved by only drawing the tiles that would be visible onscreen.
I wrote a tile map class that loads and draws TMX maps (created by Tiled), which has the advantage that there is already a map editor that you and I don't have to write ourselves. The format is a little bloated though since it uses XML and is pretty generalised overall. It's nice, though, because you can have as many layers as you want and you can attach arbitrary properties to the map and the objects in it.
My library also supports Chingu directly if you use it, and lets you hook into the loader in a few places to integrate it with your own system if you don't. Collision detection is up to you because one size doesn't fit all, but for a console RPG it should be fairly trivial. You'll need Nokogiri to use it as is, but if you're feeling adventurous, Ruby comes with a significantly less awesome but fairly straightforward XML library of its own.
I'm afraid gosu-tmx is a little undocumented, although the example should give you the gist of how it's used—don't be afraid to ask if you can't figure it out.
You can find my TMX library on GitHub at
erisdiscord/gosu-tmx and Tiled is available from
its own web site.
Oh, and right now the drawing code is set up for pre-transform Gosu, but I intend to update it to use transformations for scrolling in the future. Anybody is welcome to submit a patch to help me along if they'd like. :D
Bahaha. I'm not sure if why's (poignant) guide is a good starting point for a new programmer since I already had experience with other languages, but it made me weep tears of joy. What a book! Yeah, I recommend reading it even if you don't need to.
As usual, I am late to the fray. It seems the forum has neglected to inform me of these new postings. :)
Hah, clever—I never thought of doing that.
Powered by mwForum 2.29.7 © 1999-2015 Markus Wichitill