• Welcome to Dark Bit Factory & Gravity.
 

3D TOMB II : a DOOM-like in 4k of JavaScript

Started by p01, July 01, 2007

Previous topic - Next topic

0 Members and 0 Guests are viewing this topic.

p01

The time has come to, finally, release 3D TOMB II, the DOOM-like in 4k of JavaScript I initially made for the5k 2004.


The whole game now weighs 4003 bytes, all files included. The controls are X,C to strafe, SPACE to fire, the arrows to move around. And here is a downsized screenshot:




/!\ Due to a bug in Safari and Gecko's handling of the zIndex, the game doesn't work as expected in Safari, FireFox and co. But it works like a charm, on a semi-recent computer, in IE and Opera.


Hope you'll enjoy it.

Yaloopy

That's pretty damn cool :) Shame about it not working in FF
Fuck L. Ron Hubbard and fuck all his clones.
Challenge Trophies Won:

Rbz

Yeah, very nice work! 

I just miss some sound effects, but I know that there's no free bytes for this...



Challenge Trophies Won:

mike_g

Nice game. I played it in Opera and it ran a quite slow, but then I have got quite an old PC and doing stuff like this in Javascript is quite demanding. Considering theres the graphics in there thats quite clever getting all that done in around 4K. I got reasonably simple functions that are bigger than that. Good stuff :)

Jim

That's neat!  The 4k is a real achievement.  Why not make a full version with sounds and higher res graphics to really show it off?

Jim
Challenge Trophies Won:

benny!

@p01:

Awesome, p01. Very well done !!!
[ mycroBLOG - POUET :: whatever keeps us longing - for another breath of air - is getting rare ]

Challenge Trophies Won:

ninogenio

Challenge Trophies Won:

Tetra

Very nice, and works pretty fast too :)
Challenge Trophies Won:

Shockwave

Good work :) Heck of a programming exercise to get this game so tiny.
Shockwave ^ Codigos
Challenge Trophies Won:

p01

Thank you very much for the good words and the karma++  :cow:

3D TOMB II works best in IE. Sorry, Opera does well, but Firefox doesn't seem too happy about handling a page with 2650+ DIVs.

As for making a bigger version with improved graphics and what not ... well, that crossed my mind but honestly I should rather spend that energy on a new JavaScript demo. I've already worked on 3D TOMB II way too long : every now and then since 2002, plus some more intense periods ( a month ago, the game was ~4.6K and didn't work in Opera. It was fun, and tiresome, squeezing almost 700b. )

That doesn't mean I won't do another crazy game in JavaScript.

p01

Ahoy! rejoice people for now 3D TOMB II works in IE (quickly), Opera (ok), Firefox (slowly) and Safari 3 beta (almost nicely).

Beside, I really like that cow -> :cow:
She looks really cool.

Shockwave

:cow:

Works here in FF, IE is the way to play this though.
For what it's worth I think you are right about wanting to move on to another project, the whole point of this was to get a fps in 4kb and you did a great job of it.
Time to make something else, people who want to play a complete version of Doom with sound effects etc should perhaps get dosbox out.
Shockwave ^ Codigos
Challenge Trophies Won:

Jim

:P  Don't get me wrong, I thought it was great!

Jim
Challenge Trophies Won:

p01

I don't, don't worry. You're far from being the 1st one mentionning the idea of a bigger version.

DrewPee

@p01 - played the game last nite - well done matey - that is some cool code you have there - karma+

Drew
DrewPee
aka Falcon of The Lost Boyz (Amiga)
Ex-Amiga Coder and Graphic Designer
Administrator of > www.retrocomputermuseum.co.uk

Xone


mazemaker

is there a non-obsfucated version of the source code?

Shockwave

Quote
As for making a bigger version with improved graphics and what not ... well, that crossed my mind but honestly I should rather spend that energy on a new JavaScript demo. I've already worked on 3D TOMB II way too long : every now and then since 2002, plus some more intense periods ( a month ago, the game was ~4.6K and didn't work in Opera. It was fun, and tiresome, squeezing almost 700b. )

