Trying to change my enemy's image when collision detected

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
grodt
Prole
Posts: 6
Joined: Sun Oct 19, 2014 3:27 am

Trying to change my enemy's image when collision detected

Post by grodt »

I have "Boss" class, and its got properties defined for its default image and hit image. On the collision detction function I have, I start off with setting the boss.image to its default image, and then in the loop for the collision detection, if detects a hit, it changes boss.image to equal the hit image. The problem I have is that when I am shooting the boss, it reflects the image change almost half the time, it doesnt work properly. I can shoot the boss 10 times in a row and sometimes it doesnt show the image change.

love file: https://docs.google.com/uc?authuser=0&i ... t=download

zip: https://docs.google.com/uc?authuser=0&i ... t=download


Boss class:

Code: Select all

-- Boss
function Boss.init()
	local self = {}
	self.x = 100
	self.y = 70
	self.direction = 1
	self.bullets = {}
	self.image = love.graphics.newImage("img/nawaz.png")
	self.hit_sound = love.audio.newSource("sounds/hit.wav")
	self.width = self.image:getWidth()
	self.height = self.image:getHeight()
	self.health = 100
	self.phase = 1
	self.img_hit = love.graphics.newImage("img/nawaz_hit.png")
	self.img_def = love.graphics.newImage("img/nawaz.png")

	function self:draw()
		love.graphics.setColor(255, 255, 255)
		love.graphics.draw(self.image, self.x, self.y)
	end

	function self:update(dt)
		if self.phase == 1 then
			if boss_bullet_mark == 1 then
				dt_boss_bullet_mark = love.timer.getTime()
				boss_bullet_mark = 0
			end

			if love.timer.getTime() > dt_boss_bullet_mark + 0.5 then 
				spawn_boss_bullet(self.x + self.width/2, self.y + self.height, player.x, player.y, self.bullets)
				boss_bullet_mark = 1
			end

			if self.direction == 1 then
				self.x = self.x + 50 * dt
			else
				self.x = self.x - 50 * dt
			end
			if self.x > screen_width - self.width then
				self.direction = 0
			elseif self.x < 0 then
				self.direction = 1
			end
		end

	end

	return self
end
Collision detection for boss getting hit:

Code: Select all

-- Check collisions
function check_collision(player, players_bullets, enemy)
	enemy.image = enemy.img_def
	for i=#players_bullets, 1, -1 do 
        bullet = players_bullets[i]
        if (bullet.y >= enemy.y and bullet.y <= (enemy.y + enemy.height) and bullet.x >= enemy.x and bullet.x <= (enemy.x + enemy.width)) then
			table.remove(players_bullets, i)
			enemy.image = enemy.img_hit
			enemy.hit_sound:play()
			player.score = player.score + 1
        end
	end
end
Full source:

Code: Select all

love.window.setMode(640, 700, {vsync = false})

-- global vars
screen_width =  love.graphics.getWidth()
screen_height = love.graphics.getHeight()
stage = 1
dt_mark = 0
set_mark = 1
boss_bullet_mark = 1
dt_boss_bullet_mark = 0

-- Creating tables
Level_One = {}
Player = {}
StartScreen = {}
Bullet = {}
Boss = {}
Boss_Bullet = {}

-- Boss
function Boss.init()
	local self = {}
	self.x = 100
	self.y = 70
	self.direction = 1
	self.bullets = {}
	self.image = love.graphics.newImage("img/nawaz.png")
	self.hit_sound = love.audio.newSource("sounds/hit.wav")
	self.width = self.image:getWidth()
	self.height = self.image:getHeight()
	self.health = 100
	self.phase = 1
	self.img_hit = love.graphics.newImage("img/nawaz_hit.png")
	self.img_def = love.graphics.newImage("img/nawaz.png")

	function self:draw()
		love.graphics.setColor(255, 255, 255)
		love.graphics.draw(self.image, self.x, self.y)
	end

	function self:update(dt)
		if self.phase == 1 then
			if boss_bullet_mark == 1 then
				dt_boss_bullet_mark = love.timer.getTime()
				boss_bullet_mark = 0
			end

			if love.timer.getTime() > dt_boss_bullet_mark + 0.5 then 
				spawn_boss_bullet(self.x + self.width/2, self.y + self.height, player.x, player.y, self.bullets)
				boss_bullet_mark = 1
			end

			if self.direction == 1 then
				self.x = self.x + 50 * dt
			else
				self.x = self.x - 50 * dt
			end
			if self.x > screen_width - self.width then
				self.direction = 0
			elseif self.x < 0 then
				self.direction = 1
			end
		end

	end

	return self
end

-- Boss Bullet
function Boss_Bullet.init(boss_x, boss_y, dx, dy)

	local self = {}
	self.width = 5
	self.height = 5
	self.x = boss_x
	self.y = boss_y
	self.dx = dx
	self.dy = dy
	self.player_x = player_x
	self.player_y = player_y
	self.color = {102, 51, 0}

	function self:draw()
		love.graphics.setColor(self.color)
		love.graphics.rectangle("fill", self.x, self.y, self.width, self.height)
	end

	function self:update(dt)
		self.x = self.x + (self.dx * dt)
		self.y = self.y + (self.dy * dt)
	end

	return self
end

-- Update the position of the bullets
function update_boss_bullets(boss_bullets, dt)
	for i=#boss_bullets, 1, -1 do 
        bb = boss_bullets[i]
		bb:update(dt) 

		if bb.y > screen_height then
			table.remove(boss_bullets, i)
		end

	end
end

-- Draw all the bullets to the screen
function draw_boss_bullets(boss_bullets)
	for i=#boss_bullets, 1, -1 do 
        bb = boss_bullets[i]
		bb:draw() 
	end
end

function spawn_boss_bullet(boss_x, boss_y, player_x, player_y, boss_bullets)
	local angle = math.atan2((player_y - boss_y), (player_x - boss_x))
	local dx = 100 * math.cos(angle)
    local dy = 100 * math.sin(angle)
	bb = Boss_Bullet.init(boss_x, boss_y, dx, dy)
	table.insert (boss_bullets, bb)
end

-- Level One
function Level_One.init()
	local self = {}
	self.music = love.audio.newSource("sounds/hold_me_back_end.mp3")

	function self:draw()
		love.graphics.setColor(25, 25, 25)
		love.graphics.rectangle("fill", 0, 0, screen_width, screen_height)
	end

	return self
end

-- Player
function Player.init()
	local self = {}
	self.width = 25
	self.height = 25
	self.x = (screen_width/2) - (self.width / 2)
	self.y = (screen_height) - (self.height * 2)
	self.bullets = {}
	self.gun_sound = love.audio.newSource("sounds/shot.wav")
	self.bullet_x = self.x - self.width/2
	self.bullet_y = self.y
	self.score = 0
	self.hit_sound = love.audio.newSource("sounds/player_hit.wav")
	self.alive = true
	self.score_font = love.graphics.newFont("font/PressStart2P.ttf", 20)
	self.score_text = "SCORE:"


	function self:draw()
		love.graphics.setColor(127, 140, 141)
		love.graphics.setFont(self.score_font)
		love.graphics.print(self.score_text..tostring(self.score), 10, 10)	
		if self.alive == true then
			love.graphics.setColor(46, 204, 113)
			love.graphics.rectangle("fill", self.x, self.y, self.width, self.height)
		end
	end

	function self:shoot()
		self.bullet_x = (self.x + self.width/2) - (2.5)
		self.bullet_y = self.y
		b = Bullet.init(self.bullet_x, self.bullet_y)
		table.insert (self.bullets, b)
	end

	function self:update(dt)

		if self.alive == true then

			if self.x > screen_width - self.width then
				self.x = screen_width - self.width
			end

			if self.x < 0 then
				self.x = 0
			end

			if self.y < 0 then
				self.y = 0
			end

			if self.y > screen_height - self.height then
				self.y = screen_height - self.height
			end

			if love.keyboard.isDown( "up" ) then
			   self.y = self.y - 200 * dt
			end
			if love.keyboard.isDown( "down" ) then
			   self.y = self.y + 200 * dt
			end
			if love.keyboard.isDown( "right" ) then
			   self.x = self.x + 200 * dt
			end
			if love.keyboard.isDown( "left" ) then
			   self.x = self.x - 200 * dt
			end
			if love.keyboard.isDown( "lctrl" ) then
				if set_mark == 1 then
					dt_mark = love.timer.getTime()
					set_mark = 0
			   	end
			   	if love.timer.getTime() > dt_mark + 0.2 then
			   		self:shoot(dt)
			   		self.gun_sound:play()
			   		set_mark = 1
				end
			end
		end
	end

	return self
end

-- Bullet
function Bullet.init(x, y)

	local self = {}
	self.width = 5
	self.height = 5
	self.x = x
	self.y = y

	function self:draw()
		love.graphics.setColor(231, 76, 60)
		love.graphics.rectangle("fill", self.x, self.y, self.width, self.height)
	end

	function self:update(dt)
		self.y = self.y - 500 * dt
	end

	return self
end

-- Update the position of the bullets
function update_bullets(players_bullets, dt)
	for i=#players_bullets, 1, -1 do 
        bullet = players_bullets[i]
		bullet:update(dt) 

		if bullet.y < -10 then
			table.remove(players_bullets, i)
		end

	end
end

-- Draw all the bullets to the screen
function draw_bullets(players_bullets)
	for i=#players_bullets, 1, -1 do 
        bullet = players_bullets[i]
		bullet:draw() 
	end
end

-- Check collisions
function check_collision(player, players_bullets, enemy)
	enemy.image = enemy.img_def
	for i=#players_bullets, 1, -1 do 
        bullet = players_bullets[i]
        if (bullet.y >= enemy.y and bullet.y <= (enemy.y + enemy.height) and bullet.x >= enemy.x and bullet.x <= (enemy.x + enemy.width)) then
			table.remove(players_bullets, i)
			enemy.image = enemy.img_hit
			enemy.hit_sound:play()
			player.score = player.score + 1
        end
	end
end

-- Check boss bullet collisions
function check_boss_bullet_collision(player, boss_bullets)
	if player.alive == true then
		for i=#boss_bullets, 1, -1 do 
	        bb = boss_bullets[i]
	        if (bb.y >= player.y and bb.y <= (player.y + player.height) and bb.x >= player.x and bb.x <= (player.x + player.width)) then
				table.remove(boss_bullets, i)
				player.hit_sound:play()
				player.alive = false
	        end
		end
	end
end

-- Check for game over
function check_game_over(player)
	if player.alive == false then
		love.graphics.setColor(0, 0, 0, 200)
		love.graphics.rectangle("fill", 0, 0, screen_width, screen_height)
		game_over_font = love.graphics.newFont("font/PressStart2P.ttf", 40)
		game_over_text = "GAME OVER"
		love.graphics.setColor(231, 76, 60)
		love.graphics.setFont(game_over_font)
		love.graphics.print(game_over_text, (screen_width/2) - (game_over_font:getWidth(game_over_text)/2), (screen_height/2) - (game_over_font:getHeight(game_over_text)/2))
	end
end

