Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- require 'java'
- %w(JPanel JTextField JLabel JFrame JButton Timer).each { |c| java_import "javax.swing.#{c}"}
- %w(Rectangle Insets Color BasicStroke Dimension Canvas image.BufferStrategy BorderLayout GridBagLayout GridBagConstraints Font).each { |c| java_import "java.awt.#{c}" }
- WORLD_WIDTH = 800
- WORLD_HEIGHT = 600
- DELAY = 50
- G = 9.81
- $current_time = 0
- $images = []
- Y_0 = 500
- X_0 = 10
- VX_0 = 40
- VY_0 = 0
- class Pair
- attr_accessor :first, :second
- def initialize(first, second)
- @first = first
- @second = second
- end
- end
- def find_impact(y_0, vy_0, radius)
- discriminant = vy_0.to_f*vy_0.to_f - 2*G*(y_0.to_f-WORLD_HEIGHT+radius*2) # Simplified 4*G*(y_0-h)/2
- puts "Discriminant: #{discriminant} #{y_0}, #{vy_0}" if $DEBUG
- first_solution = (-vy_0 - Math.sqrt(discriminant)) / -G # Simplified 2*G/2
- second_solution = (-vy_0 + Math.sqrt(discriminant)) / -G # Simplified 2*G/2
- puts "first solution: #{first_solution} - second solution: #{second_solution}" if $DEBUG
- if vy_0 < 0
- [first_solution, second_solution].min.abs
- else
- [first_solution, second_solution].max
- end
- end
- class Organism < Rectangle
- attr_accessor :x, :y, :radius, :vx_0, :vy_0, :x_final
- def initialize
- @x_final = false
- end
- def draw(g)
- recalculate(g)
- g.color = Color::ORANGE
- g.draw_oval(@x, @y, @radius*2, @radius*2)
- g.fill_oval(@x+@radius, @y+@radius, 1, 1)
- end
- def recalculate(g)
- if !@x_final
- @x_final_value = @vx_0*find_impact(@y, @vy_0, @radius) + @x
- @x_final = true
- end
- $current_time += DELAY/100.0
- t = $current_time
- if @y < (WORLD_HEIGHT - @radius*2)
- @y = 0.5*G*t*t + @vy_0*t + Y_0
- else
- @y = WORLD_HEIGHT - @radius*2
- end
- if @x < (WORLD_WIDTH - @radius*2) && @y < (WORLD_HEIGHT - @radius*2)
- @x = @vx_0*t + X_0
- $images << Pair.new(@x, @y)
- else
- @x = @x_final_value
- $images << Pair.new(@x, @y)
- end
- if @y == (WORLD_HEIGHT - @radius*2)
- vx = vy = 0
- else
- vx = @vx_0
- vy = G*t + @vy_0
- end
- g.color = Color::BLUE
- g.draw_line(@x+@radius, @y+@radius, @x+@radius+vx, @y+@radius+vy)
- g.color = Color::GREEN
- g.font = Font.new("Courier new", Font::BOLD, 12)
- g.draw_string("x = #{@x.round(1)}, y = #{@y.round(1)}, v_x = #{vx.round(1)}, v_y = #{vy.round(1)}", WORLD_WIDTH - 310, 20)
- puts "x = #{@x.round(1)}, y = #{@y.round(1)}, v_x = #{vx.round(1)}, v_y = #{vy.round(1)}" if $DEBUG
- end
- end
- class Universe < Canvas
- def initialize
- super()
- self.preferred_size = Dimension.new(WORLD_WIDTH, WORLD_HEIGHT)
- self.minimum_size = self.preferred_size
- self.background = Color::BLACK
- @running = true
- @organisms = []
- end
- def game_loop
- if @running
- last_run = Time.now
- create_buffer_strategy(2)
- @strategy = self.buffer_strategy
- now = Time.now
- delta = now - last_run
- last_run = now
- g = @strategy.draw_graphics
- draw_frame(g)
- $images.each do |p|
- g.color = Color::GRAY
- g.fill_oval(p.first, p.second, 10, 10)
- end
- @organisms.each do |o|
- o.draw(g)
- end
- # flip buffer
- g.dispose()
- @strategy.show()
- end
- end
- def add_organism(organism)
- @organisms << organism
- end
- private
- def draw_frame(g)
- g.color = Color::WHITE
- old_stroke = g.stroke
- thindashed = BasicStroke.new(1.0, BasicStroke::CAP_BUTT, BasicStroke::JOIN_BEVEL, 1.0, [8.0, 3.0, 2.0, 3.0].to_java(:float), 0.0)
- g.set_stroke(thindashed)
- (0..WORLD_WIDTH).step(40) do |x|
- (0..WORLD_HEIGHT).step(40) do |y|
- g.drawLine(0, y, WORLD_WIDTH, y)
- g.drawLine(x, 0, x, WORLD_HEIGHT)
- end
- end
- g.stroke = old_stroke
- end
- end
- class ControlPanel < JPanel
- def initialize(organism)
- super()
- self.layout = GridBagLayout.new
- self.preferred_size = Dimension.new(200, WORLD_HEIGHT)
- constraints = GridBagConstraints.new
- constraints.weightx = 1.0
- constraints.fill = GridBagConstraints::HORIZONTAL
- constraints.insets = Insets.new(3, 5, 3, 5)
- self.add(JLabel.new("v_x0:"), constraints)
- constraints.gridwidth = GridBagConstraints::REMAINDER
- constraints.weightx = 10.0
- @velocity_x_field = JTextField.new(VX_0.to_s)
- self.add(@velocity_x_field, constraints)
- constraints.weightx = 1.0
- constraints.gridwidth = GridBagConstraints::RELATIVE
- self.add(JLabel.new("v_y0:"), constraints)
- constraints.gridwidth = GridBagConstraints::REMAINDER
- @velocity_y_field = JTextField.new(VY_0.to_s)
- self.add(@velocity_y_field, constraints)
- constraints.weighty = 1
- constraints.anchor = GridBagConstraints::NORTH;
- constraints.gridheight = GridBagConstraints::REMAINDER
- constraints.fill = GridBagConstraints::NONE
- button = JButton.new("Restart")
- button.add_action_listener do |e|
- organism.x = X_0
- organism.y = Y_0
- organism.x_final = false
- organism.vx_0 = initial_velocity_x
- organism.vy_0 = initial_velocity_y
- $current_time = 0
- end
- self.add(button, constraints)
- end
- def initial_velocity_x
- @velocity_x_field.text.to_f
- end
- def initial_velocity_y
- @velocity_y_field.text.to_f
- end
- end
- class ShowFrame < JFrame
- attr_accessor :universe
- def initialize
- super()
- self.title = "First Try"
- self.ignore_repaint = true
- organism = Organism.new
- organism.x = X_0
- organism.y = Y_0
- organism.vx_0 = VX_0
- organism.vy_0 = VY_0
- organism.radius = 5
- @universe = Universe.new
- @universe.add_organism(organism)
- self.content_pane.add(@universe, BorderLayout::CENTER)
- self.content_pane.add(ControlPanel.new(organism), BorderLayout::WEST)
- self.default_close_operation = JFrame::EXIT_ON_CLOSE
- self.pack()
- self.visible = true
- self.resizable = false
- Timer.new(DELAY, ->(e) { @universe.game_loop }).start
- end
- end
- java.awt.EventQueue::invokeLater do
- ShowFrame.new
- end
Add Comment
Please, Sign In to add comment