The Cloud Shepherd: Sandbox Edition

I would have bet against it even a few hours ago but we actually have something that is not far from being a game. You fly around and place fans. You can water the desert to have cacti spring up, flood the cities and so on. Alex's water simulation makes it rather entertaining!

The water simulation is in a C extension so we definitely have packaging work to do tomorrow.

It's the first time I teamed up with another programmer for PyWeek. We both liked the theme and quickly agreed on many details of a weather control puzzler. But I envisioned it as something simple, 2D and board game-like while Alex wanted to do a more realistic 3D simulation. He's the better programmer so I gave up trying to convince him.

Since we only started on Tuesday we had a scarcity of time and I kept to drawing stuff until today. This morning we only had the height map rendering, clouds, fans and a pile of useless sprites. Alex has finished the fluid simulation and realized it's dead slow. So he ported it to a C extension. I was sure at that point that we would have nothing to show for all of our brilliant ideas. But things started coming together and it's a fun little sandbox now. We'll probably do a post-final version with sounds and music tomorrow for the more lenient judges.

We only decided on the name today, so I could not write diary entries earlier... But here's an early concept sketch that reflects my tile-based approach.



I've seen really impressive screenshots from other entries so I'm looking forward to the judging period!

(log in to comment)

Comments

Hm, I've had to sed -i s:iiiinnnn:iiiikkkk: water_flow.c to get this working, not sure why, n seems to be the right thing to use...
The proper fix (obvious when I go back now to look at the docs; oh well...) is to use w/w#/w*. I'm curious why the 'n' hack didn't work for you, though. What architecture are you on? What's the size of Py_ssize_t? void *? int? Anyway, quick patch: diff --git a/water_flow.c b/water_flow.c index d60a67d..47ba9c4 100644 --- a/water_flow.c +++ b/water_flow.c @@ -36,7 +36,7 @@ static PyObject *SubTick(PyObject *self, PyObject *args) { float *water_vbo_array; int width, height; - if (!(PyArg_ParseTuple(args, "iiiinnnn", &from, &to, &width, &height, + if (!(PyArg_ParseTuple(args, "iiiiwwww", &from, &to, &width, &height, &heightmap, &water, &next_water, &water_vbo_array))) return NULL; diff --git a/world.py b/world.py index 1cb6bad..fe45d43 100644 --- a/world.py +++ b/world.py @@ -640,10 +640,10 @@ class World(object): if True: water_flow.SubTick(self.sub_progress, target, self.size[0], self.size[1], - ctypes.addressof(self.heightmap), - ctypes.addressof(self.water), - ctypes.addressof(self.next_water), - ctypes.addressof(self.water_vbo_array)) + self.heightmap, + self.water, + self.next_water, + self.water_vbo_array) if False: for y in xrange(self.sub_progress, min(target, self.size[1] - 2)): i = (y + 1) * w
Blah, sorry. Again, but with formatting:

diff --git a/water_flow.c b/water_flow.c

index d60a67d..47ba9c4 100644
--- a/water_flow.c
+++ b/water_flow.c
@@ -36,7 +36,7 @@ static PyObject *SubTick(PyObject *self, PyObject *args) {
   float *water_vbo_array;
   int width, height;
 
-  if (!(PyArg_ParseTuple(args, "iiiinnnn", &from, &to, &width, &height,
+  if (!(PyArg_ParseTuple(args, "iiiiwwww", &from, &to, &width, &height,
                          &heightmap, &water, &next_water, &water_vbo_array)))
       return NULL;
 
diff --git a/world.py b/world.py
index 1cb6bad..fe45d43 100644
--- a/world.py
+++ b/world.py
@@ -640,10 +640,10 @@ class World(object):
     if True:
       water_flow.SubTick(self.sub_progress, target,
                          self.size[0], self.size[1],
-                         ctypes.addressof(self.heightmap),
-                         ctypes.addressof(self.water),
-                         ctypes.addressof(self.next_water),
-                         ctypes.addressof(self.water_vbo_array))
+                         self.heightmap,
+                         self.water,
+                         self.next_water,
+                         self.water_vbo_array)
     if False:
       for y in xrange(self.sub_progress, min(target, self.size[1] - 2)):
         i = (y + 1) * w
Any idea what's wrong here? I'm on Ubuntu.

Traceback (most recent call last):
  File "run_game.py", line 221, in <module>
    main()
  File "run_game.py", line 70, in main
    w = world.World(size, 'data/handdrawn_noshadows.png', heightmap, shared)
  File "the-cloud-shepherd-1.1/world.py", line 247, in __init__
    self.InitRendering()
  File "the-cloud-shepherd-1.1/world.py", line 222, in InitRendering
    self.InitMeshIBO()
  File "the-cloud-shepherd-1.1/world.py", line 85, in InitMeshIBO
    GL_STATIC_DRAW)
  File "/usr/lib/pymodules/python2.6/OpenGL/wrapper.py", line 1284, in __call__
    return self.finalise()( *args, **named )
  File "/usr/lib/pymodules/python2.6/OpenGL/wrapper.py", line 455, in wrapperCall
    pyArgs = tuple( calculate_pyArgs( args ))
  File "/usr/lib/pymodules/python2.6/OpenGL/wrapper.py", line 328, in calculate_pyArgs
    args
ValueError: glBufferData requires 3 arguments (target, data, usage), received 4: (GL_ELEMENT_ARRAY_BUFFER, 524276, <world.c_uint_Array_131069 object at 0x21de290>, GL_STATIC_DRAW)
Yes, Alex has mentioned this in his post:

If you're having problems with types in PyArg_ParseTuple in the c extension, this patch might help. I've also seen issues with glBufferData only taking 3 arguments in pyopengl 3.0.0. pyopengl 3.0.1 or later seems fine; can also work around it by removing the size argument to all glBufferData (second argument) and glBufferSubData (third argument) calls in world.py.