融入动画技术的交互应用

这是一款在unity环境中制作的小音游,参考《代码本色》教程,主要运用了书中力、粒子系统、物理函数库等章节的动画技术,实现了一个基于音乐旋律的交互应用。

一、功能用法简介

玩家可自行添加歌曲(前提是电脑安装unity)并在开始界面中选择音乐,点击音乐按钮进入游戏,游戏主场景由五条弦及弦上的五个不同颜色的音符按钮组成,五个音符按钮从左到右依次由键盘上的数字键(非小键盘数字键)1、2、3、4、5控制,音乐开始后每条弦上的音符按钮会根据音乐旋律迎面移动过来,玩家需要根据音乐旋律及按钮提示及时按下相应音符按钮,按键正确时按钮上方会有火焰冒出,玩家得分增加,到音乐后半段有高音出现时还会在峰值间接出现带有尾巴的音符按钮,有助于玩家控制节奏。一首歌曲播放完毕后显示的菜单列出了音乐名称、玩家得分、玩家正确音符数、音乐总音符数及玩家正确率。

二、效果演示

(因为只能上传gif所以没有声音。。大家领会精神吧【无奈脸)

开始部分:

高音部分:

结尾部分:

三、部分关键代码

音符按钮编辑器:
using UnityEngine;
using System.Collections;
using UnityEditor;

[CustomEditor( typeof( StringButton ) )]

public class StringButtonEditor : Editor
{
	protected float LightIntensity = 0;
	protected Color OldColor;

	void Awake()
	{
		OnInspectorOpen();
	}

	void OnDisable()
	{
		OnInspectorClose();
	}

	protected void OnInspectorOpen()
	{
		EnableLightOfTargetObject( true );
		LightIntensity = GetTargetsLightObject().GetComponent().intensity;
	}

	protected void OnInspectorClose()
	{
		EnableLightOfTargetObject( false );
	}

	public override void OnInspectorGUI()
	{
		DrawDefaultInspector();
		DrawLightIntensitySlider();

		if( HasChanged() )
		{
			OnInspectorChanged();
		}

		RememberColorToCheckForChange();
	}

	protected void OnInspectorChanged()
	{
		UpdateGuitarButtonColor();
		UpdateLightIntensity();
		UpdateKeyCodeLabel();
	}

	protected bool HasChanged()
	{
		if( GUI.changed )
		{
			return true;
		}

		if( GetTarget().Color != OldColor )
		{
			return true;
		}

		return false;
	}

	protected void RememberColorToCheckForChange()
	{
		OldColor = GetTarget().Color;
	}

	protected void DrawLightIntensitySlider()
	{
		EditorGUILayout.BeginHorizontal();
			GUILayout.Space( 15 );
			GUILayout.Label( "Light Intensity", EditorStyles.structHeadingLabel );
			LightIntensity = GUILayout.HorizontalSlider( LightIntensity, 0, 8 );
		EditorGUILayout.EndHorizontal();
	}

	protected void UpdateGuitarButtonColor()
	{
		GameObject.Find( "Guitar" ).GetComponent().UpdateColorsArray();
	}

	protected void UpdateLightIntensity()
	{
		GetTargetsLightObject().GetComponent().intensity = LightIntensity;
	}

	protected void UpdateKeyCodeLabel()
	{
		KeyCode key = GetTarget().Key;
		string keyString = key.ToString();

		if( IsKeyAlphaNumeric( key ) )
		{
			keyString = keyString.Substring( 5, 1 ); //Strip String of "Alpha" pretext
		}

		SetTargetsKeyCodeLabel( keyString );
	}

	protected void SetTargetsKeyCodeLabel( string text )
	{
		GetTargetsGameObject().transform.Find( "KeyCode Label" ).GetComponent().text = text;
	}

	protected bool IsKeyAlphaNumeric( KeyCode key )
	{
		return key >= KeyCode.Alpha0 && key <= KeyCode.Alpha9;
	}

	protected void EnableLightOfTargetObject( bool enabled )
	{
		GetTargetsLightObject().GetComponent().enabled = enabled;
	}

	protected GameObject GetTargetsGameObject()
	{
		return GetTarget().gameObject;
	}

	protected GameObject GetTargetsLightObject()
	{
		return GetTargetsGameObject().transform.Find( "Light" ).gameObject;
	}

	protected StringButton GetTarget()
	{
		return ( target as StringButton );
	}
}
游戏机制的处理:
using UnityEngine;
using System.Collections;
using System.Collections.Generic;

