Cipher Drive Returns

Allen Webster Jan. 12, 2017, 1:30 a.m.
Today I brought Cipher Drive back to the internet with my first episode of the new year now available here.

In this week's episode I started working on unifying what I have to admit was just a catastrophically bad setup for my asset system. It is a good lesson in the fact that, even if you are going to go back and make something "real" later, that doesn't mean you shouldn't plan somewhat carefully what you're doing now to make sure that transition will be... you know... possible.

Anyway, all I want out of this post is to let everyone know that Cipher Drive programming is back. For those who haven't caught much or any Cipher Drive programming, for me the project is about trying some wacky game programming ideas. The first big one I am working on is setting up a system for editing the game and assets from within the game.

Bye bye for now everyone.


0 comments

Cipher Drive: Offline Recording

Allen Webster Dec. 8, 2016, 12:28 a.m.
Hi everyone!

I am moving into my office at the end of this year, and I am a little more busy than usual with the end of the school semester. So I have decided to discontinue Cipher Drive streams for December. In January I will start to record my sessions on Mondays offline, and then upload them, because I don't feel like getting ethernet in my new office.

When the programming videos comes back you can look forward to me working on:
  • Automatically converting file formats when assets are dragged into the game editor
  • Defining level type assets and game object type assets that can be edited in game
  • Making a small demo game, probably with all new programmer art, to test the engine

1 comments

Cipher Drive: Moving Forward

Allen Webster Oct. 31, 2016, 7:55 p.m.
So the team decided to take a break from the project for the month of October. We were instead jamming on one of our favorite games from the past "The Most Undead". It has definitely been a lot of fun, but we should discuss real quick why we took a break.

It looks like right now the Cipher Drive project has hit a bit of a problem. The programming team was always a little behind the hoped schedule and by the time October came around the art team had lost a lot of enthusiasm for the project. Right now it is unclear how long it will be before we can produce the game in the originally intended scope and style.

The game jam was intended to give everyone a break from not knowing how we were going to do Cipher Drive. Now that the break is over we've come to a decision on what to do with the game. Right now the programming team will keep moving forward until they've built the rest of the engine they first set out to build. Then we will retire this project until we see a satisfying way for us to finish it.
0 comments

Rectangle Packing for Font Atlas

Allen Webster Sept. 2, 2016, 1:34 a.m.
Hi everyone, I am here with the follow up on the Cipher Drive stream today. I ended up working on rectangle packing because I need it to complete the font atlas baker utility. I could have just written something dumb and moved on, but the problem struck me as interesting so we dug in and had some fun with that.

On stream the idea I got was the sort the rects by height, so that I could place them in rows. Since I place the tallest rects first, I can treat the first rect of each row as defining the height of that row, and all future rects are guaranteed to fit in that row. Every time I go to place a rect I can either insert it at the end of an existing row, or make a new row. I set it up to make it's decision based on whichever choice minimizes the difference in the width and height of the entire atlas. I chose that method because the obvious move of optimizing the area at each step tends to prevent it from ever starting new rows. Keeping it square some how intuitively meant to me that it would have to be high density and it worked.

Off stream I fixed it up some more to allow it to slip the shortest rectangles in by using the extra space left over when a rectangle that is shorter than the max height of the row it is placed in. With this it got up to 91% efficiency on my test case of LiberationSans-Regular.ttf.

For me, the whole point of making this game is to experiment with everything in order to find new things to make and share. This rectangle packing algorithm is exactly that. So I'm posting to share the code that I came up with. Everyone is free to take it, use it, critique it, improve it, or anything else. I will try to get it on a public git repository sometime soon, but for now it's right here:

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
typedef struct Packing_Rectangle{
    uint32_t w,h;
    uint32_t i;
    
    uint32_t x0,y0,x1,y1;
} Packing_Rectangle;

typedef struct Packing_Row{
    uint32_t x,y,h;
} Packing_Row;

#define RectSwap(a,b) do{        \
    uint32_t t;                  \
    t = a.w; a.w = b.w; b.w = t; \
    t = a.h; a.h = b.h; b.h = t; \
    t = a.i; a.i = b.i; b.i = t; \
}while(0)

static int32_t
sort_rects_by_h_partition(Packing_Rectangle *rects, int32_t start, int32_t max){
    int32_t pivot = max - 1;
    uint32_t pivot_h = rects[pivot].h;
    for (int32_t i = start; i < pivot; ++i){
        if (rects[i].h > pivot_h){
            RectSwap(rects[i], rects[start]);
            ++start;
        }
    }
    RectSwap(rects[pivot], rects[start]);
    return(start);
}

static void
sort_rects_by_h(Packing_Rectangle *rects, int32_t start, int32_t max){
    if (start+1 < max){
        int32_t mid = sort_rects_by_h_partition(rects, start, max);
        sort_rects_by_h(rects, start, mid);
        sort_rects_by_h(rects, mid+1, max);
    }
}

#define AbsDif(a,b) (((a)>(b))?((a)-(b)):((b)-(a)))

