Sweet! I’ll check them out
Animating/Moving CHANGEABLE weapons/armor through code? (equipping items) - PAPERDOLLING -
Okay, so I checked it out, and it looks pretty awesome. But I am using very pixely pixel art. I think it’d be way too hard to implement that with Spriter or Spine. Is there any other way of doing this without using JSON files and skeletons etc?
Best regards
I am not sure if I am understanding you correctly… but I would just have a massive spritesheet and create animations for each action that I wanted the player to do, then in the players update method simply change the animation with something like if(hasStaff){playerSprite.play(“staff”);}
This is how I would do it, which means it is probably wrong or outdated lol
I think you could do something like this.
Decide what position the weapon should have for each frame in the animation of the character, compared to the top left corner of the frame.
You’ll need variables to hold that information.
var hotspot1X:int;
var hotspot1Y:int;
change the hotspot-variables according to which frame of the animation is playing.
if(animation.currentAnimation==”walk_right”)
{
if(animation.getFrame()==0)
{
hotspot1X=25;
hotspot1Y=20;
}
else if(animation.getFrame()==1)
{
hotspot1X=20;
hotspot1Y=15;
}
and so on …
} else if(animation.currentAnimation==”walk_left”)
{
…
}
set x and y values for the animation
and then for the weapon
weapon.x=animation.x + hotspot1X;
weapon.y=animation.y + hotspot1Y;
Nice tip, I’ll use that for now! thanks
PS: I tried using getFrame() as you typed, but it didn’t seem to work.
if (sprHero.currentAnim == "run")
{
trace("running")
if (sprHero.getFrame() == 0) wepHotspotY = 85; trace("0");
if (sprHero.getFrame() == 1) wepHotspotY = 80; trace("1");
if (sprHero.getFrame() == 2) wepHotspotY = 75; trace("2");
if (sprHero.getFrame() == 3) wepHotspotY = 70; trace("3");
if (sprHero.getFrame() == 4) wepHotspotY = 70; trace("4");
if (sprHero.getFrame() == 5) wepHotspotY = 70; trace("5");
if (sprHero.getFrame() == 6) wepHotspotY = 70; trace("6");
if (sprHero.getFrame() == 7) wepHotspotY = 80; trace("7");
if (sprHero.getFrame() == 8) wepHotspotY = 85; trace("8");
}
It traces 0 through 8 on every frame whilst he is running. The running animation has 9 different frames itself.
I also tried changing it into this:
if (sprHero.currentAnim == "run")
{
if (sprHero.index == 0) wepHotspotY = 85; trace("0");
if (sprHero.index == 1) wepHotspotY = 80; trace("1");
if (sprHero.index == 2) wepHotspotY = 75; trace("2");
if (sprHero.index == 3) wepHotspotY = 70; trace("3");
if (sprHero.index == 4) wepHotspotY = 70; trace("4");
if (sprHero.index == 5) wepHotspotY = 70; trace("5");
if (sprHero.index == 6) wepHotspotY = 70; trace("6");
if (sprHero.index == 7) wepHotspotY = 80; trace("7");
if (sprHero.index == 8) wepHotspotY = 85; trace("8");
}
but that didn’t work. Which is weird, since I have an enemy who has his own punching animation and only if that punching animation has passed frame 6, then the hit will register.
if (impCollision)
{
if (invincibilityCounter == 0)
{
if (impCollision.sprImp.currentAnim == "attack")
{
if (impCollision.sprImp.index >= 6)
{
var damageTaken:Number = Imp.impStrength * armorReduction;
var xLocation:Number = x + this.width / 2 - 10;
var a:Number = x + this.width / 2;
var b:Number = Math.floor(Math.random() * (1 + y + 10 - y)) + y;
hp -= damageTaken;
invincibilityCountDown = true;
FP.world.add(new DamageShower(a, b, damageTaken, "0xFFFFFF"));
}
}
}
}
That seems to work, but not the whole hotspot thing!
If only I knew how to make the weapon render as fast as the character, so it doesn’t look like it’s “following” the player
If you’re adding your hero to a world using
_hero= new Hero();
add (_hero);
I think you need to go
_hero.sprHero.index
(you’re right, it should be index not getFrame)
could that be the problem?
Hmm… The thing is that I’m doing this code inside the Hero class
EDIT: It seems to work now!? :S What the hell.
But, isn’t there a better way to do this? If I want some very complex animations, then I have to define hotspots for every one of them! Can’t I just tell the program to “snap” the weapon to the hand automatically in some way? Like image recognition for the hero, so it detects where the hand is (let’s say I make the holding hand a different color. Like green-screening!
Anyway, I still need to override the rendering so the sword isn’t 1 frame too late, which makes it look like it’s following the hero. How can I do this? D:
If you, within a game loop,
- update the position of the hero and which frame is playing,
- update the hotSpot, and
- update the position of the weapon,
in that order, the weapon should be beside the hand when the scene renders.
If you update in any other order the weapon will be at an old position when the scene is rendered. So that is probably what is happening here. You need to make sure that the three steps update in the correct order.
As for better ways of doing it, sorry, I don’t know. Marking the spot with a unique color might be a way to do it, but I don’t know how to make the program find that spot and identify its x and y. I’m sure it can be done though. I’m not that convinced that that will make things that much easier for you.
You might want to look into masking. There might be something you can do with that.
The thing is that the weapon has its own class…
package
{
import net.flashpunk.Entity;
import net.flashpunk.Graphic;
import net.flashpunk.Mask;
import net.flashpunk.utils.Input;
import net.flashpunk.utils.Key;
import net.flashpunk.graphics.Spritemap;
import net.flashpunk.graphics.Image;
import flash.geom.Point;
import net.flashpunk.FP;
public class Weapon_Sword_Basic extends Entity
{
[Embed(source = "assets/Weapon_Sword_Basic.png")] private const SWORD:Class;
public var sprSword:Spritemap = new Spritemap(SWORD, 80, 80);
private var attacking:Boolean = false;
private var pickedUp:Boolean = false;
public function Weapon_Sword_Basic(xt:Number, yt:Number)
{
graphic = new Image(SWORD);
layer = 1;
setHitbox(80, 80)
x = xt;
y = yt;
type = "weapon";
graphic = sprSword;
sprSword.add("idle", [0], 0, true);
sprSword.add("attack", [0, 1, 2, 3, 4, 5, 6], 30, true);
Input.define("Attack", Key.X);
}
override public function update():void
{
var e:Hero = collide("hero", x, y) as Hero;
//Make hero pick it up
if (!pickedUp)
{
if (e)
{
pickedUp = true;
}
}
if (pickedUp)
{
if (Hero.isFacingLeft)
{
sprSword.flipped = true;
}else
{
sprSword.flipped = false;
}
x = Hero.wepHotspotX;
//Offset -.-
y = Hero.yPos + Hero.wepHotspotY - this.height + 11;
}
//Make it go down
if (!collide("ground", x, y))
{
if (!pickedUp)
{
y++;
}
}
if (Input.pressed("Attack"))
{
sprSword.play("attack");
attacking = true;
setHitbox(this.width, this.height)
}
if (attacking)
{
if (sprSword.frame == 6)
{
sprSword.play("idle");
attacking = false;
}
}
}
}
}
In this case, it’s best just to have a dedicated character sprite for each weapon.
But since I have a lot of weapons and armor sets, that would mean I’d have to make over a hundred different character spritemaps…
“If only I knew how to make the weapon render as fast as the character, so it doesn’t look like it’s “following” the player”
can anyone help me with this? I know I have to override the render function, but I don’t know what to override it with… the weapon is always one frame behind, so it looks like it is floating
Hey. I tried doing it, but it still doesn’t work that well. The items “stuck” on the hero are still not moving exactly the same time as the hero.
This is the hero code. Notice that the hotspot for X never changes since the character doesn’t move his hand back and forth during any animation. It is always on the same x position. The character bounces a bit as he runs, though.
In the loop:
//Change weapon hotspots, depending on the frame/animation
if (sprHero.currentAnim == "run")
{
if (sprHero.index == 0 || sprHero.index == 3)
{
wepHotspotY = yPos - 24;
helmetHotspotY = yPos - 24;
}
if (sprHero.index == 1 || sprHero.index == 2)
{
wepHotspotY = yPos - 18;
helmetHotspotY = yPos - 18;
}
if (sprHero.index == 4)
{
wepHotspotY = yPos - 32;
helmetHotspotY = yPos - 32;
}
}
if (sprHero.currentAnim == "stand")
{
if (sprHero.index == 0)
{
wepHotspotY = yPos - 24;
helmetHotspotY = yPos - 24;
}
}
if (sprHero.currentAnim == "jump")
{
wepHotspotY = yPos - 24;
helmetHotspotY = yPos - 24;
}
wepHotspotX = xPos + 104;
// Update stuck objects.
for each (var b:Weapon in _stuckEntities)
{
b.updateStuck(wepHotspotX, wepHotspotY);
}
And the weapon:
public function updateStuck(wepx:Number, wepy:Number):void
{
/*if (Hero.isFacingLeft)
{
x = wepx - 32;
sprSword.flipped = true;
}else
{
x = wepx;
sprSword.flipped = false;
}*/
this.x = wepx;
this.y = wepy;
//Attack
if (Input.pressed("Attack"))
{
if (HeroStats.currentStamina == HeroStats.stamina)
{
HeroStats.currentStamina = 0;
attacking = true;
}
}
if (attacking)
{
sprSword.play("attack");
}
if (sprSword.currentAnim == "attack")
{
if (sprSword.index == 3)
{
attacking = false;
sprSword.play("idle");
}
}
super.update();
}
}
I really need some help here, this is the only thing I’m having a big problem with at the current stage of the game. It looks horrible when the armor isn’t even “stuck” on the hero properly It’s as if the paperdolling is working, but it’s… not…
override public function update():void
{
if (!_stuck)
{
var sb:Hero = Hero(collide("hero", x, y));
if (sb != null)
{
// Hit a sticky block.
stuckOffset = sb.attachBlock(this).subtract(new Point(x, y));
_stuck = true;
}
}
super.update();
}
Please check my other thread John's Epic Megathread Of Confusion & Tomfoolery.
The problem persists with SPRITEMAPS now. They don’t play as soon as the hero spritemap starts playing. They are one step behind. I made sure that the spritemaps are equal in terms of placement of the armor in regards to the hero. I basically just took the hero spritemap, replaced his legs (for example) with armored legs and removed the hero graphic. So the leg armor has its own spritemap where its locations is relative to the hero.