LoginSignup
1
0

More than 1 year has passed since last update.

【Playdate】種類ごとにコライダーの衝突処理を変更する

Posted at

前口上

前回の外部クラス化を用いて、spriteの種類ごとにコライダーの衝突処理を変更してみます。
本記事は以下リポジトリを参考に制作しています。

実装

プレイヤーが矢を射出し、壁に矢がぶつかると反射していくという内容のものを作ります。
プレイヤー、壁、弓矢の3種類のクラスを用意し、クラスを判別してそれぞれのコライダーの衝突処理を実装します。
それぞれ source ディレクトリ直下に配置しています。

player.lua
local gfx <const> = playdate.graphics

class('Player').extends(gfx.sprite)

function Player:init(x, y)
	Player.super.init(self)
	local playerImage = gfx.image.new("Images/playerImage")
	assert( playerImage )
	self:setImage( playerImage )
	self:moveTo( x, y )
	self:setCollideRect(0, 0, self:getSize())
	self.collisionResponse = playdate.graphics.sprite.kCollisionTypeBounce
end

function Player:update()
	local offsetX = 0
	local offsetY = 0
	if playdate.buttonIsPressed( playdate.kButtonUp ) then
		offsetY = -2
	end
	if playdate.buttonIsPressed( playdate.kButtonRight ) then
		offsetX = 2
	end
	if playdate.buttonIsPressed( playdate.kButtonDown ) then
		offsetY = 2
	end
	if playdate.buttonIsPressed( playdate.kButtonLeft ) then
		offsetX = -2
	end
	self:moveWithCollisions(self.x + offsetX, self.y + offsetY)
end


function Player:collisionResponse(other)
	if other:isa(Wall) then
		return playdate.graphics.sprite.kCollisionTypeFreeze
	else
		return playdate.graphics.sprite.kCollisionTypeOverlap
	end
end
wall.lua
local gfx <const> = playdate.graphics

class('Wall').extends(gfx.sprite)

function Wall:init(x, y, w, h)
	Wall.super.init(self)
	local wallImage = gfx.image.new(w, h)
	gfx.pushContext(wallImage)
		gfx.setColor(gfx.kColorWhite)
		gfx.fillRect(0, 0, w, h)
	gfx.popContext()
	self:setImage(wallImage)
	self:moveTo(x, y)
	self:setCollideRect(0, 0, self:getSize())
end
arrow.lua
import "CoreLibs/object"
import "CoreLibs/sprites"

local gfx <const> = playdate.graphics

class('Arrow').extends(gfx.sprite)

function Arrow:init(x, y, speed, accel)
	Arrow.super.init(self)
	local arrowImage = gfx.image.new("Images/arrow")
	self:setImage(arrowImage)
	self:moveTo(x, y)
	self:setCollideRect(0, 4, 12, 5)
	self.speed = speed
	self.accel = accel
	self.currentSpeed = speed
	self.minSpeed = speed / 2
	self.yOffset = math.random(-10,10) / 10
	self.dir = 1
end

function Arrow:update()
	Arrow.super.update(self)
	
	self:moveWithCollisions(self.x + self.dir * self.currentSpeed, self.y + self.yOffset)
	self.currentSpeed -= self.dir * self.accel
	
	if math.abs(self.currentSpeed) < self.minSpeed then
		self.currentSpeed = self.dir * self.minSpeed
	end
end

function Arrow:collisionResponse(other)
	if other:isa(Wall) then
		self.dir *= -1
		self:setRotation(180)
		return playdate.graphics.sprite.kCollisionTypeBounce
	else
		return playdate.graphics.sprite.kCollisionTypeOverlap
	end
end

上記をmain.luaで読み込みます。
矢の射出はAボタンを押すと実行されるようにしました。

main.lua
import "CoreLibs/object"
import "CoreLibs/graphics"
import "CoreLibs/sprites"
import "CoreLibs/timer"

import "arrow"
import "wall"
import "player"

local gfx <const> = playdate.graphics

local playerSprite = nil
local wallSprite = nil

function myGameSetUp()

	playerSprite = Player(200, 120)
	playerSprite:add()
	
	wallSprite = Wall(300, 120, 20, 80)
	wallSprite:add()

	local backgroundImage = gfx.image.new( "Images/background" )
	assert( backgroundImage )

	gfx.sprite.setBackgroundDrawingCallback(
		function( x, y, width, height )
			backgroundImage:draw( 0, 0 )
		end
	)

end

myGameSetUp()

function playdate.update()
	-- 矢を射出
	if playdate.buttonIsPressed(playdate.kButtonA) then
		local newArrow = Arrow(playerSprite.x, playerSprite.y, 10, .1)
		newArrow:add()
	end

	gfx.sprite.update()
	playdate.timer.updateTimers()

end

解説

ポイントとしては動くスプライト(player、arrow)のsprite:collisionResponse(other)で、衝突時の処理を実行します。
otherが衝突したオブジェクトで、other:isa([クラス名])で指定したクラス名に衝突したかを調べています。
collisionResponseの返り値は衝突したときの振る舞いの定数が返ってきています。

あとはmain.luaで初期状態でplayerとwallを出し、update関数のplaydate.buttonIsPressed(playdate.kButtonA)の中でAボタンが押されたとき、矢を射出するよう処理を記述してます。

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0