whydoitweet

I'm a Lecturer in Computer Science at Brunel University London. I teach games and research simulations. Views are my own :).

Meetings are the bane of human existence. Or are they? Ask a senior colleague about their work schedule, and you'll find many of them have a work week utterly dominated by meetings, filling up 50, 60, 70 or even 90% of their work time.

Some will have a sense of agony about meetings: they appear dreary and useless. Others consider their meeting-filled schedule to be a sign of importance: clearly they matter enough in this world to be included in all sorts of select gatherings!

Now I'm sure a lot has been said on meetings in this world, so I will keep this post quite simple, and stick to conveying my own perspective on the meeting beast.

My perspective is based on personal experience, and not so much on extensive research, so I cannot promise that whatever works for me will work for you. However, it might give you some interesting ideas perhaps?

Hello meeting!

Image courtesy of Piotr Siedlecki (CC0).

Meetings are a bit like monsters. They are powerful, a little bit hard to control, and frequently end up being part of the tortuous machinations of evil. But the alternatives are not always better:

  • E-mails tend to be misinterpreted, responded to slowly, or directing attention to things that do not really matter.
  • Chats can lead to excessive distractions, or forgetfullness because only some people may bother to extract the key actions and notes from the feeds for later use.
  • And not meeting is great, as long as your aims are aligned and you know what to do, and how to do it efficiently. But most work is intended to be challenging and the best way to align things is by interacting with others.

So back to the meeting then: it seems like they're going to be necessary at least in many cases. So I'll touch upon three things: planning meetings, attending them, and holding them.

Planning meetings

For planning meetings (I tend to have 10-20 of them in a week myself), I categorize them in three types:

  • Meetings A: I have to attend these in person and I cannot move them (without pain). Examples include personal performance review meetings, important meetings that I already rescheduled once, or meetings abroad that have fixed dates and require my personal attendance.
  • Meetings B: These are important meetings, but I could ask someone else to represent me and/or send a few e-mails requesting the meeting to be moved. Of course, it will take me a little time and energy to do so, so I might not want to move them all the time.
  • Meetings C: These are useful meetings that I want to be part of. However, I can choose to just not attend them without many consequences.

These meetings are in my calendar, but in different colors, with darker colors for the more essential meetings:

Now, when I end up with two meetings in the same time slot, I simply compare the types of meetings that clash:

  • A vs. B: I delegate or move the B meeting. If I think the other party could get annoyed by the move, I upgrade the now moved B meeting to an A meeting, so that a second move is less likely.
  • A vs. C or B vs. C: I opt out of the C meeting. If the C meeting is regular and I begin to wonder why that C meeting is in my calendar, I just take it out altogether. If I need to reconnect with that C meeting due to missing it all the time, I could upgrade it once to a B meeting.
  • B vs. B or C vs. C: The earliest planned meeting prevails, or I half-attend both meetings.
  • A vs. A: This is a special case, because cancelling either would be painful. It is only here where I need to think hard, cancel the one that's least painful, and then think of a mechanism I can use to compensate for that cancellation (e.g., arrange an extra trip, or pledge some concrete support).

In general, I try to cluster my meetings in a part of the week, and defend blocks of time where I can focus on in-depth technical or writing work. Also, if the meeting involves my local group with externals, I'll always consider inviting only one key person of my local group to join, so that all the others have some extra free space.

The written update

Many meetings (especially type B ones) are all about providing status reports, and dishing out tasks for the next round of work. One method I use when I can't attend a meeting is to take the following two steps:

  • I provide a written status update by e-mail in advance, trying to cover all the angles that other participants may be wanting to ask me about.
  • I tell the leader of the meeting that I'll happily accept any action or task assigned to me, given that they state so clearly in the minutes or in a direct e-mail to me.

This approach works particularly well in groups that I am familiar with, as I am likely to be given a reasonable workload. If in any circumstance the meeting leader gives me an unreasonable workload, then I do my best to cope with that and make sure I will attend the next meeting. Now speaking of attending...

Courtesy of *Pixabay*, and my desire to break the wall of text with ill-fitting clipart.

Participating in meetings

Nobody's perfect, and many people hardly know in advance how they will behave during a meeting. Also my own behavior is inconsistent, but I do try to be mindful of a few things when I participate in a meeting:

  • Not all meetings require my continuous attention, because topics can be wide-ranging and many of them might not require my input at all. If I can contribute better to the subject matter of the meeting by filling in documents, looking up information, or actually doing work that is being discussed, then I have no qualms against doing so during the meeting (but I will notify participants in advance).
  • I try to be direct when sharing my opinion in a meeting, but I also try not to repeat myself (see ticking salaries below). This is very hard and I frequently fail at it ;).
  • I embrace the early finish. There is often no need to fill a time slot completely, and the break at the end can spur independent ideas for other participants.
  • Meetings seldom have to overrun. Unless the subject matter is of critical importance, I am okay with leaving at the end of a time slot, particularly if overrunning leads to me delaying other meetings of any type, or shortening my lunch break.
  • If I foresee technical issues coming up in a remote meeting (e.g., I will be at an airport with possibly poor wifi), then I might send the written update in advance (see above).
  • And last but not least, I don't always rush meetings. If a meeting has a pleasant social element and my schedule has room, then I'm happy for it to linger. We are humans after all, not machines :).

The third topic to touch upon, is holding a meeting myself.

Holding a meeting

The most intuitive way to make decisions about holding a meeting, in my opinion, is to imagine the salaries ticking as the meeting takes place. Think of it a little bit like the typical Coil Counter:

XRPTipbot.com was awarded $0.001472 to create this image ;).

Now let's imagine you want to hold a meeting (telco or real life) with 11 colleagues, and each of them earns, say, $25/hour. That means your meeting would cost $300 per hour or $5/minute.

Now given that, you may want to economise your meeting setup a bit, by e.g.:

  • Asking people to share updates in writing a bit before the meeting, and shortening the meeting by eliminating the “status update” part of it.
  • Reducing the number of participants to the minimum necessary.
  • Split a broader meeting into two more narrow ones, ideally each with half of the audience.
  • Pruning the agenda of any item that is not urgent, important or both.

Also, when chairing the meeting you can then take this into account. For instance, a 12-second joke might put you back $2, which is not too bad, but the 10-minutes digression into some obscure topic that only interests two people in the meeting would set you back some $50 with much annoyance and no benefit. Would that be worth it?

Closing thoughts

Meetings are an “art”, not a science, and I doubt anyone can ever achieve the perfect meeting attitude. Yet, meetings can be unwieldy and it is easy to get trapped in patterns that feel unrewarding, a waste of time, or even frustrating altogether. In this blog post I hope I gave you some useful ideas about how you could try to mitigate that, and I'm curious to know if any of it is useful to you :).

