ฉันจะทำให้รูปแบบสัญลักษณ์แสดงหัวข้อย่อยขยายได้อย่างไร


12

ฉันต้องการสร้างชุดของรูปแบบสัญลักษณ์แสดงหัวข้อย่อยที่มีรูปร่างเช่นสี่เหลี่ยมจตุรัสสามเหลี่ยมเป็นต้นตัวอย่างของสิ่งที่ฉันหลังจากสามารถเห็นได้ในวิดีโอต่อไปนี้ซึ่งเมื่อดวงดาวถูกรวบรวมกระสุนระเบิดในรูปของ ดาวฤกษ์ที่กำลังขยายตัว:

https://youtu.be/7JGcuTWYdvU?t=2m41s


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

1
ชื่อที่นิยมสำหรับเอฟเฟ็กต์แบบนั้นคือ "เอฟเฟกต์ของอนุภาค" ข้อความค้นหานั้นอาจช่วยคุณได้!
Cort Ammon

1
ขอบคุณฉันได้ใช้เอฟเฟกต์อนุภาคใน XNA และ libGDX มาระยะหนึ่งแล้ว แต่ไม่แน่ใจว่าจะจัดการกับเอฟเฟกต์พิเศษนี้ได้อย่างไร
lepton

1
มีคำตอบสำหรับเรื่องนี้ที่ทรงพลังอย่างเหลือเชื่อ แต่มีความซับซ้อนในการเขียนโปรแกรม และจำเป็นต้องใช้คีย์บอร์ดจริงเพื่อพิมพ์ออกมา คั่นหน้านี้ไว้เพื่ออธิบายในภายหลัง
Draco18 ไม่ไว้วางใจ SE

ที่น่าสนใจ - ฉันจะไม่มีวันได้รับผลกระทบของอนุภาคสำหรับสิ่งนี้ หรืออาจจะเป็นเพียงการอธิบายใน Unity ในขณะที่เอฟเฟกต์ของอนุภาคสามารถมี colliders (ซึ่งจะทำให้วัตถุเสียหาย) แต่ดูเหมือนว่าจะสร้างค่าใช้จ่ายมากกว่าการทำสำเนาวัตถุ
Jesse Williams

คำตอบ:


11

วิธีที่ง่ายที่สุดในการทำเช่นนี้คือการออกแบบรูปร่างก่อนแล้วคำนวณการเคลื่อนที่ของอนุภาค ในคำตอบนี้ฉันจะสร้างสี่เหลี่ยม แต่สิ่งนี้ใช้ได้กับทุกรูปร่าง

เริ่มต้นด้วยการออกแบบรูปร่างของคุณเป็นตำแหน่งสัมพัทธ์รอบจุดกำเนิดบางจุด

สี่เหลี่ยม

ตอนนี้คุณต้องคำนวณว่ารูปร่างจะขยายได้อย่างไร ในการทำเช่นนี้เราเพียงคำนวณเวกเตอร์ที่ชี้จากoriginไปยังทุก ๆpointด้วยการลบoriginตำแหน่งออกจากตำแหน่งของเราpointจากนั้นปรับเวกเตอร์ให้เป็นมาตรฐาน vector = normalize(point.x - origin.x, point.y - origin.y).

เวกเตอร์

ตอนนี้เราสามารถคำนวณตำแหน่งของจุดได้ทุกเวลาโดยใช้เวกเตอร์นี้ point.position += point.vector * point.velocityคุณคำนวณตำแหน่งต่อไปของจุดโดยการทำ ตัวอย่าง Pseudocode โดยใช้จุดก่อนหน้าของเรา:

// When you start your program you set these values.
point.position = (-3, 3); // Start position. Can be anything.
point.vector = normalize(-3, 3); // Normalized vector.
point.velocity = 3; // Can be anything.

// You do this calculation every frame.
point.position += point.vector * point.velocity;
// point.vector * point.velocity = (-3, 3)
// point.position is now (-6, 6) since (-3, 3) + (-3, 3) = (-6, 6)

การทำเช่นนี้จะย้ายจุดทั้งหมดออกไปด้านนอกที่ 3 หน่วยทุกเฟรม


หมายเหตุ

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

