Saturday, December 19, 2015

Scene2d


Wow, the scene2d framework has come a long way since I first looked at it, in some pre-1.0 version of LibGDX. In the last hour since the kids have been in bed, I've got almost half of my game UI mocked out using it, and switching from the draft/mockup to the "real thing" should be as easy as modifying the skin file, and then slightly nudging/resizing things.
I'd show some code here, but it's all so plain simple, I'm not sure what to even say. It's all super simple layout stuff, along the lines of:
    private Window buildControlWindow() {
        float paddingLeft = 120;

        Window window = new Window("Signal", getSkin());
        window.setPosition(0, 0);
        window.setSize(LifeInSpaceGame.WIDTH, LifeInSpaceGame.HEIGHT / 3);
        window.setMovable(false);
        window.setResizable(false);
        Label label = new Label("Radio Filters", getSkin());
        window.add(label).padLeft(paddingLeft).colspan(3).expandX();
        window.row();

        Button filter1 = new TextButton("     Filter 1     ", getSkin(), "toggle");
        window.add(filter1).padLeft(paddingLeft).expandX().padTop(10);
        window.row();

        Button filter2 = new TextButton("     Filter 2     ", getSkin(), "toggle");
        window.add(filter2).padLeft(paddingLeft).expandX().padTop(10);
        window.row();

        Button filter3 = new TextButton("     Filter 3     ", getSkin(), "toggle");
        window.add(filter3).padLeft(paddingLeft).expandX().padTop(10);
        window.row();

        return window;
    }


This builds the panel in the bottom right that lets you apply different "radio filters" to the radio signal audio that's coming in from the selected star, to help you try to pick out whether there are any signs of intelligent life coming from that star.
The next task is going to be the first somewhat challenging one: to have a cool waveform image scrolling by on the bottom left side of the screen to match the radio sounds that you hear when you tap on a star. I have some ideas about how to make it work really easily, but it might take a little finagling. 



Here we have some rough instructions (which hopefully I'll have time fill out later)
And the addition of the radio filter toggle buttions. The waveform should appear in the space to the left of the buttons.

LibGDX Game Jam

So this week I'm tentatively starting a project for the LibGDX game jam, a month-long jam with the theme "Life in Space"

Part of the jam is the requirement to document your progress, which I'm doing on their website. I'll try to cross-post a lot of it here as well, but my jam project log page is at http://itch.io/jam/libgdxjam/topic/12031/gauauus-log

The idea of the game is a very short story-based game where you are a researcher here on earth searching through the stars looking for radio signals that would show evidence of extraterrestrial life in space.  Because of the non-action, story theme, it's very different than other games I've done. And because the goal is to crank something small out quickly, it's been fun (for the 2 hours I've worked on it so far) not worrying about good extensible/general design, but writing just enough code to get the job done.

I'll leave you with a very minimal draft screenshot. The top starfield is where you search for signals. The bottom will be a control panel that lets you analyze radio signals as they come in.

Can I do this in a month? I don't know, but it'll be fun trying.


Monday, December 7, 2015

Door work and more

