Ok, I have this ship object which the user controls using the arrow keys.
if (aCurrentKeyboardState.IsKeyDown(Keys.Left) == true)
mAngle -= 0.1f;
else if (aCurrentKeyboardState.IsKeyDown(Keys.Right) == true)
mAngle += 0.1f;
if (aCurrentKeyboardState.IsKeyDown(Keys.Up) == true)
{
// mSpeed.Y = SHIP_SPEED;
// mDirection.Y = MOVE_UP;
velocity.X = (float)Math.Cos(mAngle) * SHIP_SPEED;
velocity.Y = (float)Math.Sin(mAngle) * SHIP_SPEED;
}
else if (aCurrentKeyboardState.IsKeyDown(Keys.Down) == true)
{
mSpeed.Y = SHIP_SPEED;
mDirection.Y = MOVE_DOWN;
}
The following 2 methods are in another class.
//Update the Sprite and change it's position based on the passed in speed, direction and elapsed time.
public void Update(GameTime theGameTime, Vector2 velocity, float theAngle)
{
Position += velocity * (float)theGameTime.ElapsedGameTime.TotalSeconds;
shipRotation = theAngle;
}
//Draw the sprite to the screen
public void Draw(SpriteBatch theSpriteBatch)
{
Vector2 Origin = new Vector2(mSpriteTexture.Width / 2, mSpriteTexture.Height / 2);
theSpriteBatch.Draw(mSpriteTexture, Position, new Rectangle(0, 0, mSpriteTexture.Width, mSpriteTexture.Height),
Color.White, shipRotation, Origin, Scale, SpriteEffects.None, 0);
}
The problem is that: the program thinks the front of the ship is one of the side wings, so in a way it's going sideways when I press up. I don't know why this is.
Suggestions?
Easy, play around with these two lines:
velocity.X = (float)Math.Cos(mAngle) * SHIP_SPEED;
velocity.Y = (float)Math.Sin(mAngle) * SHIP_SPEED;
For example switch the sin and cos, and make one of them negative:
velocity.X = -(float)Math.Sin(mAngle) * SHIP_SPEED;
velocity.Y = (float)Math.Cos(mAngle) * SHIP_SPEED;
If it goes backward now, just switch the negative over:
velocity.X = (float)Math.Sin(mAngle) * SHIP_SPEED;
velocity.Y = -(float)Math.Cos(mAngle) * SHIP_SPEED;
If I understand your problem correctly, you could solve your problem just by rotating your ship texture. Just try adding 90 or -10 to your shipRotation in the Draw Method:
theSpriteBatch.Draw(mSpriteTexture, Position, new Rectangle(0, 0, mSpriteTexture.Width, mSpriteTexture.Height),
Color.White, shipRotation + 90, Origin, Scale, SpriteEffects.None, 0);
or
theSpriteBatch.Draw(mSpriteTexture, Position, new Rectangle(0, 0, mSpriteTexture.Width, mSpriteTexture.Height),
Color.White, shipRotation - 90, Origin, Scale, SpriteEffects.None, 0);
Hope that helps!
Then change your original sprite to match what your program "thinks" is the front of the ship.
Related
JavaCV ~ OpenCV
It is necessary to determine the direction of a person's movement (left or right) in real time. I use JavaCV. My code gives the correct answer only based on movement in ideal conditions (there are no shadows, the lighting does not change, the person does not change the trajectory of movement):
We place the found moving object in a green rectangle, calculate the sum of the centers of mass of all rectangles, calculate the difference between the centers of mass of the previous and current frames, keep statistics from a few comparisons (to reduce the probability of an error in the final result) and on its basis we make a verdict - moves to the right or to the left.
I found the function calcGlobalOrientation(), but I don't have an example of how to use it.
Perhaps someone will give advice on how to use JavaCV with a fairly high performance and low probability of error to determine the direction of movement of the object?
if (cnts.size() > 0) {
firstEntry = true;
center_current = newPoint();
for (int i = 0; i < cnts.size(); i++) {
//continue to work only with areas that satisfy the condition
if (contourArea(cnts.get(i)) < 2000) {
continue;
}
Rect r = boundingRect(cnts.get(i));
// check if the center of mass of the figure is in the "gray" area
if (
isInside(r.x() + r.width() / 2, r.y() + r.height() / 2, getArrayGrayZone().get(0)) ||
isInside(r.x() + r.width() / 2, r.y() + r.height() / 2, getArrayGrayZone().get(1))
) {
// System.out.println("Movement in the \"grey\" zone");
continue;
}
//4th parameter - characterization of the contour of the figure ("< 0" the figure is filled, "> 0" the line thickness)
rectangle(frame, r, new Scalar(0, 255, 0, 0), 3, 0, 0);
if (firstEntry) {
//+1 frame with recognized motion that satisfies the condition
counterFrame++;
firstEntry = false;
}
//look for the center of mass of the given rectangle
center = newPoint();
center.x = r.x() + r.width() / 2;
center.y = r.y() + r.height() / 2;
//if the current center of mass has not yet been calculated, then enter a new value
if (center_current.x == 0) {
center_current = center;
continue;
}
//calculate the common center of mass of the current and past rectangles
center_current.x = (center_current.x + center.x) / 2;
center_current.y = (center_current.y + center.y) / 2;
}
//if it was possible to calculate the current center of mass of the rectangles
if (center_current.x != 0) {
//if the previous center of mass has not yet been calculated, then equalize the current and previous
if (center_prev.x == 0) {
center_prev = center_current;
} else {
difference = new Vec2d(center_current.x - center_prev.x, center_current.y - center_prev.y);
if (difference.x < 0) {
indexL++;
}
if (difference.x > 0) {
indexR++;
}
}
}
}
if (counterFrame % 10 == 0 && counterFrame > 0) {
if (indexR > indexL) {
System.out.println(
"Right" + df.format(new Date()));
}
if (indexL > indexR) {
System.out.println(
"Left" + df.format(new Date()));
}
//reset the counter of frames with a recognized motion that satisfies the condition
counterFrame = 0;
//reset the "statistical" variables for detecting shift to the right or left
indexL = indexR = 0;
}
//make current center of mass "previous"
center_prev = center_current;
For a voxel art app, the goal is to let users move and rotate a camera in a SceneKit scene then tap to place a block.
The code below lets a user rotate a camera by panning. After the gesture ends, we move an existing block so it is -X units on the camera's Z-axis (i.e., -X units in front of the camera).
cameraNode is the scene's point of view and is a child of userNode. When the user moves a joystick, we update the position of userNode.
Question: Other SO posts manipulate camera nodes by applying a transform instead of changing the rotation and position properties. Is one approach better than the other?
func sceneViewPannedOneFinger(sender: UIPanGestureRecognizer) {
// Get pan distance & convert to radians
let translation = sender.translationInView(sender.view!)
var xRadians = GLKMathDegreesToRadians(Float(translation.x))
var yRadians = GLKMathDegreesToRadians(Float(translation.y))
// Get x & y radians
xRadians = (xRadians / 6) + curXRadians
yRadians = (yRadians / 6) + curYRadians
// Limit yRadians to prevent rotating 360 degrees vertically
yRadians = max(Float(-M_PI_2), min(Float(M_PI_2), yRadians))
// Set rotation values to avoid Gimbal Lock
cameraNode.rotation = SCNVector4(x: 1, y: 0, z: 0, w: yRadians)
userNode.rotation = SCNVector4(x: 0, y: 1, z: 0, w: xRadians)
// Save value for next rotation
if sender.state == UIGestureRecognizerState.Ended {
curXRadians = xRadians
curYRadians = yRadians
}
// Set preview block
setPreviewBlock()
}
private func setPreviewBlock(var futurePosition: SCNVector3 = SCNVector3Zero, reach: Float = 8) -> SCNVector3 {
// Get future position
if SCNVector3EqualToVector3(futurePosition, SCNVector3Zero) {
futurePosition = userNode.position
}
// Get current position after accounting for rotations
let hAngle = Float(cameraNode.rotation.w * cameraNode.rotation.x)
let vAngle = Float(userNode.rotation.w * userNode.rotation.y)
var position = getSphericalCoords(hAngle, t: vAngle, r: reach)
position += userNode.position
// Snap position to grid
position = position.rounded()
// Ensure preview block never dips below floor
position.y = max(0, position.y)
// Return if snapped position hasn't changed
if SCNVector3EqualToVector3(position, previewBlock.position) {
return position
}
// If here, animate preview block to new position
SCNTransaction.begin()
SCNTransaction.setAnimationDuration(AnimationTime)
previewBlock.position = position
SCNTransaction.commit()
// Return position
return position
}
func getSphericalCoords(s: Float, t: Float, r: Float) -> SCNVector3 {
return SCNVector3(-(cos(s) * sin(t) * r),
sin(s) * r,
-(cos(s) * cos(t) * r))
}
I am creating a game that has 3 layers of background. They are added to a CCParallaxNode and it's moved by tilting the device to the right, left, up and down. I am using this code to move the CCParallaxNode (accelerometer delegate method - didAccelerate):
void SelectScreen::didAccelerate(cocos2d::CCAcceleration *pAccelerationValue)
{
float deceleration = 0.1f, sensitivity = 30.0f, maxVelocity = 200;
accelX = pAccelerationValue->x * sensitivity;
accelY = pAccelerationValue->z * sensitivity;
parallaxMovementX = parallaxMovementX * deceleration + pAccelerationValue->x * sensitivity;
parallaxMovementX = fmaxf(fminf(parallaxMovementX, maxVelocity), -maxVelocity);
float offset = -calibration * sensitivity;
parallaxMovementY = (parallaxMovementY * deceleration + pAccelerationValue->z * sensitivity) + offset;
}
Then, in the update method:
void SelectScreen::update(float dt)
{
CCNode* node = getChildByTag(100);
float maxX = (Data::getInstance()->getWinSize().width * 2) + 100;
float minX = node->getContentSize().width - 100;
float maxY = Data::getInstance()->getWinSize().height * 0.1f;
float minY = -200;
float diffX = parallaxMovementX;
float diffY = parallaxMovementY;
float newX = node->getPositionX() + diffX;
float newY = node->getPositionY() + diffY;
newX = MIN(MAX(newX, minX), maxX);
newY = MIN(MAX(newY, minY), maxY);
if(isUpdating)
node->setPositionX(newX);
if(isUpdatingY)
node->setPositionY(newY);
}
The movement is nicely done, however, when reaching any of the 4 edges it stops abruptly. Also, when changing direction (eg. moving to the right then moving to the left) it does it abruptly.
Question: How can I do a smooth stop and a smooth direction change (maybe some little bouncing effect)? I think this is also related to the accelerometer data (when going fast it must bounce longer that it should when going slow).
Thanks in advance.
You need some math to smooth the movements.
Try checking the code here:
http://www.nscodecenter.com/preguntas/10768/3d-parallax-con-accelerometer
Im wondering at my setting ball.position function, the point is to set ball's point to other spritenode(in left/middle/right side), i tried to write my own function, but it was full of bugs, (it's commented), next after review developer lib's. I found anchorPoint to parent position, but it's not working, i dont know exactly how to set current parent for ball. I'll be really grateful for some advices.
if (ball.position.y < block.position.y +10 && ball.position.y > block.position.y -10) {
midX = CGRectGetMidX(self.frame);
side = block1.size.width/2;
if (emitter.position.x < midX - side+5) {
// fixedEmitterPos = emitter.position.x+side;
ball.anchorPoint = CGPointMake(0,0.5);
}
if (emitter.position.x > midX + side-5){
// fixedEmitterPos = emitter.position.x-side;
ball.anchorPoint = CGPointMake(1,0.5);
}
if (emitter.position.x == 160) {
// fixedEmitterPos = emitter.position.x;
ball.anchorPoint = CGPointMake(0.5,0.5);
}
}
I don't know what exactly is your question but to change your anchor point you don't change anything in parent node. For example if anchor point is
ball.anchorPoint = CGPointMake(0.5,0.5);
the anchor point in exactly in the middle and if you change position of the ball like:
ball.position == CGPointMake(50,50);
the ball center will be exactly in that point (50, 50).
but if the anchor point will be:
ball.anchorPoint = CGPointMake(1, 1);
and you change the position to :
ball.position == CGPointMake(50,50);
the ball centre will be in
X = 50 - (ball width / 2)
Y = 50 - (ball height / 2)
If you want to set up ball position base on other sprite node you can do something like that:
//Attach left centre side of ball to other sprite:
ball.anchorPoint = CGPointMake(0, 0.5);
ball.position.x == otherSprit.position.x + otherSprit.size.with;
ball.position.y == otherSprit.position.y;
//Attach right centre side of ball to other sprite:
ball.anchorPoint = CGPointMake(1, 0.5);
ball.position.x == otherSprit.position.x;
ball.position.y == otherSprit.position.y;
Hope this is what you are about.
I have a texture that follows a user's finger in GLKit. I calculate the radian to draw the angle at using arctan between the two points.
Part of the trick here is to keep the object centered underfed the finger. So i have introduced the idea of an anchor point so that things can be drawn relative to their origin or center. My goal is to move the sprite into place and then rotate. I have the following code in my renderer.
// lets adjust for our location based on our anchor point.
GLKVector2 adjustment = GLKVector2Make(self.spriteSize.width * self.anchorPoint.x,
self.spriteSize.height * self.anchorPoint.y);
GLKVector2 adjustedPosition = GLKVector2Subtract(self.position, adjustment);
GLKMatrix4 modelMatrix = GLKMatrix4Multiply(GLKMatrix4MakeTranslation(adjustedPosition.x, adjustedPosition.y, 1.0), GLKMatrix4MakeScale(adjustedScale.x, adjustedScale.y, 1));
modelMatrix = GLKMatrix4Rotate(modelMatrix, self.rotation, 0, 0, 1);
effect.transform.modelviewMatrix = modelMatrix;
effect.transform.projectionMatrix = scene.projection;
One other note is that my sprite is on a texture alias. If i take out my rotation my sprite draws correctly centered under my finger. My project matrix is GLKMatrix4MakeOrtho(0, CGRectGetWidth(self.frame), CGRectGetHeight(self.frame), 0, 1, -1); so it matches the UIkit and the view its embedded in.
I ended up having to add a little more math to calculate additional offsets before i rotate.
// lets adjust for our location based on our anchor point.
GLKVector2 adjustment = GLKVector2Make(self.spriteSize.width * self.anchorPoint.x,
self.spriteSize.height * self.anchorPoint.y);
// we need to further adjust based on our so we can calucate the adjust based on our anchor point in our image.
GLKVector2 angleAdjustment;
angleAdjustment.x = adjustment.x * cos(self.rotation) - adjustment.y * sin(self.rotation);
angleAdjustment.y = adjustment.x * sin(self.rotation) + adjustment.y * cos(self.rotation);
// now create our real position.
GLKVector2 adjustedPosition = GLKVector2Subtract(self.position, angleAdjustment);
GLKMatrix4 modelMatrix = GLKMatrix4Multiply(GLKMatrix4MakeTranslation(adjustedPosition.x, adjustedPosition.y, 1.0), GLKMatrix4MakeScale(adjustedScale.x, adjustedScale.y, 1));
modelMatrix = GLKMatrix4Rotate(modelMatrix, self.rotation, 0, 0, 1);
This will create an additional adjustment based on where in the image we want to rotate and then transform based on that. This works like a charm..
There is a similar code I used to rotate a sprite around its center
First you move it to the position, then you rotate it, then you move it back halfsprite
- (GLKMatrix4) modelMatrix {
GLKMatrix4 modelMatrix = GLKMatrix4Identity;
float radians = GLKMathDegreesToRadians(self.rotation);
modelMatrix = GLKMatrix4Multiply(
GLKMatrix4Translate(modelMatrix, self.position.x , self.position.y , 0),
GLKMatrix4MakeRotation(radians, 0, 0, 1));
modelMatrix = GLKMatrix4Translate(modelMatrix, -self.contentSize.height/2, -self.contentSize.width/2 , 0);
return modelMatrix;
}