Cała oryginalna treść jest tworzona po ukraińsku. Nie wszystkie treści zostały jeszcze przetłumaczone. Niektóre posty mogą być dostępne tylko po ukraińsku.Dowiedz się więcej
Już napisałem minimalny przegląd funkcjonalności biblioteki gosu. Aby napisać prostą grę 2D, tak naprawdę nie potrzeba dużo kodu. Można również uniknąć elementów graficznych i używać prostych figur (narysowanych programowo). Na początek (podczas nauki silnika) tak właśnie trzeba robić, ale skaczący prostokąt może nie być tak fajny, jak coś narysowanego.
Wziąłem darmowe ikony (atrybucja obowiązkowa zgodnie z warunkami użytkowania) Freepik na stronie Flaticon. Grafikę można znaleźć całkowicie za darmo, narysować samodzielnie, zamówić lub wygenerować za pomocą SI. Generowana treść może być odpowiednia do procesu tworzenia, ale do wydania na świat lepiej skorzystać z usług artystów i wspierać ich ekonomię oraz twórczość.
No to wróćmy do tematu tego wpisu - demo gry Drones vs Zombies. Koncepcja jest dość prosta - za pomocą drona trzeba zniszczyć zombie, które próbują dotrzeć do pilota. Demo nie jest idealne, ale dobrze demonstruje, że około 250 linii kodu i kilka obrazków mogą przekształcić pomysł/koncepcję gry w demo.
Sam kod mojego demo:
# Drones VS Zombies v.1.0.0
# Ikony: https://www.flaticon.com/authors/freepik
# Kod: demo by memecode https://tseivo.com/b/memecode
require 'gosu'
class DroneGame < Gosu::Window
WIDTH = 800
HEIGHT = 600
def initialize
super(WIDTH, HEIGHT)
self.caption = "Drones VS Zombies"
reset_game
@background_color = Gosu::Color.new(255, 85, 104, 50)
@font = Gosu::Font.new(20)
@paused = false
end
def update
return if @game_over || @paused
@drones.each(&:update)
handle_explosions
@drones.reject!(&:exploded?)
spawn_drone if @drones.empty?
@zombies.each(&:update)
handle_zombie_movement
handle_collisions
@zombies.reject!(&:dead?)
spawn_zombie if rand < 0.02
check_game_over
end
def draw
draw_quad(0, 0, @background_color, WIDTH, 0, @background_color, WIDTH, HEIGHT, @background_color, 0, HEIGHT, @background_color)
@operator.draw
@drones.each(&:draw)
@zombies.each(&:draw)
@font.draw_text("Punkty: #{@points}", 10, 10, 2)
if @game_over
@font.draw_text("Koniec gry! Ostateczny wynik: #{@points}", WIDTH / 2 - 100, HEIGHT / 2, 3, 1.0, 1.0, Gosu::Color::RED)
@font.draw_text("Naciśnij Spację, aby zrestartować", WIDTH / 2 - 100, HEIGHT / 2 + 30, 3, 1.0, 1.0, Gosu::Color::WHITE)
elsif @paused
@font.draw_text("Wstrzymane", WIDTH / 2 - 50, HEIGHT / 2, 3, 1.0, 1.0, Gosu::Color::YELLOW)
@font.draw_text("Naciśnij Esc, aby wznowić", WIDTH / 2 - 100, HEIGHT / 2 + 30, 3, 1.0, 1.0, Gosu::Color::WHITE)
end
end
def button_down(id)
case id
when Gosu::KbReturn
@drones.each(&:explode) unless @paused
when Gosu::KbSpace
reset_game if @game_over
when Gosu::KbEscape
@paused = !@paused unless @game_over
end
end
private
def handle_collisions
@drones.each do |drone|
# Sprawdź kolizję z operatorem
if drone.collides_with?(@operator) && !drone.exploded?
drone.explode
@game_over = true
next
end
# Sprawdź kolizję z zombie
@zombies.each do |zombie|
if drone.collides_with?(zombie) && !drone.exploded?
zombie.hit
drone.explode
@points += 1
end
end
end
end
def handle_explosions
@drones.each do |drone|
next unless drone.exploded?
@zombies.reject! do |zombie|
drone.collides_with?(zombie)
end
# Sprawdź kolizję z operatorem po eksplozji
if drone.collides_with?(@operator)
@game_over = true
end
end
end
def handle_zombie_movement
@zombies.each do |zombie|
zombie.move_towards(@operator.x, @operator.y)
end
end
def spawn_zombie
@zombies << Zombie.new
end
def spawn_drone
@drones << Drone.new(@operator.x, @operator.y - 100)
end
def check_game_over
@zombies.each do |zombie|
if Gosu.distance(zombie.x, zombie.y, @operator.x, @operator.y) < 30
@game_over = true
end
end
end
def reset_game
@operator = Operator.new
@drones = []
@zombies = []
@points = 0
@game_over = false
@paused = false
spawn_drone
end
end
class Operator
attr_reader :x, :y, :size
def initialize
@x = DroneGame::WIDTH / 2
@y = DroneGame::HEIGHT - 50
@image = Gosu::Image.new("operator.png")
@size = 100
end
def draw
@image.draw(@x - @size / 2, @y - @size / 2, 1)
end
end
class Drone
attr_reader :x, :y, :exploded, :size
def initialize(x, y)
@x, @y = x, y
@image = Gosu::Image.new("drone.png")
@explosion_image = Gosu::Image.new("explosion.png")
@exploded = false
@size = 100
@angle = 0 # Zainicjalizuj kąt
@explosion_timer = 0
end
def update
return if @exploded
@y -= 5 if Gosu.button_down?(Gosu::KbUp)
@y += 5 if Gosu.button_down?(Gosu::KbDown)
@x -= 5 if Gosu.button_down?(Gosu::KbLeft)
@x += 5 if Gosu.button_down?(Gosu::KbRight)
# Rotacja
@angle -= 5 if Gosu.button_down?(Gosu::KbLeft)
@angle += 5 if Gosu.button_down?(Gosu::KbRight)
# Sprawdzanie granic
@x = [[@x, 0].max, DroneGame::WIDTH].min
@y = [[@y, 0].max, DroneGame::HEIGHT].min
if @explosion_timer > 0
@explosion_timer -= 1
end
end
def draw
if @exploded
if @explosion_timer > 0
@explosion_image.draw_rot(@x, @y, 1, @angle, 0.5, 0.5)
end
else
@image.draw_rot(@x, @y, 1, @angle)
end
end
def explode
@exploded = true
@explosion_timer = 550
end
def exploded?
@exploded
end
def collides_with?(object)
Gosu.distance(@x, @y, object.x, object.y) < (@size / 2 + object.size / 2)
end
end
class Zombie
attr_reader :x, :y, :size
def initialize
@x = rand * DroneGame::WIDTH
@y = 0
@image = Gosu::Image.new("zombie.png")
@size = 100
@speed = rand(0.05..0.2)
@alive = true
end
def update
return unless @alive
@y += @speed
end
def draw
@image.draw(@x - @size / 2, @y - @size / 2, 1)
end
def move_towards(target_x, target_y)
if @y < target_y
@y += @speed
elsif @y > target_y
@y -= @speed
end
if @x < target_x
@x += @speed
elsif @x > target_x
@x -= @speed
end
end
def hit
die if Gosu.distance(@x, @y, DroneGame::WIDTH / 2, DroneGame::HEIGHT - 50) < 50
end
def die
@alive = false
@speed = 0
end
def dead?
!@alive
end
end
DroneGame.new.show
Obrazki dodajcie sami (nie chcę przypadkowo naruszyć praw autorskich):
drone.png
explosion.png
operator.png
zombie.png
Rozmiar dla każdego z nich powinien wynosić 100x100px (png z przezroczystością).
Klasa DroneGame
Główny klasa gry, dziedzicząca po Gosu::Window.
Inicjalizuje okno gry, ustawia kolor tła i czcionkę dla elementów tekstowych.
Zawiera logikę do aktualizacji gry (update) i wyświetlania (draw), obsługuje zdarzenia naciśnięcia przycisków (button_down).
Klasa Operator
Reprezentuje operatora drona.
Odpowiada za jego położenie na ekranie i wyświetlanie obrazu operatora.
Klasa Drone
Reprezentuje drona, który jest używany do ataku.
Ma możliwość poruszania się w lewo, w prawo, w górę i w dół, obsługuje eksplozję (explode) oraz sprawdza kolizje z innymi obiektami.
Klasa Zombie
Reprezentuje zombie, które atakują operatora.
Porusza się w kierunku operatora, może być trafione przez drony, co prowadzi do zniszczenia.
Główne funkcje
Start i restart gry: gra zaczyna się od pojawienia się operatora i dronów, które go chronią. Po porażce (gdy zombie dotrą do operatora), gracz może zrestartować grę, naciskając spację (Space).
Dynamiczne obiekty: drony i zombie mają własne obiekty, które aktualizują ich ruch i stan.
Kolizje i eksplozje: logika obsługi kolizji między dronami, zombie i operatorem, a także eksplozji dronów, które prowadzą do zniszczenia zombie i końca gry.
Następnym krokiem chcę dodać dźwięki, narysować groby dla zombie po ich zniszczeniu, poprawić ruch / sterowanie dronem (teraz kręci się wokół osi), zrobić animację śmigieł drona itd. Postanowiłem publikować demo krok po kroku, ponieważ napisanie wszystkich pożądanych rzeczy zajmuje bardzo dużo czasu.
Дрон вбив оператора :(
Na przykład, przed publikacją tego wpisu dodałem kilka rzeczy:
operator drona może przypadkowo zniszczyć się dronem
dodałem granice do pola bitwy (wcześniej dron mógł wylecieć za krawędź okna i w zasadzie zniknąć)