Physicsjs Screen wrap - physicsjs

I am currently having a bit of trouble making objects in my world wrap. It sort of works, but very often objets appear to get stuck on the boundaries. My wrap code is as follows:
// Wrap our position if we are outside of the world bounds
if (this.state.pos.get(0) > 860) {
this.state.pos.set(0, this.state.pos.get(1));
}
else if (this.state.pos.get(0) < 0) {
this.state.pos.set(860, this.state.pos.get(1));
}
if (this.state.pos.get(1) > 640) {
this.state.pos.set(this.state.pos.get(0), 0);
}
else if (this.state.pos.get(1) < 0) {
this.state.pos.set(this.state.pos.get(0), 640);
}
Is there a better way of doing this? Should I use a translation on the object's position vector rather than simply setting it?

Without a jsfiddle it's a bit hard to diagnose, however this might be due to the this.state.old.pos not being set too. If the position (only) is set, then the velocity will be calculated as the difference between the current and the previous positions (in accordance with verlet integration). In that case, you're implicitly giving the body a huge velocity.
I'd recommend adding/subtracting an amount rather than setting, then you can do the same with the old position.
Here's a working example: http://labs.minutelabs.io/Relativistic-Space-Sheep/
With the relevant line of code: https://github.com/minutelabsio/Relativistic-Space-Sheep/blob/master/library/js/mediators/boilerplate.js#L743

Related

my shader is ignoring my worldspace height

