so I use the accelerometer in cocos2d to rotate my sprite but the rotation isn't smooth at all . I know that I have to use filter but I don't know how to integrate it in my code :
-(id) init
{
self.isAccelerometerEnabled = YES;
[[UIAccelerometer sharedAccelerometer] setUpdateInterval:1/60];
}
- (void) accelerometer:(UIAccelerometer *)accelerometer didAccelerate:(UIAcceleration *)acceleration {
ombreoeuf1.rotation = acceleration.y * 90 ;
}
sorry for my english I'm french :/
Here's how to implement a lowpass filter. Experiment a bit with kFilteringFactor until you get nice results.
// Declare an int `accelY` in your class interface and set it to 0 in init
-(void) accelerometer:(UIAccelerometer *)accelerometer didAccelerate:(UIAcceleration *)acceleration {
float kFilteringFactor = 0.1;
accelY = (acceleration.y * kFilteringFactor) + (accelY * (1.0 - kFilteringFactor));
ombreoeuf1.rotation = accelY * 90;
}
One thing that might help You with the smoothness is to set the update interval to 30 fps instead of 60, so update your init to:
-(id) init
{
self.isAccelerometerEnabled = YES;
[[UIAccelerometer sharedAccelerometer] setUpdateInterval:1.0/30];
}
Related
So, I have built a simple car game, and have attached a script that allows it to move on both axes. I have created an animation, so that if the car turns upside down, there is an option to press the 'f' button and flip the car back to normal. Unfortunately, once the animation plays and the car flips back onto it's wheels, the car moves forwards and backwards, but doesn't rotate.
What could be the issue?
Here is the script:
var speed : float = 10.0;
var rotationSpeed : float = 100.0;
var CarFlip : Animator;
function Start () {
CarFlip.enabled = false;
}
function Update () {
var translation : float = Input.GetAxis ("Vertical") * speed;
var rotation : float = Input.GetAxis ("Horizontal") * rotationSpeed;
translation *= Time.deltaTime;
rotation *= Time.deltaTime;
transform.Translate (0, 0, translation);
transform.Rotate (0, rotation, 0);
if(Input.GetKeyUp(KeyCode.F)){
CarFlip.enabled = true;
}
if(Input.GetKeyDown(KeyCode.B)){
speed = 30;
}
if(Input.GetKeyUp(KeyCode.B)){
speed = 15;
}
}
The Animator updates the transforms every frame so your change in Update() is being over-written.
If you want to override what it has done you need to apply your changes during LateUpdate().
I think the animator is still enabled making the rotation stuck. Maybe try something like this as a test to see if setting animator to false will get the car rotating again:
if(Input.GetKeyDown(KeyCode.F))
{
CarFlip.enabled = true;
}
if(Input.GetKeyUp(KeyCode.F))
{
CarFlip.enabled = false;
}
I need to implement a custom shader node using SpriteKit.
In simulator everything is ok. On a device (iPad 3rd gen) shader animation is smooth just for first ~30 seconds, after that shader's fps are gradually falling down until it looks like a slideshow (1 fps or even less)
It is worth noting, that SpriteKit shows 60 fps, so does Xcode.
CPU is ~75% busy, but shader itself shows ~1fps.
I own only 3rd generation iPad and I currently don't have an opportunity to test it on other devices
Shader code is taken from wwdc session, but the issue is reproduced with any animated shaders I've tried.
Shader itself:
void main(void)
{
float currTime = u_time;
vec2 uv = v_tex_coord;
vec2 circleCenter = vec2(0.5, 0.5);
vec3 circleColor = vec3(0.8, 0.5, 0.7);
vec3 posColor = vec3(uv, 0.5+0.5 * sin(currTime)) * circleColor;
float illu = pow(1. - distance(uv, circleCenter), 4.) * 1.2;
illu *= (2. + abs(0.4 + cos(currTime * -20. + 50. * distance(uv, circleCenter))/1.5));
gl_FragColor = vec4(posColor * illu * 2.0, illu * 2.0);
}
GameScene:
import SpriteKit
class GameScene: SKScene {
override func didMoveToView(view: SKView) {
addChild(shaderSprite(view.center))
}
func shaderSprite(position: CGPoint) -> SKSpriteNode {
let sprite = SKSpriteNode(texture: SKTexture(imageNamed: "dummy"), color: nil, size: CGSizeMake(100, 100))
sprite.shader = SKShader(fileNamed: "wwdc")
sprite.position = position
return sprite
}
}
Result in simulator or first ~30 seconds on iPad3:
Result on iPad3 after ~2 minutes:
Please point my mistake or just build the project on any other device to check if it's a device-specific issue. Thanks in advance.
Test project: https://github.com/alexburtnik/SKShaderTest
This is an issue with the u_time uniform, I got around it by adding my own uniform float and using it instead of using u_time
Shader
void main(void)
{
float currTime = myUniform;
...
}
Update
override func update(currentTime: CFTimeInterval) {
let shadedNode = self.childNodeWithName("shadedNode") as SKSpriteNode
let uniform = shadedNode.shader!.uniformNamed("myUniform")
uniform!.floatValue = Float(currentTime)
}
Gelan Almagro's answer above works perfectly. I'm adding the Objective-C code for the update: method.
SKSpriteNode *shadedNode = (SKSpriteNode*)[self childNodeWithName:#"shadedNode"];
SKUniform *uniform = [shadedNode.shader uniformNamed:#"myUniform"];
uniform.floatValue = (float)currentTime;
Okay, so i'm fairly new to SpriteKit, but so far it's been a lot of fun working with it. I'm looking for a way to have a large scrolling background loop endlessly. I've divided my background into small chunks to let SK call as it needs them, using this code:
for (int nodeCount = 0; nodeCount < 50; nodeCount ++) {
NSString *backgroundImageName = [NSString stringWithFormat:#"Sky_%02d.gif", nodeCount +1];
SKSpriteNode *node = [SKSpriteNode spriteNodeWithImageNamed:backgroundImageName];
node.xScale = 0.5;
node.yScale = 0.5;
node.anchorPoint = CGPointMake(0.0f, 0.5f);
node.position = CGPointMake(nodeCount * node.size.width, self.frame.size.height/2);
node.name = #"skyBG";
and I'm able to move this whole block just fine in update, but I can't get it to loop seamlessly. or at all, for that matter. I've tried the method suggested elsewhere on here that takes a copy of the background and takes it to the other end to give the appearance of a seamless loop, and no dice here. I've also tried adding this to the end of the above code, which I had hoped might work:
if (nodeCount == 49)
{
nodeCount = 0;
}
but that just cause the simulator to hang, so I assume it's inadvertently creating a loop or something. Any assistance at all would be great! I feel like there's a simple fix, but I'm just not getting there... thanks a bunch, folks!
UPDATE
here's the code I'm currently using to get the background to scroll, which works just fine:
-(void)update:(CFTimeInterval)currentTime {
_backgroundNode.position = CGPointMake(_backgroundNode.position.x - 1, _backgroundNode.position.y);
}
So to sum up: I have a moving background, but getting it to loop seamlessly has been challenging because of the size of the background. If there's anything at all I can do to help clarify, let me know! Thanks a bunch
This is just an example of the logic you can employ to achieve a scrolling background. It is by no means a final or ideal implementation, but rather a conceptual example.
Here is a simple scroller class :
// Scroller.h
#import <SpriteKit/SpriteKit.h>
#interface Scroller : SKNode
{
// instance variables
NSMutableArray *tiles; // array for your tiles
CGSize tileSize; // size of your screen tiles
float scrollSpeed; // speed in pixels per second
}
// methods
-(void)addTiles:(NSMutableArray *)newTiles;
-(void)initScrollerWithTileSize:(CGSize)scrollerTileSize scrollerSpeed:(float)scrollerSpeed;
-(void)update:(float)elapsedTime;
#end
Implementation :
// Scroller.m
#import "Scroller.h"
#implementation Scroller
-(instancetype)init
{
if (self = [super init])
{
tiles = [NSMutableArray array];
}
return self;
}
-(void)addTiles:(NSMutableArray *)newTiles
{
[tiles addObjectsFromArray:newTiles];
}
-(void)initScrollerWithTileSize:(CGSize)scrollerTileSize scrollerSpeed:(float)scrollerSpeed
{
// set properties
scrollSpeed = scrollerSpeed;
tileSize = scrollerTileSize;
// set initial locations of tile and set their size
for (int index = 0; index < tiles.count; index++)
{
SKSpriteNode *tile = tiles[index];
//set anchorPoint to bottom left
tile.anchorPoint = CGPointMake(0, 0);
// set tilesize
// this implementation requires uniform size
[tile setSize:tileSize];
//calcuate and set initial position of tile
float startX = index * tileSize.width;
tile.position = CGPointMake(startX, 0);
//add child to the display list
[self addChild:tile];
}
}
-(void)update:(float)elapsedTime
{
//calculate speed for this frame
float curSpeed = scrollSpeed * elapsedTime;
// iterate through your screen tiles
for (int index = 0; index < tiles.count; index++)
{
SKSpriteNode *tile = tiles[index];
// set new x location for tile
tile.position = CGPointMake(tile.position.x - curSpeed, 0);
// if new location is off the screen, move it to the far right
if (tile.position.x < -tileSize.width)
{
// calculate the new x position based on number of tiles an tile width
float newX = (tiles.count -1) * tileSize.width;
// set it's new position
tile.position = CGPointMake(newX, 0);
}
}
}
In your scene , init your scroller :
-(void)initScroller
{
// create an array of all your textures
NSMutableArray *tiles = [NSMutableArray array];
[tiles addObject:[SKSpriteNode spriteNodeWithTexture:skyTexture]];
[tiles addObject:[SKSpriteNode spriteNodeWithTexture:skyTexture]];
[tiles addObject:[SKSpriteNode spriteNodeWithTexture:skyTexture]];
[tiles addObject:[SKSpriteNode spriteNodeWithTexture:skyTexture]];
// create scroller instance (ivar or property of scene)
scroller = [[Scroller alloc]init];
// add the tiles to the scroller
[scroller addTiles:tiles];
// init the scroller with desired tile size and scroller speed
[scroller initScrollerWithTileSize:CGSizeMake(1024, 768) scrollerSpeed:500];
// add scroller to the scene
[self addChild:scroller];
}
In your scene update method :
-(void)update:(CFTimeInterval)currentTime
{
float elapsedTime = .0166; // set to .033 if you are locking to 30fps
// call the scroller update method
[scroller update:elapsedTime];
}
Again, this implementation is very barebones and is a conceptual example.
I am currently working on a library for a tile scroller, is using a solution similar to the one provided by prototypical, but using a Tableview datasource pattern to ask for the nodes. Take a look at it:
RPTileScroller
I take some effort to make it the most efficient possible, but mind I am not a game developer. I tried it with my iPhone 5 with random colors tiles of 10x10 pixels, and is running on a solid 60 fps.
I'm creating a simple side scroller with a couple people using Unity and am definitely a beginner. The character being used is 3D and runs forward well, but when running backwards he still faces forward. I have the controls setup in the InputManager so pressing A moves backwards and D moves forward but I'm not sure what to do so he faces his respective movement.
Any help would be greatly appreciated and if you need more information besides the following code I have for the movement let me know, it's based off another post I found.
var speed : float = 6.0;
var jumpSpeed : float = 6.0;
var gravity : float = 12.0;
//This variable is now inheriting the Vector3 info (X,Y,Z) and setting them to 0.
private var moveDirection : Vector3 = Vector3.zero;
function MoveAndJump() {
var controller : CharacterController = GetComponent(CharacterController);
if(controller.isGrounded) {
//moveDirection is inheriting Vector3 info. This now sets the X and Z coords to receive the input set to "Horizontal" and "Vertical"
moveDirection = Vector3(Input.GetAxis("Horizontal"), 0, Input.GetAxis("Vertical")); //Allows player Input
moveDirection = transform.TransformDirection(moveDirection); //How to move
moveDirection *= speed; //How fast to move
if(Input.GetButtonDown("Jump")) {
animation.Play("Jump");
moveDirection.y = jumpSpeed;
}
}
//Apply gravity
moveDirection.y -= gravity * Time.deltaTime;
//This moves the controller
controller.Move(moveDirection * Time.deltaTime);
if(Input.GetButton("Fire1")){
animation.Play("Attack");
}
if(Input.GetButton("Vertical")){
animation.Play("Run");
}
}
function Update() {
MoveAndJump();
}
For what it's worth another problem I'm having involves having two different animations being able to work at the same time, like run and attack. I figured I should mention while I'm here if anybody knew how to go about that. Thank you again for your time!
I ended up solving this based off a different code I stumbled upon, then called the function inside of Update():
var speed : float;
var jumpSpeed : float;
var gravity : float;
private var moveDirection : Vector3 = Vector3.zero;
function MoveJumpAttack() {
var controller : CharacterController = GetComponent(CharacterController);
if (controller.isGrounded) {
moveDirection = Vector3(Input.GetAxis("Horizontal"), 0, 0);
moveDirection *= speed;
if (moveDirection.sqrMagnitude > 0.01)
transform.rotation = Quaternion.Slerp (transform.rotation, Quaternion.LookRotation (moveDirection), 90);
}
moveDirection.y -= gravity * Time.deltaTime;
controller.Move(moveDirection * Time.deltaTime);
}
Here is my override code - it just calculates where to snap to:
- (void)scrollViewWillEndDragging:(UIScrollView *)scrollView withVelocity:(CGPoint)velocity targetContentOffset:(inout CGPoint *)targetContentOffset {
if(targetContentOffset->y < 400) {
targetContentOffset->y = 0;
return;
}
int baseCheck = 400;
while(baseCheck <= 10000) {
if(targetContentOffset->y > baseCheck && targetContentOffset->y < baseCheck + 800) {
targetContentOffset->y = (baseCheck + 340);
return;
}
baseCheck += 800;
}
targetContentOffset->y = 0;
}
When I hold my finger down for more than a second or two to drag the scrollview and then lift my finger, it usually animates into place. However, when I do a quick "flick" it rarely animates - it just snaps to the targetContentOffset. I am trying to emulate default paging behavior (except trying to snap to custom positions).
Any ideas?
I ended up having to animate it manually. In the same function, I set the targetContentOffset to where the user left off (current contentOffset) so that it doesnt trigger it's own animation, and then I set the contentoffset to my calculation. Additionally, I added in a velocity check to trigger'automatic' page changes. It's not perfect, but hopefully it will help other with the same issue.
(I modified the above function for readability since no one needs to see my calculations)
- (void)scrollViewWillEndDragging:(UIScrollView *)scrollView withVelocity:(CGPoint)velocity targetContentOffset:(inout CGPoint *)targetContentOffset {
CGPoint newOffset = CGPointMake(targetContentOffset->x, targetContentOffset->y);
*targetContentOffset = CGPointMake([broadsheetCollectionView contentOffset].x, [broadsheetCollectionView contentOffset].y);
if(velocity.y > 1.4) {
newOffset.y += pixelAmountThatWillMakeSurePageChanges;
}
if(velocity.y < -1.4) {
newOffset.y -= pixelAmountThatWillMakeSurePageChanges;
}
// calculate newoffset
newOffset.y = calculatedOffset;
[scrollView setContentOffset:newOffset animated:YES];
}