Krpano小功能之添加动画热点

1,571 阅读5分钟

前面两篇文章介绍Krpano的理论性内容较多,从这节开始,将介绍零散的Krpano小功能实现,我使用的Krpano版本是1.21版本,系统是MacOS,二次开发使用的IDE是VSCode,当然其他的Hbuilder或者Sublime也可以。

本章内容介绍的是如何在场景中添加动画热点,具体效果如下:

QQ20230506-101756-HD.gif 具体效果描述:

  1. 地面热点跑马灯动画效果
  2. 地面热点常驻文字显示
  3. 鼠标悬停热点时缩放效果
  4. 鼠标悬停热点时显示屏幕遮罩热点文本说明
  5. 鼠标点击热点时热点消失动画和场景切换动画

一、接下来介绍第一部分,地面热点跑马灯动画效果:

  1. 首先在vtour文件夹下建images文件夹,用来存放热点雪碧图资源,将下属雪碧图放到images目录下

enter.png

  1. 创建名称为hotspot_animate的action事件,作用是在热点图片的跑马灯效果,将该action放入tour.xml中即可
<action name="hotspot_animate">
	inc(frame,1,get(lastframe),0); 
        mul(ypos,frame,frameheight); 
        txtadd(crop,'0|',get(ypos),'|',get(framewidth),'|',get(frameheight));
	delayedcall(0.3, if(loaded, hotspot_animate()) );
</action>
  1. 创建热点的样式,添加热点的onloaded事件,当热点被加载时,执行雪碧图的跑马灯动画效果
<style name="skin_hotspotstyle" 
       url="./images/enter.png" crop="0|0|128|112"
       framewidth="128" 
       frameheight="112" 
       frame="0" 
       lastframe="4" 
       scale="0.5"
       oy="50" 
       onloaded="hotspot_animate();"
/>
  1. 具体在热点中运用如下,在tour.xml中的某个scene标签下创建名称为spot1的热点标签,并设置对应的style为skin_hotspotstyle,即可看到地面热点跑马灯动画效果
<hotspot name="spot1" 
         style="skin_hotspotstyle" 
         ath="-60" 
         atv="15" 
         rotate="-5"
         linkedscene="scene_02xjnxpwxmg" 
         linkedscene_hoffset="0.0" 
         use3dtransition="true"
/>

二、接下来介绍第二部分,地面热点常驻文字显示效果:

  1. 创建名称为add_all_the_time_tooltip的action事件,作用是在热点上方一直显示文本,文本内容为点击热点将要跳转的场景的名称,将该action放入tour.xml中即可
