libGDX เขียนเกม part 4: Understand Demo Project

Phai Panda
4 min readJan 24, 2020

--

การประกาศและใช้งานตัวแปรเบื้องต้น การประกาศและใช้งานฟังก์ชันเบื้องต้น ทำความเข้าใจโค้ดตัวอย่างที่เขียนด้วยภาษา Kotlin

ความเดิมที่ผ่านมาเราทำความเข้าใจ libGDX life cycle ได้ทราบว่า core folder มีคลาส Main ที่เราจะเขียน game logic ลงไป ส่วน desktop folder มีไฟล์ DesktopMain ทำหน้าที่เรียกคลาส Main มาทำงานพร้อมกับกำหนดค่า config ให้ด้วย

การประกาศและใช้งานตัวแปร

การประกาศตัวแปรก็คือการจองหน่วยความจำ เท่านั้นเท่านี้ขนาด เกิดการใช้งานหน่วยความจำหลัก (RAM) ของเครื่อง

ภาษา Kotlin ประกาศตัวแปรอย่างนี้

ตัวแปรที่อยู่ระดับคลาสและที่อยู่ระดับเมธอดโดยทั่วไปเมื่อประกาศก็จะกำหนดค่าเริ่มต้นให้เลย Kotlin ตัดสินใจจากค่าที่กำหนดให้นั้นว่าตัวแปรใดจะมีชนิดตัวแปรเป็นอะไร ตัวอย่าง

var number = 42

เท่ากับว่าจองหน่วยความจำชื่อ number มีค่าเท่ากับ 42 มีชนิดตัวแปรเป็น integer ใช้คำว่า Int

var message = "Hello"

เท่ากับว่าจองหน่วยความจำชื่อ message มีค่าเท่ากับสตริงที่เขียนว่า Hello มีชนิดตัวแปรเป็น string ใช้คำว่า String

ที่ผ่านมา อีกสักตัวอย่าง

val config = LwjglApplicationConfiguration()

เท่ากับว่าจองหน่วยความจำชื่อ config มีค่าเป็นออบเจ็กต์ของคลาส LwjglApplicationConfiguration ดังนั้นจะมีชนิดตัวแปรเป็น LwjglApplicationConfiguration ด้วย

บ่อยครั้งเพื่อนๆจะสังเกตเห็นว่าการกำหนดค่าให้กับตัวแปรจะใช้เครื่องหมาย =

เครื่องหมาย = (เท่ากับ) เป็นตัวสื่อสารว่าค่าทางขวาจะนำไปเก็บไว้กับตัวแปรทางซ้ายของเครื่องหมาย

และมีการใช้ var และ val นำชื่อตัวแปรขณะประกาศอีกด้วย

var คือตัวแปรนั้นมีโอกาสที่จะได้รับค่าใหม่ในอัลกอริทึมที่โปรแกรมดำเนินไป

ส่วน val คือตัวแปรที่เราตั้งใจให้มันได้รับค่าเพียงครั้งเดียวตอนประกาศ การันตีว่าค่าของตัวแปรนี้จะไม่เปลี่ยนแปลงเลยตลอดเวลาที่โปรแกรมดำเนินไป

ตัวอย่าง

var apple = 4

มีแอปเปิ้ลจำนวน 4 ผล

apple = 6

และภายหลังแอปเปิ้ลถูกกำหนดค่าใหม่เป็น 6 ผล

apple = 6 + 2

และภายหลังนำมาเพิ่มอีก 2 เป็น 8 ผล

val price = 15

ให้ราคาต่อหน่วยเท่ากับ 15 และราคานี้จะไม่เปลี่ยนแปลงอีกแล้ว แต่หากพยายามให้ค่าใหม่ก็จะพบกับ error

val total = apple * price

ข้างต้นนี้ตัวแปรชื่อ total มีค่าเท่ากับ 8 คูณ 15

print("Total is $total")

และสุดท้ายพิมพ์ค่าออกมาได้ว่า

Total is 90

โดยเครื่องหมาย และ หมายถึงสตริงซึ่งสามารถแทรกตัวแปรเข้าไปได้ ด้วยการใช้เครื่องหมาย $ นำหน้าตัวแปรอีกทีหนึ่ง

การประกาศและใช้งานฟังก์ชัน

บ่อยครั้งที่เราต้องเขียนโปรแกรมที่มีความซับซ้อน อาจประกอบด้วยอัลกอริทึมที่ให้ผลลัพธ์ชนิดเดียวกันต่างกันแค่ input ที่รับเข้ามาเท่านั้น ตัวอย่างเช่น

  • อยากได้ค่าของ 2 หารด้วย 3
  • อยากได้ค่าของ 10 หารด้วย 7
  • อยากได้ค่าเศษของ 2 หารด้วย 3
  • อยากได้ค่าเศษของ 10 หารด้วย 7 เป็นต้น

สามารถนำมาสร้างเป็นฟังก์ชันได้ดังนี้

fun divide(n1: Float, n2: Float) = n1 / n2fun fractions(n1: Float, n2: Float) = n1 % n2

เวลาใช้งาน

val result1 = divide(2F, 3F)val result2 = divide(10F, 7F)val result3 = fractions(2F, 3F)val result4 = fractions(10F, 7F)

พิมพ์ค่า

println("2 divided by 3 is $result1")println("10 divided by 7 is $result2")println("fractions 2 and 3 is $result3")println("fractions 10 and 7 is $result4")

ผลลัพธ์

2 divided by 3 is 0.6666667
10 divided by 7 is 1.4285715
fractions 2 and 3 is 2.0
fractions 10 and 7 is 3.0