public class GuitarGameplay : MonoBehaviour
{
	public GameObject NotePrefab;
	public SongData[] Playlist;

	//References to important objects or components
	protected GameObject GuitarNeckObject;
	protected KeyboardControl KeyboardControl;
	protected SongPlayer Player;
	protected List NoteObjects;
	protected Color[] Colors;	

	//Game state variables
	protected float Score = 0f;
	protected float Multiplier = 1f;
	protected float Streak = 0;
	protected float MaxStreak = 0;
	protected float NumNotesHit = 0;
	protected float NumNotesMissed = 0;

	protected bool[] HasHitNoteOnStringIndexThisFrame;

	//Use this for initialization
	void Start()
	{
		//Init references to external objects/components
		KeyboardControl = GameObject.Find( "Guitar" ).GetComponent();
		GuitarNeckObject = transform.Find( "Guitar Neck" ).gameObject;
		Player = GetComponent();
		NoteObjects = new List();

		HasHitNoteOnStringIndexThisFrame = new bool[ 5 ];

		//Get string colors from buttons
		UpdateColorsArray();
	}

	void Update()
	{
		if( Player.IsPlaying() )
		{
			//Check for ESC and possibly show in game menu
			ShowInGameMenuOnKeypress();

			//No note has been hit int this frame yet
			ResetHasHitNoteOnStringIndexArray();

			UpdateNeckTextureOffset();
			UpdateNotes();

			UpdateGuiScore();
			UpdateGuiMultiplier();
		}
	}

	public void UpdateColorsArray()
	{
		//If colors array is not initialized, do so
		if( Colors == null || Colors.Length != 5 )
		{
			Colors = new Color[ 5 ];
		}

		//Get all five string buttons, get the colors from their StringButton component and apply it to the meshes and light
		for( int i = 0; i < 5; ++i )
		{
			GameObject stringButton = GameObject.Find( "StringButton" + ( i + 1 ) );
			Color color = stringButton.GetComponent().Color;

			if( color != Colors[ i ] )
			{
				Colors[ i ] = color;

				stringButton.transform.Find( "Paddle" ).GetComponent().sharedMaterial.color = color;
				stringButton.transform.Find( "Socket" ).GetComponent().sharedMaterial.color = color;
				stringButton.transform.Find( "Light" ).GetComponent().color = color;
			}
		}
	}

	public void StartPlaying( int playlistIndex )
	{
		ResetGameStateValues();

		SetInGameUserInterfaceVisibility( true );

		Player.SetSong( Playlist[ playlistIndex ] );

		CreateNoteObjects();

		Player.Play();
		StartCoroutine( "DisplayCountdown" );
	}

	public void StopPlaying()
	{
		SetInGameUserInterfaceVisibility( false );

		DestroyNoteObjects();

		StopAllCoroutines();
	}

	protected void SetInGameUserInterfaceVisibility( bool show )
	{
		GameObject.Find( "GUI Score" ).GetComponent().enabled = show;
		GameObject.Find( "GUI Multiplier" ).GetComponent().enabled = show;
	}

	protected IEnumerator StartAudio( float delay )
	{
		yield return new WaitForSeconds( delay );

		Player.Play();
	}

	protected void CreateNoteObjects()
	{
		NoteObjects.Clear();

		for( int i = 0; i < Player.Song.Notes.Count; ++i )
		{
			//Create note and trail objects
			GameObject note = InstantiateNoteFromPrefab( Player.Song.Notes[ i ].StringIndex );
			CreateTrailObject( note, Player.Song.Notes[ i ] );

			//Hide object on start, they will be shown - when appropriate - in the UpdateNotes routine
			note.GetComponent().enabled = false;
			note.active = false;

			NoteObjects.Add( note );
		}
	}

	protected void DestroyNoteObjects()
	{
		for( int i = 0; i < NoteObjects.Count; ++i )
		{
			Destroy( NoteObjects[ i ] );
		}

		NoteObjects.Clear();
	}

	public SongData[] GetPlaylist()
	{
		return Playlist;
	}

