Làm thế nào tôi có thể mở rộng hình dạng mô hình viên đạn?


12

Tôi muốn tạo ra một loạt các mẫu đạn mở rộng tạo thành các hình dạng như hình vuông, hình tam giác, v.v. Một ví dụ về những gì tôi sau có thể được nhìn thấy trong video sau đây khi các ngôi sao được thu thập các viên đạn phát nổ theo hình dạng của một mở rộng sao:

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


2
Oh đó là một câu hỏi hay. Tôi không có câu trả lời cụ thể, nhưng tôi tưởng tượng bạn có thể sử dụng một vật thể 2D, hình dạng đơn giản hoặc hình dạng đơn giản và tạo ra các viên đạn dọc theo cạnh. Tất nhiên, mẹo sẽ là cho chúng vận tốc thích hợp, cả hai hướng ra ngoài theo hình dạng của chúng và nếu bạn đang tạo ra một chiếc xe đẩy như thế này, để khiến chúng tiến về phía trước với màn hình. Rất quan tâm để xem bất kỳ câu trả lời ở đây.
Jesse Williams

1
Một tên phổ biến cho hiệu ứng loại đó là "hiệu ứng hạt." Thuật ngữ tìm kiếm đó có thể giúp bạn ra ngoài!
Cort Ammon

1
Cảm ơn, tôi đã sử dụng các hiệu ứng hạt trong XNA và libGDX khá lâu rồi, nhưng không chắc chắn làm thế nào để xử lý phong cách hiệu ứng đặc biệt này.
lepton

1
Có một câu trả lời khác cho điều này là vô cùng mạnh mẽ, nhưng rất phức tạp để lập trình. Và là cần một bàn phím thực sự để gõ. Đánh dấu này để giải thích sau.
Draco18 không còn tin tưởng SE

Thú vị - Tôi chưa bao giờ đi với hiệu ứng hạt cho thứ gì đó như thế này. Hoặc có thể đó chỉ là một phân định trong Unity. Mặc dù các hiệu ứng hạt có thể có các máy va chạm (do đó làm hỏng một vật thể), nhưng có vẻ như điều đó sẽ tạo ra nhiều chi phí hơn là chỉ đơn giản là khởi tạo các bản sao đối tượng.
Jesse Williams

Câu trả lời:


11

Cách dễ nhất để làm điều này là đầu tiên thiết kế hình dạng sau đó tính toán chuyển động của các hạt. Trong câu trả lời này tôi sẽ xây dựng một hình vuông, nhưng điều này áp dụng cho bất kỳ hình dạng nào.

Bắt đầu bằng cách thiết kế hình dạng của bạn như các vị trí tương đối xung quanh một số điểm gốc.

Quảng trường

Bây giờ bạn cần tính toán làm thế nào hình dạng sẽ mở rộng. Để làm điều này, chúng ta chỉ cần tính toán vectơ chỉ từorigin mỗi đến pointbằng cách trừ originvị trí khỏi vị trí của chúng ta pointsau đó chuẩn hóa vectơ. vector = normalize(point.x - origin.x, point.y - origin.y).

vectơ

Bây giờ chúng ta có thể tính toán vị trí của các điểm tại bất kỳ thời điểm nào bằng cách sử dụng vectơ này. Bạn tính toán vị trí tiếp theo của các điểm bằng cách làm point.position += point.vector * point.velocity. Ví dụ mã giả sử dụng điểm trước của chúng tôi:

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

Làm điều này sẽ di chuyển tất cả các điểm ra bên ngoài ở 3 đơn vị mỗi khung.


Ghi chú

  • Bạn có thể đọc lên một số toán học vector đơn giản ở đây .
  • Vị trí có thể là bất cứ điều gì miễn là tất cả các vị trí đều liên quan đến một số điểm gốc.
  • Vận tốc của tất cả các điểm phải giống nhau để đảm bảo chuyển động đều, nhưng có vận tốc khác nhau có thể cho bạn kết quả thú vị.
  • Nếu chuyển động có vẻ tắt, bạn nên kiểm tra điểm gốc. Nếu nó không ở giữa chính xác của hình dạng, hình dạng có thể mở rộng theo một cách kỳ lạ.

9
Tôi chỉ muốn chỉ ra, vận tốc của mỗi hạt phải tỷ lệ thuận với khoảng cách từ gốc trên khung đầu tiên (nghĩa là chỉ tính một lần chứ không phải trên mỗi khung). Ngoài ra, bạn chỉ có thể không bình thường hóa vector hướng. Nếu bạn không làm điều này, hình dạng sẽ không mở rộng tuyến tính, mà chuyển sang hướng trở thành một vòng tròn (nếu tất cả các vận tốc đều giống nhau.)
Aaron

@Charanor Rất cám ơn đã giải thích. Tôi thực sự đã học toán rời rạc ở trường đại học nhưng cách đây khá lâu rồi. Tôi sẽ cố gắng và thực hiện một cái gì đó ngày hôm nay.
lepton

2

Vì vậy, có dự án này ngoài kia gọi là BulletML , một ngôn ngữ đánh dấu để tạo các mẫu hạt / viên đạn phức tạp. Bạn gần như chắc chắn sẽ cần chuyển mã sang ngôn ngữ của riêng bạn, nhưng nó có thể làm một số điều thực sự tuyệt vời.

