I'm trying to program a simple platformer game with very accurate movement using Unreal Engine 4 (4.22 release). It took some inspiration from games like Super Meat Boy or Celeste.
I'm using the APaperCharacter that uses UCharacterMovementComponent, but I'm not very satisfied of it.
Particularly I would like to avoid the deflection that is used in UCharacterMovementComponent::PhysFalling() method:
const FVector OldHitNormal = Hit.Normal;
const FVector OldHitImpactNormal = Hit.ImpactNormal;
FVector Delta = ComputeSlideVector(Adjusted, 1.f - Hit.Time, OldHitNormal, Hit);
// Compute velocity after deflection (only gravity component for RootMotion)
if (subTimeTickRemaining > KINDA_SMALL_NUMBER && !bJustTeleported)
{
const FVector NewVelocity = (Delta / subTimeTickRemaining);
Velocity = HasAnimRootMotion() && !CurrentRootMotion.HasOverrideVelocity() ? FVector(Velocity.X, Velocity.Y, NewVelocity.Z) : NewVelocity;
}
I recorded a video to show you the behavior I would like to prevent:
https://www.youtube.com/watch?v=fko1aPl-Vdo
I'm thinking to create my personal movement component that derives UCharacterMovementComponent in order to override the ComputeSlideVector() method, but I don't know if it is the best idea to resolve this issue.
I would like to have your opionion and I would like to know if I can simply solve the problem changing some parameters by editor.
I eventually decided to create my own class derived from UCharacterMovementComponent.
I solved the issue I described in my question overriding the UCharacterMovementComponent ::ComputeSlideVector() method:
FVector UMyMovementComponent::ComputeSlideVector(const FVector& Delta, const float Time, const FVector& Normal, const FHitResult& Hit) const
{
FVector Result = Super::ComputeSlideVector(Delta, Time, Normal, Hit);
if (Hit.bBlockingHit)
{
float Angle = FVector::DotProduct(Hit.Normal, FVector::DownVector);
if (Angle > KINDA_SMALL_NUMBER) // if the collision normal points downwards
{
Result.X = 0.0f;
}
}
return Result;
}
Related
I have been working on a simulation of a projectile launcher that fire a projectile to a target that is orbiting around center point. I do appreciate if someone would help explaining what is wrong with my calculation. (User input radii from center to the object, angle of center and the object, speed of the target, speed of the projectile)
This is part of my calculation function.
void::targetMove()
{double theta = 360;
theta = theta - angle;
PosX = (radius*cos(theta));
PosY = (radius*sin(theta));
angle = angle*timeStep;
return;}
This is part of my main.cpp
target tar;
projectile pro;
double spd, spd2, timeStep = 0, radius, ang;
launcher lau;
bool miss = true;
do
{
pro.distanceCal();
timeStep++;
tar.setTimeStep(timeStep);
cout<<"\n*TIME STEP "<<timeStep<<"*"<<endl<<"------------"<<endl;
tar.display();
if (abs((spd2*timeStep)/2 - pro.distanceCal()) <= 1)
{cout<<"\nThe projectile hits the target."<<endl<<endl;
miss = false;}
else
{ miss = true;}
while (miss);
This is my distance calculation function
double projectile::distanceCal()
{ distance = sqrt(pow(tar.getPosX()-tar.getCenterX(),2)+pow(tar.getPosY()-tar.getCenterY(),2));
return distance;}
My problem is that it looks like the of the orbiting target is not moving in circular motion. I kept getting weird numbers as my output for the new position of the target.
Thank you in advance for your kindness.
These are all functions that do all the calculation. The rest are just get/set functions.
I'm building a game with Cocos2d-x version 3.13.1 and I've decided to go with the built-in physics engine (Chipmunk 2D) to accomplish animations and collision detection. I have a simple projectile called BulletUnit that inherits from cocos2d::Node. It has a child sprite that displays artwork, and a rectangular physics body with the same dimensions as the artwork.
The BulletUnit has a method called fireAtPoint, which determines the angle between itself and the point specified, then sets the initial velocity based on the angle. On each update cycle, acceleration is applied to the projectile. This is done by applying impulses to the body based on an acceleration variable and the angle calculated in fireAtPoint. Here's the code:
bool BulletUnit::init() {
if (!Unit::init()) return false;
displaySprite_ = Sprite::createWithSpriteFrameName(frameName_);
this->addChild(displaySprite_);
auto physicsBody = PhysicsBody::createBox(displaySprite_->getContentSize());
physicsBody->setCollisionBitmask(0);
this->setPhysicsBody(physicsBody);
return true;
}
void BulletUnit::update(float dt) {
auto mass = this->getPhysicsBody()->getMass();
this->getPhysicsBody()->applyImpulse({
acceleration_ * mass * cosf(angle_),
acceleration_ * mass * sinf(angle_)
});
}
void BulletUnit::fireAtPoint(const Point &point) {
angle_ = Trig::angleBetweenPoints(this->getPosition(), point);
auto physicsBody = this->getPhysicsBody();
physicsBody->setVelocityLimit(maxSpeed_);
physicsBody->setVelocity({
startingSpeed_ * cosf(angle_),
startingSpeed_ * sinf(angle_)
});
}
This works exactly as I want it to. You can see in the image below, my bullets are accelerating as planned and traveling directly towards my mouse clicks.
But, there's one obvious flaw: the bullet is remaining flat instead of rotating to "point" towards the target. So, I adjust fireAtPoint to apply a rotation to the node. Here's the updated method:
void BulletUnit::fireAtPoint(const Point &point) {
angle_ = Trig::angleBetweenPoints(this->getPosition(), point);
// This rotates the node to make it point towards the target
this->setRotation(angle_ * -180.0f/M_PI);
auto physicsBody = this->getPhysicsBody();
physicsBody->setVelocityLimit(maxSpeed_);
physicsBody->setVelocity({
startingSpeed_ * cosf(angle_),
startingSpeed_ * sinf(angle_)
});
}
This almost works. The bullet is pointing in the right direction, but the trajectory is now way off and seems to be arcing away from the target as a result of the rotation: the more drastic the rotation, the more drastic the arcing. The following image illustrates what's happening:
So, it seems that setting the rotation is causing the physics engine to behave in a way I hadn't originally expected. I've been racking my brain on ways to correct the flight path, but so far, no luck! Any suggestions would be greatly apprecitated. Thanks!
I've been lately working on a simple game using C++ and SFML latest version, but I had a problem which is that the collision detection is not that good, for example the player dies even if the enemy didn't touch him yet, but just near him. Here is the code of the player class with the move function and collision detection code AND the moves of the enemy class:
`class PlayerA : public CircleShape
{
public:
//Constructor:
PlayerA(float xposition, float yposition, float radius, float s)
{
setRadius(radius);
setFillColor(Color::Yellow);
setOutlineColor(Color(00,80,00));
setOutlineThickness(-2);
setPointCount(3);
setSpeed(s);
setPosition(xposition,yposition);
}
//Movements of the player:
void up()
{
move(0,-10*speed);
}
void down()
{
move(0,10*speed);
}
void right()
{
move(10*speed,0);
}
void left()
{
move(-10*speed,0);
}
void checkA(ObsA *obs1=NULL,ObsA *obs2=NULL, ObsA *obs3=NULL, ObsA *obs4=NULL, ObsA *obs5=NULL)
{
if(obs2==NULL)
{
if(getGlobalBounds().intersects(obs1->getGlobalBounds()))
{
relevel();
}
}
private:
float speed=0.00;
void obs()
{
if(speed > 0)
{
rotate(0.5*speed);
}
else
{
rotate(0.5*speed);
}
}
private:
float speed = 0.00;
void obs()
{
if(speed > 0)
{
rotate(0.5*speed);
}
else
{
rotate(0.5*speed);
}
}
private:
float speed = 0.00;
Is there something wrong with the code, how to fix the problem, thank you!
The intersects function just check if two rectangles intersect. If you want pixel perfect collision detection in SFML you have to write that yourself.
Basically, start with intersects, if it is true, then get the intersecting rectangle and check if any pixels therein from both original rectangles contains overlaping relevant pixels.
You can use this function to perform better collision detection.Its a basic one but works well
bool circleTest(const sf::Sprite &first, const sf::Sprite &second)
{
sf::Vector2f firstRect(first.getTextureRect().width, first.getTextureRect().height);
firstRect.x *= first.getScale().x;
firstRect.y *= first.getScale().y;
sf::Vector2f secondRect(second.getTextureRect().width, second.getTextureRect().height);
secondRect.x *= second.getScale().x;
secondRect.y *= second.getScale().y;
float r1 = (firstRect.x + firstRect.y) / 4;
float r2 = (secondRect.x + secondRect.y) / 4;
float xd = first.getPosition().x - second.getPosition().x;
float yd = first.getPosition().y - second.getPosition().y;
return std::sqrt(xd * xd + yd * yd) <= r1 + r2;
}
Are you using a circle? If I remember correctly, the circle will have a rectangle hitbox. If that is the case, then you may have collision between the invisible rectangle corners.
If you're using a circle, Perhaps change class to a square rectangle and see if collision works correctly. Or try testing collision directly on an x or y axis with your circles; i.e. having them moving in a straight line towards each other only changing 1 axis. (the edge of the circle will be the same as the edge of the rectangle at the left, right, top, and bottom sections).
If you're needing a better collision for circles, there may be one already built in SFML. But I don't think it would be too much to write your own logic using the radius of your two circles, the center of your two objects, and the angle hypotenuse between the centers.
edit based on Merlyn Morgan-Graham's comment.
I am new to c++ as well as game development. I coded a function using bullet physics which returns the gravity of the world and it seems to be not working. It always returns 0. Though, I've initialized the world, solver, dispatcher, broadphase and collision configuration.
Here's the code:
void _setGravity(btScalar gravity) //sets the gravity of the world
{
if(gravity > 0.f)
gravity = -gravity;
_dynamicsWorld->setGravity(btVector3(0, gravity, 0));
}
btScalar _getGravity(void) //returns the gravity of the world
{
return ((btScalar*)_dynamicsWorld->getGravity());
}
Is there something that I am doing wrong ?
Thank you.
The getGravity function returns a btVector3 by value, so you need to use resulting vectors getY to get the gravity:
return _dynamicsWorld->getGravity().getY();
Until lately I've been just changing the x coordinate of my sprite on each update and I was happy with it. But yesterday when being in the debugDraw mode, I found out that after certain speed physics body wouldn't align correctly with the sprite ,like this:
Later I got told that, (by Birkemose in cocos2d forum) the preferred way to move a physics body from A to B is to apply impulse to it. But I have no idea how to achieve constant speed this way. This is the code I used to move it without applying any impulse:
-(void)update:(CCTime)delta{
rollingHero.position=ccp(rollingHero.position.x+scrollSpeed*delta,
rollingHero.position.y);
physicsNode.position=ccp(physicsNode.position.x-scrollSpeed*delta,
physicsNode.position.y);
}
So to create a feeling of moving I scroll the physics node and the hero in opposite directions with the same scrolling speed.
I tried lots of different variants of applying impulse, but I never got it moving with constant speed. The speed accelerates and the hero gets offscreen. I would appreciate it very much if someone would post a sample code.
The reason impulse isn't working to keep your character at a constant speed is because impulse translates directly into a change in momentum (and thus a change in velocity). So if you were to try to maintain a constant velocity through impulse, you would have to check your sprite's velocity first, and although you could get pretty close to a constant velocity, it wouldn't be truly constant.
static const float kRollingHeroMoveSpeed = 10.f;
static const float kRollingHeroAccelConstant = 10.f;
-(void)update:(CCTime)delta {
// check velocity of sprite
if(_rollingHero.physicsBody.velocity.x < kRollingHeroMoveSpeed) {
// if velocity is under limit, push character
[_rollingHero.physicsBody applyImpulse:ccp(kRollingHeroAccelConstant, 0)];
}
}
The better way to do this is to step into the C level of the Chipmunk2D physics engine that powers Cocos2D physics.
-(void)onEnter {
[super onEnter];
// tell physics engine to use our C function to update physics body
_rollingHero.physicsBody.body.body->velocity_func = playerUpdateVelocity;
}
static void playerUpdateVelocity(cpBody *body,
cpVect gravity,
cpFloat damping,
cpFloat dt) {
// check validity of cpBody
cpAssertSoft(body->m > 0.0f && body->i > 0.0f, "Body's mass and moment must be positive to simulate. (Mass: %f Moment: %f)", body->m, body->i);
// update velocity and angular velocity
body->v = cpvadd(cpvmult(body->v, damping), cpvmult(cpvadd(gravity, cpvmult(body->f, body->m_inv)), dt));
body->w = body->w*damping + body->t*body->i_inv*dt;
// reset force vector
body->f = cpvzero;
// reset torque
body->t = 0.0f;
// set body's velocity to desired velocity
body->v.x = kRollingHeroMoveSpeed;
}
Here's cpBody.h on Github.