I'm very new to box2d and I just want to make a simple check to see if a point is inside a polygon in cocos2d.
b2PolygonShape polygon;
b2Vec2 vertices[] =
{
b2Vec2(300, 400),
b2Vec2(350, 400),
b2Vec2(300, 500),
b2Vec2(350, 500)
};
polygon.Set(vertices, 4);
if(polygon.TestPoint(b2Transform(), b2Vec2(301, 405)))
{
CCLOG(#"Point is inside");
}
I dont understand what the first parameter expecting a b2transform. Why is this needed and what should I set it to? Is there something im forgetting? Im trying to do this without doing anything complicated at all like having a worldobject and so on. What's the easiest way?
bool TestPoint(const b2Transform& transform, const b2Vec2& p) const;
The transform allows you to specifiy the polygon in local coordinates, and then transform it (translate and rotate) it to its desired position/orientation. If you want want the polygon vertices to be the worldspace coordinates, use an identity (like multiplying with 1) transform:
btTransform identity; identity.SetIdentity();
polygon.TestPoint(identity, ...
You need to explicity set it to identity, as the default constructor in both b2Transform and its two members b2Vec and b2Rot don't do anything, an therefore will contain random junk in the release build (debug usually sets all un-inted values to 0).
See b2Math.h and b2PolygonShape.cpp for details.
Related
So I've been using KidsCanCode's Godot tutorials/documentation to help me create a Pokemon-like grid-based movement for a project I'm working on. For all intents and purposes, I would like to create a movement system as close to that in the earlier handheld Pokemon games as possible.
I would like to add two things before I start; one, I have grown fond of the way KidsCanCode attempted to teach grid-based movement, so while other ways of coding it may be simpler such as those that can be found on videos such as this one (https://www.youtube.com/watch?v=jSv5sGpnFso), I would like to hard-headidly stick to this method of coding it... you'll see what I mean when you read the code. Lastly, I would like to add that I had this code working before ! I actually haven't made any changes to the code since it was last working, however, for some reason it no longer seems to work, I'm not sure if that's due to Godot updating since, but hopefully someone can help me out with that.
So first of all, this is my player scene node tree. The most important parts of this being the RayCast2D and Tween nodes.
And this is my code for the main Area2D Player node:
extends Area2D
const tile_size = 16
export var speed = 5
var inputs = { "ui_right": Vector2.RIGHT,
"ui_left": Vector2.LEFT,
"ui_up": Vector2.UP,
"ui_down": Vector2.DOWN }
func _ready():
position = position.snapped(Vector2.ONE * tile_size/2)
func _unhandled_input(event):
if $Tween.is_active():
return
for dir in inputs.keys():
if event.is_action_pressed(dir):
move(inputs[dir])
func move(dir):
$RayCast2D.cast_to = inputs[dir] * tile_size
$RayCast2D.force_raycast_update()
if !$RayCast2D.is_colliding():
move_tween(dir)
func move_tween(dir):
$Tween.interpolate_property(self, "position", position,
position + inputs[dir] * tile_size, 1.0/speed, Tween.TRANS_SINE, Tween.EASE_IN_OUT)
$Tween.start()
To quickly explain, func _ready(): snaps the player to the grid. func _unhandled_input(event): then checks to see if a Tween is occurring, and if not, calls func move(dir). This function raycasts to the given direction input, forces a raycast update, and if no static body is in the given direction, calls func move_tween(dir). This last functions handles tween interpolation to the given direction and starts the tweening process. That's pretty much it. Once again, this used to work just fine.
However, now when I try to run this, I get an error "Invalid get index '(0, 1)' (on base: 'Dictionary')" where "(0, 1)" changes based on what direction I tried to move in when the game was running.
In the Debugger dock, underneath Stack Frames, it gives me errors on lines "22 - at function; move" $RayCast2D.cast_to = inputs[dir] * tile_size and "19 - at function: _unhandled_input" move(inputs[dir]).
The code on the website had these say (dir) only instead of (inputs[dir]). But doing so only gives me another error. If anyone smarter than me has any idea what's going on, I would very much appreciate any and all insight. Thank you !
Understanding the problem
Alright, let us see. The variable inputs has your dictionary:
var inputs = { "ui_right": Vector2.RIGHT,
"ui_left": Vector2.LEFT,
"ui_up": Vector2.UP,
"ui_down": Vector2.DOWN }
The keys are String, and the values are Vector2.
Thus, here:
for dir in inputs.keys():
if event.is_action_pressed(dir):
move(inputs[dir])
The variable dir is going to be a String. Which is what you need for is_action_pressed, so that is correct.
And inputs[dir] is going to be a Vector2. Which means that in move you are getting a Vector2 as argument.
Now, in move you say::
func move(dir):
$RayCast2D.cast_to = inputs[dir] * tile_size
But remember that the argument you are passing is a Vector2, and the keys of input are all String. So it fails here: inputs[dir].
Early warning for similar problems
Using types can help you identify this kind of problems early. Sadly in Godot 3.x there is no way to specify the the keys and values of a Dictionary.
Arguably you could use C# and use .NET Dictionary<TKey,TValue> from the System.Collections.Generic, which would let you specify the key and value types. Yet, we are not talking about those dictionaries here.
What you can tell with GDScript is that your parameters are either Vector2:
func move(displacement:Vector2):
# …
Or String
func move(dir:String):
# …
This way Godot can tell you when you are calling them with the wrong parameter.
Another thing that will help. Although it is more on the discipline side, is to keep consistent names. If the names you use have a concrete meaning in your system, they will help you.
For instance, you call move like this:
move(inputs[dir])
Meaning that what you are passing is not called dir※. But you have move defined like this:
func move(dir):
# …
So move expects something you call a dir. And you would see that when you are typing the call to move.
※: I'd say you are passing one of the values of inputs, so what you are passing is called an input. Or you could call them action, given that you use them in is_action_pressed. Which, again, would be using names in a way that helps you.
Solving the problem
The way I would solve this is by using the String and inputs in _unhandled_input only (after all, that function is meant to deal with inputs). And work with Vector2 from there on. This means that:
The other methods would also be useful if in the future you wanted a movement that does not come from one of the inputs.
You are not repeating the effort of looking up in the Dictionary.
Admittedly, these aren't a huge deal for your game right now. And ultimately what you do is up to you. Yet, consider this approach submitted to your consideration.
This is the code (I have added some type annotations):
extends Area2D
const tile_size:float = 16
export var speed:float = 5
var inputs = { "ui_right": Vector2.RIGHT,
"ui_left": Vector2.LEFT,
"ui_up": Vector2.UP,
"ui_down": Vector2.DOWN }
func _ready():
position = position.snapped(Vector2.ONE * tile_size/2)
func _unhandled_input(event:InputEvent) -> void:
if $Tween.is_active():
return
for dir in inputs.keys():
if event.is_action_pressed(dir):
move(inputs[dir])
func move(displacement:Vector2) -> void:
$RayCast2D.cast_to = displacement * tile_size
$RayCast2D.force_raycast_update()
if !$RayCast2D.is_colliding():
move_tween(displacement)
func move_tween(displacement:Vector2) -> void:
$Tween.interpolate_property(self, "position", position,
position + displacement * tile_size, 1.0/speed, Tween.TRANS_SINE, Tween.EASE_IN_OUT)
$Tween.start()
Or you can using String thought out, and querying the dictionary every time. Which, I believe, is what you intended. Like this:
extends Area2D
const tile_size:float = 16
export var speed:float = 5
var inputs = { "ui_right": Vector2.RIGHT,
"ui_left": Vector2.LEFT,
"ui_up": Vector2.UP,
"ui_down": Vector2.DOWN }
func _ready():
position = position.snapped(Vector2.ONE * tile_size/2)
func _unhandled_input(event:InputEvent) -> void:
if $Tween.is_active():
return
for dir in inputs.keys():
if event.is_action_pressed(dir):
move(dir)
func move(dir:String) -> void:
$RayCast2D.cast_to = input[dir] * tile_size
$RayCast2D.force_raycast_update()
if !$RayCast2D.is_colliding():
move_tween(dir)
func move_tween(dir:String) -> void:
$Tween.interpolate_property(self, "position", position,
position + input[dir] * tile_size, 1.0/speed, Tween.TRANS_SINE, Tween.EASE_IN_OUT)
$Tween.start()
Notice here that _unhandled_input is passing dir to move. The same way that move is passing dir to move_tween.
I have an app where users can draw a shape on the map to indicate potential land use, and they can also draw a shape to indicate a 'no change' zone, where we want to indicate no development plans.
Basically, they can create a shape to indicate an industrial zone, and then they could draw an overlapping shape to basically cut out that industrial zone, and designate that zone as a no-development zone.
Here's my code:
function cutOutNoChangeZone () {
var geometries = land_use_planning.graphics,
geometries_to_be_cut,
geoService = new esri.tasks.GeometryService("http://gis.website.com/ArcGIS/rest/services/Geometry/GeometryServer");
for (var i = 0, len = geometries.length; i < len; i++) {
var geometry = geometries[i];
if (geometry.planning_type === 'no_change') {
// cut ALL polygons that are under the no change zone
geometries_to_be_cut = geometries.slice(0, i);
// NEXT LINE THROWS ERROR
geoService.cut(geometries_to_be_cut, geometry);
}
}
}
It throws an error in the console:
TypeError: Cannot read property 'toJson' of undefined
It's coming from the minified ArcGIS 3.9 init.js file on the js.arcgis.com server. I have already debugged the for loop to check that the geometries are valid geometries, with toJson methods. I was trying to follow the example on this esri forum, which shows a similar function: https://geonet.esri.com/thread/63777.
Also note that I am testing this on only two shapes: one industrial and one "no-change" that overlaps. geometries_to_be_cut is an array of the single geometry, and geometry is the "no-change" geometry.
It seems like this should be a simple function. I'm not sure where I'm going wrong, and thought someone might have some insight on this.
Stepping into the code, we see that the cut method calls toJson() on a few different objects:
cut: function(a, c, f, g) {
var e = a[0].spatialReference, p = l.map(a, function(a) {
return a.toJson()
});
a = k.mixin({}, this._url.query, {f: "json",sr: n.toJson(e.toJson()),target: n.toJson({geometryType: u.getJsonType(a[0]),geometries: p}),cutter: n.toJson(c.toJson())});
var m = this._cutHandler, s = this._errorHandler, B = new h(b._dfdCanceller);
B._pendingDfd = d({url: this._url.path + "/cut",content: a,callbackParamName: "callback",
load: function(a, b) {
m(a, b, e, f, g, B)
},error: function(a) {
s(a, g, B)
}});
return B
}
This method calls toJson() on the cutting geometry and on the spatial reference of the first geometry in the list. I suspect that you somehow have a geometry with an undefined spatialReference property. Can you check for that please?
Another possible issue is that according to the documentation, the cutting geometry must be a polyline, not a polygon. You didn't specify which one you used, but since you said "draw a shape," maybe the cutting geometry is a polygon. I can't tell yet, because that issue would manifest itself only after the service gets called and returns an error, and because of your toJson() error, you're not yet calling the service.
Finally, I'm not sure that the cut method does what you need. If you get it working, cut will split the input polygons by the cutting polyline, returning the new split polygons. From your description, it sounds like either difference or intersect would be closer to what you need. But maybe I misunderstood what you wanted to do.
Sorry for the laundry list but hopefully something here is useful. :-)
Problem is:
I have created terrain and I need to fly over terrain with Camera. I added to Camera "Mouse Look" script, RigidBody: usegravity - unchecked and I have added my code in Update method:
float vert = Input.GetAxis("Vertical");
float hor = Input.GetAxis("Horizontal");
if (vert != 0)
{
if (!Physics.Raycast(this.transform.position, this.transform.forward, 5))
{
transform.Translate(Vector3.forward * flySpeed * vert);
}
else
{
transform.Translate(Vector3.up * flySpeed * vert);
}
}
if (hor != 0)
{
if (!Physics.Raycast(this.transform.position, this.transform.forward, 5))
{
transform.Translate(Vector3.right * flySpeed * hor);
}
else
{
transform.Translate(Vector3.up * flySpeed* hor);
}
}
if (Input.GetKey(KeyCode.E))
{
transform.Translate(Vector3.up * flySpeed);
}
else if (Input.GetKey(KeyCode.Q))
{
Vector3 v = Vector3.down * flySpeed;
if (!Physics.Raycast(this.transform.position, this.transform.forward, 5))
{
transform.Translate(v);
}
}
But sometimes then i go down - Q - camera goes through terrain. Why?
Also looks ugly if you are moving with camera forward as low as possible over terrain and camera does not fall through it - it starts to jump. Also why?
Make sure you have a Terrain Collider on your terrain.
In addition to S.Richmonds answer, you can add a character controller or other similar collider-component object to your camera.
See this answer in the unity questions network:
http://answers.unity3d.com/questions/45763/getting-camera-to-not-see-under-the-ground.html
The Update() method in a monobehavior gets called once each fram. Because the rate which update is called is dependent on frame rate, moving an object by a constant value in Update() can result in inconsistant motion. This can be corrected by multiplying a constant speed by Time.deltaTime, which is the time in seconds since the last frame was rendered. This will fix the fallthrough unless flySpeed is set too high (where the change in position each frame is greater than the collider's size). Additionally as suggested above, using a CharacterController without a rigidbody would be better suited to this situation. Rigidbodies are for objects primarily controlled by physics, while the CharacterController is for objects controlled by scripts.
I thought OpenMesh would support random access to faces edges vertices.
All I can find are iterators and circulators:
for( auto v : mesh->vertices() )
mesh->point(v).data();
How can I do something like this:
mesh->vertices(42);
VertexHandle vertex_handle (unsigned int _i) const
this function can be use to get a vertex handler, and if you want to get the vertex from it, just use
mesh.point(_vh);
where _vh is the handle you get from the above function.
This tutorial uses explicit OUT structures, e.g:
struct C3E1v_Output {
float4 position : POSITION;
float4 color : COLOR;
};
C3E1v_Output C3E1v_anyColor(float2 position : POSITION,
uniform float4 constantColor)
{
C3E1v_Output OUT;
OUT.position = float4(position, 0, 1);
OUT.color = constantColor; // Some RGBA color
return OUT;
}
But looking at one of my shaders I have explicit in/out parameters:
float4 slice_vp(
// Vertex Inputs
in float4 position : POSITION, // Vertex position in model space
out float4 oposition : POSITION,
// Model Level Inputs
uniform float4x4 worldViewProj) : TEXCOORD6
{
// Calculate output position
float4 p = mul(worldViewProj, position);
oposition=p;
return p;
}
I'm having some problems using HLSL2GLSL with this and wondered if my Cg format is to blame (even though it works fine as a Cg script). Is there a 'right' way or are the two simply different ways to the same end?
As you've seen, both ways work. However, I strongly endorse using structs -- especially for the output of vertex shaders (input of fragment shaders). The reasons are less to do with what the machine likes (it doesn't care), and more to do with creating code that can be safely re-used and shared between projects and people. The last thing you want to have to find and debug is a case where one programmer has assigned a value to TEXCOORD1 in some cases and is trying to read it from TEXCOORD2 in (some) other cases. Or any permutation of register mis-match. Use structs, your life will be better.