© 1979–2022 Vladimir Igonin
Сайт Владимира Игонина

SpaceWar

Третья игра на GMS2 – «SpaceWar». Два корабля, пульсар, гравитация и баллистика. Вышло очень динамично!

Вы играете за синий корабль и должны поразить метким (ха!) выстрелом корабль противника. Проблема в пульсаре, расположенном в центре игрового поля. Он обладает мощной гравитацией, и чем вы ближе к нему, тем она сильнее. Гравитация влияет как на траекторию снарядов, так и траекторию кораблей. Управление осуществляется курсорными клавишами.

Вверх ↑ – Тяга.

Влево ← и Вправо → – Поворот корабля вокруг своей оси.

Пробел – Выстрел.

Ссылка на загрузку игры: SpaceWar.zip

На этой игрушке я учился в «GameMaker Studio 2» работе с частицами и шейдерами. Частицы используются при отрисовке взрывов и шлейфов от снарядов. А шейдер создаёт анимацию пульсара. Дальше немного примеров кода из этого проекта.

Код игры в GMS2
Код игры в GMS2

Код обработки ввода игрока, событие Step в объекте obj_ship:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
image_index = 0;

if (keyboard_check(vk_left)) {
	image_angle += 5;
	image_index = 2;
}

if (keyboard_check(vk_right)) {
	image_angle -= 5;
	image_index = 3;
}

if (keyboard_check(vk_up)) {
	motion_add(image_angle, 0.05);
	image_index = 1;
}


	if (keyboard_check_pressed(vk_space)) {	
		if (cooldown < 1) {
			xa = x + lengthdir_x(16, image_angle);
			ya = y + lengthdir_y(16, image_angle);
			var inst = instance_create_layer(xa, ya, "Bullets", obj_bullet);
			inst.direction = image_angle;
			inst.image_angle = image_angle;
			inst.speed += speed;
			cooldown = room_speed / 3;
		}
	}
	cooldown = cooldown - 1;

with (self) {
	star_gravity();
}

move_wrap(true, true, sprite_width / 4);

Код шейдера пульсара:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
// Vertex shader

attribute vec3 in_Position;                  // (x,y,z)
attribute vec4 in_Colour;                    // (r,g,b,a)
attribute vec2 in_TextureCoord;              // (u,v)

varying vec2 v_vTexcoord;
varying vec4 v_vColour;

void main()
{
    vec4 object_space_pos = vec4( in_Position.x, in_Position.y, in_Position.z, 1.0);
    gl_Position = gm_Matrices[MATRIX_WORLD_VIEW_PROJECTION] * object_space_pos;
    
    v_vColour = in_Colour;
    v_vTexcoord = in_TextureCoord;
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
// Fragment shader

varying vec2 v_vTexcoord;
varying vec4 v_vColour;

uniform float iTime;

void main()
{
	vec2 dir = v_vTexcoord - vec2(.75);
	float dist = distance(v_vTexcoord, vec2(.25));
	vec2 offset = dir * (sin(dist * 80. - iTime*15.) + .5) / 30.;
	vec2 texCoord = v_vTexcoord + offset;
	gl_FragColor = v_vColour * texture2D( gm_BaseTexture, texCoord );
}

Без шейдера пульсар выглядит так:

Пульсар без шейдера
Пульсар без шейдера

А с шейдером так:

Расчёт гравитации пульсара:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
function star_gravity() {
	star_distance = distance_to_point(room_width/2, room_height/2);
	if (star_distance > 16) {
		star_grav = (room_width / star_distance^2);
	}
	if (instance_exists(self)) {
		star_direction = point_direction(room_width/2, room_height/2, x, y);
		motion_add(star_direction, -0.01*star_grav);
	}
}

Кстати, если не трогать управление при пролёте пульсара – корабль может выйти на круговую орбиту вокруг него.