Trouble making random spawning enemies shoot bullets - ruby

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

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)

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])

Ruby instance variable changes unexpectedly

In the code below, a cluster has many points.
class Cluster
attr_accessor :centroid, :points
def initialize(centroid, *points)
#centroid = centroid
#points = points
end
end
class Point
attr_accessor :x, :y
def initialize(x = 0, y = 0)
#x = x
#y = y
end
end
An example of a Cluster object (lets us call this c):
#<Cluster:0x007ff5c123c210
#centroid=#<Point:0x007ff5c123c288 #x=25, #y=125>,
#points=
[#<Point:0x007ff5c123c238 #x=25, #y=125>,
#<Point:0x007ff5c1020120 #x=28, #y=145>]>
I am trying to calculate the mean of the points, and update #centroid without changing #points.
Let's say I have:
class Point
def +(point)
#x = #x + point.x
#y = #y + point.y
self
end
def /(num)
#x = #x/num
#y = #y/num
self
end
end
and to calculate the mean of all the points, I run:
c.centroid = c.points.reduce(&:+)/c.points.length
Then, c changes to:
#<Cluster:0x007ff5c123c210
#centroid=#<Point:0x007ff5c1515ec8 #x=26, #y=135>,
#points=
[#<Point:0x007ff5c1515ec8 #x=26, #y=135>,
#<Point:0x007ff5c1020120 #x=28, #y=145>]>
Note that first element of the #points is changed. Any suggestions?
Your + method in Point modifies the point's members #x and #y. You need to return a new point with the calculated values instead:
def +(point)
Point.new(#x + point.x, #y + point.y)
end
def /(num)
Point.new(#x/num, #y/num)
end
Since you did not pass an initial value to reduce, the first point became modified. You can pass a new point as the initial value to reduce, which will be modified and returned.
c.centroid = c.points.reduce(Point.new, &:+)/c.points.length
I think the problem is caused by the + method modifying the point #x and #y values.
Try changing the + method to:
def +(point)
x = #x + point.x
y = #y + point.y
self.class.new(x, y)
end

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).

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

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! `

Resources