Not logged inGosu Forums
Forum back to libgosu.org Help Search Register Login
Up Topic Gosu / Gosu Exchange / Changing the level in a game
- - By Acturus Date 2019-08-22 14:16
So this is my game loop

  def  draw
    case @scene
        when:start
            draw_start
        when:game
            draw_game
        when:level
            draw_level
        when:end
            draw_end
     end
   end

However, I can't save the level that the game is on. How do I that? As soon as draw level occurs and the player presses a key the program reverts back  draw game, but the problem is nothing is saved. How do I make the program calculate the number of times draw_game occurs and save that value  throughout the life of the program?

Thank you,

Acturus
Parent - - By kyonides Date 2019-08-23 06:54
You know, that would relatively soon become a LARGE number so it wouldn't help you to store it at all. You'd better divide it by the update interval. Plus why do you wanna save any data in the draw method? You got an input and a general update method to do that! I'd recommend saving stuff inside any of those two methods. Since you're using an instance variable to determine the scene, that won't be a problem. :)
Parent - - By Acturus Date 2019-08-23 10:37
Thank you for your response. 

So I put the instance variable in the input  method and  increment the level in  the update game method, but it still doesn't save it. After   @scene = :game runs through its cycle all changes  are erased and the game moves to @scene = :level or @scene = :end. I need the program to save the changes that occur in @scene = :game. How can I do this? 

Acturus
Parent - - By kyonides Date 2019-08-23 21:05
First it'd be helpful if you tell us what are the "changes" you're talking about. What kind of stuff do you need to save before the scene changes? HP HUD? Level? Difficulty? Angle? Zoom? X Y coordinates? O_o?

Even so you might keep in mind you can use more instance variables to store other stuff as well. :)
Parent - By Acturus Date 2019-08-23 23:41
I need to save the level and increase it by one.
Parent - - By jlnr (dev) Date 2019-08-25 19:22
Please post more source code, it's not clear from the snippet where the problem might be.
Parent - - By Acturus Date 2019-08-25 19:49
require 'gosu'
require_relative 'credit'
require_relative 'player'
require_relative 'enemy'
require_relative 'bullet'
require_relative 'explosion'
require_relative 'score'
require_relative 'boss'
require_relative 'bossbullet'

class SectorFive < Gosu::Window
# THE BELOW VARIABLES ARE CALLED CONSTANTS
  WIDTH =  800
  HEIGHT = 600
  #ENEMY_FREQUENCY = 0.005
  MAX_ENEMIES = 10000
  EXPIRE = 180

# THE INITIALIZE METHOD STARTS THE INITIAL GAME AND SETS THE SCENE :START

  def initialize
    super(WIDTH, HEIGHT)
    self.caption =  "Sector Five"
    @background_image = Gosu::Image.new('ima/start.png')
    @start_music = Gosu::Song.new('sounds/heart.ogg')
    @start_music.play(true)
    @scene = :start
  end

# THIS METHOD CALLS THE DIFFERENT DRAW METHOD DEPENDING ON WHICH PART IN THE
# GAME THE PLAYER IS AT>> START< GAME < END

  def  draw
    case @scene
        when:start
            draw_start
        when:game
            draw_game
        when:level
            draw_level
        when:end
            draw_end
     end
   end

# THIS METHOD DRAWS THE BACKGROUND IMAGE DURING THE START WINDOW
def draw_start
@background_image.draw(0,0,0)
end

# THIS  METHOD DRAWS THE IMAGES ON THE  WINDOW

def draw_game
   @player.draw
   @background_image.draw(0,0,0)
   @score_board.draw_text("Score=#{@enemies_destroyed}",40,40,1,1,1,Gosu::Color::AQUA)
   @time.draw_text("Time=#{@countdown}",650,40,1,1,1,Gosu::Color::RED)
   @time.draw_text("Health#{@bosshealth}",50,500,1,1,1,Gosu::Color::GREEN)
   @score_board.draw_text("Location#{@distance},#{@distance}",400,400,1,1,1,Gosu::Color::AQUA)

   @time.draw_text("level#{@wave_count}",460,460,1,1,1,Gosu::Color::GREEN)

