I'm making an pool game with cocos2dx.
First, i setup the edgeBox with this parameters PhysicsMaterial(1.0f, 1.0f, 0.8f)
And then these 2 balls PhysicsMaterial(1.0f, 1.0f, 0.5f)
On the update function, i want slow down balls time by time without gravity (like making ground friction) by adding
physicsBody->setLinearDamping(0.3);
On the update function, i set the minimum velocity, if the velocity of each ball reaches lower than 15, reset velocity to 0,0
auto MV = 15;
auto v1 = player1->getPhysicsBody()->getVelocity();
auto v2 = player2->getPhysicsBody()->getVelocity();
if (v1.x > MV || v1.x < -MV ||
v1.y > MV || v1.y < -MV) {
} else if(v1 != Vec2(0,0)) {
player1->getPhysicsBody()->setVelocity(Vec2(0,0));
CCLOG("sx 1 : %f %f",v1.x,v1.y);
}
if (v2.x > MV || v2.x < -MV ||
v2.y > MV || v2.y < -MV) {
} else if(v2 != Vec2(0,0)) {
player2->getPhysicsBody()->setVelocity(Vec2(0,0));
CCLOG("sx 2 : %f %f",v2.x,v2.y);
}
Everything works fine except when the balls stand next to the wall or each other. I see the small blue glue to these objects, this is when the contact has been made.
And in these situation, i can't set the velocity to 0,0.
I think there is some kind of force constantly changing the velocity. You can see the image below to see the blue glue and keep setting velocity = 0.0 like forever.
Firstly reset forces before setting velocity to zero: player2->getPhysicsBody()->resetForces();
Also gravity can be a cause that bodies continue to move.
So you can set gravity to zero for whole physics world. For example:
auto scene = Scene::createWithPhysics();
scene->getPhysicsWorld()->setGravity(Vec2(0, 0));
or just for one particular body:
player2->getPhysicsBody()->setGravityEnable(false);
or you can customize velocity function:
#include "chipmunk.h"
cocos2d::PhysicsBody * pBody = player2->getPhysicsBody();
pBody->getCPBody()->velocity_func = customVelFunc;
where customVelFunc could be defined as:
void customVelFunc(cpBody *body, cpVect gravity, cpFloat damping, cpFloat dt)
{
cpBodyUpdateVelocity(body, cpvzero, damping, dt);
}
Related
I'm using Actionscript 3.0 in Flash. Is there a way to control the timeline with pinching (so instead of zooming out/in you are moving the timeline back/forth)? I'm working on an story app where the player is in control of the story.
You could do something like the following:
import flash.events.TransformGestureEvent;
Multitouch.inputMode = MultitouchInputMode.GESTURE;
stop();
//listen on whatever object you want to be able zoom on
stage.addEventListener(TransformGestureEvent.GESTURE_ZOOM , zoomGestureHandler);
function zoomGestureHandler(e:TransformGestureEvent):void{
//get the zoom amount (since the last event fired)
//we average the two dimensions (x/y). 1 would mean no change, .5 would be half the size as before, 2 would twice the size etc.
var scaleAmount:Number = (e.scaleX + e.scaleY) * 0.5;
//set the value (how many frames) to skip ahead/back
//we want the value to be at least 1, so we use Math.max - which returns whichever value is hight
//we need a whole number, so we use Math.round to round the value of scaleAmount
//I'm multiplying scaleAmount by 1.25 to make the output potentially go a bit higher, tweak that until you get a good feel.
var val:int = Math.max(1, Math.round(scaleAmount * 1.25));
//determine if the zoom is actually backwards (smaller than before)
if(scaleAmount < 1){
val *= -1; //times the value by -1 to make it a negative number
}
//now assign val to the actual target frame
val = this.currentFrame + val;
//check if the target frame is out of range (less than 0 or more than the total)
if(val < 1) val = this.totalFrames + val; //if less than one, add (the negative number) to the totalFrames value to loop backwards
if(val > this.totalFrames) val = val - this.totalFrames; //if more than total, loop back to the start by the difference
//OR
if(val < 1) val = 0; //hard stop at the first frame (don't loop)
if(val > this.totalFrames) val = this.totalFrames; //hard stop at the last frame (don't loop)
//now move the playhead to the desired frame
gotoAndStop(val);
}
Currently I'm busy with Actionscript. I have a map with diverse worlds. If you click on an arrow icon you will scroll to the other world. The code is:
street.street_market.addEventListener(MouseEvent.CLICK, straat_actie2);
function straat_actie2(evt:MouseEvent) {
market.bringToFront();
MovieClip(root).worldmap.targetX = marktx;
MovieClip(root).worldmap.targetY = markty;
old = "street";
new = "market";
addEventListener(Event.ENTER_FRAME, fade);
}
The worlds are sliding to each other and the other one is fading out. It works like this:
addEventListener(Event.ENTER_FRAME, ballEnterFrame)
function ballEnterFrame (pEvent):void
{
var b = pEvent.currentTarget;
b.x += (b.targetX - b.x) / 16;
b.y += (b.targetY - b.y) / 16;
}
function fade(e:Event)
{
if(new != "")
{
this[new].alpha+=0.03;
if(this[old].alpha >= 0.2)
{
this[old].alpha-=0.05;
}
}
}
It all works fine. Except one thing. The longer you stay on a world map the longer it will take to let the other world fade out. So if I stay on the street map for 10 secs and I scroll to the next one it takes around 10 seconds before the old map fades out.
Does someone know how I can solve this problem?
Thanks.
Try setting up your function like this...
function fade(e:Event)
{
if( new != "")
{
//# add : ONLY if less than 1 (full opacity)
if ( this[new].alpha < 1 )
{ this[new].alpha += 0.03; } //# fade in (increase)
//# minus : if NOT 0 -OR- is NOT less than 0 (transparent)
if ( this[old].alpha != 0 || !( this[old].alpha < 0 ) )
{ this[old].alpha -= 0.05; } //# fade out (reduce)
//# clamp within limits of 0 to 1 range
if ( this[new].alpha > 1 ) { this[new].alpha = 1; } //# never higher than 1
if ( this[old].alpha < 0 ) { this[old].alpha = 0; } //# never less than 0
}
}//# end function fade
Explained :
...if I stay on the street map for 10 secs and I scroll to the next
one it takes around 10 seconds before the old map fades out.
Do you realise that ENTER_FRAME is something that happens every frame according to your SWF's frame rate (FPS)?. If you set 30 FPS in your Document settings, by your code you are adding 0.03 x 30 every second for 10 seconds. The .alpha amount rises higher than 1, now the delay is waiting for it to reduce from 9.0 back to 1 then it fades out as expected. There is no visual benefit to allowing alpha values to become anything higher than 1 or less than 0.
I am trying to rotate my sprite when i push to go left. right now my character is idling and running to the right. but im having trouble rotating to the left.
here is my chunk of code. if anyone could help me, that would be awesome.
public void draw(SpriteBatch spriteBatch) {
stateTime += Gdx.graphics.getDeltaTime();
//continue to keep looping
if(Gdx.input.isTouched()){
int xTouch = Gdx.input.getX();
int yTouch = Gdx.input.getY();
//System.out.println(Gdx.graphics.getWidth()/4);
//go left
if(xTouch < (width/4) && yTouch > height - (height/6)){
currentRunFrame = runAnimation.getKeyFrame(stateTime, true);
spriteBatch.draw(currentRunFrame, runSprite.getX() - 32, runSprite.getY() + 150, 128, 128);
RealGame.leftButton = new Texture(Gdx.files.internal("leftButtonOver.png"));
moveLeft();
}
if(xTouch > (width/4) && xTouch < (width/4)*2 && yTouch > height - (height/6)){
currentRunFrame = runAnimation.getKeyFrame(stateTime, true);
spriteBatch.draw(currentRunFrame, runSprite.getX() - 32, runSprite.getY() + 150, 128, 128);
RealGame.rightButton = new Texture(Gdx.files.internal("rightButtonOver.png"));
moveRight();
}
if(xTouch > (width/4) * 2 && xTouch < (width/4) * 3 && yTouch > height - (height/6)){
RealGame.shootButton = new Texture(Gdx.files.internal("shootButtonOver.png"));
}
if(xTouch > (width/4) * 3 && xTouch < (width/4) * 4 && yTouch > height - (height/6)){
RealGame.jumpButton = new Texture(Gdx.files.internal("jumpButtonOver.png"));
}
}
if(!Gdx.input.isTouched()){
currentIdleFrame = idleAnimation.getKeyFrame(stateTime, true);
spriteBatch.draw(currentIdleFrame, idleSprite.getX() - 32, idleSprite.getY() + 150, 128, 128);
RealGame.leftButton = new Texture(Gdx.files.internal("leftButton.png"));
RealGame.rightButton = new Texture(Gdx.files.internal("rightButton.png"));
RealGame.shootButton = new Texture(Gdx.files.internal("shootButton.png"));
RealGame.jumpButton = new Texture(Gdx.files.internal("jumpButton.png"));
moveStop();
}
}
thank you in advance, and let me know if you need more info.
I assume your currentIdleFrame is a Texture or TextureRegion, not a Sprite. One of SpriteBatchs draw methode with Texture supports a flipX and flipY. Using this you can flip him, for example if you are walking to the left, but your Texture is facing to the right. Also this supports rotation, which should be the rotation in degrees.
Verry important note: You create new Texture every render loop. Don't do this. Instead load all your Textures in a Texture[] frames and draw the right one, depending on stateTime. Also take a look at Animations class, which will help you with this.
Hope i could help
Use a SpriteBatch draw method that takes boolean flipX parameter or call flip on the Sprite.
Oh, and if this is your main loop, stop loading the textures like you are. Load them in the beginning and just swap them as needed.
I created a script that allows your character to move around with wall collision for every direction. How do I add gravity to it on the y-axis and still have it work the same way (like a platform game)?
I tried something like char.y-- when it hits the platform if it were just the floor, but all that does is slowly bring char up no matter where it is in the object, and once it reaches the top, it shakes like crazy.
A preview of the stage: http://puu.sh/63Y1g.png
//WALL COLLISION
if(walls.hitTestPoint(char.x-(char.width/2),char.y,true) && Key.isDown(Key.A)){
char.x+=5
}
if(walls.hitTestPoint(char.x+(char.width/2),char.y,true) && Key.isDown(Key.D)){
char.x-=5
}
if(walls.hitTestPoint(char.x,char.y-(char.height/2),true) && Key.isDown(Key.W)){
char.y+=5
}
if(walls.hitTestPoint(char.x,char.y+(char.height/2),true) && Key.isDown(Key.S)){
char.y-=5
}
//CHARACTER CONTROLS
char.x+=0;
if(Key.isDown(Key.A)){
char.x+=-5;
speed=-5;
}
if(Key.isDown(Key.D)){
char.x+=5;
speed=5;
}
if(Key.isDown(Key.W)){
char.y+=-5;
speed=5;
}
if(Key.isDown(Key.S)){
char.y+=5;
speed=5;
}
To do this really simply, something like this would suffice:
// Check if there is a floor below the char
if (!floor.hitTestPoint(char.x, char.y + (char.height/2) + 2 , true))
{
// If not, apply Gravity
char.y += 5
}
This will only apply gravity if there is no floor 2 pixels directly below the char (this will stop the jittering, feel free to try with different pixel offsets that might work better in your case), I wasn't sure how you were differentiating between the walls and floor, so replace 'floor' with how you are doing it.
===============
If you would like to add realistic accelerating gravity, you will need to add a variable to track the current vertical speed of the char, then add to that each step
eg. Each step do this instead of just adding to y
// Apply gravity
vSpeed += 5
char.y += vSpeed
But if you are going to do that you might as well start getting into vectors and more complex things, there's a lot of materials on the net for this.
ok so i have a character called character_mc and i want it to move towards the mouse when you press the forward arrow and strafe relative to right angles of that.
i am quite new to actionscript so could you please include and example of your code in my original code
Here is my current code:
import flash.events.MouseEvent;
//Event Listners
stage.addChild(crosshair_mc);
crosshair_mc.mouseEnabled = false;
crosshair_mc.addEventListener(Event.ENTER_FRAME, fl_CustomMouseCursor);
function fl_CustomMouseCursor(event:Event)
{
crosshair_mc.x = stage.mouseX;
crosshair_mc.y = stage.mouseY;
}
Mouse.hide();
stage.addEventListener(MouseEvent.MOUSE_MOVE,facecursor);
stage.addEventListener(KeyboardEvent.KEY_DOWN, fl_KeyboardDownHandler);
//Functions
function facecursor(event):void
{
character_mc.rotation = (180 * Math.atan2(mouseY - character_mc.y,mouseX - character_mc.x))/Math.PI + 90;
}
function fl_KeyboardDownHandler(event:KeyboardEvent):void
{
trace("Key Code Pressed: " + event.keyCode);
if (event.keyCode == 38)
{
character_mc.y = character_mc.y - 5;
}
if (event.keyCode == 40)
{
character_mc.y = character_mc.y + 5;
}
if (event.keyCode == 39)
{
character_mc.x = character_mc.x + 5;
}
if (event.keyCode == 37)
{
character_mc.x = character_mc.x - 5;
}
}
I can tell you the basic concept of how you could do this, but you'll have to apply it to your own code. To involves converting your movement code to use a vector, then modifying the vector to get a direction facing the mouse (or at right angles to that direction) and a little bit of math.
Right now you have the character moving straight along the x and y axis only in each key press case. Left/Right only move along the X and Up/Down only move along the Y.
To move towards the mouse will require the character to move both along the X and Y when the Up/Down/Left/Right keys are pressed. Clearly you can see if you move both the character's x/y positions by the same amount, say 5, then it'll move exactly at 45 degrees (though it'll actually move a step of 7.07 pixels, hopefully you can see why). You can represent this as a vector: (5,5). You can use a Point object to represent this vector:
var movementVector:Point = new Point(5, 5);
trace(movementVector.x); // gives 5
trace(movementVector.y); // also gives 5
With that in mind, you can also use a vector to represent movement straight up and down on the y axis:
// set the x to 0 and y to 5
movementVector.x = 0; // 0 would mean not to move the character along the x
movementVector.y = 5; // using -5 would move the character up
And to move along the x axis only:
movementVector.x = 5; // using -5 would move the character right
movementVector.y = 0; // 0 would mean not to move the character along the y
To do the actual movement of the character would be the same as you are doing now, except you use the vector's values:
character_mc.x = character_mc.x + movementVector.x;
character_mc.y = character_mc.y + movementVector.y;
Now to figure out the proper vector to move on a diagonal from the character's position to the mouse position is pretty simple. The x value of the vector is the x distance from the character to the mouse, and the y value of the vector is the y distance from the character to the mouse.
Let's say the character is ay 125, 100 and the mouse at 225, 150. This means the distance between the character and mouse is 100, 50 x and y. Thus you'd end up with a vector:
movementVector.x = 100;
movementVector.y = 50;
If you were to apply this vector as it is to the character's position as it is, it would arrive at the mouse instantly (and then go beyond it) as the character is moving 100 pixels along the x and 50 pixels along the y right away. The step size would be 111.8 pixels long -too big. You would need to scale it down to the character's speed. You can do this by calling the normalise() method on the Point class to scale down the vector:
trace(movementVector.x); // gives 100
trace(movementVector.y); // gives 50
// assuming '5' is the max speed of the character
movementVector.normalise(5);
trace(movementVector.x); // gives 4.47213595499958
trace(movementVector.y); // gives 2.23606797749979
This would result in a 'step' size of 5 now. Applying this would make your character move 5 pixels towards a point 100 pixels to the right and 50 pixels down from where it started.
To transform a vector exactly 90 degrees, a quick and simple way is to swap the x and y values around.
If you are curious on what normalise() method mathematically does, is that it takes the x and y values of the vector (or point) and divides it by the length to get a unit vector (or a vector with a step size of 1), then times the input you give it to scale it to the desired length.
To move your character_mc towards the mouse point you only need the direction vector between the two:
var dir:Point = new Point(mouseX - character_mc.x, mouseY - character_mc.y);
dir.Normalize();
// The following should be called when the 'up' or 'forward' arrow is pressed
// to move the character closer to mouse point
character_mc.x += dir.x; // dir can be multiplied by a 'speed' variable
character_mc.y += dir.y;
Strafing left and right around the point is a little more tricky:
// Where radius is the distance between the character and the mouse
character_mc.x = mouseX + radius * Math.cos(rad);
character_mc.y = mouseY + radius * Math.sin(rad);
You should find this tutorial useful as it does everything you describe and more:
http://active.tutsplus.com/tutorials/actionscript/circular-motion-in-as3-make-one-moving-object-orbit-another/