	protected IEnumerator DisplayCountdown()
	{
		//Count down from 4 to 1 and GO at the beginning of a song

		yield return new WaitForSeconds( MyMath.BeatsToSeconds( 0.5f, Player.Song.BeatsPerMinute ) );

		StartCoroutine( DisplayText( "4", 1f, 0f ) );
		yield return new WaitForSeconds( MyMath.BeatsToSeconds( 1f, Player.Song.BeatsPerMinute ) );

		StartCoroutine( DisplayText( "3", 1f, 0f ) );
		yield return new WaitForSeconds( MyMath.BeatsToSeconds( 1f, Player.Song.BeatsPerMinute ) );

		StartCoroutine( DisplayText( "2", 1f, 0f ) );
		yield return new WaitForSeconds( MyMath.BeatsToSeconds( 1f, Player.Song.BeatsPerMinute ) );

		StartCoroutine( DisplayText( "1", 1f, 0f ) );
		yield return new WaitForSeconds( MyMath.BeatsToSeconds( 1f, Player.Song.BeatsPerMinute ) );

		StartCoroutine( DisplayText( "Go", MyMath.BeatsToSeconds( 1.5f, Player.Song.BeatsPerMinute ), MyMath.BeatsToSeconds( 1f, Player.Song.BeatsPerMinute ) ) );
	}

	protected void StopCountdown()
	{
		StopCoroutine( "DisplayCountdown" );
		GameObject.Find( "GUI Text" ).GetComponent().text = "";
	}

	protected void ResetHasHitNoteOnStringIndexArray()
	{
		for( int i = 0; i < 5; ++i )
		{
			HasHitNoteOnStringIndexThisFrame[ i ] = false;
		}
	}

	protected void ShowInGameMenuOnKeypress()
	{
		if( Input.GetKeyDown( KeyCode.Escape ) )
		{
			StopCountdown();
			GetComponent().ShowMenu();
		}
	}

	protected void UpdateNotes()
	{
		for( int i = 0; i < NoteObjects.Count; ++i )
		{
			UpdateNotePosition( i );

			if( IsNoteHit( i ) )
			{
				HideNote( i );

				Score += 10f * Multiplier;
				Streak++;
				NumNotesHit++;

				if( Streak > MaxStreak )
				{
					MaxStreak = Streak;
				}

				//Check if there is a trail
				if( Player.Song.Notes[ i ].Length > 0f )
				{
					//Handle the trail
					StartTrailHitRoutineForNote( i );
				}
				else
				{
					//No trail, just show the fire particles
					ShowFireParticlesForNote( i );
				}
			}

			if( WasNoteMissed( i ) )
			{
				HideNote( i );

				Streak = 0;
				Multiplier = 1;

				NumNotesMissed++;
			}
		}
	}

	protected void StartTrailHitRoutineForNote( int index )
	{
		GameObject trail = NoteObjects[ index ].transform.Find( "Trail" ).gameObject;		

		StartCoroutine( TrailHitRoutine( index, trail ) );
	}

	protected void ShowFireParticlesForNote( int index )
	{
		StartCoroutine( ShowFireParticles( Player.Song.Notes[ index ].StringIndex ) );
	}

	protected IEnumerator ShowFireParticles( int stringIndex )
	{
		KeyboardControl.GetStringButton( stringIndex ).transform.Find( "Flame" ).GetComponent().ClearParticles();
		KeyboardControl.GetStringButton( stringIndex ).transform.Find( "Flame" ).GetComponent().emit = true;

		//Wait for one frame and disable the emitter again, 
		//it is set to one shot so everything is emitted on the first frame
		yield return null;

		KeyboardControl.GetStringButton( stringIndex ).transform.Find( "Flame" ).GetComponent().emit = false;
	}

	protected IEnumerator TrailHitRoutine( int noteIndex, GameObject trail )
	{
		Note note = Player.Song.Notes[ noteIndex ];

		//Update the color of the trail
		//Initially it is darkened and now the full bright color is applied
		trail.GetComponent().material.color = Colors[ note.StringIndex ];

		//Start the spark particles
		KeyboardControl.GetStringButton( note.StringIndex ).transform.Find( "Sparks" ).GetComponent().emit = true;
		KeyboardControl.GetStringButton( note.StringIndex ).transform.Find( "Sparks" ).GetComponent().GetComponent().enabled = true;

		Vector3 trailScale = trail.transform.localScale;
		Vector3 trailPosition = trail.transform.localPosition;

		//Do this as long as the button for the specific string is pressed or until the trail reaches its end
		while( KeyboardControl.IsButtonPressed( note.StringIndex )
			&& Player.GetCurrentBeat() + 1 <= note.Time + note.Length )
		{
			//Calculate how far we have progressed in this trail
			float progress = Mathf.Clamp01( ( 1 + Player.GetCurrentBeat() - note.Time ) / note.Length );

			//Shrink the trail and adjust its position
			//Since the pivot of the trail is in the center, meaning it will shrink at the start and at the end,
			//we have to reposition the trail each frame so it appears as if its shrinking from the beginning and the
			//end remains fixed
			trail.transform.localScale = new Vector3( trailScale.x, trailScale.y, trailScale.z * ( 1 - progress ) );
			trail.transform.localPosition = new Vector3( trailPosition.x, trailPosition.y + trailPosition.y * progress, trailPosition.z );

			//Its possible to hit the note before its beat is reached, because the hit zone is wide to make it easier to hit the notes
			//Increate the score only after the notes real hit position is reached
			if( progress > 0 )
			{
				Score += 10 * Multiplier * Time.deltaTime;
			}

			yield return null;
		}

		//Hide the trail
		trail.GetComponent().enabled = false;

		//Disable the particles
		KeyboardControl.GetStringButton( note.StringIndex ).transform.Find( "Sparks" ).GetComponent().emit = false;
		KeyboardControl.GetStringButton( note.StringIndex ).transform.Find( "Sparks" ).GetComponent().GetComponent().enabled = false;
	}

