Growler Posted August 24, 2017 Share Posted August 24, 2017 I am creating a healthbar for NPCs and minions. I wasn't sure how to do it quickly with Melon (on Melon 2.1.1), so I'm doing it with the DOM. For this, I thought it'd be easy enough to append a healthbar element for each instantiated minion entity, then update the healthbar <div> as the entity moves. The problem is, the healthbar's location is initially set just fine, but as the main player moves, the healthbars tend to follow oddly with the player, moving away from the minion entities. I need the healthbar to stay consistently over the heads of the minion entities. How can I do this? let $healthBar = $(`<div class="healthbar_${this.id}">`); let updateLocation = () => { var coords = me.game.viewport.worldToLocal(this.pos.x, this.pos.y); $healthBar.css({top: `${coords.y}px`, left: `${coords.x}px`}); ... Quote Link to comment Share on other sites More sharing options...
Growler Posted August 25, 2017 Author Share Posted August 25, 2017 @Parasyte Any thoughts on this? Here is a screen recording of the problem: (note it's extra sluggish due to screen recording and playing at the same time) Quote Link to comment Share on other sites More sharing options...
Growler Posted August 28, 2017 Author Share Posted August 28, 2017 @obiot any thoughts? Quote Link to comment Share on other sites More sharing options...
obiot Posted August 29, 2017 Share Posted August 29, 2017 Looks like you are using an isometric map, so what you are probably missing is to convert back the position to an orthogonal projection (using http://melonjs.github.io/melonJS/docs/me.Vector2d.html#to2d) before calling the WorldToLocal function. So in pseudo code, something like this : 1. localVector = copy(player.pos) 2 . LocalVector.to2d() 3. coords = worldToLocal (LocalVector) Quote Link to comment Share on other sites More sharing options...
Growler Posted August 29, 2017 Author Share Posted August 29, 2017 @obiot, I am using a frontal 2D map with the art drawn to look like oblique perspective on an orthogonal map... so I can fake the 3D effect. See attached picture. Quote Link to comment Share on other sites More sharing options...
obiot Posted August 29, 2017 Share Posted August 29, 2017 oh I see is it not an issue with you updateLocation method and how it access the minion current position ? I see `this.pos.x` there, so is updateLocation a method of the minion class ? Quote Link to comment Share on other sites More sharing options...
Growler Posted August 29, 2017 Author Share Posted August 29, 2017 @obiot code snippet provided below of the minion's Entity class. healthbar:function() { ... var updateLocation = () => { var coords = me.game.viewport.worldToLocal(this.pos.x, this.pos.y); $healthBar.css({top: `${coords.y}px`, left: `${coords.x}px`}); if (!this.inViewport) { hideHealthbar(); } else { showHealthbar(); } }; return { ... updateLoc: updateLocation, } }, update: function(delta) { ... this.body.update(delta); if(!me.collision.check(this)) { if (this.nearNPC) this.nearNPC = false; } return (this._super(me.Entity, 'update', [delta]) || this.body.vel.x !== 0 || this.body.vel.y !== 0); }, onCollision : function (response, collidedObject) { if (collidedObject.type === 'npcs') { return false; } if (collidedObject.type === 'PlayerEntity' ) { if (!this.nearNPC) this.nearNPC = true; return false; } if (collidedObject.type === 'AttackObject') { if (this.nearNPC) this.nearNPC = false; return false; } if (collidedObject.type === 'collisionShape') { if (this.nearNPC) this.nearNPC = false; return false; } if (this.nearNPC) this.nearNPC = false; // Make all other objects solid return false; } Quote Link to comment Share on other sites More sharing options...
Growler Posted August 31, 2017 Author Share Posted August 31, 2017 @obiot given the code snippet above of my updateLocation, any thoughts on how to keep the healthbars over the NPCs' heads? Quote Link to comment Share on other sites More sharing options...
Parasyte Posted September 5, 2017 Share Posted September 5, 2017 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... Quote Link to comment Share on other sites More sharing options...
Growler Posted September 5, 2017 Author Share Posted September 5, 2017 @Parasyte Not sure how to "disable" scaling as me.video's scale method takes a string or number, not a boolean. I assume changing to 1.0 "disables" scaling. Also, you can see that the healthbar DOM element "moves" (updates) as I move my player. This makes sense from a logic perspective because the enemy entity's location is changing respective to the player in the viewport, but it shouldn't update the healthbar's location over the minion. Changes shown below to game.js' scaleMethod: wrapper : "screen", renderer : me.video.CANVAS, scale : "auto", // changed to scale : 1.0 scaleMethod : "flex-width", doubleBuffering : true, transparent : true, antiAlias : true This makes my canvas tiny but doesn't fix the DOM elements. Am I misunderstanding what you're saying? Quote Link to comment Share on other sites More sharing options...
Growler Posted September 7, 2017 Author Share Posted September 7, 2017 @Parasyte sorry but any more thoughts on this? It's really distracting to my players, but I can't really remove the healthbars because players want them. Quote Link to comment Share on other sites More sharing options...
Growler Posted September 8, 2017 Author Share Posted September 8, 2017 @obiot perhaps you have some more insight? Please see above Quote Link to comment Share on other sites More sharing options...
obiot Posted September 8, 2017 Share Posted September 8, 2017 sorry but i'm out of idea myself.... all I can say is that it does not seems an issue on melonJS side, so I'd rather look at your page composition (HTML/CSS) to see if something there is acting weird. did you try to output the actual returned coords in the console, and mornitor the ouput correspondingly to the player position ? at least it would allow eliminate a part of the equation, and to be fixed on either the coordinates returned by melonJS are correct or not. On a side note, you should also use a local vector object in your entity and pass it to the `localToWorld ` function, this will avoid instantiating a vector object at every frame and will make the GC more happy https://github.com/melonjs/melonJS/blob/master/src/renderable/viewport.js#L486 Quote Link to comment Share on other sites More sharing options...
Parasyte Posted September 10, 2017 Share Posted September 10, 2017 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. Quote Link to comment Share on other sites More sharing options...
Growler Posted September 12, 2017 Author Share Posted September 12, 2017 Hi @Parasyte - thanks for this. The health bars align over the NPCs' heads, but still don't stay perfectly over them. They still seem affected by the player's movement. Code: var updateLocation = () => { let canvasW = $("#myCanvas").width(); let canvasH = $("#myCanvas").height(); console.log('Canvas W/H: ', canvasW, canvasH); // [1375.5, 867] let ratioW = globals.settings.aspectratio[game.data.ratio][0]; let ratioH = globals.settings.aspectratio[game.data.ratio][1]; console.log('Aspect Ratio:', ratioW, ratioH); // [800, 600] let divX = canvasW / ratioW; let divY = canvasH / ratioH; let coords = me.game.viewport.worldToLocal(this.pos.x, this.pos.y); let newCoordsX = coords.x * divX; let newCoordsY = coords.y * divY; $healthBar.css({top: `${newCoordsY}px`, left: `${newCoordsX}px`}); Pictures: If I move the player left, it moves the healthbar opposite. If I move the player right, it moves the healthbar over the NPC's head. Quote Link to comment Share on other sites More sharing options...
Growler Posted September 15, 2017 Author Share Posted September 15, 2017 @Parasyte Am I still doing it wrong? Please see above Quote Link to comment Share on other sites More sharing options...
Parasyte Posted September 18, 2017 Share Posted September 18, 2017 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. Quote Link to comment Share on other sites More sharing options...
Growler Posted September 20, 2017 Author Share Posted September 20, 2017 @Parasyte thanks so much! Quote Link to comment Share on other sites More sharing options...
Recommended Posts
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.