Blog

Marble Odyssey - A Journey

by Christopher Thomas 16 Sept, 2019
When I started coding on Marble Odyssey, I worked in a pretty straight ahead manner. Much of the code I had never had to write before, this is my first video game. How do you chain together many many elements to make a "game"? For instance, animating lights, particles, materials and so on. Sometimes something comes out of left-field, something your not quite expecting to be tough, and for me, one of those things is the PAUSE feature. Think about it. Marble Odyssey uses a physics based engine for ALL game-play. None of it is faked, and so, when you pause the game, those physics just need to STOP. Even more important, when you un-pause the game everything that was moving before, needs to move again. So you need to not just stop physics, but also store the state of ALL physical objects, and re-instate that state on un-pause. See, not that trivial... Next, lets say you are animating some elements, like the intensity of a light, the Emission(glow) of a material, or the position of an object. Again, those animations MUST stop on a dime, and then re-start when you un-pause. This means you must not only write all your animations, but also write them in a way that can handle being stopped. EVERYTHING has to be written in a pause capable manner. Bear this in mind also, a single effect in-game, can often take the animation of a number of elements to bring them to life. For instance, an explosion could consist of a sphere that grows in size. That sphere would have a glowing material on it that gets brighter and then fades away as the explosion happens. That glowing material really needs a light to go with it, to make the explosion appear to emmit light. And if course you need sounds effects for that explosion as well eh? Oh yeah, AND particles of course! ALL of these elements must be pausable, and pause when they are requested to. So, how are they requested? Well, there are two scenarios, and these kind of force you into two approaches. CoRoutines in Unity, are loops, and you can use these loops to change values over time to produce an animation. So the first approach is you keep an eye on if the game is paused in ANY CoRoutine loop that can happen in game. If the game is not paused, the values progress, the animation happens. If pause is in effect, you skip updating and you get a pause in the animation. Great! Next, what about Audio or Particles. In Unity you don't manually mange the playing of an audio clip or a particle system frame by frame. These play themselves once kicked off and then stop at their natural end, or loop. So, you then send out events from the Game Manager on Pause/Un-Pause, and ALL objects have to manually pause all Audio or Particles that were playing, and un-pause these when Pause is released. And of course all of this is in addition to storing the physics properties of ALL physically simulated objects in-game. You see, you really DO need to think quite a lot about PAUSE and getting it to work in your game engine.
25 Jul, 2019
So, how do you go about writing AI for a marble? Well, the first thing I did was look into the tools that Unity offered out of the box. Now it has a pathfinding feature, and an AI agent to follow that path. But.. in truth, I could only really use the pathfinding element of that feature set. Why? Well, it kind of assumed that any agent would need to TURN towards a nav point on a path and then move towards it. Now, that's not quite how our marbles move. So I could make use of Unity's feature to create a path between where the bad guy IS and where it wants to be. And when it does this, it creates a set of nav points, and if you move towards each of these in turn, then you will in time reach your target. But the question begs, where should the baddy be heading for? Does it know about the player? And if it does know about the player, how does it go about getting to them, and then, what about attacking. Try and think about all of those points, as I did, and it suggests a number of problems. Internal Mental State Each Baddy needs a state model. This means, on a basic level that they have a given mental state, like resting, and then something will cause the baddy to change to another mental state, like a pursuit, or attack. So I decided to create a model for each Baddy type, that reflected all of the mental states that they might be in. Then this model has a kind of stack, of arousal, with the baddy going to a higher level when they sense the player, or dropping back if the player escapes. The Patroller As a patrolling type of baddy would be obviously useful, and would probably be the most flexible, I hit this first. It would obviously have a patrolling state, which could escalate into pursuit IF it detected the player. And if it caught up with the player, it could go into Attack mode. Exactly what the attack would be, I'd think about later. Senses Now, how does a baddy sense you? They can see, and I suppose, hear? Seeing depends on gaze, so I had to write a system that mimicked sight, including line-of-sight, field-of-view distance, and view-blocking structures. Then I tuned this sense to be less than perfect. Its easie to code AI to be perfect, and the real skill is in slowing them down, and making them fallible, like the player. Once this was working, I added hearing. Which turned out to be something of a pain. Sounds played in-game are heard by the player through speakers or headphones. But they have no real existence in the AI world. So next you have to create sound events for key sounds, have the baddy possibly hear these and again tune these so hearing works in a realistic manner. A Sum that is more than its parts When these are all put together, we get the illusion of a GHOST IN THE MACHINE . Our little Baddy marble appears to be alive. It does it's patrol, looking around for you, and listening for odd sounds. And if it hears you, or sees you, it gets miffed and heads off in pursuit. Once it gets within attack range, it switches to attack mode, and then Boom! Yes Boom, the first attack is an energy bomb, as this was the easiest attack type I could think to code as a starting point. All of this took a good month or so to write, with each stage building towards a believable result. I was very worried the result would be poor. But in the end, it turned out to actually be pretty decent. It's not perfect, the baddies make mistakes, but I actually like this, it makes them fallible, even endearing to a degree. The key thing is, it WORKS as a whole system, and its flexible enough to be built upon. Now that we have SOME baddies in-game, the focus switches back to many other elements, but the baddy will receive more art and coding love in the months ahead.
by Christopher Thomas 09 Sept, 2019
So, I reached a juncture with the game, I had shown it to a number of players, and these generally were fans of another marble based game (which shall remain nameless..). I received quite a lot of feedback, and much of it felt pretty negative. However, reading between the lines, I kind of felt there was this common theme to the feedback. They said Marble Odyssey is not good because of feature X , and that's because feature X needs to be more like the other game . And believe me, I heard this a number of times. How the marble jumped was wrong, how fast it moved, it was too slow, the marble did not turn fast enough, how heavy it felt, puzzle levels were not a good thing, faster levels were. You get my drift So, it got me to thinking and my thoughts posed this pretty fundamental question to myself and the future path of the development of the game. Should I listen to these points, tweak away, and in so doing make my game into that other game? Of course, the answer was NO! That game already existing, no one needed a knock off of it. Sure, I could absorb some of its features. As we all had of Marble Madness. But a new game was needed, not a shallow copy! So, if I'm not going to make my game more similar, then I had to make it LESS similar. Vive la difference! So, I thought about it, and some levels having a slower pace, was IMHO a good thing, variety and all that. And that other game had zero bad guys. So.. I set about thinking on how bad guys were going to work in Marble Odyssey, and I also had a quiver of fear. You see, I'm a late developer in terms of coding, and here I was thinking about writing my first AI. Gulp! But, then, I had never written a game, and Marble Odyssey is IS a working game, so, maybe writing AI would work out?
by Christopher Thomas 21 Jan, 2019
Early in the design of Marble Odyssey, we decided to follow a look that would be more photo-realistic than not. The reason for this was, we wanted our marbles to be a reasonable representation of the real thing. Now real marbles are often made of clear glass, with refraction. We know from our VFX experience that reflections are SUPER dependent on their environment. This meant we had to create or source at least one, or more high-quality Reflection maps, for use in our environments. Being an Indie game, it means that certain aspects of Marble Odyssey have had to be assembled from off the shelf components, we just do not have the man-hours to create everything. So, we sourced a set of synthetic Reflection maps. By synthetic, I mean they are not derived from real-world photographs, but rather from CG renders of various simulated cloudscapes. The advantage of this was price vs variety i.e. we could get a LOT of maps for a reasonable outlay. These maps had clear horizons, with no trees or other elements that would not work in our game. The BIG downside to these maps was, they were all rendered in Low Dynamic Range (LDR). What this means is, that although the file format they are provided in EXR supports High Dynamic Range (HDR), each of the maps luma range was in fact from 0 - 1, with 1 being what we think of as white. Why is this bad? Well, if you expose your scene lighting down, you will find that your environment maps Sun, which is usually white, will appear in-game as light grey. This is really bad. Its made worse in that when you see the same sun reflected in marbles or other surfaces the same issue appears. Let's take another example. If you have a perfectly mirror snooker ball, let's say a black one. Its reflection of the Sun would appear as white. That's despite the fact it's only reflecting back maybe 20% of the environments values. But with LDR, the Sun, as white, would appear as grey in the reflection. So, we need HIGH DYNAMIC RANGE environments to rectify this. So here is how we did this. We take an existing LDR EXR cube map, that represents our scenes reflections. And we load it in Photoshop. Bear in mind, this is a EXR so it will load as a 32bit per channel bitmap, even though its only really making use of 8bit colour really. Here, we duplicate the base map 7 or so times, to create 8 layers in total. On each of those new layers, we colour correct it, getting successively closer to black, so we slowly isolate only the LDR maps highlights. The 7th layer then is totally black apart from the Sun and its halo. Being LDR, quite often the Sun and its Halo are both white, so this becomes one big blob. But we can guess where in there the Sun actually is. Next, we pick a colour in the colour picker, with a Hue that matches our scenes sun i.e. white-yellow at mid-day, and tend more to be strong yellows, oranges and reds in sunset environments. Being a 32bit bitmap, we can choose an exposure level for that colour, and as this will be our Sun, we go for an exposure of 5x - 7x. This means the Sun will be 5x to 7x brighter than White. We then apply this colour as a filled circle, where our sun would be on the 7th layer. What this layer gives us, is a Sun that when the env map is darkened to 20% in reflection or scene exposure, the Sun will still appear as white. Think about it numerically..... White = 100 luma 5x White = 500 luma 20% can be thought of as 0.2 as a multiplier... So if we multiply our 500 luma, by 0.2, it becomes 100 luma, which is till White! Now, with this done, all we need to do is make all 7 layers ADDITIVE in comp mode. This means each layer ADDS its values to the layer below. And this means that each successive layer adds less and less luma, BUT this is more and more focussed on where light actually was in the original LDR image. The result is a new image, where the sky itself is a little brighter than before, but where the clouds, the cloud highlights, and especially the sun and its halo are much brighter. The halo probably has brightnesses of 3x or so, the Sun is 7x, and the cloud highlights are more like 1.5x -> 3x. Now, we process this new image and take it back into our game engine. In-game, our buffed environment now comes alive! Its reflections now are much more photo real and punchy. Metals look much more realistic, and our entire lighting model changes. Hoorah! Baked lighting, using these maps will now have MUCH more contrast, as the sky now has much larger ranges of luminosity. This means bounce light and fill light from the sky will have much more effect. Also, BLOOM on our cameras lens, which makes objects look like they are glowing, is now MUCH more controllable and realistic. You can dial Bloom so it only happens on luma above 2-3, and this tends to be lights, and especially your Sun, with its 5x - 7x luma. This means you ONLY get lens Bloom where it makes sense, and when you get it, its much more effective. Was it worth the effort? Well, its one of those things you may not even be aware of. But certainly to our eye, it certainly was!
by Marbalista 04 Jan, 2019
My own approach to designing anything is to start with comparable designs or products, to to make note of all of the elements that I both like and dislike. After all design on a simple level is a specification and then a set of decisions on how you will meet that spec. And then of course, there is a lot of noodling , revision and iteration before you have a "finished" design. Having decided to make a marble based game, I decided to look at the grand daddy, Marble Madness, and to see what I liked in their approach and of course also disliked... Likes I liked the intuitive way the marble is controlled with an analogue device, a rollerball on the arcade machine. I liked the senes of peril as you got close to the edge of a drop or being hit by a bad guy. I liked the fluid areas of the game where you could move at speed and kind of slalom your way across platforms, hazards and baddies. I liked the Escher like isometric level designs. A limitation of the time, but still a nice clean look. The grid helped game-play. Dislikes It felt overly difficult to control, and quite frustrating as a game experience. The time-limits made completing many of the levels near impossible. The ramp up in difficulty on the levels was really steep. It got crazy hard, very fast. If you got your speed up, you would tend to then fly off the platforms with your inertia. It was very frustrating that you died having only fallen a small distance. It was frustrating, that you could not jump from one part of the level to another. It felt like you should be able to. It was frustrating that you had a top speed, and could go no further. So there we go. It is clear that there are some basic elements there that we should try and preserve in the Likes, and a number of elments that we should address in the dislikes. Those being my thoughts, here are the basic premises I put forward for our game. Control will ideally be via an analogue controller, something like an XBox or PS4 joystick. Your marble cannot die in normal game-play. Only by falling out of bounds of the defined playfield. You can Jump You can Brake You can Turbo Jumping, Braking and Turbo can all be removed from the player, allowing for difference play-styles on some levels. Jumping, Braking and Turbo should have some kind of limits to their use. Levels would be a mixture of 2D mazes, akin to MM, but would also feature hill climbs, races and much more. Levels would feature a time to beat, but if you did not beat it, that was ok. You'd lose points but not die. So, let me explain some of the points above. The POWERS as I started to call them, Jump , Brake and Turbo , would allow for many more play-styles than in say Marble Madness. It had what were, effectively 2D mazes. If you tried to drop from one area to another, you died, so you were really restricted to rolling over surfaces. Air time was VERY perilous and would tend to end in you cracking and dying. In Marble Odyssey, it would make perfect sense to roll up a set of slopes, but also to take short cuts by Jumping where you could. And if you fell, you'd lose time, but not actually die. Jumping is based on friction, you cant jump well on ice (try this at a local ice rink...). Brake , would allow you to stop near instantly, depending on speed of course, meaning you could slalom through areas, but also stop dead, and reverse much more quickly on very serpentine, tight areas. Brake should NOT work so well on slipery surfaces, such as ice. And Turbo completed the set. You could accelerate to top speed quickly. But... to make it have downsides, we introduced turbo-lag, so the turbo kicks in say 500ms after activating it. And it would be powerful, so really not to be used on small ledges, which high up. Again, Turbo requires friction, so turboing on ice would have mixed results. And to make things even more flexible, each of these would be a Power, to be collected with a pickup, or granted for an entire level. This means I could design levels where you had no powers, where you had some, or where some could be collected by the player. This would allow for much more flexibility in level design. If I wanted a fast level, but only at normal speed, I could take away the Turbo. And if I held back the Jump, then a player would only get airborn by using ramps. Of course, removing powers could prove to be frustrating. But if it allowed for more variety in level design and challenge, I hoped the trade-off would chime with our players. This would be a key part of my design mantra. Introduce pretty basic rules, but allow for flexibility, giving me and therefor the game more variety.
by Marbalista 27 Dec, 2018
Marble Odyssey is a game that was inspired by (though certainly not copied from) an 1980s classic called Marble Madness . Lets be clear, simply copying a game from the 1980s, especially an arcade game, for the modern player, well, it just will not work. Why? Well, games for the video arcades of yore were designed to be crazy hard, to literally (OK, not really literally, that would have been very wrong...) milk coins out of the average player at a fierce old rate. And Marble Madness certainly acheived this. It was mind bogglingly hard. But it was certainly fun, and it did spin off a number of close relatives in the 80s. So our game would require many changes in the basic assumptions of a marble game, set out by MM, to make sense as a PC or console game. People need a different challenge in the modern era. And thats what we set about producing with Marble Odyssey. In the posts that follow, we'll discuss exactly what those changes were, and the decisions that has driven them.
by Christopher Thomas 16 Sept, 2019
When I started coding on Marble Odyssey, I worked in a pretty straight ahead manner. Much of the code I had never had to write before, this is my first video game. How do you chain together many many elements to make a "game"? For instance, animating lights, particles, materials and so on. Sometimes something comes out of left-field, something your not quite expecting to be tough, and for me, one of those things is the PAUSE feature. Think about it. Marble Odyssey uses a physics based engine for ALL game-play. None of it is faked, and so, when you pause the game, those physics just need to STOP. Even more important, when you un-pause the game everything that was moving before, needs to move again. So you need to not just stop physics, but also store the state of ALL physical objects, and re-instate that state on un-pause. See, not that trivial... Next, lets say you are animating some elements, like the intensity of a light, the Emission(glow) of a material, or the position of an object. Again, those animations MUST stop on a dime, and then re-start when you un-pause. This means you must not only write all your animations, but also write them in a way that can handle being stopped. EVERYTHING has to be written in a pause capable manner. Bear this in mind also, a single effect in-game, can often take the animation of a number of elements to bring them to life. For instance, an explosion could consist of a sphere that grows in size. That sphere would have a glowing material on it that gets brighter and then fades away as the explosion happens. That glowing material really needs a light to go with it, to make the explosion appear to emmit light. And if course you need sounds effects for that explosion as well eh? Oh yeah, AND particles of course! ALL of these elements must be pausable, and pause when they are requested to. So, how are they requested? Well, there are two scenarios, and these kind of force you into two approaches. CoRoutines in Unity, are loops, and you can use these loops to change values over time to produce an animation. So the first approach is you keep an eye on if the game is paused in ANY CoRoutine loop that can happen in game. If the game is not paused, the values progress, the animation happens. If pause is in effect, you skip updating and you get a pause in the animation. Great! Next, what about Audio or Particles. In Unity you don't manually mange the playing of an audio clip or a particle system frame by frame. These play themselves once kicked off and then stop at their natural end, or loop. So, you then send out events from the Game Manager on Pause/Un-Pause, and ALL objects have to manually pause all Audio or Particles that were playing, and un-pause these when Pause is released. And of course all of this is in addition to storing the physics properties of ALL physically simulated objects in-game. You see, you really DO need to think quite a lot about PAUSE and getting it to work in your game engine.
25 Jul, 2019
So, how do you go about writing AI for a marble? Well, the first thing I did was look into the tools that Unity offered out of the box. Now it has a pathfinding feature, and an AI agent to follow that path. But.. in truth, I could only really use the pathfinding element of that feature set. Why? Well, it kind of assumed that any agent would need to TURN towards a nav point on a path and then move towards it. Now, that's not quite how our marbles move. So I could make use of Unity's feature to create a path between where the bad guy IS and where it wants to be. And when it does this, it creates a set of nav points, and if you move towards each of these in turn, then you will in time reach your target. But the question begs, where should the baddy be heading for? Does it know about the player? And if it does know about the player, how does it go about getting to them, and then, what about attacking. Try and think about all of those points, as I did, and it suggests a number of problems. Internal Mental State Each Baddy needs a state model. This means, on a basic level that they have a given mental state, like resting, and then something will cause the baddy to change to another mental state, like a pursuit, or attack. So I decided to create a model for each Baddy type, that reflected all of the mental states that they might be in. Then this model has a kind of stack, of arousal, with the baddy going to a higher level when they sense the player, or dropping back if the player escapes. The Patroller As a patrolling type of baddy would be obviously useful, and would probably be the most flexible, I hit this first. It would obviously have a patrolling state, which could escalate into pursuit IF it detected the player. And if it caught up with the player, it could go into Attack mode. Exactly what the attack would be, I'd think about later. Senses Now, how does a baddy sense you? They can see, and I suppose, hear? Seeing depends on gaze, so I had to write a system that mimicked sight, including line-of-sight, field-of-view distance, and view-blocking structures. Then I tuned this sense to be less than perfect. Its easie to code AI to be perfect, and the real skill is in slowing them down, and making them fallible, like the player. Once this was working, I added hearing. Which turned out to be something of a pain. Sounds played in-game are heard by the player through speakers or headphones. But they have no real existence in the AI world. So next you have to create sound events for key sounds, have the baddy possibly hear these and again tune these so hearing works in a realistic manner. A Sum that is more than its parts When these are all put together, we get the illusion of a GHOST IN THE MACHINE . Our little Baddy marble appears to be alive. It does it's patrol, looking around for you, and listening for odd sounds. And if it hears you, or sees you, it gets miffed and heads off in pursuit. Once it gets within attack range, it switches to attack mode, and then Boom! Yes Boom, the first attack is an energy bomb, as this was the easiest attack type I could think to code as a starting point. All of this took a good month or so to write, with each stage building towards a believable result. I was very worried the result would be poor. But in the end, it turned out to actually be pretty decent. It's not perfect, the baddies make mistakes, but I actually like this, it makes them fallible, even endearing to a degree. The key thing is, it WORKS as a whole system, and its flexible enough to be built upon. Now that we have SOME baddies in-game, the focus switches back to many other elements, but the baddy will receive more art and coding love in the months ahead.
by Christopher Thomas 09 Sept, 2019
So, I reached a juncture with the game, I had shown it to a number of players, and these generally were fans of another marble based game (which shall remain nameless..). I received quite a lot of feedback, and much of it felt pretty negative. However, reading between the lines, I kind of felt there was this common theme to the feedback. They said Marble Odyssey is not good because of feature X , and that's because feature X needs to be more like the other game . And believe me, I heard this a number of times. How the marble jumped was wrong, how fast it moved, it was too slow, the marble did not turn fast enough, how heavy it felt, puzzle levels were not a good thing, faster levels were. You get my drift So, it got me to thinking and my thoughts posed this pretty fundamental question to myself and the future path of the development of the game. Should I listen to these points, tweak away, and in so doing make my game into that other game? Of course, the answer was NO! That game already existing, no one needed a knock off of it. Sure, I could absorb some of its features. As we all had of Marble Madness. But a new game was needed, not a shallow copy! So, if I'm not going to make my game more similar, then I had to make it LESS similar. Vive la difference! So, I thought about it, and some levels having a slower pace, was IMHO a good thing, variety and all that. And that other game had zero bad guys. So.. I set about thinking on how bad guys were going to work in Marble Odyssey, and I also had a quiver of fear. You see, I'm a late developer in terms of coding, and here I was thinking about writing my first AI. Gulp! But, then, I had never written a game, and Marble Odyssey is IS a working game, so, maybe writing AI would work out?
Show More
Share by: