How To: Interactive Kiosks-Part2

The kiosks are in the midst of being revised, but I figured I would share the previous setup with you, so you can at least get things to start coming together. The way it works currently includes mouse moving, and little else. Double clicking occasionally gets sent through to the kiosk, but its not as responsive as I would like.

Let’s get started though.

The next phase is getting the kiosk to work, and to wrap up the enabling and disabling of the kiosk, once the player hits the use key.

To begin with our kiosk base class will need to implement an interface, to provide the contract that our player can use. This interface will also open up the door to being able to use other actors in the world.

/* Interface IBTUsable
 * 
 * All implementors need to include 
 * bCollideActors=true and bCollideWorld=true 
 * to be able to be captured when used. 
 */
interface IBTUsable
	DependsOn(BTPC);

function Use(BTPC Controller);

Shifting our attention over to the player controller, which will do the triggering of our usable element. Thankfully, it already has a bit of the functionality we are looking for. All we need to do is a little vector magic to make sure we get the best usable actor:

inside BTPC.uc

simulated function bool PerformedUseAction()
{
	local IBTUsable BestUsable;

	// If we are paused, use will quit...
	if (BTHUD(myHUD).inPause)
	{
		BTHUD(myHUD).HUDMovie.onQuit();
		return true;
	}

	// Check for usable elements
	if (Super.PerformedUseAction() == false)
	{
		BestUsable = 
			IBTUsable(GetBestActor());

		if (BestUsable == none)
			return false;
		
		BestUsable.Use(self);		
	}

	return true;
}

function Actor GetBestActor()
{
	local Actor tmp, Best;
	local vector ViewDir, PawnLoc2D, ALoc2D;
	local float NewDot, BestDot;

	PawnLoc2D = Pawn.Location;
	PawnLoc2D.Z = 0;

	ViewDir = vector(Pawn.Rotation);

	ForEach Pawn.OverlappingActors(class'Actor', 
		tmp, MaxUseScanDistance)
	{
		if (IBTUsable(tmp) == none)
			continue;

		ALoc2D = tmp.Location;
		ALoc2D.Z = 0;

		NewDot = Normal(ALoc2D - PawnLoc2D) 
			Dot ViewDir;

		if ( (Best == None) || 
			(NewDot > BestDot) )
		{
			if ( FastTrace(tmp.Location, 
				Pawn.Location) )
			{
				Best = tmp;
				BestDot = NewDot;
			}
		}
	}

	return Best;
}

With this we have the ability to walk up to and press our use key to trigger a Use call on the usable element. This can be sped up by changing from Actor to IBTUsable, but for the most usability from this getBestActor function, I have chosen to leave it as Actor.

The kiosk and a base material are all that remain. The kiosk will setup the scene, initialize the swf movie and connect the render target to a material. The trick really comes down to the movie player only rendering to a render target OR the main viewport. Thankfully, it does that by default.

class Kiosk extends Actor
	Implements(IBTUsable)
	placeable;

var globalconfig int RenderTargetResolution;

var SwfMovie ViewscreenSWF;

var class
   
   
   
   
   
    
    
    
    
     ViewscreenMovieClass;

var ScriptedTexture ViewscreenTexture;
var StaticMeshComponent ViewscreenMesh;
var BTGFxKioskMoviePlayer ViewscreenMovie;
var MaterialInstanceConstant ViewscreenMaterial;

function Use(BTPC Controller)
{
	if (ViewscreenMovie.RenderTexture != None)
		EnableKiosk(Controller);
	else
		DisableKiosk(Controller);
}
   
   
   
   
   

So, what are we looking at, aside from a couple of very odd looking variables and variable types? This is probably one of the most complicated actors that any tutorial ill write has to offer. Lets take it one step at a time, so things are clear.

inside Kiosk.uc

simulated function PreBeginPlay()
{
	super.PreBeginPlay();

	InitializeKiosk();
}
 