static void
pack_sorted_rectangles(Packing_Rectangle *rectangles, int32_t count, Packing_Row *rows,
                       uint32_t *packed_w_out, uint32_t *packed_h_out){
    int32_t row_count = 0;
    int32_t best_row_i = 0;
    uint32_t best_row_x = 0, best_row_h = 0, this_x = 0;
    
    uint32_t new_row_y = 0, new_row_x = 0;
    
    uint32_t y_dif = 0, x_dif = 0;
    uint32_t max_x = 0, max_y = 0;
    Packing_Rectangle *rect = 0, *rect2 = 0;
    
    uint32_t left_over_h = 0, under_w = 0;
    
    for (int32_t i = 0; i < count; ++i){
        rect = rectangles + i;
        
        best_row_i = -1;
        best_row_x = 0xFFFFFFFF;
        best_row_h = 0;
        for (int32_t j = 0; j < row_count; ++j){
            this_x = rows[j].x + rect->w;
            if (this_x < max_x){
                this_x = max_x;
            }
            if (this_x < best_row_x || 
                (this_x == best_row_x && best_row_h > rows[j].h)){
                best_row_x = this_x;
                best_row_i = j;
                best_row_h = rows[j].h;
            }
        }
        
        new_row_x = (max_x > rect->w)?(max_x):(rect->w);
        new_row_y = max_y + rect->h;
        y_dif = AbsDif(new_row_y, new_row_x);
        x_dif = AbsDif(max_y, best_row_x);
        
        if (y_dif < x_dif){
            rows[row_count].x = 0;
            rows[row_count].y = max_y;
            rows[row_count].h = rect->h;
            max_y += rect->h;
            best_row_i = row_count;
            ++row_count;
        }
        
        rect->x0 = rows[best_row_i].x;
        rect->y0 = rows[best_row_i].y;
        rect->x1 = rect->x0 + rect->w;
        rect->y1 = rect->y0 + rect->h;
        
        rows[best_row_i].x += rect->w;
        
        under_w = rect->w;
        left_over_h = rows[best_row_i].h - rect->h;
        while (i+1 < count &&
               rectangles[count-1].h <= left_over_h &&
               rectangles[count-1].w <= under_w){
            rect2 = &rectangles[count-1];
            rect2->x0 = rect->x0 + (under_w - rect2->w);
            rect2->y0 = rect->y1;
            rect2->x1 = rect2->x0 + rect2->w;
            rect2->y1 = rect2->y0 + rect2->h;
            under_w -= rect2->w;
            --count;
        }
        
        if (rows[best_row_i].x > max_x){
            max_x = rows[best_row_i].x;
        }
    }
    
    *packed_w_out = max_x;
    *packed_h_out = max_y;
}
5 comments

August Update

Allen Webster Aug. 30, 2016, 9:37 p.m.
Hey folks,

This is Allen posting on behalf of the team. I would just like to let everyone know that not much has happened this month. I've have been on my internet hiatus and vacation. Other members have been shifting around some of their affairs.

To rectify the silence on this project I will be streaming new development September 1st.

Until next time everyone!
0 comments

Drum Roll Please ...

Allen Webster July 17, 2016, 7:42 p.m.
Dropping Anchor

So we finally made it! Albeit nearly a week after we thought we would dock but the seas of handmade.network are rough to sail, and the S.S. Overreact lacked sufficient navigational tools to make the trip any shorter. So many thanks to Abner, Jeroen, Andrew, Matt and Martin for all of their work guiding us into port. We are excited to officially be a part of the gregarious community. We strongly believe in the handmade movement, and we wish to head towards quality rather than taking the easy route. With moonstone in hand, we will be sailing day and night towards that destination. For us it is an honor to join such a proud fleet of principled developers.


Who is Overreact You Ask?

Overreact is no single artist, developer, musician, or designer. Overreact is a conglomeration of humble developers who do whatever they want... because it's the right thing to do. You see, over the years of playing god awful games we came to the conclusion that we need to change the course that games are on. One of our biggest philosophies is that every game we create should break ground in some respect. Borrowing ideas from other developers is totally acceptable but what isn't acceptable is cookie cutter games. We're here to ensure that games aren't given a bad rep.


What Drive? Cipher Drive!

That's right: Cipher Drive! So what exactly are we talking about when we say "Cipher Drive!"? What we're talking about is a space shooter, point and click, card game set a long long time from now in the Covaris galaxy, where "smuggling goods from star system to star system while dodging bounty hunters, Elven police, and surviving the Denglorian Onslaught" is your middle name, and that's not all. Cipher Drive is also a game unlike any other in that rumors, reputation, and NPC interaction actually matter.

The Overreact philosophy clearly states that we should break new ground in our work. So how are we doing that in Cipher Drive? Pfft that's an easy one. Cipher Drive involves experiments on both technical and artistic fronts. On the technical front we are looking for new ways to improve programmer and artist productivity as well as quickening development cycles to continue making better games. On the artistic front we are looking for a unique aesthetics that are under represented in games.

Technically speaking our experiments include an in game editor that features hot reloading both for code and assets so that all team members can iterate at top speeds. We also have a totally modular approach to the programming so that our programmers can operate independently to accomodate for long distance collaboration.

Visually we are looking to create an aesthetic that is true to the pages of an old school comic book. Musically we are trying to crack the dynamic music problem without excluding the composer by procedurally generating all of the music and without composing songs in segments. Mechanically our aim is to flip quest oriented game play on it's head by making a living world full of potential quests rather than a static world filled with predetermined quests.


Bye Bye For Now. Stay Tuned Folks.

There are many channels by which you can stay in the loop with Cipher Drive. Obviously there is this fantastic blog (thanks again handmade.network) which we will try to update about twice a month. There are also the forums here where we will invite others to discuss the game and ask questions. We have several accounts on twitch for live streaming the development. There is artist Connor Hart here, programmer Allen Webster here, and even programmer Tyler Camp may begin streaming soon.

There are also plenty of places to follow Overreact across social media:
On twitter
On instagram
On facebook

If you want to see exclusive content, or you really just like us, you can support us on this Patreon.

We don't want to put ourselves in a position where we won't be able to update as much as we'd like to. Let's be realistic here... That's like the word of the project. But we'll definitely be in touch.
0 comments

Cipher Drive License

C Allen Webster July 17, 2016, 12:03 p.m.
TBD
0 comments