Welcome, Guest. Please login or register.

Login with username, password and session length

 
Advanced search

1412081 Posts in 69447 Topics- by 58486 Members - Latest Member: holdemech

June 26, 2024, 12:41:23 PM

Need hosting? Check out Digital Ocean
(more details in this thread)
TIGSource ForumsCommunityDevLogsDragon Attack - an arcade game about burning everything
Pages: [1]
Print
Author Topic: Dragon Attack - an arcade game about burning everything  (Read 1287 times)
Frozen Fractal
Level 0
**



View Profile WWW
« on: December 08, 2015, 06:22:23 AM »

Devlog entries are cross-posted from my blog. Best to subscribe there in case I forget to post them here!

I'm currently working on an improved version of my last Ludum Dare entry, Glauron. I sent that version to an HTML5 games portal (GamePix), where it’s now trickling in some beer money. However, some other portals refused it because it wasn’t performant enough, especially on mobile – and they were right. It seems that collision detection in Crafty.js is not exactly fast.

So I spent most of the past week porting the game to LibGDX, under the name Dragon Attack. It’s about 70% of the way towards being on par with the Ludum Dare version, and I’m making some things better as I go. In particular, Crafty.js doesn’t let you do additive blending, so drawing proper fire is nearly impossible:



The fire in Dragon Attack looks about a zillion times better:



Naturally, since this isn’t a game jam, and I plan to extend the game quite a bit, the code needs to be more solid and extensible. That’s part of the reason why the port is taking longer than the original. The other reason is that I’m learning Ashley as I go. This is the first time I use an entity component system (ECS), so naturally there’s a learning curve. It’s not rocket science, but figuring out the most effective way to get the job done still takes time.

You may also have noticed in the animations that the dragon moves differently. In Glauron, the dragon was controlled entirely from its head, and its body sort of trailed behind. This is why the head movement is so jerky. In Dragon Attack on the other hand, the dragon is controlled from the place its wings are attached. This makes for a smoother movement of the head (no sudden angle changes that break up the stream of fire), but does make him look a bit stiff. I loved the fluidity of the old dragon, so I will have to address that at some point, but this’ll do for now.

After I hit feature parity with Glauron, the plan is to add more content:

  • more enemies (crossbowmen, catapults, ballistas)
  • more buildings (towers, castles, cathedrals)
  • more powerups (hint: what was Smaug’s main defense in The Hobbit?)
  • more terrain types (plains, hills, mountains)
  • more decoration (trees, cattle)
  • more backdrops (night, storm, dawn)

This looks like a lot, but thanks to Ashley the engine is very modular, so I can create new things with little to no code, just by snapping components together. (In fact, maybe I will make it so that it doesn’t take any code, just JSON files.) The main effort will be in the artwork and the balancing. And hey, I can work on this fulltime now!

I’m planning to group this content into three or four “episodes”. The first will be free (and also published to browser game portals); the others will be available via in-app purchases. There may also be achievements and social integration (e.g. leaderboards shared with your Facebook friends).
« Last Edit: April 22, 2016, 12:48:57 AM by Frozen Fractal » Logged

frozenfractal.com | @frozenfractal | Devblog posts are cross-posted from frozenfractal.com/blog; subscribe there if you don't want to miss any!
marcgfx
Level 8
***


if you don't comment, who will?


View Profile WWW
« Reply #1 on: December 08, 2015, 06:43:05 AM »

just gave it a try, I like it!

I noticed two things:
1. there is an issue with the input. if you hold the up-arrow he continues to flap, thats great. but if you then press the fire button, he stops flapping. either make every wing flap a button press, or dont let the fire breathing override the other action.
2. my screen resolution on my macbook. a chunk of the screen gets cut off at the bottom, maybe check for the window size/visible area and do some scrolling if required.

always nice to see a fellow html5 dev Smiley
Logged

Frozen Fractal
Level 0
**



View Profile WWW
« Reply #2 on: December 08, 2015, 07:16:02 AM »

Hi, thanks for the feedback, I'm glad you like it! You were looking at the Ludum Dare entry, which was hacked together in 48 hours, so of course there are bugs Wink I guarantee that the "proper" version will be much better. In fact both of the issues you mention are already fixed in the development version :D
Logged

