I need to determine the area of a Polygon object that's been drawn on a Canvas in a Windows Store App (WinRT) in XAML/C#. It looks like they stripped the Geometry.GetArea() from the WinRT libraries, so I unfortunately can't use that. Since this polygon is irregularly shaped, with a dynamic list of points, I can't use any static formulas. Are there any libraries or 3rd-party extensions that I can use in WinRT to accomplish this?
I was able to figure this out. This method will take a Polygon object and give the area.
double GetPolygonArea(Polygon poly)
{
List<Point> points = new List<Point>();
foreach (Point p in poly.Points)
{
points.Add(p);
}
points.Add(poly.Points[0]);
double xTotal = 0;
for (int x = 0; x < points.Count - 1; x++)
{
xTotal += ((points[x].X) * (points[x + 1].Y));
}
double yTotal = 0;
for (int y = 0; y < points.Count - 1; y++)
{
yTotal += ((points[y].Y) * (points[y + 1].X));
}
return Math.Abs((xTotal - yTotal) / 2);
}
Related
I want to initialize a square of textures with sf::sprite elements.
To make the main()-function as clean as possible, I wrote a function in another file, it looks like this:
vector<vector<sf::Sprite>> init_board_graphics(int size) {
sf::Texture _t1;
sf::Texture _t2;
_t1.loadFromFile("images/whitefield.png");
_t2.loadFromFile("images/blackfield.png");
vector<vector<sf::Sprite>> board;
//init vector for insert row-values
vector<sf::Sprite> help_vector;
for (int i = 0; i < size; i++) {
help_vector.clear();
for (int j = 0; j < size; j++) {
sf::Sprite insert_element;
if ((i + j) % 2 == 0) {
insert_element = sf::Sprite(_t1);
}
else {
insert_element = sf::Sprite(_t2);
}
insert_element.setPosition(i * pixel_field, j * pixel_field);
help_vector.push_back(insert_element);
}
board.push_back(help_vector);
}
return board;
}
When I call the function in main(), everything is fine at first, the elements are at the correct positions and the textures are also of correct size.
When I try to debug the next steps, I can observe that the textures of the elements are getting changed in size, even though the next lines have absolutely nothing to do with my object. First, I thought the entries are getting changed because I allocate the entries in the <vector<vector<sf::sprite>> - object in a wrong way but I fixed this:
if (parameters::visual_output) {
//Draw field
for (int i = 0; i < size_board; i++) {
vector<sf::Sprite> help_vec = board[i];
for (int j = 0; j < size_board; j++) {
window.draw(help_vec[j]);
}
}
}
The textures are still getting changed for some reason. Why is this happening?
I'm trying to make a homing projectile for my bullet hell game and I'd need to be able to calculate the angle between the target and projectile relatively to the projectile's angle (0 degrees would be the direction the projectile is pointing). Right now the angle calculation is absolute done using point_direction, but the problem is when the target is at the 4th sector the projectile starts steering the wrong way. Another issue is that if the projectile does a 180 degree turn while chasing the target (or moves down if fired by enemy) the steering direction will get inverted. I have also tried mp_potential_ functions but their pathfinding is too "agressive".
This is what my current code looks like:
if(instance_exists(obj_fighter1)) {
var target;
target = instance_nearest(x, y, obj_fighter1);
if(target != noone) {
var angle_to_target;
angle_to_target = point_direction(x,y,target.x,target.y);
if(angle_to_target < direction) {
direction -= 2;
}
if(angle_to_target > direction) {
direction += 2;
}
}
}
Hopefully this information is enough and is understandable.
Okay, a common Game Maker question. The routine I use is below. Looking at it, it could do with a bit of refactoring, but it does work.
var wantDir;
var currDir;
var directiondiff;
var maxTurn;
// want - this is your target direction \\
wantDir = argument0;
// max turn - this is the max number of degrees to turn \\
maxTurn = argument1;
// current - this is your current direction \\
currDir = direction;
if (wantDir >= (currDir + 180))
{
currDir += 360;
}
else
{
if (wantDir < (currDir - 180))
{
wantDir += 360;
}
}
directiondiff = wantDir - currDir;
if (directiondiff < -maxTurn)
{
directiondiff = -maxTurn
}
if (directiondiff > maxTurn)
{
directiondiff = maxTurn
}
return directiondiff
So you'd call this, and it'll return you a value that you can add to your missile's angle. So if you call it scr_get_angle, your code might then look like this:
if(instance_exists(obj_fighter1)) {
var target;
target = instance_nearest(x, y, obj_fighter1);
if(target != noone) {
var angle_to_target;
angle_to_target = point_direction(x,y,target.x,target.y);
direction += scr_get_angle(angle_to_target, 2);
}
}
I'm trying to figure out how to extrude an already loaded .obj object to make it "thicker". I think I'm looking for a way to scale my object not from its anchor point but scaling it by each polygon normal.
A classic example would be to take a "ring" object. If you scale it up with just the normal scale methods it just gets bigger from the center but I want the ring to become thicker/thinner. Its called a 'normal scale' in cinema 4d.
Here's some example code of what I currently have, and which isn't giving me the expected result.
var objLoader = new THREE.OBJLoader();
var material = new THREE.MeshLambertMaterial({color:'yellow', shading:THREE.FlatShading});
objLoader.load('objects/gun/M1911.obj', function (obj) {
obj.traverse(function (child) {
if (child instanceof THREE.Mesh) {
child.geometry.computeVertexNormals();
child.material = material;
}
});
obj.material = material;
obj.scale.set(7, 7, 7);
scene.add(obj);
});
scaleGeo: function (geo, ratio) {
for (var i = 0; i < geo.faces.length; i++) {
var faceI = geo.faces[i];
var vertexArr = [faceI.a, faceI.b, faceI.c];
for (var j = 0; j < vertexArr.length; j++) {
var vertexJ = geo.vertices[vertexArr[j]];
var normalJ = faceI.vertexNormals[j];
if (vertexJ.hasScale) continue;
vertexJ.x += normalJ.x * ratio;
vertexJ.y += normalJ.y * ratio;
vertexJ.z += normalJ.z * ratio;
vertexJ.hasScale = true;
}
}
return geo;
},
I have a tile engine and that's all working swell, my player walks around all good, I'm working on adding items, the player is always in the centre of the screen, until he gets close to the edges of the world then he starts going close to the edges.
When I draw items in the world, they draw fine, except when the player leaves the centre (at the edge of the world). I just can't wrap my head around how to fix this.
public static void Draw(SpriteBatch spriteBatch, World w, Item i, Player p, Point screenDimensions)
{
bool IsOnScreen = true;
float leftX = p.X - ((screenDimensions.X / 32) / 2);
float rightX = leftX + (screenDimensions.X / 32);
float topY = p.Y - ((screenDimensions.Y / 32) / 2);
float bottomY = topY + (screenDimensions.Y / 32);
if (i.x < leftX || i.x > rightX || i.y < topY || i.y > bottomY)
IsOnScreen = false;
if (IsOnScreen)
i.animation.Draw(spriteBatch, (int)Math.Floor((i.x - leftX) * 32), (int)Math.Floor((i.y - topY) * 32));
}
Its pretty self explainatory, the world is passed in to get the dimensions (w.worldDimensions.x for width, and .y for height), the item is used to get the i.x and i.y (location in game world, not on screen), the player for drawing it relative (contains .x and .y for location) and then the screenDimensions.
Well it does not look very clear to me. Are you using a camera class? If you use a camera class and use that to navigate your world this should never happen.
Here is a basic one i currently use for my project.
class Camera
{
float zoom;
public float Rotation { get; private set; }
public Vector2 Position { get; private set; }
Matrix transform;
int velocity = 60;
UserInput input;
public float Zoom
{
get { return zoom; }
set { zoom = value; if (zoom < 0.1f) zoom = 0.1f; } // Negative zoom will flip image
}
public Camera(UserInput input)
{
zoom = 1.0f;
Rotation = 0f;
Position = new Vector2(0, 0);
this.input = input;
}
public void MoveCam()
{
if (input.IsKeyHold(Keys.Up))
{
Position += new Vector2(0, -velocity);
}
if (input.IsKeyHold(Keys.Left))
{
Position += new Vector2(-velocity, 0);
}
if (input.IsKeyHold(Keys.Down))
{
Position += new Vector2(0, velocity);
}
if (input.IsKeyHold(Keys.Right))
{
Position += new Vector2(velocity, 0);
}
if (input.IsKeyHold(Keys.OemMinus))
{
Zoom -= .01f * Zoom;
}
else if (input.IsKeyHold(Keys.OemPlus))
{
Zoom += .01f * Zoom;
}
}
public void FollowCam(int xPos, int yPos)
{
Position = new Vector2(xPos * TileData.Width, yPos * TileData.Height);
}
public Matrix TransformMatrix(GraphicsDevice device)
{
transform = Matrix.CreateTranslation(new Vector3(-Position.X, -Position.Y, 0)) *
Matrix.CreateRotationX(MathHelper.ToRadians(Rotation)) *
Matrix.CreateRotationY(MathHelper.ToRadians(Rotation)) *
Matrix.CreateRotationZ(MathHelper.ToRadians(Rotation)) *
Matrix.CreateScale(new Vector3(zoom, zoom, 0)) *
Matrix.CreateTranslation(new Vector3(device.Viewport.Width * 0.5f, device.Viewport.Height * 0.5f, 0));
return transform;
}
}
Just instantiate the class like in main and use this in your draw method.
batch.Begin(SpriteSortMode.Immediate, BlendState.AlphaBlend, null, null, null, null, camera.TransformMatrix(graphicsDevice));
batch.End()
Draw everything in your world within this spritebatch and use a new basic to draw to screen cooridinates, like a gui/hud. You can use the camera move method to move it manually and the lock to lock it on any location (it follows if updated).
If you have large maps you might want to render only necessary tiles. I do it like this in my map class:
public void Draw(SpriteBatch batch, Vector2 camPosition, float camZoom, GraphicsDevice device)
{
float top = (camPosition.Y / TileData.Height) - ((device.Viewport.Height / 2) / TileData.Height + 1) / camZoom;
float bottom = (camPosition.Y / TileData.Height) + ((device.Viewport.Height / 2) / TileData.Height + 2) / camZoom;
float left = (camPosition.X / TileData.Width) - ((device.Viewport.Width / 2) / TileData.Width + 1) / camZoom;
float right = (camPosition.X / TileData.Width) + ((device.Viewport.Width / 2) / TileData.Width + 2) / camZoom;
for (int y = (int)top; y < (int)bottom; y++)
{
for (int x = (int)left; x < (int)right; x++)
{
if (y >= 0 && y < map.GetLength(1) && x >= 0 && x < map.GetLength(0))
{
batch.Draw(map[x, y].texture, new Rectangle(x * TileData.Width, y * TileData.Height, TileData.Width, TileData.Height), Color.White);
}
}
}
}
Here first i figure out which tiles to draw from each direction. Note the camZoom, you want more tiles to be drawn when zooming out. Then i use these "bounderies" in my for loops, the if statement makes sure i am not accessing tiles that dont exist (out of bounds).
In Java, you sometimes do something like this:
for (int a = 1, b = 2; b < high;) {
if (b % 2 == 0) {
result += b;
}
int tmp = b;
b = a + b;
a = tmp;
}
Here, I used a for loop instead of a while loop to limit the scope of a and b.
But how can I achieve this in JavaFX? The for loop doesn't seem to offer this possibility. Do I have to use a while loop?
You could use the Java trick of anonymous blocks:
var high = 10;
{
var a = 0;
for (b in [1..high-1]) {
// this is fine
println("{a}");
}
}
// won't compile here
//println("{a}");
The are simmilar expressions in JavaFX but with those expressions you will get a double loop. According to this doc.