Im VERY new to shaders so bear with me. I have a mesh that I want to put a sand texture on below a worldspace position y of say 10 else it should be a grass texture. Apparantly it seems to be ignoring anything I put in and only selecting the grass texture. Something IS happening because my vert and tris count explodes with this function, compared to if I just return the same texture. I just dont see anything no matter what my sandStart value is
this is in my frag function:
if (input.positionWS.y < _SandStart) {
return tex2D(_MainTex, input.uv)* mainLight.shadowAttenuation;
} else {
return tex2D(_SandTex, input.uv) * mainLight.shadowAttenuation;
}
Is there also a way I can easily debug some of the values?
Please note that the OP figured out that their specific problem wasn't caused by the code in the question, but an error in their geometry function, this answer is only about the question "Is there a way to debug shader values" as this debugging method helped the OP find the problem
Debugging shader code can be quite a challenging task, depending on what it is you need to debug, and there are multiple approaches to it. Personally the approach I like best is using colours.
if we break it down there are three aspects in your code that could be faulty:
the value of input.positionWS.y
the if statement (input.positionWS.y < _SandStart)
Returning your texture return tex2D(_MainTex, input.uv)* mainLight.shadowAttenuation;
Lets walk down the list and test each individually.
checking if input.positionWS.y actually contains a value we expect it to contain. To do this we can set any of the RGB channels to its value, and just straight up returning that.
return float4(input.positionWS.y, 0, 0, 1);
Now if input.positionWS.y isn't a normalized value (a.k.a a value that ranges from 0 to 1) this is almost guaranteed to just return your texture as entirely red. To normalize it we divide the value by its max value, lets take max = 100 for the exmaple.
return float4(input.positionWS.y / 100, 0, 0, 1);
This should now make the texture full red at the top (where input.positionWS.y / 100 would be 1) and black at the bottom (where input.positionWS.y / 100 is zero), and a gradient from black to full red inbetween. (Note that since its a position in world space you may need to move the texture up/down to see the colour shift). If this doesn't happen, for example it always stays black or full red then your issue is most likely the input.positionWS.y.
The if statement. It could be that your statement (input.positionWS.y < _SandStart) always returns either true or false, meaning it'll never split. We can test this quite easily by commenting out the current return texture, and instead just return a flat colour like so:
if(input.positionWS.y < _SandStart)
{
return float4(1,0,0,1);
}
else
{
return float4(0,0,1,1);
}
if we tested the input.positionWS.y to be correct in step 1, and _SandStart is set correctly we should see the texture be divided in parts red (if true) and the other part blue (if false) (again since we're basing off world position we might need to change the material's height a bit to see it). If this division in colours doens't happen then the likely cause is that _SandStart isn't set properly, or to an incorrect value. (assuming this is a property you can inspect its value in the material editor)
if both of above steps yield the expected result then return tex2D(_MainTex, input.uv)* mainLight.shadowAttenuation; is possibly the culprit. To debug this we can return one of the textures without the if statement and shadowAttenuation, see if it applies the texture, and then return the other texture by changing which line is commented.
return tex2D(_MainTex, input.uv);
//return tex2D(_SandTex, input.uv);
If each of these textures gets applied properly seperately then it is unlikely that that was your cause, leaving either the shadowAttenutation (just add the multiplication to the above test) or something different altogether that isn't covered by the code in your question.
bonus round. If you got a shader property you want to debug you can actually do this from C# as well using the material.Get<type> function (the supported types can be found in the docs here, and include the array variants too, as well as both Get and Set). a small example:
Properties
{
_Foo ("Foo", Float) = 2
_Bar ("Bar", Color) = (1,1,1,1)
}
can be debugged from C# using
Material mat = getComponent<Material>();
Debug.LogFormat("_Foo value: {0}", mat.GetFloat("_Foo"); //prints 2
Debug.LogFormat("_Bar value: {0}", mat.GetFloat("_Bar"); //prints (1,1,1,1)

How to get current frame from Animated Tile/Tilemap.animationFrameRate in Unity

I am using tilemaps and animated tiles from the 2dExtras in unity.
My tiles have 6 frames, at speed=2f, and my tilemap frame rate is 2.
New tiles placed always start on frame 1 and then immediately jump to the current frame of the other tiles already placed, the tilemap is keeping every tile at the same pace, which is working as I want.
However I would like the newly placed tiles to start at the frame the others are currently on,(instead of placing a tile that jumps from frame 1 to frame 4) I would like the new tile to start on frame 4
I've found how to pick the frame I want to start on, however I am having trouble retrieving which frame the animation is currently on, so I was wondering how exactly can I access the current frame of animation of a given tilemap ( Or a given tile, I can create a dummy tile and just read the info out of it, how can I get the current frame of an animated tile? )
The animated tilemaps feature seems to lack the feature to retrieve this information, also when I try tilemap.getsprite it always returns the first frame of the sequence(does not return the sprite currently displayed), and there doesn't seem to be any method to poll info from tilemap.animationFrameRate.
I thought another method would be to set a clock and sync it to the rate of the animation but since I can't get the exact framerate duration the clock eventually goes out of sync.
Any help would be appreciated!
I found a way to solve this question. But it's not 100% insurance.
First of all, I used SuperTile2Unity. That doesn't seem to be the point.
private void LateUpdate()
{
// I use this variable to monitor the run time of the game
this.totalTime += Time.deltaTime;
}
private void func()
{
// ...
TileBase[] currentTiles = tilemap.GetTilesBlock(new BoundsInt(new Vector3Int(0, 0, 0), new Vector3Int(x, y, 1)));
Dictionary<string, Sprite> tempTiles = new Dictionary<string, Sprite>();
//I use SuperTiled2Unity. But it doesn't matter, the point is to find animated tile
foreach (SuperTiled2Unity.SuperTile tile in currentTiles)
{
if (tile == null)
{
continue;
}
if (tile.m_AnimationSprites.Length > 1 && !tempTiles.ContainsKey(tile.name))
{
// find animated tile current frame
// You can easily find that the way SuperTile2Unity is used to process animation is to generate a sprite array based on the time of each frame set by Tiled animation and the value of AnimationFrameRate parameter.
// The length of array is always n times of AnimationFrameRate. You can debug to find this.
tempTiles.Add(tile.name, tile.m_AnimationSprites[GetProbablyFrameIndex(tile.m_AnimationSprites.Length)]);
}
}
//...
}
private int GetProbablyFrameIndex(int totalFrame)
{
//According to the total running time and the total length of tile animation and AnimationFrameRate, the approximate frame index can be deduced.
int overFrameTime = (int)(totalTime * animationFrameRate);
return overFrameTime % totalFrame;
}
I have done some tests. At least in 30 minutes, there will be no deviation in animations, but there may be a critical value. If the critical time is exceeded, there may be errors. It depends on the size of AnimationFrameRate and the accumulation mode of totalTime. After all, we don't know when and how the unity deals with animatedTile.
You could try using implementation presented in [1] which looks as follows:
MyAnimator.GetCurrentAnimatorClipInfo(0)[0].clip.length * (MyAnimator.GetCurrentAnimatorStateInfo(0).normalizedTime % 1) * MyAnimator.GetCurrentAnimatorClipInfo(0)[0].clip.frameRate;
[1] https://gamedev.stackexchange.com/questions/165289/how-to-fetch-a-frame-number-from-animation-clip

Flipping a child sprite's xscale in Spritekit using Swift

Alright I'm offically stumped. I've been able to figure out my problems myself in the past but I'm lost on this one.
I'm trying to flip a child sprite's xscale. I want the flip to occur when the child's x position is negative. With the code below, the sprite does flip, every time the sprite reaches negative position, it loops back and forth flipping until reaching positive again.
I've tried numerous variations, but this is the code in it's simplest form. Any help or alternatives would be appreciative.
override func update(currentTime: CFTimeInterval) {
/* Called before each frame is rendered */
let pin = childNodeWithName(Pin1) as SKSpriteNode!
let guyPoint = guy.convertPoint(guy.position, fromNode: pin)
if guyPoint.x <= 0 {
guy.xScale = -1
}
else {
guy.xScale = 1
}
}
So if it is constantly flipping it's probably an issue of coordinate space. So check to make sure your convertPoint method is accurately returning the point you want. I would use println() to see what's going on there.
Probably what's happening is you want to flip the xScale when the child node is negative in the scene space or something (i.e. when the child is off the screen) but instead guyPoint might be the position of the child in its parent's coordinate space (so relative to the parent).
Also try with and without the else{} part to see if that changes anything.

determine if a sprite is on screen or not in cocos2d

i want to determine if the sprite is in the screen or not in cocos2d.
am using the code some thing like these.
CGSize winSize = [CCDirector sharedDirector].winSize;
if (_SmallBlueAlien1.position.x> 0 || _SmallBlueAlien1.position.x > winSize.width || _SmallBlueAlien1.position.y> 0 || _SmallBlueAlien1.position.y > winSize.height)
{
//Sprite is not in the screen)
}
but not working properly. were am mistaking.
correct me
Unless you changed the anchor point of the sprite this is only testing if half of the sprite is on the screen. To fix this you want to check if
_SmallBlueAlien1.position.x > [_SmallBlueAlien1 contentSize].texture.width / 2;
You can follow this process for all the other interactions.
//Edit
As phix23 noted this does not account for rotation or scale but should work if you are doing neither of those.
regardless of the semantics of 'position' in coco, your '>' should be '<' for both x and y, assuming your interpretation of the .position property holds. It is likely however that the 'sprite'.position is in reference to an enclosing object, thus even when your test is corrected, it may still not give you what you want to know ('visible on screen').

Creating An "Autopilot" For Lander in Perl

I'm using Perl to create a simple Lunar Lander game. All of the elements work (i.e. graphical interface, user implemented controls, etc), but I cannot seem to get the "AutoPilot" function to work. This function should fly the lander to a spot that it can land (or a spot designated as a target for landing), and then safely land there. The restrictions placed on landing are the slope of the place the lander lands and the velocity that the lander has when landing. The only file I can change is AutoPilot.pm. I will post the code I am allowed to work with:
package AutoPilot;
use strict;
use warnings;
# use diagnostics;
=head1 Lunar Lander Autopilot
The autopilot is called on every step of the lunar lander simulation.
It is passed state information as an argument and returns a set of course
correction commands.
The lander world takes the surface of the moon (a circle!)
and maps it onto a rectangular region.
On the x-axis, the lander will wrap around when it hits either the
left or right edge of the region. If the lander goes above the maximum
height of the world, it escapes into the space and thus fails.
Similarly, if the lander's position goes below 0 without ever landing
on some solid surface, it "sinks" and thus fails again.
The simulation is simple in the respect that if the langer goes at a high speed
it may pass through the terrain boundary.
The y-axis has normal gravitational physics.
The goal of the autopilot is to land the craft at (or near) the landing
zone without crashing it (or failing by leaving the world).
=head2 Interface in a nutshell
When the simulation is initialized, AutoPilot::Initialize() is called.
Every clock tick, AutoPilot::ComputeLanding() is called by the simulator.
For more explanation, see below.
=cut
# if you want to keep data between invocations of ComputeLanding, put
# the data in this part of the code. Use Initialize() to handle simulation
# resets.
my $call_count = 0;
my $gravity;
my ($x_min, $y_min, $x_max, $y_max);
my ($lander_width, $lander_height, $center_x, $center_y);
my $target_x;
my ($thrust, $left_right_thrust);
my ($max_rotation, $max_left_right_thrusters, $max_main_thruster);
my $ascend_height = 980;
=head1 AutoPilot::Initialize()
This method is called when a new simulation is started.
The following parameters are passed to initialize:
$gravity, a number, describing the gravity in the world
$space_boundaries, a reference to an array with 4 numerical
elements, ($x_min, $y_min, $x_max, $y_max), describing
the world boundaries
$target_x, a number representing the target landing position
$lander_capabilities, a reference to an array with
5 elements,
($thrust, $left_right_thrust, $max_rotation, $max_left_right_thrusters, $max_main_thruster),
describing the capabilities of the lander.
$lander_dimensions, a reference to an array with
4 elements,
($lander_width, $lander_height, $center_x, $center_y),
describing the dimensions of the lander.
=head2 Details
=head3 Dimensions
The dimensions are given in 'units' (you can think of 'units' as meters).
The actual numbers can take any real value, not only integers.
=head4 World dimensions
The lander world is a square region with a lower left corner at
($x_min,$y_min) and an upper right corner at ($x_max, $y_max).
The measurement units of these dimensions will just be called units
(think about units as meters). By definition, $x_max>$x_min and
$y_max>$y_min.
The default values for the lower left and upper right corners
are (-800,0), and (800,1600), respectively.
=head4 Lander dimensions
The lander is $lander_width units wide and $lander_height high.
The coordinates of the lander are always specified with respect to its center.
The center of the lander relative to the lower left corner of the lander bounding box
is given by $center_x, $center_y. Thus, if ($x,$y) are the coordinates of the lander,
($x-$center_x,$y-$center_y) and ($x-$center_x+$lander_width,$y-$center_y+$lander_height)
specify the corners of the bounding box of the lander. (Think of the lander as completely
filling this box.) The significance of the bounding box of the lander is that a collision
occurs if the bounding box intersects with the terrain or the upper/lower edges of the world.
If a collision occurs, as described earlier, the lander might have just landed,
crashed or 'escaped' (and thus the lander failed).
The constraints on these values are: $lander_width>0, $lander_height>0,
$center_x>0, $center_y>0.
The default value for the width is 60 units, for the height it is 50,
for $center_x it is 30, for $center_y it is 25.
=head4 Forces
The gravitational force is:
$g
The thrust exerted by the engine when fired is:
$thrust
The thrust exerted by the left/right thrusters when fired is:
$left_right_thrust
=head4 Limits to the controls
Within a single timestep there are limits to how many degrees the
lander may rotate in a timestep, and how many times the side thrusters,
and main thruster, can fire. These are stored in:
$max_rotation, $max_left_right_thrusters, $max_main_thruster
=head4 Target
The target landing zone that the lander is supposed to land at:
$target_x
which returns
the string "any" if any safe landing site will do, or
a number giving the x-coordinate of the desired landing site.
Note: there is no guarantee that this is actually a safe spot to land!
For more details about how the lander is controlled, see AutoPilot::ComputeLanding.
=cut
sub Initialize {
my ($space_boundaries, $lander_capabilities,$lander_dimensions);
($gravity, $space_boundaries, $target_x, $lander_capabilities, $lander_dimensions) = #_;
($x_min, $y_min, $x_max, $y_max) = #{$space_boundaries};
( $thrust, $left_right_thrust, $max_rotation,
$max_left_right_thrusters, $max_main_thruster) = #{$lander_capabilities};
($lander_width, $lander_height, $center_x, $center_y) = #{$lander_dimensions};
$call_count = 0;
}
=head1 AutoPilot::ComputeLanding()
This method is called for every clock tick of the simulation.
It is passed the necessary information about the current state
and it must return an array with elements, describing the
actions that the lander should execute in the current tick.
The parameters passed to the method describe the actual state
of the lander, the current terrain below the lander and some
extra information. In particular, the parameters are:
$fuel, a nonnegative integer describing the remaining amount of fuel.
When the fuel runs out, the lander becomes uncontrolled.
$terrain_info, an array describing the terrain below the lander (see below).
$lander_state, an array which contains information about the lander's state.
For more information, see below.
$debug, an integer encoding whether the autopilot should output any debug information.
Effectively, the value supplied on the command line after "-D",
or if this value is not supplied, the value of the variable $autopilot_debug
in the main program.
$time, the time elapsed from the beginning of the simulation.
If the simulation is reset, time is also reset to 0.
=head2 Details of the parameters
=head3 The terrain information
The array referred to by $terrain_info is either empty, or
it describes the terrain element which is just (vertically) below the lander.
It is empty, when there is no terrain element below the lander.
When it is non-empty, it has the following elements:
($x0, $y0, $x1, $y1, $slope, $crashSpeed, $crashSlope)
where
($x0, $y0) is the left coordinate of the terrain segment,
($x1, $y1) is the right coordinate of the terrain segment,
$slope is the left to right slope of the segment (rise/run),
$crashSpeed is the maximum landing speed to avoid a crash,
$crashSlope is the maximum ground slope to avoid a crash.
=head3 The state of the lander
The array referred to by $lander_state contains
the current position, attitude, and velocity of the lander:
($px, $py, $attitude, $vx, $vy, $speed)
where
$px is its x position in the world, in the range [-800, 800],
$py is its y position in the world, in the range [0, 1600],
$attitude is its current attitude angle in unit degrees,
from y axis, where
0 is vertical,
> 0 is to the left (counter clockwise),
< 0 is to the right (clockwise),
$vx is the x velocity in m/s (< 0 is to left, > 0 is to right),
$vy is the y velocity in m/s (< 0 is down, > 0 is up),
$speed is the speed in m/s, where $speed == sqrt($vx*$vx + $vy*$vy)
=head2 The array to be returned
To control the lander you must return an array with 3 values:
($rotation, $left_right_thruster, $main_thruster)
$rotation instructs the lander to rotate the given number of degrees.
A value of 5 will cause the lander to rotate 5 degrees counter clockwise,
-5 will rotate 5 degrees clockwise.
$left_right_thruster instructs the lander to fire either the left or
right thruster. Negative value fire the right thruster, pushing the
lander to the left, positive fire the left thruster, pushing to the right.
The absolute value of the value given is the number of pushes,
so a value of -5 will fire the right thruster 5 times.
$main_thruster instructs the lander to fire the main engine,
a value of 5 will fire the main engine 5 times.
Each firing of either the main engine or a side engine consumes
one unit of fuel.
When the fuel runs out, the lander becomes uncontrolled.
Note that your instructions will only be executed up until the
limits denoted in $max_rotation, $max_side_thrusters, and $max_main_thruster.
If you return a value larger than one of these maximums than the
lander will only execute the value of the maximum.
=cut
sub ComputeLanding {
my ($fuel, $terrain_info, $lander_state, $debug, $time) = #_;
my $rotation = 0;
my $left_right_thruster = 0;
my $main_thruster = 0;
# fetch and update historical information
$call_count++;
if ( ! $terrain_info ) {
# hmm, we are not above any terrain! So do nothing.
return;
}
my ($x0, $y0, $x1, $y1, $slope, $crashSpeed, $crashSlope) =
#{$terrain_info};
my ($px, $py, $attitude, $vx, $vy, $speed) =
#{$lander_state};
if ( $debug ) {
printf "%5d ", $call_count;
printf "%5s ", $target_x;
printf "%4d, (%6.1f, %6.1f), %4d, ",
$fuel, $px, $py, $attitude;
printf "(%5.2f, %5.2f), %5.2f, ",
$vx, $vy, $speed;
printf "(%d %d %d %d, %5.2f), %5.2f, %5.2f\n",
$x0, $y0, $x1, $y1, $slope, $crashSpeed, $crashSlope;
}
# reduce horizontal velocity
if ( $vx < -1 && $attitude > -90 ) {
# going to the left, rotate clockwise, but not past -90!
$rotation = -1;
}
elsif ( 1 < $vx && $attitude < 90 ) {
# going to the right, rotate counterclockwise, but not past 90
$rotation = +1;
}
else {
# we're stable horizontally so make sure we are vertical
$rotation = -$attitude;
}
# reduce vertical velocity
if ($target_x eq "any"){
if (abs($slope) < $crashSlope){
if ($vy < -$crashSpeed + 6){
$main_thruster = 1;
if (int($vx) < 1 && int ($vx) > -1){
$left_right_thruster = 0;
}
if (int($vx) < -1){
$left_right_thruster = 1;
}
if (int($vx) > 1){
$left_right_thruster = -1;
}
}
}
else{
if ( $py < $ascend_height) {
if ($vy < 5){
$main_thruster=2;
}
}
if ($py > $ascend_height){
$left_right_thruster = 1;
if ($vx > 18){
$left_right_thruster = 0;
}
}
}
}
if ($target_x ne "any"){
if ($target_x < $px + 5 && $target_x > $px - 5){
print "I made it here";
if (abs($slope) < $crashSlope){
if ($vy < -$crashSpeed + 1){
$main_thruster = 1;
if (int($vx) < 1 && int ($vx) > -1){
$left_right_thruster = 0;
}
if (int($vx) < -1){
$left_right_thruster = 1;
}
if (int($vx) > 1){
$left_right_thruster = -1;
}
}
}
}
if ($target_x != $px){
if ( $py < $ascend_height) {
if ($vy < 5){
$main_thruster=2;
}
}
if ($py > $ascend_height){
$left_right_thruster = 1;
if ($vx > 10){
$left_right_thruster = 0;
}
}
}
}
return ($rotation, $left_right_thruster, $main_thruster);
}
1; # package ends
Sorry about the length of the code...
So, there are a few things I want this autopilot program to do. In order they are:
Stabilize the lander (reduce attitude and horizontal drift to zero if they are nonzero). Once stabilized:
If above a target and the target's segment is safe to land on then descend on it.
Otherwise ascend to the safe height, which is above 1200 units. You can safely assume that there are no objects at this height or higher and also that during straight ascends from its initial position, the lander will not hit anything.
Once at the safe height, the lander can start going horizontally towards to its target, if a target is given, otherwise it should target the first safe landing spot that is can sense by scanning the terrain in one direction. It is important that the lander maintains its altitude while it moves horizontally, because it cannot sense objects next to it and there could be objects anywhere below this height.
Once the target x coordinate is reached and is found to be safe to land on, start a descend.
If the target x coordinate is is reached, but the terrain is unsafe, if a good spot has been seen while moving towards the target, go back to it, otherwise continue searching for a good spot.
Once a good spot is seen, just land on it nice and safe.
Ok, so, I've updated the code. My code is now able to land the lander in all tests (except one, got fed up, the code works close enough) where there is no target. However, I am having huge troubles figuring out how to get the lander to land at a target. Any ideas with my code so far? (actual used code is found in the ComputeLanding subroutine)
Here's a hint: try approaching the problem from the other end.
Landing is almost equivalent to takeoff with time reversed. The only thing that doesn't get reversed is fuel consumption. (Whether that matters depends on whether the simulation counts fuel as part of the lander's mass. In a realistic sim, it should, but at a glance, it looks like yours might not.)
The optimal way (in terms of fuel efficiency) to take off in a rocket is to fire the engines at maximum power until you're going fast enough, then turn them off. The slower you climb, the more fuel you waste hovering.
Thus, the optimal way to land a rocket is to freefall (after a possible initial burn to correct heading) until the last possible instant, and then fire the engines at full power so that you come to a stop just above the landing pad (or hit the pad at whatever velocity you consider acceptable, if that's greater than zero).
Can you calculate what the right moment to turn on the engines would be? (Even if you can't do it directly, you could always approximate it by binary search. Just pick a point and simulate what happens: if you crash, start the burn earlier; if you stop before hitting the surface, start it later.)
(Ps. This seems like a rather silly exercise for a Perl programming course. Yes, you can certainly solve this in Perl, but there's nothing about Perl that would be particularly well suited for this exercise. Indeed, this isn't even fundamentally a programming problem, but a mathematical one — the only programming aspect to it is translating the mathematical solution, once found, into a working program.)
You could use a genetic algorithm for the lander implementation check out this book AI Techniques for game programming. It has exactly what you need with code examples. However, those examples are in c++.