Problem with Space Invaders

Questions about the LÖVE API, installing LÖVE and other support related questions go here.
Forum rules
Before you make a thread asking for help, read this.
Post Reply
User avatar
vSxo.lua
Prole
Posts: 5
Joined: Fri Jun 08, 2018 3:08 pm
Location: Poland

Problem with Space Invaders

Post by vSxo.lua »

Hi. I'm not the best programmer and im not very good at LOVE 2D. So here is the problem. Im on the way of creating a clone of Space Invaders but i encountered a problem with asynchroonus enemies movement. When any enemy touches bounds of the screen function enemies_jump() is called, which calls Enemy:jump() for every enemy. This function is reversing speed of enemies and increasing thier Y position by 64. The middle row of enemies is moving in asynchronous way (it shouldn't). The X pos of most left enemy is weird compared to the rest of the aliens. I dont know why it is happening. They should move all together in the same pattern.

Can you help me? Im using classic.lua library.
Here is the code:

main.lua

Code: Select all

Object = require "classic"
require "player"
require "bullet"
require "enemy"

-- constants
WINDOW_WIDTH = 1024
WINDOW_HEIGHT = 768


function love.load()
	-- window
	love.window.setMode(WINDOW_WIDTH, WINDOW_HEIGHT, {resizable = false, vsync = true})
	love.graphics.setDefaultFilter('nearest', 'nearest')
	love.window.setTitle("Space Invaders")
	
	-- graphics
	background = love.graphics.newImage("background.png")
	ground = love.graphics.newImage("ground.png")
	spritesheet = love.graphics.newImage("sprites.png")
	
	rocket = love.graphics.newQuad(0,0,16,16,spritesheet:getDimensions())
	alien1 = love.graphics.newQuad(16,0,16,16,spritesheet:getDimensions())
	alien2 = love.graphics.newQuad(32,0,16,16,spritesheet:getDimensions())
	alien3 = love.graphics.newQuad(48,0,16,16,spritesheet:getDimensions())
	bullet = love.graphics.newQuad(64,0,16,16,spritesheet:getDimensions())
	charge = love.graphics.newQuad(80,0,16,16,spritesheet:getDimensions())
	heart = love.graphics.newQuad(96,0,16,16,spritesheet:getDimensions())
	
	-- sounds
	shoot = love.audio.newSource("shoot.wav", "static")
	hit = love.audio.newSource("hit.wav", "static")
	gameover = love.audio.newSource("gameover.wav", "static")
	
	-- varibles
	player = Player(512, 576, 3)
	bullets = {} -- table of bullets	
	enemies = {}
	
	spawn_enemies()
end

function spawn_enemies()
	enemy_speed = 150
	table.insert(enemies, Enemy(0, 0, "alien3", enemy_speed))
	table.insert(enemies, Enemy(64, 0, "alien3", enemy_speed))
	table.insert(enemies, Enemy(128, 0, "alien3", enemy_speed))
	table.insert(enemies, Enemy(192, 0, "alien3", enemy_speed))
	table.insert(enemies, Enemy(256, 0, "alien3", enemy_speed))
	table.insert(enemies, Enemy(320, 0, "alien3", enemy_speed))
	table.insert(enemies, Enemy(384, 0, "alien3", enemy_speed))
	table.insert(enemies, Enemy(448, 0, "alien3", enemy_speed))
	table.insert(enemies, Enemy(512, 0, "alien3", enemy_speed))
	table.insert(enemies, Enemy(576, 0, "alien3", enemy_speed))
	table.insert(enemies, Enemy(0, 64, "alien2", enemy_speed))
	table.insert(enemies, Enemy(64, 64, "alien2", enemy_speed))
	table.insert(enemies, Enemy(128, 64, "alien2", enemy_speed))
	table.insert(enemies, Enemy(192, 64, "alien2", enemy_speed))
	table.insert(enemies, Enemy(256, 64, "alien2", enemy_speed))
	table.insert(enemies, Enemy(320, 64, "alien2", enemy_speed))
	table.insert(enemies, Enemy(384, 64, "alien2", enemy_speed))
	table.insert(enemies, Enemy(448, 64, "alien2", enemy_speed))
	table.insert(enemies, Enemy(512, 64, "alien2", enemy_speed))
	table.insert(enemies, Enemy(576, 64, "alien2", enemy_speed))
	table.insert(enemies, Enemy(0, 128, "alien1", enemy_speed))
	table.insert(enemies, Enemy(64, 128, "alien1", enemy_speed))
	table.insert(enemies, Enemy(128, 128, "alien1", enemy_speed))
	table.insert(enemies, Enemy(192, 128, "alien1", enemy_speed))
	table.insert(enemies, Enemy(256, 128, "alien1", enemy_speed))
	table.insert(enemies, Enemy(320, 128, "alien1", enemy_speed))
	table.insert(enemies, Enemy(384, 128, "alien1", enemy_speed))
	table.insert(enemies, Enemy(448, 128, "alien1", enemy_speed))
	table.insert(enemies, Enemy(512, 128, "alien1", enemy_speed))
	table.insert(enemies, Enemy(576, 128, "alien1", enemy_speed))
end