9
ฉันต้องการชี้ให้เห็นความเร็วของแต่ละอนุภาคควรเป็นสัดส่วนกับระยะทางจากจุดกำเนิดในเฟรมแรก (หมายถึงคำนวณเพียงครั้งเดียวไม่ใช่ต่อเฟรม) อีกวิธีหนึ่งคุณก็ไม่สามารถทำให้เวกเตอร์ทิศทางเป็นปกติได้ หากคุณไม่ทำเช่นนี้รูปร่างจะไม่ขยายเป็นเส้นตรง แต่ควรมุ่งไปสู่การกลายเป็นวงกลม (หากความเร็วทั้งหมดเท่ากัน)
แอรอน

@ Charanor ขอบคุณมากสำหรับคำอธิบาย จริง ๆ แล้วฉันเรียนวิชาคณิตศาสตร์ไม่ต่อเนื่องที่มหาวิทยาลัย แต่เมื่อไม่นานมานี้ วันนี้ฉันจะลองทำอะไรบางอย่าง
lepton

2

ดังนั้นจึงมีโครงการนี้เรียกว่าBulletMLซึ่งเป็นภาษามาร์กอัปสำหรับการสร้างรูปแบบอนุภาค / กระสุนที่ซับซ้อน คุณเกือบจะต้องย้ายรหัสไปยังภาษาของคุณเอง แต่ก็สามารถทำสิ่งที่น่าอัศจรรย์ได้

ตัวอย่างเช่นเจ้านายนี้ทำในส่วนขยาย (แก้ไขอย่างมาก) ของ BulletML สำหรับ Unity3D (ผู้เขียนรูปแบบนั้นอัปโหลดวิดีโอและความทุกข์ยากว่าเป็นบ้าและดี1 ) มันเป็นการเปลี่ยนแปลงที่ยากที่สุดของศัตรูตัวนั้นและมันแสดงให้เห็นว่า BulletML นั้นมีความสามารถที่ค่อนข้างดี (และตรวจสอบบอสอื่น ๆ ของ Misery เช่นเดียวกับWallmaster )

หรือฉันสามารถแสดงตัวอย่างนี้ซึ่งเป็นรูปแบบที่ฉันเขียนขณะทำงานเกี่ยวกับการขยายสำหรับThe Last Federationโดยใช้การแก้ไขระบบเก่าที่ไม่ค่อยเป็นมิตรกับ mod และใช้ตัวแปร AZ เพียงอักขระเดียว:

ตัวอย่างรูปแบบหัวข้อย่อย

กระสุนสีเขียวที่ทำให้วงแหวนเหล่านั้นเกิดจากลูกกระสุนที่หมุนด้วยความเร็วสูง แต่ตัวมันเองไม่มีการเคลื่อนไหว พวกเขาจัดการกับความเสียหายขนาดใหญ่ทำให้ผู้เล่นในระยะยาว จำกัด พวกเขาลงเพื่อลดความเสียหายอาวุธและอนุญาตให้ผู้พิทักษ์มือถือเพื่อก่อกวนผู้เล่น

นี่คือส่วนหนึ่งของไวยากรณ์ XML ที่สร้างลูกโป่งเหล่านี้:

<bullet_pattern name="Barrier">
    $WallShotAngle B=.3 A=90
    $WallShotAngle B=.3 A=-90
    $WallShotAngle B=.3 A=0
    $WallShotAngle B=.375 A=180
</bullet_pattern>

<var name="WallShotAngle">
    <bullet angle="[A]" speed="4000" interval_mult=".01" dumbfire="1" shot_type="GravityWavePurple">
        <wait time="[B]" />
        <change angle="0" speed="1000" time=".0001" />
        <spawn>
            <bullet_pattern>
                <bullet angle="[A]" speed="0" shot_type="CurveBarGreen" damage_mult="8">
                <wait time="12" />
                <die />
                </bullet>
            </bullet_pattern>
        </spawn>
        <die />
    </bullet>
</var>

คุณสามารถเห็นภาพ "คลื่นแรงโน้มถ่วง" สีม่วงบางภาพในสกรีนช็อตซึ่งเคลื่อนที่ได้เกือบทันทีจากแหล่งที่มา (ซึ่งหมุน) ไปที่ขอบของฟองโดยที่มันวางไข่ยิง "บาร์โค้ง" สีเขียวซึ่งอยู่ที่นั่นเป็นเวลา 12 วินาทีก่อน despawning ภาพสีน้ำเงินและสีเหลืองที่ฉันข้ามไปเนื่องจากมีความซับซ้อนมากขึ้น

หนึ่งในรูปแบบอื่น ๆ ( กระสุนปืนใหญ่ ) ในการขยายตัวถูกเขียนโดย Misery ถึงแม้ว่าฉันจะทำการดัดแปลงบางอย่าง ตอนแรกมันเป็นดาเมจต่ำยิงทะลุทะลวงออกไปในระยะไกลจากนั้นก็ระเบิดออกมาเป็นพลุขนาดใหญ่สร้างความเสียหายมากมาย ระยะสูงสุดนั้นสูงกว่าระดับที่ผู้เล่นสามารถทำได้โดยบังคับให้ผู้เล่นมีส่วนร่วมในระยะสั้นซึ่งเป็นข้อได้เปรียบสำหรับหน่วย NPC ประเภทอื่นเนื่องจากเอฟเฟกต์ของปืนลูกซอง (กระสุนกลุ่มในโซนเล็ก ๆ )

BulletML นั้นใช้งานได้ง่ายโดยทั่วไปและสามารถทำสิ่งมหัศจรรย์ได้ สัญลักษณ์แสดงหัวข้อย่อยสามารถเปลี่ยนทิศทางเปลี่ยนความเร็ววางไข่รูปแบบอื่น ๆ ตายก่อนรวบรวมคำสั่งซ้ำในวงวนใช้ความล่าช้าเปลี่ยนภาพกระสุนสไปรต์ติดตามผู้ปกครองของพวกเขา (หรือไม่) ... และอะไรก็ตามที่คุณไม่สนับสนุนเขียนลงไป

ฉันขอแนะนำอย่างแน่นอนหากคุณกำลังเล่นเกมยิงปืนร้ายแรง คุณยังคงต้องคิดคำนวณพิกัดเพื่อให้ได้รูปร่างที่ต้องการตามที่ Charanor พูดถึงในคำตอบของเขา แต่เครื่องมือกระสุนอย่าง BulletML จะให้ความยืดหยุ่นมากกว่าที่คุณจะใช้เวลาในการออกแบบรูปแบบใหม่มากกว่าการหาวิธีรหัสพวกเขา

  1. เพื่ออธิบายความทุกข์ยากที่ดีวิดีโอเหล่านั้นขัดต่อหัวหน้าชั้นกับอุปกรณ์เริ่มต้น : ไม่มีโมดูลไม่มีวัสดุสิ้นเปลืองและปืนยิงถั่วพื้นฐาน และ xe ใช้เวลาตีเพียงครั้งเดียวแม้จะมีลักษณะของการต่อสู้ที่ยืดยาว ตกลง, 9 การปะทะกับ Centrifuge (ผู้ที่ไม่ปรากฎจนกว่าชั้นสามหลังจากผู้เล่นจะมีการอัพเกรดแน่นอนทำให้เกิดความเสียหายอย่างน้อยสองเท่าเมื่อเทียบกับ)

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

@lepton เข้าใจได้โดยสิ้นเชิง นั่นเป็นการตัดสินใจให้คุณ แต่คำตอบอาจเป็นคำที่ "ดีที่สุด" สำหรับคนอื่น ฉันรู้ว่าหลังจากทำงานกับ TLF และเริ่มสร้างนักกีฬาของฉันเองฉันต้องการใช้มันเพียงเพราะมันมีประสิทธิภาพและใช้งานง่าย :)
Draco18 ไม่ไว้วางใจ SE

1

Charanor ชี้ให้เห็นคุณสามารถใช้อาร์เรย์ของคะแนนเพื่อกำหนดรูปร่างของคุณ ด้านล่างนี้เป็นตัวอย่างการทำงานของวิธีใช้รูปร่างดาวหรือรูปร่างที่กำหนดเองโดยใช้คะแนน:

package com.mygdx.gtest;

