Rotate sprite according to onMouseMove cocos2d-x - cocos2d-x

img
auto spr= Sprite::create("spr.png");
spr->setPosition(Vec2(500, 500);
spr->setScale(0.2);
layer->addChild(gun, 1);
What do I need to do so my sprite can rotate my head according to the mouse position
void HelloWorld::onMouseMove(Event *event)
{
EventMouse* e = (EventMouse*)event;
(................)
}
1:

I think this is what you are trying to do:
const float PI = 3.1415;
void HelloWorld::onMouseMove(Event *event)
{
float dx = evnt->getCursorX() - spr->getPosition().x;
float dy = evnt->getCursorY() - spr->getPosition().y;
float rotation = (atan2(dx, dy)) * 180 / PI;
spr->setRotation(rotation);
}
I don't understand what you mean with "so my sprite can rotate my head" but that is the way to rotate a sprite, so apply it to whatever sprite you need.
Hope it helps! :D

Related

Collision detection for an arc of a circle

So how do i implement the collision detection for an arc of a circle? Will i have to use the Box 2d collision or can i do it some other way using Rectangle or stuff like that?
BTW I hate box2d because i dont understand most of the things in it, so if there is a solution that excludes the box2d, it will be very much appreciated.
The yellow arc keeps on rotating over the black circle. How do i implement collision detection in here?
Please help ! Thanks!
To avoid using Box2D you could define the shape as a polygon and use the polygon.contains(x,y) method or use the Intersector
Below is an example using both:
import com.badlogic.gdx.ApplicationAdapter;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.InputProcessor;
import com.badlogic.gdx.graphics.Color;
import com.badlogic.gdx.graphics.GL20;
import com.badlogic.gdx.graphics.glutils.ShapeRenderer;
import com.badlogic.gdx.math.Circle;
import com.badlogic.gdx.math.Intersector;
import com.badlogic.gdx.math.Polygon;
public class Test extends ApplicationAdapter implements InputProcessor{
private ShapeRenderer sr;
private Polygon polya;
private boolean isColliding = false;
private Circle mp;
#Override
public void create () {
//define arc as polygon
// the more points used to define the shape will
// increase both required computation and collision precision
polya = new Polygon();
// create vertices
float section = 15f;
float[] newVerts = new float[200];
for(int i = 0; i < 50; i++){
newVerts[i*2] = (float)Math.sin(i/section); //x 0 to 98 even
newVerts[i*2+1] = (float)Math.cos(i/section); //y 1 to 99 odd
newVerts[199-i*2] = (float)Math.cos(i/section); //x 100 to 108
newVerts[198-i*2] = (float)Math.sin(i/section) + 0.2f; //y 101 to 199
}
polya.setVertices(newVerts);
polya.scale(50);
polya.setOrigin(1, 1);
polya.rotate(60);
//define circle to act as point for checking intersections
mp = new Circle(Gdx.graphics.getWidth()/2,Gdx.graphics.getHeight()/2,4);
// setup batchers
sr = new ShapeRenderer();
sr.setAutoShapeType(true);
Gdx.input.setInputProcessor(this);
}
#Override
public void render () {
Gdx.gl.glClearColor(0f, 0f, 0f, 0f);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
// check collision with polygon
isColliding = polya.contains(mp.x,mp.y);
//check collision using Intersector
isColliding = Intersector.isPointInPolygon(polya.getTransformedVertices(),0,polya.getVertices().length,mp.x,mp.y);
sr.begin();
sr.setColor(Color.WHITE);
if(isColliding){
sr.setColor(Color.RED);
}
sr.polygon(polya.getTransformedVertices());
sr.circle(mp.x,mp.y,mp.radius);
sr.end();
}
#Override
public void dispose () {
}
#Override
public boolean mouseMoved(int screenX, int screenY) {
int newy = Gdx.graphics.getHeight() - screenY;
polya.setPosition(screenX, newy);
return false;
}
(... removed unused input processor methods for clarity ...)
}
In my case, the arc was in motion and I needed to calculate its collision, so I updated the polygon along with the rendering. Essentially, I got the vertices in the same way that LibGDX renders an arc.
On the left you can see what the arcs I'm drawing look like. On the right you can see what the polygons would look like calculated from the shape of their corresponding arcs if I had to draw them.
Ignore the different colors and count of sections, they are randomly generated.
To achieve this result, I wrote this method:
import com.badlogic.gdx.math.MathUtils;
import com.badlogic.gdx.math.Polygon;
import com.badlogic.gdx.math.Vector2;
import java.util.ArrayList;
// ...
public void fillPolygonWithArc(Polygon polygon, float x, float y, float radius, float start, float degrees, int segments) {
float theta = (2 * MathUtils.PI * (degrees / 360.0f)) / segments;
float cos = MathUtils.cos(theta);
float sin = MathUtils.sin(theta);
float cx = radius * MathUtils.cos(start * MathUtils.degreesToRadians);
float cy = radius * MathUtils.sin(start * MathUtils.degreesToRadians);
ArrayList<Vector2> vertices = new ArrayList<>();
vertices.add(new Vector2(x, y));
vertices.add(new Vector2(x + cx, y + cy));
for (int i = 0; i < segments; i++) {
vertices.add(new Vector2(x + cx, y + cy));
float temp = cx;
cx = cos * cx - sin * cy;
cy = sin * temp + cos * cy;
vertices.add(new Vector2(x + cx, y + cy));
}
vertices.add(new Vector2(x + cx, y + cy));
cx = 0;
cy = 0;
vertices.add(new Vector2(x + cx, y + cy));
polygon.setVertices(new float[vertices.size() * 2 + 4]);
for (int i = 0; i < vertices.size(); i++) {
polygon.setVertex(i, vertices.get(i).x, vertices.get(i).y);
}
}
// ...
How does he work?
It takes as parameters a polygon in which to write the vertices of the
arch and the parameters needed to get the shape of the arch, these are
the same parameters that you pass to the method that draws the arc (shapeRenderer.arc).
And then it calculates the vertices of the arch in the same way as
LibGDX does and fills the polygon with them.
I just looked at the LibGDX source.
Use case:
fillPolygonWithArc(polygon, getPosition().x, getPosition().y, getRadius(), start, finalStep, getSegments());
shapeRenderer.setColor(color);
shapeRenderer.begin(ShapeRenderer.ShapeType.Filled);
shapeRenderer.arc(getPosition().x, getPosition().y, getRadius(), start, finalStep, getSegments());
shapeRenderer.end();
Also, if you want, you can draw a polygon:
fillPolygonWithArc(polygon, getPosition().x, getPosition().y, getRadius(), start, finalStep, getSegments());
shapeRenderer.setColor(color);
shapeRenderer.begin(ShapeRenderer.ShapeType.Line);
shapeRenderer.polygon(polygon.getVertices());
shapeRenderer.end();
Ultimately, you can check if some point is inside the polygon you need:
polygon.contains(new Vector2(4, 20));

How to achieve the following effect with libGDX?

I'm developping a game with libGDX. I have a question: Know the initial coordinates and target coordinates, as the picture shows, how to achieve the parabolic effect of the bullet ? to achieve the operation of shells . Who can teach me ? or tell me some tutorial. Tks
picture
You need to add some physics to your app (ex. Box2d). Then you 'throw' canon ball with some velocity and some direction/angle.
Physics engine do rest for you.
Here you have tutorial for box2d: https://www.youtube.com/watch?v=vXovY2KTing
Very very basic example for throw something without box2d. For your example you need to calculate right 'power' for target position.
public class SampleApp extends ApplicationAdapter
{
Sprite sprite;
Vector2 velocity = new Vector2(0, 0);
Vector2 terminateVelocity = new Vector2(2000, 2000);
Vector2 friction = new Vector2(200, 300);
Vector2 position = new Vector2(0, 0);
Vector2 launchPower = new Vector2(0, 0);
boolean shotNow;
#Override
public void render()
{
update(Gdx.graphics.getDeltaTime());
// ...
// here render your stuff
}
public void shot(float power)
{
// Calculate x launch power
launchPower.x = ((power - sprite.getX() + sprite.getWidth()*0.5f) / 2f) + velocity.x;
// We want to end our fly at ground
launchPower.y = ((0 - sprite.getY()) / 2f) + velocity.y;
// Setup start position
position.x = sprite.getX();
position.y = sprite.getY();
// Add some acc to velocity
velocity.add(launchPower);
shotNow = true;
}
public void update(float dt)
{
if (Gdx.input.justTouched()) {
shot(900);
}
// Very basic sprite movement.
// For best results you should implement more physics (acceleration etc.)
if (shotNow && position.y > 0) {
// Friction/gravity
velocity.x = MathUtils.clamp(velocity.x - friction.x * dt, -terminateVelocity.x, terminateVelocity.x);
velocity.y = MathUtils.clamp(velocity.y - friction.y * dt, -terminateVelocity.y, terminateVelocity.y);
position.add(velocity.x * dt, velocity.y * dt);
sprite.setPosition(position.x, position.y);
}
}
}

move body to specific point in world coordinates at a constant speed

I have a kinematic body with gravity 0 which I want to move from a specific point to a specific point in my world coordinates. I've tried to adjust the code from here
to the one below. But the body stays still and doesn't move?
#Override
public void act(float delta) {
super.act(delta);
//Target position in world coordinates
Vector2 targetPosition = new Vector2(4.5142856f, -4.228572f);
//target speed
float targetSpeed = 1f;
//direction
Vector2 direction = targetPosition.sub(body.getPosition());
//distance
float distanceToTravel = direction.nor().len2();
// For most of the movement, the target speed is ok
float speedToUse = targetSpeed;
float distancePerTimestep = speedToUse / 60.0f;
if ( distancePerTimestep > distanceToTravel )
speedToUse *= ( distanceToTravel / distancePerTimestep );
Vector2 desiredVelocity = direction.scl(speedToUse);
Vector2 changeInVelocity = desiredVelocity.sub(body.getLinearVelocity());
Vector2 force = new Vector2(changeInVelocity.scl(body.getMass() * 60.0f));
System.out.println(force);
body.applyForce(force, body.getWorldCenter(), true);
}
Ok I figured it out. The method below will return the correct velocity so that the body can reach the target point.
public Vector2 calculateVelocity(Vector2 target) {
Vector2 direction = new Vector2(target.x - body.getPosition().x, target.y - body.getPosition().y ).nor();
float speed = Constants.enemySpeed;
return new Vector2( speed * direction.x, speed * direction.y );
}

How to find correct offset to adjust sprite to the position of box2D body after rotation

I am trying to implement phsyics with the as3 box2d port. I currently have a b2body for each of some certain sprites in my game and I am able to update the sprite's positions correctly from the positions of the bodies. This is shown in the picture below (debugDraw shows the positions of the b2bodies overlaid on their corresponding spirtes. The green rectangles are the walls and floor)
However, I also want to have the sprite's rotations reflect the rotations of the b2bodies. But, after I rotate the sprites, the offset I use to center them correctly with the b2body positions is no longer accurate.
My code for updating the sprites positions is as follows:
private function Update(update_event:TimerEvent):void
{
//step physics simulation forward
world.Step(0.025,10,10);
//update all objects in world
for each (var obj:HouseItemPhysicsObject in physicsObjects)
{
//update object's position from gravity if it is not being dragged
if(!obj.isHeld)
{
/*adjust rotation of sprite along with body -> yourMC.rotation = (yourMCbody.GetAngle() * 180 / Math.PI) % 360; */
obj.object.rotation = (obj.pBody.GetAngle() * 180/Math.PI) % 360;
if(obj.object.rotation >=5)
// set object's x position but adjust for offset between the cooridinate systems
obj.x = (obj.pBody.GetPosition().x* scaleFactor)-(obj.object.width/2);
//keep in horizontal bounds of screen
if(obj.x > GeneralConstants.GAME_WIDTH)
{
obj.x =GeneralConstants.GAME_WIDTH;
}
else if(obj.x < 0)
{
obj.x = 0;
}
// set object's x position but adjust for offset between the cooridinate systems in Flash and box2d
obj.y = (obj.pBody.GetPosition().y * scaleFactor)-(obj.object.height/2);
//keep in vertical bounds of the screen
if(obj.y > GeneralConstants.GAME_HEIGHT)
{
obj.y =GeneralConstants.GAME_HEIGHT;
}
else if(obj.x < 0)
{
obj.x = 0;
}
/*Draw shapes to see for debug*/
//obj.DrawDebug();
//trace("OBJECT's X is :" + obj.x + " Y is :" +obj.y);
trace("Object's rotation is:" + obj.object.rotation);
}
}
//move debug draw to front of display list
m_sprite.parent.setChildIndex(m_sprite, m_sprite.parent.numChildren - 5);
world.DrawDebugData();
}
How can I find the correct X and Y offset between the coordinate systems (Flash and Box2d) after rotating the sprite according to the b2Body? Thanks for the help.
EDIT:
For clarity, the object is a class that extends the Sprite class, and it's data member _object is a an instance of MovieClip.
Box2D objects have their anchor point in the center by default, while for Flash objects, it's in the top left. To position them properly, you need to take this into account
Easy way
Wrap your Bitmaps/whatever in a Sprite and center them:
// create the image, center it, and add it to a holder Sprite
var image:Bitmap = new Bitmap( objGraphicsBitmapData );
image.x = -image.width * 0.5;
image.y = -image.height * 0.5;
var holder:Sprite = new Sprite;
holder.addChild( image );
Now just set the position and rotation of holder as you do currently, and it should be fine
Hard way
You need to manually adjust the position offset based on the object's rotation. A simple rotation function:
public function rotate( p:Point, radians:Number, out:Point = null ):Point
{
// formula is:
// x1 = x * cos( r ) - y * sin( r )
// y1 = x * sin( r ) + y * cos( r )
var sin:Number = Math.sin( radians );
var cos:Number = Math.cos( radians );
var ox:Number = p.x * cos - p.y * sin;
var oy:Number = p.x * sin + p.y * cos;
// we use ox and oy in case out is one of our points
if ( out == null )
out = new Point;
out.x = ox;
out.y = oy;
return out;
}
First we need to store the object's offset - this is normally new Point( -obj.width * 0.5, -obj.height * 0.5 ). You need to stock this while it's rotation is 0, and rotating the object will change its width and height properties, so the following won't work properly.
obj.offset = new Point( -obj.width * 0.5, -obj.height * 0.5 );
When you're updating the position, simply rotate the offset by the rotation and add it:
// get our object's position and rotation
// NOTE: you'll probably need to adjust the position based on your pixels per meter value
var pos:Point = new Point( obj.pBody.GetPosition().x, obj.pBody.GetPosition().y ); // pos in screen coords
var rotR:Number = obj.pBody.GetAngle(); // rotation in radians
var rotD:Number = radiansToDegrees( rotR ); // rotation in degrees
// rotate our offset by our rotation
var offset:Point = rotate( obj.offset, rotR );
// set our position and rotation
obj.x = pos.x + offset.x;
obj.y = pos.y + offset.y;
obj.rotation = rotD;
Other useful functions:
public function degreesToRadians( deg:Number ):Number
{
return deg * ( Math.PI / 180.0 );
}
public function radiansToDegrees( rad:Number ):Number
{
return rad * ( 180.0 / Math.PI );
}
If you do it to give your sprites properties of physical objects, it can be easier to use physInjector for box2D:
http://www.emanueleferonato.com/2013/03/27/add-box2d-physics-to-your-projects-in-a-snap-with-physinjector/
It is free can do it in a couple of lines.

AS3 Rotate an object around its center point

I want this object to rotate around its center rather than the top left corner.
The code looks like this:
switch (event.keyCode)
{
case 37:
car.rotation = -90;
car.x -= 5;
break;
So when i press the left key, the car turns left but as it is now it jumps up a bit because its rotating around the top corner.
Thanks
The following will rotate around center :
public function rotateAroundCenter(object:DisplayObject, angleDegrees:Number):void {
if (object.rotation == angleDegrees) {
return;
}
var matrix:Matrix = object.transform.matrix;
var rect:Rectangle = object.getBounds(object.parent);
var centerX = rect.left + (rect.width / 2);
var centerY = rect.top + (rect.height / 2);
matrix.translate(-centerX, -centerY);
matrix.rotate((angleDegrees / 180) * Math.PI);
matrix.translate(centerX, centerY);
object.transform.matrix = matrix;
object.rotation = Math.round(object.rotation);
}
It translates the center of the object to 0,0 then rotate it and then translate it back.
The easiest way to accomplish this is to add your car sprite/movieclip onto another sprite, where the x and the y coordinates are half the width and height properties. If the car is drawn in adobe flash you can also drag it to the top left, so that the center point is in the middle.