irpg Community

Full Version: [Ren'Py] ระบบต่อสู้จากเกม Guardian Tales - The Behind of Light
You're currently viewing a stripped down version of our content. View the full version with proper formatting.
;3

สวัสดีครับทุกท่าน พอดีมีผู้สนใจวิธีการทำระบบสู้ในเกม Guardian Tales - The Behind of Light แล้วระบบก็ไม่ได้ยากอะไร ผมก็เลยจะมาอธิบายวิธีเขียนให้ทุกท่านที่สนใจอ่านกันครับ

แปะมู้เกมกันเสียเล็กน้อย http://irpg.in.th/thread-1642.html Y me gusta mucho

ขอออกตัวก่อนว่าอันที่จริงผมไม่ได้คิดเองหมด ผมประยุกต์เอาเสียมากกว่า ทุกท่านที่ได้ศึกษา Renpy มาคงได้เข้าไปศึกษาที่เว็บ thaigraph กันใช่ไหมครับ ผมก็เอามาจากที่นั้นแหละ แหะๆ ยังไงก็ขอขอบคุณท่าน NOOKFUFU2 จาก thaigraph ที่มีบทความดีๆ ให้ผมได้ศึกษาครับ ;w;

ช่วงที่พัฒนาขึ้นมานั้น ผมมีเวลาสร้างเกมจำกัดอาจจะเขียนระบบไว้ไม่ดีนัก ทุกท่านก็ลองเอาไปประยุกต์ให้ดีขึ้นแล้วกันครับ แมวร้อง

พูดเยอะไปและ เข้าเรื่องดีกว่า. . . อาโน. . พูดเรื่องไรก่อนดีอ่ะ // โดนถีบ Sparta #1


หลอดพลังของตัวละคร
หลอดพลังของทั้งของตัวเอกและของมอน ผมประยุกต์มาจากบทความนี้ครับ วิธีทำ label Fight RPG

แต่ในเกมผมจะเอาแค่หลอดพลังเท่านั้น ก็เอาแต่ ui.bar มาใช้ครับ

Code:
init:
    python hide:
        def score_honor():
            if show_score:
                ui.bar(max_score_honor, score_honor,
                xmaximum=312,
                ymaximum=35,
                left_bar=Frame("honorgate_full.png", 0, 0),
                right_bar=Frame("honorgate_empty.png", 0, 0),
                thumb=None,
                thumb_shadow=None)
        config.overlay_functions.append(score_honor)
        
        def mon_hp():
            if show_mon:
                ui.bar(mon_max_hp, mon_hp,
                xmaximum=312,
                ymaximum=21,
                left_bar=Frame("mongate_full.png", 0, 0),
                right_bar=Frame("mongate_empty.png", 0, 0),
                thumb=None,
                thumb_shadow=None)
        config.overlay_functions.append(mon_hp)

นำ code ด้านบน วางไว้ในไฟล์ .rpy ไฟล์ใดก็ได้ แต่ต้องไม่อยู่ภายใน label screen หรือ init python ใดๆ ส่วนของผมวางไว้ล่างสุดของไฟล์ options.rpy ส่วนรูปหลอดพลังให้หาหรือสร้างเอาเองนะครับ

ui.bar() เป็นฟังก์ชันสร้าง bar ของ Renpy รายละเอียด คลิ๊ก

และมีตัวแปรควบคุมการซ่อน/แสดง หลอดพลังด้วย show_score, show_mon

วิธีใช้
ที่ไฟล์ script.rpy ประการตัวแปร max_hp และ hp ณ ปัจจุบัน สำหรับใช้ใน ui.bar เอาไว้บนสุดของไฟล์ หรือที่เดียวกับตัวแปรพวกตัวละคร(Character) และตัวแปร show_score, show_mon เป็น false เพื่อซ่อนไว้ ไม่ให้เห็นตั้งแต่เริ่มเกม (เวลาแสดงก็แค่เขียน $ show_score = True เวลาซ่อนก็เขียน $ show_score = False)

Code:
$ show_score = False
$ show_mon = False
$ max_score_honor = 100
$ score_honor = 0
$ mon_max_hp = 100
$ mon_hp = 0

จะลดพลังของมอน ก็เขียน $ mon_hp -= 5 หรือจะเพิ่มพลังก็เขียน $ mon_hp += 5 ลงไป ($ mon_hp -= 5 กับ $ mon_hp = $ mon_hp - 5 มีความหมายเดียวกัน)
*เกมของผมพระเอกไม่ได้มีหลอดพลัง แต่เป็นแต้มเพิ่มไปเรื่อยๆ จนถึง ค่า max


ระบบสู้
ตัวอย่าง code ระบบสู้ภายในเกม พร้อมเขียนอธิบายไว้ในบรรทัด

Code:
$ show_score = True
    $ show_mon = True    
    $ mon_max_hp = 100  # เลือดทั้งหมดของมอน
    $ mon_hp = 100 # เลือด ณ ปัจจุบันของมอน
    $ actor_attack_point  = 1.0 # พลังโจมตีของตัวเอก
    $ actor_cri_point  = 2.0 # พลังโจมตีติดคริของตัวเอก
    $ mon_attack_point  = 5 # พลังโจมตีของมอน
    $ mon_cri_point  = 9 # พลังโจมตีติดคริของมอน
    $ hit = False
    $ miss = False
    
    speaker "FIGHT !!"  # โชว์ข้อความก่อนเข้าลูปสู้
    
    while mon_hp > 0:  # วนลูปไปเรื่อยๆ จนกว่าพลังมอนจะเหลือ 0
        
        $ show_score = False # ซ่อนหลอดพลังไว้หรือไม่อยากซ่อนก็เอาออกไป
        
        if miss: # อันนี้เขียนเงื่อนไขดักไว้กรณีเรากดปุ่ม HIT ไม่ทันหรือกดไม่โดน
                call expression renpy.random.choice(["mon_hit", "mon_cri"])
                # call expression เป็นการใช้เรียกใช้เหตุการณ์ ซึ่งจะไม่เหมือน jump ตรงที่หลังจากจบเหตุการณ์ที่เรียกมาใช้แล้ว จะกลับมารันเหตุการณ์เดิมต่อไป ซึ่งถ้าเป็น jump พอไปอีกเหตุการณ์หนึ่ง ก็จะจบเกมทันที
                # renpy.random.choice() ฟังก์ชั่นแรนดอมของ Renpy
                $ miss = False
        
        $ hit = False
        show screen btnHit(renpy.random.randint(1, 10))
        # เข้า screen btnHit()
        # renpy.random.randint() เป็นฟังก์ชั่นแรนดอมตัวเลขของ Renpy ในที่นี้แรนดอมเลข 1 ถึง 10
        
        show wyvern_pic at center
        with Pause(1.0) # หยุดรอให้เวลาเรากดปุ่ม Hit ที่นี่
        
        hide screen btnHit
        
        if hit == False: # เข้าเงื่อนไขถ้าผู้เล่นกด Hit ไม่ทันหรือกดไม่โดน
            play sound "sound/dragonsnarl.mp3"
            $ show_score = True
            wyvern "! ! ! ! ! ! ! !"
            stop sound fadeout 0.5            
            $ miss = True
    
    # End while    
    $ show_score = True  
    wyvern ". . . . . . . . . . . . . . ."


การทำปุ่ม Hit
ปุ่ม Hit หรือ Critical ผมเขียนคล้ายฟังก์ชั่นเอาไว้ ให้ง่ายต่อการใช้

Code:
screen btnHit(damage):    
    if damage <= 7: # เงื่อนไขถ้าน้อยกว่าหรือเท่ากับ 7 ให้โชว์ปุ่ม Hit
        hbox:
            area (renpy.random.randint(10, 650), renpy.random.randint(10, 300), 1.0, 75)
            imagebutton:
                    idle "hit_damage.png"
                    hover "hit_damage_hover.png"
                    action ui.callsinnewcontext("actor_hit")
    else:
        hbox:
            area (renpy.random.randint(15, 650), renpy.random.randint(10, 300), 1.0, 75)
            imagebutton:
                    idle "menu/cri_damage.png"
                    hover "menu/cri_damage_hover.png"            
                    action ui.callsinnewcontext("actor_cri")  
                
label actor_hit:    
    show bg_blank with wflash
    with sshake
    play sound "sound/attack3.ogg"
    $ mon_hp = mon_hp - actor_attack_point
    $ score_honor += actor_attack_point
    $ hit = True
    return

label actor_cri:
    show bg_blank with wflash
    with sshake
    play sound "sound/battle3.ogg"
    $ mon_hp = mon_hp - actor_cri_point
    $ score_honor += actor_cri_point
    $ hit = True
    return

ui.callsinnewcontext() เอาไว้เรียกใช้ฟังก์ชั่น(เป็น Label) อีกทีหนึ่ง รายละเอียด คลิ๊ก

ส่วน code การโจมตีของมอน ก็เขียนเป็น label แยกไว้แบบตีธรรมดากับตีคริ ตรงนี้ผมไม่อธิบายแล้วกันฮะ เพราะน่าจะเข้าใจกัน

Code:
label mon_hit:
    show bg_blank with rflash
    with sshake
    play sound "sound/damage4.ogg"
    if score_honor >= 1:
        $ score_honor = score_honor - mon_attack_point  
    else:
        $ score_honor = 1  
    $ hit = True
    return

label mon_cri:
    show bg_blank with rflash
    with sshake
    play sound "sound/battle1.ogg"
    if score_honor >= 1:
        $ score_honor = score_honor - mon_cri_point
    else:
        $ score_honor = 1
    $ hit = True
    return

การเขียนระบบสู้ของผมก็มีเพียงเท่านี้ครับ ลองประยุกต์กันดูนะครับ ตายแปป. .
ขอบคุณมากครับท่านฝัน