When the player dies, I want the sprite to stop animating on the last frame.
I tried this on Animation End event
if (sprite_index == spr_ninja_dead) {
image_speed = 0;
image_index = image_number - 1;
}
I also tried this
if (sprite_index == spr_ninja_dead) {
image_speed = 0;
image_index = 9;
}
This is the recommended way that GM suggests, yet the sprite freezes on the first sub image. What am I doing wrong?
When the player gets hit, the sprite would change to a flashing sprite image. Then an alarm would change it back to normal. I added an if statement to fix this:
if (sprite_index = spr_ninja_flash){
sprite_index = spr_ninja_idle;
}
What you want to do is run the animation first.
So try this:
if( sprite_index == spr_ninja_dead ){
if( image_index == image_number ){ // This will check if the image is the last image of the sprite
image_speed = 0;
}
}
First you check if the sprite is the dead one, then you check if it's the last image of the sprite and if that is the case you can pause the animation using the image speed.
Related
Unsquashed Sprite Squashed Sprite
My brother has issues with his sprite squashing whilst moving horizontally. The squashing is permanent after moving. I have found the line that causes the problem but cannot figure out what is causing this issue. When I remove this line the squashing stops however the sprite does not turn. He is following Shaun Spalding's Complete Platformer Tutorial and though I've watched it over I cannot find any issues with the actual code.
/// #description Insert description here
// You can write your code in this editor
// get player input
key_left=keyboard_check(vk_left);
key_right=keyboard_check(vk_right);
key_jump=keyboard_check_pressed(vk_up);
// calculate movement
var move=key_right-key_left;
hsp=move*walksp;
vsp=vsp+grv;
if(place_meeting(x,y+1,o_wall)) and (key_jump)
{
vsp=-7;
}
// horizontal collision
if (place_meeting(x+hsp,y,o_wall))
{
while(!place_meeting(x+sign(hsp),y,o_wall))
{
x=x+sign(hsp);
}
hsp=0;
}
x=x+hsp;
// vertical collision
if (place_meeting(x,y+vsp,o_wall))
{
while(!place_meeting(x,y+sign(vsp),o_wall))
{
y=y+sign(vsp);
}
vsp=0;
}
y=y+vsp;
// animation
if(!place_meeting(x,y+1,o_wall))
{
sprite_index=splayerA;
image_speed=0;
if (sign(vsp) > 0) image_index = 1; else image_index = 0;
}
else
{
image_speed=1;
if (hsp==0)
{
sprite_index=s_player;
}
else
{
sprite_index=splayerR;
}
}
if (hsp != 0) image_xscale = sign(hsp); //this line is wrong and causes the squishing
A possible cause of this is that you've set the image_xscale to a different value before using the line:
if (hsp != 0) image_xscale = sign(hsp);
For example, you may have set this in the Create Event to enlarge the sprite:
image_xscale = 2;
But that value is reset after setting image_xscale again, as that line will only return -1 or 1 because of the Sign().
One quick solution is to apply the scale change to that line of code, like this:
if (hsp != 0) image_xscale = 2 * sign(hsp);
(Once again, presuming you've changed it's scale value somewhere else)
Though another solution is to enlarge the sprite itself in the sprite editor, so the scale doesn't have to be kept in mind everytime.
I have a script in my simple platformer game which says that if my player is in the ground and "Z" is pressed, his movement in the Y axis is going to go up to 600, and if he's not in the ground, he's going to perform the jump animation.
So here's the thing, I know it plays only the first frame of the jumping animation because the code is constantly detecting that the player is in the air. I want a way to tell the code to trigger the animation only once.
I tried using a function called input_(event): but it seems that it doesn't have a is_action_just_pressed type of Input, just is_action_pressed.
I'm fairly new to Godot and don't know how to use signals. Signals might help via animation_finished(), although that function might have nothing to do with what I actually want to do in my code.
Here's my code:
extends KinematicBody2D
#Variables van aquĆ
var movimiento = Vector2();
var gravedad = 20;
var arriba = Vector2(0, -1);
var velocidadMax = 600;
var fuerza_salto = -600;
var aceleracion = 5;
var saltando = false;
func _ready(): # Esto es void Start()
pass;
func _physics_process(delta): #Esto es void Update()
movimiento.y += gravedad;
if Input.is_action_pressed("ui_right"):
$SonicSprite.flip_h = true;
$SonicSprite.play("Walk");
movimiento.x = min(movimiento.x +aceleracion, velocidadMax);
elif Input.is_action_pressed("ui_left"):
$SonicSprite.flip_h = false;
$SonicSprite.play("Walk");
movimiento.x = max(movimiento.x-aceleracion, -velocidadMax);
else:
movimiento.x = lerp(movimiento.x, 0, 0.09);
$SonicSprite.play("Idle");
if is_on_floor():
if Input.is_action_just_pressed("z"):
movimiento.y = fuerza_salto;
else:
$SonicSprite.play("Jump");
movimiento = move_and_slide(movimiento, arriba)
I had the smae problem, and it was solved for me adding the next after move_and_slide():
if velocity.y == 0:
velocity.y = 10
Apparently, if velocity is 0 after move_and_slide() it does not detect is_on_floor() anymore (bug?) so i added small velocity in direction of gravity.
About usinginput_(event), you do not need just_pressed because it only process when there is an input.. you can do somethin like this:
func _input(event):
if event.is_action_pressed("ui_up") and is_on_floor():
velocity.y = jump_speed
What i called velocity, i think in your script is called movimiento. Also, i think you are mixing gravities and velocities in movimiento. I'm sharing you my character scrpit so you can compare and see if it works better:
extends KinematicBody2D
var Bullet = preload("res://Bullet.tscn")
var speed = 200
var jump_speed = -300
var shot_speed = 100
var velocity = Vector2()
var grav = 980
var shooting = false
func _ready():
$AnimatedSprite.play()
$AnimatedSprite.connect("animation_finished",self,"on_animation_finished")
func _input(event):
if event.is_action_pressed("ui_up") and is_on_floor():
velocity.y = jump_speed
if event.is_action_pressed("shoot") and !shooting:
shooting = true
shot_speed = 20
velocity.y = -200
fire_weapon()
func _physics_process(delta):
velocity.x = 0
if Input.is_action_pressed("ui_right"):
velocity.x += speed
if Input.is_action_pressed("ui_left"):
velocity.x -= speed
if velocity.length() > 0:
if velocity.x < 0:
$AnimatedSprite.flip_v = true
$AnimatedSprite.rotation_degrees = 180
elif velocity.x > 0:
$AnimatedSprite.flip_v = false
$AnimatedSprite.rotation_degrees = 0
if shooting:
$AnimatedSprite.animation = "shot"
velocity.x = -shot_speed * cos($AnimatedSprite.rotation_degrees)
shot_speed *= 0.98
else:
if is_on_floor():
if velocity.x == 0:
$AnimatedSprite.animation = "idle"
else:
$AnimatedSprite.animation = "moving"
else:
$AnimatedSprite.animation = "jumping"
velocity.y += grav * delta
velocity = move_and_slide(velocity, Vector2(0,-1))
if velocity.y == 0:
velocity.y = 10
func on_animation_finished():
if $AnimatedSprite.animation == "shot":
shooting = false
func fire_weapon():
var bullet = Bullet.instance()
get_parent().add_child(bullet)
if $AnimatedSprite.flip_v :
bullet.position = $ShotLeft.global_position
else:
bullet.position = $ShotRight.global_position
bullet.rotation_degrees = $AnimatedSprite.rotation_degrees
bullet.linear_velocity = Vector2(1500 * cos(bullet.rotation),1500*sin(bullet.rotation))
Notice that i do not use gravity as a velocity or moviemiento; instead y multiply it by delta for getting velocity, as acceleration x time gives velocity.
I hope this helps.
This kind of problem can be solved using a Finite State Machine to manage your character controls and behaviour. You would play the Jump animation on entering the Jumping state from the Walking state. Utilizing correct design patterns early prevents spaghetti code in the future.
This is not a Godot specific solution, but definitely one worth your attention.
Let's dissect what's happening here, you fire up the code and ask your player to play the animation in one frame and then again in the other and in the next as long as the correct key is pressed or you in the correct state.
What the problem, the problem is that at every call of the function play it fires the animation again and again so it just restarts or another call runs separately and this causes unexpected behaviour.
The better way will be to manage the state of the player and animation player simultaneously and using that to perform animation calls.
enum State { IDLE, WALK, RUN, JUMP, INAIR, GROUNDED } ## This is to manage the player state
var my_state = State.IDLE ## Start the player with the idle state
As for the animation player state use the signal that you were talking about using the GUI or with code like below.
get_node("Animation Player").connect("animation_finished", this, "method_name")
## Here I assume that you have the Animation Player as the Child of the Node you the script on
And also hold a boolean variable to tell if the animation is playing or not.
if ( animation_not_playing and (case)):
animation_player.play("animation")
Turn it true or false as per your liking. Based on the animation finished signal.
In future, you might want to consider even using a simple FSM to maintain all this state data and variables.
I have 5 images that is to be displayed at the bottom of my screen.
Now what i want is the images to appear one after the other and in a infinite loop type display (i.e After the 5th Image the 1st image should appear). This should go on as long as the user is on this page.
I tried Carousel, but after the 5th image, an auto rewind action takes place and the 1st image is loaded(Horrible).
How do i achieve the same using simple animation ?
Did you tried something like this:
string[] image = { "image1","another","third","oneMore","lastImage"};
int index = 0;
Device.StartTimer(TimeSpan.FromSeconds(5), () =>
{
if(index >= (image.Length - 1))
index = 0;
else
index++;
imgView.FadeTo(0.1, 250, Easing.Linear);
imgView.Source = ImageSource.FromResource(image[index]);
imgView.FadeTo(1, 250, Easing.Linear);
return true;
});
Use a simple Image instead of the CarouselView. Maybe you'll need surround the actions over imgView with a "Device.BeginInvokeOnMainThread". Check it out.
I am very new to coding and I'm still trying different languages out, I started off with GameMaker Studio and changed to Godot due to its compatibility with Mac I might as well learn something newer since GameMaker has been out for quite some time.
I want to create a RPG game and apply animation to each direction the character moves but the animation only plays after the key is pressed AND lifted. This means that while my key is pressed, the animation stops, and the animation only plays while my character is standing still, which is the complete opposite of what I want. The script looked really straight forward, but doesn't seem to be working.
I would tag this as the GDScript language instead of Python, but I guess I'm not reputable enough to make a new tag, so I tagged it under python because it is the most similar.
#variables
extends KinematicBody2D
const spd = 100
var direction = Vector2()
var anim_player = null
func _ready():
set_fixed_process(true)
anim_player = get_node("move/ani_move")
#movement and sprite change
func _fixed_process(delta):
if (Input.is_action_pressed("ui_left")) :
direction.x = -spd
anim_player.play("ani_player_left")
elif (Input.is_action_pressed("ui_right")):
direction.x = spd
anim_player.play("ani_player_right")
else:
direction.x = 0
if (Input.is_action_pressed("ui_up")) :
direction.y = -spd
anim_player.play("ani_player_up")
elif (Input.is_action_pressed("ui_down")):
direction.y = (spd)
anim_player.play("ani_player_down")
else:
direction.y = 0
if (Input.is_action_pressed("ui_right")) and (Input.is_action_pressed("ui_left")):
direction.x = 0
if (Input.is_action_pressed("ui_up")) and (Input.is_action_pressed("ui_down")) :
direction.y = 0
# move
var motion = direction * delta
move(motion)
As you check the input in _fixed_process, you call anim_player.play() several times a frame, which always seems to restart the animation, and thus, keeps the very first frame of the animation visible all the time.
As soon as you release the key, anim_player.play() stops resetting the animation back to start, and it can actually proceed to play the following frames.
A simple straight-forward solution would be to remember the last animation you played, and only call play() as soon as it changes.
You need to know if the animation has changed
First you need to put these variables in your code:
var currentAnim = ""
var newAnim = ""
And then you add this in your _fixed process:
if newAnim != anim:
anim = newAnim
anim_player.play(newAnim)
To change the animation you use:
newAnim = "new animation here"
Hi everyone For the pass two days I was trying to solve the problem I'm having without success..
I want to make game when the hero jumps on platform and goes up. It is Doodle Jump type of a game.
Here is the code
I make the the world node
SKNode *world;
Then the hero
SKSpriteNode *hero;
// setting the physicsBody
// add categoryBitMask = heroCat;
// add contactTestBitMask = platformCat;
// add collisionBitMask = 0;
The platform
SKSpriteNode *platform;
// setting the physicsBody
// add categoryBitMask = platformCat;
// add collisionBitMask = 0;
In didBeginContact
// Only bounce the hero if he's falling
if (hero.physicsBody.velocity.dy < 0){
hero.physicsBody.velocity = CGVectorMake(hero.physicsBody.velocity.dx, 500.0f);
}
In didSimulatePhysics
// if the game is started and the hero position is > 0 and hero position > the new max hero y
if(self.isStarted && hero.position.y > 0 && hero.position.y > _maxHeroY){
CGPoint positionInScene = [self convertPoint:hero.position fromNode:hero.parent];
world.position = CGPointMake(world.position.x, world.position.y -positionInScene.y);
}
So far so good but what the I notice that sometimes I can jump when:
in didSimulatePhysics i also gen new platform on random Y with fixed x value from the preveos platform
when the hero goes up the world position change
the hero is falling
he is not above the platform but abble to contact with his body, this is wrong cause he has to jump only when the feet are above the platform
So I change the didBeginContact
// hero position in the world
CGPoint positionInScene = [self convertPoint:hero.position fromNode:node.parent];
// platform position in the world
CGPoint positionInSceneP = [self convertPoint:node.position fromNode:node.parent];
// get the positon of the bottom edge of the hero (the feet)
int heroBottomEdge = positionInScene - hero.frame.size.height/2;
// get the positon of the top edge of the platfrom
int platformTopEdge = positionInScene - node.frame.size.height/2;
// Only bounce the hero if he's falling and the bottom edge of the hero node(the feet) is above the platform top edge or or equal to jump
if (hero.physicsBody.velocity.dy < 0 && heroBottomEdge >= platformTopEdge){
hero.physicsBody.velocity = CGVectorMake(hero.physicsBody.velocity.dx, 500.0f);
}
The problem is that sometimes platformTopEdge is bigger that the heroBottomEdge and ther hero pass through the platform without jumping
I also try with just hero.position.y and node.position.y but the effect is the same