	protected void HideNote( int index )
	{
		NoteObjects[ index ].GetComponent().enabled = false;
	}

	protected bool IsNoteHit( int index )
	{
		Note note = Player.Song.Notes[ index ];

		//If no button is pressed on this notes string, it cannot be hit
		if( !KeyboardControl.WasButtonJustPressed( note.StringIndex ) )
		{
			return false;
		}

		//If a note was already hit on this string during this frame, dont hit this one aswell
		if( HasHitNoteOnStringIndexThisFrame[ note.StringIndex ] )
		{
			return false;
		}

		//When the renderer is disabled, this note was already hit before
		if( NoteObjects[ index ].GetComponent().enabled == false )
		{
			return false;
		}

		//Check if this note is in the hit zone
		if( IsInHitZone( NoteObjects[ index ] ) )
		{
			//Set this flag so no two notes are hit with the same button press
			HasHitNoteOnStringIndexThisFrame[ note.StringIndex ] = true;
			return true;
		}

		//The note is not in the hit zone, therefore cannot be hit
		return false;
	}

	protected bool WasNoteMissed( int index )
	{
		//If position.z is greater than 0, this note can still be hit
		if( NoteObjects[ index ].transform.position.z > 0 )
		{
			return false;
		}

		//If the renderer is disabled, this note was hit
		if( NoteObjects[ index ].GetComponent().enabled == false )
		{
			return false;
		}

		//Yea, this note was missed
		return true;
	}

	protected void ResetGameStateValues()
	{
		Score = 0;
		Streak = 0;
		MaxStreak = 0;
		Multiplier = 1;
		NumNotesMissed = 0;
		NumNotesHit = 0;
	}

	protected void UpdateNotePosition( int index )
	{
		Note note = Player.Song.Notes[ index ];

		//If the note is farther away then 6 beats, its not visible on the neck and we dont have to update it
		if( note.Time < Player.GetCurrentBeat() + 6 )
		{
			//If the note is not active, it is visible on the neck for the first time
			if( !NoteObjects[ index ].active )
			{
				//Activate and show the note
				NoteObjects[ index ].active = true;
				NoteObjects[ index ].GetComponent().enabled = true;

				//If there is a trail, show that aswell
				if( Player.Song.Notes[ index ].Length > 0f )
				{
					NoteObjects[ index ].transform.Find( "Trail" ).GetComponent().enabled = true;
				}
			}

			//Calculate how far the note has progressed on the neck
			float progress = ( note.Time - Player.GetCurrentBeat() - 0.5f ) / 6f;

			//Update its position
			Vector3 position = NoteObjects[ index ].transform.position;
			position.z = progress * GetGuitarNeckLength();
			NoteObjects[ index ].transform.position = position;
		}
	}

	protected void UpdateGuiScore()
	{
		GameObject.Find( "GUI Score" ).GetComponent().text = Mathf.Floor( Score ).ToString();
	}

	protected void UpdateGuiMultiplier()
	{
		Multiplier = Mathf.Ceil( Streak / 10 );

		Multiplier = Mathf.Clamp( Multiplier, 1, 10 );

		GameObject.Find( "GUI Multiplier" ).GetComponent().text = "x" + Mathf.Floor( Multiplier ).ToString();
	}

	protected void UpdateNeckTextureOffset()
	{
		//Get the current offset
		Vector2 offset = GuitarNeckObject.GetComponent().material.GetTextureOffset( "_MainTex" );

		//Update its y component
		offset.y = 1 - ( Player.GetCurrentBeat() - 0.5f ) / 6f;

		//And set it again
		GuitarNeckObject.GetComponent().material.SetTextureOffset( "_MainTex", offset );
	}

	protected float GetNeckMoveOffset()
	{
		return Time.deltaTime * Player.Song.BeatsPerMinute * ( 1f / 6f / 60f );
	}

	protected bool IsInHitZone( GameObject note )
	{
		return note.transform.position.z < GetHitZoneBeginning()
			&& note.transform.position.z > GetHitZoneEnd();
	}

	protected float GetGuitarNeckLength()
	{
		return 20f;
	}

	public Color GetColor( int index )
	{
		if( Colors == null || Colors.Length != 5 )
		{
			UpdateColorsArray();
		}

		return Colors[ index ];
	}

	public float GetScore()
	{
		return Score;
	}

	public float GetMaximumStreak()
	{
		return MaxStreak;
	}

	public float GetNumNotesHit()
	{
		return NumNotesHit;
	}

	public float GetNumNotesMissed()
	{
		return NumNotesMissed;
	}

	protected Vector3 GetStartPosition( int stringIndex )
	{
		return new Vector3( (float)( stringIndex - 2 ), 0f, GetGuitarNeckLength() );
	}

	protected GameObject InstantiateNoteFromPrefab( int stringIndex )
	{
		GameObject note = Instantiate( NotePrefab
									 , GetStartPosition( stringIndex )
									 , Quaternion.identity
									 ) as GameObject;

		note.GetComponent().material.color = Colors[ stringIndex ];
		note.transform.Rotate( new Vector3( -90, 0, 0 ) );
		
		return note;
	}

	protected GameObject CreateTrailObject( GameObject noteObject, Note note )
	{
		if( note.Length == 0 )
		{
			return null;
		}

		GameObject trail = GameObject.CreatePrimitive( PrimitiveType.Plane );

		//We don't need the collider of the plane
		Destroy( trail.GetComponent() );
		
		//The guitar neck is 20 units long
		//The plane primitive is 10 units long
		//1/6th of the neck is one beat, therefore 1/3rd of the initial plane length
		float scaleZ = 0.33f * note.Length;

		//Scale the plane
		trail.transform.localScale = new Vector3( 0.03f, 1f, scaleZ );

		//Add the trail as child of the note
		trail.transform.parent = noteObject.transform;

		//position it so that the trail is behind the note
		trail.transform.localPosition = new Vector3( 0f, -10f * scaleZ / 2f, 0.01f );

		//Setup colors and shader
		trail.GetComponent().material.color = Colors[ note.StringIndex ] * 0.2f;
		trail.GetComponent().material.shader = Shader.Find( "Self-Illumin/Diffuse" );
		trail.GetComponent().enabled = false;

		trail.name = "Trail";

		return trail;
	}

	protected float GetHitZoneBeginning()
	{
		//Adjust this if you want to enable the player to hit the note earlier
		return 2.4f;
	}

	protected float GetHitZoneEnd()
	{
		//Adjust this if you want to enable the player to hit the note later
		return 0.95f;
	}

	public void OnSongFinished()
	{
		GameObject.Find( "GUI Score" ).GetComponent().enabled = false;
		GameObject.Find( "GUI Multiplier" ).GetComponent().enabled = false;

		GetComponent().ShowMenu();
	}

	protected IEnumerator DisplayText( string text, float duration, float fade = 0f )
	{
		//Display a Text in the center of the screen for 'duration' seconds

		GameObject guiTextObject = GameObject.Find( "GUI Text" );

		guiTextObject.GetComponent().text = text;

		//Make text visible
		Color newColor = guiTextObject.GetComponent().material.color;
		newColor.a = 1;
		guiTextObject.GetComponent().material.color = newColor;

		//Wait for duration - fade
		yield return new WaitForSeconds( MyMath.BeatsToSeconds( duration - fade, Player.Song.BeatsPerMinute ) );

		//Fade out text
		float fadeTime = MyMath.BeatsToSeconds( fade, Player.Song.BeatsPerMinute );
		float totalFadeTime = fadeTime;

		while( fadeTime > 0 && guiTextObject.GetComponent().text == text )
		{
			newColor = guiTextObject.GetComponent().material.color;
			newColor.a = fadeTime / totalFadeTime;
			guiTextObject.GetComponent().material.color = newColor;

			fadeTime -= Time.deltaTime;

			yield return null;
		}

		//If no other DisplayText() Coroutine has changed the text, hide it
		if( guiTextObject.GetComponent().text == text )
		{
			guiTextObject.GetComponent().text = "";
		}
	}
}
键盘控制:
using UnityEngine;
using System.Collections;

