Project Menggunakan Visual Basic .NET dan XNA Framework 4.0
Source Code bisa di download {belum di upload}
Video hasil project bisa di lihat {belum di upload}
Pada saat mengembangkan games untuk berbagai platforms, anda dengan cepat akan menemukan situasi dimana game anda membutuhkan beberapa cara yang berbeda untuk menampilkan suatu aksi yang sama berdasarkan pada batasan dari masing- masing platform.
Kebalikan dari situasi tersebut dapat terjadi bila anda mengembangkan game untuk satu platform saja. Sejalan dengan game anda secara progresif menjadi semakin kompleks, anda mungkin akan butuh untuk memetakan aksi pada yang berbeda pada game anda dengan tombol yang sama, berdasrkan pada layar yang aktif.
Tidak masalah pada situasi yang mana sekarang anda berada, ada suatu jawaban yang sangat sederhana. Seperti yang telah dideskripsikan pada tulisan ini, sebuah sistem manajemen input yang baik akan menyediakan kebebasan untuk memetakan berbagai macam aksi pada satu kontrol dan memetakan berbagai macam kontrol untuk sebuah aksi.
Langkah pertama saat membuat sebuah sitem manajemen input adalah melepaskan atau memutuskan aksi-aksi yang menyebabkan control input terpakai. Dengan cara ini membuat anda dapat memetakan berbagai tipe input menjadi untuk sebuah aksi dan juga membuatnya lebih mudah untuk mengubah pemetaan (apabila dibutuhkan) dari satu screen ke screen berikutnya.
Input.vb
Tujuan dari input.vb class adalah untuk menyimpan informasi mengenai setiap tipe input yang akan anda terapkan pada game anda. Class ini akan digunakan pada Inputs collection pada GameInput.vb class yang akan dijelaskan kemudian.
Mulailah dengan membuat sebuah Windows Game Project yang baru dan namakan InputHandlerDemo
.
Setelah itu pilih versi target windows phone OS

Masukkan sebuah SpriteFont pada Content Project

dan biarkan nama defaultnya SpriteFont1.spritefont

Aturlah property Size menjadi 20 supaya lebih dapat terbaca.

Sebelum memasukkan class-class baru apapun, anda diharuskan untuk melakukan sedikit pekerjaan. Mulailah dengan meng-klik kanan nama project tersebut pada window Solution Explorer dan menambahkan sebuah new folder.

Namakan folder ini dengan nama Inputs.

Saat anda melakukan ini, class apapun yang anda masukkan ke folder Inputs akan berada pada namespace InputHandlerDemo.Inputs
Anda juga butuh untuk menambahkan sebuah referensi namespace Microsoft.Devices.Sensors. Anda dapat melakukan ini dengan mengklik menu Project dan memilih Add Reference.

Kemudian klik namespace Microsoft.Devices.Sensors kemudian klik OK

Selanjutnya, masukkan sebuah class baru didalam folder Inputs

dan namakan Input.vb

