I need advice on how to do collision in a clone of Pong - ruby

Hi I am building a clone pong program with ruby and rubygame. My ain problem at the moment is the collision of the leftside. The collision happends backwards. The right works perfectly fine. I need help. Can anyone fix this?
Heres my code
require 'rubygems'
require 'rubygame'
Rubygame::TTF.setup
class Game
def initialize
#screen = Rubygame::Screen.new [640,480], 0,
[Rubygame::HWSURFACE, Rubygame::DOUBLEBUF]
#screen.title = "Pong"
#queue = Rubygame::EventQueue.new
#clock = Rubygame::Clock.new
#clock.target_framerate = 60
limit = #screen.height - 10
#player = Paddle.new 50, 10, Rubygame::K_W, Rubygame::K_S, 10, limit
#enemy = Paddle.new #screen.width-50-#player.width, 10,
Rubygame::K_UP, Rubygame::K_DOWN, 10, limit
#player.center_y #screen.height
#enemy.center_y #screen.height
#ball = Ball.new #screen.width/2, #screen.height/2
#background = Background.new #screen.width, #screen.height
end
def run!
loop do
update
draw
#clock.tick
end
end
def update
#player.update
#enemy.update
#ball.update #screen
#queue.each do |ev|
#player.handle_event ev
#enemy.handle_event ev
case ev
when Rubygame::QuitEvent
Rubygame.quit
exit
when Rubygame::KeyDownEvent
if ev.key==Rubygame::K_ESCAPE
#queue.push Rubygame::QuitEvent.new
end
end
end
if collision? #ball, #player
#ball.collision #player, #ball
elsif collision? #ball, #enemy
#ball.collision #enemy, #ball
end
end
def draw
#screen.fill [0,0,0]
#background.draw #screen
#player.draw #screen
#enemy.draw #screen
#ball.draw #screen
#screen.flip
end
def collision? obj1, obj2
if obj1.y + obj1.height < obj2.y ; return false ; end
if obj1.y > obj2.y + obj2.height ; return false ; end
if obj1.x + obj1.width < obj2.x ; return false ; end
if obj1.x > obj2.x + obj2.width ; return false ; end
return true
end
end
class GameObject
attr_accessor :x, :y, :width, :height, :surface
def initialize x, y, surface
#x = x
#y = y
#surface = surface
#width = surface.width
#height = surface.height
end
def update
end
def draw screen
#surface.blit screen, [#x, #y]
end
def handle_event event
end
end
class Paddle < GameObject
def initialize x,y,up_key,down_key,top_limit,bottom_limit
surface = Rubygame::Surface.new [20, 100]
surface.fill [255, 255, 255]
#up_key = up_key
#down_key = down_key
#moving_up = false
#moving_down = false
#top_limit = top_limit
#bottom_limit = bottom_limit
super x, y, surface
end
def center_y h
#y = h/2-#height/2
end
def handle_event event
case event
when Rubygame::KeyDownEvent
if event.key==#up_key
#moving_up = true
elsif event.key==#down_key
#moving_down = true
end
when Rubygame::KeyUpEvent
if event.key==#up_key
#moving_up = false
elsif event.key==#down_key
#moving_down = false
end
end
end
def update
if #moving_up and #y > #top_limit
#y -= 5
end
if #moving_down and #y+#height < #bottom_limit
#y += 5
end
end
end
class Background < GameObject
def initialize width, height
surface = Rubygame::Surface.new [width, height]
# Draw Background
white = [255, 255, 255]
#Top
surface.draw_box_s [0, 0], [surface.width, 10], white
#Left
surface.draw_box_s [0, 0], [10, surface.height], white
#Bottom
surface.draw_box_s [0, surface.height-10, 10],
[surface.width, surface.height], white
#Right
surface.draw_box_s [surface.width-10, 0],
[surface.width, surface.height], white
#Middle Divide
surface.draw_box_s [surface.width/2-5, 0],
[surface.width/2+5, surface.height], white
super 0, 0, surface
end
end
class Ball < GameObject
def initialize x, y
surface = Rubygame::Surface.load('Ball.png')
#vx = #vy = 5
super x, y, surface
end
def update screen
#x += #vx
#y += #vy
if #x <= 10 or #x+#width >= screen.width-10
#vx *= -1
end
if #y <= 10 or #y+#height >= screen.height-10
#vy *= -1
end
end
def collision paddle, screen
if paddle.x < screen.width/2
unless #x < paddle.x-5
#x = paddle.x+paddle.width+1
#vx *= -1
end
else
unless #x > paddle.x+5
#x = paddle.x-#width-1
#vx *= -1
end
end
end
end
class Text < GameObject
def initialize x=0, y=0, text="Hello, World!", size=40
#font = Rubygame::TTF.new "font.ttf", size
#text = textssssw
super x, y, #font.render(#text, true, [255,255,255])
end
end
g = Game.new
g.run! `

Related

Error in my program!!!! There is no rendering queue for this operation

I'm creating a game with ruby and gosu, and I get an error:
C:/Ruby26-x64/destroy!/bullet.rb:14:in draw_rot': There is no rendering queue for this operation (RuntimeError)
from C:/Ruby26-x64/destroy!/bullet.rb:14:indraw'
from C:/Ruby26-x64/destroy!/player.rb:45:in fire'
from C:/Ruby26-x64/destroy!/destroy.rb:36:inupdate'
from C:/Ruby26-x64/lib/ruby/gems/2.6.0/gems/gosu-0.14.5-x64-mingw32/lib/gosu/patches.rb:72:in tick'
from C:/Ruby26-x64/lib/ruby/gems/2.6.0/gems/gosu-0.14.5-x64-mingw32/lib/gosu/patches.rb:72:intick'
from C:/Ruby26-x64/destroy!/destroy.rb:40:in `'
[Finished in 0.517s]
I've tried to change draw in the bullet class to draw_rot, but no avail.
My Classes
Destroy
require 'gosu'
require 'cmath'
require_relative 'player.rb'
require_relative 'enemy.rb'
require_relative 'bullet.rb'
class Destroy < Gosu::Window
def initialize
super(800, 600)
self.caption = 'Destroy!'
#player = Player.new(self)
#enemies = []
#enemies.push(Enemy.new(self))
end
def draw
#player.draw
#enemies.each do |enemy|
enemy.draw
end
end
def update
#player.righturn if button_down?(Gosu::KbRight)
#player.lefturn if button_down?(Gosu::KbLeft)
#player.startmove
#player.move if button_down?(Gosu::KbUp)
#freq = 0.0025
if rand < #freq
#enemies.push(Enemy.new(self))
end
#enemies.each do |enemy|
enemy.move
enemy.update(#player.x, #player.y)
end
if #freq < 0.5
#freq += 0.0002
end
#player.fire(self)
end
end
window = Destroy.new
window.show
Bullet
class Bullet
attr_accessor :x
attr_accessor :y
attr_accessor :fired
def initialize(window)
#image = Gosu::Image.new('C:\Ruby26-x64\destroy!\images\bullet.png')
#fired = 0
#x = 0
#y = 0
end
def draw(x, y)
#x = x
#y = y
#image.draw_rot(x, y, 1, 0)
#fired = 1
end
def update(angle)
#xspeed = Gosu.offset_x(angle, 2)
#yspeed = Gosu.offset_y(angle, 2)
if (#x > 800 || #x < 0 || #y > 600 || #y < 0)
#fired = 0
end
end
end
Player
require_relative 'bullet.rb'
require 'gosu'
class Player
attr_accessor :x
attr_accessor :y
def initialize(window)
#x = 200
#y = 200
#xspeed = 0
#yspeed = 0
#angle = 0
#image = Gosu::Image.new('C:/Ruby26-x64/destroy!/images/man.png')
end
def draw
#image.draw_rot(#x, #y, 1, #angle)
end
def righturn
#angle += 3
end
def lefturn
#angle -= 3
end
def startmove
#xspeed = Gosu.offset_x(#angle, 2)
#yspeed = Gosu.offset_y(#angle, 2)
end
def move
if #x > 767
#xpeed = 0
#x = 767
end
if #x < 33
#xpeed = 0
#x = 33
end
if #y > 567
#yspeed = 0
#y = 567
end
#x += #xspeed
#y += #yspeed
end
def fire(window)
#bullet = Bullet.new(window)
#bullet.draw(#x, #y)
while #bullet.fired = 1
#bullet.update(#angle)
end
end
end
Enemy
require 'cmath'
class Enemy
def initialize(window)
#flipped = 0
#x = rand(800 - 2 * 30) + 30
#y = rand(600 - 2 * 30) + 30
#firefreq = 1 / 60
#health = 5
#numkilled = 0
#dead = 0
#xspeed = 0
#yspeed = 0
#angle = 0
#image = Gosu::Image.new('C:/Ruby26-x64/destroy!/images/enemy.png')
#imageflipped = Gosu::Image.new('C:/Ruby26-x64/destroy!/images/enemyflip.png')
end
def gethit
#health -= 1
end
def die
#numkilled += 1
#dead = 1
end
def move
if rand < 0.1
#xspeed = rand(-3..3)
#yspeed = rand(-3..3)
end
if #x + #xspeed > 800
#x = 800
end
if #x + #xspeed < 0
#x = 0
end
if #y + #yspeed > 600
#y = 600
end
if #y + #yspeed < 0
#y = 0
end
if !(#y + #yspeed < 0 && #y + #yspeed > 600 && #x + #xspeed < 0 && #x + #xspeed > 800)
#y += #yspeed
#x += #xspeed
end
end
def draw
if #dead == 0
if #flipped == 1
#imageflipped.draw_rot(#x, #y, 1, #angle)
end
if #flipped == 0
#image.draw_rot(#x, #y, 1, #angle)
end
end
end
def update(xdist, ydist)
if #x < xdist
(#angle = CMath.atan((ydist - #y) / (xdist - #x)) * 180 / 3.14159265358979323846264338327950289)
#flipped = 0
end
if #x > xdist
(#angle = CMath.atan(-(ydist - #y) / (#x - xdist)) * 180 / 3.14159265358979323846264338327950289)
#flipped = 1
end
end
end
I do not get this at all.
Your Destroy#update method calls Player#fire which calls Bullet#draw which calls Gosu::Image#draw_rot. You can't call draw methods from within the main update method.
You will have to move your #bullet.draw method call out from Player#fire (which gets called during main update) and into Player#draw (which gets called during main draw)

Trouble making random spawning enemies shoot bullets

I have figured out how to randomly spawn enemies in different locations, but I cant figure out to make some of the enemies randomly fire bullets.
I created a Bullet class and a Enemy class. I use attr_reader to locate the enemies and call the x and y locations in the new Bullet method, but it fails to find where the enemy is located.
require 'gosu'
require_relative 'player'
require_relative 'enemy'
require_relative 'bullet'
class Proto < Gosu::Window
WIDTH = 1000
HEIGHT = 800
ENEMY_FREQUENCY = 0.03
attr_reader :x, :y, :radius, :angle
def initialize
super(WIDTH,HEIGHT)
self.caption = "Proto"
#player = Player.new(self)
#enemies = []
#bullets = []
#framecounter = 0
end
def update
#framecounter += 1
#player.turn_left if button_down?(Gosu::KbLeft)
#player.turn_right if button_down?(Gosu::KbRight)
#player.accelerate if button_down?(Gosu::KbUp)
#player.backward if button_down?(Gosu::KbDown)
#player.move
if rand < ENEMY_FREQUENCY
#enemies.push Enemy.new(self)
end
#enemies.each do |enemy|
enemy.move
if #framecounter % 60 == 0 && #enemies[3]
#bullets.push Bullet.new(self, #enemy.x, #enemy.y, #enemy.angle)
end
end
#bullets.each do |bullet|
bullet.move
end
end
def draw
#player.draw
#enemies.each do |enemy|
enemy.draw
end
#bullets.each do |bullet|
bullet.draw
end
end
end
window = Proto.new
window.show
class Enemy
SPEED = 1
attr_reader :x, :y, :radius, :angle
def initialize(window)
#radius = 20
#x = rand(window.width - 2 * #radius) + #radius
#y = 0
#image = Gosu::Image.new('ima/tile000.png')
end
def move
#y += SPEED
end
def draw
#image.draw(#x - #radius, #y - #radius, 2)
end
end
require_relative 'enemy'
class Bullet
SPEED = 5
def initialize(window, x, y, angle)
#x = x
#y = y
#direction = angle
#image = Gosu::Image.new('ima/tile000.png')
#imaget = Gosu::Image.new('ima/tile000.png')
#radius = 3
#window = window
end
def move
#y += SPEED
end
def draw
#image.draw(#x - #radius, #y - #radius, 1)
#imaget.draw(#enemy.x - radius, #enemy.y - #radius, 1)
end
end
I expect random enemies to fire bullets.
As discussed in the comments, the issue was that you had
#enemies.each do |enemy|
#enemy.draw
end
instead of
#enemies.each do |enemy|
enemy.draw
end

Change position according to facing in Ruby

I need to implement a move method that change position according to facing, position is a [x,y] and I thinking that if move to south is y+1, to north y-1, to east x-1 and to west x+1. this movements are into a matrix.
This is my code. Thank you so much for your help!
# Models the Robot behavior for the game
class Robot
FACINGS = [:south, :east, :north, :west]
def initialize(attr = {})
#position = attr[:position] || [1, 1]
# #move = attr[:move]
#facing_index = facing_index(attr[:facing]) || 0 # south
#facing = facing
# #errors =
end
def position
#position
end
def move
end
def facing
#facing = FACINGS[#facing_index]
end
def errors
end
private
def facing_index(facing)
facing if facing.is_a? Integer
FACINGS.index(facing&.to_sym)
end
end
DIRECTION_NUMBER = { :north=>0, :east=>1, :south=>2, :west=>3 }
#left = { :north=>:west, :west=>:south, :south=>:east, :east=>:north }
#right = #left.invert
#=> {:west=>:north, :south=>:west, :east=>:south, :north=>:east}
def turn_left
#facing = #left[#facing]
end
def turn_right
#facing = #right[#facing]
end
def move(direction)
x, y = #location
#location =
case direction
when :north
[x,y+1]
when :east
[x+1,y]
when :south
[x,y-1]
else
[x-1,y]
end
update_facing(direction)
end
private
def update_facing(direction)
change = (DIRECTION_NUMBER[direction] - DIRECTION_NUMBER[#facing]) % 4
case change
when 1
turn_right
when 2
turn_right; turn_right
when 3
turn_left
end
end
#location = [3, 3]
#facing = :east
move(:south)
#location #=> [3, 2]
#facing #=> :south
move(:north)
#location #=> [3, 3]
#facing #=> :north
move(:west)
#location #=> [2, 3]
#facing #=> :west
move(:east)
#location #=> [3, 3]
#facing #=> :east
Add MOVES which says how to move based on how you're facing.
MOVES = {
north: [0, 1],
south: [0, -1],
east: [1, 0],
west: [-1,0]
}
def move
move = MOVES.fetch(#facing)
#position[0] += move[0]
#position[1] += move[1]
end
MOVES.fetch(#facing) is used instead of MOVES[#facing] so an error will be raised if there is no move for that facing.
You could also do this with a case statement, but this keeps move simple and data driven. You can add more directions like northeast: [1,1]. And if you make this an instance variable, you can customize how individual robots move.
# Define `moves` and `moves=` to get and set `#moves`
attr_accessor :moves
def initialize(attr = {})
...
# Initialize `moves` with either Robot.new(moves: {...})
# or the default MOVES
#moves ||= attr[:moves] || MOVES
...
end
def move
move = moves.fetch(#facing)
#position[0] += move[0]
#position[1] += move[1]
end
FACINGS enum example.
module FACINGS
NORTH = [0, 1]
SOURTH = [0, -1]
EAST = [1, 0]
WEST = [-1,0]
end
class Robot
attr_reader :position
def initialize(attr = {})
#position = attr[:position] || [1, 1]
end
def move(facings)
#position[0] += facings[0]
#position[1] += facings[1]
end
end
r = Robot.new
r.move(FACINGS::NORTH)
r.move(FACINGS::SOURTH)
r.move(FACINGS::WEST)
r.move(FACINGS::EAST)

Keeping track of the path, Knights travel

So far my shortest path method will stop when it reaches the goal position, printing out everything it did along the way. I would like to know how I could go about implementing parent positions so I can print the path along with the goal. This is an assignment.
class Knight
attr_accessor :x, :y, :prev_position, :moves
def initialize(position)
#x = position[0]
#y = position[1]
#prev_position = nil
#moves = [
[-1,-2],
[-2,-1],
[-2,+1],
[-1,+2],
[+1,-2],
[+2,-1],
[+2,+1],
[+1,+2]]
end
def possible
move_list = Array.new
#moves.each do |moves|
x = #x + moves[0]
y = #y + moves[1]
if x.between?(0,7)
if y.between?(0,7)
move_list << [x,y]
end
end
end
move_list
end
end
def shortest_path(position,goal)
paths = Array.new
#start_knight = Knight.new(position)
until #start_knight.x == goal[0] and
#start_knight.y == goal[1]
#start_knight.possible.each do |p| paths << p end
shifted = paths.shift
#start_knight.x = shifted[0]
#start_knight.y = shifted[1]
puts "[#{#start_knight.x},#{#start_knight.y}]"
end
end
shortest_path([0,0],[7,7])

having problems with Gosu tutorial, possibly not just a syntax error

I've been trying out the Gosu tutorial so I can learn to make games. I'm getting errors with my code. Could someone point out to me what I'm doing wrong? Here's the tutorial link:
https://github.com/jlnr/gosu/wiki/Ruby-Tutorial
here's my code:
require 'Gosu'
class GameWindow < Gosu::Window
def initialize
super 640, 480, false
self.caption = "Gosu Tutorial Game"
#background_image = Gosu::Image.new(self, "Usable Images/final_fantasy_background.png", true)
#player = Player.new(self)
#player.warp(320, 240)
#Star_anim = Gosu::Image::load_tiles(self, "Usable Images/donut.png", 25, 25, false)
#Star = Array.new
end
def update
if button_down? Gosu::KbLeft or button_down? Gosu::GpLeft then
#player.turn_left
end
if button_down? Gosu::KbRight or button_down? Gosu::GpRight then
#player.turn_left
end
if button_down? Gosu::KbUp or button_down? Gosu::GpButton0 then
#player.accelerate
end
#player.move
#player.collect_stars(#stars)
if rand(100) < 4 and #Star.size < 25 then
#Star.push(Star.new(#Star_anim))
end
end
def draw
#background_image.draw(0,0,ZOrder::Background)
#player.draw
stars = Star.new()
#stars.each{ |star| star.draw}
end
def button_down(id)
if id == Gosu::KbEscape
close
end
end
end
class Player
def initialize(window)
#image = Gosu::Image.new(window, "Usable Images/eric_cartman.png", false)
#x = #y = #vel_x = #vel_y = #angle = 0.0
#score = 0
end
def warp(x, y)
#x, #y = x, y
end
def turn_left
#angle -= 4.5
end
def turn_right
#angle += 4.5
end
def accelerate
#vel_x += Gosu::offset_x(#angle, 0.5)
#vel_y += Gosu::offset_x(#angle, 0.5)
end
def move
#x += #vel_x
#y += #vel_y
#x %= 640
#y %= 480
#vel_x *= 0.95
#vel_y *= 0.95
end
def draw
#image.draw_rot(#x, #y, 1, #angle)
end
def score
#score
end
def collect_Star(star)
if Star.reject! {|star| Gosu::distance(#x, #y, Star.x, star.y) < 35} then
#score += 1
end
end
end
module ZOrder
Background, Star, Player, UI = *0..3
end
class Star
attr_reader :x, :y
def initialize(animation)
#animation = animation
#color = Gosu::Color.new(0xff000000)
#color.red = rand(256 - 40) + 40
#color.green = rand(256 - 40) + 40
#color.blue = rand(256 - 40) + 40
#x = rand * 640
#y = rand * 480
end
def draw
img = #animation[Gosu::milliseconds / 100 % #animation.size];
img.draw(#x - image.width / 2.0, #y - img.height / 2.0, ZOrder::Star, 1, 1, #color, :add)
end
end
window = GameWindow.new
window.show
You have Star.new(), but you define it as initialize(animation) (with one mandatory argument).

Resources