Ok, enemy spawning finally works right. There were a couple of minor bugs in my spawning code that I last posted (c'mon, nobody spotted them? I thought with a million eyes, all bugs are shallow? I guess that means I have a few less than a million readers that are also 6502 assembly programmers!) But I got the bugs taken care of.

I decided the next step, to try to get my brain interested in this project again, was to go ahead and start actually making the first dungeon. Awhile ago I posted a survey to see if I should re-implement the maps from the original Anguna, or make a new adventure. Everyone voted for a new adventure. But it sounds really fun to try to reproduce the first dungeon, at least. So that's what I started on.

And immediately realized that although I had worked out proof-of-concepts for my door code, it wasn't finished. Doors on the top worked. I hadn't finished doors on the bottom. Which required going back and modifying my display kernel code, which meant I was back to counting cycles.

But I think I have that working, finally.

I also originally only allowed for a left-side or right-side to be closed (if I wanted them both to be closed, I had to draw the room map with a permanently closed wall, which reduced that room layout's flexibility for use in other rooms).  But after playing with that, I didn't like it much. So I had to re-think how this was going to work.

Originally, I used the Atari "ball" graphics object, (which is a 1,2, or 4 pixel blob) extended vertically across the whole screen, to block off a left-side or right-side door. But if I wanted to block both at once, this wasn't going to work. (there's only 1 ball!) So instead, I counted and realized I had time to squeeze in one additional instruction in my code that pushes the background data to the right registers, so I could pre-load a byte in ram with a mask to be applied to the walls, and, OR that with the actual room wall data before pushing it to the display registers. Because I'm using a mirrored background, that could close both the left and right doors at once.

Both the left and right doors are closed! Hooray!


The next step is another part that I realized I never implemented: if you have a secret door that only opens when all the enemies are dead....well, it never opens.  Not because my code to open it doesn't work. But more because it turns out I never wrote that code.

So that's next!




Thursday, November 19, 2015

Enemy Spawning

Still working on Crop Insurance. The one nice thing about it is that I'm tracking my hours, which lets me see a better estimate of how much time I spend on my side projects. The answer is about 5-6 hours per week.

No wonder it took 3 years to finish Robo-Ninja.

That being said, I'm feeling a bit stuck on Atari Anguna. I haven't been doing much, because when I do, I've been working on my semi-random enemy spawning routines. And I haven't been happy with it.

The issue is that I don't want enemies spawning stuck in walls, which means:

1. I can go completely random on spawns, but then if it's a collision, try again.
1b. To check for a collision, I either have to do the math to figure out if I've collided with a wall (which on the Atari is non-trivial due to the crazy arrangement of the playfield registers) or
1c. Draw the enemy once, check the collision registers, and then move (which means each try eats up a frame, which could be slow and look really tacky)

2. Instead, I could designate "safe spawn" areas in each room layout.
2b. Depending on how I do this, it could eat up quite a few bytes per room. (I potentially need at least 3 safe spots per room. This could be 6 bytes per room, more than I want to spend)
2c. I could cut down on rom usage by having a lookup table of safe spawns, the question is how this would work, and doing the randomization and lookup in a way that's fast and compact.


I spent WAY too long thinking through these, testing ideas, etc, and not being happy with the results. Which made me less interested in working on the game, and thus slower progress.

Finally I have a solution that I think I'm happy with, and seems to be mostly working.  I build a lookup table of 8 potential spawn points (16 bytes for the lookup table). Then each room has a byte to tell which of these potential spawns are allowed for each room layout -- a 1 means it's safe to spawn in.  Then I pick a random number between 1 and 8, check that bit. If it's not safe, try the next. Once I get a safe bit, spawn an enemy at the position that the bit refers to. Then if there are more enemies to spawn, I just check the next consecutive bits (instead of picking more random numbers, and risking enemies spawning in the same position as each other) until I've spawned them all.

It seems to work, doesn't require much storage, and is relatively fast.

For any 6502 assembly nerds, here's the code I used. You can probably spot all the places that I'm doing things really badly (I end up wasting a lot of cycles saving and loading values -- it seems I just don't have enough registers to track everything I need and still use X and Y for indexed loads (Why oh why didn't the 6502 have TXY and TYX opcodes to move values between X and Y directly?))

LoadPositionsFromSafeSpawnsImpl
    SUBROUTINE
    ;TempPF2 should be the number of enemies we want to spawn
    ;TempPF2 then holds the number of enemies we want to spawn - 1
    dec TempPF2

    ;load the room index
    ldy #0
    lda (RoomDef),Y
    tax
    ;x now has room index

    ;Store #1 in TempPF1 to bit against..
    lda #1
    sta TempPF1

    ;get random number between 0 and 7
    lda Rand
    and #%00000111
    tay
    iny

    ;a has safe spawns
    lda SafeSpawns,X

    ;rotate the safe spawn based on the random number
    sty Temp
    ldx Temp

