Constrain a sprite within a polygon area in Phaser - javascript

I am creating a click and point adventure game. I have a character walking in the area but I'm unsure as to how to constrain where his feet can venture to. In the attached image, I have his feet in yellow, but I must not allow him to go outside the blue polygon area on the floor.
Any ideas on how to make this work? Please bear in mind, I'm creating a tween for the character to follow when the user clicks the screen. If he bumps into an area outside of the polygon, it will make the player (pink rectangle) stop.
I've tried arcade physics but that's only for square based sprites. I guess I have to use p2 physics? Can I use p2 physics on shapes or maybe a simple line like the polygon area?

You don't need to use any of Phasers physics engines to handle this, you can do it using the Polygon geometry object and just check if the click is within the polygon or not.
Here's an online example: http://phaser.io/examples/v2/geometry/polygon-contains
But the code is quite simple. First create a polygon (be aware about overlapping points and the way the poly winds, see docs for details):
poly = new Phaser.Polygon([ new Phaser.Point(200, 100), new Phaser.Point(350, 100), new Phaser.Point(375, 200), new Phaser.Point(150, 200) ]);
and then just check if they've clicked within it:
if (poly.contains(game.input.x, game.input.y))
{
// allow walk
}

Related

Video with a small bulge/curve in decentraland

I made a simple billboard in blender with a curve in it. I'd like to now how I can add a video to it with the same curve. The video needs to be loaded separately in dcl. I can now modify the video with Typescript (Threejs or babylonjs). Is there a simple way to curve that video/image?
Curved screens are made by creating a parent Entity, and placing multiple planes inside of it, each with the same video Texture applied to each plane.
You will then have to offset and rotate each plane so that it gets its curved shape. (Toughest part)
You will then have to apply a unique UV map to each plane so that each strip of the video only shows the correct part of the video.
https://github.com/pmacom/dcldash/blob/818b3627751e491173cbeef5ea436fbe69d1c1e4/src/utils/Uvs.ts#L3 contains a helper function for generating the proper UVs for each plane. You can probably just copy it directly into your project. Usage is as follows:
planeshapes.forEach((planeshape: PlaneShape, index: number) => {
planeShape.uvs = Dash_UV_Curved_Video(planeshapes.length-1, index)
})
Hopefully this helps

Three.js - Clip plane if object intersects?

I'm using a PlaneGeometry as water, and have added a ship (gltf model) on it. Problem is, when the boat slightly rests into the water, the water is shown inside the boat, even though the boat is afloat. Is there a way to clip the water when a boat (or other models/objects) intersect with it with motion?
Every material in Three.js has an AlphaMap property that you can use to change the opacity of the mesh. So you could draw a black rectangle where the boat is to "cut out" that part of the water plane with an opacity of 0.
I presume your boat is going to be moving, so your texture would also need to move this black rectangle. To solve this, you could use an HTML <canvas> element to draw and move the black rectangle. Then you could use THREE.CanvasTexture to turn the <canvas> into a texture for your plane's alpha.
const drawingCanvas = document.getElementById( 'drawing-canvas' );
const canvasTexture = new THREE.CanvasTexture( drawingCanvas );
const waterMaterial = new THREE.MeshBasicMaterial({
transparent: true,
alphaMap: squareTexture
});
See this working demo for how to use a 2D canvas as a texture in your 3D scene. When you draw on the top-left square, you'll see it being applied to the cube. You could copy this approach, but instead of assigning it to material.map, you'd use it on material.alphaMap.
You could check for the position of the hull vertices of the ship each frame and, given enough points on the PlaneGeometry, you could displace all vertices of the surface inside the ship hull to the y coordinate of the nearest hull vertex. This could probably also be done by a custom shader, which is probably a more efficient solution.
#Marquizzo's idea with the alpha channel is probably a better solution, too, since you don't really want to simulate the displacement of the water, as I assume, but simply get rid of the display of water inside the ship. In this case, I would place an orthographic camera above the ship, set the near and far clipping planes as close as possible to the plane, and use the alpha channel or rather CanvasTexture inside the alpha channel as rendertarget. This way, you'll get a real time alpha map that also reacts to rolling, pitching and heave of the ship.
Effect of floating is made with sin function, applied to y-coordinate. You can use the same principle to make gltf model(ship) move on any coordinate axis.
Example:
position.y = Math.sin(ship.userData.initFloating + t) * 0.15;