In addition, this post is part of a new series (Boffins' Office). So again, I will be gauging the interest and take that along in my decision whether to write follow-up posts or not.

For subscribers I have a reference to an external book that I really like, and of whom I met the author in person recently.

Credits

Header from Maxpixel (CC0 Public Domain).

Read more...

In my previous post I did a first analysis of several possible shapes you could choose for your Game World: spherical, flat, or even an inner sphere. However, other shapes are of course possible and in this post I'll reflect on the more exotic shapes, ranging from the somewhat unlikely to the hilariously obscure.

Ellipsoid

An ellipsoidal planet is a spherical planet, but then squashed to a certain extent. It's very easy to justify physically, because technically the earth is a ellipsoidal planet. It's circumference is 40,008 km from pole to pole and back, and 40,075 km around the equator.

Other planets are even more extreme, for instance Saturn has circumferences of respectively 120,536 km and 108,728 km. This phenomenon is called an equatorial bulge (this Wiki page has a great explanation btw), and is essentially caused by centrifugal forces related to the planets rotation. So, if you want a bigger bulge just make your planet spin faster, for instance. :)

Torus

Another option is to punch a hole into the concept of spherical worlds, e.g. by opting for a donut-shaped world:

Image credits: Weisstein, Eric W. “Torus.” From *MathWorld--A Wolfram Web Resource.* *http://mathworld.wolfram.com/Torus.html.*

Especially the ring torus gives a very unconventional look, but provides a similar range of flexibility as spherical worlds do. For starters, it's pretty easy to visualize a spinning torus in a constellation of planets and stars. But the hole in the middle gives the concept a twist, and gives rise to some very interesting design decisions:

  • For starters, the size of the hole is an important aspect. A small hole may make it a very central feature in the world, because regions in the hole will be practically devoid of sunlight and provide a completely different environment. However, a very large hole will make the feature less prominent, and if visibility is limited, then some of its citizens may think that the world is merely cylindrical instead of a torus.
  • A second aspect is gravity. First, what stops your donut from caving in or collapsing? And second, how does it work to begin with? Do objects fall into the central hole (and perhaps disappear), or can you walk on all sides of the torus as you can walk on a spherical planet?
  • Third, objects like moons may move through the hole of the torus, creating some kind of very powerful ecliptic event (imagine the tidal effects on the inside, for instance).
  • And fourth, you can also invert the idea, and insist that people don't live on the outside of the torus, but on the inside. This would make it somewhat similar to an inner sphere, and in fact a major Dungeons and Dragons town is in a dimension of exactly this shape (see header image and credits). In this case, you have to think hard about how any suns or stars might move though (D&D solved it by just having “ambient light”).

Other, funkier variations of this shape could include the Moebius Strip:

Image courtesy of Wikimedia Commons.

The Lemniscate.

Image courtesy of Wikimedia Commons.

Or the Hyperboloid:

Image courtesy of Wikimedia Commons.

Thanks go out to curiousmatic.com for providing these ideas :).

Dodecahedron (or any other Platonic Solid)

So perhaps you're one of those people who is making a game world for a table-top role playing game with loads of dice. In that case, why not cast your game world as a die itself?

Image courtesy of the *Dodecahedron Earth Society on Twitter*.

The example here shows a 12-sided die, but of course many shapes are possible. For instance, there are five Platonic solids that you can choose from, ranging from 4-sided to the conventional 6-sided die to the 20-sided Platonic solid. Physically it's not impossible to justify, but it would make things easier if your world is relatively small in this case. Perhaps the world is very young and will gradually turn into a sphere over time, or perhaps a powerful civilization deliberately created the world in this shape, and deployed it in outer space (the outrageousness of this idea grows with the size of your proposed world :)).

Here are a few other aspects worth contemplating:

  • Of course, one can't help but ask why? Why would your world be 12-sided, and not 4-sided, 20-sided or just spherical?
  • One very interesting aspect of world of these shapes is that time zones work in interesting ways. Each face of the planet will get the same exposure to sunlight at all times, so it is quite realistic to think that civilizations would cluster on the faces of the planet, rather than on the ridges between them.
  • Perhaps you can add some remarkable detail about the areas where three of the faces intersect? It could be that those points are key to explaining why your gaming world has the shape of a Platonic Solid?

No static shape

Lastly, if you really want to go for something exotic, try contemplating about a world that changes shape. For instance, your world could represent the inside of a lung, and rythmically expand and contract, or a sphere that squashes into an ellipsoid and then becomes spherical again. Now obviously you need to think up the machinations that cause the shape to change, but things like an irregular orbit and a rather soft core could help a little bit to justify this and reduce the mythical fudge required to make it work.

And if you still can't think of an exciting idea....

...well, then perhaps you could contemplate on the shape of a Beating Greek Heart, an animated shape that somehow made it into Wikimedia Commons, and is not visually reproduced here to preserve your sanity.

Closing thoughts

The list of possibilities is endless, but I hope this two-part series gave some inspiration for both choosing a nice shape and trying to justify it. I hope to pick this series up soon again, covering an entirely different topic!

For the subscribers, I have a few extra references to write-ups about world shapes.

Credits

Header image of Sigil courtesy of Jason Engle. Role-playing setting courtesy of Wizards of the Coast.

Read more...

Today we're going to model a star (or more if you like) with a few planets. Given that this is a blog series about small simulations, and I did my PhD in astrophysics, there's no way I cannot touch upon this one :).

Our mission today is to:

  • model the movement of stars and planets.

These simulations are called N-body simulations, and the first known one dates back to 1941, when Erik Holmberg simulated the interaction between two galaxies using... real-life light bulbs and students:

Courtesy of Holmberg, Astrophysical Journal, 1941.

Of course, all this became much easier once computers became commonplace, and modern researchers usually perform N-body simulations with millions, and sometimes even billions of stars.

Because of that, there are also many example N-body codes on the web, for instance at Rosetta Code, and a dedicated website called nbabel.org.

Once more, to start off this tutorial, simply go to Repl.it and create a new “Pygame” Repl:

Image courtesy of repl.it.

What libraries do we need today?

So yes, like last time, we will use PyGame, because it does a pretty good job with animations (particularly this one). In addition, we need the time module to display the frames at a good rate:

import pygame

import time

We also initialize PyGame like we did in the previous bouncy ball tutorial:

pygame.init()

width, height = 800, 600

backgroundColor = 0, 0, 0

screen = pygame.display.set_mode((width, height))

