Not logged inGosu Forums
Forum www.libgosu.org Help Search Register Login
Up Topic Gosu / Gosu Showcase / Early Version of KUnits Gosu
- - By kyonides Date 2017-09-23 03:35 Edited 2018-03-03 00:17
KUnits Gosu

This is a project I originally started on another game making software but later moved to Ruby Gosu once I felt comfortable enough with it. Below you can find my original script namely Gem Roulette where you can make that wheel spin like crazy and get some prize if any. It's a demo filled with features like working traditional or creative menus, map scrolling, teleporting, event collisions, buying items at a local shop, etc.




DOWNLOAD SECTION

MEDIAFIRE

MEGA
Parent - - By kyonides Date 2018-02-07 01:58
This topic is linked to the following Slowdown during state switching step because it really suffers from strange delays... I'm posting this comment just to let you know, guys.
Parent - - By lol_o2 Date 2018-02-07 03:01 Edited 2018-02-07 03:37
You should've said earlier that it was this game. I visited here after your post on slowdown topic, but for some reason I didn't notice the demo download button then XD

Anyways, I finally got to try this game and seek the issue. First problem I encountered was missing bgm directory in your demo, so I had to supply placeholder file.
After booting the game, I already encountered a M A S S I V E slowdown in menu. Every time I change cursor position, there's a 1-2-second lag. Not sure if the demo is outdated, or you didn't even notice the issue (unlikely).
I traced the problem and the source was update_cursor method. Digging deeper, you call update_string_colors each time you change index. Now, this method is interesting. Your update colors creates new texts every time, instead of just updating your color. And the texts are actually of Text class, which derives from Gosu::Font. So... every time you change position, you create 5 new texts just to change color, but these texts actually create a new font instance, reading file each time and processing everything. This is... terrible. I hope that this version is really outdated and you fixed the issue, because I can't imagine you thought it's alright.

A rule about loading a resource each time: DON'T DO THIS. Don't create new fonts, new images or new music files. Don't make classes that inherit them, unless you use them as resources, not... texts. You should cache your resources, so everything you need is loaded exactly ONCE.

On the topic of your state slowdowns, I didn't dig into the code deeper yet (actually, I'm writing all this without going past title screen), but I suspect that you repeat the same mistake everywhere. So when you load map, you load each image/bgm again each time. If that is the case, here's a method that should help you:
def img(name)
  $_images ||= {}
  $_images[name] ||= Gosu::Image.new(name)
end

I think I posted it somewhere already, but probably it wasn't for you.
Basically what this method does is load an image and store in memory for later use. So when you want to access an image, you just call img("the image you want to use") and it will be automatically loaded first time you use it and all subsequent calls will be super-fast. If you make it accessible in global scope, you will save yourself a hassle for creating variables for each image (like you do right now with samples). Obviously, this method can be modified to be used with music, samples and fonts, which I really recommend you to do. And replace every Image.new() in your code with img(), same with music and samples, and that should aid your problem.

EDIT:
Yeah, I was right. I pasted my img method into your game and did CTRL+H on additions.rb, replacing Gosu::Image.new with img. This alone cut map transition time by ~3/4. You should make a method to cache tiles too, so you call Image.load_tiles only ones for each spriteset/size. Basically, the game suffers from bad resource management.

Well, sorry, seems like you had this issue going for months, but I was able to identify it and find a fix in 10 minutes after running your game. This should've been solved long time ago :/
If you have any more problems just ask here.
Parent - - By jlnr (dev) Date 2018-02-07 08:34
Great analysis! I think the performance behavior of Gosu::Font can be a bit unintuitive because other toolkits cache fonts internally. What Gosu's font does is basically call Gosu::Image.from_text('a'...) once for each letter that is used, and these letters are then cached per Font instance. So yeah, don't re-create fonts if you can at all avoid it, otherwise every letter will have to be rendered again.