Pastikan statement berikut ini berada pada bagian paling atas dari Input.vb class :
Imports System
Imports System.Collections.Generic
Imports Microsoft.Xna.Framework.Input
Imports Microsoft.Xna.Framework.Input.Touch
Imports Microsoft.Xna.Framework
Imports Microsoft.Devices.Sensors
Didalam Input class anda, buatlah 6 buah Object Dictionary berikut untuk menyimpan input- input dari keyboard, gamepad, touch (tap), touch (slide), gesture, dan accelerometer, secara berturut- turut:
Private keyboardInputs As New Dictionary(Of Keys, Boolean)
Private gamepadInputs As New Dictionary(Of Buttons, Boolean)
Private touchTapInputs As New Dictionary(Of Rectangle, Boolean)
Private touchSlideInputs As New Dictionary(Of Direction, Single)
Private gestureInputs As New Dictionary(Of Integer, GestureDefinition)
Private accelerometerInputs As New Dictionary(Of Direction, Single)
Buttons merupakan tabel yang berisikan semua daftar tombol, sticks, dan triggers yang dapat ditemukan pada gamepad dan berada pada namespace Microsoft.Xna.Framework.Input. Anda dapat melihat definisi komplitnya disini:
<Flags()> _
Public Enum Buttons
DPadUp = 1
DPadDown = 2
DPadLeft = 4
DPadRight = 8
Start = 16
Back = 32
LeftStick = 64
RightStick = 128
LeftShoulder = 256
RightShoulder = 512
BigButton = 2048
A = 4096
B = 8192
X = 16384
Y = 32768
LeftThumbstickLeft = 2097152
RightTrigger = 4194304
LeftTrigger = 8388608
RightThumbstickUp = 16777216
RightThumbstickDown = 33554432
RightThumbstickRight = 67108864
RightThumbstickLeft = 134217728
LeftThumbstickUp = 268435456
LeftThumbstickDown = 536870912
LeftThumbstickRight = 1073741824
End Enum
Untuk mengingatkan kembali pada arti dari <Flags()> attribute, maupun alasan atas mengapa semua values merupakan kelipatan dari 2, cobalah lihat di pembahasan sebelumnya disini.
Direction berisikan daftar dari 4 buah arah (atas/up, bawah/down, kanan/right, dan kiri/left) dan akan di jelaskan nanti.
Anda akan membuat GestureDefinition.vb class setelah Input.vb class selesai. Untuk sekarang, anda hanya perlu untuk mengetahui bahwa class tersebut menyimpan informasi GestureSample dan menyediakan cara-cara untuk menargetkan sebuah area tertentu dengan gestures anda. Lalu, tambahkan lagi dua buah objek Dictionary, kali ini untuk menyimpan objek dari GamePadState yang sekarang maupun yang sebelumnya. Anda mungkin ingin melakukan hal ini agar anda dapat membedakan antara menekan tombol sekali dan menahan tombol tersebut, dan menspesifikasikan bagaimana game anda akan merespon pada masing- masing aksi.
Public Shared CurrentGamePadState As New Dictionary(Of PlayerIndex, GamePadState)
Public Shared PreviousGamePadState As New Dictionary(Of PlayerIndex, GamePadState)
Walupun anda tidak dapat menyambungkan gamepad Xbox 360 ke device windows phone anda, Tujuan dari GamePadState adalah digunakan untuk mendeteksi apakah tombol Back sedang ditekan atau tidak. Dan juga membuat semua code yang terdapat di Xbox dan Windows game sedikit lebih mudah untuk dijaga dan dipertahankan, karena hal tersebut digunakan dengan cara yang sama.
Anda ingin melakukan hal yang sama untuk menyimpan states sekarang dan states sebelumnya dari TouchLocation dan Keyboard states :
Public Shared CurrentTouchLocationState As TouchCollection
Public Shared PreviousTouchLocationState As TouchCollection
Public Shared CurrentKeyboardState As KeyboardState
Public Shared PreviousKeyboardState As KeyboardState
Hal selanjutnya yang harus anda masukkan kedalam bagian ini ialah baris berikut ini untuk memeriksa state dari koneksi Gamepad:
Public Shared GamepadConnectionState As New Dictionary(Of PlayerIndex, Boolean)
Bukan sesuatu hal yang diwajibkan untuk mengecek state dari koneksi Gamepad pada game yang hanya berbasis windows phone. Akan tetapi, dikarenakan XNA ini mendukung segala bentuk platforms, anda nantinya mungkin ingin melakukannya untuk Xbox 360 dan Windows games.
Windows Phone Games secara sederhana akan terus mengevaluasi state yang tersambung. Selanjutnya, masukkan baris berikut untuk menyimpan gestures yang terdeteksi pada saat single pass terjadi. Variabel ini akan dikosongkan pada awal dari rutinitas Update.
Private Shared detectedGestures As New List(Of GestureDefinition)
Sekarang masukkan support untuk sensor accelerometer dan hasil pembacaan accelerometer saat ini:
Private Shared accelerometerSensor As Accelerometer
Private Shared _currentAccelerometerReading As Vector3
Terakhir, anda akan memasukkan sebuah list yang menyimpan segala jenis arah yang memungkinkan untuk custom TouchSlide gesture. Ini akan digunakan oleh TouchSlide dictionary yang telah anda tetapkan sebelumnya.
Public Enum Direction
Up
Down
Left
Right
End Enum
Nama lain yang lebih baik dari custom TouchSlide gesture mungkin adalah Swipe, sebenarnya lebih enak menyebutnya dengan swipe J. Walaupun Swipe Gesture tidak terdapat pada XNA 4.0 sekarang ini, mungkin saja gesture tersebut akan ada pada versi XNA yang selanjutnya. Karena itu, untuk menghindari kebingungan dan konflik yang mungkin terjadi, sang penulis memutuskan untuk menggunakan nama TouchSlide.
Melihat sekarang anda sudah menyingkirkan semua class level variabel, anda sudah dapat membuat constructor untuk Input.vb class. Code dibawah ini akan menginisialisasikan bentuk sekarang dan sebelumnya dari GamePadState Dictionaries, GamepadConnectionState, dan Accelerometer sensor.
Public Sub New()
If CurrentGamePadState.Count = 0 Then
CurrentGamePadState.Add(PlayerIndex.One, GamePad.GetState(PlayerIndex.One))
CurrentGamePadState.Add(PlayerIndex.Two, GamePad.GetState(PlayerIndex.Two))
CurrentGamePadState.Add(PlayerIndex.Three, GamePad.GetState(PlayerIndex.Three))
CurrentGamePadState.Add(PlayerIndex.Four, GamePad.GetState(PlayerIndex.Four))
PreviousGamePadState.Add(PlayerIndex.One, GamePad.GetState(PlayerIndex.One))
PreviousGamePadState.Add(PlayerIndex.Two, GamePad.GetState(PlayerIndex.Two))
PreviousGamePadState.Add(PlayerIndex.Three, GamePad.GetState(PlayerIndex.Three))
PreviousGamePadState.Add(PlayerIndex.Four, GamePad.GetState(PlayerIndex.Four))
GamepadConnectionState.Add(PlayerIndex.One, CurrentGamePadState(PlayerIndex.One).IsConnected)
GamepadConnectionState.Add(PlayerIndex.Two, CurrentGamePadState(PlayerIndex.Two).IsConnected)
GamepadConnectionState.Add(PlayerIndex.Three, CurrentGamePadState(PlayerIndex.Three).IsConnected)
GamepadConnectionState.Add(PlayerIndex.Four, CurrentGamePadState(PlayerIndex.Four).IsConnected)
End If
If accelerometerSensor Is Nothing Then
accelerometerSensor = New Accelerometer
AddHandler accelerometerSensor.ReadingChanged, AddressOf AccelerometerReadingChanged
End If
End Sub
Anda mungkin bertanya-tanya kenapa anda memasukkan code untuk 4 orang player padahal Windows Phone 7 hanya mensupport PlayerIndex.One. Sistem manajemen input yang sedang anda buat didesain untuk dapat bekerja dengan semua jenis platform yang ter-support. Hal ini akan membuat nya secara signifikan lebih mudah untuk membagikan lebih banyak code base yang sama, tak perduli platform mana yang anda targetkan apakah windows phone, xbox ataupun windows game.
Sekarang, masukkan dua buah methods berikut. Methods-methods ini akan menset states sekarang dan sebelumnya untuk gamepad, touch panel, dan keyboard, dan mengosongkan gestures apapun yang terdeteksi sebelumnya, sebelum akhirnya akan memasukkan gestures lain yang baru saja terdeteksi. Sebuah versi yang sedikit lebih diabstraksikan dari dua methods ini akan diakses sebagai bagian dari Update() method dari game anda, yang mana terbungkus oleh code untuk mendeteksi aksi dari player.
Public Shared Sub BeginUpdate()
CurrentGamePadState(PlayerIndex.One) = GamePad.GetState(PlayerIndex.One)
CurrentGamePadState(PlayerIndex.Two) = GamePad.GetState(PlayerIndex.Two)
CurrentGamePadState(PlayerIndex.Three) = GamePad.GetState(PlayerIndex.Three)
CurrentGamePadState(PlayerIndex.Four) = GamePad.GetState(PlayerIndex.Four)
CurrentTouchLocationState = TouchPanel.GetState()
CurrentKeyboardState = Keyboard.GetState(PlayerIndex.One)
detectedGestures.Clear()
Do While TouchPanel.IsGestureAvailable
Dim gesture = TouchPanel.ReadGesture()
detectedGestures.Add(New GestureDefinition(gesture))
Loop
End Sub
Public Shared Sub EndUpdate()
PreviousGamePadState(PlayerIndex.One) = CurrentGamePadState(PlayerIndex.One)
PreviousGamePadState(PlayerIndex.Two) = CurrentGamePadState(PlayerIndex.Two)
PreviousGamePadState(PlayerIndex.Three) = CurrentGamePadState(PlayerIndex.Three)
PreviousGamePadState(PlayerIndex.Four) = CurrentGamePadState(PlayerIndex.Four)
PreviousTouchLocationState = CurrentTouchLocationState
PreviousKeyboardState = CurrentKeyboardState
End Sub
Method selanjutnya untuk ditambahkan adalah target dari event yang anda letakkan pada bagian bawah dari Input.vb class constructor. Method ini akan diakses untuk menset currentAccelerometerReading
Private Sub AccelerometerReadingChanged(ByVal sender As Object, ByVal e As AccelerometerReadingEventArgs)
_currentAccelerometerReading.X = CSng(e.X)
_currentAccelerometerReading.Y = CSng(e.Y)
_currentAccelerometerReading.Z = CSng(e.Z)
End Sub
Method berikutnya yang akan anda tambahkan akan digunakan untuk memetakan sebuah aksi dari game pada input yang spesifik. Kelebihan dari pendekatan ini adalah besarnya ke fleksibilitas yang ditawarkannya. Bila anda ingin memetakan banyak inputs untuk menampilkan aksi yang sama, yang harus anda lakukan adalah menentukan aksi tersebut sekali dalam game anda, dan kemudian anda dapat memetakannya dengan input- input yang berbeda sebanyak mungkin yang anda butuhkan.
Public Sub AddKeyboardInput(ByVal theKey As Keys, ByVal isReleasedPreviously As Boolean)
If keyboardInputs.ContainsKey(theKey) Then
keyboardInputs(theKey) = isReleasedPreviously
Return
End If
keyboardInputs.Add(theKey, isReleasedPreviously)
End Sub
Public Sub AddGamepadInput(ByVal theButton As Buttons, ByVal isReleasedPreviously As Boolean)
If gamepadInputs.ContainsKey(theButton) Then
gamepadInputs(theButton) = isReleasedPreviously
Return
End If
gamepadInputs.Add(theButton, isReleasedPreviously)
End Sub
Public Sub AddTouchTapInput(ByVal theTouchArea As Rectangle, ByVal isReleasedPreviously As Boolean)
If touchTapInputs.ContainsKey(theTouchArea) Then
touchTapInputs(theTouchArea) = isReleasedPreviously
Return
End If
touchTapInputs.Add(theTouchArea, isReleasedPreviously)
End Sub
Pekerjaan Ini mungkin terlihat seperti anda sedang melakukan banyak pekerjaan infrastruktur saat ini, tetapi jangan khawatir! Semua nya akan terbayar kalau anda sudah mulai bekerja pada Game class dan lihat lah hasil dari kerja anda.
Sadarkah anda bahwa ke tiga method tersebut mengikuti pola yang serupa?
Pada method AddKeyboardInput(), anda memasukkan dua buah parameter.
- Yang pertama mengandung kunci mana yang digunakan untuk pemetaan, dan
- yang ke dua adalah sebuah Boolean flag yang mengindikasikan apakah dengan menahan tombol tersebut dihitung sebagai aksi tunggal (false) atau mengulang aksi yang sama sampai anda melepaskannya (true).
Hampir sama dengan AddKeyboardInput method, method AddGamepadInput() menerima dua parameter:
- tombol mana untuk pemetaan, dan
- sebuah flag untuk mengetahui apakah dengan menahan tombol tersebut dihitung sebagai aksi tunggal (false) atau mengulang aksi yang sama sampai anda melepaskannya (true).
Pada AddTouchTapInput() method, anda juga akan memasukkan 2 buah parameter.
- Parameter pertama mengandung sebuah bujursangkar atas area layar yang bertanggung jawab atas aksi, dan
- yang kedua adalah auto-repeat flag yang sama seperti yang telah dikatakan. Pada kasus ini, mempertahankan jari anda berada pada layar setelah melakukan tapping, secara efektif dikatakan sama dengan menahan sebuah tombol.
Pada inti nya, ke 3 method secara dasarnya bekerja dengan cara yang sama :
- Apakah aksi yang anda tambahkan sudah ada pada dictionary yang bersangkutan?
- Bila YA, update flag pada value yang telah dimasukkan dan keluar.
- Bila TIDAK, tambahkan aksi tersebut pada dictionary yang benar, set flag nya dan keluar.
Sekarang masukkan dua buah methods berikut untuk menangani TouchSlide gesture custom dan XNA provided gestures :
Public Sub AddTouchSlideInput(ByVal theDirection As Direction, ByVal slideDistance As Single)
If touchSlideInputs.ContainsKey(theDirection) Then
touchSlideInputs(theDirection) = slideDistance
Return
End If
touchSlideInputs.Add(theDirection, slideDistance)
End Sub
Public PinchGestureAvailable As Boolean = False
Public Sub AddTouchGesture(ByVal theGesture As GestureType, ByVal theTouchArea As Rectangle)
TouchPanel.EnabledGestures = theGesture Or TouchPanel.EnabledGestures
gestureInputs.Add(gestureInputs.Count, New GestureDefinition(theGesture, theTouchArea))
If theGesture = GestureType.Pinch Then
PinchGestureAvailable = True
End If
End Sub
Method AddTouchSlideInput() juga menerima dua parameter. Tetapi kali ini, mereka sedikit berbeda.
- Yang pertama mengandung arah (direction) kemana anda menslide jari anda, dan
- yang kedua mengandung sebuah nomor floating point yang memeberitahu harus sejauh mana anda harus mengarahkan/ men-slide jari anda untuk mengkatifkan aksi tersebut.
AddTouchGesture() method menerima GestureType() dan sebuah objek bujursangkar, yang menetapkan area touch yang memungkinkan.
Anda juga akan mengekspos variabel dari PinchGestureAvailable, yang akan di cek pada GameInput.vb class.
Dua buah methods yang berikutnya, yang digabungkan dengan isAccelerometerStarted flag, memverifikasikan bahwa accelerometernya dimulai. Anda kemudian diizinkan untuk memasukkan atau mengeluarkan input accelerometer dari accelerometerInputs Dictionary.
Pada method yang pertama, anda akan mensuplai sebuah direction dan sebuah data bertipe single yang melambangkan batas kemiringan untuk input tersebut :
Private Shared isAccelerometerStarted As Boolean = False
Public Sub AddAccelerometerInput(ByVal direction As Direction, ByVal tiltThreshold As Single)
If Not isAccelerometerStarted Then
Try
accelerometerSensor.Start()
isAccelerometerStarted = True
Catch e As AccelerometerFailedException
isAccelerometerStarted = False
System.Diagnostics.Debug.WriteLine(e.Message)
End Try
End If
accelerometerInputs.Add(direction, tiltThreshold)
End Sub
Public Sub RemoveAccelerometerInputs()
If isAccelerometerStarted Then
Try
accelerometerSensor.Stop()
isAccelerometerStarted = False
Catch e As AccelerometerFailedException
' The sensor couldn't be stopped.
System.Diagnostics.Debug.WriteLine(e.Message)
End Try
End If
accelerometerInputs.Clear()
End Sub
Sekarang, masukkan method IsConnected(), yang mana menghasilkan sebuah Boolean yang menandakan apakah PlayerIndex yang dimasukkan sekarang terhubung :
Public Shared Function IsConnected(ByVal thePlayerIndex As PlayerIndex) As Boolean
Return CurrentGamePadState(thePlayerIndex).IsConnected
End Function
Berikutnya, anda masukkan overloaded method IsPressed dan method individual control input. Hal-hal tersebut akan melengkapi setengah bagian lainnya dari class ini, mengingat mereka bertanggung jawab dalam menentukan keberadaan apakah ada input yang telah ditetapkan benar-benar sudah ada.
Public Function IsPressed(ByVal thePlayerIndex As PlayerIndex) As Boolean
Return IsPressed(thePlayerIndex, Nothing)
End Function
Method berikut ini mengandung 6 blok code yang bertanggung jawab untuk mendeteksi dan menangani :
- keyboard input
- gamepad input
- touch (tap) input
- touch (slide) input
- gesture input (pada lokasi yang spesifik), dan
- accelerometer input
secara berturut-turut. Bila tidak ada dari ke enam input ini yang terdeteksi, method IsPressed() secara sederhana akan menghasilkan kesalahan (false)
Public Function IsPressed(ByVal thePlayerIndex As PlayerIndex,
ByVal theCurrentObjectLocation? As Rectangle) As Boolean
If IsKeyboardInputPressed() Then
Return True
End If
If IsGamepadInputPressed(thePlayerIndex) Then
Return True
End If
If IsTouchTapInputPressed() Then
Return True
End If
If IsTouchSlideInputPressed() Then
Return True
End If
If IsGestureInputPressed(theCurrentObjectLocation) Then
Return True
End If
Return False
End Function
Melihat sekarang IsPressed method sudah berada di tempatnya, Visual Studio akan protes mengenai semua method yang belum anda buat J. Mulailah dengan menambahkan method berikut ini untuk mendeteksi apakah ada dari tombol- tombol yang telah anda masukkan pada keyboardInputs dictionary telah ditekan. Anda juga akan mengecek untuk Boolean value (yang sewajarnya dimasukkan pada AddKeyboardInput() method melalui parameter isReleasedPreviously) untuk menentukan apakah hanya menerima penekanan tombol yang baru (new press), atau untuk mengenali saat suatu tombol sedang ditahan (hold)
Private Function IsKeyboardInputPressed() As Boolean
For Each aKey In keyboardInputs.Keys
If keyboardInputs(aKey) AndAlso
CurrentKeyboardState.IsKeyDown(aKey) AndAlso
(Not PreviousKeyboardState.IsKeyDown(aKey)) Then
Return True
ElseIf (Not keyboardInputs(aKey)) AndAlso CurrentKeyboardState.IsKeyDown(aKey) Then
Return True
End If
Next aKey
Return False
End Function
Method selanjutnya mengecek untuk melihat apkah game anda telah menerima suatu input dari gamepad yang berhubungan dengan player tertentu. Pada Windows Phone 7 game, input ini akan selalu menjadi PlayerIndex.One, akan tetapi hal ini bisa saja salah satu dari empat controller yang tersedia pada Xbox 360 atau Windows game.
Method ini juga bergantung pada teknik yang sama dengan method sebelumnya untuk membedakan input yang baru dengan input yang sedang berlangsung.
Private Function IsGamepadInputPressed(ByVal thePlayerIndex As PlayerIndex) As Boolean
For Each aButton In gamepadInputs.Keys
If gamepadInputs(aButton) AndAlso
CurrentGamePadState(thePlayerIndex).IsButtonDown(aButton) AndAlso
(Not PreviousGamePadState(thePlayerIndex).IsButtonDown(aButton)) Then
Return True
ElseIf (Not gamepadInputs(aButton)) AndAlso
CurrentGamePadState(thePlayerIndex).IsButtonDown(aButton) Then
Return True
End If
Next aButton
Return False
End Function
Method berikutnya ini bekerja hampir sama seperti dengan dua method sebelumnya. Method ini menentukan apakah suatu touch input telah ada pada area bujursangkar yang anda sediakan saat menempatkan input ( dengan memasukkannya ke touchTapInputs dictionary).
Private Function IsTouchTapInputPressed() As Boolean
For Each touchArea In touchTapInputs.Keys
If touchTapInputs(touchArea) AndAlso
touchArea.Intersects(CurrentTouchRectangle) AndAlso
PreviousTouchPosition() Is Nothing Then
Return True
ElseIf (Not touchTapInputs(touchArea)) AndAlso
touchArea.Intersects(CurrentTouchRectangle) Then
Return True
End If
Next touchArea
Return False
End Function
Kemungkinan yang dapat diwujudkan dalam menggunakan method ini tidak terbatas. Mungkin anda memiliki onscreen buttons, atau mungkin bujursangkar tersebut melambangkan sasaran atau potongan puzzle. Dapat membandingkan lokasi dari touch dengan lokasi dari sebuah item onscreen.
Method selanjutnya mendeteksi apakah custom gesture TouchSlide dilakukan atau tidak, dan juga arah dari slide dan apakah panjang minimum dari slide memenuhi syarat. Anda menentukan arah dan panjang pada parameter yang dimasukkan ke AddTouchSlideInput() method.
Private Function IsTouchSlideInputPressed() As Boolean
For Each slideDirection In touchSlideInputs.Keys
If CurrentTouchPosition() IsNot Nothing AndAlso
PreviousTouchPosition() IsNot Nothing Then
Select Case slideDirection
Case Direction.Up
If CurrentTouchPosition().Value.Y + touchSlideInputs(slideDirection) <
PreviousTouchPosition().Value.Y Then
Return True
End If
Exit Select
Case Direction.Down
If CurrentTouchPosition().Value.Y - touchSlideInputs(slideDirection) >
PreviousTouchPosition().Value.Y Then
Return True
End If
Exit Select
Case Direction.Left
If CurrentTouchPosition().Value.X + touchSlideInputs(slideDirection) <
PreviousTouchPosition().Value.X Then
Return True
End If
Exit Select
Case Direction.Right
If CurrentTouchPosition().Value.X - touchSlideInputs(slideDirection) >
PreviousTouchPosition().Value.X Then
Return True
End If
Exit Select
End Select
End If
Next slideDirection
Return False
End Function
Sekarang, anda masukkan sebuah method untuk mendeteksi input gesture. Method ini looping melalui dictionary gestures anda dan membandingkannya dengan daftar gestures yang terdeteksi pada akses yang sekarang ke Update() method. Bila kecocokan ditemukan, anda kemudian akan mengecek apakah gesture tersebut di lakukan dengan benar pada layar.
Private Function IsGestureInputPressed(ByVal theNewDetectionLocation? As Rectangle) As Boolean
currentGestureDefinition = Nothing
If detectedGestures.Count = 0 Then
Return False
End If
' Check to see if any of the Gestures defined in the gestureInputs
' dictionary have been performed and detected.
For Each userDefinedGesture In gestureInputs.Values
For Each detectedGesture In detectedGestures
If detectedGesture.Type = userDefinedGesture.Type Then
' If a Rectangle area to check against has been passed in, then
' use that one, otherwise use the one originally defined
Dim areaToCheck = userDefinedGesture.CollisionArea
If theNewDetectionLocation IsNot Nothing Then
areaToCheck = CType(theNewDetectionLocation, Rectangle)
End If
' If the gesture detected was made in the area where users were
' interested in Input (they intersect), then a gesture input is
' considered detected.
If detectedGesture.CollisionArea.Intersects(areaToCheck) Then
If currentGestureDefinition Is Nothing Then
currentGestureDefinition = New GestureDefinition(detectedGesture.Gesture)
Else
' Some gestures like FreeDrag and Flick are registered many,
' many times in a single Update frame. Since there is only
' one variable to store the gesture info, you must add on
' any additional gesture values so there is a combination
' of all the gesture information in currentGesture
currentGestureDefinition.Delta += detectedGesture.Delta
currentGestureDefinition.Delta2 += detectedGesture.Delta2
currentGestureDefinition.Position += detectedGesture.Position
currentGestureDefinition.Position2 += detectedGesture.Position2
End If
End If
End If
Next detectedGesture
Next userDefinedGesture
If currentGestureDefinition IsNot Nothing Then
Return True
End If
Return False
End Function
Method selanjutnya berikut ini adalah yang terakhir untuk Input.vb class. Sekali anda memasukkannya dan beberapa properti, anda akan selesai dengan Input class ini.
Tujuan dari method ini adalah untuk membandingkan bacaan accelerometer pada saat ini dengan tingkat/batas kemiringan untuk arah yang sudah ditentukan dan untuk mengembalikan value true bila telepon nya dimiringkan dengan benar pada arah yang tepat.
Private Function IsAccelerometerInputPressed() As Boolean
For Each input In accelerometerInputs
Select Case input.Key
Case Direction.Up
If Math.Abs(_currentAccelerometerReading.Y) > input.Value AndAlso
_currentAccelerometerReading.Y < 0 Then
Return True
End If
Exit Select
Case Direction.Down
If Math.Abs(_currentAccelerometerReading.Y) > input.Value AndAlso
_currentAccelerometerReading.Y > 0 Then
Return True
End If
Exit Select
Case Direction.Left
If Math.Abs(_currentAccelerometerReading.X) > input.Value AndAlso
_currentAccelerometerReading.X < 0 Then
Return True
End If
Exit Select
Case Direction.Right
If Math.Abs(_currentAccelerometerReading.X) > input.Value AndAlso
_currentAccelerometerReading.X > 0 Then
Return True
End If
Exit Select
End Select
Next input
Return False
End Function
Pada tahapan ini anda telah selesai dengan semua method pada class input.vb ini, tapi ada beberapa properties yang harus di tambahkan.
Ini adalah rangkaian awal properties yang akan di gunakan untuk menyediakan informasi dan delta axis ke GameInput.vb class, yang nantinya akan anda bangun.
Private currentGestureDefinition As GestureDefinition
Public Function CurrentGesturePosition() As Vector2
If currentGestureDefinition Is Nothing Then
Return Vector2.Zero
End If
Return currentGestureDefinition.Position
End Function
Public Function CurrentGesturePosition2() As Vector2
If currentGestureDefinition Is Nothing Then
Return Vector2.Zero
End If
Return currentGestureDefinition.Position2
End Function
Public Function CurrentGestureDelta() As Vector2
If currentGestureDefinition Is Nothing Then
Return Vector2.Zero
End If
Return currentGestureDefinition.Delta
End Function
Public Function CurrentGestureDelta2() As Vector2
If currentGestureDefinition Is Nothing Then
Return Vector2.Zero
End If
Return currentGestureDefinition.Delta2
End Function
Dua properties selanjutnya akan me-loop melalui touch location yang terkandung dalam State object dan memperlihatkan lokasi sekarang dan sebelumnya dari screen touch points, secara berturut- turut.
Public Function CurrentTouchPosition() As Vector2?
For Each location In CurrentTouchLocationState
Select Case location.State
Case TouchLocationState.Pressed
Return location.Position
Case TouchLocationState.Moved
Return location.Position
End Select
Next location
Return Nothing
End Function
Private Function PreviousTouchPosition() As Vector2?
For Each location In PreviousTouchLocationState
Select Case location.State
Case TouchLocationState.Pressed
Return location.Position
Case TouchLocationState.Moved
Return location.Position
End Select
Next location
Return Nothing
End Function
Property berikutnya di dalam class input.vb ini adalah property CurrentTouchRectangle, yang memberikan informasi rectangle yang mana yang disentuh:
Private ReadOnly Property CurrentTouchRectangle As Rectangle
Get
Dim touchPosition? = CurrentTouchPosition()
If touchPosition Is Nothing Then
Return Rectangle.Empty
End If
Return New Rectangle(CInt(touchPosition.Value.X) - 5,
CInt(touchPosition.Value.Y) - 5,
10,
10)
End Get
End Property
Terakhir, masukkan property CurrentAccelerometerReading, yang memperlihatkan value dari pembacaan accelerometer yang sekarang berjalan:
Public ReadOnly Property CurrentAccelerometerReading As Vector3
Get
Return _currentAccelerometerReading
End Get
End Property
Anda telah menyelesaikan Input.vb class.
Seperti yang sudah anda lihat, disamping input yang telah ditetapkan sejak awalnya (seperti keyboard, gamepad, accelerometer, dan sistem gesture), class ini dapat diperluas lebih lanjut untuk memasukkan custom gesture dari anda sendiri.
GestureDefinition.vb
GestureDefinition.vb class digunakan untuk menyimpan informasi mengenai tipe dari gesture yang sedang dilakukan, target rectangle mana gestures seharusnya di lakukan, dan informasi dari object GestureSample yang sesungguhnya. GestureDefinition.vb class digunakan disepanjang Input.vb class.
Untuk menciptakan class ini, masukkan sebuah class baru ke Inputs folder anda dan namakan GestureDefinition.vb

Pastikan bahwa statement berikut ini ada pada bagian atas dari class file yang baru dibuat:
Imports System
Imports Microsoft.Xna.Framework
Imports Microsoft.Xna.Framework.Input.Touch
Selanjutnya, tambahkan Public Class variabel berikut ini untuk menyimpan semua informasi yang Anda butuhkan nanti:
Public Type As GestureType
Public CollisionArea As Rectangle
Public Gesture As GestureSample
Public Delta As Vector2
Public Delta2 As Vector2
Public Position As Vector2
Public Position2 As Vector2
Berikutnya, tambahkan Overloaded Constructors berikut ini kedalam GestureDefinition.vb class.
Public Sub New(ByVal theGestureType As GestureType,
ByVal theGestureArea As Rectangle)
Gesture = New GestureSample(theGestureType,
New TimeSpan(0),
Vector2.Zero,
Vector2.Zero,
Vector2.Zero,
Vector2.Zero)
Type = theGestureType
CollisionArea = theGestureArea
End Sub
Public Sub New(ByVal theGestureSample As GestureSample)
Gesture = theGestureSample
Type = theGestureSample.GestureType
CollisionArea = New Rectangle(CInt(theGestureSample.Position.X),
CInt(theGestureSample.Position.Y), 5, 5)
Delta = theGestureSample.Delta
Delta2 = theGestureSample.Delta2
Position = theGestureSample.Position
Position2 = theGestureSample.Position2
End Sub
- Overload yang pertama akan menerima sebuah Gesture type dan sebuah Rectangle yang menjelaskan dimana seharusnya gesture ini dilakukan. Dari sini, sebuah GestureSample objek yang baru dibuat dan dinisialisasikan dengan nilai awal untuk properties Position dan Delta.
- Overload yang kedua menerima sebuah GestureSample objek yang sudah ada dan mengisi GestureDefinition properties dari informasi yang terkandung didalamnya. Itulah semua yang ada untuk GestureDefinition.vb class. Sekarang adalah saatnya untuk meletakkan nya dan Input class untuk digunakan pada GameInput.vb class.
GameInput.vb
GameInput.vb class membungkus fungsi dari Input dan GestureDefinition.vb class dan juga menyediakan sebuah dictionary dari tipe-tipe Input yang anda tentukan untuk game anda.
Tambahkan suatu class baru yang lain ke project anda (juga didalam Input folder) dan namakan GameInput.vb.

