Gosu::Image already allows you to read the height and width, so you don't have to save that value again.
Also, note that it might be better to save a bunch of items in an array, instead of using variable names with numbers in them.
So, you have
but you could use
instead, which would also let you use any number of different images inside of your Layer class.
As another small style note, Ruby has another
if style specifically for one-liners
so you wrote
if @xt <= -@iw then @xt = @x end
but it's also acceptable to write
@xt = @x if @xt <= -@iw
oh derp. I could have sworn I double-checked that before posting.
Yes, you are right. I always mess that up.
Sorry, sometimes I forget the Windows terminology for things.
Ah, sorry, my mistake. I guess I didn't understand how #update_interval works as well as I thought I did. Yes, that sounds like a fine idea.
(Sounds like my post was still somewhat useful, so at least there's that.)
Yes, my code is just a interface tweak over the raw functionality.
However, you can turn local-space coordinates to world-space ones using CP::Body#local_to_world(vec). This will take into account the position and rotation of the body. Totally already part of Chipmunk :D
(I should probably at least consider adding iteration over the world-space coordinates as well.)
You can get the vertices of any
object by using
is the index of the vert you want to retrieve. You can see how many verts there are by using
This interface is taken directly from the C API, and as such is very clunky and extremely un-Ruby-like.
I plan to submit a patch to the Chipmunk repo eventually with my interface modification to make this much more pleasant
(but don't hold your breath :P I think I've been saying that for at least a year now)
If you want some clean interface goodness RIGHT NOW feel free to use this monkeypatch:https://gist.github.com/RavensKrag/f64eae75de5e4eb68378
That's the code I wrote, and have been using in my projects.
It defines various names for iterators over the vertices in a Poly object.
Feel free to use whatever interface feels the most natural to you.
Chipmunk expects a fixed timestep, and the simulation can degrade rapidly if the timestep is not fixed.
This is related to the compounding error of the integration solver. The Euler method assumes that the error will level out when taking fixed steps of small size. But when the steps start to get large (which is possible when the timestep is not fixed) then things can get weird.
This is the canonical article on the subject, but it can indeed be a bit confusing.http://gafferongames.com/game-physics/fix-your-timestep/
The takeaway as I understand it is that you should think about how the physics system will degrade as the game starts to lag, and not just about how the game will run in the best case.
The general problem of conversion between screen coordinate-space positions and surface coordinate-space positions is called 'mouse picking'
Hopefully that helps you out some.
It sounds like what you want is something like a layer mask from Photoshop.
I'm not sure specifically how you would do this with Gosu-related libraries, but the general technique goes like this:
* Make a black and white image. Think of black as "off" and white as "on". This is your mask. It should be the same size as your main image (ie, the part behind the mask)
* Start with a fully black mask.
* Color the paths you want to trace out in white
* Take your main image
* Render the main image such that:
1) the pixels corresponding to BLACK pixels in the mask are simply the pixel data from the source image.
2) the pixels corresponding to WHITE pixels in the mask are transparent
(you might have to flip the notions of "off" and "on" around depending on how you choose to implement this)
The specific technique I've described is called an alpha mask. If you use only pure black and pure white, that's a 1-bit alpha mask. If you used various shades of gray, you could get many levels of alpha transparency, which would let you get some anti-aliasing (as mentioned by RunnerPack).
Combining the mask with the image should be a simple task for a shader, but you might need something like Texplay to generate the actual mask.
I think you may have to install
. I don't think that comes standard with Ubuntu, but sometimes you end up installing things that list
as a dependency, end up having it when you need it (especially when you do a lot of programming)
if you need it, just grab it through apt:
>: sudo apt-get install curl
As a note for anyone who comes here in the future from the wiki, and wonders why they would want to go through the trouble of installing ruby this way (using RVM) rather than the "standard way" (installing the package through using apt-get):
RVM allows you to install multiple versions of Ruby in a sane way. For example, If you want to start with 1.9, and then move to 2.0 later, then RVM may be a cleaner solution than using the packages in Ubuntu's repository.
Why? Because Ubuntu's packages (as well as the Debian packages they are derived from) pack different versions of Ruby under different packages. This means that you would call
ruby20 rather than just calling
ruby. If you would rather not have to think about the version number every time, using RVM is a good choice.
RVM will also change out the gems for you, so when you switch to using 1.9, one set of gems will be active, and when you use 2.0 (or some other version) a separate set with be used. This is especially useful when you try to upgrade to a newer version of Ruby, only to realize that the gems you need aren't updated yet. With RVM, it's super easy to just go back to using your old setup.
Maybe you need to add the bundler executables to your PATH?
I'm not really sure how to do that on Windows, but I think the other people here should be able to help you with that part.
Have you tried running
bundle in a terminal, just to make sure that everything is working correctly?
Maybe it would be better to have an option to lock the cursor to the window instead?
With these things in mind, I will return to your questions:
I'm going to answer #3 first, because #2 is dependent on #3
In the coordinate system I tend to use, verticies should always be specified clockwise. If you would prefer to use a y+ DOWN coordinate system, (as is consistent with Gosu's coordinate system) then yes, the verticies should be specified counter-clockwise. In either case, the verticies should be specified in order of decreasing rotation. CW / CCW is relative to the coordinate system you use the interpret the data, but the direction of positive rotation is determined by Chipmunk. It makes assumptions about rotations, sometimes referred to as the "handedness" of a coordinate system (as in "right handed" or "left handed"), to return correct signage for things like the cross product.
I think when you say "bottom-left vertex" you are using the same coordinate system as the one I tend to use with Chipmunk. However, I believe the tutorial uses an y+ DOWN coordinate system. This means the first vertex is actually the TOP LEFT point. In general, the top-left of an image is the origin of that image (this applies to all image formats that I know of, not just Gosu::Image objects). Thus, the top-left is generally specified first, simply because it is the origin.
The coordinate systems are tripping you up again.
Here's a diagram which explains how the example lists verts for the shape of the ship:
[ATTACHED BELOW, can't figure out how to inline at proper size]
What we're going to do is rotate the shape so that it is correct in Chipmunk coordinate space, and then transform the data such that the sprite can be rendered correctly in Gosu coordinate space.
In the end, the ship ends up rendered on screen pointing up, because the sprite is being drawn with a rotation of 0 degrees in Gosu coordinate space (see first diagram for refresher).
However, UP in Chipmunk coordinate space (again, we're assuming y+ DOWN) is 3 PI / 2. We thus want
@player.shape.body.a == 3 * Math::PI / 2. This means rotating the ship a quarter turn CCW from it's initial orientation of 0 radians. Knowing that we want the final result to point UP, and that we need to turn the body a quarter turn CCW, we must specify the verticies such that the ship points to the right in its default orientation. (Notice that RIGHT is a quarter turn CW from UP)
At this point, you may think:
"why not just rotate the body BEFORE the verticies are applied?"
That's unfortunately not how this works.
This is another case of coordinate space conversion.
The shape verticies are specified (and stored) in a coordinate space relative to the body. In order to evaluate collisions, all shapes are converted to global coordinate space. In fact, Chipmunk actually exposes
local2world if you ever need to convert between those coordinate systems.
Thus, you can't simply rotate the body ahead of time, because that rotation is not applied until the shape verticies are converted from local space to world space. This conversion needs to done repeatedly inside of CP::Space to account for both the rotation and translation of objects.
But the heavy-lifting behind that is why you're using Chipmunk :D
Switching between coordinate systems can be really confusing, and confusion causes bugs. Thus, I once again recommend that you write methods to perform coordinate space conversion, rather than writing it out each time. It's not just because you're a beginner. I still get tripped up by this stuff sometimes.
(Also, man. I had forgotten how bad that tutorial is. Ugh.)
The problems you describe in #2 and #3 have to do with differences in coordinate systems. This is something that the current tutorial does not explain very well at all. I certainly struggled with it myself when I was getting started.
Please feel free to ask questions. This is the first time I've tried explaining the notion of coordinate systems.
(Hopefully I'll compile this info along with some other stuff into a proper Chipmunk tutorial when I have more free time)
This first part is an explanation of how coordinate systems are relevant to this problem.
The second post (right under this one) uses this information to answer your questions.
Take a look at this diagram.
[ATTACHED BELOW, can't figure out how to inline at proper size]
The illustration of Gosu's coordinate system is how the Gosu window is set up. That's rather definitive (though, like most things in programming, you could alter it if you really wanted).
However, you can interpret the data from Chipmunk in various ways. Chipmunk is just a physics library. It does not really specify how data is to be visualized. I prefer to think of the positive direction of the Y-Axis as being "up", but you could interpret that data as "down" if you wanted to. (In particular, the tutorial seems to use y+ DOWN, so I have illustrated both.)
In fact, specifying y+ DOWN may make combining Gosu and Chipmunk more straightforward. If you look at the diagram, you'll notice that the three differences between these coordinate systems are:
1) y+ DOWN (vs) y+ UP
2) positive rotation clockwise (vs) positive rotation COUNTER-clockwise
3) 0 is UP (vs) 0 is RIGHT
Points (1) and (2) are linked.
When you flip your interpretation of the Chipmunk Y-Axis, your interpretation of positive rotation direction with be altered as well. PI/2 is always attached to the Y+ axis, regardless of where that may lie. Same goes for any other axis and angle measure pair.
Even after interpreting both Chipmunk and Gosu as y+ DOWN, you will find that the 0 angle measures will not match up. They will always be out of sync by a quarter turn.
However, you can't just change your interpretation of which angles are associated with which axes. Doing so would mean the numbers Chipmunk gives you concerning rotations would cease to make sense. Chipmunk's internal math assumes a coordinate system with a certain angle and axis relationship (I'm not sure of the formal term for this).
I suggest implementing some sort of method to allow for easy conversion between Chipmunk's coordinate space and Gosu's coordinate space (and vice versa) so that it is always clear that a coordinate space conversion is happening, and not some other sort of angular math.
I will assume you understand the difference between angles and radians, and can convert between the two appropriately. The specifics of how you want to write the conversion methods are up to you. Do you want to create methods like radians_to_degrees(angle), or will you monkey-patch Numeric to provide Numeric#to_degrees and Numeric#to_radians. Do you want conflate conversion between radians and degrees with the coordinate space conversion? Or do you want to keep those two ideas separate? There are many choices to be made at this point, but I'm not certain there is a "best" answer. It seems like more of an issue of personal coding style.
I can confirm that the "older" versions of Gosu have this problem, but the newer SDL2 builds do not.
This is one of the reasons I am most grateful for the 8.0 pre release :D
In case MJoergen (or anyone else) is curious as to why this effects only linux: this has something to do with how shift+letter used to be handled on linux. IIRC, It was basically just "take the lower case letter and make it a capital" which made generation of special characters impossible. # is not actually "capital 3" in any sense, although it is shift+3 on a QWERTY layout.
If you want to follow the discussion that was had about this, start by following this link:https://github.com/jlnr/gosu/issues/61
(links to issue 55 where the real meat of the problem is)
From just looking at the video it seems like you're problem is with the turn rate of the ship. It seems to have a slight acceleration to it, and the entire rate of turning seems a bit slow (in terms of angle measure per unit time). But I couldn't say if that's actually bad in the context of the game, as I haven't played it yet. It's certainly something that could make a game feel sluggish, though.
Or maybe the video (or just it's playback) smooths out things a little? I don't see any problem with frame stuttering. (Note that youtube caps at 30fps)
Could you post some screenshots? Or perhaps tell us a bit more about what the gameplay is like?
It's not a huge deal just to download and run the game to find out, but it would make a better first impression.
Sorry for taking many months to respond, but I would like to confirm that this does fix my problem as well.
Ok, I'm gonna give you some tips on code organization and style. I'll try to come back to the actual content of your code tomorrow, as it's pretty late where I am right now, and I should be getting to bed soon. Just some stuff I wish I had learned sooner. Maybe you already know this stuff, and you're just rushing the code a bit to prototype fast.
As an organizational tip, I personally recommend copying Gosu's convention and giving each object you create #update and #draw methods. This will make it clear what phase of the game calculation you are in. I recommend never getting mixed up between what is rendering / display logic and what is world state logic. You seem to be confusing the two a lot in your code, which can be dangerous if you're not careful.
In a similar train of thought, separate files for separate classes can be helpful, as you can easily jump to different classes by switching files.
Keeping everything in one file is sometimes really great for prototyping though.
You're creating a bunch of variables in Window#initialize that all start with @star. That's a pretty good indication that you should be creating a new class called Star.
For one-liners with if statements, I think that
run_this if condition
makes for cleaner code, as opposed to the
if condition then run_this
style you're currently using. It's just a matter of taste though, as both do the same thing.
But the style I propose only works for one-liners, while the style you're currently using works for multi-liners as well, so it's more versatile.
You don't seem to understand what attr_reader / attr_accessor does, as you used it in one place, and not in others. I think that's a question that has already been answered better in other places on the internet, so I'll let you figure that out yourself.
One last note:
Don't be afraid to run your code after each small step of implementing something new. That will allow you to see what works and what doesn't. It looks like you wrote this code all in one go, without running it. I say this because you've defined a method #button_down(id) inside of Window#update. I'm not sure if that's even valid ruby syntax.
I'll try to answer your second question. Not just in terms of giving you a path to the solution, but walking you through the process of developing your own solution.
What does it mean to be on the ground? What qualities would make that state different from flying?
The most obvious one is that if you're on the ground.
Another way of saying this is that you are colliding with the ground.
How do you know you're colliding with something?
That happens when you're pressed up right next to it.
In games there's two main ways of solving this problem:
You can figure out what "right next to you" means.
This generally means figuring out your position, and then the position of the thing you're possibly colliding with.
When the distance between the two is small, then they are adjacent.
Tile-based games make this concept easier, because you can simplify this into just checking the adjacent tiles.
The other way is the way physics engines work. It's more complicated, but much more powerful. You don't necessarily need to know how to implement a system like this, just understand how it works, and find a physics library to use.
You need to realize that every game is a series of discrete states, much like the separate frames in an animation. This means all objects must have a definitive position on each frame. Most of these positions are good, but you never want to display a frame where one object is inside of another. So, you move the objects in your game a little bit each frame. Then, if your logic generates a frame where two objects would overlap, you move them apart BEFORE you go to actually render that frame. Thus, the player never sees the misstep. It is only something momentarily stored in the game's internal state.
The first part is called collision detection (fairly easy) and the second is collision resolution (a little trickier).
A bit long, but I hope that helps.
hmmm.... it seems ok to me.
Have you tried defining #button_down(id) and #button_up(id) instead of using the Window#button_down?(id) method? The two should be equivalent, but maybe there's a bug or something?
class Window < Gosu::Window
if id == Gosu::KbUp
What key are you trying to use to start the game?
Using ruby 2.0 results in the application running for a longer period of time (not timing it, but it feels like it runs longer) but then crashing with a different error.
(some sort of error on Gosu::Text this time, rather than IO)
ruby backtrace: https://gist.github.com/RavensKrag/8074047
I'm starting to suspect that it's not actually the custom code DIRECTLY, but some weird side effect that's intersecting with other systems.
(I'm still extremely confused though.)
I thought Gosu didn't work with 2.0, but apparently I was mistaken (or it's already been fixed?). I'll try that then. I think I'm using a couple things that were introduced in 1.9.3, so 1.8 probably won't work (could be wrong though).
The program involves manipulating objects with the mouse. You need to grab one of the red circles it spawns (hold right click) and then shake it violently for a few seconds.
(Weird, but rather consistent.)
Letting it sit may work, but this is my procedure for triggering the behavior.
This code will be public, but it's not on github just yet. I'll let you know when I get it up, but it could be a while, what with Christmas coming and such. It also depends on a custom input library I wrote (pure ruby, so it should run on anything) so I have to figure out if I want to vendor that through rubygems.org or just ship it through the repository for this application.
Testing with ruby 2.0 now, will report back with findings.
Maybe IO is involved because I'm doing some input stuff while the crash is happening? It may be an intersection of this code with some other things, but definitively, the crash goes away if I remove this code.
Strangely, disabling GC seems to have no effect (I'm using GC.disable, hopefully that's correct? Haven't done this in a while)
but forcing GC using GC.start before the block seems to eliminate the error.
Also, sometimes I just get this error, instead of a full explosion:
/home/ravenskrag/.rvm/gems/ruby-1.9.3-p448/gems/gosu-0.7.50/lib/gosu/swig_patches.rb:37:in show': method
call' called on terminated object (0x0000000190cb98 flags=0x0 klass=0x0) (NotImplementedError)show'
Don't think that's very helpful though....
Will post back when I manage to get it to blow up again
(stupid sporadic errors D:)
Thanks in advance for your help :D
Section of code that causes crash:https://gist.github.com/RavensKrag/8050038
Dump of all the errors:https://gist.github.com/RavensKrag/8050151
Is there some bug with custom gl code?
I just wanted to try and approximate a circle using OpenGL, so I thought I'd just whip out a triangle fan and be done with it. Something has gone really screwy, my program seems to crash randomly. When this code is commented out, I have no problems, so it seems like the error is here somewhere.
IIRC, #update generally happens before #draw, but #draw can also happen as the OS demands.
So sometimes you get things like
but not necessarily every frame.
This is one of the reasons why you don't want to do any game logic in the #draw method, only rendering logic.
You might want to look for a way to get gamepad inputs using Ruby that's not related to Gosu.
Gosu's input system is extremely minimal, so it doesn't handle stuff like this. But that doesn't mean there's not some other library that could help you. That being said, I do not know of one. There are certainly many C/C++ libraries that do stuff like this though.
(If anyone manages to find one, I would like to know. Don't want to have to write my own =/)
Can't speak for OSX ,but automating these things on Ubuntu as well as Windows isn't a big deal at all. That should solve the problem of user error / extra hassle of installation, without making the user install multiple Ruby interpreter setups for different Ruby games. (Not like there are a ton of those right now, but still...)
You can easily run
gem install bundler and
bundle install through a script. Or even go as far as to install ruby though apt-get (Ubuntu) or the rubyinstaller.org package (Windows).
Could probably automate the devkit install too, but I haven't looked in to that yet.
(I should really pack this up into a nice package so it's easy to deploy games this way, if people want to...)
Still, I don't think it's too much to ask the user to just install the Ruby interpreter, especially on Windows. Minecraft runs on Java, so you'd have to install Java to play it. I don't consider that a big deal, though maybe other people would disagree?
At that point, you'd only have to distribute pre-compiled Windows gems for key libraries (but many Ruby gems are pre-compiled for Windows deployment anyway, so that should be minimal effort).
I like the concept of a Space, because that way you have a collection where all the physics stuff is. You can't figure out things like "which object are in this area" without looping over a bunch of collision classes. Might as well store them all in a collection which can optimize queries by breaking up the game world into smaller bits. (Avoids looping over ALL objects every query).
Velocities are just changes in position over time, which is almost the same as moving a position by a certain amount each frame. The main difference is that you can move to thinking in real time units, instead of game ticks.
For collision testing between two objects, Chipmunk allows you to set up callbacks, which fire when objects collide.
I prefer callbacks over having to manually poll the system
(I do input parsing in Gosu::Window#button_down rather than using #button_down? as well)
but I will concede that is simply a matter of personal taste.
I think callbacks make it easier to organize code, allowing you to split up different types of collisions into separate files.
(Chipmunk callbacks are also tied to objects, so you can use inheritance if you want to :D)
Also, having a system to compute collision pairs for you removes the need to check if you're currently testing
"A1 with B1" or "B1 with A1"
both of which are the same collision, and you only want to process that collision once.
Is this true even if you use Bundler?
(I'm assuming the user has Bundler installed already, which I know is a bit of stretch.)
I suppose by "easier to use" you mean it's easier to get the sort of motion you desire?
I find the syntax of Chimpunk (at least through Ruby) to be really nice,
but I do agree that using a physics engine to do character movement or something can be tricky.
(Though I think if you set velocities instead of using forces it's exactly the same as rolling your own thing (I've never actually done that... but I'm considering it for my next project))
Alternatively, you could check if a certain amount of time has past since the last bolt:
@time_between_shots = 100
@time = 0
@time += Gosu::milliseconds
if button_down? Gosu::KbSpace
if @time >= @time_between_shots
# put code to fire off more bolts here
@time = 0
Same principle, but this way makes more sense to me personally.
This method is also framerate independent, because it uses the millisecond timer, instead of counting game ticks.
Just curious, but why are you implementing your own system instead of just using Chipmunk?
Why are the buttons for previous state and next state so far apart? "Previous" and "next" are closely related, but the Q and ENTER keys are so far apart (opposite ends of keyboard).
I would sort of understand if it was a semantic binding (you have P bound to "pause", which is semantic), but Q doesn't really convey "go back" to me.
If it's because you don't want to use the arrow keys, because they're being used in the actual games, I would suggest CTRL+LEFT / CTRL+RIGHT. Or maybe something like F7 / F8 because there next to each other, and F-keys are not used often in gameplay.
(I picked F7 / F8 specifically because on my keyboard, FN+F7 is "previous track" and FN+F8 is "next track)
You may want to consider taking advantage of Ruby's dynamic features instead of using a tagging system. Tagging is Unity's only option, because it relies on static typing, but there are other options.
Rather than have a "hurt" tag, you can simply define a method #hurt? and check based on that. More of a duck-typing approach.
@health = 5
return true if @health <= 0
g = GameObject.new
# Do whatever is necessary with the gameobject
If not all objects are going to implement #hurt?, you can check if that method exists, similarly to how you can check if an object is of a particular class. To carry on the previous example, you could use
Does adding this to your project file not work?
This is the only way I ever launch ruby files through Sublime, and it works just fine for me.
Using the real project directory, of course :P
This also assumes that the file you want to run is called "main.rb", not necessarily the file you're currently in.
I personally prefer to use a series of arrays inside of a hash. Makes for a cleaner syntax.
@gameobjects[:enemy_shot].each do |x|
@enemy_shots += 1
The tagging system might be better for finding objects multiple tags, but the strategy I use lets you easily pass a reference to a group of objects. Depends on your particular needs, I suppose.
As a separate issue, why are you iterating over all Battlers when you only want the first one to play it's animation? Why not just queue the battlers, and only process the first one?
@battlers = [Battler.new("one"), Battler.new("two"), Battler.new("three")]
@battlers.shift if @battlers.first.animation_done? # remove the first element from the queue
This is a more simplistic pattern which should accomplish the same task. It's much more readable, which will help as your codebase grows larger.
The reason your code freezes up is because there's nothing to break out of the while loop under #wait_animation. Generally speaking, trying to wait like that isn't very useful in game programming because the entire program is already a giant loop, so you can't use general looping constructs to repeat. That'll just cause your game to get stuck on one tick.
I assume you mean .deb, or debian packages. This seems totally doable :D
Though I believe Chipmunk 6 uses quadtrees by default. Doesn't really affect Ruby devs, but it's good to keep in mind.
There is an option to use the spatial hash like in Chipmunk 5 though. I think the C guys complained that the hash was too hard to optimize.
This is what Chipmunk is for.
I believe implementing any system of this sort at the ruby level will probably be too slow for a game which requires that level of complexity in collisions. Chipmunk is written in C for speed, but has a nice ruby extension :D
Only downside is that it's based on Chipmunk 5, not the new version 6.
I was just worried about efficiency, but I think it's actually a non-issue. It takes more time to clip than not, but the additional time is probably so small, that in ruby, for a 2D game, it doesn't matter.
I assume he uses the same screenname on Github, so I took a quick poke over there. Looks like slightly more than nothing at the moment. Though the idea is sure promising.
I should really get into using IRC again...
Is there any way to use load part of a Gosu::Image as another one? I know you can load blob data into a Gosu::Image, and then specify source x,y, and dimensions, but it seems like there should be simple enough to create an Image from another one, without having to go through the #to_blob interface. Parsing the blob data is rather slow, but it seems like all that needs to be done is change a few properties on the glTextureInfo thing.
Though from the current train of discussion, it seems that's not the case.
Would doing it that way be any better than just macroing a clip_to?
Is Hanmac doing a fresh port, or is he building on older stuff? I think there's a really old ruby Ogre binding, but it's old and incomplete.
I've been thinking of wrapping part of Ogre actually, but I'm not sure if it'd be better to work with a good deal of C++ and just use ruby to control big chunks, or if a full-on wrapper would actually be worth it. Regardless, thanks for making me aware of such a thing :D
Powered by mwForum 2.29.7 © 1999-2015 Markus Wichitill