@enemies.each  do |enemy|
         enemy.draw
   end
   @enemybullets.each do |bullet|
         bullet.draw
   end
   @bullets.each do |bullet|
     bullet.draw_two
   end
   @explosions.each do |explosion|
     explosion.draw
   end
   @playerexplosions.each do |explosion|
     explosion.draw_two
   end
   @boss.each do |b|
     b.draw
   end
   @bossbullets.each do |bullet|
     bullet.draw
   end
end

# THIS METHOD  TELLS THE GAME WHICH UPDATE TO FOLLOW DEPENDING ON WHICH PART
# THE GAME IS ON. GAME OR END

def update
  case @scene
  when :game
    update_game
  when :end
    update_end
  end
end

# THIS METHOD SPECIFIES THE DIFFERENT USABLE BUTTONS DEPENDING ON WHICH  PART
# OF THE GAME THE PLAYER IS ON. START < GAME < END

def button_down(id)
  case @scene
when :start
   button_down_start(id)
when :game
   button_down_game(id)
when :level
   button_down_level(id)
when :end
   button_down_end(id)
end
end

# THIS METHOD STARTS THE GAME

def button_down_start(id)
initialize_game
end

# THIS METHOD CONTAINS  ALL THE VARIABLES TO BE MANIPULATED

def initialize_game
   @background_image = Gosu::Image.new('ima/space.png')
   @player = Player.new(self)
   @enemy_frequency = 0.0
   @boss = []
   @bosshealth = 0
   @enemies = []
   @bullets = []
   @enemybullets = []
   @bossbullets = []
   @random_enemy_bullets = []
   @explosions = []
   @playerexplosions = []
   @bossexplosions = []
   @framecounter = 0
   @scene = :game
   @enemies_appeared = 0
   @enemies_destroyed = 0
   @credits = []
   @game_music = Gosu::Song.new('sounds/chill.ogg')
   @game_music.play(true)
   @explosion_sound = Gosu::Sample.new('sounds/explosion.ogg')
   @shooting_sound = Gosu::Sample.new('sounds/shoot.ogg')
   @falling_sound = Gosu::Sample.new('sounds/fall.ogg')
   @score_board = Gosu::Font.new(30)
   @counter = 0
   @time = Gosu::Font.new(30)
   @distance = 0
   @distance_two = 0
   @bossbulletdistance = 0
   @turn_r_counter = 0
   @turn_l_counter = 0
   @killedenemies = 100
   @countdown = 10
   @level = update_level
end

def update_game
@countdown -= 1 if @framecounter % 60 == 0
@framecounter += 1
@counter += 1 if @framecounter % 60 == 0
# @enemy_frequency += 0 if @counter % 3600 == 0
@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

   #CREATES THE ENEMEY
  if rand < @enemy_frequency
     @enemies.push Enemy.new(self)
     @enemies_appeared += 1
  end

  #THE BOSS CREATION
  if @framecounter % 900 == 0
    @boss.push Boss.new(self)
    @bosshealth += 100
  end

@boss.each do |b|
   if @boss.length > 1
     @boss.delete b
   end
end

# When A Bullet Hits a Boss AN EXPLOSION IS CREATED
@boss.dup.each do |b|
   @bullets.dup.each do |bullet|
     distance = Gosu.distance(b.x, b.y, bullet.x, bullet.y)
     if distance < b.radius + bullet.radius
       @bullets.delete bullet
       @explosions. push Explosion.new(self, b.x, b.y)
       @enemies_destroyed += 5
       @bosshealth -= 20
       if @bosshealth <= 0
         @boss.delete b
       end
       @explosion_sound.play(0.3)
     end
   end