I guess not..
Shockwave ^ Codigos
Challenge Trophies Won:

p01

Shockwave: correct :p

However I just ran the code through a de-obfuscater and it's "ok", and not so long that it should remain manageable if you are a bit curious. I also added a couple of comments:// main
function N()
{
    t++;
    C = '#000';
    //    if player still alive, move it if need be
    if (h = p.h)
    {
        p.A += (K[39] - K[37]) * P / 96 + P * 2;
        while (p.A > P)
        {
            p.A -= P * 2;
        }
        p.U(K[38] - K[40], K[67] - K[88])
    }
    p.t += I =- 1;
    U[32] &= m * p.t * p.h < 0;
    z = p.h ? P / 3 : P / (3 + Math.cos(t / 5) / 3);
    A = p.A - z / 2;
    n = p.x - p.c * 64;
    o = p.y - p.s * 64;
    a = 4 * 64 * 64 * Math.tan(z / 2);
    //    do the floor casting
    for (Z = x = 0; x < 50; x++)
    {
        r = a / Math.cos(A - p.A);
        u = Math.cos(A) * r;
        s = Math.sin(A) * r;
        A += z / 50;
        i = 130;
        d = (c = x * 52) + 52;
        do
        {
            d--;
            v = n + u / i;
            w = o + s / i;
            k = q[(w >> 3 & 56) + (v >> 6)];
            if (k >> 8 || (v | w) &- 512)
            {
                break;
            }
            if (H[d].style.backgroundColor != Q[b = T[k + (v & 56) + (w >> 3 & 7)]])
            {
                H[d].style.backgroundColor = Q[b], H[c].style.backgroundColor = Q[b + 1];
            }
            c++
        }
        while (i -= 5);
        with (W[x].style)
        {
            left =- ((v^w) & 56) - (v & w & 64);
            top = W[x].t = 130 - i;
            W[x].parentNode.style.zIndex = height = i * 2
        }
        if (x == 25)
        {
            Z = i;
        }
    }
    //    process the entities
    for (j = 0; j < 6 + L / 2; j++)
    {
        X = E[j].x - n;
        Y = E[j].y - o;
        A = Math.atan2(Y, X) - p.A + P * 2;
        while (A > P)
        {
            A -= P * 2;
        }
        i = Math.round(Math.sqrt(a / Math.cos(A) * a / Math.cos(A) / (E[j].d = d = X * X + Y * Y)));
        i *= i < 130;
        A *= 400 / z;
        //    close to the player then point towards it
        if (d < 16 * 64 * 64 && p.h)
        {
            E[j].A = p.A;
        }
        E[j].A += (((Math.random() * 3) & 3) - 1) * P / 8;
        with (W[j + 51].parentNode.style)
        {
            left = 200 + A - i;
            top = 130 - i;
            width = zIndex = height = i * 2
        }
        //    living entity ->
        if (E[j].h)
        {
            x = Math.round(25 + A / 8);
            if (--E[j].t < L * 2 && W[x] && 130 - i < W[x].t)
            {
                E[j].t = 48, C = '#600', p.h -= p.h > 0;
            }
            W[j + 51].style.left =- (E[j].k + ((j * 4 + E[j].t) & 4 ? 1 : 0)) + '00%';
            E[j].U(-2, 0);
            if (U[32] && (Math.abs(A) | Z) < i && (I < 0 || E[I].d > d))
            {
                I = j;
            }
        }
        //    pick up entity if it's close
        else if (d < 64 * 64)
        {
            $ += (E[j].k - 1 ? 1 : 10), E[j].k ? m += 5 : p.h += 2, E[j].x =- d;
        }
    }
    //    firing
    if (I + 1 && !--E[I].h)
    {
        W[I + 51].style.left = '-200%', $ += E[I].k - 3 ? 10 : 5;
    }
    //    hud
    W[50].style.left = p.h ?- 112 * U[32] :- 224;
    m -= U[32];
    p.t += U[32] * 8;
    U[32] = 0;
    B.style.backgroundColor = C;
    S.innerHTML = p.h + '<br>' + m + '<br>' + L + '<br>' + $;
    //    oh noes! you just died
    if (!p.h & h)
    {
        M.src = $ + '<br>' + (prompt('your name ?', ''));
    }
    //    bottom right of the map -> next level
    if (p.x > 464 && p.y > 384)
    {
        l();
    }
}
//    Entity class
function O(v, w, h)
{
    i = q[(v >> 6) + (w >> 3 & 56)] >> 8;
    W[j + 51].style.left =- h + '00%';
    this.x = v;
    this.y = w;
    this.A = 0;
    this.k = h;
    this.t = this.h = h > 1 ? h : 0;
    //    move() method
    this.U = function (X, Y)
    {
        this.c = v = Math.cos(this.A);
        this.s = w = Math.sin(this.A);
        e = (v * X - w * Y) * this.k / 3;
        u = (w * X + v * Y) * this.k / 3;
        v = this.x + e;
        w = this.y;
        if (q[(w >> 3 & 56) + (v >> 6)] >> 8)
        {
            v -= e;
        }
        w += u;
        if (q[(w >> 3 & 56) + (v >> 6)] >> 8)
        {
            w -= u;
        }
        this.x = v;
        this.y = w;
    }
}
//    initLevel()
function l()
{
    Q = '#10,#21,#32,#43,#54,#b9,#ca,#db'.split(',');
    for (i = 0; i < 3 * 64; U[i] = K[i++] = 0)
    {
        Q[i] += (i + L % 3) >> 1;
        T[i] =+ '000000000000000000000000000000000000000000000000000000000000000000000000001111000122221001222210012222100122221000111100000000000000000000000000005555000005500000000000055555500055550000055000'.charAt(i) + eval('(i' + '^+|-*&%/'.charAt(L & 7) + '(i>>3))/4&1');
        q[i] = ((b = '5555555520000005500000055000000550000005500000055000000255555555'.charAt(i)) > 1 ? b : Math.random() * 9 > 5 ? Math.random() * 9 > 5 : 9) * 64
    }
    i = 54;
    while (i > 1)
    {
        q[i] = (n = Math.random() * 9 > 5) * 64, i -= (i & 7) - 1 ? (i >> 3) - 1 ? 1 + 7 * n : 1 : 8;
    }
    m = 50;
    L++;
    for (j = 0; j < 6 + L / 2; j += i < 1)
    {
        p = new O(32, 96, 10), E[j] = new O(Math.random() * 512, Math.random() * 512, j < 2 + L  / 6 ? (j < L  / 9 - .5 ? 1 : 0) : (j < 1 + L  / 2 ? 5 : 3));
    }
    p.k = 3;
    N();
    alert('START LEVEL ' + L)
}
// global stuff
H = [];
W = [];
K = [];
U = [];
q = [];
E = [];
T = [];
P = Math.PI;
//    create the markup for the rendering area, the entities & player
for (t = $ = i = j = L = p = m = Q = x = 0; x < 50; x++)
{
    with ((d = document.createElement('div')).style)
    {
        width = 8;
        height = 260;
        left = x * 8
    }
    y = 0;
    while (y < 260)
    {
        with ((H[i] = document.createElement('div')).style)
        {
            width = 8;
            height = 5;
            top = y
        }
        d.appendChild(H[i++]);
        y += 5
    }
    (W[j] = document.createElement('img')).src = 1;
    with (W[j].style)
    {
        width = 128
    }
    d.appendChild(W[j]);
    R.appendChild(d);
    j += 50;
    with ((d = document.createElement('div')).style)
    {
        width = 112;
        height = 143;
        top = 117;
        zIndex = 512;
        left = 143 + x * 512
    }
    (W[j] = document.createElement('img')).src = x ? 0 : 2;
    with (W[j].style)
    {
        width = (x ? 7 : 3) + '00%';
        height = '100%'
    }
    d.appendChild(W[j]);
    R.appendChild(d);
    j -= 49
}
//    init the first level
l();
//    let the be light
setInterval(N, 9)
Have fun.