Pastikan statement berikut ini berada pada bagian atas dari GameInput.vb class file:
Imports System
Imports System.Collections.Generic
Imports Microsoft.Xna.Framework
Imports Microsoft.Xna.Framework.Input
Imports Microsoft.Xna.Framework.Input.Touch
Kemudian deklarasikan variabel Input ini kedalam Class GameInput.vb
Private Inputs As New Dictionary(Of String, Input)
Dictionary untuk Input akan menyimpan semua tipe Input yang anda gunakan pada game anda.
Method berikut ini menunjukkan tipe input atas aksi apapun yang anda masukkan. Sebagai tambahan, bila aksi tersebut belum berada pada dictionary, method tersebut akan membuat sebuah entri aksi yang baru secara otomatis dan kemudian menunjukkan tipe inputnya.
Public Function GetInput(ByVal theAction As String) As Input
'Add the Action if it doesn't already exist
If Inputs.ContainsKey(theAction) = False Then
Inputs.Add(theAction, New Input)
End If
Return Inputs(theAction)
End Function
Dua method yang berikutnya dengan praktisnya membungkus method-method dengan nama yang sama di dalam Input class, membuat nya menjadi sederhana untuk Game class anda. Anda cukup untuk hanya menangani GameInput class daripada menangani Input dan GameInput.
Public Sub BeginUpdate()
Input.BeginUpdate()
End Sub
Public Sub EndUpdate()
Input.EndUpdate()
End Sub
Method IsConnected() berikut ini menunjukkan hubungan dari controller Gamepad berdasarkan pada PlayerIndex yang dimasukkan:
Public Function IsConnected(ByVal thePlayer As PlayerIndex) As Boolean
' If there never WAS a gamepad connected, just say the gamepad is STILL connected
If Input.GamepadConnectionState(thePlayer) = False Then
Return True
End If
Return Input.IsConnected(thePlayer)
End Function
Berikutnya overloaded method IsPressed akan mengecek Inputs dictionary lokal untuk sebuah aksi. Bila aksi tersebut tidak berada didalam dictionary, akan memberitahukan suatu kesalahan. Bila tidak, hal tersebut akan mengakses IsPressed() method khusus untuk objek input yang berhubungan dengan aksi tersebut dan akan mengembalikan value true bila input yang benar diberikan si player; bila tidak akan menunjukkan value false.
Public Function IsPressed(ByVal theAction As String) As Boolean
If Not Inputs.ContainsKey(theAction) Then
Return False
End If
Return Inputs(theAction).IsPressed(PlayerIndex.One)
End Function
Public Function IsPressed(ByVal theAction As String, ByVal thePlayer As PlayerIndex) As Boolean
If Inputs.ContainsKey(theAction) = False Then
Return False
End If
Return Inputs(theAction).IsPressed(thePlayer)
End Function
Public Function IsPressed(ByVal theAction As String, ByVal thePlayer? As PlayerIndex) As Boolean
If thePlayer Is Nothing Then
Dim theReturnedControllingPlayer As PlayerIndex
Return IsPressed(theAction, thePlayer, theReturnedControllingPlayer)
End If
Return IsPressed(theAction, CType(thePlayer, PlayerIndex))
End Function
Overload berikutnya adalah tantangan yang sebenarnya, maka perhatikanlah dengan saksama mengenai apa yang terjadi didalamnya. Disini, anda akan memasukkan sebuah Action objek dan mungkin sebuah PlayerIndex. (Perhatikan ?, yang mana mengartikan tipe nullable.)
- Bila Action objek yang anda masukkan tidak cocok dengan konten apapun pada Inputs dictionary, method tersebut akan mengembalikan value false dan keluar.
- Bila anda memasukkan Action objek yang benar, tetapi anda tidak memasukkan sebuah PlayerIndex, method tersebut akan mengecek ke empat player yang memungkinkan untuk melihat apakah salah satu darinya mengeluarkan aksi tersebut.
- Bila player yang mengeluarkan aksi tersebut ditemukan, set controlling player ke index dari player yang mengeluarkan aksi tersebut dan akan mengembalikan value true.
- Bila player yang bersangkutan tidak dapat ditemukan, set controlling player pada PlayerIndex.One dan akan mengembalikan nilai false.
- Bila sebuah PlayerIndex benar-benar dimasukkan, set controlling player pada index yang sesuai dan aktifkan satu dari overload IsPressed dengan parameter Action dan PlayerIndex.
- Berikut adalah code untuk melakukan ini:
Public Function IsPressed(ByVal theAction As String,
ByVal thePlayer? As PlayerIndex,
<System.Runtime.InteropServices.Out()> ByRef theControllingPlayer As PlayerIndex) As Boolean
If Not Inputs.ContainsKey(theAction) Then
theControllingPlayer = PlayerIndex.One
Return False
End If
If thePlayer Is Nothing Then
If IsPressed(theAction, PlayerIndex.One) Then
theControllingPlayer = PlayerIndex.One
Return True
End If
If IsPressed(theAction, PlayerIndex.Two) Then
theControllingPlayer = PlayerIndex.Two
Return True
End If
If IsPressed(theAction, PlayerIndex.Three) Then
theControllingPlayer = PlayerIndex.Three
Return True
End If
If IsPressed(theAction, PlayerIndex.Four) Then
theControllingPlayer = PlayerIndex.Four
Return True
End If
theControllingPlayer = PlayerIndex.One
Return False
End If
theControllingPlayer = CType(thePlayer, PlayerIndex)
Return IsPressed(theAction, CType(thePlayer, PlayerIndex))
End Function
Enam Properties berikutnya dipanggil langsung dari game1.vb class, enam properties ini menyediakan pemetaan input kepada aksi dan perilaku game.
Public Sub AddGamePadInput(ByVal theAction As String,
ByVal theButton As Buttons,
ByVal isReleasedPreviously As Boolean)
GetInput(theAction).AddGamepadInput(theButton, isReleasedPreviously)
End Sub
Public Sub AddTouchTapInput(ByVal theAction As String,
ByVal theTouchArea As Rectangle,
ByVal isReleasedPreviously As Boolean)
GetInput(theAction).AddTouchTapInput(theTouchArea, isReleasedPreviously)
End Sub
Public Sub AddTouchSlideInput(ByVal theAction As String,
ByVal theDirection As Input.Direction,
ByVal slideDistance As Single)
GetInput(theAction).AddTouchSlideInput(theDirection, slideDistance)
End Sub
Public Sub AddKeyboardInput(ByVal theAction As String,
ByVal theKey As Keys,
ByVal isReleasedPreviously As Boolean)
GetInput(theAction).AddKeyboardInput(theKey, isReleasedPreviously)
End Sub
Public Sub AddTouchGestureInput(ByVal theAction As String,
ByVal theGesture As GestureType,
ByVal theRectangle As Rectangle)
GetInput(theAction).AddTouchGesture(theGesture, theRectangle)
End Sub
Public Sub AddAccelerometerInput(ByVal theAction As String,
ByVal theDirection As Input.Direction,
ByVal tiltThreshold As Single)
GetInput(theAction).AddAccelerometerInput(theDirection, tiltThreshold)
End Sub
Empat properties berikutnya seharusnya sudah terlihat akrab. Empat Properties ini memegang informasi Position dan Delta dari Input objek yang melekat pada Aksi yang anda masukkan dan mengembalikannya ke Game1.vb class:
Public Function CurrentGesturePosition(ByVal theAction As String) As Vector2
Return GetInput(theAction).CurrentGesturePosition()
End Function
Public Function CurrentGestureDelta(ByVal theAction As String) As Vector2
Return GetInput(theAction).CurrentGestureDelta()
End Function
Public Function CurrentGesturePosition2(ByVal theAction As String) As Vector2
Return GetInput(theAction).CurrentGesturePosition2()
End Function
Public Function CurrentGestureDelta2(ByVal theAction As String) As Vector2
Return GetInput(theAction).CurrentGestureDelta2()
End Function
Dua properties yang berikutnya menunjukkan touch point yang sekarang atau data touch position berdasarkan pada Action yang anda masukkan:
Public Function CurrentTouchPoint(ByVal theAction As String) As Point
Dim currentPosition? = GetInput(theAction).CurrentTouchPosition()
If currentPosition Is Nothing Then
Return New Point(-1, -1)
End If
Return New Point(CInt(currentPosition.Value.X), CInt(currentPosition.Value.Y))
End Function
Public Function CurrentTouchPosition(ByVal theAction As String) As Vector2
Dim _currentTouchPosition? = GetInput(theAction).CurrentTouchPosition()
If _currentTouchPosition Is Nothing Then
Return New Vector2(-1, -1)
End If
Return CType(_currentTouchPosition, Vector2)
End Function
Property yang selanjutnya digunakan khususnya dengan tipe gesture Pinch. Properti ni menunjukkan Single value yang negatif atau positif yang melambangkan perubahan skala dari pinch itu sendiri (atau 0 bila tidak terjadi perubahan apapun).
Public Function CurrentGestureScaleChange(ByVal theAction As String) As Single
' Scaling is dependent on the Pinch gesture. If no input has been setup for
' Pinch then just return 0 indicating no scale change has occurred.
If Not GetInput(theAction).PinchGestureAvailable Then
Return 0
End If
' Get the current and previous locations of the two fingers
Dim currentPositionFingerOne = CurrentGesturePosition(theAction)
Dim previousPositionFingerOne = CurrentGesturePosition(theAction) - CurrentGestureDelta(theAction)
Dim currentPositionFingerTwo = CurrentGesturePosition2(theAction)
Dim previousPositionFingerTwo = CurrentGesturePosition2(theAction) - CurrentGestureDelta2(theAction)
' Figure out the distance between the current and previous locations
Dim currentDistance = Vector2.Distance(currentPositionFingerOne, currentPositionFingerTwo)
Dim previousDistance = Vector2.Distance(previousPositionFingerOne, previousPositionFingerTwo)
' Calculate the difference between the two and use that to alter the scale
Dim scaleChange = (currentDistance - previousDistance) * 0.00999999978F
Return scaleChange
End Function
sekarang anda sudah selesai berurusan dengan GameInput.vb class.
TouchIndicator.vb
TouchIndicator.vb class bukanlah sebuah keharusan dari sitem manajemen input, tetapi terdapat di sini karena class ini mengilustrasikan kegunaan yang sangat berguna. Anda akan menggunakan class ini untuk menyediakan petunjuk/penanda visual untuk user anda (atau player) mengenai dimana secara tepatnya mereka sedang menyentuh layar.
Game class yang akan anda buat nantinya pada bagian ini akan mendapatkan benefit dari TouchIndicator dan TouchIndicatorCollection class.
Mulailah dengan membuat sebuah class baru didalam namespace Inputs dan namakan TouchIndicator.vb.

