- 2025/08/09(土)
[love2d]ブロック崩しを作りながら色々な初期設定する
表示が乱れた場合は再ロードをお試しください。
ゲーム開発を始めたばかりの方にとって「最初の画面設定」や「変数の使い方」は、いまいちイメージがつかみにくい部分かもしれません。
この記事では [Love2D] を使ってブロック崩しゲームを作りながら、画面サイズの指定 や 変数の宣言方法、そして 図形や文字の描画 といった基礎をひとつずつ確認していきます。
以下は前回の記事です。
基本的に自分の忘備録もかねています。プロではないので間違っていたらすみません。
作ったものは以下に公開しようかなと思っています。今回のコードもあります。
games/love2d/block at main · N-Samurai/games
ゲーム開発の画面の大きさの設定
まずゲームの画面の大きさなどを設定します。
以下の二つは内容というよりも、共通化したおまじない程度に考えてもらえばいいと思います。
大事なことは800:600でこのゲームを作っているということです。
conf.lua
以下のように設定してみました。
love.conf
LÖVEが最初に読み込む設定用の特別な関数。引数tに色々な設定項目が入っている。t.window.title
ウィンドウのタイトルバーに表示される文字列。t.window.width/t.window.height
ウィンドウの初期サイズ。t.window.highdpi
macOS の Retina ディスプレイや Windows の高DPI環境で高解像度描画をするかどうか。falseにすると通常解像度で描画。t.window.resizable
ユーザーがマウスでウィンドウサイズを変更できるかどうか。
function love.conf(t)
t.window.title = "Lurker test"
t.window.width = 800
t.window.height = 600
t.window.highdpi = false
t.window.resizable = true
endmain.lua
ゲームの基本的な解像度を800:600に指定して、ウインドウサイズを取得してスケーリングで表示が伸びないようにしました。
local gameWidth, gameHeight = 800, 600 -- 内部解像度
local scale, offsetX, offsetY = 1, 0, 0
function love.load()
love.window.setMode(0, 0, { resizable = true }) -- フルスクリーン解像度取得可能
updateScale()
end
function love.resize(w, h)
updateScale()
end
function updateScale()
local windowWidth, windowHeight = love.graphics.getDimensions()
local scaleX = windowWidth / gameWidth
local scaleY = windowHeight / gameHeight
scale = math.min(scaleX, scaleY) -- 縦横比維持
-- 中央寄せオフセット
offsetX = (windowWidth - gameWidth * scale) / 2
offsetY = (windowHeight - gameHeight * scale) / 2
end
function love.draw()
love.graphics.push()
love.graphics.translate(offsetX, offsetY)
love.graphics.scale(scale)
-- ここから下が内部解像度800×600での描画
love.graphics.clear(0.2, 0.2, 0.25)
love.graphics.setColor(1, 1, 1)
love.graphics.print("内部解像度: 800x600", 20, 20)
-- テスト用: 四角を描画
love.graphics.rectangle("line", 0, 0, gameWidth, gameHeight)
love.graphics.pop()
end図形の描画
基本的な図形の描画を以下に示します。
以下のようにlove.draw()で囲んで描画します。
function love.draw()
-- テスト用: 四角を描画
love.graphics.rectangle("line", 0, 0, gameWidth, gameHeight)
end1. 四角形を描く
-- 矩形を描く
love.graphics.rectangle(mode, x, y, width, height)
-- mode: "fill"(塗りつぶし)または "line"(枠線のみ)
love.graphics.setColor(1, 0, 0) -- 赤 (R=1, G=0, B=0)
love.graphics.rectangle("fill", 100, 100, 200, 150)2. 円・楕円を描く
-- 円を描く
love.graphics.circle(mode, x, y, radius)
-- 楕円を描く
love.graphics.ellipse(mode, x, y, radiusX, radiusY)
love.graphics.setColor(0, 1, 0) -- 緑
love.graphics.circle("line", 400, 300, 80)
love.graphics.setColor(0, 0, 1) -- 青
love.graphics.ellipse("fill", 400, 300, 100, 50)3. 多角形を描く
-- 頂点座標を順番に指定
love.graphics.polygon(mode, x1, y1, x2, y2, x3, y3, ...)
love.graphics.setColor(1, 1, 0) -- 黄色
love.graphics.polygon("fill", 100, 100, 150, 50, 200, 100, 150, 150)4. 線を引く
love.graphics.setColor(1, 1, 1) -- 白
love.graphics.setLineWidth(3)
love.graphics.line(50, 50, 200, 200)5. 点を打つ
love.graphics.points(x, y, ...)
love.graphics.setColor(1, 0, 1) -- マゼンタ
love.graphics.points(300, 300, 320, 320, 340, 300)これだけで、以下のように基本的なゲーム画面を作ることができます。