<action name="add_all_the_time_tooltip">
	txtadd(tooltipname, 'tooltip_', get(name)); 
        addplugin(get(tooltipname));
	txtadd(plugin[get(tooltipname)].parent, 'hotspot[', get(name), ']'); 
        set(plugin[get(tooltipname)].url,'%SWFPATH%/plugins/textfield.swf');
	set(plugin[get(tooltipname)].align,top); 
        set(plugin[get(tooltipname)].edge,bottom);
	set(plugin[get(tooltipname)].x,0); set(plugin[get(tooltipname)].y,0); 
        set(plugin[get(tooltipname)].width,100);
	set(plugin[get(tooltipname)].autoheight,true); 
        set(plugin[get(tooltipname)].background,true);
	set(plugin[get(tooltipname)].backgroundcolor,0x000000); 
        set(plugin[get(tooltipname)].roundedge,15);
	set(plugin[get(tooltipname)].backgroundalpha,0.5); 
        set(plugin[get(tooltipname)].border,true);
	set(plugin[get(tooltipname)].glow,4); 
        set(plugin[get(tooltipname)].glowcolor,0xFFFFFF);
	set(plugin[get(tooltipname)].css,'text-align:center; color:#FFFFFF; font-family:Arial;
	font-weight:bold; font-size:16px;'); 
        set(plugin[get(tooltipname)].textshadow,1);
	set(plugin[get(tooltipname)].textshadowrange,6.0); 
        set(plugin[get(tooltipname)].textshadowangle,90);
	copy(plugin[get(tooltipname)].html,scene[get(linkedscene)].title); 
        set(plugin[get(tooltipname)].enabled,false);
</action>
  1. 修改热点样式skin_hotspotstyle中的代码如下:
<style name="skin_hotspotstyle" url="./images/enter.png" crop="0|0|128|112"
framewidth="128" frameheight="112" frame="0" lastframe="4" scale="0.5"
oy="50" onloaded="hotspot_animate();add_all_the_time_tooltip(get(linkedscene),1));"
/>

三、接下来介绍第三部分,鼠标悬停热点时缩放效果:

  1. 修改热点样式skin_hotspotstyle中的代码如下
<style name="skin_hotspotstyle" 
       url="./images/enter.png" 
       crop="0|0|128|112"
       framewidth="128" 
       frameheight="112" 
       frame="0" 
       lastframe="4" 
       scale="0.5"
       oy="50" 
       onloaded="hotspot_animate();add_all_the_time_tooltip(get(linkedscene),1));"
       onover.addevent="tween(scale,0.55);"
       onout.addevent="tween(scale,0.5);"
/>

四、接下来介绍第四部分,鼠标悬停热点时显示屏幕遮罩热点文本说明效果:

  1. 该部分功能需使用到官方插件showtext.xml插件,先确定tour文件夹下的plugins文件下是否包含showtext.xml文件,官方地址:krpano.com/plugins/sho… ,如果没有该文件,可创建该文件,将如下代码放入该文件中
<krpano>
	<!-- predefine a DEFAULT textstyle element -->
	<textstyle name="DEFAULT" />
	<!-- the automatic running (autorun=preinit) install action -->
	<action name="showtext_install" autorun="preinit" scope="private:showtext">
		<!-- remove the build-in 'showtext' function to use the 'showtext' <action> instead: -->
		delete(global.showtext);
		<!-- initialize internal variables -->
		set(showtext_style, DEFAULT); set(showtext_prevstyle, null); set(showtext_text,
		''); set(showtext_prevtext, ''); set(showtext_timeout, 0.1); set(showtext_fadeout,
		0.0); set(showtext_clipping, false);
	</action>
	<action name="showtext" scope="private:showtext" args="text, style">
		if(!style, set(style, DEFAULT)); if(global.textstyle[get(style)], copy(showtext_style,
		style); , warning("showtext() - there is no textstyle '", style, "' defined!");
		global.textstyle.createarrayitem(get(style)); ); copy(showtext_text, text);
		if(showtext_text != showtext_prevtext, copy(showtext_prevtext, showtext_text);
		showtext_createnewtext(); , delayedcall(showtext_timer, get(showtext_timeout),
		showtext_hide() ); );
	</action>
	<action name="showtext_createnewtext" scope="private:showtext">
		<!-- stop running mouse and alpha update calls -->
		stopdelayedcall(showtext_mouseupdates); stoptween(global.layer[showtext_tf].alpha);
		<!-- remove the old textfield when the style has changed -->
		if(showtext_style != showtext_prevstyle, copy(showtext_prevstyle, showtext_style);
		removelayer(showtext_tf); );
		<!-- create a new textfield plugin layer -->
		addlayer(showtext_tf);
		<!-- create 'shortcut' variables (tf,ts) for faster access -->
		copy(tf, global.layer[showtext_tf]); copy(ts, global.textstyle[get(showtext_style)]);
		<!-- get the position settings -->
		if(ts.origin !== null, copy(ts_origin, ts.origin), set(ts_origin, 'cursor'));
		if(ts.edge !== null, copy(ts_edge, ts.edge), set(ts_edge, 'bottom')); if(ts.xoffset
		!== null, copy(ts_xoffset, ts.xoffset), set(ts_xoffset, 0)); if(ts.yoffset
		!== null, copy(ts_yoffset, ts.yoffset), set(ts_yoffset, -3));
		<!-- set the position settings -->
		if(ts_origin == 'cursor', set(tf.align, 'lefttop'); showtext_movetomouse();
		, copy(tf.align, ts_origin); ); copy(tf.edge, ts_edge); copy(tf.ox, ts_xoffset);
		copy(tf.oy, ts_yoffset);
		<!-- get the font settings -->
		if(ts.font !== null, copy(ts_font, ts.font), set(ts_font, 'Times')); if(ts.fontsize
		!== null, copy(ts_fontsize, ts.fontsize), set(ts_fontsize, 12.0)); if(ts.bold
		!== null, copy(ts_bold, ts.bold), set(ts_bold, true)); if(ts.italic !==
		null, copy(ts_italic, ts.italic), set(ts_italic, false)); if(ts.textcolor
		!== null, copy(ts_textcolor, ts.textcolor), set(ts_textcolor, 0x000000));
		if(ts.textalign !== null, copy(ts_textalign, ts.textalign), set(ts_textalign,
		'left'));
		<!-- use the font settings to build the CSS style -->
		set(tf_css, ''); tohex(ts_textcolor, '#', 6); txtadd(tf_css, 'font-family:',get(ts_font),';
		font-size:',get(ts_fontsize),'px; color:',get(ts_textcolor),'; '); if(ts_textalign
		!= 'none', txtadd(tf_css, get(tf_css), 'text-align:',get(ts_textalign),';
		')); if(ts_bold, txtadd(tf_css, 'font-weight:bold; ')); if(ts_italic, txtadd(tf_css,
		'font-style:italic; ')); if(ts.css !== null, txtadd(tf_css, get(ts.css)));
		copy(tf.css, tf_css);
		<!-- size settings -->
		if(ts.width !== null AND ts.width !== '', copy(tf.width, ts.width)); if(ts.height
		!== null AND ts.height !== '', copy(tf.height, ts.height)); if(ts.vcenter
		!== null AND ts.vcenter !== '', copy(tf.vcenter, ts.vcenter)); if(ts.padding
		!== null AND ts.padding !== '', copy(tf.padding, ts.padding), set(tf.padding,1));
		<!-- background, border, shadow settings -->
		if(ts.background !== null, copy(tf.background, ts.background)); if(ts.backgroundcolor
		!== null, copy(tf.backgroundcolor, ts.backgroundcolor)); if(ts.backgroundalpha
		!== null, copy(tf.backgroundalpha, ts.backgroundalpha)); if(ts.border !==
		null, copy(tf.border, ts.border), set(tf.border,true)); if(ts.bordercolor
		!== null, copy(tf.bordercolor, ts.bordercolor)); if(ts.borderalpha !==
		null, copy(tf.borderalpha, ts.borderalpha)); if(ts.borderwidth !== null,
		copy(tf.borderwidth, ts.borderwidth)); if(ts.roundedge !== null, copy(tf.roundedge,
		ts.roundedge)); if(ts.shadow !== null, copy(tf.shadow, ts.shadow)); if(ts.shadowrange
		!== null, copy(tf.shadowrange, ts.shadowrange)); if(ts.shadowangle !==
		null, copy(tf.shadowangle, ts.shadowangle)); if(ts.shadowcolor !== null,
		copy(tf.shadowcolor, ts.shadowcolor)); if(ts.shadowalpha !== null, copy(tf.shadowalpha,
		ts.shadowalpha)); if(ts.textshadow !== null, copy(tf.textshadow, ts.textshadow));
		if(ts.textshadowrange !== null, copy(tf.textshadowrange, ts.textshadowrange));
		if(ts.textshadowangle !== null, copy(tf.textshadowangle, ts.textshadowangle));
		if(ts.textshadowcolor !== null, copy(tf.textshadowcolor, ts.textshadowcolor));
		if(ts.textshadowalpha !== null, copy(tf.textshadowalpha, ts.textshadowalpha));
		<!-- showing settings -->
		if(ts.alpha !== null, copy(ts_alpha, ts.alpha), set(ts_alpha, 1.0)); if(ts.showtime
		!== null, copy(ts_showtime, ts.showtime), set(ts_showtime, 0.1)); if(ts.fadetime
		!== null, copy(ts_fadetime, ts.fadetime), set(ts_fadetime, 0.0)); if(ts.fadeintime
		!== null, copy(ts_fadeintime, ts.fadeintime), set(ts_fadeintime, 0.0));
		copy(showtext_timeout, ts_showtime); copy(showtext_fadeout, ts_fadetime);
		if(ts_fadeintime GT 0, set(tf.alpha, 0.0); tween(global.layer[showtext_tf].alpha,
		get(ts_alpha), get(ts_fadeintime), linear); , copy(tf.alpha, ts_alpha);
		); if(ts.noclip !== null, copy(showtext_clipping,ts.noclip), set(showtext_clipping,
		true)); if(showtext_clipping, set(tf.onloaded, showtext_do_clipping() );
		set(tf.onautosized, showtext_do_clipping() ); );
		<!-- special flash-only settings -->
		if(ts.embeddedfonts !== null, copy(tf.embeddedfonts, ts.embeddedfonts));
		if(ts.effect !== null, copy(tf.effect, ts.effect)); if(ts.blendmode !==
		null, copy(tf.blendmode, ts.blendmode));
		<!-- set the text and the basic settings to start showing the textfield
		-->
		copy(tf.html, showtext_text); set(tf.enabled, false); set(tf.zorder, 999999);
		if(ts.parent, copy(tf.parent, ts.parent) ); set(tf.type, 'text');
		<!-- start the text-hiding timer -->
		delayedcall(showtext_timer, get(showtext_timeout), showtext_hide() );
	</action>
	<action name="showtext_do_clipping" scope="private:showtext">
		if(showtext_clipping, copy(tf_px, global.layer[showtext_tf].pixelx); copy(tf_py,
		global.layer[showtext_tf].pixely); if(tf_px LT 0, sub(global.layer[showtext_tf].x,
		tf_px); , add(tf_rightedge, tf_px, global.layer[showtext_tf].pixelwidth);
		if(tf_rightedge GE global.stagewidth, sub(tf_rightedge,global.stagewidth);
		sub(global.layer[showtext_tf].x,tf_rightedge); ); ); if(tf_py LT 0, sub(global.layer[showtext_tf].y,
		tf_py); , add(tf_bottomedge, tf_py, global.layer[showtext_tf].pixelheight);
		if(tf_bottomedge GE global.stageheight, sub(tf_bottomedge,global.stageheight);
		sub(global.layer[showtext_tf].y,tf_bottomedge); ); ); );
	</action>
	<action name="showtext_movetomouse" scope="private:showtext">
		copy(global.layer[showtext_tf].x, global.mouse.stagex); copy(global.layer[showtext_tf].y,
		global.mouse.stagey); showtext_do_clipping(); delayedcall(showtext_mouseupdates,
		0, showtext_movetomouse() );
	</action>
	<action name="showtext_hide" scope="private:showtext">
		if(global.layer[showtext_tf], tween(global.layer[showtext_tf].alpha, 0.0,
		get(showtext_fadeout), linear, stopdelayedcall(showtext_mouseupdates);
		removelayer(showtext_tf); set(showtext_text, ''); set(showtext_prevtext,
		''); ); );
	</action>
</krpano>
  1. 创建文本样式,具体代码如下:
<textstyle name="STYLE4" 
           font="Arial" 
           fontsize.no-mobile="14" 
           fontsize.mobile="20" 
           bold="true" 
           background="true" 
           backgroundcolor="0x000000" 
           backgroundalpha="0.667" 
           border="true" 
           borderwidth="2" 
           bordercolor="0xFFFFFF" 
           roundedge="10" 
           textcolor="0xFFFFFF" 
           padding="6 10" 
           textalign="center"
           yoffset.no-touch="-5" 
           yoffset.touch="-40"/>
  1. 修改热点样式skin_hotspotstyle中的代码如下,此时鼠标悬停时即会显示屏幕悬停热点文本:
<style name="skin_hotspotstyle" 
       url="./images/enter.png" 
       crop="0|0|128|112"
       framewidth="128" 
       frameheight="112" 
       frame="0" 
       lastframe="4" 
       scale="0.5"
       oy="50" 
       onhover="if(linkedscene, showtext(get(scene[get(linkedscene)].title),STYLE4))"
       onloaded="hotspot_animate();add_all_the_time_tooltip(get(linkedscene),1));"
/>

注意不要忘记引入插件,可在tour.xml中或者vtourskin.xml中添加如下代码:

<include url="../plugins/showtext.xml"/>

五、接下来介绍第五部分,鼠标点击热点时热点消失动画和场景切换动画:

  1. 创建热点点击事件skin_hotspot_click,具体代码如下:
<!-- 切换场景动画效果 -->
<action name="skin_hotspot_click">
	if(linkedscene, tween(scale,0.25,0.5); 
        tween(oy,-20,0.5); tween(alpha,0,0.5);
	zoomto(60,smooth(300,300,300));    
        loadscene(get(linkedscene),null,MERGE,OPENBLEND(0.5,-0.5, 0.3, 0.8, linear)); 
        skin_updatescroll();
	);
</action>
  1. 修改热点样式skin_hotspotstyle中的代码如下,即可实现点击切换场景的动画效果:
<style name="skin_hotspotstyle" 
       url="./images/enter.png" 
       crop="0|0|128|112"
       framewidth="128" 
       frameheight="112" 
       frame="0" 
       lastframe="4" 
       scale="0.5"
       oy="50" 
       onclick="skin_hotspot_click(get(hlookat),get(fov));" 
       onhover="if(linkedscene, showtext(get(scene[get(linkedscene)].title),STYLE4))"
       onloaded="hotspot_animate();add_all_the_time_tooltip(get(linkedscene),1));"
/>

以上即为本次要介绍的动画热点相关内容,下篇将介绍场景来回跳转时如何保持进入场景的视角是和热点的方向保持一致的,即有A、B、C三个场景,从A场景跳转到B场景,从C场景也可以跳转到B场景,但是这两次进入B场景是展示的视角要求不同,该如何实现。