screen.fill(backgroundColor)

We also put in the gravitational constant, G:

G = 9.81 # gravity coefficient

Defining the stars and planets

In our simulations, stars a point-like objects that move, and may accelerate and decellerate. To define this, we write their class as follows:

avity coefficient

class Star:

def __init__(self, x, y, vx, vy):

self.x = x

self.y = y

self.vx = vx # x velocity

self.vy = vy # y velocity

self.ax = 0. # x acceleration

self.ay = 0. # y acceleration

self.lax = 0. # last x acceleration

self.lay = 0. # last y acceleration

self.radius = 32

self.mass = 16

self.lx = x # x coordinate of last step

self.ly = y # y coordinate of last step

I set the radius to 32 so that stars look big on the screen. I set the mass to 16.

For planets, we can now re-use the definitions for stars, but we'll adjust the mass and radius such that they are smaller and less massive:

class Planet(Star):

def __init__(self, x, y, vx, vy):

Star.__init__(self, x, y, vx, vy)

self.radius = 8

self.mass = 1

You can see that we reuse the definitions of the Star class on the first line. Also, when we construct the object (using __init__()), we also first call the construction function for the parent Star class.

This is all great, but just defining these things isn't enough to have actual stars and planets. So let's call these classes and make some bodies for our simulation:

bodies = [Star(350.0, 350.0, 0.0, 0.0), Planet(250., 350., 0., 1.), Planet(450., 350., 0., -1.), Planet(150., 350., 0., 0.5), Planet(550., 350., 0., -.6)]

This blurb creates a star with four planets spinning around it, and should lead to a visually interesting setup :). But if you want to add more bodies (stars or planets), you can easily do so by inserting more objects in the list.

Defining how bodies move and accelerate

In the real world there are numerous mechanisms that cause movement of stars and planets, but by far the most important one is gravity. It's possible to simulate movement caused by gravity by applying Newton's Law of Gravity:

Here, r is the distance between the two bodies, and m1 and m2 is the mass of each of the two bodies, while G is the gravitational constant we defined at the start of the tutorial :).

Now to model the movements we use a method called leapfrog, where we alternate the updating of positions, and the velocities, and do a recalculation of the forces (or accelerations) in between these updates.

Courtesy of *Drexel University*.

You can find an excellent and detailed explanation of the algorithm on the student web pages of Drexel University.

Now, onwards to applying the algorithm! First we calculate the forces (or accelerations) for our bodies:

def accelerate(bodies):

We loop over all our bodies, as we want to update them all,

for k1, b1 in enumerate(bodies):

and keep a record of the x and y accelerations from our previous step, while resetting them to 0.0 for the current step,

b1.lax = b1.ax

b1.lay = b1.ay

b1.ax = 0.0

b1.ay = 0.0

We then loop again over all our bodies, because all bodies attract each other,

for k2, b2 in enumerate(bodies):

a body doesn't have a gravitational pull to itself in our model, because it is a point particle,

if k1 == k2:

pass

but in all other cases, we calculate the forces using Newton's equations of motion,

else:

dist = ((b1.x - b2.x)**2.0 + (b1.y - b2.y)**2.0)**0.5

temp = G * b2.mass / dist**3

b1.ax += (b2.x - b1.x) * temp

b1.ay += (b2.y - b1.y) * temp

And that is how we calculate the forces! Now we need to do a little more to actually move the stars, because our bodies only move when their positions change. We do that as follows:

def update_position(bodies, dt):

for k1, b1 in enumerate(bodies):

b1.x += (b1.vx + 0.5*b1.ax) * dt

b1.y += (b1.vy + 0.5*b1.ay) * dt

So, we add the velocity to each position here, but also half of the acceleration. This is because the velocity is not the same during the full time step, and that should affect the position as well.

Now we almost have all movements defined, but one thing we still need to do is update the velocities. We do this by adding half of the acceleration of the last time step, and half of the acceleration of the current time step:

def update_velocity(bodies, dt):

for k1, b1 in enumerate(bodies):

b1.vx += (0.5*b1.ax + 0.5*b1.lax) * dt

b1.vy += (0.5*b1.ay + 0.5*b1.lay) * dt

Making the main simulation and visualization loop

We have stars, planets and means to move them. So now we can make the main loop. As usual, I do the drawing in the main loop, as I'll use simple circles for convenience.

First of all, the simulation will keep going until you close it:

while True:

Next, we apply the leapfrog scheme:

accelerate(bodies)

update_position(bodies, 1.0)

accelerate(bodies)

update_velocity(bodies, 1.0)

and clear the screen to remove previous drawings (this somehow is faster than drawing over them actually),

screen.fill(backgroundColor)

next up, we draw all the bodies as circles with their radius as size,

for b in bodies:

pygame.draw.circle(screen, (255, 255, 0), (int(b.x), int(b.y)), int(b.radius), 0)

Lastly, after all drawing is done we reveal the whole thing to the screen and sleep for a 0.05 second to give about 18-20 frames per second.

pygame.display.flip()

time.sleep(50 / 1000)

All this code should result in an animation, that looks roughly like this:

Closing thoughts

So I presented a simple model how to simulate a few stars and planets. If you like, you could for instance tweak this model to recreate the solar system, or make a simplified version of the Milky Way (like Holmberg did).

Now, as a final bit, I'll attach the full code and, for subscribers, a little tidbit about the performance of N-body codes.

Credits

Header image courtesy of NASA.

Previous: Modelling a Pub

Next: Modelling an Election

Appendix 1: Full code and repl.it version

Here is the full code:

import pygame

import time

pygame.init()

width, height = 800, 600

backgroundColor = 0, 0, 0

screen = pygame.display.set_mode((width, height))

screen.fill(backgroundColor)

G = 9.81 # gravity coefficient

class Star:

def __init__(self, x, y, vx, vy):

self.x = x

self.y = y

self.vx = vx # x velocity

self.vy = vy # y velocity

self.ax = 0. # x acceleration

self.ay = 0. # y acceleration

self.lax = 0. # last x acceleration

self.lay = 0. # last y acceleration

self.radius = 32

self.mass = 16

class Planet(Star):

def __init__(self, x, y, vx, vy):

Star.__init__(self, x, y, vx, vy)

self.radius = 8

self.mass = 1

def accelerate(bodies):

for k1, b1 in enumerate(bodies):

b1.lax = b1.ax

b1.lay = b1.ay

b1.ax = 0.0

b1.ay = 0.0

for k2, b2 in enumerate(bodies):

if k1 == k2:

pass

else:

dist = ((b1.x - b2.x)**2.0 + (b1.y - b2.y)**2.0)**0.5

