Character won't punch
by Herlan Rovelo · in Torque X 2D · 07/22/2009 (1:49 pm) · 10 replies
Hi everyone! This is my first post and my first real dive into TorqueX. I'm working on a beat 'em up game in the tradition of Double Dragon. Unfortunately, my entire background is in art; concept, 3D, you name it! This is why I opted to purchase TorqueX; it seemed simple enough to use and I had success with a lot of the tutorials. I've gotten some very basic stuff to work (thanks to some of the resources on this forum), but I'm having a hard time figuring out how to make my character punch when I press Spacebar or X on my 360 game pad. I've pasted the code from my AnimatedCharacterComponent below so you guys can see what I've done. Again, I'm no programmer, just as artist trying to learn as I go. Any help or direction is appreciated. I'm using the basic starter game template, not the Platformer Kit, btw. Thanks in advance!
using System;
using System.Collections.Generic;
using System.Text;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Input;
using GarageGames.Torque.Core;
using GarageGames.Torque.T2D;
using GarageGames.Torque.Sim;
using GarageGames.Torque.Platform;
using GarageGames.Torque.Util;
using GarageGames.Torque.SceneGraph;
using GarageGames.Torque.MathUtil;
namespace StarterGame2D
{
[TorqueXmlSchemaType]
public class AnimatedCharacterComponent : TorqueComponent, ITickObject
{
//======================================================
#region Static methods, fields, constructors
#endregion
//======================================================
#region Constructors
#endregion
//======================================================
#region Public properties, operators, constants, and enums
public T2DSceneObject SceneObject
{
get { return Owner as T2DSceneObject; }
}
public T2DAnimatedSprite AnimatedSprite
{
get { return Owner as T2DAnimatedSprite; }
}
public T2DAnimationData AnimNorth
{
get { return _animNorth; }
set { _animNorth = value; }
}
public T2DAnimationData AnimNorthWest
{
get { return _animNorthWest; }
set { _animNorthWest = value; }
}
public T2DAnimationData AnimWest
{
get { return _animWest; }
set { _animWest = value; }
}
public T2DAnimationData AnimSouthWest
{
get { return _animSouthWest; }
set { _animSouthWest = value; }
}
public T2DAnimationData AnimSouth
{
get { return _animSouth; }
set { _animSouth = value; }
}
public T2DAnimationData AnimSouthEast
{
get { return _animSouthEast; }
set { _animSouthEast = value; }
}
public T2DAnimationData AnimEast
{
get { return _animEast; }
set { _animEast = value; }
}
public T2DAnimationData AnimNorthEast
{
get { return _animNorthEast; }
set { _animNorthEast = value; }
}
public T2DAnimationData AnimPunch
{
get { return _animPunch; }
set { _animPunch = value; }
}
#endregion
//======================================================
#region Public methods
public void PlayMyAnimation(T2DAnimationData animationData)
{
if (AnimatedSprite.AnimationData != animationData || !AnimatedSprite.IsAnimationPlaying)
{
AnimatedSprite.PlayAnimation(animationData);
AnimatedSprite.PlayAnimation();
}
}
public virtual void ProcessTick(Move move, float dt)
{
if (move != null)
{
if (move.Buttons[0].Pushed)
{
PlayMyAnimation(_animPunch);
}
if ((move.Sticks[0].X > 0) && (move.Sticks[0].Y > 0))
{
PlayMyAnimation(_animNorthEast);
}
else if ((move.Sticks[0].X > 0) && (move.Sticks[0].Y < 0))
{
PlayMyAnimation(_animSouthEast);
}
else if ((move.Sticks[0].X < 0) && (move.Sticks[0].Y > 0))
{
PlayMyAnimation(_animNorthWest);
}
else if ((move.Sticks[0].X < 0) && (move.Sticks[0].Y < 0))
{
PlayMyAnimation(_animSouthWest);
}
else if (move.Sticks[0].X > 0)
{
PlayMyAnimation(_animEast);
}
else if (move.Sticks[0].X < 0)
{
PlayMyAnimation(_animWest);
}
else if (move.Sticks[0].Y > 0)
{
PlayMyAnimation(_animNorth);
}
else if (move.Sticks[0].Y < 0)
{
PlayMyAnimation(_animSouth);
}
else
{
AnimatedSprite.PauseAnimation();
}
// set our test object's Velocity based on stick/keyboard input
_sceneObject.Physics.VelocityX = move.Sticks[0].X * 25.0f;
_sceneObject.Physics.VelocityY = -move.Sticks[0].Y * 25.0f;
}
}
public virtual void InterpolateTick(float k)
{
// todo: interpolate between ticks as needed here
}
public override void CopyTo(TorqueComponent obj)
{
base.CopyTo(obj);
AnimatedCharacterComponent obj2 = obj as AnimatedCharacterComponent;
obj2._animNorth = _animNorth;
obj2._animNorthWest = _animNorthWest;
obj2._animWest = _animWest;
obj2._animSouthWest = _animSouthWest;
obj2._animSouth = _animSouth;
obj2._animSouthEast = _animSouthEast;
obj2._animEast = _animEast;
obj2._animNorthEast = _animNorthEast;
obj2._animPunch = _animPunch;
}
#endregion
//======================================================
#region Private, protected, internal methods
protected override bool _OnRegister(TorqueObject owner)
{
if (!base._OnRegister(owner) || !(Owner is T2DSceneObject))
return false;
// retain a reference to this component's owner object
_sceneObject = owner as T2DSceneObject;
_SetupInputMap(_sceneObject, 0, "gamepad0", "keyboard");
// tell the process list to notifiy us with ProcessTick and InterpolateTick events
ProcessList.Instance.AddTickCallback(Owner, this);
return true;
}
void _OnBackButton(float val)
{
if (val > 0.0f)
Game.Instance.Exit();
}
// todo: perform initialization for the component
// todo: look up interfaces exposed by other components
// E.g.,
// _theirInterface = Owner.Components.GetInterface<ValueInterface<float>>("float", "their interface name");
private void _SetupInputMap(TorqueObject player, int playerIndex, String gamePad, String keyboard)
{
// Set player as the controllable object
PlayerManager.Instance.GetPlayer(playerIndex).ControlObject = player;
// Get input map for this player and configure it
InputMap inputMap = PlayerManager.Instance.GetPlayer(playerIndex).InputMap;
int gamepadId = InputManager.Instance.FindDevice(gamePad);
if (gamepadId >= 0)
{
inputMap.BindMove(gamepadId, (int)XGamePadDevice.GamePadObjects.LeftThumbX, MoveMapTypes.StickAnalogHorizontal, 0);
inputMap.BindMove(gamepadId, (int)XGamePadDevice.GamePadObjects.LeftThumbY, MoveMapTypes.StickAnalogVertical, 0);
inputMap.BindMove(gamepadId, (int)XGamePadDevice.GamePadObjects.X, MoveMapTypes.Button, 0);
inputMap.BindAction(gamepadId, (int)XGamePadDevice.GamePadObjects.Back, _OnBackButton);
}
// keyboard controls
int keyboardId = InputManager.Instance.FindDevice(keyboard);
if (keyboardId >= 0)
{
inputMap.BindMove(keyboardId, (int)Keys.Right, MoveMapTypes.StickDigitalRight, 0);
inputMap.BindMove(keyboardId, (int)Keys.Left, MoveMapTypes.StickDigitalLeft, 0);
inputMap.BindMove(keyboardId, (int)Keys.Up, MoveMapTypes.StickDigitalUp, 0);
inputMap.BindMove(keyboardId, (int)Keys.Down, MoveMapTypes.StickDigitalDown, 0);
inputMap.BindMove(keyboardId, (int)Keys.Space, MoveMapTypes.Button, 0);
// WASD
inputMap.BindMove(keyboardId, (int)Keys.D, MoveMapTypes.StickDigitalRight, 0);
inputMap.BindMove(keyboardId, (int)Keys.A, MoveMapTypes.StickDigitalLeft, 0);
inputMap.BindMove(keyboardId, (int)Keys.W, MoveMapTypes.StickDigitalUp, 0);
inputMap.BindMove(keyboardId, (int)Keys.S, MoveMapTypes.StickDigitalDown, 0);
}
}
protected override void _OnUnregister()
{
// todo: perform de-initialization for the component
base._OnUnregister();
}
protected override void _RegisterInterfaces(TorqueObject owner)
{
base._RegisterInterfaces(owner);
// todo: register interfaces to be accessed by other components
// E.g.,
// Owner.RegisterCachedInterface("float", "interface name", this, _ourInterface);
}
#endregion
//======================================================
#region Private, protected, internal fields
T2DSceneObject _sceneObject;
T2DAnimationData _animNorth;
T2DAnimationData _animNorthWest;
T2DAnimationData _animWest;
T2DAnimationData _animSouthWest;
T2DAnimationData _animSouth;
T2DAnimationData _animSouthEast;
T2DAnimationData _animEast;
T2DAnimationData _animNorthEast;
T2DAnimationData _animPunch;
#endregion
}
}
using System;
using System.Collections.Generic;
using System.Text;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Input;
using GarageGames.Torque.Core;
using GarageGames.Torque.T2D;
using GarageGames.Torque.Sim;
using GarageGames.Torque.Platform;
using GarageGames.Torque.Util;
using GarageGames.Torque.SceneGraph;
using GarageGames.Torque.MathUtil;
namespace StarterGame2D
{
[TorqueXmlSchemaType]
public class AnimatedCharacterComponent : TorqueComponent, ITickObject
{
//======================================================
#region Static methods, fields, constructors
#endregion
//======================================================
#region Constructors
#endregion
//======================================================
#region Public properties, operators, constants, and enums
public T2DSceneObject SceneObject
{
get { return Owner as T2DSceneObject; }
}
public T2DAnimatedSprite AnimatedSprite
{
get { return Owner as T2DAnimatedSprite; }
}
public T2DAnimationData AnimNorth
{
get { return _animNorth; }
set { _animNorth = value; }
}
public T2DAnimationData AnimNorthWest
{
get { return _animNorthWest; }
set { _animNorthWest = value; }
}
public T2DAnimationData AnimWest
{
get { return _animWest; }
set { _animWest = value; }
}
public T2DAnimationData AnimSouthWest
{
get { return _animSouthWest; }
set { _animSouthWest = value; }
}
public T2DAnimationData AnimSouth
{
get { return _animSouth; }
set { _animSouth = value; }
}
public T2DAnimationData AnimSouthEast
{
get { return _animSouthEast; }
set { _animSouthEast = value; }
}
public T2DAnimationData AnimEast
{
get { return _animEast; }
set { _animEast = value; }
}
public T2DAnimationData AnimNorthEast
{
get { return _animNorthEast; }
set { _animNorthEast = value; }
}
public T2DAnimationData AnimPunch
{
get { return _animPunch; }
set { _animPunch = value; }
}
#endregion
//======================================================
#region Public methods
public void PlayMyAnimation(T2DAnimationData animationData)
{
if (AnimatedSprite.AnimationData != animationData || !AnimatedSprite.IsAnimationPlaying)
{
AnimatedSprite.PlayAnimation(animationData);
AnimatedSprite.PlayAnimation();
}
}
public virtual void ProcessTick(Move move, float dt)
{
if (move != null)
{
if (move.Buttons[0].Pushed)
{
PlayMyAnimation(_animPunch);
}
if ((move.Sticks[0].X > 0) && (move.Sticks[0].Y > 0))
{
PlayMyAnimation(_animNorthEast);
}
else if ((move.Sticks[0].X > 0) && (move.Sticks[0].Y < 0))
{
PlayMyAnimation(_animSouthEast);
}
else if ((move.Sticks[0].X < 0) && (move.Sticks[0].Y > 0))
{
PlayMyAnimation(_animNorthWest);
}
else if ((move.Sticks[0].X < 0) && (move.Sticks[0].Y < 0))
{
PlayMyAnimation(_animSouthWest);
}
else if (move.Sticks[0].X > 0)
{
PlayMyAnimation(_animEast);
}
else if (move.Sticks[0].X < 0)
{
PlayMyAnimation(_animWest);
}
else if (move.Sticks[0].Y > 0)
{
PlayMyAnimation(_animNorth);
}
else if (move.Sticks[0].Y < 0)
{
PlayMyAnimation(_animSouth);
}
else
{
AnimatedSprite.PauseAnimation();
}
// set our test object's Velocity based on stick/keyboard input
_sceneObject.Physics.VelocityX = move.Sticks[0].X * 25.0f;
_sceneObject.Physics.VelocityY = -move.Sticks[0].Y * 25.0f;
}
}
public virtual void InterpolateTick(float k)
{
// todo: interpolate between ticks as needed here
}
public override void CopyTo(TorqueComponent obj)
{
base.CopyTo(obj);
AnimatedCharacterComponent obj2 = obj as AnimatedCharacterComponent;
obj2._animNorth = _animNorth;
obj2._animNorthWest = _animNorthWest;
obj2._animWest = _animWest;
obj2._animSouthWest = _animSouthWest;
obj2._animSouth = _animSouth;
obj2._animSouthEast = _animSouthEast;
obj2._animEast = _animEast;
obj2._animNorthEast = _animNorthEast;
obj2._animPunch = _animPunch;
}
#endregion
//======================================================
#region Private, protected, internal methods
protected override bool _OnRegister(TorqueObject owner)
{
if (!base._OnRegister(owner) || !(Owner is T2DSceneObject))
return false;
// retain a reference to this component's owner object
_sceneObject = owner as T2DSceneObject;
_SetupInputMap(_sceneObject, 0, "gamepad0", "keyboard");
// tell the process list to notifiy us with ProcessTick and InterpolateTick events
ProcessList.Instance.AddTickCallback(Owner, this);
return true;
}
void _OnBackButton(float val)
{
if (val > 0.0f)
Game.Instance.Exit();
}
// todo: perform initialization for the component
// todo: look up interfaces exposed by other components
// E.g.,
// _theirInterface = Owner.Components.GetInterface<ValueInterface<float>>("float", "their interface name");
private void _SetupInputMap(TorqueObject player, int playerIndex, String gamePad, String keyboard)
{
// Set player as the controllable object
PlayerManager.Instance.GetPlayer(playerIndex).ControlObject = player;
// Get input map for this player and configure it
InputMap inputMap = PlayerManager.Instance.GetPlayer(playerIndex).InputMap;
int gamepadId = InputManager.Instance.FindDevice(gamePad);
if (gamepadId >= 0)
{
inputMap.BindMove(gamepadId, (int)XGamePadDevice.GamePadObjects.LeftThumbX, MoveMapTypes.StickAnalogHorizontal, 0);
inputMap.BindMove(gamepadId, (int)XGamePadDevice.GamePadObjects.LeftThumbY, MoveMapTypes.StickAnalogVertical, 0);
inputMap.BindMove(gamepadId, (int)XGamePadDevice.GamePadObjects.X, MoveMapTypes.Button, 0);
inputMap.BindAction(gamepadId, (int)XGamePadDevice.GamePadObjects.Back, _OnBackButton);
}
// keyboard controls
int keyboardId = InputManager.Instance.FindDevice(keyboard);
if (keyboardId >= 0)
{
inputMap.BindMove(keyboardId, (int)Keys.Right, MoveMapTypes.StickDigitalRight, 0);
inputMap.BindMove(keyboardId, (int)Keys.Left, MoveMapTypes.StickDigitalLeft, 0);
inputMap.BindMove(keyboardId, (int)Keys.Up, MoveMapTypes.StickDigitalUp, 0);
inputMap.BindMove(keyboardId, (int)Keys.Down, MoveMapTypes.StickDigitalDown, 0);
inputMap.BindMove(keyboardId, (int)Keys.Space, MoveMapTypes.Button, 0);
// WASD
inputMap.BindMove(keyboardId, (int)Keys.D, MoveMapTypes.StickDigitalRight, 0);
inputMap.BindMove(keyboardId, (int)Keys.A, MoveMapTypes.StickDigitalLeft, 0);
inputMap.BindMove(keyboardId, (int)Keys.W, MoveMapTypes.StickDigitalUp, 0);
inputMap.BindMove(keyboardId, (int)Keys.S, MoveMapTypes.StickDigitalDown, 0);
}
}
protected override void _OnUnregister()
{
// todo: perform de-initialization for the component
base._OnUnregister();
}
protected override void _RegisterInterfaces(TorqueObject owner)
{
base._RegisterInterfaces(owner);
// todo: register interfaces to be accessed by other components
// E.g.,
// Owner.RegisterCachedInterface("float", "interface name", this, _ourInterface);
}
#endregion
//======================================================
#region Private, protected, internal fields
T2DSceneObject _sceneObject;
T2DAnimationData _animNorth;
T2DAnimationData _animNorthWest;
T2DAnimationData _animWest;
T2DAnimationData _animSouthWest;
T2DAnimationData _animSouth;
T2DAnimationData _animSouthEast;
T2DAnimationData _animEast;
T2DAnimationData _animNorthEast;
T2DAnimationData _animPunch;
#endregion
}
}
#2
07/22/2009 (2:50 pm)
Thanks Brian! Funny, a big part of my inspiration to get this going was actually Castle Crashers! I've spent the better part of today looking for "simple" input info with little to no luck. Most of the info I found related to the platformer kit amd seems to be a little more involved than what I'm looking for. I'll check out your link.
#3
I didn't forget about you. Ran into a snag trying to create a component for you to look at. It's funny because in trying to jam it all into one component and make it less complicated than what I'm doing in the game I'm working on right now, I introduced several bugs that are driving me nuts. I'll work on it again tomorrow.
Brian
07/22/2009 (11:32 pm)
Hey Herlan,I didn't forget about you. Ran into a snag trying to create a component for you to look at. It's funny because in trying to jam it all into one component and make it less complicated than what I'm doing in the game I'm working on right now, I introduced several bugs that are driving me nuts. I'll work on it again tomorrow.
Brian
#4
if the x distance is less than a certain amount and the y is within a certain amount when the punch is thrown?
07/23/2009 (6:11 am)
I must not be understanding correctly. For a beat 'em up, whether it's double dragon, castle crashers, tmnt, even wrestlefest, couldn't you simple check the distance between characters?if the x distance is less than a certain amount and the y is within a certain amount when the punch is thrown?
#5
I looked at the code for AnimatedCharacterComponent and used that to learn what the code should look like to make the character move. I've been trying to find code samples that simply show, "attack when button X is pushed".
I understand this code:
}
else if (move.Sticks[0].X > 0)
{
PlayMyAnimation(_animEast);
tells the game, move the character right when the right direction on the analog stick is pressed. I've been trying to figure out what the code is to tell the engine, attack when button X is pressed.
I hope I made things a little easier to understand. I know this is probably something super simple, but again, I don't have a background in programming and I'm trying to learn as I go. Thanks again fellas!
07/23/2009 (7:25 am)
Ok, let me try to make this simpler...I want to make my character punch, kick, jump, etc based on a button push on the 360 gamepad controller or key on the keyboard.I looked at the code for AnimatedCharacterComponent and used that to learn what the code should look like to make the character move. I've been trying to find code samples that simply show, "attack when button X is pushed".
I understand this code:
}
else if (move.Sticks[0].X > 0)
{
PlayMyAnimation(_animEast);
tells the game, move the character right when the right direction on the analog stick is pressed. I've been trying to figure out what the code is to tell the engine, attack when button X is pressed.
I hope I made things a little easier to understand. I know this is probably something super simple, but again, I don't have a background in programming and I'm trying to learn as I go. Thanks again fellas!
#6
After binding the x button to button 0, then the code
A few questions:
Some possibilities off the top of my head would be that:
Regarding that last possibility, be sure the property AnimPunch is set to the right anim in TXB.
07/23/2009 (8:12 am)
The code you posted doesn't work? Because as it's written, it looks correct.After binding the x button to button 0, then the code
if (move.Buttons[0].Pushed)
{
PlayMyAnimation(_animPunch);
} should respond to the button push.A few questions:
- Is the controller responding at all?
- Do the other animations work, i.e. moving around?
- Are you familiar with running in debug mode, using breakpoints to step through the code?
Some possibilities off the top of my head would be that:
- the controller is not getting mapped
- the line
PlayMyAnimation(_animPunch);
is not working right. - _animPunch is not mapped to the animation
Regarding that last possibility, be sure the property AnimPunch is set to the right anim in TXB.
#7
I'm not familair with breakpoints to step through the code, but I'm sure that's just a matter of doing a little reading and learning on my part. :)
I'll double check everything and let you guys know. I think my programming buddy came to the same conclusion you did so I'll do some re-checking now and keep you posted on my progress. For sure I know I mapped the AnimPunch to the right animation in TXB. I hope I didn't simply forget something basic (it happened before).
07/23/2009 (10:00 am)
You rock, Scott! Thanks for your input. Yes, the controller responds to all movement input, just no button input. I had aslo trie mapping a different animation to different directions and that worked as well; that's I why I thought there has to be something wrong with the button input code.I'm not familair with breakpoints to step through the code, but I'm sure that's just a matter of doing a little reading and learning on my part. :)
I'll double check everything and let you guys know. I think my programming buddy came to the same conclusion you did so I'll do some re-checking now and keep you posted on my progress. For sure I know I mapped the AnimPunch to the right animation in TXB. I hope I didn't simply forget something basic (it happened before).
#8
A question regarding input and animation though; when I hold left or right, the character moves and the animation cycle plays through ONLY as long as I'm holding the direction. If I let go of the stick the animation cycle will stop on whatever frame was last playing; it won't revert back to frame 1. This makes it look like the charcter stopped in mid stride. Is there a way to fix this?
Thanks again!!!
07/23/2009 (12:46 pm)
Update, fellas...it worked...for the most part. Thanks for the help! The problem I'm having now is the animation doesn't play properly; it's kind of jumpy. Not sure how to explain without posting a video, but at least this is progress in the right direction. I hit a button or key and my character attacks! :)A question regarding input and animation though; when I hold left or right, the character moves and the animation cycle plays through ONLY as long as I'm holding the direction. If I let go of the stick the animation cycle will stop on whatever frame was last playing; it won't revert back to frame 1. This makes it look like the charcter stopped in mid stride. Is there a way to fix this?
Thanks again!!!
#9
Brian
07/23/2009 (1:21 pm)
I think this will set him to stand right here:AnimatedSprite.SetAnimationFrame(0);//Or whatever frame is standing. AnimatedSprite.PauseAnimation();Also, you need to check if the current animation is the same as your last animation because you don't want it to restart the animation every time it detects you are pushing a direction. I usually find just setting the animation to loop in TXB2D and then stopping it with the above code when no movement is happening works pretty well. You probably don't want to loop punches though.
Brian
#10
07/23/2009 (1:40 pm)
Totally worked, Brian! Thanks! I'm finding out more and more how one simple line of code makes all the difference. This project is looking more and more like a game everyday! Thanks guys!
Torque Owner Brian
Opinions wanted: How to check for a successful punch in a 2D action/fight game similar to Double Dragon/Final Fight etc
Brian