変数の宣言
変数の宣言は以下のように行います。
local lives = 3 -- local: このブロックの中だけ有効
speed = 200 -- global: どこからでも使えるゲームの中だと、プレイヤーの移動であったり、ボールの挙動、ブロックの判定など色々使います。
以下のようにまとめて宣言もできます。
local player = { x=400, y=500, width=50, height=25, speed=1000 }
local block = { width=50, height=50 }
local ball = { x=425, y=490, size=10, vx=180, vy=-220, active=false } --キーの入力
キーの入力は以下のようにisDownで設定します。
function love.update(dt)
-- 上下左右キーで移動
if love.keyboard.isDown("up") then
player.y = player.y - player.speed * dt
end
if love.keyboard.isDown("down") then
player.y = player.y + player.speed * dt
end
if love.keyboard.isDown("left") then
player.x = player.x - player.speed * dt
end
if love.keyboard.isDown("right") then
player.x = player.x + player.speed * dt
end
end移動制限の追加
このままだとプレイヤーの挙動が画面外に行ってしまうため、移動制限を追加しました。
local function clamp(v, lo, hi)
if v < lo then return lo elseif v > hi then return hi else return v end
end
function love.update(dt)
lurker:update() -- ★ これを毎フレーム最初に
if love.keyboard.isDown("right") then player.x = player.x + player.speed*dt end
if love.keyboard.isDown("left") then player.x = player.x - player.speed*dt end
player.x = clamp(player.x, 0, gameWidth - player.size)
end当たり判定の追加
壁とボール
四角の座標は描画されている者の左上から始まります。
丸の座標は中心から始まります。
壁とボールの当たり判定は、右側と左側と上側の3つ必要です。
一つ目の右側は、ボールのx座標とボールのsizeを足したものが800より大きいとき
二つ目の左側は、ボールのx座標からsizeを引いたものが0より小さくなったら
三つ目の左側は、ボールのy座標からsizeを引いたものが0より小さくなったら
速度ベクトルを反転させます。

プレイヤーとボール
今度はプレイヤーとボールです。
操作パドルの中で接触したら速度ベクトルを反転させます。
つまり、ボールのx座標とボールの半径を足したものよりプレイヤーのxが小さく、ボールのx座標とボールの半径を引いたものよりプレイヤーのx座標とパドルの大きさを足したものが大きければいいという範囲になります。
さらに、y座標も同様にやります。くどいので省略します。

ブロックのアルゴリズム
判定は同様の考え方です。ただたくさんあります。
今、ブロックは横に16個、縦に5個並ぶように設計しています。なので、配列で一行目二列目をrow=1,col=2という風に表していきます。
例えば、2行3列のブロックの当たり判定は、3×ブロックのx座標から、3×ブロックのx座標+ブロックの横幅です。
生存フラグ
local cols, rows = 16, 5
local bricks = {}
for j=1, rows do
bricks[j] = {}
for i=1, cols do
bricks[j][i] = true -- true = 生存, false = 破壊済み
end
end当たり判定
当たり判定は先ほどのものを流用します。
for j=1, rows do
for i=1, cols do
if bricks[j][i] then
local rx = (i-1)*block.width
local ry = (j-1)*block.height
local hit, dx, dy = circleRectHit(ball.x, ball.y, ball.size, rx, ry, block.width, block.height)
if hit then
bricks[j][i] = false -- ★ 破壊(=もう描かない/判定しない)
-- 反射方向を決める(どの面に近いかでXかYを反転)
if math.abs(dx) > math.abs(dy) then
ball.vx = -ball.vx
else
ball.vy = -ball.vy
end
goto afterBricks -- 1フレームに1個だけ壊す
end
end
end
end描画
生存フラグが立っているものだけを描画するように変更します。
for j=1, rows do
for i=1, cols do
if bricks[j][i] then
local rx = (i-1)*block.width
local ry = (j-1)*block.height
local hit, dx, dy = circleRectHit(ball.x, ball.y, ball.size, rx, ry, block.width, block.height)
if hit then
bricks[j][i] = false -- ★ 破壊(=もう描かない/判定しない)
-- 反射方向を決める(どの面に近いかでXかYを反転)
if math.abs(dx) > math.abs(dy) then
ball.vx = -ball.vx
else
ball.vy = -ball.vy
end
goto afterBricks -- 1フレームに1個だけ壊す
end
end
end
end文字の描画
文字の描画です。
基本的にwidthで幅を決めて、色と描画する場所を指定します。
function love.draw()
local text = "中央揃えテキスト"
local width = 800 -- 文字を収める領域の幅
love.graphics.setColor(1, 1, 0)
love.graphics.printf(text, 0, 200, width, "center") -- 中央揃え
end"left", "center", "right" で左揃えなどを指定可能です。
フォントサイズを変更するためには以下のように指定することも可能です。
function love.load()
fontSmall = love.graphics.newFont(14)
fontLarge = love.graphics.newFont(32)
end
function love.draw()
love.graphics.setFont(fontSmall)
love.graphics.print("小さい文字", 50, 50)
love.graphics.setFont(fontLarge)
love.graphics.setColor(1, 0, 0)
love.graphics.print("大きい文字", 50, 100)
endhitの関数のところでscoreを加算して得点を表示するようにしました。
love.graphics.setFont(fontLarge)
local width = 80 -- 文字を収める領域の幅
love.graphics.setColor(1, 1, 0)
love.graphics.printf(score, 600, 550, width, "center") -- 中央揃えここまででメインの機能の解説は終わりました。
あとは、スタート時にボタンを発射するとか失敗時の挙動とかを追加して完成です。
まとめ
今回の記事では、Love2D を使ったブロック崩し作りの第一歩として、以下の要素を学びました。
- main.lua 内で内部解像度(800×600)を維持しつつ、リサイズやスケーリングを扱う方法
- love.graphics を用いた図形や文字の描画(四角形、円、多角形、テキストなど)
- 変数の宣言と利用(プレイヤーやボールの位置・速度などを管理)
- キーボード入力の処理でプレイヤーを操作する方法
- 当たり判定とブロック管理により、ゲームらしい挙動を実現する手順
ここまでで、ブロック崩しの基本的な骨組みは完成しました。
このあと「ボールを発射するタイミング」や「ゲームオーバー処理」「スコア表示」などを追加すれば、さらに完成度が高まります。
Love2D はシンプルなコードでゲームが作れるので、今回のサンプルをベースにして 効果音の追加 や 画像の差し替え、アイテム要素の導入 など、自分だけのオリジナル要素を組み込んでみてください。