Ví dụ: ông chủ này đã được thực hiện trong một phần mở rộng (được sửa đổi nhiều) của BulletML cho Unity3D (tác giả của mẫu đó đã tải lên video đó và Misery là điên rồ, cũng như tốt 1 ). Đây là biến thể khó nhất của kẻ thù đó và nó cho thấy BulletML có khả năng khá tốt (và cũng kiểm tra một số tên trùm khác của Misery, như Wallmaster ).

Hoặc tôi có thể hiển thị ví dụ này, đây là mẫu tôi đã viết khi thực hiện mở rộng cho Liên kết cuối cùng , sử dụng bản sửa đổi cũ hơn của hệ thống ít thân thiện với mod và chỉ sử dụng các biến AZ ký tự đơn:

Ví dụ mẫu đạn

Những viên đạn màu xanh lá cây làm cho những chiếc nhẫn đó được sinh ra từ viên đạn mẹ quay với tốc độ cao, nhưng bản thân chúng không có chuyển động. Chúng gây sát thương lớn, giữ người chơi ở tầm xa hơn, hạn chế chúng hạ vũ khí sát thương thấp hơn và cho phép các hậu vệ di động quấy rối người chơi (người chơi đã thắng nếu cấu trúc không di chuyển ở giữa bị phá hủy).

Đây là một phần của cú pháp XML tạo ra các bong bóng đó:

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

Bạn có thể thấy một số bức ảnh "sóng trọng lực" màu tím trong ảnh chụp màn hình, di chuyển gần như ngay lập tức từ nguồn (quay) đến cạnh của bong bóng, sau đó nó sinh ra bức ảnh "thanh cong" màu xanh lá cây, nằm ở đó trong 12 giây trước khinh bỉ Các bức ảnh màu xanh và màu vàng tôi đã bỏ qua, vì chúng phức tạp hơn nhiều.

Một trong những mẫu khác ( đạn pháo ) trong bản mở rộng thực sự được viết bởi Misery, mặc dù tôi đã thực hiện một số sửa đổi cho nó. Ban đầu, nó là một phát bắn có lực sát thương thấp, bay ra tầm xa và sau đó phát nổ thành một màn pháo hoa khổng lồ, gây ra hàng tấn sát thương. Tầm bắn tối đa của nó cao hơn nhiều so với người chơi có thể đạt được, về cơ bản buộc người chơi phải tham gia ở tầm ngắn, đó là lợi thế cho các loại đơn vị NPC khác do hiệu ứng súng ngắn (nhiều viên đạn tập trung trong một khu vực nhỏ).

BulletML rất dễ làm việc với, nói chung, và có thể làm những điều tuyệt vời. Đạn có thể thay đổi hướng, thay đổi tốc độ, sinh ra các mẫu khác, chết sớm, lặp lại bộ sưu tập các lệnh trong một vòng lặp, sử dụng độ trễ, thay đổi hình ảnh viên đạn, theo dõi cha mẹ của chúng (hoặc không) ... Và bất cứ điều gì nó không hỗ trợ bạn có thể viết vào đó

Tôi chắc chắn sẽ khuyên bạn nếu bạn đang thực hiện một trò chơi bắn súng nghiêm túc. Bạn vẫn cần phải thực hiện phép toán tọa độ để có được các hình dạng mong muốn, như Charanor nói về câu trả lời của anh ấy, nhưng một công cụ đạn như BulletML sẽ giúp bạn linh hoạt hơn rất nhiều mà bạn sẽ dành nhiều thời gian hơn để thiết kế các mẫu mới hơn là tìm ra Làm thế nào mã họ.

  1. Để giải thích Misery tốt như thế nào, những video đó chống lại các ông chủ sàn với thiết bị khởi đầu : không có mô-đun, không có vật tư tiêu hao và game bắn đậu cơ bản. Và xe chỉ mất một đòn bất chấp bản chất kéo dài của cuộc chiến. Ok, 9 lần tấn công vào Máy ly tâm (người không xuất hiện cho đến tầng ba sau khi người chơi chắc chắn sẽ có các bản nâng cấp dẫn đến thiệt hại ít nhất gấp đôi so với).

Cảm ơn, tôi đã mơ hồ biết về BulletML, vì nó đã xuất hiện được một thời gian, nhưng nó chắc chắn quá mức cho trò chơi đơn giản của tôi, thứ chỉ thỉnh thoảng lao vào địa ngục đạn, và không phải là một game bắn súng địa ngục.
lepton

@lepton Hoàn toàn dễ hiểu. Đó là một quyết định để bạn đưa ra, nhưng câu trả lời có thể là "tốt nhất" cho người khác. Tôi biết rằng sau khi làm việc trên TLF và tiếp tục bắt đầu xây dựng game bắn súng của riêng mình, tôi muốn sử dụng nó chỉ vì nó hoạt động mạnh mẽ và dễ dàng như thế nào. :)
Draco18 không còn tin tưởng SE

1

Như Charanor đã chỉ ra, bạn có thể sử dụng một loạt các điểm để xác định hình dạng của mình và sau đó cập nhật vị trí của chúng theo thời gian. Dưới đây là một ví dụ hoạt động về cách triển khai hình dạng ngôi sao hoặc hình dạng tùy chỉnh bằng cách sử dụng các điểm:

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);
            }
        }
    }
}

Cảm ơn rất nhiều về ví dụ này, tôi sẽ kiểm tra chiều nay để xem liệu tôi có thể khởi động nó không.
lepton
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.