I have a pirate ship, which has cannons, which work when the ship isn't rotated but when it is they stay (as expected) at 0 degrees. I need them to rotate around the center of the pirate ship when it rotates, so they are still in line with the cannons on the image of the ship. Put simply, what I need is this:
Cannons to stay the same rotation relative to the ship (as shown in the picture captioned "What I want"
Cannons to stay the same position relative to the ship when it moves
The cannons have a Vector2 in them named forwardDirection and I need this to always point the same direction relative to the ship
For the position and rotation, It should be the same as in Unity 3D & other game engines when you parent something to something else, as in it is always the same relative position and rotation to the parent.
I have absolutely no idea on how to do this, so I need help. Also this explanation might not be clear so if theres anything which doesn't make sense then comment it and I'll change it so it does.
Let's assume you have 10 cannons and each cannon is stored as an object in a List.
For sake of ease let's say cannon1 is List.get(0) (getting first cannon)
float newX = calculateDistanceX(ship.velocity, cannon1.currentAngle) + cannon1.xPosition;
float newY = calculateDistanceY(ship.velocity, cannon1.currentAngle) + cannon1.yPosition;
cannon1.setX(newX);
cannon1.setY(newY);
/**
* Calculates the offset which needs to be added to the X position according
* to the angle .
*
* #param velocity
* The velocity
* #param angle
* The angle
* #return The offset which needs to be added
*/
protected float calculateDistanceX(float velocity, float angle) {
return velocity * MathUtils.cos(MathUtils.degreesToRadians * angle);
}
/**
* Calculates the offset which needs to be added to the Y position according
* to the angle.
*
* #param velocity
* The velocity
* #param angle
* The angle
* #return The offset which needs to be added
*/
protected float calculateDistanceY(float velocity, float angle) {
return velocity * MathUtils.sin(MathUtils.degreesToRadians * angle);
}
Now this way you will be able to move your cannon with the ship. This formula will change the location of your cannon when you move your ship up and down. Do this for all your cannons and you will get their locations.
There may be better way to do this, but this is how I do in my game and it works for a single cannon perfectly.
Hope this gives you a basic idea of how to approach the problem. (The math bit of it, is basically resolving sin and cos components i.e. basic physics)
Related
I have composited my sprites to build a monster truck with customizable bumpers, cabs, spoilers wheels etc. The class that holds these Sprites is MTruck and I can draw it perfectly provided I stay with scale 1.0.
mWheels.setPosition(posX + 17 * scale, posY);
mCab.setPosition(posX + 22 * scale, posY + 7 * scale);
mFender.setPosition(posX, posY + 75 * scale);
mWheels is positioned at the y origin of the Truck and mFender at the x origin.
I've tried all sorts of values for scale and extracting it separate from the scale I apply to mWheels, mCab etc but all that happens is the sprites scale but their positions become misaligned.
I'm going to have to render to a texture and scale that as I whole if I can't crack this.
perhaps, Set origin could help you:
void setOrigin(float originX, float originY)
Sets the origin in relation to the sprite's position for scaling and
rotation.
float getOriginX()
The origin influences setPosition(float, float),
setRotation(float) and the expansion direction
of scaling setScale(float, float)
float getOriginY()
The origin influences setPosition(float, float),
setRotation(float) and the expansion direction of
scaling setScale(float, float)
http://libgdx.badlogicgames.com/nightlies/docs/api/com/badlogic/gdx/graphics/g2d/Sprite.html
NEW EDIT: maybe if you are customizing the vehicle on a menu for example, as is practicable after this the customized vehicle and create an image at runtime, and scale, an use this image in Sprite, for maybe it's easier, but it's just an idea
I am trying to make an actor follow the player's finger (long touch). I'm positive I have the math right, but the actor fails to move exactly to where the player touched.
Here is an illustration of my problem:
When the touch is near the top, the actor goes beyond the visible scene at the top.
When the touch is near the bottom, the actor goes out of the visible scene at the bottom.
Same goes for the left and right.
When the touch is performed in the middle of the scene the actor moves perfectly to the touch. In short, the further the touch is away from the middle the more pronounced the distance between the actor and the touch is. In other words; the closer the touch is to the middle, the closer the actor moves towards the touch.
Please note that when the touch was near the bottom or the top the distance between the touch and the actor was more pronounced then when the touch was on the right or the left; as the top/bottom are further from the mid point.
Here is the code used to follow the actor towards the touch:
Lang: Lua
Lib: Cocosd2-x 3.1
local velocity = 1.4
local x, y = self.sprite:getPosition()
-- self.dest[X/Y] are cached coordinates to where the actor should move next.
local angle = math.atan2(touch.y - y, touch.x - x)
local deltaX = velocity * math.cos(angle)
local deltaY = velocity * math.sin(angle)
local newX = x + deltaX
local newY = y + deltaY
self.sprite:setPositionX(newX)
self.sprite:setPositionY(newY)
Things I've tried:
Changed the scale of background layer and sprites. No change
Changed the algorithm used to compute the angle. No change.
Created a red dot and set its position to the exact touch x/y to determine if there was some weird transformation issue when determining the actor's point. The red dot was always perfectly under the touch.
Discovered the issue. When I created the Actor sprite I set its z-index to 100. When I uncommented out the call that set the z-index, everything worked perfectly. In my situation, this particular sprite must always be above all other sprites. What I did to fix the issue is set the z-index much lower than what I had originally set it to; which ended up being 15.
sprite:setPositionZ(15)
From my observation it appears that the sprite is having some type of scale applied to its position the larger the z-index is of the sprite.
Update 1
Using :setPositionZ(int) will unnecessarily scale your sprite bigger in some cases. I now use :setGlobalZOrder(int) with much better success:
sprite:setGlobalZOrder(15)
To detect when 1 image is within range of another image on the canvas I do:
if (herohitboxX <= (villageMain.x + 200) && villageMain.x <= (herohitboxX) && herohitboxY <= (villageMain.y + 200) && villageMain.y <= (herohitboxY) ) { console.log('inside bldg') }
which works great but I'm having a huge problem figuring out how to not let the player walk into the building/tree/object, but while letting them still move away from the object.
I can make the player slide through the object by moving them while touching, and block them from coming back from that 1 direction, but I can't block movement from all 4 sides....
The main problem is it only detects if they're overlapping, but it doesn't tell you what direction the player was coming from. Simply negating the players movement direction when they're inside the building didn't work(if they're pressing right and touching object, go left, else if they're not touching and pressing right, go right). Or if they were walking UP and touch the building, send DOWN. Shouldn't that work????
The only thing I can think of is to do 4 thin rectangles/lines representing each side of the perimeter, then just not allowing movement from the direction it's facing. But there has to be some easier way! What is it?
Store previous location and make a comparison?? Right now there isn't really a movement direction to look to, if you UP is detected in key listener, it moves the background image and adjusts the players sprite position. Any tips?
Presumably this code happens during the player moving or trying to move.
Determine the center of both objects. If the player's center is attempting to move away from the other object's center, allow the move to take place even though they intersect.
If not, stop the move.
Put another way, you have player's center and object's center. This makes line1.
And you have a move command that would create a potential new place for the player's center (the old location plus some direction). Calculate this to get line2.
Now if the second line is longer than the first line, that means the player is moving away from the intersecting object and so it should be allowed. Maybe they are up against an object on their right and they want to move up or left. Both of these make line2 longer than line1.
It should only be blocked if the player is attempting to make the line shorter (by moving directly towards the object).
tips for lines
Suppose the player's center was px, py and suppose the object's center is ox, oy. Then the distance between them is:
var dx = px - ox;
var dy = py - oy;
var dist = Math.sqrt(dx * dx + dy * dy);
But there's something funny here. We don't actually need to know the distance, we just need to compare it to another distance. This means we can skip the (potentially slow) Math.sqrt call, and compared the squared distance of line1 to the squared distance of line2. So here's line1:
var dx = px - ox;
var dy = py - oy;
var line1 = dx * dx + dy * dy;
And for line2 we need to know where the player would be if the move command was successful, we call that newpx, newpy.
var dx2 = newpx - ox;
var dy2 = newpy - oy;
var line2 = dx2 * dx2 + dy2 * dy2;
So if line2 > line1, allow the move! Otherwise, block the move from occurring.
note that all of this assumes that the player can only move in one cardinal direction at a time (up, down, left, right) and not up-right. If that is the case you'll have to be a little more careful.
I have made a Car Game using Box2D [in Flash] and I have one remaining bug, which I cannot fix. I added graphics and put them on top of the Box2D body. Everything went as good as expected, but after X rotations the movie clips for the car-wheels, stop spinning. I do something like this wheelSprite.rotation = wheelBody.GetAngle() * 180 / Math.PI. I ran a separate program and I saw that, if you do X.rotation += variable and you increase the variable every frame, after ~30 000 (value of variable) the MovieClip stops rotating, so I reset it to 0 after ~28 000. What do I do? The wheelBody.GetAngle() keeps going up, and I need it to make it look real. How do I reset it?
I faced this problem some time ago. The solution was:
rotation = newRotation % 2*Math.PI;
Which means that rotation must be between 0 and 360 degrees (0 - 2*PI).
Remainder solve this issue:
yourMC.rotation = (yourMCbody.GetAngle() * 180 / Math.PI) % 360;
http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/operators.html#modulo
Can't you use the SetAngle() function to set the angle to an equivalent angle?
ie: If the angle rotates over 360 degrees, set it back to 0?
The Box2D manual specifies that the rotation of bodies is unbounded and may get big after awhile and that you can you can reset it using SetAngle.
I use a while loop to calculate the normalized angle (you can apparently call modulo with a floating point operand but I don't know if that is bad for performance). This code normalizes the angle to 0 <= angle < 2pi but I've seen angles sometimes normalized to -pi <= angle < pi as well.
const 2PI:Number = Math.PI * 2;
var rotation:Number = wheelBody.GetAngle();
// normalize angle
while(rotation >= 2PI)
rotation -= 2PI;
while(rotation < 0)
rotation += 2PI;
// store the normalized angle back into Box2D body so it doesn't overflow (optional)
wheelBody.SetAngle(rotation);
// convert to degrees and set rotation of flash sprite
wheelSprite.rotation = rotation * 180 / Math.PI;
I haven't collected the code into a function but it would be easy to do so.
I have a task:
I need to place about 100 sprites on one canvas (with prepared grid on it). I need to place them as invisible (circles) stones, on the board, and make visible only on mouseover.
The problem I come across is following, I can't place those objects accurately into the nodes on the grid.
E.g.
if I define stones (it's just a sprite, as I said earlier) this way:
var stone:StoneSprite = new StoneSprite();
stone.x = this.x + 2*cellWidth;
stone.graphics.beginFill( 0x000000 );
stone.graphics.drawCircle(stone.x , this.y + cellWidth, cellWidth/3 );
stone.graphics.endFill();
rawChildren.addChild(stone);
They don't sit on the node...
See image:
http://img.skitch.com/20091014-kuhfyjeg1g5qmrbyxbcerp4aya.png
And if I do it this way:
var stone:StoneSprite = new StoneSprite();
stone.graphics.beginFill( 0x000000 );
stone.graphics.drawCircle(this.x + 2*cellWidth , this.y + cellWidth, cellWidth/3 );
stone.graphics.endFill();
rawChildren.addChild(stone);
The stone is displayed correctly in the grid node... See image 2:
http://img.skitch.com/20091014-f595tksjxramt98s7yfye591bh.png
So I wonder what is the difference between these 2 approaches.
Also, I think I need to pass correct coordinates to the stone class... In case I would like to change some properties of the stone object. E.g. visibility, or radius.
Could you please suggest, what's wrong in defining coordinates as stone.x, stone.y
How to fix the problem with incorrect positioning.
Would really appreciate ideas about the problem, I am trying to solve for so long :(
Assume x & y are 30 and cellWidth is 30.
First Example:
stone.x = 30 + 60; //90
drawCircle(90, 60, 10);
This means if you were to draw a rectangle around your circle, it would be at [170,50]. (x,y).
Second Example:
stone.x = 0;
drawCircle(90, 60, 10)
This means the rectangle around your circle is at [80,50];
In the first example, you are moving the sprite to position x==90. Then drawing a circle whose center is at x==90 inside the sprite. So relative to this, you're at x==180. But because a circle's x,y coords are the center, subtract 10 for the radius to get the boundary x position.
In the second example, the sprite defaults to position x==0 relative to this and you're drawing the circle inside the sprite at position x==90. (therefore it begins at x==80).
I am not sure what's causing the issue - might be some padding induced by the container - can't say without testing. But I believe that adding a Sprite (say board) to canvas.rawChildren and using it as the parent for the grid and stones would fix the issue.