frozenfractal.com | @frozenfractal | Devblog posts are cross-posted from frozenfractal.com/blog; subscribe there if you don't want to miss any!
Frozen Fractal
Level 0
**



View Profile WWW
« Reply #3 on: April 18, 2016, 01:32:05 AM »

Been very busy with another game that I cannot talk about yet, but I found some time to make the dragon SOAR! In its original version, Glauron, the mechanics are very simple:

  • Horizontal speed is constant.
  • Vertical speed is affected by gravity as usual.
  • When you tap, a fixed amount of speed is added to the vertical speed over the next half second or so.



This is almost as simple as in Flappy Bird; the only difference is that the vertical speed boost isn’t all delivered at once (which would make for very jerky movement). The similarity is why Glauron has also been jokingly called “Flappy Dragon” (including by me).

But I wanted something more sophisticated, something which gives you more control, while keeping much of the simplicity. Something that is easy to learn, but hard to master. I wanted to let you swoop down from high up, building speed so your fire reaches farther, but of course running a greater risk of crashing into the ground.
So instead of just tapping, I came up with the following control scheme:

  • If you do nothing, you just follow a ballistic trajectory like before. Flying is hard work, yo.
  • Tap to flap your wings, as before. However, instead of affecting just your vertical speed, you get a bit of forwards speed as well (“forwards” being “along your current velocity vector”).
  • Tap and hold to glide. Drag up and down (like a joystick) to control your pitch. Drag up to curve upwards, down to curve downwards.

Naturally, it took a lot of tweaking to get this even remotely right. I started by looking up how real dragons fly. There seems to be little to no literature on the subject, so I used bird and aeroplane flight as a proxy instead. That turns out to be pretty complicated! I did spend half a day trying to implement a very simplified aerodynamics model, but it didn’t offer me the amount of control that I wanted. In particular, it kept either adding energy to the system exponentially, resulting in infinite speeds and crashes, or dissipating energy too quickly, resulting in a dragon slowly falling straight down as through syrup.

So instead, I decided to just fake it. Flapping your wings simply takes some vector between the velocity vector and the vertical, and applies acceleration in that direction. Pitching is even simpler: it just rotates your velocity vector. The stronger you pitch, the faster it rotates. This doesn’t add or remove any energy, so it’s quite robust. But since flapping does add energy, I had to add some drag to prevent breaking the sound barrier.

The keen reader might have noticed a problem: when a touch goes down, how do we know whether it will be a tap, or a drag? Therefore, how do we know whether to flap the wings or not? The answer is: we don’t; we’ll have to wait until the tap is released again. But because that makes the entire thing feel very laggy and unresponsive, we use a trick: as soon as a tap is detected, the wings start coming down towards the horizontal, as if we were to flap. If the tap is released before they reach a certain point, that motion continues downwards and the flapping is completed. But if the tap is held down, the motion stops at 30 degrees from the horizontal, which is the spread-winged position used when gliding. Physically nothing happens, but the graphical effect of the wings moving is enough to give a feeling of responsiveness.

And there you have it: a flappy, swoopy, soary, glidy dragon!



It took me an entire blog post to explain, but I’m planning to add some animated infographics to the game so that it’ll be totally clear from the start.
Logged

frozenfractal.com | @frozenfractal | Devblog posts are cross-posted from frozenfractal.com/blog; subscribe there if you don't want to miss any!
Frozen Fractal
Level 0
**



View Profile WWW
« Reply #4 on: April 22, 2016, 12:48:23 AM »

With another project winding down, I’ve had all week to dedicate to Dragon Attack. A lot remains to be done, especially in the tweaking and balancing department, but there has been a lot of progress.

Treasure

I added something I’d been thinking about for a while: sticky treasure. You know how Smaug in The Hobbit has his chest crusted with jewels, making him nearly invulnerable? In Dragon Attack, houses now spawn gold coins, and churches spawn diamonds. Both stick to your dragon wherever they first touch, and provide protection against arrows. A coin neutralizes one hit and then falls off, a diamond three.



This has a big impact on gameplay. Previously, without the hearts spawned by houses and churches, you wouldn’t make it past level 2. Now, I usually make it to level 5 or 6, even though there is no way to replenish health. Placing the treasure strategically is critical, and this gives experienced players something to do early on in the game, so they won’t get bored dispatching easier enemies but instead are preparing themselves for the tougher stages.