Pastikan statement yang digunakan berikut ada pada bagian atas dari class file:
Imports System
Imports System.Collections.Generic
Imports Microsoft.Xna.Framework
Imports Microsoft.Xna.Framework.Graphics
Imports Microsoft.Xna.Framework.Input.Touch
Imports Microsoft.Xna.Framework.Content
Kemudian tambahkan variabel berikut ini:
Private alphaValue As Integer = 255
Public TouchID As Integer
alphaValue akan termodifikasi pada Update() routine dan juga digunakan pada Draw() routine untuk mengontrol memudarkan indikatornya masuk atau keluar.
TouchID ditetapkan didalam class constructor dan digunakan untuk menunjukkan posisi TouchLocation pada Game1.vb class.
Private touchCircleIndicatorTexture As Texture2D
Private touchCrossHairIndicatorTexture As Texture2D
Dua variabel ini digunakan untuk menyimpan gambar- gambar untuk indikator berbentuk circle atau crosshair. Mereka akan ditempatkan pada class constructor.
Private touchPositions As New List(Of Vector2)
Yang terakhir dari variabel class-level, touchPositions, mengandung sebuah daftar dari nilai Vector2 yang berhubungan dengan posisi dari suatu objek TouchLocation manapun. Sebelum membuat constructor nya, masukkan file Circle.png dan Crosshair.png pada ContentProject anda (file ada dalam sample code).
Selanjutnya, buatlah constructor tersebut untuk class ini. Constructor ini akan menerima sebuah integer touchID dan sebuah objek ContentManager, yang mana akan anda gunakan untuk meload sprites indikator menjadi dua variabel Texture2D yang anda tetapkan sebelumnya.
Public Sub New(ByVal touchID As Integer, ByVal content As ContentManager)
Me.TouchID = touchID
touchCircleIndicatorTexture = content.Load(Of Texture2D)("Circle")
touchCrossHairIndicatorTexture = content.Load(Of Texture2D)("Crosshair")
End Sub
Pada method yang berikutnya, anda akan menerima sebuah TouchCollection object dan menunjukkan informasi posisi untuk TouchLocation yang sesuai dengan variabel TouchID. Bila tak ada yang sesuai dengan ID nya, anda akan mendapatkan value null / Nothing.
Private Function TouchPosition(ByVal touchLocationState As TouchCollection) As Vector2?
Dim touchLocation As TouchLocation
If touchLocationState.FindById(TouchID, touchLocation) Then
Return touchLocation.Position
End If
Return Nothing
End Function
Berikutnya anda masukkan Update() method. Method ini menerima sebuah TouchCollection objek sebagai sebuah parameter. Update() method dan Draw() method yang akan anda buat keduanya secara singkat terakses melalui TouchIndicatorCollection class. {code}
Public Sub Update(ByVal touchLocationState As TouchCollection)
Dim currentPosition? = TouchPosition(touchLocationState)
If currentPosition Is Nothing Then
If touchPositions.Count > 0 Then
alphaValue -= 20
If alphaValue <= 0 Then
touchPositions.Clear()
alphaValue = 255
End If
End If
Else
If alphaValue <> 255 Then
touchPositions.Clear()
alphaValue = 255
End If
touchPositions.Add(CType(currentPosition, Vector2))
End If
End Sub
Bila informasi posisi tidak tersedia dari touchLocationState, posisi touch tersimpan didalam daftar touchPosition, anda secara bertahap akan mengurangi alphaValue dan akhirnya mengosongkan daftar tersebut bersamaan dengan alphaValue yang turun dibawah 0. Sebaliknya, bila TouchPosition() method menunjukkan suatu data posisional, anda akan me-reset alphaValue ke value awal dan menambahkan posisi sekarang pada daftar dari posisi touch.
Dua method yang terakhir yang harus anda masukkan ke class ini adalah Draw() dan DrawLine(). Walaupun ke dua method ini dapat digabungkan, pendekatan ini membuat code tersebut lebih bersih dan lebih tertata.
Pertama, masukkan Draw() method, memasukkan sebuah parameter SpriteBatch. Bila ada suatu item yang berada pada daftar touchPositions, aturlah posisi yang sebelumnya dan loop melalui setiap item pada daftar touchPosition. Akses DrawLine() method pada masing-masing posisi dengan alpha channel value yang spesifik untuk tingkat ketransparanan.
Public Sub Draw(ByVal batch As SpriteBatch)
If touchPositions.Count <> 0 Then
Dim previousPosition = touchPositions(0)
Dim offsetForCenteringTouchPosition As New Vector2(-25, 0)
For Each aPosition In touchPositions
DrawLine(batch,
touchCircleIndicatorTexture,
touchCrossHairIndicatorTexture,
previousPosition + offsetForCenteringTouchPosition,
aPosition + offsetForCenteringTouchPosition,
New Color(0, 0, 255, alphaValue))
previousPosition = aPosition
Next aPosition
End If
End Sub
Terakhir, masukkan DrawLine() method. Method ini mengambil parameter dari Draw() method dan mengambarkan gambar crosshair dan sebuah garis yang muncul seiring dengan anda men-drag jari anda di atas layar:
Private Sub DrawLine(ByVal batch As SpriteBatch,
ByVal lineTexture As Texture2D,
ByVal touchTexture As Texture2D,
ByVal startingPoint As Vector2,
ByVal endingPoint As Vector2,
ByVal lineColor As Color)
batch.Draw(touchTexture, startingPoint, lineColor)
Dim difference = startingPoint - endingPoint
Dim lineLength = difference.Length() / 8
For i = 0 To CInt(lineLength) - 1
batch.Draw(lineTexture, startingPoint, lineColor)
startingPoint.X -= difference.X / lineLength
startingPoint.Y -= difference.Y / lineLength
Next i
batch.Draw(touchTexture, endingPoint, lineColor)
End Sub
Anda mungkin bertanya-tanya apa yang terjadi dengan akses ke batch.Begin() dan batch.End(), yang biasanya akan membungkus batch.Draw() calls.
Dalam kasus ini, SpriteBatch tersebut sesungguhnya sedang dibuka dan ditutup lebih rendah pada tumpukan akses, sebelumnya paga Game1.vb class, yang akan anda buat sesaat lagi. Tinggal satu bagian dari sitem manajemen input yang tersisa yaitu TouchIndicatorCollection.vb class, yang akan anda tambahkan selanjutnya.
TouchIndicatorCollection.vb
Pertama, buatlah sebuah class baru pada namespace Inputs dan namakan TouchIndicatorCollection.vb.

