C#, 118 bytes
n=>string.Join('\n',new int.Select((_,i)=>new string('#',n)+(n%2==i%2?"#"+new string('x',n).Replace("x"," -"):"")))
-5 bytes thanks to Stone_Red from The Programmers Hangout discord
Curse you C# and your verbose string repeating shakes fist
Try it on .NETFiddle
n is the size of the spaceship,
i is the 0-indexed current line being generated.
Select is C#'s version of a
map function. When the provided predicate takes 2 arguments, the first will be the original value in the collection being enumerated, and the second will be the index of that value in the collection.
In our case we don't care about the original value, we're just using it as a shorter
for(int i = 0; i < 3; i++). Likewise we don't care about the original type, because
Select will return a collection of whatever type the provided predicate function returns. In this case the predicate function returns a string, so
Select will return an
IEnumerable<string> regardless of the fact that it's enumerating over an
int was chosen as it's the shortest standard type name in .NET.
Every line of output begins with
new string('#',n), which is C#'s way to repeat a char
n times. Then the following ternary statement handles generating guns:
(n%2==i%2?"#"+new string('x',n).Replace("x"," -"):"")
The condition here is
n%2==i%2, which is true if the parity of the size and line number match. If
n's parity matches
i's parity, it's a gun line (even values for
n will have a gun on line 0 and 2, odd values will have a gun on line 1).
Guns have one extra
#, so we start with
new string('x',n).Replace("x"," -") generates a string of
x characters, then replaces each
-, this is the golfiest way I know of to repeat a string
n times, as the
new string('#',n) method only works for repeating a single char.
IEnumerable<string> returned from
Select is passed to
string.Join('\n',...), which simply concatenates the collection into a single string, with newlines between each line.