How to find equivalent coordinates in current world from other world in openlayers without mouse event

I have an OpenLayers map with a Polygon in every world. I have added an animation on view which pan's to the polygon on button click.
The problem is if the user is in other world than the one in which polygon's geometry lies, the animation takes user to the polygon's original world.
I don't want that to happen, if the user is in nth world to left or right, the pan to polygon should happen in that specific world only.
I am using polygon.getGeometry().getInteriorPoint().getCoordinates() to get the mid of the polygon and then set it as the center of the ol.View().
Now since the polygons geometry is in 0th world, view's center always gets settled to that world and hence map pan's that specific world.
Is there any way to calculate the coordinate in current world from the polygon's midpoint in another world ? I think that will solve the issue.
Here is what I am trying : current output
This will work for the current world (as defined by the date line). Since your geometry is relatively close to the dateline it might not be the shortest route.
var point = t.getGeometry().getInteriorPoint().clone();
var worldWidth = ol.extent.getWidth(view.getProjection().getExtent());
var currentWorld = Math.round(view.getCenter()[0]/worldWidth);
point.translate(currentWorld * worldWidth, 0);
view.animate({
center: point.getCoordinates(),
duration: 1200
});

Folding rectangles to form a cube using three.js

I am trying to make a cube with given 6 faces lying on the surface as a cube net with one face movable. Something like this:
In the above picture, there are 6 faces, one face ( blue one) is movable.
One can rotate them up together along their edges to form a “net”.
Once they think they are finished, they can press a “fold it” button – all edges turn up 90 degrees to create the cube (or may not be a cube if he hasn't joined the blue face at proper position.)
Below is intermediate status after pressing "fold it" button.
After the faces are folded it should like this:
The corresponding animation is given here: http://www.mathematikus.de/10/
(somehow that link is not working on mac)
I am not sure how to go about this. Any help is appreciated.
Thanking you in advance.
You can use hierarchy of objects.
var obj1 = new THREE.Mesh(...);
var obj2 = new THREE.Mesh(...);
obj1.add(obj2);
There's a good example of it.
So, using this principle, I made animation for folding the cube, given in your question. Of course, this is not the ultimate solution, this is just a starting point.
jsfiddle example
upd: I've updated the fiddle. You can start folding by clicking the PressMe button. Animation made with Tween.js (see the foldTheCube() function)

How to calculate the index of the tile underneath the mouse in an isometric world taking into account tile elevation

I have a tile-based isometric world and I can calculate which tile is underneath specific (mouse) coordinates by using the following calculations:
function isoTo2D(pt:Point):Point{
var tempPt:Point = new Point(0, 0);
tempPt.x = (2 * pt.y + pt.x) / 2;
tempPt.y = (2 * pt.y - pt.x) / 2;
return(tempPt);
}
function getTileCoordinates(pt:Point, tileHeight:Number):Point{
var tempPt:Point = new Point(0, 0);
tempPt.x = Math.floor(pt.x / tileHeight);
tempPt.y = Math.floor(pt.y / tileHeight);
return(tempPt);
}
(Taken from http://gamedevelopment.tutsplus.com/tutorials/creating-isometric-worlds-a-primer-for-game-developers--gamedev-6511, this is a flash implementation but the maths is the same)
However, my problem comes in when I have tiles that have different elevation levels:
In these scenarios, due to the height of some tiles which have a higher elevation, the tiles (or portions of tiles) behind are covered up and shouldn't be able to be selected by the mouse, instead selecting the tile which is in front of it.
How can I calculate the tile by mouse coordinates taking into account the tiles' elevation?
I'm using a javascript and canvas implementation.
There is a technique of capturing object under the mouse on a canvas without needing to recalculate mouse coordinates into your "world" coordinates. This is not perfect, has some drawbacks and restrictions, yet it does it's job in some simple cases.
1) Position another canvas atop of your main canvas and set it's opacity to 0. Make sure your second canvas has the same size and overlaps your main one.
2) Whenever you draw your interactive objects to the main canvas, draw and fill the same objects on the second canvas, but using one unique color per object (from #000000 to #ffffff)
3) Set mouse event handling to the second canvas.
4) Use getPixel on the second canvas at mouse position to get the "id" of the object clicked/hovered over.
Main advantage is WYSIWYG principle, so (if everything is done properly) you can be sure, that objects on the main canvas are in the same place as on the second canvas, so you don't need to worry about canvas resizing or object depth (like in your case) calculations to get the right object.
Main drawback is need to "double-render" the whole scene, yet it can be optimized by not drawing on the second canvas when it's not necessary, like:
in "idling" scene state, when interactive objects are staying on their places and wait for user action.
in "locked" scene state, when some stuff is animated or smth. and user is not allowed to interact with objects.
Main restriction is a maximum number of interactive objects on the scene (up to #ffffff or 16777215 objects).
So... Not reccomended for:
Games with big amount of interactive objects on a scene. (bad performance)
Fast-paced games, where interactive objects are constantly moved/created/destroyed.(bad performance, issues with re-using id's)
Good for:
GUI's handling
Turn-based games / slow-paced puzzle games.
Your hit test function will need to have access to all your tiles in order to determine which one is hit. It will then perform test hits starting with the tallest elevation.
Assuming that you only have discreet (integer) tile heights, the general algorithm would be like this (pseudo code, assuming that tiles is a two-dimensional array of object with an elevation property):
function getTile(mousePt, tiles) {
var maxElevation = getMaxElevation(tiles);
var minElevation = getMinElevation(tiles);
var elevation;
for (elevation = maxElevation; elevation >= minElevation; elevation--) {
var pt = getTileCoordinates(mousePt, elevation);
if (tiles[pt.x][pt.y].elevation === elevation) {
return pt;
}
}
return null; // not tile hit
}
This code would need to be adjusted for arbitrary elevations and could be optimized to skip elevation that don't contain any tiles.
Note that my pseudocode ignores vertical sides of a tile and clicks on them will select the (lower elevation) tile obscured by the vertical side. If vertical tiles need to be accounted for, then a more generic surface hit detection approach will be needed. You could visit every tile (from closest to farthest away) and test whether the mouse coordinates are in the "roof" or in one of the viewer facing "wall" polygons.
If map is not rotatable and exatly same as picture you posted here,
When you are drawing polygons, save each tile's polygon(s) in a polygon array. Then sort the array only once using distance of them(their tile) to you(closest first, farthest last) while keeping them grouped by tile index.
When click event happens, get x,y coordinates of mouse, and do point in polygon test starting from first element array until last element. When hit, stop at that element.
No matter how high a tile is, will not hide any tile that is closer to you(or even same distance to you).
Point in polygon test is already solved:
Point in Polygon Algorithm
How can I determine whether a 2D Point is within a Polygon?
Point in polygon
You can even check every pixel of canvas once with this function and save results into an 2d array of points, vect2[x][y] which gives i,j indexes of tiles from x,y coordinates of mouse, then use this as a very fast index finder.
Pros:
fast and parallelizable using webworkers(if there are millions of tiles)
scalable to multiple isometric maps using arrays of arrays of polygons sorted by distance to you.
Elevation doesnt decrease performance because of only 3 per tile maximum.
Doesn't need any conversion to isometric to 2d. Just the coordinates of corners of polygons on canvas and coordinates of mouse on the same canvas.
Cons:
You need coordinates of each corner if you haven't already.
Clicking a corner will pick closest tile to you while it is on four tiles at the same time.
The answer, oddly, is written up in the Wikipedia page, in the section titled "Mapping Screen to World Coordinates". Rather than try to describe the graphics, just read the section three times.
You will need to determine exactly which isomorphic projection you are using, often by measuring the tile size on the screen with a ruler.

Categories