temp = G * b2.mass / dist**3

b1.ax += (b2.x - b1.x) * temp

b1.ay += (b2.y - b1.y) * temp

def update_position(bodies, dt):

for k1, b1 in enumerate(bodies):

b1.x += (b1.vx + 0.5*b1.ax) * dt

b1.y += (b1.vy + 0.5*b1.ay) * dt

def update_velocity(bodies, dt):

for k1, b1 in enumerate(bodies):

b1.vx += (0.5*b1.ax + 0.5*b1.lax) * dt

b1.vy += (0.5*b1.ay + 0.5*b1.lay) * dt

bodies = [Star(350.0, 350.0, 0.0, 0.0), Planet(250., 350., 0., 1.), Planet(450., 350., 0., -1.), Planet(150., 350., 0., 0.5), Planet(550., 350., 0., -.6)]

while True:

accelerate(bodies)

update_position(bodies, 1.0)

accelerate(bodies)

update_velocity(bodies, 1.0)

screen.fill(backgroundColor)

for b in bodies:

pygame.draw.circle(screen, (255, 255, 0), (int(b.x), int(b.y)), int(b.radius), 0)

pygame.display.flip()

time.sleep(50 / 1000)

And a repl can be found here.

Read more...

Welcome to the second edition of the Game World Series, where we will now focus on generating some ideas to design a distinctive and entertaining geography and climate for your world.

Image copyright owned by Wizards of the Coast.

The shape of your world has a fundamental influence on all other aspects of your design. It affects how you draw your maps, how the seasons could work, and gives the overarching frame for all your epic storylines. Now the possibilities are endless, but I will give a range of ideas to try and get you started. As part of this post I will also try to give some pointers in terms of physical justification. However, in fantasy settings you can of course always ignore these justifications, and instead decide that some almighty being makes your world (or parts of it) work the way it does:

Sphere

From *pxhere (CC0)*.

Like our own planet, your people live on a sphere, that may or may not rotate. It's the easiest to justify because it's the case in reality, but for some it may be not exciting enough for a game setting. When you have a spherical world, you can tune all sorts of (astro-)physical aspects in other ways to give color to your setting. Here are few examples:

  • How fast does it spin? This can determine whether days are long or short.
  • How much does it tilt? The more it tilts, the more extreme the seasons will be (especially near the poles). If it doesn't tilt at all, there may be few or no seasonal effects. As a reference, the earth has a tilt of 23.5 degrees, by the way.
  • Does it have moons, and how big are they? Moons can give light at night, but more importantly they affect the tides of the oceans.
  • Is there one sun, or are there multiple ones? More suns will radically change the definitions of day and night, and the size and distance of any suns will change radiation and temperature of course.

Flat

Courtesy of Edwin Abbott Abbott (public domain).

A simple alternative is to have a world as flat as a pancake. Taken to the very extreme you end up with a setting like Flatland. Flat worlds are great for map-making, because the whole planet can be drawn up conveniently on a piece of paper.

In terms of physical logic it is harder to justify. An important choice is the thickness of your world. If it is very thick, you'll want to think about why the stars don't come down crashing into the planet. If it is very think, you may want to think why it's not bending of deforming in other ways. In any case, some mythical fudge will make your life easier if flat is your shape of choice (for which Terry Pratchett's Discworld is an excellent reference, by the way).

Inner sphere

Gauss sphere with charge inside. Courtesy of *Wikimedia*.

So your world could be a sphere...with civilization living on the inside of it as well. This makes for quite an unusual setting, as the whole notion of interstellar travel changes (distances in the sky are quite short), and there is no longer any notion of horizon in your world. Moreover, there would be no notion of a setting or rising sun, unless you make a hole in your inner sphere somewhere...

Physics-wise it's of course tricky to justify, yet not entirely outrageous. To prevent your inner sphere from collapsing something needs to be at its center (a sun I suppose) repulsing the matter around it. Repulsive effects are common in nature (think of magnetism, for example), so you can reuse that here. However, it is not unlikely that you'll still need a little bit of mythical fudge to glue the last logical pieces together :).

I have made many campaign world using inner spheres, and here are a few things you can think about to give your world extra flavour:

  • The sun: Does it move at all, or does it stay stationary in the middle? Also, how do you define day and night in your world? You could rythmically change the brightness and intensity of the sun over time, or move it through a whole in the earth somehow. Or perhaps it just disintegrates and re-emerges on a periodical basis?
  • Visibility: with perfect visibility you can see practically the whole planet from anywhere. Do you want that to be the case, or do you prefer to have some tactically placed “fog of war”?
  • The stars: In a spherical planet stars are usually huge and far away. In inner spheres they will have to be small and quite nearby. Will you have stars in your world? If so, how do they move around, and how do they not collapse on the planet? Perhaps your stars are actively flying, or have no weight of their own? You can see how this can: get quite exotic...
  • Digging: So you hit the ground and start digging, where will you reach? I think there are two obvious choices here. Either the soil is infinitely deep -or- after digging you reach a different world which is on the outside of your inner sphere, and therefore a regular sphere.

Closing thoughts

So I pondered about possible shapes of your gaming world today, and started off with three “relatively” straightforward types in this blog post. Next time I'll try to dig up some more exotic world shapes (also derived from existing settings), and explore what the implications would be for using those.

For subscribers I have a little tidbit about world size today.

Credits

Header image courtesy of Maysam Yabandeh.

Previous: Design a spinning globe.

Read more...

Read more...

So Ken Melendez called for a 30 day blog challenge yesterday, inviting people to try and make 30 posts in 30 days.

Since I made a post yesterday anyway, and have a few in the pipeline, I decided to give this a shot. The main reason I want to try it is because it's a nice way to nudge myself to try and post a lot of different kind of posts in a short period. This will help me to better figure out what works for this blog, and what doesn't. I'm not so sure that I can make 30 posts in 30 days, given my life schedule, but even if I miss a post at some point, I will try to remain as close to it as I reasonably can.

Obviously many of my posts will be simpler than the ones you're used to. But just as before, you can tell me what's good by upvoting the posts you like, and not upvoting the ones you don't like.

Credits

Header image courtesy of needpix.com.

Exactly a month ago I started this blog, and 31 days + 12 posts later I think it's good to look back a little bit. What has worked well, what hasn't worked so well, and how should I change my tune going forward?

The numbers

I like to make decisions based on direct evidence, so let's have a look at the numbers first.

The posts with the most upvotes:

The days with the most traffic:

So what can I make out of this? Well, I think that most posts have been pretty well received, given the youth of this blog, and that the two general posts I made were pretty popular as well. But a few things worked less well too...

