sidenote

Archívum
A(z) „játék” kategória bejegyzései

As a follow-up for my last post hereby I present a Creeper (right) in (Lua)LaTeX.

Creeper Creeper

Image source (left): File:Creeper.png – Minecraft Wiki

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
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
% Creeper
% Author: István Szántai (szantaii)
\documentclass{article}

\usepackage{luacode}

\usepackage{xcolor}

\usepackage{tikz}
\usepackage{tikz-3dplot}

\usepackage[active, tightpage]{preview}
\PreviewEnvironment{tikzpicture}
\setlength{\PreviewBorder}{1cm}

\definecolor{creeper_white}{HTML}{9AD78E}
\definecolor{creeper_lightgreen}{HTML}{5ED04C}
\definecolor{creeper_green}{HTML}{00A500}
\definecolor{creeper_darkgreen}{HTML}{255522}

\begin{luacode*}
    function draw_coordinate_system()
        tex.sprint("\\draw[white!50!gray,thick,->] (0,0,0) -- " ..
            "(3,0,0) node[text=white!50!gray,anchor=north east]{$x$};")
        tex.sprint("\\draw[white!50!gray,thick,->] (0,0,0) -- " ..
            "(0,3,0) node[text=white!50!gray,anchor=west]{$y$};")
        tex.sprint("\\draw[white!50!gray,thick,->] (0,0,0) -- " ..
            "(0,0,3) node[text=white!50!gray,anchor=south]{$z$};")
    end
   
    function matrix_scalar_multiplication(matrix, scalar)
        local rows = #matrix
        local cols = #matrix[1]
        local tmp_matrix = {}
       
        for i = 1, rows do
            tmp_matrix[i] = {}
            for j = 1, cols do
                tmp_matrix[i][j] = matrix[i][j] * scalar
            end
        end
       
        return tmp_matrix
    end
   
    function shift_coordinates(matrix, array)
        local matrix_rows = #matrix
        local matrix_cols = #matrix[1]
        local array_length = #array
        local tmp_matrix = {}
       
        if matrix_cols == array_length then
            for i = 1, matrix_rows do
                tmp_matrix[i] = {}
                for j = 1, matrix_cols do
                    tmp_matrix[i][j] = matrix[i][j] + array[j]
                end
            end
           
            return tmp_matrix
        else
            return nil
        end
    end
   
    function tikzcube(x, y, z, color)
        local side_1 = {{1, 1, -1},
            {-1, 1, -1},
            {-1, -1, -1},
            {1, -1, -1}}
        local side_2 = {{-1, 1, -1},
            {-1, 1, 1},
            {-1, -1, 1},
            {-1, -1, -1}}
        local side_3 = {{-1, -1, -1},
            {1, -1, -1},
            {1, -1, 1},
            {-1, -1, 1}}
        local side_4 = {{1, 1, -1},
            {-1, 1, -1},
            {-1, 1, 1},
            {1, 1, 1}}
        local side_5 = {{1, -1, -1},
            {1, 1, -1},
            {1, 1, 1},
            {1, -1, 1}}
        local side_6 = {{1, 1, 1},
            {-1, 1, 1},
            {-1, -1, 1},
            {1, -1, 1}}
        local cube_sides = {side_1, side_2, side_3, side_4, side_5, side_6}
        local tex_cube = ""
       
        for i = 1, #cube_sides do
            tex_cube = tex_cube .. "\\draw[ultra thin, fill=" .. color .. "] "
           
            local current_side = matrix_scalar_multiplication(cube_sides[i], 0.5)
            current_side = shift_coordinates(current_side, {x, y, z})
           
            local current_side_rows = #current_side
            local current_side_cols = #current_side[1]
           
            for j = 1, current_side_rows do
                for k = 1, current_side_cols do
                    if k == 1 then
                        tex_cube = tex_cube .. "("
                    end
                   
                    tex_cube = tex_cube .. current_side[j][k]
                   
                    if k ~= current_side_cols then
                        tex_cube = tex_cube .. ", "
                    else
                        tex_cube = tex_cube .. ") -- "
                    end
                end
            end
           
            tex_cube = tex_cube .. "cycle;"
           
        end
       
        tex.sprint(tex_cube)
    end
   
    function draw_head(x_pos, y_pos, z_pos, colors_array)
        for x = x_pos, x_pos + 7, 1 do
            for y = y_pos, y_pos + 7, 1 do
                for z = z_pos, z_pos + 7, 1 do
                    if x == x_pos or x == x_pos + 7 or
                        y == y_pos or y == y_pos + 7 or
                        z == z_pos or z == z_pos + 7 then
                       
                        local color_index = math.random(1, #colors_array - 1)
                        tikzcube(x, y, z, colors_array[color_index])
                       
                        if x == x_pos + 7 and
                            (z == z_pos + 4 and
                            (y == y_pos + 2 or y == y_pos + 5)) or
                            (z == z_pos + 2 and
                            (y == y_pos + 3 or y == y_pos + 4)) or
                            (z == z_pos + 1 and
                            (y > 1 and y < 6)) then
                           
                            tikzcube(x, y, z, "black")
                        end
                       
                        if x == x_pos + 7 and
                            ((z == z_pos + 5 and
                            ((y > y_pos and y < y_pos + 3) or
                            (y > y_pos + 4 and y < y_pos + 7))) or
                            (z == z_pos + 4 and
                            (y == y_pos + 1 or y == y_pos + 6)) or
                            (z == z_pos + 3 and
                            (y == y_pos + 3 or y == y_pos + 4)) or
                            (z == z_pos + 2 and
                            (y == y_pos + 2 or y == y_pos + 5)) or
                            (z == z_pos and
                            (y == y_pos + 2 or y == y_pos + 5))) then
                           
                            tikzcube(x, y, z, colors_array[#colors_array])
                        end
                    end
                end
            end
        end
    end
   
    function draw_leg(x_pos, y_pos, z_pos, colors_array)
        for x = x_pos, x_pos + 3, 1 do
            for y = y_pos, y_pos + 7, 1 do
                for z = z_pos, z_pos + 5, 1 do
                    if x == x_pos or x == x_pos + 3 or
                        y == y_pos or y == y_pos + 7 or
                        z == z_pos or z == z_pos + 5 then
                       
                        local color_index = math.random(1, #colors_array - 1)
                        tikzcube(x, y, z, colors_array[color_index])
                       
                        if x == x_pos + 3 and
                            ((z == z_pos + 1 and
                            (y == y_pos or y == y_pos + 2 or
                            y == y_pos + 4 or y == y_pos + 6)) or
                            (z == z_pos and
                            (y == y_pos + 1 or y == y_pos + 3 or
                            y == y_pos + 5 or y == y_pos + 7))) then
                           
                            tikzcube(x, y, z, colors_array[#colors_array])
                        end
                       
                        if x == x_pos + 3 and
                            ((z == z_pos + 1 and
                            (y == y_pos + 1 or y == y_pos + 3 or
                            y == y_pos + 5 or y == y_pos + 7)) or
                            (z == z_pos and
                            (y == y_pos or y == y_pos + 2 or
                            y == y_pos + 4 or y == y_pos + 6))) then
                           
                            tikzcube(x, y, z, "black")
                        end
                    end
                end
            end
        end
    end
   
    function draw_bodypart(x_pos, y_pos, z_pos, x_length, y_length, z_length, colors_array)
        local color
        for x = x_pos, x_pos + x_length - 1, 1 do
            for y = y_pos, y_pos + y_length - 1, 1 do
                for z = z_pos, z_pos + z_length - 1, 1 do
                    if x == x_pos or x == x_pos + x_length - 1 or
                        y == y_pos or y == y_pos + y_length - 1 or
                        z == z_pos or z == z_pos + z_length - 1 then
                       
                        local color_index = math.random(1, #colors_array)
                        tikzcube(x, y, z, colors_array[color_index])
                    end
                end
            end
        end
    end
   
    function draw_creeper(x_rotation, z_rotation)
        local creeper_colors = {"creeper_white",
            "creeper_lightgreen",
            "creeper_green",
            "creeper_darkgreen"}
       
        tex.sprint("\\tdplotsetmaincoords{" .. x_rotation .. "}{" .. z_rotation .. "}")
        tex.sprint("\\begin{tikzpicture}[tdplot_main_coords]")
       
        math.randomseed(os.time())
       
        draw_leg(-2, 0, -18, creeper_colors)
        draw_leg(6, 0, -18, creeper_colors)
        draw_bodypart(2, 0, -12, 4, 8, 12, creeper_colors)
        draw_head(0, 0, 0, creeper_colors)
        -- draw_coordinate_system()
       
        tex.sprint("\\end{tikzpicture}")
    end
\end{luacode*}

\begin{document}
\luadirect{draw_creeper(66, 135)}
\end{document}
Megosztás, like stb.

In the last couple of months I’ve watched some videos of Achievement Hunter’s Let’s Play Minecraft videos where were some encounters with Endermen. I was really fascinated by these creatures since they can teleport, demand respect, mysterious, etc.

I have been “playing” with LaTeX, especially with LuaTeX, recently, and I wanted to make a 3D-like picture. So I have chosen tikz‑3dplot and LuaTeX to draw an Enderman. (I think this is totally drawable with pure TikZ (syntax), therefore compilable with pdflatex, etc., but I found making this using LuaTeX much more simple.)

Enderman Enderman

Image source (left): File:Enderman normal.png – Minecraft Wiki

My drawing (right) is not accurate by many aspects, but I’ve achieved what I wanted.

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
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
% Enderman
% Author: István Szántai (szantaii)
\documentclass{article}

\usepackage{luacode}

\usepackage{xcolor}

\usepackage{tikz}
\usepackage{tikz-3dplot}

\usepackage[active, tightpage]{preview}
\PreviewEnvironment{tikzpicture}
\setlength{\PreviewBorder}{1cm}

\definecolor{endermanblack}{HTML}{000000}
\definecolor{endermangray}{HTML}{161616}
%\definecolor{endermanpurple}{HTML}{CC00FA}
%\definecolor{endermanlightpurple}{HTML}{E079FA}
\definecolor{endermanpurple}{HTML}{FF9EFF}
\definecolor{endermanlightpurple}{HTML}{FFC9FF}
\definecolor{particlecolor}{HTML}{DF4AF8}

\begin{luacode*}
    function draw_coordinate_system()
        tex.sprint("\\draw[white!50!gray,thick,->] (0,0,0) -- " ..
            "(3,0,0) node[text=white!50!gray,anchor=north east]{$x$};")
        tex.sprint("\\draw[white!50!gray,thick,->] (0,0,0) -- " ..
            "(0,3,0) node[text=white!50!gray,anchor=west]{$y$};")
        tex.sprint("\\draw[white!50!gray,thick,->] (0,0,0) -- " ..
            "(0,0,3) node[text=white!50!gray,anchor=south]{$z$};")
    end
   
    function tikzcube(x, y, z, color)
        --[[
        \draw[fill=red] (0.5, 0.5, -0.5) -- (-0.5, 0.5, -0.5) -- (-0.5, -0.5, -0.5) -- (0.5, -0.5, -0.5) -- cycle;
        \draw[fill=red] (-0.5, 0.5, -0.5) -- (-0.5, 0.5, 0.5) -- (-0.5, -0.5, 0.5) -- (-0.5, -0.5, -0.5) -- cycle;
        \draw[fill=red] (-0.5, -0.5, -0.5) -- (0.5, -0.5, -0.5) -- (0.5, -0.5, 0.5) -- (-0.5, -0.5, 0.5) -- cycle;
        \draw[fill=red] (0.5, 0.5, -0.5) -- (-0.5, 0.5, -0.5) -- (-0.5, 0.5, 0.5) -- (0.5, 0.5, 0.5) -- cycle;
        \draw[fill=red] (0.5, -0.5, -0.5) -- (0.5, 0.5, -0.5) -- (0.5, 0.5, 0.5) -- (0.5, -0.5, 0.5) -- cycle;
        \draw[fill=red] (0.5, 0.5, 0.5) -- (-0.5, 0.5, 0.5) -- (-0.5, -0.5, 0.5) -- (0.5, -0.5, 0.5) -- cycle;
        ]]

        local cube = ""
       
        cube = cube .. "\\draw[ultra thin, fill=" .. color .. "]" ..
            "(0.5 + " .. x .. ", 0.5 + " .. y .. ", -0.5 + " .. z .. ") -- " ..
            "(-0.5 + " .. x .. ", 0.5 + " .. y .. ", -0.5 + " .. z .. ") -- " ..
            "(-0.5 + " .. x .. ", -0.5 + " .. y .. ", -0.5 + " .. z .. ") -- " ..
            "(0.5 + " .. x .. ", -0.5 + " .. y .. ", -0.5 + " .. z .. ") -- cycle;"
        cube = cube .. "\\draw[ultra thin, fill=" .. color .. "]" ..
            "(-0.5 + " .. x .. ", 0.5 + " .. y .. ", -0.5 + " .. z .. ") -- " ..
            "(-0.5 + " .. x .. ", 0.5 + " .. y .. ", 0.5 + " .. z .. ") -- " ..
            "(-0.5 + " .. x .. ", -0.5 + " .. y .. ", 0.5 + " .. z .. ") -- " ..
            "(-0.5 + " .. x .. ", -0.5 + " .. y .. ", -0.5 + " .. z .. ") -- cycle;"
        cube = cube .. "\\draw[ultra thin, fill=" .. color .. "]" ..
            "(-0.5 + " .. x .. ", -0.5 + " .. y .. ", -0.5 + " .. z .. ") -- " ..
            "(0.5 + " .. x .. ", -0.5 + " .. y .. ", -0.5 + " .. z .. ") -- " ..
            "(0.5 + " .. x .. ", -0.5 + " .. y .. ", 0.5 + " .. z .. ") -- " ..
            "(-0.5 + " .. x .. ", -0.5 + " .. y .. ", 0.5 + " .. z .. ") -- cycle;"
        cube = cube .. "\\draw[ultra thin, fill=" .. color .. "]" ..
            "(0.5 + " .. x .. ", 0.5 + " .. y .. ", -0.5 + " .. z .. ") -- " ..
            "(-0.5 + " .. x .. ", 0.5 + " .. y .. ", -0.5 + " .. z .. ") -- " ..
            "(-0.5 + " .. x .. ", 0.5 + " .. y .. ", 0.5 + " .. z .. ") -- " ..
            "(0.5 + " .. x .. ", 0.5 + " .. y .. ", 0.5 + " .. z .. ") -- cycle;"
        cube = cube .. "\\draw[ultra thin, fill=" .. color .. "]" ..
            "(0.5 + " .. x .. ", -0.5 + " .. y .. ", -0.5 + " .. z .. ") -- " ..
            "(0.5 + " .. x .. ", 0.5 + " .. y .. ", -0.5 + " .. z .. ") -- " ..
            "(0.5 + " .. x .. ", 0.5 + " .. y .. ", 0.5 + " .. z .. ") -- " ..
            "(0.5 + " .. x .. ", -0.5 + " .. y .. ", 0.5 + " .. z .. ") -- cycle;"
        cube = cube .. "\\draw[ultra thin, fill=" .. color .. "]" ..
            "(0.5 + " .. x .. ", 0.5 + " .. y .. ", 0.5 + " .. z .. ") -- " ..
            "(-0.5 + " .. x .. ", 0.5 + " .. y .. ", 0.5 + " .. z .. ") -- " ..
            "(-0.5 + " .. x .. ", -0.5 + " .. y .. ", 0.5 + " .. z .. ") -- " ..
            "(0.5 + " .. x .. ", -0.5 + " .. y .. ", 0.5 + " .. z .. ") -- cycle;"
       
        tex.sprint(cube)
    end
   
    function draw_head(x_pos, y_pos, z_pos)
        local color
        for x = x_pos, x_pos + 7, 1 do
            for y = y_pos, y_pos + 7, 1 do
                for z = z_pos, z_pos + 6, 1 do
                    if (x == x_pos or x == x_pos + 7 or
                        y == y_pos or y == y_pos + 7 or
                        z == z_pos or z == z_pos + 6) and
                        not (x == x_pos + 7 and y > y_pos and y < y_pos + 7 and z == z_pos) then
                       
                        if x == x_pos + 7 and
                            (y == y_pos or y == y_pos + 2 or
                            y == y_pos + 5 or y == y_pos + 7) and
                            z == z_pos + 2 then
                           
                            tikzcube(x, y, z, "endermanlightpurple")
                        elseif x == x_pos + 7 and
                            (y == y_pos + 1 or y == y_pos + 6) and
                            z == z_pos + 2 then
                           
                            tikzcube(x, y, z, "endermanpurple")
                        else
                            if math.random(0, 8) < 6 then
                                color = "endermangray"
                            else
                                color = "endermanblack"
                            end
                            tikzcube(x, y, z, color)
                        end
                    end
                end
            end
        end
    end
   
    function draw_bodypart(x_pos, y_pos, z_pos, x_length, y_length, z_length)
        local color
        for x = x_pos, x_pos + x_length - 1, 1 do
            for y = y_pos, y_pos + y_length - 1, 1 do
                for z = z_pos, z_pos + z_length - 1, 1 do
                    if x == x_pos or x == x_pos + x_length - 1 or
                        y == y_pos or y == y_pos + y_length - 1 or
                        z == z_pos or z == z_pos + z_length - 1 then
                       
                        if math.random(0, 8) < 6 then
                            color = "endermangray"
                        else
                            color = "endermanblack"
                        end
                        tikzcube(x, y, z, color)
                    end
                end
            end
        end
    end
   
    function draw_particles(x_min, x_max, y_min, y_max, z_min, z_max)
        local x
        local y
        local z
        local black_amount
        local particle_size
        local particle_scale
        local particle_count = math.random(30, 40)
        local particle
       
        for i = 1, particle_count, 1 do
           
            x = math.random(x_min, x_max)
            y = math.random(y_min, y_max)
            z = math.random(z_min, z_max)
           
            particle_size = math.random(1, 8)
            particle_scale = math.random(20, 100) / 100
            black_amount = math.random(0, 25)
           
            tex.sprint("\\tdplottransformmainscreen{" .. x .. "}{" .. y .. "}{" .. z .. "}")
            for i = 0, particle_size - 1, 1 do
                for j = 0, particle_size - 1, 1 do
                    if math.random(0, 1) == 0 and
                        ((i ~= 0 and j ~= 0) and
                        (i ~= particle_size - 1 and j ~= 0) and
                        (j ~= particle_size - 1 and i ~= 0) and
                        (i ~= particle_size - 1 and j ~= particle_size - 1)) then
                       
                        particle = "\\filldraw[black!" .. black_amount ..
                            "!particlecolor, tdplot_screen_coords] (" ..
                            i * particle_scale * 0.25 .. "+\\tdplotresx, " ..
                            j * particle_scale * 0.25 .. "+\\tdplotresy) " ..
                            "rectangle +(" .. particle_scale .. "*0.25, " ..
                            particle_scale .. "*0.25);"
                       
                        tex.sprint(particle)
                    end
                end
            end
        end
    end
   
    function draw_enderman(x_rotation, z_rotation)
        tex.sprint("\\tdplotsetmaincoords{" .. x_rotation .. "}{" .. z_rotation .. "}")
        tex.sprint("\\begin{tikzpicture}[tdplot_main_coords]")
       
        math.randomseed(os.time())
       
        draw_bodypart(3, -2, -30, 2, 2, 30) -- right arm
        draw_bodypart(3, 1, -42, 2, 2, 30) -- right leg
        draw_bodypart(3, 5, -42, 2, 2, 30) -- left leg
        draw_bodypart(2, 0, -12, 4, 8, 12) -- body
        draw_bodypart(3, 8, -30, 2, 2, 30)-- left arm
        draw_head(0, 0, 0) -- head
       
        draw_particles(-10, 10, -10, 10, -44, 10)
        -- draw_coordinate_system()
       
        tex.sprint("\\end{tikzpicture}")
    end
\end{luacode*}

\begin{document}
\luadirect{draw_enderman(70, 130)}
\end{document}

Copy the code, save with UTF-8 (without BOM) encoding, and compile using lualatex.

lualatex filename.tex

Update ~16:00 CEST on 21 July 2014:

Yesterday I’ve sent in this code as an example for TeXample.net. I got an answer from the site maintainer including a small improvement suggestion, namely that I should try algorithmize the drawing of a single (TikZ) cube (instead of concatenating a bunch of strings and make the TeX engine do the calculations). So I did, see the code below. (More details below the code.)

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
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
% Enderman
% Author: István Szántai (szantaii)
\documentclass{article}

\usepackage{luacode}

\usepackage{xcolor}

\usepackage{tikz}
\usepackage{tikz-3dplot}

\usepackage[active, tightpage]{preview}
\PreviewEnvironment{tikzpicture}
\setlength{\PreviewBorder}{1cm}

\definecolor{endermanblack}{HTML}{000000}
\definecolor{endermangray}{HTML}{161616}
%\definecolor{endermanpurple}{HTML}{CC00FA}
%\definecolor{endermanlightpurple}{HTML}{E079FA}
\definecolor{endermanpurple}{HTML}{FF9EFF}
\definecolor{endermanlightpurple}{HTML}{FFC9FF}
\definecolor{particlecolor}{HTML}{DF4AF8}

\begin{luacode*}
    function draw_coordinate_system()
        tex.sprint("\\draw[white!50!gray,thick,->] (0,0,0) -- " ..
            "(3,0,0) node[text=white!50!gray,anchor=north east]{$x$};")
        tex.sprint("\\draw[white!50!gray,thick,->] (0,0,0) -- " ..
            "(0,3,0) node[text=white!50!gray,anchor=west]{$y$};")
        tex.sprint("\\draw[white!50!gray,thick,->] (0,0,0) -- " ..
            "(0,0,3) node[text=white!50!gray,anchor=south]{$z$};")
    end
   
    function matrix_scalar_multiplication(matrix, scalar)
        local rows = #matrix
        local cols = #matrix[1]
        local tmp_matrix = {}
       
        for i = 1, rows do
            tmp_matrix[i] = {}
            for j = 1, cols do
                tmp_matrix[i][j] = matrix[i][j] * scalar
            end
        end
       
        return tmp_matrix
    end
   
    function shift_coordinates(matrix, array)
        local matrix_rows = #matrix
        local matrix_cols = #matrix[1]
        local array_length = #array
        local tmp_matrix = {}
       
        if matrix_cols == array_length then
            for i = 1, matrix_rows do
                tmp_matrix[i] = {}
                for j = 1, matrix_cols do
                    tmp_matrix[i][j] = matrix[i][j] + array[j]
                end
            end
           
            return tmp_matrix
        else
            return nil
        end
    end
   
    function tikzcube(x, y, z, color)
        local side_1 = {{1, 1, -1},
            {-1, 1, -1},
            {-1, -1, -1},
            {1, -1, -1}}
        local side_2 = {{-1, 1, -1},
            {-1, 1, 1},
            {-1, -1, 1},
            {-1, -1, -1}}
        local side_3 = {{-1, -1, -1},
            {1, -1, -1},
            {1, -1, 1},
            {-1, -1, 1}}
        local side_4 = {{1, 1, -1},
            {-1, 1, -1},
            {-1, 1, 1},
            {1, 1, 1}}
        local side_5 = {{1, -1, -1},
            {1, 1, -1},
            {1, 1, 1},
            {1, -1, 1}}
        local side_6 = {{1, 1, 1},
            {-1, 1, 1},
            {-1, -1, 1},
            {1, -1, 1}}
        local cube_sides = {side_1, side_2, side_3, side_4, side_5, side_6}
        local tex_cube = ""
       
        for i = 1, #cube_sides do
            tex_cube = tex_cube .. "\\draw[ultra thin, fill=" .. color .. "] "
           
            local current_side = matrix_scalar_multiplication(cube_sides[i], 0.5)
            current_side = shift_coordinates(current_side, {x, y, z})
           
            local current_side_rows = #current_side
            local current_side_cols = #current_side[1]
           
            for j = 1, current_side_rows do
                for k = 1, current_side_cols do
                    if k == 1 then
                        tex_cube = tex_cube .. "("
                    end
                   
                    tex_cube = tex_cube .. current_side[j][k]
                   
                    if k ~= current_side_cols then
                        tex_cube = tex_cube .. ", "
                    else
                        tex_cube = tex_cube .. ") -- "
                    end
                end
            end
           
            tex_cube = tex_cube .. "cycle;"
           
        end
       
        tex.sprint(tex_cube)
    end
   
    function draw_head(x_pos, y_pos, z_pos)
        local color
        for x = x_pos, x_pos + 7, 1 do
            for y = y_pos, y_pos + 7, 1 do
                for z = z_pos, z_pos + 6, 1 do
                    if (x == x_pos or x == x_pos + 7 or
                        y == y_pos or y == y_pos + 7 or
                        z == z_pos or z == z_pos + 6) and
                        not (x == x_pos + 7 and y > y_pos and y < y_pos + 7 and z == z_pos) then
                       
                        if x == x_pos + 7 and
                            (y == y_pos or y == y_pos + 2 or
                            y == y_pos + 5 or y == y_pos + 7) and
                            z == z_pos + 2 then
                           
                            tikzcube(x, y, z, "endermanlightpurple")
                        elseif x == x_pos + 7 and
                            (y == y_pos + 1 or y == y_pos + 6) and
                            z == z_pos + 2 then
                           
                            tikzcube(x, y, z, "endermanpurple")
                        else
                            if math.random(0, 8) < 6 then
                                color = "endermangray"
                            else
                                color = "endermanblack"
                            end
                            tikzcube(x, y, z, color)
                        end
                    end
                end
            end
        end
    end
   
    function draw_bodypart(x_pos, y_pos, z_pos, x_length, y_length, z_length)
        local color
        for x = x_pos, x_pos + x_length - 1, 1 do
            for y = y_pos, y_pos + y_length - 1, 1 do
                for z = z_pos, z_pos + z_length - 1, 1 do
                    if x == x_pos or x == x_pos + x_length - 1 or
                        y == y_pos or y == y_pos + y_length - 1 or
                        z == z_pos or z == z_pos + z_length - 1 then
                       
                        if math.random(0, 8) < 6 then
                            color = "endermangray"
                        else
                            color = "endermanblack"
                        end
                        tikzcube(x, y, z, color)
                    end
                end
            end
        end
    end
   
    function draw_particles(x_min, x_max, y_min, y_max, z_min, z_max)
        local x
        local y
        local z
        local black_amount
        local particle_size
        local particle_scale
        local particle_count = math.random(30, 40)
        local particle
       
        for i = 1, particle_count, 1 do
           
            x = math.random(x_min, x_max)
            y = math.random(y_min, y_max)
            z = math.random(z_min, z_max)
           
            particle_size = math.random(1, 8)
            particle_scale = math.random(20, 100) / 100
            black_amount = math.random(0, 25)
           
            tex.sprint("\\tdplottransformmainscreen{" .. x .. "}{" .. y .. "}{" .. z .. "}")
            for i = 0, particle_size - 1, 1 do
                for j = 0, particle_size - 1, 1 do
                    if math.random(0, 1) == 0 and
                        ((i ~= 0 and j ~= 0) and
                        (i ~= particle_size - 1 and j ~= 0) and
                        (j ~= particle_size - 1 and i ~= 0) and
                        (i ~= particle_size - 1 and j ~= particle_size - 1)) then
                       
                        particle = "\\filldraw[black!" .. black_amount ..
                            "!particlecolor, tdplot_screen_coords] (" ..
                            i * particle_scale * 0.25 .. "+\\tdplotresx, " ..
                            j * particle_scale * 0.25 .. "+\\tdplotresy) " ..
                            "rectangle +(" .. particle_scale .. "*0.25, " ..
                            particle_scale .. "*0.25);"
                       
                        tex.sprint(particle)
                    end
                end
            end
        end
    end
   
    function draw_enderman(x_rotation, z_rotation)
        tex.sprint("\\tdplotsetmaincoords{" .. x_rotation .. "}{" .. z_rotation .. "}")
        tex.sprint("\\begin{tikzpicture}[tdplot_main_coords]")
       
        math.randomseed(os.time())
       
        draw_bodypart(3, -2, -30, 2, 2, 30) -- right arm
        draw_bodypart(3, 1, -42, 2, 2, 30) -- right leg
        draw_bodypart(3, 5, -42, 2, 2, 30) -- left leg
        draw_bodypart(2, 0, -12, 4, 8, 12) -- body
        draw_bodypart(3, 8, -30, 2, 2, 30)-- left arm
        draw_head(0, 0, 0) -- head
       
        draw_particles(-10, 10, -10, 10, -44, 10)
        -- draw_coordinate_system()
       
        tex.sprint("\\end{tikzpicture}")
    end
\end{luacode*}

\begin{document}
\luadirect{draw_enderman(70, 130)}
\end{document}

I have added two new functions (matrix_scalar_multiplication, shift_coordinates), and rewrote the tikzcube function, so now the LuaTeX engine makes all necessary calculations instead of the TeX (TikZ?) engine which is considerably slower. Let’s see the numbers.

I’ve measured the compilation time of the original and the improved code. I made 20–20 “dry” compilations (no previous aux, log or pdf files). The average compilation time of the original code was 25.35 seconds while the improved code’s average was only 18.30 seconds. This means that the improved version is 25% faster than the previous one. Stefan, thanks for your suggestion!

Megosztás, like stb.

A héten bevásároltam játékból, megvettem a Humble Indie Bundle 8-at: Hotline Miami, Proteus, Little Inferno, Awesomenauts, Capsized, Thomas Was Alone, Dear Esther + soundtrackek. Azért döntöttem a vásárlás mellett, mert a hétből három játék (amiből már egy megvan) érdekelt, plusz akartam a zenéiket is, és persze mert pokoli olcsó.

Dear Esther

Egyszer volt már szó erről a játékról, úgyhogy nem írom le, mi is ez. Azért jó, hogy a Dear Esther is bekerült a Humble Indie Bundle-be, mert így megkaptam a teljes soundtracket is a már meglévő játék mellé. A zenét Jessica Curry írta, és külön is megvásáráolható.

Hotline Miami

Hotline Miami is a high-octane action game overflowing with raw brutality, hard-boiled gunplay and skull crushing close combat. Set in an alternative 1989 Miami, you will assume the role of a mysterious antihero on a murderous rampage against the shady underworld at the behest of voices on your answering machine.

Hotline Miami – Steam

Erősen tizennyolc-pluszos játék. Teljesen 80’s feeling GTA 1-2-vel nyakonöntve, szóval nagyon addiktív és nagyon beteg.

Proteus

A Proteus annyiban hasonló a Dear Esther-hez, hogy ez is egy „felfedezős” játék, ám itt nincs történet, nincs puzzle, csak gyönyörködni kell a tájban és a zenében. Szerintem csodaszép.

+ a többiek

Meh.

Megosztás, like stb.

Ezt írtam legutóbb:

A következő nagy projekt a Gorillas játék Bash változata. Hosszú lesz megírni, és egészen biztos vagyok benne, hogy fájdalmasan lassan fog futni, de akkor is… Jó lesz!

Nem volt hosszú, vagy nehéz megírni, és nem fut „fájdalmasan lassan” sem (ez persze géptől függ), viszont tényleg jó lett.

bash-gorillas

Előkövetelmény Bash ≥ 4.2, ncurses-bin, bc és minimum 80×22 méretű terminál. A kód elérhető GitHub-on, a futtatáshoz pedig a következőket kell terminálba bepötyögni:

$ git clone https://github.com/szantaii/bash-gorillas.git
$ cd bash-gorillas
$ bash bash-gorillas.sh

bash-gorillas bash-gorillas

További fejlesztések:

  • README frissítése (hét második fele);
  • kód kommentezése (majd valamikor);
  • dobás szög és sebesség felhasználó által való javítási lehetősége (ezt a hét második felében megcsinálom);
  • max_speed, wind_value beállítása a játék indításakor getopts használatával (hétvégén vagy jövő héten megírom);
  • bejegyzés létrehozása a Projektek, illetve a bash.sidenote.hu oldalakon.

A hátralevő fejlesztések ellenére már használható a cucc. Viszont ne habozzatok írni, ha találtok bugot, elérhetőségem a Rólunk oldalon. (Diffeknek örülnék a legjobban.)

Megosztás, like stb.

Poszt-apokaliptikus cyberpunk point-and-click kalandjáték csodálatos zenével és grafikával. Ezzel leptem meg magam karácsonyra.

What happened to the humans?

Set in a post-apocalyptic world strewn with cast-off machines, Primordia tells the story of Horatio Nullbuilt, a stoic robot who values his solitude and independence. Horatio spends his days studying the Book of Man, sparring with his droid companion Crispin, and tinkering with the airship they call home — a peaceful existence that becomes threatened when a rogue robot steals the energy source that the pair needs to survive.

When Horatio and Crispin’s search for energy brings them to the dazzling city of Metropol, the simple quest to recover their stolen power core leads to unexpected discoveries about Horatio’s origins and a new understanding of the legendary humans who walked the earth before him.

Primordia

Megosztás, like stb.

Gorillas

Image source: File:Gorillas screenshot.png – Wikipedia

I hope there are still some of you out there who remember the game Gorillas written in Basic. I have friends who still play this game from time to time.

These guys use Linux as their main operating system, so getting Gorillas to work needed the following workaround. First you had to get QBasic (from Microsoft or another source), then install DOSBox under Linux, start QBasic in DOSBox, load the source of Gorillas, and start the game. Each time you wanted to play you had to go through these steps, plus you had to adjust the game speed in DOSBox for your computer. I admit this isn’t difficult, but it is pokey.

So the other day I thought about rewriting this game in Basic and make it work under Windows and Linux. Finding the original(?) source wasn’t hard. The next step was to find a Basic compiler. I knew FreeBASIC, and after looking into it a little I’ve found out I can use the original graphics library of QBasic using FreeBASIC. The only problem was that I couldn’t set up FreeBASIC under 64 bit Linux, and there was the issue that FreeBASIC is a 32 bit only compiler too. I diched FreeBASIC and started to search for another Basic compiler, and luckily I’ve found QB64.

“Over 45 years of compatibility…” said the QB64 website. This aroused my interest, I thought that I might not need to rewrite the game at all but I may be able to compile the original source with QB64. To cut a long story short I had to touch only five lines of code in the original source to get the game work under Windows and Linux. Here is the receipt.

  1. QB64 doesn’t like the inline definition on line 211, so comment it out.

    211
    'DEF FnRan (x) = INT(RND(1) * x) + 1

  2. Add a new function declaration to the code (around line 90 in the original source).

    1
    DECLARE FUNCTION FnRan (x)

  3. Add the following function definition to the end of the file.

    1
    2
    3
    4
    5
    FUNCTION FnRan (x)

        FnRan = INT(RND(1) * x) + 1

    END FUNCTION

  4. Adjust the CONST SPEEDCONST constant’s value from 500 to 100,000,000 (line 123 in the original source). Note that you may need to use a different value, depending your computer.

    123
    CONST SPEEDCONST = 100000000

  5. Compile.

That’s it. After these modifications the code will compile without any errors. I tried it on Windows and Linux. (I don’t have a Mac but I’m pretty sure this will work under OS X too.) See the proof below.

Gorillas running under Windows 7 Gorillas running under Ubuntu 12.04 (64 bit)

Edit #1

I’m posting a patch which contains all described modifications. To patch the original source first unpack the linked tar.gz file then enter the following command in your terminal.

1
patch gorilla.bas -o gorilla-patched.bas < gorilla.bas.patch

Note that you will need the diff and patch programs for this operation (available through Cygwin under Windows).

Megosztás, like stb.

Pár napja dedikált OpenTTD szervert futtatok a Raspberry Pi-omon. Bárki játszhat rajta, a szerverek között [HU] RPiTTD néven szerepel. Mérsékelt égövi, 64×64-es térkép, egy AI (OtviAI) két AI, villamosok és sokféle közúti jármű (lovaskocsi is!), 2000–2050. Ezek vannak.

A térkép azért ilyen kicsi, mert a RasPi nem egy erőgép, és a játék vége felé, ha többen játszanak, a processzorhasználat simán felmegy 70% fölé is. A kis térkép ne riassza vissza a hardcore OpenTTD játékosokat (ha van ilyen), mert a helyszűke miatt igazi kihívás az AI és egy-két másik játékos mellett elférni a mapon.

Igazából arra vagyok kíváncsi, hogy mit bír a RasPi. Mérem az OpenTTD processzor és memóriahasználatát. Csinálok majd szép grafikont, ha lesz elég mért adat. Addig is játsszatok!

Megosztás, like stb.

A hét képe:

És az elmúlt hét legnagyobb Linux-játék híre:

[…]

For some time, Gabe has been interested in the possibility of moving Steam and the Source game engine to Linux. At the time, the company was already using Linux by supporting Linux-based servers for Source-based games and also by maintaining several internal servers (running a 64-bit version of Ubuntu server) for various projects. In 2011, based on the success of those efforts and conversations in the hallway, we decided to take the next step and form a new team. At that time, the team only consisted of a few people whose main purpose was investigating the possibility of moving the Steam client and Left 4 Dead 2 over to Ubuntu.

Why Ubuntu? There are a couple of reasons for that. First, we’re just starting development and working with a single distribution is critical when you are experimenting, as we are. It reduces the variability of the testing space and makes early iteration easier and faster. Secondly, Ubuntu is a popular distribution and has recognition with the general gaming and developer communities. This doesn’t mean that Ubuntu will be the only distribution we support. [!] Based on the success of our efforts around Ubuntu, we will look at supporting other distributions in the future.

After successfully porting L4D2 to Ubuntu, interest grew within Valve and, as a result, the team and projects we were working on also grew. Currently, our focus is on the following projects:

  • getting the Steam client onto Linux with full functionality
  • optimizing a version of L4D2 running at a high frame rate with OpenGL
  • porting additional Valve titles

[…]

Steam’d Penguins | Valve

Megosztás, like stb.

Az Amanita Design legújabb point-and-click kalandjátéka. Megüti a korábbi játékaik által feltett mércét. Akinek kétségei vannak, nézze meg az alábbi trailert.

Nem igazán tudom, mit írjak. Zseniális játék. Pont. Az egyetlen idegesítő rész az volt, amikor egy csillagot kellett kiszabadítani egy hernyó fogságából, kb. tizedszerre sikerült megcsinálni. (Egy „csillagot kellett kiszabadítani egy hernyó fogságából”, kérdezhetnéd. Inkább ne.)

A zene és a hangok itt is legalább olyan fontosak, mint a Machinariumban, kénytelen leszek ezt a soundtracket is megvenni. Áh, csúcsszuper játék, millió apró részlettel, fantasztikus világgal. Tessék megvenni!

 
 

Botanicula

Megosztás, like stb.

A Syndicate Warsban a hirdetőtáblákon többek között a Ghost in the Shell trailere futott. Cyberpunk at its best!

Kommentben megígértem, hogy kiegészítem a posztot, de inkább csak kiteszem ide a kommentek releváns részeit.

Írta: Red 2012. április 25. 10:14
Hogy lemaradtam erről… Kicsit rossz szájízem van, hogy FPS-t csináltak belőle, de kíváncsi lennék rá, lehet, hogy beszerzem majd Xbox-ra.

Írta: szantaii 2012. április 25. 11:06
Én is így voltam vele. Jobban örültem volna valami stratégiai játéknak. Az FPS-ek (1-2 kivételtől eltekintve) már nemigazán kötnek le. Viszont ez elég ütős lett, jól visszaadja a régi hangulatot, persze azért sok minden hiányzik is belőle.
Van ez a Skrillex gyerek meg még 1-2 DJ [ejtsd: diddzséj :)], akik remixelték a régi zenéket ehhez az új játékhoz, és habár nem vagyok dubstep fan, mégis jók lettek.
[…]

Megosztás, like stb.