สำหรับ print และ println ต่างกันที่ตัวแรกจะพิมพ์ค่าเป็นสตริงแล้วจบไป ส่วนตัวที่สองจะพิมพ์ค่าเป็นสตริงแล้วขึ้นบรรทัดใหม่แถมให้

หรือฟังก์ชันใดมีมากกว่า 1 บรรทัดก็ให้ใช้เครื่องหมาย { และ } เป็นตัวระบุขอบเขต และหากต้องการส่งค่าที่เกิดจากการทำงานกลับไปยังตำแหน่งที่เรียก ก็ให้ใช้คำสั่ง return ตัวอย่าง

ฟังก์ชันคำนวณพื้นที่ของสามเหลี่ยม (Tri Angle Area)

fun getTriAngleArea(height: Float, base: Float): Float {
return 1/2F * height * base
}

เรียกใช้

val triAngleArea = getTriAngleArea(result4, result3)println("Tri Angle area of height $result4 and base $result3 is $triAngleArea")

ผลลัพธ์

Tri Angle area of height 3.0 and base 2.0 is 3.0

อยากรู้ก็ขอให้อ่านเพิ่มเติมนะครับ

Demo Project

กลับมาที่โปรเจกต์แรกเริ่มของเรา Main.kt ยังจำได้ไหม หน้าจอสีเขียวนั่นไง

ให้สีพื้นหลังเป็นสีขาวดีกว่า RGBA ก็คือ 1, 1, 1, 1

Gdx.gl.glClearColor(1F, 1F, 1F, 1F)

แล้วประกาศตัวแปรระดับคลาสเพิ่ม 2 ตัว ได้แก่

  • ชื่อ texture มีชนิดเป็นคลาส Texture เก็บค่าตำแหน่งของรูปภาพและชื่อของรูปภาพนั้น
  • ชื่อ batch มีชนิดเป็นคลาส SpriteBatch มีหน้าที่วาดรูปภาพ
package com.pros

import com.badlogic.gdx.ApplicationAdapter
import com.badlogic.gdx.Gdx
import com.badlogic.gdx.graphics.GL20
import com.badlogic.gdx.graphics.Texture
import com.badlogic.gdx.graphics.g2d.SpriteBatch

class Main: ApplicationAdapter() {
lateinit var texture: Texture
lateinit var batch: SpriteBatch
...}

โค้ดนี้มีที่แปลกตาคือ lateinit เชื่อว่ามือใหม่ไม่รู้จักแน่ มีไว้เพื่อบอกกับ Kotlin ว่า ใจเย็นก่อน เราจะยังไม่กำหนดค่าให้เธอในตอนนี้หรอกนะ ใจเย็นก่อน ค่าที่เราจะกำหนดให้เธอจะอยู่ที่อื่น

ในประดาฟังก์ชันของ Kotlin Life Cycle เราจะกำหนดค่าให้กับ 2 ตัวแปรนี้ผ่านฟังก์ชัน create (หรือจะเรียกว่า create state ก็ได้) การจองหน่วยความจำนั้นเกิดขึ้นแล้ว

override fun create() {
texture = Texture("badlogic.jpg")
batch = SpriteBatch()
}

texture ได้เก็บค่าตำแหน่งและชื่อของภาพเป็น badlogic.jpg ที่ว่าตำแหน่งเพราะมันต้องอยู่ใน folder ชื่อ assets จึงจะนำมาใช้งานได้

ส่วน batch นั้นมีค่าเป็นออบเจ็กต์ SpriteBatch มีสมบัติในการวาดลง screen

ที่ฟังก์ชัน render เพิ่มโค้ดต่อไปนี้

override fun render() {
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT)
Gdx.gl.glClearColor(1F, 1F, 1F, 1F)

batch.begin()
batch.draw(texture, 50F, 100F)
batch.end()

}

กฏในการวาดคือต้องมีจุดเริ่มต้น (begin) และสิ้นสุด (end) ครอบอยู่ระหว่างโค้ดที่ต้องการสั่งให้วาด

ในที่นี้สั่งให้วาด badlogic.jpg ซึ่งเก็บอยู่ในตัวแปร texture ณ ตำแหน่งแกน X มีค่า 50 และแกน Y มีค่า 100 โดยที่จุด (0, 0) อยู่ตรงมุมล่างซ้าย

สุดท้ายคือคืนหน่วยความจำแก่ระบบ ฟังก์ชัน dispose รับผิดชอบเรื่องนี้ (สำคัญมากเลยนะ อย่าลืมเทียว)

override fun dispose() {
texture.dispose()
batch.dispose()
}

ผลลัพธ์

Screen width & height

นอกจากนี้เรายังสามารถกำหนดความกว้างและสูงแก่ screen ได้

เปิดไฟล์ DesktopMain.kt (หรือเรียกว่า desktop launcher) ตัวอย่าง

val config = LwjglApplicationConfiguration()
config.width = 500
config.height = 300

ผลลัพธ์

ความสูงน้อยเกินไปเป็นเหตุให้รูปภาพเห็นแค่บางส่วน

ผมยังคงไม่อยากให้เนื้อหาแต่ละ part ยาวจนเกินไป เพราะจะทำให้ผู้อ่านโดยเฉพาะมือใหม่ใช้การจดจำมากกว่าปกติ อยากให้ค่อยดูไปทีละส่วน รู้ว่าใจร้อนอยากสร้างผลงานเร็วๆ แต่เชื่อผม เราควรทิ้งให้ตนเองได้คิดและจิตนาการ รวมถึงทำความเข้าใจภาษาโปรแกรมและจุดที่จะต้องวางโค้ดคำสั่งครับ

part หน้าไปดูเรื่อง sprite sheet กันครับ

อ่านต่อ

--

--

No responses yet