Not so great aspects

Image courtesy of Vaikoovery (Wikimedia Commons).

So far, I can see three things that worked out less well:

  • My initial idea of answering questions from people about simulation didn't caught on. After one month I've had a whopping 0 questions. The offer still stands, but I'll focus on other things for now :).
  • The later editions of the Small Sims series are a bit less popular than the earlier ones. I suspect that this is either because there are issues with those posts that I am not yet aware of, or the graphics are too unappealing to catch on more widely.
  • The Game World contest didn't catch on. Nobody responded, even though the post itself was very well received!

Going forward

So I haven't at all cracked the issue of making this place more interactive: the relatively static Coil interface (where no comments can be placed) doesn't help here, but I have hope that this will be resolved in due time. Until then, I plan to share my posts a bit more actively via Facebook, Twitter and Reddit.

And in terms of the tutorials, I plan to do a revamp of some of the previous tutorials in due time, trying to make them more attractive without lengthening the code. In fact, at time of writing, I already made changes to the Bouncing Ball tutorial to make it more appealing. In addition, I will be focusing a bit more on the Game World series, and a bit less on the Small Sims one :).

Lastly, I'd like to experiment with a few new types of posts in the coming month, including a few on more general topics, and one or two personal/historical posts. Whether those will be a long-term thing depends again on the reception :).

Anyway, to wrap this little meta-post up, I'll talk a bit about monetization for subscribers, and I'll share the three posts I liked the most on Coil:

  • Stoic quotes 2 by @Miguel_Se7. I especially like this one: “You become what you give your attention to.”, but there are many other good ones in this post.
  • New to Coil – 10 Keys to Success by @RileyQ. A very systematic list of things to pay attention to. Especially the “break it up” suggestion was one I didn't think about at all before :).
  • The Coil Content Review series by @vengeful_seven. It's a bit meta, but it is a good read every time, and helps me find the signals amidst the noise here at Coil.

Credits

Read more...

Today we are going to simulate a pub! Or at least part of it: our mission is to:

  • make a simulation of a pub, with people moving about, ordering drinks and socializing at a table.

I'll warn you in advance: I'm a very poor graphics designer and PyGame in repl.it can be slow on older machines, so I'll keep the graphics super-basic with squares and circles for now. However, inserting images with PyGame is easy, so you can simply plug in your own graphics after you've got the code working.

So, to start off this tutorial, simply go to Repl.it and create a new “Pygame” Repl:

Image courtesy of repl.it.

What libraries do we need today?

So yes, like last time, we will use PyGame, because it does a pretty good job with animations (particularly this one). In addition, we need the time module to display the frames at a good rate, numpy to create and make changes to the floor plan of the bar, and random for our random walk:

import pygame

import time

import numpy as np

import random

We also initialize PyGame like we did in the previous bouncy ball tutorial:

pygame.init()

width, height = 800, 600

backgroundColor = 0, 0, 0

screen = pygame.display.set_mode((width, height))

screen.fill(backgroundColor)

Just to be clear, we are not simulating this! ;) Courtesy of *Big Bad Bar Crawl from Game Jam 2013*.

Making the floor plan of the bar

An easy way to make a bar is by dividing it into tile (say, of 1x1 meter), and have everything move from tile to tile. To make this we need to define the size of the tile in pixels:

tile_size = 60

tl2 = int(tile_size/2)

And define that the floor plan of the bar is 12 tiles wide and 8 tiles high.

bar_width = 12

bar_height = 8

bar = np.zeros((bar_width, bar_height), dtype=np.int)

These five lines are all you need to create an empty bar. Now let's put a bar into it!

bar[0][4:8] = 1 # A value of 1 is a bar

To be precise, we but a bar 0 tiles away from the left border (see the [0] part), and 4 to 7 tiles away from the top border (see the [4:8] part). Next, let's add a few tables:

bar[5][3] = 2 # A value of 2 is a table

bar[5][7] = 2 # A value of 2 is a table

bar[7][5] = 2 # A value of 2 is a table

bar[9][3] = 2 # A value of 2 is a table

bar[9][7] = 2 # A value of 2 is a table

Just to be clear, when we visualize this later the floor plan will look like this:

With the brown area symbolizing the whole establishment, the white area the counter to order drinks, and the gray squares being tables.

Next up, we want to simulate the movement of drunk people. For this, we can use the random step function from the first Random Walk tutorial. However, we need to make two tweaks:

  1. We don't want people to walk outside of the bar (so 0<x<bar_width and 0<y<bar_height for each person).
  2. We don't want people to walk on top of the bar or the tables (so we cancel a move if the destination x and y coordinate of a person has a value greater than 0 on our floor plan.

Having made these two tweaks, we then get the following step function:

def random_step(x, y):

direction = random.randint(0,3)

newx = x

newy = y

if direction == 0 and x > 0 and bar[newx-1][newy] == 0:

newx -= 1

if direction == 1 and x < bar_width-1 and bar[newx+1][newy] == 0:

newx += 1

if direction == 2 and y > 0 and bar[newx][newy-1] == 0:

newy -= 1

if direction == 3 and y < bar_height-1 and bar[newx][newy+1] == 0:

newy += 1

return newx, newy

Before we can define the wandering people, there is one more preparatory thing we need to do. Since people tend to order drinks next to a bar, and sit next to a table, we need a function to check out whether they are next to something:

def near_object(x,y,i):

if x > 0:

if bar[x-1][y] == i:

return True

if x < bar_width-1:

if bar[x+1][y] == i:

return True

if y > 0:

if bar[x][y-1] == i:

return True

if y < bar_height-1:

if bar[x][y+1] == i:

return True

return False

Here x and y are the position of a person, and i indicates the type of object we're checking. You can set it to 1 to check if a person is next to a bar, or 2 to check it a person is next to a table :).

Making the Bar visitors

Okay, with all that in place we can define the people visiting the bar.

class Person:

Each person will have:

  • An x and y location in tiles.
  • A radius, indicating the girth of the person.

  • A “food” indicator, with 0 being very hungry and >50 being fully nourished.

  • A “happiness” indicator, which will increase when they're chilling out next to a table.

In code, this looks as follows:

def __init__(self, x, y):

self.x = x

self.y = y

self.radius = tl2

self.food = 5

self.happiness = 0

Now every person will do something at every time step. They may:

  • Get food if they're next to a bar and they're not fully nourished.
  • Chill our if they're next to a table and they're not getting hungry.
  • Wander around randomly otherwise.

To code this up, we make a step function as follows:

def step(self):

