I'm building this popup countdown timer for a game. The issue is I can't figure out how to update the the animate so that the display changes too. It works so far, but you can't see the numbers changing. It blends into the 00:00. I'm pretty positive it works so far just having trouble with this change. This is done with green shoes. Any ideas what I'm doing wrong here?
#Timer button used for creating a countdown timer for the game.
#Game ends when timer is zero.
flow width: 80, height: 0.2 do
button 'Timer', width: 1.0, height: 1.0 do
window do
def time_change!
#clock = '%02d:%02d' % [#second / 60, #second % 60]
if(#second == 0)
alert "game is over"
#clock = '00:00'
close()
para #clock, size: 50, stroke: black
end
end
background whitesmoke
#clock = '00:00'
para #clock, size: 50, stroke: black
#second = 10
animate(1) do
#second -= 1
time_change!
para #clock, size: 50, stroke: black
end
end
end
You can replace the text of the current para which displays the clock:
Shoes.app do
flow do
button 'Timer', width: 100, height: 50 do
window width: 200, height: 100 do #Open a child window when the button is clicked
seconds = 3
tenths = 0
clock = '%02d:%02d'
flow do
#p = para clock % [seconds, tenths], #Assign the clock para to an instance variable,
size: 50, #which will make the variable visible outside this block.
stroke: black
end
a = animate(10) do #Upate the clock every 1/10 of a second.
tenths -= 1
if tenths < 0
tenths = 9
seconds -= 1
end
#p.text = clock % [seconds, tenths] #Replace the clock text.
if seconds == 0 and tenths == 0
a.stop
alert("game over")
close #=>self.close where self is the window whose block contains this code
end
end #animate
end #window
end #button
end #flow
end #app
To verify that the clock is actualy showing each time increment, you can slow things down by changing animate(10) to animate(1).
Related
I am working on a ruby program using Gosu. I want to display the number of mouse click times every time I click on a button on the screen. Please help me with this. Thank you so much
require 'rubygems'
require 'gosu'
module ZOrder
BACKGROUND, MIDDLE, TOP = *0..2
end
WIN_WIDTH = 640
WIN_HEIGHT = 400
class DemoWindow < Gosu::Window
def initialize
super(WIN_WIDTH, WIN_HEIGHT, false)
#background = Gosu::Color::WHITE
#button_font = Gosu::Font.new(20)
#info_font = Gosu::Font.new(10)
#locs = [60,60]
end
def draw
Gosu.draw_rect(0, 0, WIN_WIDTH, WIN_HEIGHT, #background, ZOrder::BACKGROUND, mode=:default)
if area_clicked(mouse_x, mouse_y)
draw_line(50, 50, Gosu::Color::BLACK, 150, 50, Gosu::Color::BLACK, ZOrder::TOP, mode=:default)
draw_line(50, 50, Gosu::Color::BLACK, 50, 100, Gosu::Color::BLACK, ZOrder::TOP, mode=:default)
draw_line(150, 50, Gosu::Color::BLACK, 150, 101, Gosu::Color::BLACK, ZOrder::TOP, mode=:default)
draw_line(50, 100, Gosu::Color::BLACK, 150, 100, Gosu::Color::BLACK, ZOrder::TOP, mode=:default)
end
Gosu.draw_rect(50, 50, 100, 50, Gosu::Color::GREEN, ZOrder::MIDDLE, mode=:default)
#button_font.draw_text("Click me", 60, 60, ZOrder::TOP, 1.0, 1.0, Gosu::Color::BLACK)
#info_font.draw_text("mouse_x: #{mouse_x}", 0, 350, ZOrder::TOP, 1.0, 1.0, Gosu::Color::BLACK)
#info_font.draw_text("mouse_y: #{mouse_y}", 100, 350, ZOrder::TOP, 1.0, 1.0, Gosu::Color::BLACK )
if Gosu.button_down? Gosu::MsLeft
index =0
button = area_clicked(mouse_x, mouse_y)
case button
when 1
index+=1
#info_font.draw("Times Click: #{index}", 370, 350, ZOrder::TOP, 1.0, 1.0, Gosu::Color::BLACK)
end
end
end
def needs_cursor?; true; end
def area_clicked(mouse_x, mouse_y)
if ((mouse_x > 50 and mouse_x < 150) and (mouse_y > 50 and mouse_y < 100))
return 1
else
end
end
def button_down(id)
if id == Gosu::KB_ESCAPE
close
else
super
end
end
end
DemoWindow.new.show
Below is the code I have added. When I click on the button, it only displays the number of times click is 1, however, I need it to display the number of times I clicked on.
This is because you're setting index back to zero every time the mouse is clicked (index =0). You should probably set your index to zero in your initialize function, and make it a class variable (add # to the front).
Then your initialize code would be:
def initialize
super(WIN_WIDTH, WIN_HEIGHT, false)
#background = Gosu::Color::WHITE
#button_font = Gosu::Font.new(20)
#info_font = Gosu::Font.new(10)
#locs = [60,60]
#index = 0
end
and the code for the mouse click would be:
if Gosu.button_down? Gosu::MsLeft
button = area_clicked(mouse_x, mouse_y)
case button
when 1
#index += 1
#info_font.draw("Times Click: #{#index}", 370, 350, ZOrder::TOP, 1.0, 1.0, Gosu::Color::BLACK)
I want to make a shape in gosu to have a border when a mouse hovers over it.
Gosu.draw_rect(50, 50, 100, 50, Gosu::Color::GREEN, ZOrder::TOP, mode=:default)
I expect the output, the shape will have a black border around it when the mouse cursor hovers over the rectangle
You can add a check in update routine.
def update
if mouse_over?(50, 50, 150, 100)
Gosu.draw_rect(50, 50, 100, 50, Gosu::Color::GREEN, ZOrder::TOP, mode=:default)
end
end
def mouse_over?(px1, py1, px2, py2)
mx = mouse_x
my = mouse_y
((mx >= px1) && (my >= py1)) && (mx <= px2) && (my <= py2)
end
mouse_x and mouse_y are variable provided by Gosu.
HERE MORE INFO...
I'm building a simple calculator in Ruby using Green Shoes, a graphics toolkit. This calculator should work similar to the standard Windows Calculator, with the ability to perform */+= functions on integers and decimals (fractions) and output values rounded to the 100th place.
So far, the calculator can add/subtract/multiply/divide integers and output integers. For example, 6/5=1, 8/3=2, and 1/2=0. The is the first issue, as I want the calculator to output values rounded to the 100th place.
The second issue regards inputs, as calculator does not currently recognize floating points when entering value. This is probably due to the fact that I haven't assigned any variables/functions to my . decimal button.
My code is as follows:
require 'green_shoes'
Shoes.app(title: "Ford's calculator", width: 200, height: 260) do
number_field = nil
#number = 0
flow width: 200, height: 260 do
flow width: 0.7, height: 0.2 do
number_field = para #number, margin: 10
end
flow width: 0.3, height: 0.2 do
background rgb(232, 161, 0)
button 'Clr', width: 1.0, height: 1.0 do
#number = 0
number_field.replace(#number)
end
end
flow width: 1.0, height: 0.8 do
background rgb(50, 205, 50)
%w(7 8 9 + 4 5 6 - 1 2 3 / 0 . = *).each do |btn|
button btn, width: 50, height: 50 do
case btn
when /[0-9]/
#number = #number.to_i * 10 + btn.to_i
when '='
#number = #previous.send(#op, #number)
else
#previous, #number = #number, nil
#op = btn
end
number_field.replace(#number)
end
end
end
end
end
So my questions are as follows:
What do I need to add to my code to make the app INPUT floating
points in terms of capturing variables?
What do I need to add to my code to make the app OUTPUT numbers
rounded to the 100th place instead of rounding to whole numbers?
Thanks in advance! And if there's any clarification you guys need in re: requirements, etc., let me know!
To convert a String to a Float:
"3.41".to_f # 3.41
#input = #input.to_f # Convert String #input to a Float
To print a number with max x decimals, use round:
3.412631.round(2) # 3.41
3.412631.round(100) # 3.412631
I want to loop the background image in a Ruby gosu side scrolling game.I have problem with the counters #k and #p which are used to translate the background image and the duplicated background image.I can't think of a good way to plus them.Here's the code to make it more clear.
require 'gosu'
class GameWindow < Gosu::Window
attr_accessor :x, :y
SHIFT = 700
def initialize
super 640,440
#background = Gosu::Image.new("./images/bg.png")
#player = Gosu::Image.new("./images/000.png")
#x1, #y1 = 0, 0
#player_x, #player_y = 50, 50
#k = 0 #counter
#p = 1 #counter
end
def update
#x1 -= 3
#player_y += 1 if #player_y <= 375
#player_y -= 3 if button_down?(Gosu::KbSpace) and #player_y >= 0
#coordinates = Gosu::Image.from_text(
self, "#{#x1},#{#k}", Gosu.default_font_name, 30)
#here should be the code for #k and #p
end
def draw
#background.draw(#x1 + #k*SHIFT, #y1, 0)
#background.draw(#x1 + #p*SHIFT, #y1, 0)
#player.draw(#player_x, #player_y, 0)
#coordinates.draw(0, 0, 1)
end
def button_down(id)
$window.close if id == Gosu::KbEscape
end
end
window = GameWindow.new
window.show
So how do I plus the counters #k and #p.Tried this
if #x1 > -(SHIFT+5)*#p and #x1 < -SHIFT*#p #705 and 700
#k += 2
end
if #k > 0 and #x1 > -SHIFT*#k - 5 and #x1 < -SHIFT*#k - 3 #1405 and 1403
#p += 2
end
but it works only in the beginning(2-3 image shifts).
Also tried this
if #x1 == -SHIFT*#p
#k += 2
end
and it did not work.
Assumptions & Analysis
I'm assuming that #x1 and #y1 are the offset of the left-most background's origin relative to the screen. You also have #player_x and #player_y, which denote the player's position on the screen. Your player is kept horizontally in the center of the screen, moving vertically when jumping or falling, and your background only scrolls horizontally. Also, your window size is 640x440, and your background image is 700px wide and at least 440px tall.
Your update step handles things like jumping (but only to the top of the screen) and simple, constant-velocity gravity, both by modifying the player's screen coordinates. It also provides a constant horizontal scroll by subtracting 3 units per frame from #x1, the horizontal camera coordinate in world-space.
Your draw step then takes the background image and draws two of them, offsetting them by the camera offset #x1 plus the shift for which image is which. This shift, however, isn't important, because we can calculate it fairly simply, and we're left without having to manipulate the additional state of remembering which one is which.
Code Solution
Instead of remembering the counter values #k and #p, we're going to just modulo by the image width to eliminate the excess in #x1 and get it where we need it to be. #k and #p are useless, so delete those. SHIFT can be deleted as well.
Instead, we need to do the following:
Calculate the screen offset of the left-most image
Determine if two images need to be drawn instead of just one
Draw the image(s)
Our goal looks something like this:
Our new code:
require 'gosu'
class GameWindow < Gosu::Window
attr_accessor :x, :y # side note - are these used at all?
def initialize
super 640,440
#background = Gosu::Image.new("./images/bg.png")
#player = Gosu::Image.new("./images/000.png")
#x1, #y1 = 0, 0
#player_x, #player_y = 50, 50
end
def update
#x1 -= 3
#player_y += 1 if #player_y <= 375
#player_y -= 3 if button_down?(Gosu::KbSpace) and #player_y >= 0
#coordinates = Gosu::Image.from_text(
self, "#{#x1}", Gosu.default_font_name, 30)
end
def draw
# the important bits!
#local_x = #x1 % -#background.width
#background.draw(#local_x, #y1, 0)
#background.draw(#local_x + #background.width, #y1, 0) if #local_x < (#background.width - self.width)
#player.draw(#player_x, #player_y, 0)
#coordinates.draw(0, 0, 1)
end
def button_down(id) # Side note: Does this work correctly?
$window.close if id == Gosu::KbEscape
end
end
window = GameWindow.new
window.show
What this does is, it takes #x1 and modulos it with the (negative) width of the image. This means, it gives the remainder of an integer division of the two numbers. Modulo is very useful when trying to ensure that an integer value "wraps around" after exceeding a limit in either direction; it effectively maps it to between 0 (inclusive) and the given number (exclusive). The results of this are illustrated in the graphic above.
Keep in mind this solution only works as-is for your circumstances; vertical scrolling will require more code, and this will break pretty quickly if your window becomes wider than your background image.
I'm starting to code GUIs with Shoes. I tried the progress bar from the examples, but I found no way to exit the animation, break did not work...
animate do |frames|
unless frames > 100
#p.fraction = (frames % 100) / 100.0
else
break
end
end
Is there any possibility to stop a animation with Shoes? Thanks.
sure, stop does that
Shoes.app do
stack :margin => 0.1 do
title "Progress example"
#p = progress :width => 1.0
#animate = animate (24) do |i|
#p.fraction = (i % 100) / 100.0
#animate.stop if i > 99
end
end
end