end

   # ENEMY Fires a bullet
   @enemies.select do |enemy|
     if @framecounter % 600 == 0
       @enemybullets.push Bullet.new(self, @enemies[-1].x, @enemies[-1].y, @enemies[-1].angle)
       if @enemies.length >  3
         @enemybullets.push Bullet.new(self, enemy.x, enemy.y, enemy.angle)
       end
     end
  end

   #Boss Fires A Bullet
   @boss.select do |b|
     if @framecounter % 60 == 0
       @bossbullets.push BBullet.new(self, @boss[-1].x, @boss[-1].y, @boss[-1].angle)
     end
   end

   #Direction of Boss Bullet
@bossbullets.each do |bullet|
@bossbulletdistance = Gosu::distance(@player.x, @player.y, bullet.x, bullet.y)
     @bossbulletdistance < 800
        if @player.x > bullet.x
            bullet.move
        end
        if @player.y < bullet.y
           bullet.move_four
        end
        if @player.x < bullet.x
           bullet.move_three
        end
        if @player.y > bullet.y
           bullet.move_two
        end

        if @bossbulletdistance < bullet.radius + @player.radius
     @bossbullets.delete bullet
   end
end

#  THE BOSS FOLLOWS THE ENEMY
@boss.each do |b|
@distance = Gosu::distance(@player.x, @player.y, b.x, b.y)
x1 = @player.x
y1 = @player.y
x2 = b.x
y2 = b.y
  @distance < 800
    if @player.x > b.x
      b.move
    end
    # if @player.y < b.y
    #   b.move_four
    # end
    # if @player.x < b.x
    #   b.move_three
    # end
    # if @player.y > b.y
    #    b.move_two
    # end
end

#TURN THE BOSS TO THE PLAYER
@boss.each do |b|
@ang = b.angle
b.angle
end

# Detects whether there is a collision between a player bullet and an  enemy.
  @enemies.dup.each do |enemy|
    @bullets.dup.each do  |bullet|
      distance = Gosu.distance(enemy.x, enemy.y, bullet.x, bullet.y)
      if distance < enemy.radius + bullet.radius
        @enemies.delete enemy
        @bullets.delete bullet
        @explosions.push Explosion.new(self, enemy.x, enemy.y)
        @enemies_destroyed += 1
        @explosion_sound.play(0.3)
      end
    end
  end

# DELETES THE EXPLOSIONS AFTER  THE EXPLOSION  ARRAY LENGTH IS GREATER THAN 15
  @explosions.dup.each do |explosion|
   if @explosions.length > 15
    @explosions.delete explosion
    @explosions.delete explosion
  end
end

# DELETES AN ENEMY IF THE ENEMY COMES IN CONTACT WITH AN EXPLOSION
   @explosions.dup.each do |explosion|
     @enemies.dup.each do |enemy|
       distance = Gosu.distance(explosion.x, explosion.y, enemy.x, enemy.y)
       if distance  < explosion.radius + enemy.radius
         @enemies.delete enemy
         @explosions.push Explosion.new(self, enemy.x, enemy.y)
         @enemies_destroyed += 1
         @explosion_sound.play(0.3)
       end
     end
   end

#  CREATES AN  EXPLOSION IF A BULLET TOUCHES AN ENEMY
@enemybullets.each  do |bullet|
distance = Gosu.distance(bullet.x, bullet.y, @player.x, @player.y)
if distance < bullet.radius + @player.radius
   @enemybullets.delete bullet
   @playerexplosions.push Explosion.new(self, @player.x, @player.y)
   @explosion_sound.play(0.3)
end
end
@playerexplosions.dup.each do |explosion|
@explosions.delete explosion unless explosion.finishedtwo
end

# CREATES A SOUND IF AN ENEMY LEAVES SOUTH OF THE GAMEBOARD
  @enemies.dup.each do |enemy|
    if enemy.y > HEIGHT + enemy.radius
      @enemies.delete enemy
      @falling_sound.play(0.2)
    end
  end

# THE BELOW COMMANDS MOVE THE DIFFERENT CLASSES

  @bullets.dup.each do |bullet|
    @bullets.delete bullet unless bullet.onscreen?
  end
  @enemybullets.each do |bullet|
    bullet.enemy_move
  end
  @bullets.each do |bullet|
    bullet.move
  end
  @explosions.each  do |explosion|
    explosion.move
  end
   @playerexplosions.each do |explosion|
     explosion.move
  end
   @enemies.each do |enemy|
      enemy.move
  end

# STARTS THE INITIALIZE_END METHOD DEPENDING IF ONE OF THE  CONDITIONS BELOW IS MET
   initialize_end(:count_reached) if @enemies_appeared > MAX_ENEMIES
   @enemies.each do |enemy|
     distance = Gosu::distance(enemy.x, enemy.y, @player.x, @player.y)

   initialize_end(:hit_by_enemy) if distance < @player.radius + enemy.radius
   end
   initialize_end(:off_top) if @player.y < -@player.radius

   initialize_level(:time_expire) if @countdown == 0
   update_level if @count_down ==  0
end

# CONTROLS THE PLAYERS FIRING MECHONISIM

def button_down_game(id)
if  id == Gosu::KbSpace
   @bullets.push Bullet.new(self, @player.x, @player.y, @player.angle)
   @shooting_sound.play(0.9)
end
end

# THE INITILIALIZE END METHOD CREATES THE MESSAGES AFTER THE GAME IS  OVER

def end_of_level(what)
case what
    when :time_expire
     @message3 = "Congratulations!!! :) You Survived the Swarm"
    when :enemy
     @message4 = " Congratulations!!! :) You Killed all the Enemies"
end
@final_message = "THE NEXT LEVEL WILL BEGIN SOON"
@final_message2 = " OR YOU CAN PRESS P to play again, or Q to quit."
end

def initialize_end(fate)
case fate
when :count_reached
   @message = "You Made it! You destroyed #{@enemies_destroyed} ships"
   @message2 = "and #{100 - @enemies_destroyed} reached the base."

when :hit_by_enemy
   @message = "You were struck by an enemy ship"
   @message2 = "Before your ship was destroyed, "
   @message2 += "you took out #{@enemies_destroyed} enemy ships!"

when :off_top
   @message = "You got too close to the enemy mothership."
   @message2 = "Before your ship was destroyed, "
   @message2 += "you took out #{@enemies_destroyed} enemy ships!"
end
@bottom_message = "Press P to play again, or Q to quit."
@message_font = Gosu::Font.new(28)
y = 700

# THIS FUNCTION FILE.OPEN LINKS TO THE FILE WITH THE END CREDIT INFORMATION
# AND APPLIES A  SCROLLING  FUNCTION
File.open('credits.txt').each do |line|
   @credits.push(Credit.new(self,line.chomp,100,y))
   y+=30
end

#>>> @SCENE CHANGES TO :END
@scene = :end
@end_music = Gosu::Song.new('sounds/mind.ogg')
@end_music.play(true)
end

# THIS PART DRAWS THE  SCORE ON THE TOP LEFT  CORNER OF THE WINDOW
def score_counter
  clip_to(50,140,700,360) do
    @score += 1 if @enemies_destroyed +=1
    @score.draw
  end
end

# THIS METHOD PLACES THE FILE INFORMATION IN THE MIDDLE OF THE SCREEN
def draw_end
  clip_to(50,140,700,360) do
         @credits.each do |credit|
             credit.draw
          end
        end
# THIS  PORTION OF THE METHOD ADDS COLOR TO THE  TEXT AND SEPARATES
# PIECES OF THE WINDOW USING LINES>
draw_line(10,140,Gosu::Color::GREEN,WIDTH,140,Gosu::Color::RED)
@message_font.draw(@message,40,40,1,1,1,Gosu::Color::FUCHSIA)
@message_font.draw(@message2,40,75,1,1,1,Gosu::Color::FUCHSIA)
draw_line(0,500,Gosu::Color::GREEN,WIDTH,500,Gosu::Color::RED)
@message_font.draw(@bottom_message,180,540,1,1,1,Gosu::Color::AQUA)
end