Storing the last locations first for the undrawing:

self.lx = self.x

self.ly = self.y

And assuming that at every step, a person will lose 1 food (being in a bar burns calories, right? ;)).

self.food -= 1

We then check if there is a bar or table next to the person.

bar_nearby = near_object(self.x, self.y, 1)

table_nearby = near_object(self.x, self.y, 2)

If next to a bar, give 10 food.

if bar_nearby:

self.food += 10

And if next to a table, chilling out will give 1 happiness.

if table_nearby:

self.happiness += 1

Lastly, check whether the person is next to a table and not hungry:

if table_nearby and self.food > 0:

pass

... or next to a bar and not fully nourished:

if bar_nearby and self.food < 50:

pass

in all other cases, the person starts a random movement!

else:

self.x, self.y = random_step(self.x, self.y)

Placing the persons in the bar

This section is super short! Just do:

Persons = [Person(5, 5), Person(4, 2), Person(3, 5), Person(2, 6)]

This places 4 persons in the bar, at coordingates (5,5), (4,2), (3,5) and (2,6), all places where there are no tables and outside the counter area.

Making the main simulation and visualization loop

Okay, with all the pieces in place, we can now make the main loop. I'll do the drawing within the main loop, as I'm only drawing simple rectanges and circles anyway :).

First of all, the simulation will keep going until you close it:

while True:

Second, we draw a brown area indicating the bar as a whole.

pygame.draw.rect(screen, (32,32,0), pygame.Rect(0, 0, bar_width*tile_size, bar_height*tile_size))

Third, we draw the floor plan.

for x in range(0,bar_width):

for y in range(0,bar_height):

xpos = x*tile_size

ypos = y*tile_size

To draw the bar, I put a white rectangle on each tile.

if bar[x][y] == 1:

pygame.draw.rect(screen, (255, 255, 255), pygame.Rect(xpos, ypos, tile_size, tile_size))

To draw tables, I put a gray rectangle on each tile.

if bar[x][y] == 2:

pygame.draw.rect(screen, (128, 128, 128), pygame.Rect(xpos, ypos, tile_size, tile_size))

Fourth, we draw all the persons on the floor plan.

for k,p in enumerate(Persons):

Before we draw them, we move them around if needed.

p.step()

And then we draw them. To draw people, I use circles, and I use a very simple equation to give each person a slightly different color. The color of each person (RGB) is ((60*k)%255, int(255-60*k)%255, (k%2)*128), where k is the index number of the person (0,1,2 or 3).

# draw person

pygame.draw.circle(screen, ((60*k)%255, int(255-60*k)%255, (k%2)*128), (int(p.x*tile_size+tl2), int(p.y*tile_size+tl2)), int(p.radius), 0)

Lastly, after all drawing is done we reveal the whole thing to the screen and sleep for a second.

pygame.display.flip()

time.sleep(1000 / 1000)

All this code should result in an animation, that looks roughly like this:

Closing thoughts

Although it may look basic, this is how you make a bar! To complete the tutorial, I'll share three more things:

  • A few ideas for extending / improving the code.
  • Full code and repl.it version of the tutorial.
  • And lastly for the subscribers, a few tips on how to use graphics for the people and the bar!

Thanks a lot for your time and see you around next time!

Previous: Bouncing Ball

Next: Pub Simulation

Appendix 1: ideas for extending and improving the code

You may well have many ideas to extend the code yourself, but here are a few ideas from my side that may be reasonably simple for you to put in the code:

  • The persons can currently move on top of each other. You could write and add a function that checks whether persons are about to move on top of another person, and cancel any movement if this is the case. This is called collision detection, and is very common in games.
  • You can add more people. :)
  • You could add an exit, and make a rule that people try to leave the bar once they have reached a certain amount of happiness.

I'm sure you can think up loads more stuff, but at least this is a start :).

Appendix 2: Full code and repl.it version

Here is the full code:

import pygame

import time

import numpy as np

import random

pygame.init()

width, height = 800, 600

backgroundColor = 0, 0, 0

screen = pygame.display.set_mode((width, height))

screen.fill(backgroundColor)

tile_size = 60

tl2 = int(tile_size/2)

bar_width = 12

bar_height = 8

bar = np.zeros((bar_width, bar_height), dtype=np.int)

bar[0][4:8] = 1 # A value of 1 is a bar

bar[5][3] = 2 # A value of 2 is a table

bar[5][7] = 2 # A value of 2 is a table

bar[7][5] = 2 # A value of 2 is a table

bar[9][3] = 2 # A value of 2 is a table

bar[9][7] = 2 # A value of 2 is a table

def random_step(x, y):

direction = random.randint(0,3)

newx = x

newy = y

if direction == 0 and x > 0 and bar[newx-1][newy] == 0:

newx -= 1

if direction == 1 and x < bar_width-1 and bar[newx+1][newy] == 0:

newx += 1

if direction == 2 and y > 0 and bar[newx][newy-1] == 0:

newy -= 1

if direction == 3 and y < bar_height-1 and bar[newx][newy+1] == 0:

newy += 1

return newx, newy

def near_object(x,y,i):

if x > 0:

if bar[x-1][y] == i:

return True

if x < bar_width-1:

if bar[x+1][y] == i:

return True

if y > 0:

if bar[x][y-1] == i:

return True

if y < bar_height-1:

if bar[x][y+1] == i:

return True

return False

class Person:

def __init__(self, x, y):

self.x = x

self.y = y

self.radius = tl2

self.food = 5

self.happiness = 0

def step(self):

self.lx = self.x

self.ly = self.y

self.food -= 1

bar_nearby = near_object(self.x, self.y, 1)

table_nearby = near_object(self.x, self.y, 2)

if bar_nearby:

self.food += 10

if table_nearby:

self.happiness += 1

if table_nearby and self.food > 0:

pass

if bar_nearby and self.food < 50:

pass

else:

self.x, self.y = random_step(self.x, self.y)

Persons = [Person(5, 5), Person(4, 2), Person(3, 5), Person(2, 6)]

while True:

pygame.draw.rect(screen, (32,32,0), pygame.Rect(0, 0, bar_width*tile_size, bar_height*tile_size))

for x in range(0,bar_width):

for y in range(0,bar_height):

xpos = x*tile_size

ypos = y*tile_size

if bar[x][y] == 1:

pygame.draw.rect(screen, (255, 255, 255), pygame.Rect(xpos, ypos, tile_size, tile_size))

if bar[x][y] == 2:

pygame.draw.rect(screen, (128, 128, 128), pygame.Rect(xpos, ypos, tile_size, tile_size))

for k,p in enumerate(Persons):

