类似炉石传说 箭头效果

首先声明我用的是corona引擎,不过思路都是一样的,看懂了就可以改成给其他引擎使用

先上代码:

local M = {}
local rectH = 80
M.tRect = {}
--根据数组长度分段类等腰三角形一次函数/\
local function linearFunction( sum,k,min,max )
	local y
	if sum==1 then
		return min
	end
	if k>= 1+(sum-1)/2 then
		y=max/(1-sum)*k+min-(max*sum/(1-sum))
	else
		y=max/(sum-1)*k+min-(max/(sum-1))
	end
	return y
end

--抛物线
local function parabola( x )
	local y = math.pow((x),2)*0.3
	return y
end

--抛物线
local function getScale( distanceXY )
	return (1+distanceXY/6000)
end
--设置矩形y坐标
local function setRectY( ... )
	local height = 0
	for k,imgRect in pairs(M.tRect) do
		--矩形之间间隙
		local spaceY = linearFunction(#M.tRect,k,4,20)
		height = height+imgRect.height+spaceY
		imgRect.y = height
	end
end
--移除所有矩形
local function removeAllRect( ... )
	for i,imgRect in pairs(M.tRect) do
		display.remove(imgRect)
		imgRect = nil
	end
	M.tRect = {}
end
--计算矩形高度
local function computerRectHeight( sum,k )
	--图片高度
	local height = linearFunction(sum,k,30,80)
	return height
end
--计算distanceXY应该创建多少个矩形
local function getAllCount( distanceXY )
	if distanceXY<=rectH then
		return 0
	end
	--架设矩形个数在1-20之间反复检测,满足条件就返回
	--i为创建个数
	for i=1,20 do
		local height = 0
		for j=1,i do
			--矩形之间间隙
			local spaceY = linearFunction(i,j,4,20)
			height = height+getScale(distanceXY)*computerRectHeight(i,j)+spaceY
			if height>=distanceXY-rectH then
				return i
			end
		end
	end
	return 20
end
--创建矩形
local function createRect( distanceXY )
	local count = getAllCount(distanceXY)-#M.tRect
	if count>0 then
		for i=1,count do
			local imgRect = display.newImage( M.gRect, "arrow/rect.png")
			imgRect.anchorY = 1
			table.insert(M.tRect,imgRect)
		end
	elseif count<0 then
		for i=1,-count do
			local imgRect = table.remove(M.tRect)
			display.remove(imgRect)
			imgRect = nil
		end
	end
end

--设置角度,高度,图形的变形
local function setCoordinate( startX,startY,endX,endY,distanceX,distanceY,distanceXY )
	M.imgCenter.x,M.imgCenter.y = endX,endY
	M.imgArrow.x,M.imgArrow.y = endX,endY
	M.imgArrow.rotation = math.atan2(distanceY,distanceX)*180/math.pi+90

	M.gRect.x,M.gRect.y = startX,startY
    M.gRect.rotation = math.atan2(distanceY,distanceX)*180/math.pi+90
    M.gRect.xScale,M.gRect.yScale = getScale(distanceXY),getScale(distanceXY)

    local len = #M.tRect
    local centerLen = math.ceil(#M.tRect/2)
    for k,imgRect in pairs(M.tRect) do
		local offsetLen = math.abs(centerLen-k)
		if centerLen-k<0 then
			imgRect.path.x1 = parabola(offsetLen-1)
			imgRect.path.x4 = -parabola(offsetLen-1)

			imgRect.path.x2 = parabola(offsetLen)
			imgRect.path.x3 = -parabola(offsetLen)

		else
			imgRect.path.x1 = parabola(offsetLen)
			imgRect.path.x4 = -parabola(offsetLen)

			imgRect.path.x2 = parabola(offsetLen-1)
			imgRect.path.x3 = -parabola(offsetLen-1)
		end
		if #M.tRect%2~=0 and k==centerLen then
			imgRect.path.x1 = 0
			imgRect.path.x4 = 0

			imgRect.path.x2 = 0
			imgRect.path.x3 = 0
		end
		if #M.tRect%2==0 and (k==centerLen or k==centerLen+1 ) then
			if k==centerLen then
				imgRect.path.x1 = 0
				imgRect.path.x4 = 0
			end
			if k==centerLen+1 then
				imgRect.path.x2 = 0
				imgRect.path.x3 = 0
			end
		end
		imgRect.height = computerRectHeight(#M.tRect,k)
	end
end
--touch事件监听
local function touchListener( event )
	local phase = event.phase
	local self = event.target
	local endX,endY =  event.x-M.gTouch.x,event.y-M.gTouch.y
	local startX,startY = event.xStart-M.gTouch.x,event.yStart-M.gTouch.y
	local distanceX,distanceY = endX-startX,endY-startY
	local distanceXY = math.sqrt(math.pow((distanceY),2)+math.pow((distanceX),2))

	-- print("phase",phase,startX,startY)
	if phase == "began" then
        display.getCurrentStage():setFocus( self )
        self.isFocus = true
        M.imgCenter.isVisible = true
        M.imgArrow.isVisible = true
        M.gRect.isVisible = distanceXY>=rectH
        setCoordinate(startX,startY,endX,endY,distanceX,distanceY,distanceXY)
    elseif ( self.isFocus ) then
        if phase == "moved" then
        	M.gRect.isVisible = distanceXY>=rectH
        	createRect(distanceXY)
        	setCoordinate(startX,startY,endX,endY,distanceX,distanceY,distanceXY)
        	-- setRectY()
        elseif phase == "ended" or phase == "cancelled" then
            display.getCurrentStage():setFocus( nil )
            self.isFocus = nil
            M.imgCenter.isVisible = false
            M.imgArrow.isVisible = false
            M.gRect.isVisible = false
            removeAllRect()
        end
    end
    return true
end
function M.addListener( sceneGroup )
	M.gTouch = display.newGroup()
	M.gTouch.x,M.gTouch.y = display.contentWidth/2,display.contentHeight/2
	-- 底图
    local imgBg = display.newRect( M.gTouch, 0,0, display.contentWidth,display.contentHeight )
    --背景
    local imgBg = display.newImage( M.gTouch, "bg.png")

    --靶心
	M.imgCenter = display.newImage( M.gTouch, "arrow/center.png")
	M.imgCenter.isVisible = false
	--矩形条组
	M.gRect = display.newGroup()
	M.gTouch:insert(M.gRect)
	M.gRect.anchorY = 1
	M.gRect.anchorChildren = true
	M.gRect.isVisible = false
	--箭头
	M.imgArrow = display.newImage( M.gTouch, "arrow/arrow.png")
	M.imgArrow.anchorY = -3
	M.imgArrow.isVisible = false

	
	
	M.gTouch:addEventListener( "touch", touchListener )
	Runtime:addEventListener( "enterFrame", setRectY )
	return M.gTouch
end
return M

设计前的分析思路:

1.我们应该先分析这一整个箭头的功能是由哪几块组成的,如何分块较容易实现该功能。

2.分析这个功能的难点有哪些?角度,怎么表现的有立体感,一块块矩形组成起来怎么表现出有弧度。

设计思路:

1.我们将整个箭头分成三块,矩形块的组(a),箭头(b),靶心(c)。a里面存放的一块块小矩形。

2.当鼠标移动的时候,我们只要记录touch事件点击起始的x,y,和现在touch事件的现在的x,y。便可以求出旋转的角度。

    相关公式:math.atan2(distanceY,distanceX)*180/math.pi+90

    distanceX,distanceY为起始x,y和现在x,y的差值

    求出的角度用来设置箭头(b)和矩形块组(a)的rotation,并且设矩形块组(a)锚点anchorY=1

    并且将箭头(b)和靶心(c)的坐标设成touch事件的坐标,保证(b)和(c)一直跟着touch的位置移动。

    然后将矩形块的组(a)的位置设成touch事件点击的起始位置。

3.当然,我们监听的touch事件,只需要touch为移动的时候去创建。放开的时候移除矩形就可以了。

4.那么如何创建矩形,刚开始的思路是根据distanceX和distanceY勾股定理,得出鼠标起始位置到终点位置的距离(l),并且根据距离(l),得出需要创建几个矩形。刚开始还没将立体感考虑进去,所以当每个矩形的rHeight为一个固定值,所以只要l/rHeight就得出了这个距离所要创建的矩形个数。并且touch移动的时候,不要反复的全部移除和创建,而是根据距离(l),l长了就在原来矩形块组(a)的基础上继续创建所需的个数,如果l短了,就移除多了的个数。

5.在每一帧去设置这些矩形的y,y就是根据上一个矩形的y加上矩形的height,再加上一个间隙。

6.当上面的步骤做好后,其实已经有一个可以看的箭头效果了,只是不立体而已。接下来我们就是做立体的效果,有种抛物线的感觉

    第一步,如果需要抛物线的效果,我们的视角是在箭头的正上方,所以整个矩形块组(a)表现出的效果就应该是两边小,中间大。所以我们要对每一个矩形做形变,两边的矩形,要形变成梯形,并且越靠矩形块组(a)的中部,形变越小,最中间的不形变。这时我只考虑矩形的width,先不考虑rHeight,因为rHeight涉及到距离(l)所要创建的矩形个数。代码中设置的x1,x2,x3,x4规则是如下图这样的。并且刚开始我用的是一次函数,后来为了更加立体,我设置的函数改成了二次抛物线函数,并且抛物线的x和数组的索引有关。

    相关公式:y = math.pow((x),2)*0.3

    e62dc6199dba7ecfacb7ff978123a4ad45a.jpg

7.设置完每个矩形的形变,你会发现图片变得胖胖的。因为我们只改变了矩形的width。所以现在我们要把矩形height考虑进去。

    我们矩形的height按线性方程来设置,根据矩形块组(a)里面矩形的个数,和矩形所在的索引为条件,一样也是越两边矩形的height越小。

    并且线性函数linearFunction其实是一个分段的线性函数,画出来是呈一个等腰梯形的。并且代码设的最大值为30-80之间,这就是矩形的height计算。

    并且矩形和矩形之间的间隙也是一样,越中间越大,越靠边越窄。所以我们一样也是用了线性函数,只是最大值我们设置为4-20。

    相关公式:左边一段y=max/(sum-1)*k+min-(max/(sum-1))             

                    右边一段y=max/(1-sum)*k+min-(max*sum/(1-sum))

                    sum为当前矩形个数,max,min为函数最大值最小值

8.这时其实整个矩形块组(a)已经有立体感了。可是由于之前创建的个数是按每个矩形高度相同,都为rHeight均分计算的,所以创建出来的个数明显和距离(l)对不上,连接不起来。因为现在每个矩形的高度都不同了。

    刚开始想根据距离(l)想出一个公式来计算出应该创建矩形的个数,可是发现这样行不通,因为设置矩形的高度和坐标还有间隙,都是根据当前有几个矩形决定的,而我现在要知道的就是应该创建几个矩形,这就陷入了一个死循环,计算的结果就是计算过程所需要的数据。

    后来想了一下,用了假设法,假设矩形个数为1,2,3,4……一直到20,20个矩形应该是可以跨越整个屏幕了,才设了20,所以最多只可以创建20个矩形。并且根据一个个假设去计算出20种情况中哪一种满足现状距离(l)的情况,这样就得出了所需要创建的矩形个数。

9.做到以上那步已经差不多了,最后一步就是设置放大比例,根据距离(l),移的越远放的越大,也不能太大。

    相关公式:y = (1+l/6000)

    当然这个放大的比例也应该放入上面步骤的假设中去一起计算。

效果图:

0a62497747dcd28b90b669d8ec3a6579cbf.jpg0d3306026cdf8c8567637f047f2af69c99f.jpg

21b6d59373c17319cf3a9df4ac81bd3065a.jpg

转载于:https://my.oschina.net/u/3891480/blog/1936382

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值