reliable client function InitializeKiosk()
{
	if (WorldInfo.NetMode == NM_ListenServer 
		|| WorldInfo.NetMode == NM_DedicatedServer )
		return;

	ViewscreenTexture = ScriptedTexture(
		class'ScriptedTexture'.static.Create(
		RenderTargetResolution, 
		RenderTargetResolution));

	ViewscreenMaterial = ViewscreenMesh.
		CreateAndSetMaterialInstanceConstant(0);
	ViewscreenMaterial.SetParent(
		Material'BTBanking.KioskSWF_mat');
	ViewscreenMaterial.SetTextureParameterValue(
		'SWFMovie', ViewscreenTexture);

	ViewscreenMovie = new ViewscreenMovieClass;
	ViewscreenMovie.RenderTexture = ViewscreenTexture;

	ViewscreenMovie.bIgnoreMouseInput = false;

	ViewscreenMovie.SetMovieInfo(ViewscreenSWF);
	ViewscreenMovie.setKiosk(self);
	ViewscreenMovie.Start();

	DisableKiosk(none);
}

I have removed my comments to help shorten this up, but ill take it from the top down. The first test is simply a confirmation that this is not the server. There are other ways to do this, you should play with them. We don’t want to have the following created on the server side.

Our kiosk screen mesh is going to need a texture, hence ViewscreenTexture. We create a ScriptedTexture, which allows for a number of options to us. the next three function calls are setting up our material with that texture and hook it into our base texture. This is when we are attaching our Kiosk to the texture, which is expecting an SWFMovie parameter.

RenderTargetResolution directly relates to the resolution of the texture, I would suggest you play with this, but know that render targets take up further memory, so any value you choose will be contextual. I have mine set to 256 in my config and use it for all of my kiosks.

ViewscreenMovieClass is the class that we use, deriving from GFxMoviePlayer. We have a reference to the Kiosk, so we can send signals both directions, and then hook in the render target. We set the SWF up and then start the movie. Then we call a magic function – DisableKiosk.

simulated function DisableKiosk(BTPC PC)
{
	ViewscreenMovie.ClearCaptureKeys();
	ViewscreenMovie.ClearFocusIgnoreKeys();
	
	if (PC != None)
	{
		PC.MousePlayer.SetFilterer(none);
		PC.MousePlayer.DisableMouseInput();
	}

	ViewscreenMovie.SetPause(true);
}

// Executed when the kiosk is "used"
simulated function EnableKiosk(BTPC PC)
{
	if (PC != None)
	{
		PC.MousePlayer.SetFilterer(ViewscreenMovie);
		PC.MousePlayer.EnableMouseInput();
	}

	ViewscreenMovie.SetPause(false);
	ViewscreenMovie.AddCaptureKeys();
}

Note the SetFilterer call, which is what hooks our input filter into play. The way we get around starting and stopping is via the pause command, setting when we disable the kiosk. This keeps the render target from getting updates when it is not activated.

The following is only present for posterity, you will likely need to make your own modifications.

defaultproperties
{
	// define here as lot of sub classes which have 
	// moving parts will utilize this
 	Begin Object Class=DynamicLightEnvironmentComponent 
		Name=PickupLightEnvironment
 	    bDynamic=false
 	    bCastShadows=true
 	End Object

	Begin Object Class=StaticMeshComponent Name=KioskMesh
		StaticMesh=StaticMesh'BTBanking.Kiosk'
		LightEnvironment=PickupLightEnvironment

		CollideActors=true
		BlockActors=true
		BlockZeroExtent=false
		BlockNonZeroExtent=true
		BlockRigidBody=true

	End Object

	Begin Object Class=StaticMeshComponent Name=Mesh
		StaticMesh=StaticMesh'BTPrimitives.Plane'

		LightEnvironment=PickupLightEnvironment
		Scale=31

		Rotation=(Pitch=0,Yaw=-16383,Roll=14199)
		Translation=(X=11,Y=0,Z=76)
	End Object

	bCollideActors=true
	bBlockActors=true
	bCollideWorld=true

	bNoDelete=true
	bEdShouldSnap=true

	CollisionType=COLLIDE_BlockAll

	ViewscreenSWF = SwfMovie'BTFlash.Kiosk'

	ViewscreenMovieClass = class'BTGFxKioskMoviePlayer'

	ViewscreenMesh = Mesh

	Components.Add(Mesh)
	Components.Add(KioskMesh)
  	Components.Add(PickupLightEnvironment)

	CollisionComponent=KioskMesh
}

In the next installment ill walk through the movie player and address any questions regarding this section. We are nearly done.

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值