# THIS PORTION CALLS THE  MOVE METHOD FROM THE  CREDITS FILE
def update_end
@credits.each do |credit|
   credit.move
end
if @credits.last.y < 150
    @credits.each do |credit|
     credit.reset
   end
end
end

# COMMANDS THE GAME TO RUN AGAIN IF PLAYER PRESSES "P" OR QUIT GAME IF THE
# PLAYER PRESSES "Q"

def button_down_end(id)
  if id == Gosu::KbP
     initialize_game
   elsif id  == Gosu::KbQ
     close
   end
end
end

def initialize_level(medium)

  case medium
  when :time_expire
    @message_three = "You survived wave number #{@level}. Congratualations!
    Prepare for the next level by Pressing P!"
    @message_font_two = Gosu::Font.new(40)
    @scene = :level
  end

end

  def draw_level
    @message_font_two.draw(@message_three,30,300,1,1,1,Gosu::Color::FUCHSIA)
  end

  def update_level
    @wave_count = 0
    if @scene = :game
      @wave_count += 1
    end
    return @wave_count
  end

  def button_down_level(id)
    if id == Gosu::KbP
       initialize_game
     end
  end

# THIS FUNCTION OPENS THE WINDOW

window = SectorFive.new
window.show

#THANK YOU!
Parent - By jlnr (dev) Date 2019-08-25 21:37
I'm still not quite sure what the issue is, but I would suggest a structure that I've used and seen in many Gosu games: Instead of having all the methods and variables in the Window, you can create new classes such as StartScene, GameScene etc. And then inside your window, you point @scene at an instance of the scene that is currently selected, and call @scene.draw in draw etc. That makes it a lot easier to follow the flow of control throughout the game.

To make it possible for scenes to replace themselves with a new scene, you can pass the window to each scene's constructor, and then you can set @window.scene = EndScene.new(...) to advance to the next part of the game. Or you could simply make the current scene a global variable $scene and update that as appropriate.

Anyway. Once you have scene objects, you would typically construct the scene for a specific level like this: GameScene.new(@window, level_number), and the GameScene would store the level number in an instance variable @level_number. And if you have a screen that comes up inbetween levels, you would also pass the next level number to its constructor, and so on.

I hope that is the kind of progress saving you are talking about? Either way, it's a useful design pattern :)
Parent - By kyonides Date 2019-08-27 03:51
Since jlnr suggested you should redistribute your game data, here's a small example of how to extrapolate all that stuff to different scenes.

#!/usr/bin/env ruby
#   Scripter : Kyonides-Arkanthes
#   Last Update : 2019-08-25
begin
  puts 'Using custom Gosu gem'
  require './gosu.so'
  require './lib/require_custom'
  Game.custom_gem = true
rescue
  puts 'Retry - Now using default Gosu gem'
  require 'gosu'
  require './lib/require_default'
  Game.custom_gem = nil
end
require './tileset'
require './lib/map'
class MainWindow < Gosu::Window
  attr_accessor :scene
  def initialize
    super(800, 608, false, 40) # Custom Gosu Gem
    Game.current_dimensions(self.width, self.height)
    self.show_cursor = true rescue nil
    self.caption = 'KScenario Gosu'
    puts 'Using Gosu version ' + Gosu::VERSION
    Game.setup_title
  end
  def button_down(bid) Game.scene.button_down(bid) end
  def button_up(bid) Game.scene.button_up(bid) end
  def update() Game.update end
  def draw() Game.scene.draw rescue nil end
  #def needs_cursor?() true end # Not needed in my custom Gosu gem!
end

begin
  Game.start_loop(MainWindow)
rescue
  Load.clear
  puts "Rescue!"
  puts m = $!.message
  puts b = $!.backtrace.reverse
  File.open('log.txt','w') do |file|
    puts "Opened file!"
    file.puts Time.now
    file.puts m
    file.puts b
  end
end
Up Topic Gosu / Gosu Exchange / Changing the level in a game

Powered by mwForum 2.29.7 © 1999-2015 Markus Wichitill