Unity3d achieve precise collision determination pixel game

Disclaimer: This article is a blogger original article, follow the CC 4.0 BY-SA copyright agreement, reproduced, please attach the original source link and this statement.
This link: https://blog.csdn.net/qq493453700/article/details/99397316
-- 检测碰撞物,如果发生碰撞则进行位移
function LColliderBDY:BDYFixedUpdate(velocity)
	local isGround = false
	local isWall = false

	-- 检测和什么碰,2d碰撞范围一般比实际要大,因为AABB要大一点,为了精确碰撞,需要自己实现
	local contactColliders = CS.Tools.Instance:Collider2DOverlapCollider(self.collider, self.filter) -- 这个函数其实Collider2D.OverlapCollider,用来手动检测碰撞,这边因为lua的缘故封装了一下

	-- 最终位移坐标
	local finalOffset_x = 0
	local finalOffset_y = 0
	for p, k in pairs(contactColliders) do
		if self.collider.bounds:Intersects(k.bounds) then

			local up, down, left, right = false, false, false, false

			local go = k.attachedRigidbody.gameObject
			if go:GetComponent(typeof(CS.UnityEngine.Rigidbody2D)) ~= nil and go.name == "test" then -- 如果是地图块
				local name = utils.split(k.name, ",")
				local num = tonumber(name[#name]) -- 地图块最后一个数字作为bit

				if num | 14 == 15 then --位操作,算出这个方块朝哪个方向进行碰撞,一个方块可以有多个碰撞方向,这部分随意设计,只需要能知道这个collider的判定方向,用layermask什么都行
					up = true
				end
				if num | 13 == 15 then --位操作
					down = true
				end
				if num | 11 == 15 then --位操作
					left = true
				end
				if num | 7 == 15 then --位操作
					right = true
				end
			elseif go:GetComponent(typeof(CS.XLuaTest.LuaBehaviour)) ~= nil then -- 是游戏object,则只允许左右进行碰撞,LuaBehaviour是用来调用lua的脚本,雨女无瓜
				left = true
				right = true
			else
				return false, false
			end

			local menseki = utils.getBoundsIntersectsArea(self.collider.bounds, k.bounds)
			if menseki.magnitude > 0 then -- 无视多少面积设置,先不设

				-- 算2个collider之间距离,主要是为了法线
				local cd2d = self.collider:Distance(k)

				local a =  CS.UnityEngine.Vector3(cd2d.pointA.x, cd2d.pointA.y, 0)
				local b =  CS.UnityEngine.Vector3(cd2d.pointB.x, cd2d.pointB.y, 0)
				local normal =  -CS.UnityEngine.Vector3(cd2d.normal.x, cd2d.normal.y, 0)
				CS.UnityEngine.Debug.DrawLine(a, a + normal, CS.UnityEngine.Color.red)
				CS.UnityEngine.Debug.DrawLine(b, b + normal, CS.UnityEngine.Color.yellow)

				-- 做碰撞法线与行进方向的点积
				-- local projection = CS.UnityEngine.Vector2.Dot(velocity.normalized, normal) -- 没用到,有需要可以自己看情况加

				local offset_x = 0
				local offset_y = 0

				-- 左移,右移
				if self.collider.bounds.center.x < k.bounds.center.x then
					if left and CS.UnityEngine.Vector2.Dot(velocity.normalized, CS.UnityEngine.Vector2(-1, 0)) <= 0 then -- 如果碰撞朝向与行进方向相反,则求出位移坐标

						offset_x = -menseki.x
					end
				else
					if right and CS.UnityEngine.Vector2.Dot(velocity.normalized, CS.UnityEngine.Vector2(1, 0)) <= 0 then
						offset_x = menseki.x
					end
				end
				-- 上移,下移
				if self.collider.bounds.center.y > k.bounds.center.y then
					if up and CS.UnityEngine.Vector2.Dot(velocity.normalized, CS.UnityEngine.Vector2(0, 1)) <= 0 then
						offset_y = menseki.y
					end
				else
					if down and CS.UnityEngine.Vector2.Dot(velocity.normalized, CS.UnityEngine.Vector2(0, -1)) <= 0 then
						offset_y = -menseki.y
					end
				end

				if (up or down) and (left or right) then -- 如果同时满足上下和左右方向同时存在的情况,则根据碰撞方向来筛选掉另一个轴的位移
					offset_x = offset_x * math.abs(normal.x)
					offset_y = offset_y * math.abs(normal.y)
				end

				-- 留下最小位移坐标
				if velocity.x > 0 then
					if offset_x < finalOffset_x then
						finalOffset_x = offset_x
					end
				else
					if offset_x > finalOffset_x then
						finalOffset_x = offset_x
					end
				end

				if velocity.y > 0 then
					if offset_y < finalOffset_y then
						finalOffset_y = offset_y
					end
				else
					if offset_y > finalOffset_y then
						finalOffset_y = offset_y
					end
				end

				if go:GetComponent(typeof(CS.UnityEngine.Rigidbody2D)) ~= nil and go.name == "test" then -- 判断是不是撞到地面,这样写不好,以后再优化
					if finalOffset_x ~= 0 then
						isWall = true
					end
					if finalOffset_y > 0 then
						isGround = true
					end
				end
			end
		end
	end

	-- 更新自身位置
	self.collider.attachedRigidbody.position = self.collider.attachedRigidbody.position + CS.UnityEngine.Vector2(finalOffset_x, finalOffset_y)

	return isGround, isWall
end

Directly on the code, call the code fixedupdate where the code is written in lua

Remember rigidbody2d set Kinematic, useFullKinematicContacts set to false, because we own realization collision, no unity of the collision oncolliderenter like, put this off may improve performance 8

Talk about ideas

Because the unity of aabb collision with box2d trigger range than the range defined to be large, so for pixel games, there will be pixel difference, affect the actual picture, such as standing on the ground sometimes vacated pixels high off the ground a

Moreover, the game is basically a block of pixels determination, but also with what is unlikely to friction, rebound, the geometry of the collision, simple I could add, so their impact is to achieve a good choice

See Official Collider2D.OverlapCollider with the API, the collision was detected, allows to obtain the impactor collision orientation (up, down, left, right), and their collider collider is detected at each detecting bounds, then the intersection

See their area was calculated collision position of an object, whether moving direction and facing toward their object allows collision (dot product is less than 0), i.e. the offset x and y axes of displacement required, based on its own position and to leave minimum offset direction, with the moving direction of the normal to write code may look good points, the last update position rigidbox

Just provide ideas, not the

Guess you like

Origin blog.csdn.net/qq493453700/article/details/99397316