Code Monkey home page Code Monkey logo

Comments (12)

straker avatar straker commented on May 10, 2024 1

As I work with the pointer code, I'm wondering if I should flatten the kontra object so there are no keys, pointer, etc. sub-objects.

The reason for this is that the functions exported by both of these don't make much sense out of context. Pointer has pressed, onUp, onDown, over, track and untrack. Keys has pressed, bind, and unbind. These functions aren't very clear what they are doing out of the context of the keys and pointer objects if you were to import them by themselves. I already have to rename the two pressed functions to be keyPressed and pointerPressed, so I might as well do the same for the rest of the functions.

// what exactly is onDown? Is it a key onDown event? Hard to know without the 
// `pointer` context from before
import { onDown } from 'kontra';

This would mean I would move the pointer and keys context to the function names themselves and just have them be off the kontra object directly. This gives two advantages that I see:

  1. There would be a 1:1 parity between function name and kontra function. Instead of having kontra.keys.pressed be one function but keyPressed be the function you have to import, it would just always be keyPressed.
  2. The exported function names make more sense when imported. onDown isn't very specific but onPointerDown is.

from kontra.

BoldBigflank avatar BoldBigflank commented on May 10, 2024

I'd like to help out with this, but haven't done this stuff before. Perhaps you could get one done and I can use it to mimic on some others.

from kontra.

straker avatar straker commented on May 10, 2024

Sounds great. The main problem is I've been trying to learn how tree shaking works. As the code is now, it's not very tree shakable so you get the entire library when you do some things. Things like adding event listeners on keyboard and pointer events in the main scope cause lots of problems.

The only thing I've been able to find is moving those things to their own functions that either the user has to call, like an init function but for keyboard, pointer, assets, etc., or doing some creative code refactoring to make sure those things are auto inited when the user calls the standard functions. So when a user calls the bind or pressed functions of keyboard, the keyboard events are setup at that point instead of before (which means the first call will always fail since there's no events set up).

Example of option 1:

import { keys} from 'kontra';

keys.init();  // set up event listeners
keys.bind('a', () => {
  // do things on 'a' key
});

Example of option 2:

import { keys } from 'kontra'

// calling pressed will setup event listeners, which means 
// this is always false until after the function runs
if (kontra.keys.pressed('a')) {

}

I'm not really excited about either of these options but I'm not really finding anything else that can be done to make the code tree shaking friendly (which is mostly the entire reason to move to es6 module imports IMO).

from kontra.

straker avatar straker commented on May 10, 2024

Alright, so I think I found a compromise that will work (or will have to work). I've pushed my current workings to the es6Modules branch. I have currently done:

  • animation
  • core
  • events
  • gameLoop
  • keys

If you look at keys.js, I have to export the init function that adds the event listeners. Anyone who imports any function from that file will just have call the initKeys function themselves since I can't find any way to to do it for them while still removing it from tree shaking if it's not imported.

import { initKeys, pressed } from 'kontra'

initKeys();
if (pressed('a'), () => {
  // a key pressed
});

However, in kontra.defaults.js, I add the init function to the kontra object, and then can test to see if that function exists inside the main init function of core.js, and if it does I can call it there. That will auto init the keyboard listener for anyone who imports the entire library or downloads the generated output of the entire library.

import kontra from 'kontra';

kontra.init();  // this will also call the keys init function now

My Guidelines so far

The general approach I'm currently taking is to extract all the objects (keys, assets, pointer, etc.) and just make them export their functions. Then inside kontra.defaults.js construct the objects with their functions to maintain the current API. That way you can import just the functions needed from those files and let tree shaking remove the rest.

I've also tried to make all the constructor functions (sprite, animation, vector, etc.) Classes where it makes sense. There are some things (like the gameLoop) where the amount of private variables would just bloat the code with so many this references that it's noticeably smaller to leave it as is. For any Class, I've exported the factory function wrapper (so you don't have to call new) and added the Class as the prototype to the function.

Lastly, I have a test file in examples/test.js that I run rollup on and edit as I go to see how the output out.js looks. You can generate it by running npm run rollup. This lets me test things and make sure I'm not doing something that breaks tree shaking. Mostly what I've found is that accessing any global object/function, chaining functions, or using any imported variables/functions at the top scope will cause a side effect and break tree shaking. That's why in assets.js the canUse object was turned into a function since it needed access to a global Audio call and chained the result.

Anyway, that's a lot to take in and this is still a lot of trial and error. Hopefully this works for the rest of the code.

from kontra.

BoldBigflank avatar BoldBigflank commented on May 10, 2024

Doing some work on this now, looks like I'm digging into assets, keys and sprite.

from kontra.

straker avatar straker commented on May 10, 2024

from kontra.

straker avatar straker commented on May 10, 2024

Alright, latest changes pushed. Although most of the files are converted to es6 modules, the organization and what is exported / how is still undecided for me. I don't like having to export init functions for keys and pointer, but I can't think of any other way to do it while still having it work for tree shaking. I also went ahead an implemented your asset feature to return the asset if it already was loaded.

I also am still debating between lowercase or upper case for any factory function / class name export. Lower case is more like it is v5, but prevents using that name in your code

import { sprite } from 'kontra.js'

// cant name a variable `sprite` anymore

Upper case solves this but I'm just not sure how I feel about it.

import { Sprite } from 'kontra.js'

let sprite = Sprite();

Lastly, I'm trying to do all the breaking changes in this version, so if you have any breaking changes you've been wanting to make, let me know.

from kontra.

BoldBigflank avatar BoldBigflank commented on May 10, 2024

You might not have noticed that this change makes binding "space" doesn't work any more, now it's " ".

from kontra.

straker avatar straker commented on May 10, 2024

Ya... I wanted to use event.code so it'd be space but it's not widely supported. We could go back to keycodes, but the building up of it would have to move to the init function as well (can't loop over the object and add properties in the main scope)

from kontra.

BoldBigflank avatar BoldBigflank commented on May 10, 2024

keys doesn't seem so hard, couldn't you give it an let initialized = false variable and on the first line of bindKeys and keyPressed add if (!initialized) initKeys()

I suppose that doesn't work for keyPressed at first, which is a concern...

from kontra.

BoldBigflank avatar BoldBigflank commented on May 10, 2024

Is it possible to put a on('init', initKeys()) somewhere, like pointer used to do.

from kontra.

BoldBigflank avatar BoldBigflank commented on May 10, 2024

#66 works for me.

from kontra.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.