.keepRotating
    cmp #$80
    rol
    dex
    bne .keepRotating

    ldx Temp
    ;now work our way through seeing if it's safe
.checkSpawnLoop

    ;if it's safe, go to useThisValue (of x)
    bit TempPF1
    bne .useThisValue

.beforeRotation
    ;if not, rotate again, increase X
    cmp #$80
    rol

    inx

    ; if X equals start, fail. What then?
    cpx Temp
    beq .useThisValue

    ; if X equals 8, set to 0
    cpx #8
    bne .checkSpawnLoop
    ldx #0
    jmp .checkSpawnLoop


.useThisValue
    pha
    ldy TempPF2

    ; otherwise, look up X and Y in table
    lda SpawnsX,X
    sta Enemy0X,Y

    lda SpawnsY,X
    sta Enemy0Y,Y
    pla

    dec TempPF2
    bmi .allDone

    jmp .beforeRotation
.allDone

Sunday, October 25, 2015

CivKeyboard to play store

I haven't said much on here recently. Mainly because most of my non-work time has been doing some paid consulting work, (a project involving converting a farm insurance calculator from excel spreadsheets to a web app).

I do have a few things to say, though:


  • Robo-Ninja is now on the Amazon app store (it's now free to publish there, and they had an offer of $100 in AWS credit if you publish your first app there before Nov 1, so I took advantage of that!)
  • Do you remember that custom keyboard I made for playing Civ in DOSBox? I decided to go ahead and publish it on the play store. Google onrejected it the first time for "spam" in the text (they didn't like the Civ and DOSBox in the title I guess), but I reworded it and got it listed. (It's still in beta test mode, so that link might not work for you yet....)
  • Robo-Ninja finally hit 1000 downloads this week. Not particularly amazing, but at least people are finding and playing it.
  • I'm still slowly advancing on the girly game for my daughter. But she hasn't seemed particularly interested in it recently, so maybe I'll go back to focusing a little more time on Atari Anguna. We'll see.

Sunday, September 20, 2015

Girly game (more about ramps?)

So I've got yet another detour in my hobby coding.  While my son and I were working on Robo-Ninja, my daughter kept asking if she could help me design a game.  She had drawn some rough pictures and had some ideas about what it could be like, but we hadn't really done anything with it.

She asked again recently, so I thought it was time to humor her. She decided it would be a cute little game where she could walk around a neighborhood (in a 2-d side scroller, despite me trying to convince her that it should be a top-down game) to visit friends, and collect items.  Eventually we settled on the idea that she's trying to make a leaf collection for school, so she has to collect leaves.

Well, being a 2-d side scroller, and wanting to see if I can churn this out pretty quickly, I decided to reuse a bunch of the codebase from Robo-Ninja.

So with a few hours work, I was able to pull in a bunch of the main classes from Robo-Ninja, clean up a good bit of stuff, and have something working for her.  The biggest difference is that you can actually control the main character of this game, so I had to re-work the main character a good bit. Which also gave me a chance to redo a bunch of the code that had turned to spaghetti in Robo-Ninja.



Using the knowledge of the mistakes I made from Robo-Ninja, and some tips from that page I referred to in my last post, getting the collisions and movement, particularly on ramps, was quite a bit cleaner. It makes me pretty embarrassed to compare with my Robo-Ninja ramp code, really.

Anyway, the game currently lets you run and jump around. Time to add a little bit of fluff (items, characters to talk to), and it will be half done already. (yeah right, these things always take WAY longer than I'd ever estimate!)

Stanguna is still in my brain, even though I haven't done much with it lately. Someday soon, hopefully....

Saturday, September 12, 2015

Collectibles

Well, turns out that was pretty easy. The new build with collectibles is now in the play store. With a new achievement if you collect all 16 of them.

(which means I had to play through the game yet again to test it. I'm getting pretty good at this silly game by now)


NES Anguna

Well, I had a little bit of time still, while Frankengraphics is finishing up her game Project Blue, to have a little downtime on Halcyon, s...