2017/11/27(月) [n年前の日記]
#1 [love2d][lua] love2dでシューティングゲームの自機っぽいものを書いてたり
love2dを使って、縦スクロールシューティングゲームの自機っぽい処理を書いてたり。
こんな感じに。カーソルキーで移動。Zキーで弾を撃つ方向の変更/固定を切り替え。
動作確認環境は、Windows10 x64 + love2d 0.10.2。
弾を加算合成で描画してるので、love2d 0.10.0以降が必要。もっとも、加算合成の指定部分を修正すれば love2d 0.9.x でも動きそうだけど…。
こんな感じに。カーソルキーで移動。Zキーで弾を撃つ方向の変更/固定を切り替え。
動作確認環境は、Windows10 x64 + love2d 0.10.2。
弾を加算合成で描画してるので、love2d 0.10.0以降が必要。もっとも、加算合成の指定部分を修正すれば love2d 0.9.x でも動きそうだけど…。
◎ 使用画像。 :
以下が自作の使用画像。License : CC0 / Public Domain ってことで。
_airplane_03_64x64_000.png
_airplane_03_64x64_001.png
_bg_640x480_02.png
_bullet_01_32x32.png
_airplane_03_64x64_000.png
_airplane_03_64x64_001.png
_bg_640x480_02.png
_bullet_01_32x32.png
◎ ソース。 :
_conf.lua
_main.lua
function love.conf(t) t.window.title = "Stg Player Test01" t.window.width = 1280 t.window.height = 720 t.window.vsync = true -- t.window.fullscreen = true -- t.window.fullscreentype = "exclusive" end
_main.lua
-- Stg Player Test01 angle_change_key = false function love.load() -- init -- set filter love.graphics.setDefaultFilter("nearest", "nearest") scr_w = 640 scr_h = 480 canvas = love.graphics.newCanvas(scr_w, scr_h) -- get window width and height wdw_w, wdw_h = love.graphics.getDimensions() scr_scale = math.min((wdw_w / scr_w), (wdw_h / scr_h)) scr_ofsx = (wdw_w - (scr_w * scr_scale)) / 2 scr_ofsy = (wdw_h - (scr_h * scr_scale)) / 2 -- load image bgimg = love.graphics.newImage("bg_640x480_02.png") player_img_a = love.graphics.newImage("airplane_03_64x64_000.png") player_img_b = love.graphics.newImage("airplane_03_64x64_001.png") bullet_img = love.graphics.newImage("bullet_01_32x32.png") -- define player class Player = {} Player.new = function(x, y, img_a, img_b) local obj = {} obj.activate = true obj.speed = 300 obj.x = x obj.y = y obj.gun_angle = -90 obj.gun_angle_change_mode = false obj.img_a = img_a obj.img_b = img_b obj.img_w = img_a:getWidth() obj.img_h = img_a:getHeight() setmetatable(obj, {__index = Player}) return obj end Player.update = function(self, dt) if not self.activate then return end if angle_change_key then self.gun_angle_change_mode = not(self.gun_angle_change_mode) angle_change_key = false end local ang = -1 if love.keyboard.isDown("left") then ang = 180 elseif love.keyboard.isDown("right") then ang = 0 end if love.keyboard.isDown("up") then if ang < 0 then ang = 270 elseif ang == 0 then ang = 270 + 45 else ang = 180 + 45 end elseif love.keyboard.isDown("down") then if ang < 0 then ang = 90 elseif ang == 0 then ang = 45 else ang = 180 - 45 end end if ang >= 0 then local spd = self.speed * dt local ra = math.rad(ang) self.x = self.x + (spd * math.cos(ra)) self.y = self.y + (spd * math.sin(ra)) if self.gun_angle_change_mode then -- gun angle change local tgt_ang = (ang + 180) % 360 if self.gun_angle ~= tgt_ang then local a = (tgt_ang - self.gun_angle) % 360 if a > 180 then a = a - 360 end local spd = 5 if a > 0 then if a < spd then self.gun_angle = tgt_ang else self.gun_angle = (self.gun_angle + spd) % 360 end elseif a < 0 then if a > -spd then self.gun_angle = tgt_ang else self.gun_angle = (self.gun_angle - spd) % 360 end end end end end -- move area check local wh = self.img_w / 2 local hh = self.img_h / 2 local xmin, ymin = wh, hh local xmax, ymax = scr_w - wh, scr_h - hh self.x = math.min(math.max(self.x, xmin), xmax) self.y = math.min(math.max(self.y, ymin), ymax) end Player.draw = function(self) if not self.activate then return end local ox, oy = self.img_w / 2, self.img_h / 2 local x, y = self.x, self.y local ang = math.rad(self.gun_angle) local scale = 1.0 love.graphics.draw(self.img_a, x, y, 0, scale, scale, ox, oy) love.graphics.draw(self.img_b, x, y, ang, scale, scale, ox, oy) end -- define player bullet class PlayerBullet = {} PlayerBullet.new = function(x, y, ang, img) local obj = { speed = 600, activate = true, x = x, y = y, ang = ang, img = img } obj.img_w, obj.img_h = img:getWidth(), img:getHeight() obj.img_wh, obj.img_hh = obj.img_w / 2, obj.img_h / 2 setmetatable(obj, {__index = PlayerBullet}) return obj end PlayerBullet.update = function(self, dt) if not self.activate then return end local ra = math.rad(self.ang) self.x = self.x + (math.cos(ra) * self.speed * dt) self.y = self.y + (math.sin(ra) * self.speed * dt) local xmin, ymin = -self.img_wh, -self.img_hh local xmax, ymax = scr_w + self.img_wh, scr_h + self.img_hh if self.x < xmin or self.x > xmax or self.y < ymin or self.y > ymax then self.activate = false end end PlayerBullet.draw = function(self) if not self.activate then return end love.graphics.draw(self.img, self.x, self.y, math.rad(self.ang), 1.0, 1.0, self.img_wh, self.img_hh) end -- work math.randomseed(0) player = Player.new(scr_w / 2, scr_h / 2, player_img_a, player_img_b) player_bullets = {} shot_timer = 0 -- framerate steady min_dt = 1 / 60 next_time = love.timer.getTime() end function love.update(dt) -- update next_time = next_time + min_dt if dt > 1.0 then return end player:update(dt) shot_timer = shot_timer + dt if shot_timer >= 0.1 then -- born player bullet shot_timer = shot_timer - 0.1 local x = player.x local y = player.y local ang = player.gun_angle + math.random(-20, 20) / 10 local obj = PlayerBullet.new(x, y, ang, bullet_img) table.insert(player_bullets, obj) end -- move player bullets for i, spr in ipairs(player_bullets) do spr:update(dt) end -- remove bullet local elen = #player_bullets for i=elen,1,-1 do if not player_bullets[i].activate then table.remove(player_bullets, i) end end end function love.draw() -- set canvas love.graphics.setCanvas(canvas) -- draw BG love.graphics.setColor(255, 255, 255) love.graphics.draw(bgimg, 0, 0) -- draw objects love.graphics.setColor(255, 255, 255) player:draw() love.graphics.setBlendMode("add") for i, spr in ipairs(player_bullets) do spr:draw() end love.graphics.setBlendMode("alpha") -- unset canvas love.graphics.setCanvas() -- draw canvas to window love.graphics.setColor(255, 255, 255) love.graphics.draw(canvas, scr_ofsx, scr_ofsy, 0, scr_scale, scr_scale) love.graphics.print("FPS: "..tostring(love.timer.getFPS()), 10, 10) love.graphics.print("env: "..tostring(love.system.getOS()), 10, 40) if love.system.getOS() == "Windows" then -- wait local cur_time = love.timer.getTime() if next_time <= cur_time then next_time = cur_time else love.timer.sleep(next_time - cur_time) end end end function love.keypressed(key, isrepeat) -- ESC to exit if key == "escape" then love.event.quit() elseif key == "z" then angle_change_key = true end end
◎ 少し説明。 :
加算合成描画は、love.graphics.setBlendMode("add") を指定してから描画すればいいらしい。通常描画に戻すときは、love.graphics.setBlendMode("alpha") を呼ぶ。
love.graphics.setBlendMode("add") for i, spr in ipairs(player_bullets) do spr:draw() end love.graphics.setBlendMode("alpha")
[ ツッコむ ]
以上です。