p.step()

# draw new circle

pygame.draw.circle(screen, ((60*k)%255, int(255-60*k)%255, (k%2)*128), (int(p.x*tile_size+tl2), int(p.y*tile_size+tl2)), int(p.radius), 0)

pygame.display.flip()

time.sleep(1000 / 1000)

And a repl can be found here.

Read more...

With UK Parliament prorogued yesterday night, many official debates are suspended, while the spectre of No-Deal is looming. I am interested in this because I live in the UK, I am an EU Citizen, and I do research in EU projects. And yet, I not a Brexit expert and I am of course prone to be biased for all these aforementioned reasons.

Now there are many experts on Brexit, and you won't struggle to find them in the media deluge that has flooded us all in the past couple of years. In particular, I found the Brexit diagram by Jon Worth a very helpful tool to have an idea of what's coming next:

Brexit diagram version 18 created by *Jon Worth*. License: CC-By SA.

I think any seen person who keeps track of Brexit should follow this guy, as especially these diagrams very nicely cover all the details of the whole thing.

But in all these detailed day-to-day discussions and rollercoastering between astonishment and outrage, it is sometimes easy to forget the big picture. So what I aim to do here is to sketch that big picture in a simple way, at least from my personal perspective.

That simplistic picture consists of three pieces:

  1. UK's position in any negotiations with the EU.
  2. UK's position in a world where it cannot trade (easily) with the single market.
  3. The Irish border.

Viewpoint 1: UK's position in any negotiations with the EU

Whether you can win a negotiation depends on your strength relative to the other negotiating party, and in this case I would argue that economic power is quite a good indicator of that. Here's what that looks like:

  • GDP United Kingdom: €2392 billion (2018)
  • GDP European Union (with UK): €15890 billion (2018)
  • GDP European Union (without UK): €13498 billion (2018)

Source: *Eurostat*.

And in a simple pie chart showing the power ratio this would look as follows:

Now actually the UK GDP as percentage of the full EU GDP (15.1%) is actually decreasing since 2016, when it was 16.1% GDP. By the way, the EU accounts for 40% of the UK's exports, and the UK only for 8% of the exports of the EU (including intra-EU exports, see fullfact).

So any negotiation is taking place on a strength difference ranging between 5-to-1 (if you look at export percentages) to 6-to-1 (if you look at GDP). This makes me think that any aggressive threats from the Johnson government can easily be ignored by the EU, as he's waving a chopstick, not a baseball bat here. To make matters worse, many businesses are already moving jobs and capital out of the UK, undermining its negotiating position while the negotiations are still ongoing. Conclusion: I think that any negotiations that assume equal negotiating positions are not going to lead to anything useful here.

Viewpoint 2: UK's position in a no-deal world

Okay, so the leverage with EU is weak-ish, but what about the rest? In the map below I have colored the UK in blue, and all the countries that are not in the Single Market in green:

Map of the UK and non-Single Market countries. Apologies if I miscolored anything, it was a manual job.

Now far a country like Greece or Bulgaria there would be quite a few good trading opportunities nearby, but unfortunately due to its geographical location this is not the case for the UK. The closes possible trading partners either lack in size (Andorra, Monaco), in population (e.g., Greenland), or are just quite far away (Morocco, Russia, Turkey). So a UK ignoring a Single Market would be a lonely state of affairs indeed, and surely the countries in white would make easy pickings of Team Blue if this were to be a game of Diplomacy.

Viewpoint 3: The Irish Border

On this topic, my personal view is that the Irish border matter is not simple at all.

Apparently people and goods are to move freely between Ireland and Northern Ireland. Now with the UK and Ireland both in the EU (single market + freedom of movement) this is all easily sorted. If the UK and Ireland were both outside of the EU it would also be easily sorted with a bilateral deal. But a No-Deal exit would leave the UK outside the EU and Ireland inside of the EU and the single market.

Given all that, any free movement of goods and people between the UK and Ireland would mean exactly the same for the UK and the EU, effectively wedding the UK to the single market after all. Except...if you choose to compromise on freedom of movement and goods between Northern Ireland and the UK, but that would result in a border within the UK. Now I am sure that there are many things I am overlooking here, but given all the complications I think it's safer to assume a mess here after No-Deal Brexit than some trivial solution that miraculously descends from the sky.

Closing thoughts

If anything, I felt it's useful to jot down my three main viewpoints, because it's handy and easy to refer to them when I need to later on :). I think the reality is quite harsh for No-Deal Brexit, so I'm in favour of keeping things simple, and just retain EU membership by revoking Article 50. For the subscribers I'll close off with a small remark about a competitor for the current PM.

Credits

Header image courtesy of Petr Kratochvil (CC-0 license).

Read more...

To test PyGame with Repl.it, I will simulate a bouncing ball. This is a bit different than what I had previously in mind, but since I'm using a new approach I'd like to start simple and then see if it works well enough to do something more fancy :).

The mission is simple: simulate a bouncing ball, as simple as reasonably possible.

What libraries do we need today?

