Bagaimana saya bisa membuat bentuk pola peluru yang berkembang?

12

Saya ingin membuat serangkaian pola peluru yang berkembang yang membentuk bentuk-bentuk seperti kotak, segitiga, dll. Contoh dari apa yang saya kejar dapat dilihat dalam video berikut ini di mana ketika bintang-bintang dikumpulkan, peluru meledak dalam bentuk sebuah mengembang bintang:

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

lepton
sumber
2
Oh, itu pertanyaan yang bagus. Saya tidak punya jawaban spesifik, tapi saya bayangkan Anda bisa menggunakan objek 2D, baik bentuk sprite atau sederhana, dan menelurkan peluru di sepanjang tepi. Tentu saja, triknya akan memberi mereka kecepatan yang tepat, baik dalam bentuknya maupun jika Anda membuat scroller seperti ini, untuk membuat mereka bergerak maju dengan layar. Sangat tertarik melihat jawaban apa pun di sini.
Jesse Williams
1
Nama populer untuk efek semacam itu adalah "efek partikel." Istilah pencarian itu dapat membantu Anda!
Cort Ammon
1
Terima kasih, saya telah menggunakan efek partikel dalam XNA dan libGDX untuk waktu yang cukup lama sekarang, tetapi tidak yakin bagaimana menangani gaya efek khusus ini.
lepton
1
Ada jawaban lain untuk ini yang sangat kuat, tetapi sangat kompleks untuk diprogram. Dan perlu keyboard nyata untuk mengetik. Bookmark ini untuk penjelasan nanti.
Draco18s tidak lagi mempercayai SE
Menarik - Saya tidak akan pernah pergi dengan efek partikel untuk sesuatu seperti ini. Atau mungkin itu hanya penggambaran dalam Unity. Sementara efek partikel dapat memiliki colliders (sehingga merusak suatu objek), sepertinya itu akan menciptakan overhead yang lebih banyak daripada hanya membuat salinan objek.
Jesse Williams

Jawaban:

11

Cara termudah untuk melakukan ini adalah pertama-tama merancang bentuk kemudian menghitung pergerakan partikel. Dalam jawaban ini saya akan membangun sebuah persegi, tetapi ini berlaku untuk bentuk apa pun.

Mulailah dengan mendesain bentuk Anda sebagai posisi relatif di sekitar titik asal.

kotak

Sekarang Anda perlu menghitung bagaimana bentuk akan berkembang. Untuk melakukan ini, kita cukup menghitung vektor yang menunjuk dari originke setiap pointdengan mengurangi originposisi dari posisi kita pointkemudian menormalkan vektor. vector = normalize(point.x - origin.x, point.y - origin.y).

vektor

Kita sekarang dapat menghitung posisi titik pada titik waktu kapan saja dengan menggunakan vektor ini. Anda menghitung posisi poin selanjutnya dengan melakukan point.position += point.vector * point.velocity. Contoh kodesemu menggunakan poin kami sebelumnya:

// 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)

Melakukan ini akan memindahkan semua poin ke luar pada 3 unit setiap frame.


Catatan

  • Anda dapat membaca tentang beberapa matematika vektor sederhana di sini .
  • Posisi dapat berupa apa saja selama semua posisi relatif terhadap beberapa titik asal.
  • Kecepatan semua titik harus sama untuk memastikan pergerakan yang seragam, tetapi memiliki kecepatan yang berbeda mungkin memberi Anda hasil yang menarik.
  • Jika gerakan tampak tidak aktif, Anda harus memeriksa titik asal. Jika tidak tepat di tengah bentuknya, bentuknya mungkin akan mengembang dengan cara yang aneh.
Charanor
sumber
9
Saya hanya ingin menunjukkan, kecepatan masing-masing partikel harus sebanding dengan jarak dari titik asal pada frame pertama (artinya hanya menghitung sekali tidak per frame). Atau, Anda tidak bisa menormalkan vektor arah. Jika Anda tidak melakukan ini, bentuknya tidak akan menskala secara linier, melainkan bergerak menuju menjadi lingkaran (jika semua kecepatan adalah sama.)
Aaron
@ Charanor Terima kasih banyak atas penjelasannya. Saya sebenarnya belajar matematika diskrit di universitas tetapi beberapa waktu yang lalu sekarang. Saya akan mencoba dan mengimplementasikan sesuatu hari ini.
lepton
2

Jadi, ada proyek di luar sana yang disebut BulletML yang merupakan bahasa markup untuk membuat pola partikel / peluru yang kompleks. Anda hampir pasti perlu melakukan porting kode ke bahasa Anda sendiri, tetapi dapat melakukan beberapa hal yang sangat menakjubkan.

Sebagai contoh, bos ini dilakukan dalam ekstensi BulletML untuk Unity3D (dimodifikasi banyak) (penulis pola itu mengunggah bahwa video dan Misery gila, serta bagus 1 ). Ini variasi yang paling sulit dari musuh itu dan menunjukkan apa yang mampu dilakukan BulletML dengan baik (dan lihat juga beberapa bos Misery lainnya, Seperti Wallmaster ).