Collisions

There are many collisions going on in the game: between arrows and the dragon, between fire and the archers, between fire and buildings, between powerups and the dragon, and so on. Up to this point I’d been handling these in an ad-hoc way, but the time had come for a refactor. Now I can register collision handlers that look at the two colliding entities and decide whether they want to do something with this collision, or pass it on to the next handler.

This simplified a feature I wanted to add: making fire not go through the ground. It makes for more interesting gameplay because you can no longer burn archers from the other side of a hill, but it also makes the ground feel a bit more solid. And because the ground is something you really, really don’t want to hit, that’s a good thing.

Font

I also replaced the font by one I think more fitting, Trade Winds:



It’s not suitable for large swathes of text (like the stats you get at the end), but as a display font I think it works nicely. I hope people won’t find it too pirate-themed; otherwise I might try Shojumaru – though I find it a bit too Oriental for this rather Western dragon.

Note that this splash screen is temporary (thank goodness).

Trees

Oh my, trees! I’ve always been saying “I want lots of stuff to burn in this game”, and this is only the beginning. Basically, patches of bare land without anything flammable should be few and far between.

I’m going for a somewhat realistic art style despite the silhouettes, so I figured it would take a lot of time to even draw one tree, let alone some variation. That’s when I thought to type “procedural tree generator” into Google, and out popped Arbaro, a Java application that generates trees and exports them to povray files. The results are really decent, and the program comes with several examples:



I wired some stuff together with shell scripts, added collision boxes and spawner configurations, and voila!



Maybe I’ll need a bit more variation, but it’s really easy to generate, so I’ll leave that for later.

Music

Oh my, music! Music can be so important to the mood of a game. I’m talking to an audio designer about doing sound effects, and although he can make music as well, I think that will be outside my budget. So, like everyone, I turned to Kevin MacLeod’s amazing collection of Creative Commons music.

Besides being free, an advantage of using these over a custom-made track is that you know exactly what you’re going to get, and you can try out different tracks before settling on one. So I wrote a few lines of code that would play a different track from my shortlist on every playthrough, so I could compare and contrast easily.

I used to envision this game with a rock or punk soundtrack, with a pumping rhythm and lots of bass and dirty guitars, like some of the tracks of Red Alert 2. MacLeod does have a few of those, but I found that this style generally becomes really tiring to listen to after a while. I also think it would clash too much with the sound effects.

So I tried some orchestral tracks instead, more like what you would find in battle scenes in a fantasy action movie, and that also works pretty well. Once I make up my mind which of the four remaining tracks is most suitable, I should really make a video.

And more!

Also, last weekend I participated in another Ludum Dare game jam. The result is Morphing Maria, a puzzle game involving plumbers and princesses. Please rate and comment if you can!
Logged

frozenfractal.com | @frozenfractal | Devblog posts are cross-posted from frozenfractal.com/blog; subscribe there if you don't want to miss any!
Frozen Fractal
Level 0
**



View Profile WWW
« Reply #5 on: May 20, 2016, 08:17:20 AM »

Earlier this week, I added some variations to the procedural terrain in Dragon Attack.

Previously, the landscape was generated one segment at a time, forming a “chain” of rotated sprites. Each segment would have the same slope as the previous one, plus or minus a random number. To avoid going off the screen, the random number would be biased downwards near the top, and upwards near the bottom. This system worked great, but it made it pretty hard to implement variety in the terrain. For example, with just the previous height and slope as your “state”, how would you generate a mountain range?

The obvious solution was to switch to fractal noise. Generate an array of random numbers, sample from those at different “frequencies” and with different interpolation functions, and sum them together, each with its own “amplitude”. This gave me lots of creative freedom in varying frequencies and amplitudes (width and height of terrain features) and interpolation functions (smooth or jagged), so I could get a terrain that would look good and play well. It’s also possible to put arbitrary functions in between (for instance, abs or pow) for more dramatic effects.

Taking the chain of segments and making it fit the noise function turned out to be nontrivial. It’s easy to sample the height at some particular x coordinate, but when you rotate the current segment into position, its right side moves, so your sampled height is invalidated. I mostly solved this by sampling multiple times, each time allowing for less rotation to let the thing stabilize. It works well enough.

Lowlands, mostly flat, great for the first level (ignore the headless archers):