Pastikan namespace–namespace berikut ada:
Imports System
Imports System.Collections.Generic
Imports Microsoft.Xna.Framework
Imports Microsoft.Xna.Framework.Content
Imports Microsoft.Xna.Framework.Input.Touch
Imports Microsoft.Xna.Framework.Graphics
Sekarang, masukkan variabel class-level berikut, yang memiliki sebuah daftar object TouchIndicator:
Private touchPositions As New List(Of TouchIndicator)
Hapir sama dengan TouchIndicator.vb class yang anda buat sebelumnya, class ini juga memilki Update() dan Draw() method. Keduanya diakses dari method mereka masing- masing pada Game class anda. Pada Update() method, anda mendapatkan keadaan sekarang dari touch panel dan men-loop melalui TouchCollection, yang membandingkan TouchLocationID dengan seluruh TouchIndicator ID yang tersimpan di dalam daftar touchPositions.
Bila tidak ada kesesuaian yang ditemukan, masukkan sebuah TouchIndicator objek yang baru ke daftar TouchLocations. Terakhir, anda mengakses Update() method dari masing- masing TouchIndicator objek yang tersimpan pada daftar.
Public Sub Update(ByVal gameTime As GameTime, ByVal content As ContentManager)
Dim currentTouchLocationState = TouchPanel.GetState()
For Each location In currentTouchLocationState
Dim isTouchIDAlreadyStored = False
For Each indicator In touchPositions
If location.Id = indicator.TouchID Then
isTouchIDAlreadyStored = True
Exit For
End If
Next indicator
If Not isTouchIDAlreadyStored Then
Dim indicator As New TouchIndicator(location.Id, content)
touchPositions.Add(indicator)
End If
Next location
For Each indicator In touchPositions
indicator.Update(currentTouchLocationState)
Next indicator
End Sub
Method terakhir pada class ini adalah Draw() method. Method ini men-loop melalui daftar TouchPositions dan mengakses Draw() method dari masing- masing objek TouchIndicator pada daftar.
Public Sub Draw(ByVal batch As SpriteBatch)
For Each indicator In touchPositions
indicator.Draw(batch)
Next indicator
End Sub
Okay, Anda telah membuat sesuatu yang dapat berfungsi sebagai pondasi dari banyak games, tidak peduli platform mana yang anda targetkan.
Teknik-teknik menggabungkan sistem manajemen input ini dengan state management yang akan anda pelajari akan memberikan anda suatu start awal yang menguntungkan pada project game anda yang selanjutnya.
Sekarang, mari letakkan sistem ini untuk digunakan di dalam sebuah sampel game.
Bagian selanjutnnya ini tidaklah terlalu dibutuhkan, tetapi pada game yang besar atau kompleks, adalah suatu hal yang membuat pekerjaan anda menjadi lebih sederhana dengan memiliki semua aksi diletakkan di satu tempat dan dibagi menjadi beberapa class yang terpisah. Maka walau anda tidak membutuhkannya disini, hal ini merupakan kebiasaan yang baik untuk anda dalami.
Action.vb
Buatlah sebuah class baru pada solution anda, dan namakan Action.vb

