Browse Source

Some sounds;

bjorn 10 years ago
parent
commit
4d55443163
11 changed files with 279 additions and 0 deletions
  1. 188 0
      deps/slam.lua
  2. 67 0
      deps/sound.lua
  3. 1 0
      game.lua
  4. 1 0
      loader.lua
  5. BIN
      media/sounds/impact.ogg
  6. BIN
      media/sounds/pop.ogg
  7. BIN
      media/sounds/scream1.ogg
  8. BIN
      media/sounds/splat.ogg
  9. 19 0
      person.lua
  10. 1 0
      pigeon.lua
  11. 2 0
      require.lua

+ 188 - 0
deps/slam.lua

@@ -0,0 +1,188 @@
+-- Simple LÖVE Audio Manager
+--
+-- Copyright (c) 2011 Matthias Richter
+-- Permission is hereby granted, free of charge, to any person obtaining a copy
+-- of this software and associated documentation files (the "Software"), to deal
+-- in the Software without restriction, including without limitation the rights
+-- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+-- copies of the Software, and to permit persons to whom the Software is
+-- furnished to do so, subject to the following conditions:
+--
+-- The above copyright notice and this permission notice shall be included in
+-- all copies or substantial portions of the Software.
+--
+-- Except as contained in this notice, the name(s) of the above copyright holders
+-- shall not be used in advertising or otherwise to promote the sale, use or
+-- other dealings in this Software without prior written authorization.
+--
+-- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+-- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+-- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+-- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+-- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+-- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+-- THE SOFTWARE.
+--
+
+local newInstance = love.audio.newSource
+local stop = love.audio.stop
+
+------------------
+-- source class --
+------------------
+local Source = {}
+Source.__index = Source
+Source.__newindex = function(_,k) error(('Cannot write key %s'):format(tostring(k))) end
+
+local function remove_stopped(sources)
+	local remove = {}
+	for s in pairs(sources) do
+		remove[s] = true
+	end
+	for s in pairs(remove) do
+		sources[s] = nil
+	end
+end
+
+local function get_target(target)
+	if type(target) == 'table' then
+		return target[math.random(1,#target)]
+	end
+	return target
+end
+
+local play_instance, stop_instance
+function Source:play()
+	remove_stopped(self.instances)
+	if self._paused then self:stop() end
+	local instance = newInstance(get_target(self.target), self.how)
+
+	-- overwrite instance:stop() and instance:play()
+	if not (play_instance and stop_instance) then
+		play_instance = getmetatable(instance).play
+		getmetatable(instance).play = error
+
+		stop_instance = getmetatable(instance).stop
+		getmetatable(instance).stop = function(this)
+			stop_instance(this)
+			self.instances[this] = nil
+		end
+	end
+
+	instance:setLooping(self.looping)
+	instance:setPitch(self.pitch)
+	instance:setVolume(self.volume)
+
+	self.instances[instance] = instance
+	play_instance(instance)
+	return instance
+end
+
+function Source:stop()
+	for s in pairs(self.instances) do
+		s:stop()
+	end
+	self._paused = false
+	self.instances = {}
+end
+
+function Source:pause()
+	if self._paused then return end
+	for s in pairs(self.instances) do
+		s:pause()
+	end
+	self._paused = true
+end
+
+function Source:resume()
+	if not self._paused then return end
+	for s in pairs(self.instances) do
+		s:resume()
+	end
+	self._paused = false
+end
+
+function Source:addTags(tag, ...)
+	if not tag then return end
+	love.audio.tags[tag][self] = self
+	return Source.addTags(self, ...)
+end
+
+function Source:removeTags(tag, ...)
+	if not tag then return end
+	love.audio.tags[tag][self] = nil
+	return Source.removeTags(self, ...)
+end
+
+function Source:isStatic()
+	return self.how ~= "stream"
+end
+
+-- getter/setter for looping, pitch and volume
+for _, property in ipairs{'looping', 'pitch', 'volume'} do
+	local name = property:sub(1,1):upper() .. property:sub(2)
+	Source['get' .. name] = function(self)
+		return self[property]
+	end
+
+	Source['set' .. name] = function(self, val)
+		self[property] = val
+		for s in pairs(self.instances) do
+			s['set' .. name](s, val)
+		end
+	end
+end
+Source.isLooping = Source.getLooping
+
+--------------------------
+-- love.audio interface --
+--------------------------
+function love.audio.newSource(target, how)
+	local s = {
+		_paused   = false,
+		target    = target,
+		how       = how,
+		instances = {},
+		looping   = false,
+		pitch     = 1,
+		volume    = 1,
+	}
+	if how == 'static' and type(target) == 'string' then
+		s.target = love.sound.newSoundData(target)
+	end
+	love.audio.tags.all[s] = s
+	return setmetatable(s, Source)
+end
+
+function love.audio.play(source)
+	assert(source and source.instances, "Can only play source objects.")
+	return source:play()
+end
+
+function love.audio.stop(source)
+	if source and source.stop then return source:stop() end
+	stop()
+end
+
+----------
+-- tags --
+----------
+local Tag = { __mode = "kv" }
+function Tag:__index(func)
+	-- calls a function on all tagged sources
+	return function(...)
+		for s in pairs(self) do
+			assert(type(s[func]) == "function", ("`%s' does not name a function."):format(func))
+			s[func](s, ...)
+		end
+	end
+end
+
+love.audio.tags = setmetatable({}, {
+	__newindex = error,
+	__index = function(t,k)
+		local tag = setmetatable({}, Tag)
+		rawset(t, k, tag)
+		return tag
+	end,
+})

+ 67 - 0
deps/sound.lua

@@ -0,0 +1,67 @@
+Sound = class()
+
+function Sound:init(options)
+  options = options or {}
+
+  self.muted = options.muted or false
+  self.volumes = {master = options.master or 1.0, music = options.music or 1.0, sound = options.sound or 1.0}
+	self.sounds = {}
+  self.tags = {sound = setmetatable({}, {__mode = 'kv'}), music = setmetatable({}, {__mode = 'kv'})}
+  self.baseVolumes = setmetatable({}, {__mode = 'k'})
+
+  if ctx.event then
+    ctx.event:on('sound.play', f.cur(self.play, self))
+    ctx.event:on('sound.loop', f.cur(self.loop, self))
+  end
+end
+
+function Sound:update()
+  love.audio.setPosition(ctx.view.x + ctx.view.width / 2, ctx.view.y + ctx.view.height / 2, 200)
+end
+
+function Sound:play(sound, cb)
+  if self.muted or not sound then return end
+  if type(sound) == 'string' then sound = data.media.sounds[sound] end
+  if not sound then return end
+
+  local isMusic = self:isMusic(sound)
+
+  local sound = sound:play()
+  if sound then f.exe(cb, sound) end
+  local tag = isMusic and 'music' or 'sound'
+  self.tags[tag] = self.tags[tag] or {}
+  self.tags[tag][sound] = sound
+  self.baseVolumes[sound] = sound:getVolume()
+  self:refreshVolumes()
+  return sound
+end
+
+function Sound:loop(sound, cb)
+  return self:play(sound, function(sound)
+    sound:setLooping(true)
+    f.exe(cb, sound)
+  end)
+end
+
+function Sound:mute()
+  self.muted = not self.muted
+  self:refreshVolumes()
+end
+
+function Sound:setMute(muted)
+  if self.muted ~= muted then self:mute() end
+end
+
+function Sound:isMusic(sound)
+  return sound == data.media.sounds.riteOfPassage or (ctx.biome and sound == data.media.sounds[ctx.biome])
+end
+
+function Sound:refreshVolumes()
+  table.each(self.tags.music, function(sound)
+    sound:setVolume(self.muted and 0 or self.volumes.master * self.volumes.music * (self.baseVolumes[sound] or 1))
+  end)
+
+  table.each(self.tags.sound, function(sound)
+    sound:setVolume(self.muted and 0 or self.volumes.master * self.volumes.sound * (self.baseVolumes[sound] or 1))
+  end)
+end

+ 1 - 0
game.lua

@@ -21,6 +21,7 @@ function Game:load()
   self.hud = Hud()
   self.hud = Hud()
   self.goal = Goal()
   self.goal = Goal()
   self.particles = Particles()
   self.particles = Particles()
+  self.sound = Sound()
 
 
   self.map:spawnHuts()
   self.map:spawnHuts()
 
 

+ 1 - 0
loader.lua

@@ -34,6 +34,7 @@ data.load = function()
 
 
   data.media = {}
   data.media = {}
 	data.media.graphics = setmetatable({_path = 'media/graphics'}, {__index = lookup({'.png', '.dds'}, love.graphics and love.graphics.newImage or f.empty)})
 	data.media.graphics = setmetatable({_path = 'media/graphics'}, {__index = lookup({'.png', '.dds'}, love.graphics and love.graphics.newImage or f.empty)})
+	data.media.sounds = setmetatable({_path = 'media/sounds'}, {__index = lookup('.ogg', love.audio and love.audio.newSource or f.empty)})
 
 
   -- Data
   -- Data
   local function load(dir, type, fn)
   local function load(dir, type, fn)

BIN
media/sounds/impact.ogg


BIN
media/sounds/pop.ogg


BIN
media/sounds/scream1.ogg


BIN
media/sounds/splat.ogg


+ 19 - 0
person.lua

@@ -23,6 +23,9 @@ function Person:activate()
 
 
   self.phlerp = PhysicsInterpolator(self, 'alpha')
   self.phlerp = PhysicsInterpolator(self, 'alpha')
 
 
+  self.screamed = false
+  self.splatted = false
+
   ctx.event:emit('view.register', {object = self})
   ctx.event:emit('view.register', {object = self})
 
 
   Enemy.activate(self)
   Enemy.activate(self)
@@ -71,6 +74,16 @@ function Person:collideWith(other)
     end
     end
   end
   end
 
 
+  if select(2, self.body:getLinearVelocity()) > 1000 then
+    if not self.splatted then
+      ctx.sound:play('splat')
+      self.splatted = true
+      if self.screamSound then
+        self.screamSound:stop()
+      end
+    end
+  end
+
   return true
   return true
 end
 end
 
 
@@ -108,6 +121,7 @@ function Person.dead:enter()
   self.body:applyLinearImpulse(-200 + love.math.random() * 400, -200 + love.math.random() * -500)
   self.body:applyLinearImpulse(-200 + love.math.random() * 400, -200 + love.math.random() * -500)
   self.body:setAngularVelocity(-20 + love.math.random() * 40)
   self.body:setAngularVelocity(-20 + love.math.random() * 40)
   ctx.hud:addScore(10, 'person')
   ctx.hud:addScore(10, 'person')
+  ctx.sound:play('pop')
 end
 end
 
 
 function Person.dead:update()
 function Person.dead:update()
@@ -118,4 +132,9 @@ function Person.dead:update()
       ctx.enemies:remove(self)
       ctx.enemies:remove(self)
     end
     end
   end
   end
+
+  if y > 1000 and not self.screamed then
+    self.screamed = true
+    self.screamSound = ctx.sound:play('scream1')
+  end
 end
 end

+ 1 - 0
pigeon.lua

@@ -92,6 +92,7 @@ function Pigeon:init()
     elseif name == 'laser' then
     elseif name == 'laser' then
       self.laser.active = true
       self.laser.active = true
     elseif name == 'peck' and self.state == self.peck then
     elseif name == 'peck' and self.state == self.peck then
+      ctx.sound:play(data.media.sounds.impact)
       self.peck.impact(self)
       self.peck.impact(self)
     end
     end
   end)
   end)

+ 2 - 0
require.lua

@@ -5,6 +5,8 @@ lume = require 'deps/lume'
 lurker = require 'deps/lurker'
 lurker = require 'deps/lurker'
 ls = require 'deps/lovestep/lovestep'
 ls = require 'deps/lovestep/lovestep'
 shine = require 'deps/shine'
 shine = require 'deps/shine'
+require 'deps/slam'
+require 'deps/sound'
 require 'deps/lutil/util'
 require 'deps/lutil/util'
 require 'deps/util'
 require 'deps/util'
 require 'deps/animation'
 require 'deps/animation'