Atau saya dapat menunjukkan contoh ini, yang merupakan pola yang saya tulis saat mengerjakan perluasan untuk The Last Federation , menggunakan revisi sistem yang lebih lama yang kurang ramah-mod dan hanya menggunakan variabel AZ karakter tunggal:

Contoh pola peluru

Peluru hijau yang membuat cincin itu muncul dari peluru induk yang berputar dengan kecepatan tinggi, tetapi mereka sendiri tidak memiliki gerakan. Mereka menangani kerusakan besar-besaran, menjaga agar pemain berada pada jarak yang lebih jauh, membatasi mereka untuk menurunkan senjata yang rusak dan memungkinkan pembela bergerak untuk melecehkan pemain (pemain menang jika struktur yang tidak bergerak di tengah sana dihancurkan).

Berikut adalah sebagian dari sintaks XML yang menciptakan gelembung-gelembung itu:

<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>

Anda dapat melihat beberapa bidikan "gelombang gravitasi" ungu di tangkapan layar, yang bergerak hampir secara instan dari sumber (yang berotasi) ke tepi gelembung, di mana ia menghasilkan bidikan "bilah melengkung" berwarna hijau, yang duduk di sana selama 12 detik sebelum melecehkan. Tembakan biru dan kuning yang saya hilangkan, karena jauh lebih rumit.

Salah satu pola lain ( peluru artileri ) dalam ekspansi sebenarnya ditulis oleh Misery, meskipun saya membuat beberapa modifikasi. Awalnya ini adalah tembakan menembus rendah yang menembus ke jarak jauh dan kemudian meledak menjadi tampilan kembang api besar, menghasilkan banyak kerusakan. Kisaran maksnya jauh lebih tinggi daripada yang bisa dicapai pemain, pada dasarnya memaksa pemain untuk terlibat dalam jarak pendek, yang menguntungkan untuk jenis unit NPC lain karena efek shotgun (lebih banyak peluru yang dikelompokkan di zona kecil).

BulletML mudah digunakan, secara umum, dan dapat melakukan hal-hal menakjubkan. Peluru dapat mengubah arah, mengubah kecepatan, menelurkan pola lain, mati lebih awal, mengulangi kumpulan perintah dalam satu lingkaran, menggunakan penundaan, mengubah gambar spet peluru, mengikuti induknya (atau tidak) ... Dan apa pun yang tidak mendukung Anda dapat tulis ke dalamnya.

Saya pasti akan merekomendasikan itu jika Anda melakukan game shoot up serius. Anda masih perlu mengerjakan matematika koordinat untuk mendapatkan bentuk yang diinginkan, seperti yang dibicarakan Charanor dalam jawabannya, tetapi mesin peluru seperti BulletML akan memberi Anda jauh lebih banyak fleksibilitas sehingga Anda akan menghabiskan lebih banyak waktu merancang pola-pola baru daripada mencari tahu bagaimana kode mereka.

  1. Untuk menjelaskan betapa bagusnya Misery, video-video itu melawan bos lantai dengan peralatan pemula : tidak ada modul, tidak ada bahan habis pakai, dan penembak kacang polong dasar. Dan xe hanya mengambil satu pukulan meskipun pertarungan sifatnya memanjang. Ok, 9 hits melawan Centrifuge (yang tidak muncul sampai lantai tiga setelah pemain pasti akan memiliki peningkatan yang menghasilkan setidaknya dua kali lipat kerusakan secara komparatif).
Draco tidak lagi percaya pada SE
sumber
Terima kasih, saya samar-samar menyadari BulletML, karena sudah ada untuk sementara waktu, tapi itu pasti berlebihan untuk permainan sederhana saya, yang hanya sesekali berkecimpung dalam neraka-peluru, dan bukan penembak peluru-neraka sendiri.
lepton
@ lepton Sangat bisa dimengerti. Itu keputusan yang harus Anda buat, tetapi jawabannya mungkin yang "terbaik" untuk orang lain. Saya tahu bahwa setelah bekerja pada TLF dan mulai membangun penembak saya sendiri, saya ingin menggunakannya hanya karena betapa kuat dan mudahnya untuk bekerja dengannya. :)
Draco18s tidak lagi mempercayai SE
1

Seperti yang ditunjukkan oleh Charanor, Anda dapat menggunakan berbagai titik untuk menentukan bentuk Anda dan kemudian memperbarui posisi mereka dari waktu ke waktu. Di bawah ini adalah contoh kerja bagaimana menerapkan bentuk bintang atau bentuk khusus menggunakan poin:

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);
            }
        }
    }
}
Empat
sumber
Terima kasih banyak untuk contohnya, saya akan memeriksanya sore ini untuk melihat apakah saya bisa menjalankannya.
lepton