Anda tidak membutuhkan statement apapun pada file ini, jadi singkirkanlah mereka. Karena ini akan menjadi kelas statis yang mengandung hanya suatu konstanta sebagai definisi untuk aksi anda, masukkan keyword statis tersebut menuju definisi class. Berikutnya anda masukkan aksi untuk game ini.
Friend NotInheritable Class Actions
Public Const Jump As String = "Jump"
Public Const [Exit] As String = "Exit"
Public Const Up As String = "Up"
Public Const Pause As String = "Pause"
End Class
Sample game ini mengandung hanya empat buah aksi, yang dapat diaktifkan dengan berbagai macam cara. Sebuah game yang lebih besar atau lebih kompleks mungkin memiliki segudang aksi yang dapat dimunculkan. Dengan didefinisikan nya hal tersebut dalam file class yang terpisah menjaga banyak kekacauan yang tidak perlu keluar dari Game class utama anda.Mengenai Game class, itulah yang berikutnya akan anda kerjakan.
Game1.vb
Anda sudah memiliki sebuah Game1.vb class pada project anda, maka sekarang lah waktunya untuk mengerjakannya. Class ini menggunakan SpriteFont untuk menampilkan teks pada layar. Maka klik kanan Content project pada Solution Explorer anda dan masukkan sebuah Spritefont. Namakan display.spritefont.
Kemudian tambahkan juga file Pixel.png (file tersedia dalam sample code yg bisa di download)
Sekarang bukalah file Game1.vb anda dan pastikan anda memilki statement berikut di bagian atas dari file tersebut:
Imports System
Imports Microsoft.Xna.Framework
Imports Microsoft.Xna.Framework.Content
Imports Microsoft.Xna.Framework.Graphics
Imports Microsoft.Xna.Framework.Input
Imports Microsoft.Xna.Framework.Input.Touch
Berikutnya, masukkan variabel berikut pada class level. Ini akan digunakan untuk menyediakan feedback visual bahwa code input nya bekerja dengan benar.
Private font As SpriteFont
Private square As Texture2D
Private action As String = ""
Kemudian tambahkan variabel untuk Object GameInput dan TouchIndicatorCollection
Private gameInput As GameInput
Private touchIndicators As TouchIndicatorCollection
Terakhir, tambahkan definisi rectangle untuk ke empat area touch pada game anda. Rectangle-rectangle ini akan digunakan seperti tombol onscreen dalam demo.
Private JumpRectangle As New Rectangle(0, 0, 480, 100)
Private UpRectangle As New Rectangle(0, 150, 480, 100)
Private PauseRectangle As New Rectangle(0, 500, 200, 100)
Private ExitRectangle As New Rectangle(220, 500, 200, 100)
Setelah semua class-level variabel berada ditempat nya, masukkan code berikut di dalam constructor:
graphics.PreferredBackBufferWidth = 480
graphics.PreferredBackBufferHeight = 800
Ke dua baris kode ini digunakan untuk membuat game anda menggunakan mode Portrait.
Pada Initialize() method dari Game1.vb class anda, sebelum akses ke MyBase.Initialize(), masukkan baris berikut untuk menginstansiasikan GameInput.vb class dan TouchIndicatorCollection.vb class tetapkanlah game inputs:
gameInput = New GameInput
touchIndicators = New TouchIndicatorCollection
AddInputs()
VisualStudio akan sedikit mengeluh karena anda belum membuat AddInputs() method. Karena itu, masukkan code dibawah ini:
Private Sub AddInputs()
' Add keyboard, gamepad and touch inputs for Jump
gameInput.AddKeyboardInput(Actions.Jump, Keys.A, True)
gameInput.AddKeyboardInput(Actions.Jump, Keys.Space, False)
gameInput.AddTouchTapInput(Actions.Jump, JumpRectangle, False)
gameInput.AddTouchSlideInput(Actions.Jump, Input.Direction.Right, 5.0F)
' Add keyboard, gamepad and touch inputs for Pause
gameInput.AddGamePadInput(Actions.Pause, Buttons.Start, True)
gameInput.AddKeyboardInput(Actions.Pause, Keys.P, True)
gameInput.AddTouchTapInput(Actions.Pause, PauseRectangle, True)
gameInput.AddAccelerometerInput(Actions.Pause, Input.Direction.Down, 0.1F)
' Add keyboard, gamepad and touch inputs for Up
gameInput.AddGamePadInput(Actions.Up, Buttons.RightThumbstickUp, False)
gameInput.AddGamePadInput(Actions.Up, Buttons.LeftThumbstickUp, False)
gameInput.AddGamePadInput(Actions.Up, Buttons.DPadUp, False)
gameInput.AddKeyboardInput(Actions.Up, Keys.Up, False)
gameInput.AddKeyboardInput(Actions.Up, Keys.W, True)
gameInput.AddTouchTapInput(Actions.Up, UpRectangle, True)
gameInput.AddTouchSlideInput(Actions.Up, Input.Direction.Up, 5.0F)
gameInput.AddAccelerometerInput(Actions.Up, Input.Direction.Up, 0.1F)
' Add keyboard, gamepad and touch inputs for Exit
gameInput.AddGamePadInput(Actions.Exit, Buttons.Back, False)
gameInput.AddKeyboardInput(Actions.Exit, Keys.Escape, False)
gameInput.AddTouchTapInput(Actions.Exit, ExitRectangle, True)
' Add some Gestures too, just to show them off?
gameInput.AddTouchGestureInput(Actions.Jump, GestureType.VerticalDrag, JumpRectangle)
gameInput.AddTouchGestureInput(Actions.Pause, GestureType.Hold, PauseRectangle)
End Sub
Tujuan dari method ini adalah untuk memetakan berbagai aksi game ke input- input yang mengaktifkan mereka.
Anda tidak perlu mengelompokkan code anda berdasarkan aksi bila anda tidak menginginkannya, tetapi dengan melakukannya dapat membuatnya lebih teratur dan membuatnya lebih mudah untuk menemukan suatu baris yang anda cari bila anda ingin mengubah sesuatu.Lihatlah pada baris code, dan perhatikan pemetaan untuk input Keyboard dan Gamepad.
Walaupun maksud dari contoh ini adalah untuk memperlihatkan berbagai jenis platform, ingatlah bahwa beberapa Device Windows Phone 7 memilki slide-out hardware keyboard, dan code ini akan bekerja dengan cara yang bnar- benar sama pada device-device tersebut layaknya dengan keyboard biasa yang ada pada box 360 atau Windows PC.
Pada LoadContent() method dari Game1.vb class anda, masukkan dua buah baris berikut untuk meload asset-asset game anda:
font = Content.Load(Of SpriteFont)("Display")
square = Content.Load(Of Texture2D)("Pixel")
Di dalam Update() method dari Game1.vb class, masukkan blok code berikut:
gameInput.BeginUpdate()
' Allows the game to exit
If gameInput.IsPressed(Actions.Exit, PlayerIndex.One) Then
Me.Exit()
End If
If gameInput.IsPressed(Actions.Jump, PlayerIndex.One) Then
action = Actions.Jump
End If
If gameInput.IsPressed(Actions.Pause, PlayerIndex.One) Then
action = Actions.Pause
End If
If gameInput.IsPressed(Actions.Up, PlayerIndex.One) Then
action = Actions.Up
End If
touchIndicators.Update(gameTime, Content)
gameInput.EndUpdate()
Akses untuk BeginUpdate() dan EndUpdate() ada untuk mendapatkan state saat ini dari berbagai macan tipe input yang berbeda, dan juga untuk mengatur keadaan sebelumnya ke keadaan yang sekarang. Perhatikan kode yang biasanya untuk mendeteksi tombol Back telah digantikan dengan code yang dengan sederhana mengecek untuk melihat apakah ada dari Inputs yang dipetakan untuk aksi Exit telah diaktifkan. Hal ini lebih bersih dibandingkan dengan memilki begitu banyak kode yang membuat Update() method menjadi kacau.
Tiga kode blok code lainnya bekerja dengan cara yang sama. Daripada mengecek semua kemungkinan input untuk aksi yang sama dan kemudian melanjutkan ke aksi yang berikutnya, lebih baik anda diharuskan untuk mengecek hanya sekali dari setiap aksi. Method terakhir yang harus anda update adalah Draw() method. Masukkan baris dari kode berikut setelah GraphicsDevice.Clear() dan sebelum MyBase.Draw():
Empat buah blok kode yang pertama yang anda masukkan setelah memulai SpriteBatch anda menetapkan representasi visual dari touch rectangles yang anda letakkan sebelumnya. Baris yang berikutnya akan menuliskan nama dari aksi yang terdeteksi. Terakhir, touch indicator akan terpanggil setiap kali sebuah touch ter-register.
Oke, codingnya. Sekarang waktunya untuk menjalankan dan mencobanya.
Bila anda tidak memilki sebuah device windows phone 7, anda tetap dapat menjalankan dan mengetes code ini, tetapi anda tidak akan dapat mengaktifkan aksi dari Acceloremeter apapun.
Saat anda menjalankan sebuah demo pada telepon anda, seharusnya akan terlihat seperti gambar dibawah ini:
