landgreen / n-gon

2-d physics rogue-lite platformer shooter
https://landgreen.github.io/n-gon/
GNU General Public License v3.0
134 stars 193 forks source link

SKINtech: compression engine(double jump) #272

Closed TNTiger17 closed 3 weeks ago

TNTiger17 commented 1 month ago

Basically an implementation of the double jumping idea listed somewhere in todo.txt- uses aperture skin for now but I wanted it to be a skintech because it feels too game changing to be a random tech you find from a field or something Description- this takes up three lines, which makes the this tech column look weird compared to others, so that would need to change: After jumping jump again in midair, double jumping requires 50% of current energy, double jumping boosts speed

tech.js code(I put it after diaphragm):


{
        name: "compression engine",
        description: "after jumping jump again in <strong>midair</strong><br><strong>double jumping</strong> requires <strong>50%</strong> of current <strong class='color-f'>energy</strong><br><strong>double jumping</strong> boosts <strong class='color-speed'>speed</strong>",
        maxCount: 1,
        count: 0,
        frequency: 1,
        frequencyDefault: 1,
        isSkin: true,
        allowed() {
            return true
        },
        requires: "",
        effect() {
            tech.isDoublejump = true
            m.skin.dilate()
        },
        remove() {
            tech.isDoublejump = false
            if (this.count) m.resetSkin();
        }
    },

No skin actually implemented yet because I recently decided it would be a skin tech

And then the actual function, which goes into player.js' jump function, after this line: player.force.y = -m.jumpForce; //player jump force

//***double jump***
if (tech.isDoublejump) {
    simulation.ephemera.push({
        name: "doublejump",
        count: 500,
        do() {
            m.doublejump = true
            if (!m.onGround && this.count < 480 && input.up) {
                m.energy /= 2
                Matter.Body.setVelocity(player, {
                x: player.velocity.x * 2,
                y: 0
                });
                player.force.y = -(m.jumpForce); 
                this.count = 0;
                for (let i = 0; i < 9; i++) { //draw boost effect
                    simulation.drawList.push({
                        x: m.pos.x,
                        y: m.pos.y+50,
                        radius: 50*(1 - 0.1 * i),
                        color: `rgba(245, 102, 66,${1 - 0.2 * i})`,
                        time: (i + 2) * 4
                    });
                }
                for (let i = 0; i < 10; i++) {
                    const me = bullet.length;
                    const dir = 1.5 + (Math.random() - 0.5)
                    bullet[me] = Bodies.rectangle(m.pos.x, m.pos.y, 1, 1, b.fireAttributes(dir));
                    Composite.add(engine.world, bullet[me]);
                    const SPEED = 52 + Math.random() * 8
                    Matter.Body.setVelocity(bullet[me], {
                        x: SPEED * Math.cos(dir),
                        y: SPEED * Math.sin(dir)
                    });
                    bullet[me].endCycle = simulation.cycle + 10 - (Math.random()*5)
                    bullet[me].minDmgSpeed = 0
                    bullet[me].frictionAir = 0.034;
                    bullet[me].do = function () {
                        const scale = 0.5
                        ctx.fillStyle = "rgba(255, 160, 5, 0.16)";
                        ctx.beginPath();
                        ctx.arc(this.position.x, this.position.y, 40*scale, 0, 2 * Math.PI);
                        ctx.fill();
                    };
                }
            }
            this.count--
            if (this.count < 0) {simulation.removeEphemera(this.name);m.doublejump = false}
            if (m.onGround && this.count < 480) {simulation.removeEphemera(this.name);m.doublejump = false}
        }
    })
}
landgreen commented 4 weeks ago

I've resisted double jump partly because it a cliche, but also because with negative mass, worm hole and grappling hook the game play space is full.

My default stance is I don't want any donated code, but I figured I'd test it out to see how it feels. I have to same this is very well written. It doesn't add much code overhead, and the graphics look cool. I'll look into integrating this into the game, but maybe not as a skin, I'm not sure. It should probably be a field tech.

TNTiger17 commented 4 weeks ago

Alright, I originally made this for a level I've been working on, and then realized it worked better as an individual tech, and thought it could be a cool idea on it's own. As for the gameplay space, I kind of just wanted an option for increased/unique mobility that would increase interaction with the map, rather than just sailing through it. I also wanted to able to focus on damage for both the field and gun, and I think plenty of builds in the game work well without energy, such as perfect diamagnetism or charmed baryons.

landgreen commented 3 weeks ago

I made something from this idea with one major change. You print a block and jump off it to get second jumps. It's a field tech for molecular assembler, which gives that field some nice movement and cool synergies with drones that can eat the blocks.

Screenshot 2024-06-12 at 7 45 57 AM Screenshot 2024-06-12 at 7 46 15 AM
kgurchiek commented 3 weeks ago

Cool, that looks really fun! Will the blocks be permanent or will they despawn after a few seconds like meteor shower’s?

landgreen commented 3 weeks ago

for now they last. it's not much different from additive manufacturing.

TNTiger17 commented 3 weeks ago

It would look cool if the blocks had a more explosive version of the warped shape additive manufacturing has, like a visual similar to the plasma ball explosion Maybe also make them shrink so using it a lot in levels like reactor won't fill the room like additive manufacturing with inflation does