Smooth rolling hills, a bit higher and more challenging:



Canyons, created by rounding one of the octaves to a hard 0 or 1 and diminishing their effect far away from the 0.5 range (ignore the artifacts on the edges, they’re gone now):



Mountains, created by sampling multiple times and computing the max, simulating multiple layers and raising the average height in the process:



It’s clear that these need some different sprites as well. Lowlands should have more grass, mountains should have more boulders, etcetera. It would also be nice if things spawned in more sensible places, e.g. no trees above a certain height, and no houses on a steep slope.

I also worked on tree variations and added ballistas. Both need some work still, but I’m sure they will show up here soon.
« Last Edit: June 03, 2016, 06:21:41 AM by Frozen Fractal » Logged

frozenfractal.com | @frozenfractal | Devblog posts are cross-posted from frozenfractal.com/blog; subscribe there if you don't want to miss any!
Frozen Fractal
Level 0
**



View Profile WWW
« Reply #6 on: June 03, 2016, 06:19:26 AM »

Always new things to learn! This week, I integrated Facebook highscores into Dragon Attack, so you’ll be able to see your friends’ scores and challenge them to beat yours. I’m hoping this will give the game more lasting appeal, not to mention some ‘virality’.

This is what it currently looks like:



I have mockups for a better looking layout, but you can see that the base idea is there. Susan Alabdjfhfdaij Bushakstein is one of my autogenerated test accounts. Interestingly, these all have really long names, presumably to try and break your UI. And their middle name mostly consists of letters on the home row of a qwerty keyboard. Coincidence? I think not!

These highscores actually took a fair amount of work to implement, so the rest of this post will be rather technical.
The first problem is that you have to juggle two types of access token: one for reading the current score (READ), one for writing a new one (PUBLISH). Since the library I’m using (gdx-facebook) stores only a singleton-like “current” token, you have to be careful to sequence all calls to the server and sign in with the right token before each series of calls.

Then there is the lack of atomic operations in the Facebook API itself. You have to fetch the user’s current highscore, compare it to the new score, and post the new score only if it is higher. There is a possible concurrency bug here, which will likely never happen because nobody plays on two devices at the same time, but it still bothers me. And of course we have to post the new score before we fetch the list of other people’s scores, because we want that list to be up to date. (Fortunately, there don’t seem to be significant propagation delays. A side effect of Facebook running largely on MySQL?)

Actually rendering the list also takes a fair number of API calls. First we get all known scores (from a subset of your friends). Then we get all friends (because we need their profile picture URLs), and the user’s own profile picture URL (because they’re not in their own friend list). We merge those, then fetch each profile picture with an individual HTTP request to the CDN. I used to work on a JavaScript-heavy single-page application, and this really goes against the lessons (about performance, and quota usage) that I learned there. I might get some improvement by using the batching API, but still would have to fetch each picture one by one. Right now I’m caching everything in RAM only, hoping that it will be a good compromise between freshness and performance.

This would take some thinking in a language that was actually designed with concurrency and asynchronicity in mind. Java, although it gives you all the tools, is not. The gdx-facebook library gives you callbacks for each operation, which have one success mode and three different failure modes. The HTTP library in libGDX also comes with its own callbacks. Some operations can be parallelized, some must be done in sequence, and some must wait for an entirely different operation to complete first (because of the access token thing). And of course, you have to be careful to make all these callbacks run on the right threads, otherwise libGDX will explode. So in order not to go entirely crazy, I finally caved in and added Google’s excellent Guava library to the project. Its ListenableFuture and AsyncFunction make life a whole lot easier – palatable, almost.

Finally there is a potential future problem: in the Facebook model, there can only be one score per user per app. So if I ever want to have multiple levels, or multiple game modes, I’m out of luck. I’m not sure how I’ll solve that if the need arises. I would still use Facebook for authentication, authorization and friends discovery, but would have to store the data elsewhere, like Firebase. But then I’d either have to make all data public (privacy nightmare) or copy over the user’s friend list to serve as an access control list (other privacy nightmare on top of a synchronization nightmare). Yay.
Logged

frozenfractal.com | @frozenfractal | Devblog posts are cross-posted from frozenfractal.com/blog; subscribe there if you don't want to miss any!
Pages: [1]
Print
Jump to:  

Theme orange-lt created by panic