I am working on a pool game of sorts. To create a table, I have used cubes as sides. I want to use the inbuilt physics engine to get those sides interact with the balls. Sadly I am unable to get it working.
Here is what I have done. I created cube as side, and a sphere for ball. To move the sphere, I am using rigidbody.MovePosition function. both the cube and sphere have colliders and rigidbody attached, and gravity turned off.
Sphere movement is fine, but when it collides with cube, it makes the cube fly. Since the cube is supposed to be an immovable wall, I constrained all axes rotation and movement. But, using constraints cause physics engine to go bonkers. Instead of sphere coming to stop or moving in opposite direction, it simply passes through the cube. Clearly, something is wrong, and I need help figuring out the same.
Thanks in advance.
Here is the code used to move the sphere.
public float movePower = 10.0f;
// Update is called once per frame
void Update ()
{
if(Input.GetKey(KeyCode.LeftArrow))
{
rigidbody.MovePosition(transform.position + Vector3.left* movePower * Time.deltaTime);
}
if(Input.GetKey(KeyCode.RightArrow))
{
rigidbody.MovePosition(transform.position + Vector3.right* movePower * Time.deltaTime);
}
if(Input.GetKey(KeyCode.DownArrow))
{
rigidbody.MovePosition(transform.position + Vector3.down* movePower * Time.deltaTime);
}
if(Input.GetKey(KeyCode.UpArrow))
{
rigidbody.MovePosition(transform.position + Vector3.up* movePower * Time.deltaTime);
}
}
The simplest way is to remove the Rigidbody from all cubes as they are supposed to be fixed. Another way is to mark the cubes' Rigidbody components as Kinematic, but this meant to be used for moving objects like player characters that should participate in physics but should not be moved by the engine.
I recommend reading the Unity Physics man page.
Update:
More things to consider:
Don't check Is Trigger
Check that your Layer Collision Matrix is set up right (menu Edit/Project Settings/Physics)
If the velocity is pretty high, physics engine might get confused and collision are not detected
Ensure that the models are not scaled down or up extremely (best is to have scale = 1)
The best mass for Rigidbody.mass is 1
Be careful when playing with PhysicsManager settings like Min Penetration For Penalty or Solver Iteration Count
Use gravity if possible
Never move by manipulating Transform directly. Use Rigidbody methods instead
Avoid calling rigidbody.MovePosition on every update if it's a constant linear motion. Do it once and leave it untouched
Remember to use FixedUpdate for calling rigidbody.MovePosition etc.
Related
Trying to align the in game physics with devide gravity in realtime.
Inspired by "How to change global gravity properties at runtime?" post using following code during _process/_physics_process
var acc_gravity = Input.get_gravity().rotated(Vector3(-1, 0, 0), deg2rad(90))
PhysicsServer.area_set_param(get_world().get('space'),
PhysicsServer.AREA_PARAM_GRAVITY_VECTOR, acc_gravity.normalized())
PhysicsServer.area_set_param(get_world().get('space'),
PhysicsServer.AREA_PARAM_GRAVITY, acc_gravity.length())
But the physics just went into very weird behavior, kind of slowmotion or outright nothing move. Seems these parameter setting does much more than changing a number; and can only be set at ready but not updated constantly. Is there a workaround? Thanks.
For what I understand you want a constantly changing gravity. I suggest to not use gravity at all. Instead simply use add_central_force in _physics_process:
add_central_force(Input.get_gravity().rotated(Vector3(-1, 0, 0), deg2rad(90)))
This is something that differs between 2D and 3D physics in Godot: in 3D forces are reset every physics frame.
So, if I do this in a RigidBody2D:
func _ready() -> void:
add_central_force(Vector2.LEFT * 10)
I'll see the RigidBody2D accelerate to the left…
But if I do this in a RigidBody:
func _ready() -> void:
add_central_force(Vector3.LEFT * 10)
I'll see the RigidBody move a little and then stop, or not move at all (depending if it is using Bullet or GodotPhysics).
Thus, since you are working in 3D, you don't need to keep track of the prior forces you added.
I am trying to model the interior of an epithelial space and am stuck on movement around the interior edges of a cylindrical space. Basically, I'm trying to implement StickyBorders and keep agents on those borders in a cylindrical space that I am creating.
Is there a way to use cylindrical coordinates in Repast Simphony? I found this example (https://www.researchgate.net/publication/259695792_An_Agent-Based_Model_of_Vascular_Disease_Remodeling_in_Pulmonary_Arterial_Hypertension) where they seem to have done something similar, but the paper doesn't explain methods in much depth, and I don't believe this is an example in the repast simphony models.
Currently, I have a class of epithelial cells that are set up to form a cylinder and other agents start just inside that cylinder. To move, they are choosing their most desired spot (similar to the Zombie code) then pointing to a new location in the direction of that desired location within one grid square of that original location. They check that new point before moving to it and make sure that there are at least two other epithelial cells in the immediate moore neighborhood, to ensure they stay against the wall.
GridPoint intendedpt = new GridPoint((int)Math.rint(alongX),(int)Math.rint(alongY),(int)Math.rint(alongZ));
GridCellNgh<EpithelialCell> nearEpithelium = new GridCellNgh<EpithelialCell>(mac_grid, intendedpt, EpithelialCell.class, 1,1,1);
List<GridCell<EpithelialCell>> EpiCells = nearEpithelium.getNeighborhood(false);
int nearbyEpiCellsCount=0;
for (GridCell<EpithelialCell> cell: EpiCells) {
nearbyEpiCellsCount++;
}
if (nearbyEpiCellsCount<2) {
System.out.println(this + " leaving epithelial wall /r");
RunEnvironment.getInstance().pauseRun();
//TODO: where to go if false
}
I am wondering if there is a way to either set the boundaries of the space to be a cylinder or to check which side of the agent is against the wall and restrict its movement in that direction.
The sticky border code (StickyBorders.java) essentially just checks if the point that the agent moves to is beyond any of the space's dimensions, and if so the point is clamped to that dimension. So, for example, if the space is 3x4 and an agent's movement would take it to 4,2, then that point becomes 3,2 and the agent is placed there. Can you do something like that in this case? If not, can you edit your question to explain why not and maybe that will help us understand better.
The approach we took in that model was to use a 3D grid space with custom borders and query methods. The space itself was still Cartesian - we just visualized it as a cylinder using custom display code. Using the Cartesian grid was an reasonable approximation for this application since the cell dimensions were significantly smaller that the vessel radius, so curvature effects were neglected. The boundary conditions on the vessel space were wrap around in the angular dimension, so that cells could move continuously around the circumference of the vessel, and the axial boundary conditions were also wrapped, as we assumed a long enough vessel length that this would be reasonable. The wall thickness dimension had hard boundaries at the basement membrane (y=0) and at the fluid interface (y=wall thickness).
Depending on which type of space you are using, you will need to implement a PointTranslator or GridPointTranslator that performs the border functions. If you want specific examples of the code I suggest you reach out to the author's directly.
I have a circle-shaped dynamic body and I need to resize it during the game (It appears like a point, then it grows to a circle and after that it starts moving). How should I do that?
I have an idea - it's to use some animation (Circle has the same radius, but due to animation it looks like the circle grows), but I'm not sure if it's right way or not. (Besides I don't know how to realize it)
For scaling circle, if you are using sprite just scale it sprite.setScale(float), if your sprite is attached to Box2d Circle-shape then get the Body's shape and set the radius
Shape shape = body.getFixture().getShape;
shape.setRadius(radiusValue);
and if you are using ShapeRenderer just multiply the points of ShapeRenderer.
I assume that you are talking about a Box2D body.
It is not possible to change a circle-shaped fixture with Box2D. Box2D is a rigid body simulator. What you would have to do is destroy the fixture and replace it with a smaller/bigger version of the circle. But this will cause a lot of problems, since you cannot destroy a fixture when there is still a contact for example.
It would be better to keep the circle the same size and just simulate a change in size with an animation of a texture on top.
If you cannot simulate that, then maybe try the following approach: Have several versions of that circle in different sizes and keep them on top of each other. Implement a ContactFilter which will only cause contacts for the one circle which is currently "active".
Inside any Object class with box2d, I use the following for dynamic resizing:
public void resize(float newradius) {
this.body.destroyFixture(this.fixture);
fixtureDef.density = (float) (this.mass/(Math.PI*newradius*newradius));
this.radius = newradius;
CircleShape circle = new CircleShape();
circle.setRadius(newradius);
this.fixtureDef.shape = circle;
circle.dispose();
this.fixture = body.createFixture(fixtureDef);
this.fixture.setUserData(this);
}
You can also see the following topic: How to change size after it has been created
I have been having great difficulty creating a jumping system whereby the user can tap the jump button for a small jump and hold it down for a higher jump.
I stumbled upon this topic:
https://gamedev.stackexchange.com/questions/13277/variable-height-jumping-in-side-scrollers
Which greatly helped me develop the following code:
PlayerMovementTimer = [NSTimer scheduledTimerWithTimeInterval:0.005 target:self selector:#selector(movePlayer) userInfo:nil repeats:YES];
[JumpButton addTarget:self action:#selector(jumpPlayer:) forControlEvents:UIControlEventTouchDown];
[JumpButton addTarget:self action:#selector(stopJump:) forControlEvents:UIControlEventTouchCancel | UIControlEventTouchUpInside | UIControlEventTouchDragExit];
- (void)movePlayer
{
CGFloat playerY = Player.center.y + PlayerYV;
if(playerY > 264) {
PlayerYV = 0;
playerY = 264;
}
if(playerY < 264) {
PlayerYV += 0.048f - PlayerYD;
}
if(HoldingJump && PlayerYV < 0 && PlayerYD + 0.0018f < 0.048f) {
PlayerYD += 0.0018f;
}
Player.center = CGPointMake(Player.center.x + PlayerXV, playerY);
}
- (IBAction)jumpPlayer:(id)sender
{
if(Player.center.y == 264) {
PlayerYD = 0;
PlayerYV = -2.25;
HoldingJump = true;
}
}
- (IBAction)stopJump:(id)sender
{
HoldingJump = false;
}
The code seems to work (some of the values need a bit of fine tuning but I haven't gotten round to that yet). The only problem is that the movement appears to be slightly jerky (even on the real device) and that when the player is at the top of the jump they accelerate really slowly and no values I put seem to be able to get the jump to look smooth like on Mario games.
Please take a look at the code and see if I am missing something obvious, or if there is a more efficient method of controlling movement than an NSTimer calling a void function. Also, is setting a UIImageView's position to a float value bad?
Thanks.
So there are quite a few things wrong here. First, yes, you should never be setting the origin of an ImageView or any other UI element to a coordinate position that is a fractional pixel. This causes sub-pixelling which will blur your image. To avoid this, all CGFloats should be rounded to the nearest whole number using roundf() or other similar rounding functions.
Another issue I can see is that you're setting Player.center. I hope for your sake that Player is not an ImageView cause you're going to be making your life harder. As mentioned above, when the origin of a frame is not set to a CGFloat that is a round number, you'll get sub-pixelling. When you use the center property, you can easily cause yourself to get on a bad origin value. For example, if I have a 11 by 11 image and set it's center to (11,11), the origin will get set to (5.5,5.5) and will cause sub-pixelling. Easy ways to avoid this is just do the math to place the origin correctly and make sure to round the CGFloats that you feed into it (or use CGRectIntegral on the frame before you set it).
A third issue here is that the timer is being called 0.005 seconds. Let's assume you want this game to run with 60 FPS. 60 FPS translates to about 0.0167 seconds. The timer is calling the method three times more often then it would need to even if you wanted 60 FPS and additionally, calling this method so often could be causing some of your jerky motion.
Now in terms of getting a "Mario" like jump, what you really need to do is look at getting a dedicated physics engine since if you're using the code above, you don't appear to have one. What a physics engine would do is it would apply a constant "gravity" which will help make the player jumps look and act more realistically. You would, when a player presses a button, apply an impulse up on the player character. The use of impulses would also simplify your work as you could apply impulses in different ways depending on how long they hold the button, etc. The code above is simply trying to get around this problem instead of addressing the real issue of you not having a physics engine.
Go investigate cocos2D and Box2D as a possible physics engine you could use. There are a wealth of resources on cocos2D+Box2D and there is a developer who even has made a tutorial on using cocos2D to create a Super Mario clone that should give you some basic understanding of how physics engines work: http://www.raywenderlich.com/15230/how-to-make-a-platform-game-like-super-mario-brothers-part-1
I'm having trouble with physics in unity 3d. I'm wanting my ball to bounce off of walls and go another direction. When the ball hits the wall it just bounces straight back. I have tried changing the direction to be orthogonal to the direction it hits the wall but it doesn't change direction. Due to this, the ball just keeps hitting the wall and bouncing straight back.
Secondly, sometimes the ball goes through the wall. The walls have box colliders while the ball has a sphere collider. They all have continuous dynamic as the collision detection mode.
Here's a link to a similar thread:
http://forum.unity3d.com/threads/22063-I-shot-an-arrow-up-in-the-air...?highlight=shooting+arrow
Personally, I would code the rotation using LookAt as GargarathSunman suggests in this link, but if you want to do it with physics, you'll probably need to build the javelin in at least a couple of parts, as the others suggest in the link, and add different drag and angular drag values to each part,perhaps density as well. If you threw a javelin in a vacuum, it would never land point down because air drag plays such an important part (all things fall at the same rate regardless of mass, thank you Sir Isaac Newton). It's a difficult simulation for the physics engine to get right.
Maybe try to get the collider point between your sphere and your wall then catch your rigidbody velocity and revert it by the collision point normal.
an example of a script to do that ---> (put this script on a wall with collider )
C# script:
public class WallBumper : MonoBehaviour
{
private Vector3 _revertDirection;
public int speedReflectionVector = 2;
/***********************************************
* name : OnCollisionEnter
* return type : void
* Make every gameObject with a RigidBody bounce againt this platform
* ********************************************/
void OnCollisionEnter(Collision e)
{
ContactPoint cp = e.contacts[0];
_revertDirection = Vector3.Reflect(e.rigidbody.velocity, cp.normal * -1);
e.rigidbody.velocity = (_revertDirection.normalized * speedReflectionVector);
}
}
I recently has an issue with a rocket going through targets due to speed and even with continuous dynamic collision detection I couldn't keep this from happening a lot.
I solved this using a script "DontGoThroughThings" posted in wiki.unity3d.com. This uses raycasting between current and previous positions and then ensures the frame ends with the colliders connected for messages an OnTrigger event. Has worked everytime since and it's just a matter of attaching the script so super easy to use.
I think the physics answer is as others have suggested to use multiple components with different drag although typically I think you only want a single RigidBody on the parent. Instead of direction using transform.LookAt you could try and calculate using Quaternion.LookRotation from the rigidbody.velocity. Then use Vector3.Angle to find out how much are are off. The greater the angle diference the more force should be experienced and then use RigidBody.ApplyTorque. Maybe use the Sin(angleDifference) * a constant so less force is applied to torque as you approach proper rotation.
Here is some code I used on my rocket although you'll have to substitute some things as I was pointing toward a fixed target and you'll want to use your velocity.
var rotationDirection = Quaternion.LookRotation(lockedTarget.transform.position - this.transform.position);
var anglesToGo = Vector3.Angle(this.transform.rotation.eulerAngles, rotationDirection.eulerAngles);
if (anglesToGo > RotationVelocity)
{
var rotationDirectionToMake = (rotationDirection * Quaternion.Inverse(this.transform.rotation)).eulerAngles.normalized * RotationVelocity;
transform.Rotate(rotationDirectionToMake);
}