public class KeyboardControl : MonoBehaviour
{
	//This constant is only used in this class and cannot be adjusted to work with more or less strings
	//This feature is planned for the future
	const int NumStrings = 5;

	//The five button objects in the scene
	protected GameObject[] StringButtons;

	//Stores if the button is held down
	protected bool[] ButtonsPressed;

	//Stores if the button was just pressed in this frame
	protected bool[] ButtonsJustPressed;

	//KeyCodes that control the five string buttons
	protected KeyCode[] StringKeys;

	//Use this for initialization
	void Start()
	{
		ButtonsPressed = new bool[ NumStrings ];
		ButtonsJustPressed = new bool[ NumStrings ];

		for( int i = 0; i < NumStrings; ++i )
		{
			ButtonsPressed[ i ] = false;
			ButtonsJustPressed[ i ] = false;
		}

		UpdateStringKeyArray();
		SaveReferencesToStringButtons();
	}

	protected void UpdateStringKeyArray()
	{
		StringKeys = new KeyCode[ NumStrings ];

		for( int i = 0; i < NumStrings; ++i )
		{
			StringKeys[ i ] = GameObject.Find( "StringButton" + ( i + 1 ) ).GetComponent().Key;
		}
	}

	void SaveReferencesToStringButtons()
	{
		StringButtons = new GameObject[ NumStrings ];

		for( int i = 0; i < NumStrings; ++i )
		{
			StringButtons[ i ] = GameObject.Find( "StringButton" + ( i + 1 ) );
		}
	}

	//Update is called once per frame
	void Update()
	{
		ProcessKeyInput();
	}

	void ProcessKeyInput()
	{
		ResetButtonsJustPressedArray();

		for( int i = 0; i < NumStrings; ++i )
		{
			CheckKeyCode( StringKeys[ i ], i );
		}
	}

	void CheckKeyCode( KeyCode code, int stringIndex )
	{
		if( Input.GetKeyDown( code ) )
		{
			OnStringChange( stringIndex, true );
		}
		if( Input.GetKeyUp( code ) )
		{
			OnStringChange( stringIndex, false );
		}
		if( Input.GetKey( code ) && !ButtonsPressed[ stringIndex ] )
		{
			OnStringChange( stringIndex, true );
		}
	}

	protected void ResetButtonsJustPressedArray()
	{
		for( int i = 0; i < NumStrings; ++i )
		{
			ButtonsJustPressed[ i ] = false;
		}
	}

	protected int GetNumButtonsPressed()
	{
		int pressed = 0;

		for( int i = 0; i < NumStrings; ++i )
		{
			if( ButtonsPressed[ i ] )
			{
				pressed++;
			}
		}

		return pressed;
	}

	public GameObject GetStringButton( int index )
	{
		return StringButtons[ index ];
	}

	public bool IsButtonPressed( int index )
	{
		return ButtonsPressed[ index ];
	}

	public bool WasButtonJustPressed( int index )
	{
		return ButtonsJustPressed[ index ];
	}

	void OnStringChange( int stringIndex, bool pressed )
	{
		Vector3 stringButtonPosition = StringButtons[ stringIndex ].transform.Find( "Paddle" ).transform.position;
		
		if( pressed )
		{
			//Only press this if less then two buttons are already pressed
			//The keyboard limits multiple key presses arbitrarily, sometimes its 2, sometimes 3
			//So I locked it to a maximum of two key presses at the same time for consistency
			if( GetNumButtonsPressed() < 2 )
			{
				//Move the paddle upwards
				stringButtonPosition.y = 0.16f;

				//Enable the light
				StringButtons[ stringIndex ].transform.Find( "Light" ).GetComponent().enabled = true;

				//Update key state
				ButtonsPressed[ stringIndex ] = true;
				ButtonsJustPressed[ stringIndex ] = true;
			}
		}
		else
		{
			//Move paddle down
			stringButtonPosition.y = -0.06f;

			//Disable light
			StringButtons[ stringIndex ].transform.Find( "Light" ).GetComponent().enabled = false;

			//Update key state
			ButtonsPressed[ stringIndex ] = false;
		}

		//Set paddle position
		StringButtons[ stringIndex ].transform.Find( "Paddle" ).transform.position = stringButtonPosition;
	}
}

你可能感兴趣的:(融入动画技术的交互应用)