我想制作一系列可扩展的子弹图案,以形成正方形,三角形等形状。在下面的视频中可以看到我所追求的一个例子,当收集星星时,子弹会以膨胀星:
我想制作一系列可扩展的子弹图案,以形成正方形,三角形等形状。在下面的视频中可以看到我所追求的一个例子,当收集星星时,子弹会以膨胀星:
Answers:
最简单的方法是首先设计形状,然后计算粒子的运动。在这个答案中,我将构建一个正方形,但这适用于任何形状。
首先将形状设计为围绕某个原点的相对位置。
现在,您需要计算形状将如何扩展。为此,我们只需从的位置减去位置,然后对向量进行归一化,即可计算从指向origin
每个向量的向量。。point
origin
point
vector = normalize(point.x - origin.x, point.y - origin.y)
现在,我们可以使用此向量计算点在任何时间点的位置。您可以通过计算下一个点的位置point.position += point.vector * point.velocity
。使用我们之前的观点的伪代码示例:
// 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个单位。
笔记
因此,有一个名为BulletML的项目,它是用于创建复杂粒子/项目符号模式的标记语言。几乎可以肯定,您需要将代码移植到您自己的语言,但是它可以做一些非常神奇的事情。
例如,这个老板是在BulletML for Unity3D的(经过大量修改的)扩展中完成的(该模式的作者上传了该视频,而Misery则是疯了,以及good 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秒产卵。我已经省略了蓝色和黄色的镜头,因为它们要复杂得多。
扩展中的其他模式之一(炮弹外壳)实际上是由Misery编写的,尽管我对此做了一些修改。最初,这是一种低损伤,穿透力强的射击,可以飞到很远的地方,然后爆炸成巨大的烟火表演,造成数吨的伤害。它的最大射程远高于玩家所能达到的范围,从根本上迫使玩家在短距离内进行战斗,由于the弹枪的效果(更多子弹聚集在一个小区域内),这对于其他类型的NPC单位是有利的。
通常,BulletML易于使用,并且可以完成出色的工作。项目符号可以更改方向,更改速度,生成其他模式,尽早死亡,在循环中重复收集命令,使用延迟,更改项目符号精灵图像,跟随其父代(或不跟随)……而任何不支持的功能都可以写进去。
如果您正在认真进行射击游戏,我绝对会推荐它。正如Charanor在他的回答中所提到的,您仍然需要计算坐标数学以获得所需的形状,但是BulletML之类的子弹引擎将为您提供更多的灵活性,您将花费更多的时间设计新的模式而不是弄清楚如何编码。
正如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);
}
}
}
}