Parasyte

Members
  • Content Count

    150
  • Joined

  • Last visited

Everything posted by Parasyte

  1. Parasyte

    Code that runs on resize

    There's also VIEWPORT_ONRESIZE. Depending on which event you really care about. But the event handler is definitely the right way to handle this.
  2. Parasyte

    registerPointerEvent not emitting in 5.1

    FWIW, you can use the pointer-events CSS property to allow events to "fall through" the invisible DOM container to the canvas below. You'll have to set the same property on the GUI element children to allow them to recapture pointer events that the parent ignores.
  3. Parasyte

    Minimap for melon v5.1.0

    The rectangle defines the draw destination. Usually it's the viewport: https://github.com/melonjs/melonJS/blob/5.1.0/src/game.js#L345 If you already have a GUI object or something else that represents the minimap size and position, you might just be able to use its rect. Otherwise you can create a me.Rect with the parameters you need, and use that.
  4. Parasyte

    registerPointerEvent not emitting in 5.1

    Do any of these examples work for you? http://melonjs.github.io/melonJS/examples/multitouch/ http://melonjs.github.io/melonJS/examples/drag-and-drop/ http://melonjs.github.io/melonJS/examples/shapes/ http://melonjs.github.io/melonJS/examples/UI/ http://melonjs.github.io/melonJS/examples/particles/ http://melonjs.github.io/melonJS/examples/whack-a-mole/ The drag-and-drop and particles examples no longer work for me, but the other examples do. They all use registerPointerEvent
  5. @Growler No problems with that! It's conceptually similar to using shape entities for things like doors or kill planes. I guess in this case it's most similar to me.ParticleEmitter
  6. What kind of events would trigger the entities to "actually load"? Would it be something that just happens nondeterministically, or when loading the map with certain state? If the latter, I would probably lean toward using a copy of the map with the various different states. I know this won't work for every situation, but it's definitely the easiest to implement. For a longer-term solution, you might consider using the object layers supported by Tiled. IIRC, you can change the visibility (on/off, but melonJS just uses it to set the entity opacity to 0) and melonJS won't render invisible layers. But the entity would still be active and needs to be "disabled" or else it will continue to be updated and will be included in collision detection tests, etc. One idea that just came to me is that each object layer can be implemented as a me.Container, if you pass options.flatten=false to me.levelDirector.loadLevel. In short, the most naïve approach is to grab the container reference by the layer's name in the options.onLoaded callback, then remove it from the scene and store it somewhere for later until you need it again. It might look something like this: me.levelDirector.loadLevel('my_map', { flatten: false, onLoaded: () => { // Save an array of every layer named 'quest' to a global object game.quest_layers = me.game.world.getChildByName('quest'); // Remove all of the quest layers from the scene game.quest_layers.forEach((layer) => { me.game.world.removeChild(layer, true); // The second arg preserves the layer }); }, }); setTimeout(() => { // ... Some time passes and we can trigger the quest entities to appear // We'll just use a random layer index for illustration ... let x = Math.floor(Math.random() * game.quest_layers.length); // Remove the layer from the global array, and add it to the scene let layer = game.quest_layers.splice(x, 1); me.game.world.addChild(layer); }, 5000); This is super simplified. A more complex implementation might take layers by multiple names, and store them in a hash map, or even iterate the entire world container looking for invisible containers... There's a lot that can be done to customize it, but the takeaway is that it's desirable to remove children from the scene graph, and add them back in later. And this can be done with the optional keepalive argument when removing children. That might be a good place to start, anyway. Hope it helps.
  7. I am familiar with immediate mode GUI! Never really considered it in the web stack, though. The DOM is already the opposite of immediate mode, and trying to reimplement the entire collection of GUI elements in webGL would be insane. 😅 I also can't see the immediate mode working well with a batching GL compositor that melonJS uses, since the compositor relies on the fact that GL is a stateful API; It tries to optimize rendering by uploading everything early and reusing state often. It is possible to stream vertices to the GPU, though. And that's exactly how dear imgui works.
  8. Forgive me if this sounds skeptical, but most of the existing abstractions are already lightweight, and you'll just end up reinventing the wheel in many areas. The one major exception is probably the observable vector classes. On the other hand, there's really no requirement to use them, nor any of the physics classes, or particle emitters, or tile maps, etc. if you don't plan to use any of that functionality. The existing game loop is about as bare-bones as it gets: https://github.com/melonjs/melonJS/blob/acf776161b421d64509c87bbedfe00501104c863/src/state/state.js#L153-L167 The update and draw loops are likewise very light: https://github.com/melonjs/melonJS/blob/97ede483f5798651e7a7c225df2bb77df66a4a27/src/game.js#L262-L363 ... handling various things like pausable timers and accurate frame skipping/interpolation logic. me.game.world is a container which hosts an array of children to update and draw. The complexity that you envision comes from the nested hierarchy of containers, that can build a complete-but-flexible scene graph. The added flexibility comes at the cost of added complexity. Containers are also fairly lightweight: https://github.com/melonjs/melonJS/blob/acf776161b421d64509c87bbedfe00501104c863/src/renderable/container.js#L758-L849 Everything else in this module is a collection of utility methods to help support nesting. It is conceivable to replace the root container (me.game.world) with a non-nestable container, if that's what you're going for... Which is exactly what the ParticleContainer is. It's unclear just how much benefit you can extract from doing such a thing, but it is certainly an option. So to answer your question, you just need to determine at which level you want to replace the game loop, and patch out that part. You can either monkeypatch it through the me.game references, or using the builtin patching APIs. And then you need to determine which pieces you need to reimplement for a solid foundation beyond just drawing textures.
  9. The code in the OP shows that you return true from the collision handler unconditionally. (Remember, this is the only information I have to go on! I can't see all of your code, and I definitely don't see any conditions checking the shape index.) Which means it would apply the collision response (repel the entities by adjusting the velocity). The code I linked above shows how it calls respondToCollision on the body when the collision handler returns true. And this method adjusts the velocity accordingly. Thus, my observation.
  10. I think what you're seeing has something to do with the misunderstanding of collision shapes on a body. Collision detection does not happen on a "per-shape basis", but on a "per-body basis". In short, bodies collide with other bodies, not with shapes. The shapes are only there to add a physical structure to the body. Under this axiom, it doesn't make sense to have a large rectangle with a smaller inner rectangle, because only the larger rectangle "matters" when performing collision detection. Secondly, you are using two competing collision processes and expecting them to operate independently (I guess). In reality, they are just two sides of the same feature; the me.collision.check() call is the caller, and the onCollision handler is the callee. Obviously, the check ignores itself, but it will call onCollision on the same object in addition to other objects that implement the handler. What you're seeing in the console log is this exact behavior: one of the entities somewhere in the scene is not colliding with anything, and somewhere else, two or more entities are colliding. Thirdly, the scenario that you are testing is artificial, since it should not be possible (under normal circumstances) to end up with two solid entities in the configuration shown in the screenshot. What I mean by artificial is that you have set explicit coordinates to "force" the smaller entity inside the larger one. If they were moved using only the physics properties such as velocity, they would instead repel one another by responding to the collision; adjusting the velocities to counteract any motion that would result in overlapping like that. I believe that describes the situation, at least in short. To fix it, you want to use the collision detection system only as a way to respond to collisions (e.g. pushing solid entities apart, taken damage from projectiles, etc.) and use something else like distanceTo() for the interaction range. You can use me.collision.quadTree.retrieve() to gather a list of potential candidates for performing distance checks. edit: I had mistakenly asserted that onCollision will not be called on the same object that calls me.collision.check(). The handler is definitely called on both entities when they collide. You can see the implementation here: https://github.com/melonjs/melonJS/blob/97ede483f5798651e7a7c225df2bb77df66a4a27/src/physics/collision.js#L486-L492
  11. Parasyte

    Hybrid GFX test - scaling tilemap

    @Growler I think you might want to try it the other way; Set the video mode into the highest resolution supported, and scale up the tile background layer. I don't have any code on hand for this, and I'm not 100% sure it will work with collision shapes and stuff, but you definitely want to go with this approach. Going through some old github issues, it looks like the new Renderable transformation matrices will make this significantly easier to work with: https://github.com/melonjs/melonJS/issues/335#issuecomment-231292730 The problem you are facing in the screenshots is that the canvas size is very small, and you're stretching the whole thing, making big chunky pixels. Scaling down a GUI element onto that canvas is the same thing as scaling the image down in photoshop, and then scaling it back up with nearest neighbor (this is the "stretching" that I just described).
  12. Parasyte

    How do I tween the rotation

    I used it in Neverwell Moor for the intro scrolling: https://github.com/blipjoy/nm-prototype/blob/gh-pages/js/objects/screens.js#L357-L384
  13. Parasyte

    How do I tween the rotation

    The me.Tween class provides a callback that is called with a delta on each frame. The delta can be passed directly to the rotate method; no need to manage state on the class at all.
  14. Parasyte

    Do you build your UI's in MelonJS or DOM?

    For a quest log, yes. For other bits of status GUI, no, probably not. You want to avoid moving DOM elements as much as possible, since that will cause the UA to reflow the DOM. Status bars are easy to render in melonJS, using either the canvas context drawing methods (like fillRect()) or by clipping a texture. Using the melonJS font classes are also pretty decent performance-wise (except when you want to update the text on every frame, that doesn't work well with the WebGL compositor).
  15. Parasyte

    Do you build your UI's in MelonJS or DOM?

    Simple elements like buttons can be implemented with the melonJS GUI_Button class. The advantages with this are immediate feedback (DOM click events have a delay on mobile devices), and they use the WebGL compositor (great for all-in-one über textures) For more complex UIs, use the DOM. DOM should definitely be in your toolbelt for rich GUIs. The advantages are obvious, and there are very few disadvantages (more like just caveats). It's great for any form input fields, scrollable areas, etc. DOM also has the advantage that the text rendering is really fantastic, especially with web fonts, and certain character sets (CJK, RTL, etc) One of the caveats you might run into is that by default all DOM elements consume pointer events. There are some useful CSS properties that can help you workaround it if needed: https://developer.mozilla.org/en-US/docs/Web/CSS/pointer-events and https://developer.mozilla.org/en-US/docs/Web/CSS/touch-action
  16. Parasyte

    Fix position after scale

    If you are using the collision shapes for pointer events, you can create a plugin to patch me.input.globalToLocal() to apply the same scaling transformation. This won't make the debugPanel render the collision shapes scaled, but your plugin could also patch the debugPanel's draw method to apply the scaling transformation, if you needed to. If, however, you aren't using pointer events, why would you want to scale the collision shapes at all?
  17. Parasyte

    Run without rendering (for online game)

    I think you will find it significantly more difficult than it appears at first. I'm not trying to discourage you, that's just the reality. But if you can manage to make it successful, then that is awesome.
  18. Parasyte

    Run without rendering (for online game)

    Out of curiosity, how do you expect running melonJS on the server to prevent cheating? This is a topic which I have studied fairly extensively. Unless you implement a mechanism to actively address cheating, you're going to get a very sad surprise one day when your players start complaining about cheaters. For starters, here's a short list of relevant resources on the subject: Deterministic Lockstep Lag Hacking Pick your favorite anti-cheat tools; EAC, Punkbuster, ... To followup with an idea provided in that Stack Overflow answer, running the game only server-side is effective against cheaters if you can guarantee low latency while streaming an audio/video feed (or the procedural equivalent). But that's way beyond the scope of what melonJS intends to provide. By the way, are you familiar with the concepts of prediction, dead reckoning, and jitter buffering for networked multiplayer? If you miss these, you're going to have an unpleasant experience because the network is unreliable. Once your game goes multiplayer, you've entered the realm of distributed computing. And as with the CAP theorem, you can't sacrifice partition tolerance. This is a fun can of worms that many platform engineers will spend their entire careers learning and dealing with. Isn't it amazing how extending a simple game to play on even two computers suddenly raises the complexity exponentially?
  19. Parasyte

    melonjs zooming and panning

    @Growler I actually wrote a crazy bit of logic that can animate tile layers for that... Each frame is on its own layer, and the animation just cycles the layer visibility. The code for that is here: https://github.com/blipjoy/nm-prototype/blob/gh-pages/js/objects/screens.js#L43-L55 There are better ways to do this now that melonJS and Tiled both support tile animations. But back then, this was a really impressive feat. BTW the original windmill assets are available here: https://opengameart.org/content/lpc-cnilsson
  20. Glad it all worked out! 10,000 is also quite a lot; each of those entities needs to update in a tight loop on every frame, and again in a second tight loop to draw. It's a very similar problem that the particle emitter experiences; but we have the luxury that the particles are much lighter-weight than entities. A more efficient implementation would be moving the BasicPlant logic into the PlantManager. The manager is already recording the state of each plant in a 2D array, so it's not a huge leap to have the PlantManager draw each plant to an off-screen canvas when a new plant is spawned. That will reduce the update and draw calls from O(n) to O(1) runtime, which is huge! (Where n is the maximum number of plants.) And updating the plant state from the manager will be much lighter weight than the Entity class, too. So that's also a win. It sounds like a really cool concept, though. I've always wanted to make a game with some evolution simulation elements.
  21. First thing I noticed is that you are using a bunch of global variables in the PlantManager class, probably unintentionally. plantMap should probably be a class property: this.plantMap. The others (plantLocation, clean, random, x, y, growthLocation, plant) should be declared with var (or let if you're using ES6 syntax). Fixing the variable scoping may not solve the issue, though. The second thing I noticed is that on the edges of the tilemap, the plantManger.getGrowthLocation() method will raise an exception, because you're filtering the undefined values after attempting to access the plant property on undefined. You can easily solve this by filtering the array before mapping the values. Ah, here is the problem, on this line: if(growthLocation && !plantMap[x][y].plant){ The boolean is pointing at the parent location, which is initially false. You want to check the value of growthLocation.plant here, and assign true to this property inside the condition body. Also, as a side note, you should set plantMap[50][50].plant = true in the seed method, otherwise it will grow a second plant in that location. Also, one question and an observation: Are all of these plants supposed to be 1x1 pixel each? Seems like you're going to end up creating a ton of plant objects if that's true! A modern retina display has over 5 million pixels, as an example. So a full screen plant-reproduction-simulator on such a device will create a maximum of 5,184,000 plant objects. The game will become unplayably slow before it fills the entire screen with green pixels, though.
  22. Parasyte

    NPC Healthbar with DOM element

    I just noticed you're using the "flex-width" scaling method, which means the canvas aspect ratio is flexible along the horizontal axis. The vertical aspect ratio can be used to scale both dimensions equally. In your example code: let divY = canvasH / ratioH; This is the ratio you want to scale both axes by. So if you change the newCoordsX to scale by divY instead, it will all work: let newCoordsX = coords.x * divY; let newCoordsY = coords.y * divY; BTW, all of this scaling logic will have to change if you decide to switch to a different video scaling mode.
  23. Parasyte

    melonjs zooming and panning

    I have some really old code that does non-linear interpolations (tweening) between camera positions. Some of it should still be usable. You can see it in action on the Neverwell Moor title screen, and the code is available here: https://github.com/blipjoy/nm-prototype/blob/gh-pages/js/objects/screens.js#L349-L384 Maybe it will help you out.
  24. Parasyte

    NPC Healthbar with DOM element

    Ok, the test was successful. It means the scaling is what's causing the issue. You can fix it by applying the same transformation to the DOM element position. You can get the transformation by reading the canvas width and height, and dividing by the width and height that is passed to me.video.init(). This will give you two values; one for width and one for height. When you go to move the DOM elements, multiply the x and y coordinates with the two scaling values you got from the last step.
  25. Parasyte

    NPC Healthbar with DOM element

    I think you might be having problems with the DOM element position because the canvas is scaled. If you disable the video scaling mode, you should see the element position align with the entity. You can try this to validate the hypothesis that video scaling is the issue. If this identifies the cause, then you can fix it by scaling the position by the same factor as the video scaling. You might have to compute the scaling factor from the initial resolution and actual canvas dimensions...