I always feel I should document these things better, but I'm not sure where. RDoc? GitHub wiki? :/
Parent - - By lol_o2 Date 2018-02-07 12:34
I'm not sure if this is necessary. The delay when loading image or song is really noticeable, so one could assume Font works the same. In kyonides' case it's just less obvious, because he makes a Font subclass and calls the constructor by using super.
Parent - - By kyonides Date 2018-02-08 04:57
Actually a version I modified later on does include a Cache module that should work like your $_img global variable by creating a specific map or sprite cache of sorts. Perhaps if you could test it including the five script files I included on the support topic you could tell me if I could not solve the issue because I had overlooked it somehow :(
Parent - - By lol_o2 Date 2018-02-08 11:48
Well, your Cache module seems alright, but in the files you provided you use it only for bgms. Obviously this should be done for e.g. images, so you don't load anything twice etc.
For example this:
def backdrop(filename) Gosu::Image.new('images/backdrops/' + filename + '.png') end
Should become this:
def backdrop(filename) Cache.images[name = 'images/backdrops/' + filename + '.png'] ||= Gosu::Image.new(name) end

Also, I'd suggest you to make your own methods in cache module instead of using default readers, to make usage more comfortable:
@bgm = Cache.bgm(name)
looks better than
@bgm = Cache.bgm[name] ||= Gosu::Song.new(name)
Matter of preference though.
Parent - - By kyonides Date 2018-02-09 01:17
I have posted an updated version of KUnits Gosu, including a lot more cache stuff I had been coding in the last few months. I guess it is faster than usual, but I am unsure if that's good enough :(
Parent - - By lol_o2 Date 2018-02-09 20:12 Edited 2018-02-09 22:19
I found two more problems. First, as I said in the beginning, Text class CAN'T inherit Gosu::Font, because that's ultra expensive when you create new texts. Instead, make text and font separate and cache your fonts like other resources.

If you want to do this REALLY quickly without changing functionality at all, here's a little hack:
def get_font(*args)
  @@fonts = {} unless defined?(@@fonts)
  @@fonts[args] ||= Gosu::Font.new(*args)
end
 
def text_width(*args)@font.text_width(*args)end
def height(*args)@font.height(*args)end
def draw(*args)@font.draw(*args)end


Add these methods to Text class and then in initialize
replace super(temp_height, name: @name)
with this:@font = get_font(temp_height, name: @name)
Keep in mind that this is a hacky code, you will probably want to do it in different way, because you have your own coding style. However, using it this way, it removes menu lags and speeds up map loading, because you are creating texts for labels each time.

Now, another problem is KUnitsWeather class. When changing maps, or doing transitions in general, I noticed a 162 (for me) millisecond delay that shouldn't be there. After narrowing the problem, this whole time is spent inside KUnitsWeather initialize method, more particularly the loop that creates new sprites (now I know why it took forever without caching images btw). You needlessly initialize the sprites each time. A little optimization would be skipping creating sprites if the new weather is the same as the old one. So don't create new weather object each time if you don't need it.
As previously, here's a little hack of mine (sorry, but I normally don't write code like this XD):
$sprites ||= []
@max.times {|i| x, y = rand(300..1200) - 300, rand(100..808) - 650
y += 1 if y.odd?
$sprites << Sprite_Icon.new(x, y, @names[@type], z: 1050) } if $sprites.empty?
@sprites = $sprites


Obviously you'll want to make it in a different way, but adding this will make map transitions instant. I N S T A N T.

Glad I could help ;)

EDIT:
btw, if you want to avoid delays even more (e.g. when you open a menu for the first time etc.), you could pre-load all your resources into cache at start. So, loading screen. Game will work much smoother then.

EDIT2:
Also, menu cursor feels unresponsive. Nothing important, but when I press e.g. down in main menu, I expect the cursor to move right away. There seem to be a few frames of delay though,  which might need tweaking in Input module. But at least it doesn't come from resource loading (when you finally fix Text class).
Parent - - By kyonides Date 2018-02-11 04:59
I know what you said earlier about fonts, but I wonder if it really lets you update a font's contents when you change stuff like its dimensions or the text itself. Won't I find weird stuff on my screen after caching those fonts? O.o?

By the way I could not make waterdrops fall adequately. After a few cycles you may notice there is a large gap that keeps growing and growing...
Parent - - By lol_o2 Date 2018-02-11 12:03 Edited 2018-02-11 12:28
You only need fonts for different sizes, each text doesn't require new Font. Like jlnr said, think of fonts as small images for each letter. Loading font is creating these images, but displaying text just draws them in a specific order. So you cache only Font instance, but you can change the text as you like, because you specify it only in font.draw.

As for weather:
def increase_xy(nx, ny) @x, @y = (@y.between?(608,660)? [@base_x, @base_y + (@y - 608)] : [@x + nx, @y + ny]) end

Your problem is that you are teleporting flakes/drops at constant position. So e.g. when it falls 16 pixels below screen, it's leveled to 0, instead of appearing at 16 pixels from the top. The line above fixes this behavior.
Also, the reason you provided is very poor excuse for creating the weather so often. What if players spends some time on one map? The gap will appear anyway, and causing artificial delays to aid it temporarily is not the solution.
Parent - By kyonides Date 2018-02-12 02:47
It was a mess, caching Text or Font the way you suggested provoked weird just as I had foreseen, either the color did not match or the height... The main reason why I hate Font the way it is would be the impissibility to change the font height. That was the motivation I had to implement Text without caching it at all. Now I need to modify Gosu::Font to become similar to text without the recreate method. The window Ruby file is quite old indeed, the original file was written when Gosu had reached version 0.7 or so... :P
Parent - - By kyonides Date 2018-03-03 00:20
Well, I finally implemented a system to let my map events include more player interaction than just automatically opening a new scene. Now it lets the player read a conversation before switching scenes. :) I know, other people have achieved such a simple thing with ease, but I just could not make up my mind to come up with my own implementation :P
Attachment: kunitsgosulinux10.png (67k)
Attachment: kunitsgosulinux09.png (64k)
Attachment: kunitsgosulinux08.png (62k)
Parent - - By kyonides Date 2018-04-08 02:09
Well, I have updated my KUnits scripts and resources, but I faced a weird issue while working with the Image#subimage method... :S Nope, it won't make the game project crash at all. :P
Parent - - By kyonides Date 2018-04-10 22:50
I think you had download an outdated version from mediafire, the other day I only had uploaded RAR files to mega :P

Anyway this time I have uploaded new demos to both websites, plus I do think I have come up with a sprite script that might not be affected by subimage method the way CompositePictureSprite does. I even dared to call the new class the Gauge Sprite.
Parent - - By lol_o2 Date 2018-04-11 00:31
Wait, you are replying to me, right? In another topic? XD

I got the newest version then, but you updated it again. Well, the new version has the problem with music again. Why don't you just upload it too?
Parent - By kyonides Date 2018-04-11 18:25
Just edit the Audio.state variable by setting its value to false or nil. :P
Up Topic Gosu / Gosu Showcase / Early Version of KUnits Gosu

Powered by mwForum 2.29.7 © 1999-2015 Markus Wichitill