function enemies_jump()
	for i, enemy in pairs (enemies) do
		enemy:jump()
		print("Enemy"..i.. " x:" .. enemy.x .. " y: " .. enemy.y .. " speed: " .. enemy.x_speed)
	end
end

function love.update(dt)
	player:update(dt)
	for index, bullet in pairs (bullets) do 
		bullet:update(dt)
		if bullet.y + bullet.height < 0 then
			table.remove(bullets, index)
		end
	end
	for i, enemy in pairs (enemies) do
		enemy:update(dt)
	end
end

function love.draw()
	love.graphics.draw(background, 0, 0)
	love.graphics.draw(ground, 0, 640, 0, 4, 4)
	player:draw()
	for index,bullet in pairs (bullets) do
		bullet:draw()
	end
	for i, enemy in pairs (enemies) do
		enemy:draw()
	end
end
player.lua

Code: Select all

Player = Object:extend()
require "bullet"

function Player:new(x, y, hearts)
	self.x = x
	self.y = y
	self.width = 64
	self.height = 64
	self.hearts = hearts
	self.speed = 300
	self.cooldown = 0
end

function Player:shot(self)
	table.insert(bullets, Bullet(self.x, self.y - 48))
	self.cooldown = 0.5
end

function Player:update(dt)
	self.cooldown = self.cooldown - dt
	if self.x + self.width > WINDOW_WIDTH then
		self.x = WINDOW_WIDTH - self.width
	end
	if self.x < 0 then
		self.x = 0
	end
	if love.keyboard.isDown("left") then
		self.x = self.x - self.speed * dt
	elseif love.keyboard.isDown("right") then
		self.x = self.x + self.speed * dt
	end
	if love.keyboard.isDown("space") and self.cooldown < 0 then
		Player:shot(self)
	end
end

function Player:draw()
	for i = 1, self.hearts do
		love.graphics.draw(spritesheet, heart, (i - 1) * 64, WINDOW_HEIGHT - 64, 0, 4, 4)
	end
	love.graphics.draw(spritesheet, rocket, self.x, self.y, 0, 4, 4)
end
bullet.lua

Code: Select all

 Bullet = Object:extend()
 
 function Bullet:new(x, y)
	self.x = x
	self.y = y 
	self.width = 20
	self.height = 40
	self.speed = 460
 end
 
 function Bullet:update(dt)
	self.y = self.y - (self.speed * dt)
 end
 
 function Bullet:draw()
	love.graphics.draw(spritesheet, bullet, self.x + 32, self.y + 32, 0, 4, 4, 8,8)
 end
enemy.lua

Code: Select all

 Enemy = Object:extend()

enemies_count = 0

function Enemy:new(x, y, typeof, x_speed)
	self.x = x
	self.y = y
	self.typeof = typeof
	self.x_speed = x_speed
	enemies_count = enemies_count + 1
end

function Enemy:jump()
	self.y = self.y + 64
	self.x_speed = - self.x_speed
end

function Enemy:update(dt)
	self.x = self.x + (self.x_speed * dt)
	if self.x <= 0 then
		self.x = 0
		enemies_jump()
	end
	if self.x + 64 >= WINDOW_WIDTH then
		self.x = WINDOW_WIDTH - 64
		enemies_jump()
	end
end

function Enemy:draw()
	if self.typeof == "alien1" then
	  love.graphics.draw(spritesheet, alien1, self.x, self.y, 0, 4, 4)
	  elseif self.typeof == "alien2" then
	 	love.graphics.draw(spritesheet, alien2, self.x, self.y, 0, 4, 4)
	  else
		love.graphics.draw(spritesheet, alien3, self.x, self.y, 0, 4, 4)
	end
end
Whole project is attached in zip file ;)
Thank you in advance.
Attachments
Space_Invaders.zip
(1.63 MiB) Downloaded 176 times
User avatar
pgimeno
Party member
Posts: 3656
Joined: Sun Oct 18, 2015 2:58 pm

Re: Problem with Space Invaders

Post by pgimeno »

Hi, welcome to the forums!

I believe the cause of the desync is that, by the time you detect that one alien is out of the screen, you have already moved several others. This is made worse by the fact that you're using pairs() instead of ipairs(), and pairs() visits the elements in a random-ish order. But it still happened when I switched to ipairs() so that's not the only cause.

One of several possible solutions is to have a single source of positions. I mean, imagine the aliens are in a box. You move this box, not the aliens. You just place the aliens in a position that is always the same relative to the box. When an alien is killed, you recalculate the box dimensions, just in case it was the last one in the border.

Another possible, perhaps simpler solution is to set a flag when one alien goes out of the screen, instead of correcting it immediately, and when finishing updating, if the flag is set, correct all of them by the same amount.
User avatar
vSxo.lua
Prole
Posts: 5
Joined: Fri Jun 08, 2018 3:08 pm
Location: Poland

Re: Problem with Space Invaders

Post by vSxo.lua »

Thank you pgimeno! I did it with flag setting and now it's working. Now I know why it was not working. I realized this when i changed pairs() to ipairs(). Basically when enemies were hitting right side for the first time only 10 of 30 were updated. When they hit the left side 11 of 30 were updated because loop was broken. :3
Post Reply

Who is online

Users browsing this forum: Ahrefs [Bot], Semrush [Bot] and 2 guests