kgurchiek commented 3 weeks ago

Speaking of shrinking, maybe to prevent players from spamming this forever it could start to shrink and give less powerful jumps after several consecutive jumps until it eventually isn’t powerful enough and you fall.

landgreen commented 3 weeks ago

I'm not sure there is a reason to worry about players spamming this or filling rooms. Right now players with good energy regen and just jump forever. Maybe it will need to be nerfed, but I rather do that with a research cost or a tech prerequisite.

TNTiger17 commented 3 weeks ago

Yeah, I just thought it could get annoying with strong energy builds later

landgreen commented 3 weeks ago

I figure people will jump less if it's annoying.

TNTiger17 commented 3 weeks ago

I was just thinking of a run I had where I kept spamming additive manufacturing and the room got filled, but it wasn't really annoying, so I think it's fine cause it's pretty easy to move blocks

landgreen commented 3 weeks ago

Good to know that others find lots of blocks manageable. I just did one test and I've decided to remove the energy cost to make it more carefree, but I had to cap it at 1 extra jump per jump, like a traditional double jump. I think it's basically done.

One idea I stole form you is giving the player a horizontal boost with the double jump. I wouldn't have thought of that.

TNTiger17 commented 3 weeks ago

Is it the same boost doubling horizontal speed, because I found the doubling speed to be pretty powerful especially on levels like subway and towers with lots of space, maybe a set speed boost would be good but I wanted the tech to give both a versatility and speed enhancement

landgreen commented 3 weeks ago

It's a linear scaling of 8.5. Here is the jump code:

let horizontalVelocity = 8.5 * (- input.left + input.right)
Matter.Body.setVelocity(player, { x: player.velocity.x + horizontalVelocity, y: -7.5 + 0.25 * player.velocity.y });
player.force.y = -m.jumpForce; //player jump force

here is the full code, it runs in the field code once a cycle

if (tech.isBlockJump) {
if (m.onGround && m.buttonCD_jump + 10 < m.cycle) this.blockJumpPhase = 0 //reset after touching ground or block
if (this.blockJumpPhase === 0 && !m.onGround) { //1st jump or fall
    this.blockJumpPhase = 1
} else if (this.blockJumpPhase === 1 && !input.up && m.buttonCD_jump + 10 < m.cycle) { //not pressing jump
    this.blockJumpPhase = 2
} else if (this.blockJumpPhase === 2 && input.up && m.buttonCD_jump + 10 < m.cycle) { //2nd jump
    this.blockJumpPhase = 3

    //make a block
    const radius = 25 + Math.floor(15 * Math.random())
    body[body.length] = Matter.Bodies.polygon(m.pos.x, m.pos.y + 40 + radius, 4, radius, {
        friction: 0.05,
        frictionAir: 0.001,
        collisionFilter: {
            category: cat.body,
            mask: cat.player | cat.map | cat.body | cat.bullet | cat.mob | cat.mobBullet
        },
        classType: "body",
    });
    const block = body[body.length - 1]
    //mess with the block shape (this code is horrible)
    Composite.add(engine.world, block); //add to world
    const r1 = radius * (1 + 0.4 * Math.random())
    const r2 = radius * (1 + 0.4 * Math.random())
    let angle = 0
    const vertices = []
    for (let i = 0, len = block.vertices.length; i < len; i++) {
        angle += 2 * Math.PI / len
        vertices.push({ x: block.position.x + r1 * Math.cos(angle), y: block.position.y + r2 * Math.sin(angle) })
    }
    Matter.Body.setVertices(block, vertices)
    Matter.Body.setAngle(block, Math.PI / 4)
    Matter.Body.setVelocity(block, { x: 0.9 * player.velocity.x, y: 10 });
    Matter.Body.applyForce(block, m.pos, { x: 0, y: m.jumpForce * 0.12 * Math.min(m.standingOn.mass, 5) });
    if (tech.isBlockRestitution) {
        block.restitution = 0.999 //extra bouncy
        block.friction = block.frictionStatic = block.frictionAir = 0.001
    }
    if (tech.isAddBlockMass) {
        const expand = function (that, massLimit) {
            if (that.mass < massLimit) {
                const scale = 1.04;
                Matter.Body.scale(that, scale, scale);
                setTimeout(expand, 20, that, massLimit);
            }
        };
        expand(block, Math.min(20, block.mass * 3))
    }

    //jump
    m.buttonCD_jump = m.cycle; //can't jump again until 20 cycles pass
    let horizontalVelocity = 8.5 * (- input.left + input.right)
    Matter.Body.setVelocity(player, { x: player.velocity.x + horizontalVelocity, y: -7.5 + 0.25 * player.velocity.y });
    player.force.y = -m.jumpForce; //player jump force
} else if (this.blockJumpPhase === 3 && m.onGround && m.buttonCD_jump + 10 < m.cycle) {
    //reset
    this.blockJumpPhase = 0 //reset
}
}
TNTiger17 commented 3 weeks ago

It think it works great, perhaps a visual for the block appearing in the future, but it's already implemented and it's fine on its own