-- Start Screen
function StartScreen.init()
	local self = {}
	self.music = love.audio.newSource("sounds/hold_me_back_start.mp3")
	self.start_text = "Tap to Start!"
	self.title_text = "HARAM ZADON"
	self.credit_text = "© 2014 Super Mega Turbo"
	self.screen_font = love.graphics.newFont("font/PressStart2P.ttf", 20)
	self.title_font = love.graphics.newFont("font/PressStart2P.ttf", 40)
	self.credit_font = love.graphics.newFont("font/PressStart2P.ttf", 12)
	self.start_text_width = self.screen_font:getWidth(self.start_text)
	self.start_text_height = self.screen_font:getHeight(self.start_text)	
	self.title_text_width = self.title_font:getWidth(self.title_text)
	self.credit_text_width = self.credit_font:getWidth(self.credit_text)
	self.title_text_height = self.title_font:getHeight(self.title_text)
	self.blink = true
	self.dt = 0

	function self:draw()
		love.graphics.setFont(self.title_font)
		love.graphics.setColor(155, 89, 182)
		love.graphics.print(self.title_text, (screen_width/2) - (self.title_text_width/2), 200)
		love.graphics.setFont(self.credit_font)
		love.graphics.setColor(255, 255, 255)
		love.graphics.print(self.credit_text, (screen_width/2) - (self.credit_text_width/2), (screen_height - 200))
		love.graphics.setFont(self.screen_font)
		love.graphics.setColor(255, 255, 255)
		if self.blink == true then
			love.graphics.print(self.start_text, (screen_width/2) - (self.start_text_width/2), (screen_height/2) - (self.start_text_height/2))
		end
	end

	function self:update(dt)
		self.music:play()
		self.dt = self.dt + dt
		if self.dt > 0.5 then
			self.blink = not self.blink 
			self.dt = self.dt - 0.5
		end
	end

	return self
end

-- Creating instances
start_screen = StartScreen.init()
level_one = Level_One.init()
player = Player.init()
boss = Boss.init()

-- Love game loop
function love.load()
	love.graphics.setBackgroundColor(0, 0, 0)
end

function love.draw()
	if stage == 0 then 
		start_screen:draw()
	elseif stage == 1 then
		level_one:draw()
		player:draw()
		boss:draw()
		draw_bullets(player.bullets)
		draw_boss_bullets(boss.bullets)
		check_game_over(player)
	end 
end

function love.update(dt)
	if love.keyboard.isDown( "return" ) then
   		stage = 1
	end
	if stage == 0 then
		start_screen:update(dt)
	elseif stage == 1 then
		start_screen.music:stop()
		level_one.music:play()
		level_one.music:setVolume(0.0);
		player:update(dt)
		boss:update(dt)
		update_bullets(player.bullets, dt)
		update_boss_bullets(boss.bullets, dt)
		check_collision(player, player.bullets, boss)
		check_boss_bullet_collision(player, boss.bullets)
	end
end
Last edited by grodt on Sun Nov 30, 2014 5:36 pm, edited 2 times in total.
bobbyjones
Party member
Posts: 730
Joined: Sat Apr 26, 2014 7:46 pm

Re: Trying to change my enemy's image when collision detecte

Post by bobbyjones »

Um hello it will be a lot easier if you attached a .love so that we can run the game easier.
grodt
Prole
Posts: 6
Joined: Sun Oct 19, 2014 3:27 am

Re: Trying to change my enemy's image when collision detecte

Post by grodt »

bobbyjones wrote:Um hello it will be a lot easier if you attached a .love so that we can run the game easier.
I updated the post to include the love file download. The uploading via attachment was not working.

Link: https://docs.google.com/uc?authuser=0&i ... t=download
User avatar
nfey
Citizen
Posts: 63
Joined: Tue Feb 18, 2014 9:50 am
Location: Romania

Re: Trying to change my enemy's image when collision detecte

Post by nfey »

From what I can see at a glance, you're calling check_collision() from love.update(). The update() method is called loads of times per second which means that the "img_hit" image stays on for a frame, at most. You need to implement a mechanism that allows the image to stay as "img_hit" for a second or more.

My suggestion is to use a timer (a simple integer variable) that you substract from on each love.update(), if the boss was hit. When the timer reaches 0, you change the image back to the normal boss image.

There might be better ways to handle this, however. I'm sure some of the more experienced Love users can give more intelligent solutions.
Post Reply

Who is online

Users browsing this forum: Ahrefs [Bot] and 4 guests