import com.badlogic.gdx.ApplicationAdapter;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.graphics.Color;
import com.badlogic.gdx.graphics.GL20;
import com.badlogic.gdx.graphics.Pixmap;
import com.badlogic.gdx.graphics.Pixmap.Format;
import com.badlogic.gdx.graphics.Texture;
import com.badlogic.gdx.graphics.g2d.SpriteBatch;
import com.badlogic.gdx.math.Vector2;
import com.badlogic.gdx.utils.Array;

public class Test extends ApplicationAdapter{

    public SpriteBatch sb;
    private StarShape ss, ssBig;

    @Override
    public void create() {
        sb = new SpriteBatch();
        Pixmap pmap = new Pixmap(2, 2,Format.RGBA8888);
        pmap.setColor(Color.WHITE);
        pmap.fill();
        ss = new StarShape(50,50,new Texture(pmap), 10, true);
        ssBig = new StarShape(250,250,new Texture(pmap), 50, false);
        pmap.dispose();

    }


    @Override
    public void render() {
        super.render();

        Gdx.gl.glClearColor(0, 0, 0, 1);
        Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);

        ss.update(Gdx.graphics.getDeltaTime());
        ssBig.update(Gdx.graphics.getDeltaTime());

        sb.begin();
            ss.draw(sb);
            ssBig.draw(sb);
        sb.end();

    }


    @Override
    public void dispose() {
        super.dispose();
    }

    private class StarShape{
        public float progress = 1f;
        public Texture bulletTex;
        public Array<Vector2> points = new Array<Vector2>();
        public Vector2 center;

        public StarShape(float x, float y, Texture tex, float initialSize, boolean mathWay){
            center = new Vector2(x,y);
            bulletTex = tex;

            if(mathWay){
                // define star shape with maths
                float alpha = (float)(2 * Math.PI) / 10; 
                float radius = initialSize;

                for(int i = 11; i != 0; i--){
                    float r = radius*(i % 2 + 1)/2;
                    float omega = alpha * i;
                    points.add(
                            new Vector2(
                                    (float)(r * Math.sin(omega)), 
                                    (float)(r * Math.cos(omega)) 
                                )
                            );
                }
            }else{
            // or define star shape manually (better for non geometric shapes etc

                //define circle
                points.add(new Vector2(-3f,0f));
                points.add(new Vector2(-2.8f,1f));
                points.add(new Vector2(-2.2f,2.2f));
                points.add(new Vector2(-1f,2.8f));
                points.add(new Vector2(0f,3f));
                points.add(new Vector2(1f,2.8f));
                points.add(new Vector2(2.2f,2.2f));
                points.add(new Vector2(2.8f,1f));
                points.add(new Vector2(3f,0f));
                points.add(new Vector2(2.8f,-1f));
                points.add(new Vector2(2.2f,-2.2f));
                points.add(new Vector2(1f,-2.8f));
                points.add(new Vector2(0f,-3f));
                points.add(new Vector2(-1f,-2.8f));
                points.add(new Vector2(-2.2f,-2.2f));
                points.add(new Vector2(-2.8f,-1f));

                // mouth
                points.add(new Vector2(-2,-1));
                points.add(new Vector2(-1,-1));
                points.add(new Vector2(0,-1));
                points.add(new Vector2(1,-1));
                points.add(new Vector2(2,-1));
                points.add(new Vector2(-1.5f,-1.1f));
                points.add(new Vector2(-1,-2));
                points.add(new Vector2(0,-2.2f));
                points.add(new Vector2(1,-2));
                points.add(new Vector2(1.5f,-1.1f));

                points.add(new Vector2(-1.5f,1.5f));
                points.add(new Vector2(1.5f,1.5f));

            }

        }

        public void update(float deltaTime){
            this.progress+= deltaTime;
        }

        public void draw(SpriteBatch sb){
            Vector2 temp = new Vector2(0,0);
            for(Vector2 point: points){
                temp.x = (point.x);
                temp.y = (point.y);
                temp.scl(progress);
                sb.draw(bulletTex,temp.x + center.x,temp.y +center.y);
            }
        }
    }
}

ขอบคุณมากสำหรับตัวอย่างฉันจะไปตรวจสอบในบ่ายวันนี้เพื่อดูว่าฉันจะสามารถเปิดใช้งานได้หรือไม่
lepton
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.