So, this is the first Small Sim installment using PyGame. I chose to switch to PyGame, because the image generation using the previous pillow library was quite buggy on Firefox when making animated gifs, and neither pillow not matplotlib have good interaction support on repl.it (if at all). However, PyGame does have that support, and while doing some quick tests yesterday I found that the visualization is a bit slow, but at least a little bit more reliable than with other things. Conclusion: today we need PyGame. To enable this, you have to create a repl in the “Pygame” language (not Python, even though we're obviously writing Python):

Image courtesy of repl.it.

You then need to add the following libraries at the top of your Repl:

import pygame

import time

Starting up PyGame is not too complicated. It requires (1) an initialization function and (2) creating a creen with a width, a height and a backgroundcolor (0,0,0 is black and 255,255,255 is white):

pygame.init()

width, height = 800, 600

backgroundColor = 0, 0, 0

screen = pygame.display.set_mode((width, height))

screen.fill(backgroundColor)

Building the Bouncing Ball

Now for bouncing balls we are going to have to do a little physics. When you drop a ball from high altitude, its downward velocity will increase every second. In an idealized environment with no wind, air resistance etc. that velocity will increase by -9.81 meters per second, which is the gravitational constant G. Of course, in the real world there is a bit of air resistance, and I introduce a parameter e to introduce it, with 1.0 being no drag and 0.0 being so much drag that nothing can move. It's inversely related to a physical quantity called the drag coefficient.

In code, setting these things is pretty simple:

e = 0.99 # air resistance coefficient

g = -9.81 # gravity coefficient

Next up is creating the ball. Now since we will be changing the ball in all sorts of ways, I decided to make a class for it, with attributes that contain its position in two directions, velocities in two directions, and its radius. Since we do only a simple tutorial, the ball doesn't deform in any way here (perhaps one day...).

class Ball:

def __init__(self, x, y, vx, vy):

self.x = x

self.y = y

self.vx = vx # x velocity

self.vy = vy # y velocity

self.radius = 10

And you can make an actual ball using this line:

b = Ball(100.0, 100.0, 1.0, 0.0)

This ball starts at x=100, y=100, and has a velocity of 1 pixel/“meter” per second in the x direction.

Now that we have the ball, what's next? Moving it! To do so, we define a function which moves the ball for a length of time in seconds called dt.

def step(ball, dt):

During that period, we drift the ball forward, according to the x and y velocities that we have set on it. To do that you use two very similar formulas:

ball.x = ball.x + dt*ball.vx

ball.y = ball.y + dt*ball.vy

But as mentioned before: something that falls will fall faster and faster. So, we need to the velocity too. To account for the gravity effect we can use:

ball.vy -= dt*g

And to apply the air resistance that we set we can use:

ball.vx *= e**dt

ball.vy *= e**dt

Congratulations! You now have a dropping ball... that will leave your screen as it will never bounce...

Source: *Shining Source*, one of the first websites I started (now maintained by superior beings), with a logo that featured a non-stop pulsating “bouncy ball” in its early incarnations.

So how do we do the bounce? Well, we need to figure out when to do it, and how to do it.

  • When: probably when we think the ball touches the bottom of the screen. At that point, the y coordinate of the center of the ball will be equal to the height of the screen minus the radius of the ball:

if ball.y + ball.radius > height:

  • How: well, the simplest way I can think of that is not completely ridiculous is to (a) reverse the speed in the y direction, and (b) set the position exactly equal to the bouncing point (so that at least it doesn't go through the floor:

ball.vy = -ball.vy

ball.y = float(height) - ball.radius

Bouncing function done!

Building and visualizing the bouncing ball simulation as a whole

As in previous occasions, we again just have to make a loop that does the same thing over and over again: increment the simulation by a step, and draw the thing.

In PyGame we don't draw to an image, but we draw to the screen in real-time. Because of this, the performance can be quite slow if you choose to redraw the whole screen each frame. What I do instead is to just draw over any previous circle (located at coordinates lx and ly) with the background color, and then draw a new circle straight after that. To do so, we need to define lx and ly outside of the main loop:

lx = 0 # x coordinate of last circle

ly = 0 # y coordinate of last circle

And load an image for the Ball. In this case, I took a basketball image from Wikimedia and reduced it in size:

Image courtesy of *Mazenl77*.

You load it using:

ball_img = pygame.image.load('ball.png')

...and in the main loop, we overwrite the old image with a circle (optional) and then write the image:

while True:

# overwrite old circle with bg color (optional)

pygame.draw.circle(screen, backgroundColor, (lx, ly), int(b.radius), 0)

# draw new circle

screen.blit(ball_img, (b.x-b.radius, b.y-b.radius))

Note that I don't overwrite the old image in my examples, because in that way the images give a more 'animated' look.

We then have to update the coordinates of the circle last drawn to the one we just drew:

lx = int(b.x)

ly = int(b.y)

Display the screen:

pygame.display.flip()

Move the simulation forward by a step (I took a step size of 0.25 seconds, which works okay-ish.

step(b, 0.25)

And pause everything a bit so that the frame rate doesn't become ridiculously high.

time.sleep(25 / 1000)

Now obviously I'm not writing animated .gifs anymore (I will look for a good screen recording tool soon), but your animation should have images like this:

Closing thoughts

Once you have all that, you can press play, and a simple bouncing ball should appear! Admittedly PyGame can look a bit glitchy in places, but unlike Pillow it does appear to work reliably on all browsers that I've tested, irrespective of whether you've run it before or not.

There are a few more things I want to share, namely a few variations you can try to research and implement yourself, the source code and Repl.it address, and for subscribers a link to a slide set where I first started tinkering a bit with this particular problem.

Update 16-09-2019: I modified the tutorial to make it a bit more visually appealing.

Previous: Simulating Living Populations

Next: Simulating a Bar

Appendix A: Variations

This tutorial is very simple, but I think in its simplicity it does make for a nice launchpad to experiment with more complicated features. The possibilities are nearly endless, but here are some first things you could play around with:

  • The current ball has no velocity to begin with, but if you want to model a goal kick or a cannonball, try giving it some velocity in the x direction, when you create the ball object.
  • In terms of accuracy, the code is not perfect because the step() function uses a very simple so-called 1st order Euler integration function. It is quite easy to do better than that. For instance, have a look at writing a leapfrog integration function (which is second order), or a Runge-Kutta function (which is fourth order). Or, if you prefer to spend more time waiting and less time thinking and coding, you can just reduce the time step size from 0.25 to something smaller.
  • Now I've set the value of g to -9.81 m/s to reflect an earth-like environment. However, in many games the value is very different. For instance, in the old-school Super Mario games the value is in the range of 70-110. You may want to play around with g a little to see how it affects your animation :).

Appendix B: Code and Repl

The whole code is here:

import pygame

import time

pygame.init()

width, height = 800, 600

backgroundColor = 0, 0, 0

screen = pygame.display.set_mode((width, height))

screen.fill(backgroundColor)

e = 0.99 # air resistance coefficient

g = -9.81 # gravity coefficient

class Ball:

def __init__(self, x, y, vx, vy):

self.x = x

self.y = y

self.vx = vx # x velocity

self.vy = vy # y velocity

self.radius = 10

def step(ball, dt):

ball.x = ball.x + dt*ball.vx

ball.y = ball.y + dt*ball.vy

ball.vy -= dt*g

ball.vx *= e**dt

ball.vy *= e**dt

if ball.y + ball.radius > height:

ball.vy = -ball.vy

ball.y = float(height) - ball.radius

#print(ball.x, ball.y, ball.vx, ball.vy, e**dt)

b = Ball(100.0, 100.0, 1.0, 0.0)

lx = 0 # x coordinate of last circle

ly = 0 # y coordinate of last circle

ball_img = pygame.image.load('ball.png')

while True:

# overwrite old circle with bg color

pygame.draw.circle(screen, backgroundColor, (lx, ly), int(b.radius), 0)

# draw new circle

screen.blit(ball_img, (b.x-b.radius, b.y-b.radius))

lx = int(b.x)

ly = int(b.y)

pygame.display.flip()

step(b, 0.25)

time.sleep(25 / 1000)

And you can find the Repl here.

Read more...