Game Development Community

A Greeting and a Query

by Cameron Higgins-Homebrook · in Torque Game Builder · 04/01/2010 (3:59 pm) · 12 replies

First I'd like to start by saying hello to the Torque Development Community.

hello

I'm new to Torque so please excuse me if my question is noobish...
I have a project I have to do for a game development course and in this project I am attempting to create a behavior in which the character attacks the enemy

This is my current code...

if(!isObject(platformerAttack))
{
   %template = new BehaviorTemplate(platformerAttack)
   
   %template.friendlyName = "PlayerAttack"; 
   %template.behaviorType = "Input";
   %template.description  = "Sets the players attack";
   
   %template.addBehaviorField(Button, "Button to attack", keybind, "Space");
   //%template.addBehaviorField(isMelee, "Is it a Melee attack", bool, true);
   //%template.addBehaviorField(Attack Animation, "The file of the animation sprite sheet", 
   %template.addBehaviorField(Length, "Length of the attack(pixels)", float, 30.0);
}

function platformerAttack::onBehaviorAdd(%this)
{
   %this.StartX = %this.owner.getSizeX();
   %this.StartY = %this.owner.getSizeY();
   %this.count = 0;
   %this.increment = 1;
   %this.retract = false;
   
   %this.owner.enableUpdateCallback();
}

function platformerAttack::OnUpdate(%this)
{
   if (%this.retract == false)
   {
      %this.StartX += increment;
      %this.count += 1;
   }
   if (%this.retract == true)
   {
      %this.StartX -= increment;
      %this.count -= 1;
   }
   if (%this.count > %this.Length)
   {
      %this.retract = true;
      %this.count = 30;
   }
   if (%this.count < %this.Length)
   {
      %this.retract = false;
      %this.count = 0;
   }
}

however, i seem to be getting an error around here...
%template.friendlyName = "PlayerAttack";

I'm using Torsion as I cod and the error seems to be a parsing error but for the life of me i can't understand why

About the author

Recent Threads


#1
04/01/2010 (4:31 pm)
You're just missing the semi-colon on the previous line. (Easy, enough!)
#2
04/01/2010 (4:34 pm)
lol wow..

Thanks. lol Now i feel a little silly
#3
04/02/2010 (10:00 pm)
okay I have a new question and really don't want to get off on the wrong foot by spamming the forums, so I'll ask it here.

The script above is meant to be a melee-esque attack. However I'm having trouble coding it at the moment.

The way I want to do this is to have the behavior cast out a small distance scan to see if an enemy is in the way. If there is an enemy then it is supposed to kill it.

I have been using the platformer Control behavior from the Torque Development Network as a reference in creating the keybinds and am slowly making progress. But where I would really appreciate help is in knowing how to set up the actual attack scan.

My new code so far is...
if(!isObject(platformerAttack))
{
   %template = new BehaviorTemplate(platformerAttack);
   
   %template.friendlyName = "Platformer Attack"; 
   %template.behaviorType = "Input";
   %template.description  = "Sets the players attack";
   
   %template.addBehaviorField(Button, "Button to attack", keybind, "Space");
   %template.addBehaviorField(Length, "Length of the attack(pixels)", float, 30.0);
}

function platformerAttack::onLevelLoad(%this, %scenegraph)
{
   %this.startX = %this.owner.getSizeX();
   
   if(!isObject(moveMap))
      return;
   
   moveMap.bindObj(%this.getWord(%this.Button,0),%this.getWord(%this.Button,1), "beginAttack", %this);
   
   %this.attacking = false;   
   
   %this.enableUpdateCallback();
}

function platformerAttack::OnUpdate(%this)
{
}

function platformerAttack::beginAttack(%this)
{
   %this.attacking = true;
}

function platformerAttack::updateAttack()
{
   
}

Any help is again appreciated
#4
04/02/2010 (10:32 pm)
You might be looking for the pickLine function.

You can create a small line segment using your player's position, direction, and your length field. Something like the following (not exactly real code, but for reference):
%start = %this.owner.getPosition();
if( Player_Is_Facing_To_The_Right ) // However you set this
  %end = t2dVectorAdd( %start, %this.Length SPC 0 );
else
  %end = t2dVectorAdd( %start, -%this.Length SPC 0 );

// You might want to use the other parameters to make this easier...
%hits = %this.owner.getSceneGraph().pickLine( %start, %end );

for( %i = 0; %i < getWordCount( %hits ); %i++ )
{
  %hitObject = getWord( %hits, %i );
  // From here on is up to you...
}
#5
04/03/2010 (7:04 am)
okay so if I'm getting this right...

%start = %this.owner.getPosition();
this gets the position (is it both the x and y position?) If so then is that in the center of the object or one of the corners?
%end = t2dVectorAdd( %start, %this.Length SPC 0 );
I'm guessing this finds the end point using the start and I assume the SPC 0 is concatenating it so that the .Length is also a vector.
%hitObject = getWord( %hits, %i );
this is where I'm starting to get confused... Is this one object of the list? and then the getWord(%hits...) is putting in the object in the position i?

Sorry If I am incorrect and beginning to confuse people... woke up early to try and do this today and am still half asleep

EDIT: Also is there a way to check if a hit is of a certain class type.
I want to use safe delete (i think thats what its called) to kill the enemies but i think if I just use that it will also delete the platforms as well
#6
04/04/2010 (7:48 am)
Okay so I think I have something that might work... I used the shooter tutorial to (hopefully) jerry rig a kill attack... But I am unsure if this will work (a friend is working on the enemies and he's out of town so I cannot test atm) If anyone can point out some complications to this then please do.

if(!isObject(platformerAttack))
{
   %template = new BehaviorTemplate(platformerAttack);
   
   %template.friendlyName = "Platformer Attack"; 
   %template.behaviorType = "Input";
   %template.description  = "Sets the players attack";
   
   %template.addBehaviorField(Button, "Button to attack", keybind, "Space");
   %template.addBehaviorField(Length, "Length of the attack(pixels)", float, 30.0);
}

function platformerAttack::onLevelLoad(%this, %scenegraph)
{   
   if(!isObject(moveMap))
      return;
   
   if ($sword)
   {
   moveMap.bindObj(%this.getWord(%this.Button,0),%this.getWord(%this.Button,1), "beginAttack", %this);
   
   %this.attacking = false;   
   
   %this.enableUpdateCallback();
   }
}

function platformerAttack::OnUpdate(%this)
{
   updateAttack();
   updateAnim();
}

function platformerAttack::beginAttack(%this)
{
   %this.attacking = true;
}

function platformerAttack::updateAttack()
{
   %start = %this.owner.getPosition();
   %xVel = %this.owner.getLinearVelocityX();
   
   if (%xVel >= 0)
   {
      %end = t2dVectorAdd( %start, %this.Length SPC 0);
   }
   else
   {
      %end = t2dVectorAdd( %start, -%this.Length SPC 0);
   }
   
   %hits = %this.owner.getSceneGraph().pickLine (%start, %end);
   
   for( %i = 0; %i < getWordCount(%hits); %i++)
   {
      %hitObject = getWord(%hits, %i);
      
      if (%hitObject.class $= "enemy")
      {
         %hitObject.die();
      }
   }
}

function platformerAttack::updateAnim(%this)
{
}

Note the update anim function is currently empty while i move onto more pressing matters
#7
04/04/2010 (8:52 am)
I'm about to take off for the day, but just a quick note:

"pickLine" will return a string like this "1078 1154 1369". Those are handles to the 3 objects on the line segment.

"getWord" just gets each word, 1 at a time.

At a really quick glance, your test with the class name will work.

Later!
#8
04/06/2010 (6:04 am)
hmm something is amiss with my code but I can't understand what. It seems that the function beginAttack is never called.

At least I believe that to be the case as i want my behavior to output to the console, hello but i never see hello in the console

My code so far...

if(!isObject(platformerAttack))
{
   %template = new BehaviorTemplate(platformerAttack);
   
   %template.friendlyName = "Platformer Attack"; 
   %template.behaviorType = "Input";
   %template.description  = "Sets the players attack";
   
   %template.addBehaviorField(Button, "Button to attack", keybind, "Space");
   %template.addBehaviorField(Length, "Length of the attack(pixels)", float, 30.0);
}

function platformerAttack::onBehaviorAdd(%this)
{   
   if(!isObject(moveMap))
      return;
   
   //if ($sword)
   //{
   moveMap.bindObj(%this.getWord(%this.Button,0),%this.getWord(%this.Button,1), "beginAttack", %this);
//i believe the problem to be here...     

   %this.enableUpdateCallback();
   //}
}

function platformerAttack::OnUpdate(%this)
{
   updateAttackAnim();
}

function platformerAttack::beginAttack(%this, %val)
{
   echo("Hello");
   %start = %this.owner.getPosition();
   %xVel = %this.owner.getLinearVelocityX();
   
   if (%xVel >= 0)
   {
      %end = t2dVectorAdd( %start, %this.Length SPC 0);
   }
   else
   {
      %end = t2dVectorAdd( %start, -%this.Length SPC 0);
   }
   
   %hits = %this.owner.getSceneGraph().pickLine (%start, %end);
   
   for( %i = 0; %i < getWordCount(%hits); %i++)
   {
      %hitObject = getWord(%hits, %i);
      
      if (%hitObject.class $= "enemy")
      {
         %hitObject.die(%this);
      }
   }
}
function platformerAttack::updateAttackAnim(%this)
{
}

Is my keypress code correct or have i done something horrible?
#9
04/06/2010 (6:44 am)

moveMap.bindObj(%this.getWord(%this.Button,0),%this.getWord(%this.Button,1), "beginAttack",

It should look like this I think (untested):
moveMap.bindObj(getWord(%this.Button, 0), getWord(%this.Button, 1), "beginAttack", %this);

%this.getWord looks like it won't work. Just stip the %this part because getWord should be a global function and not related to any object or behavior. Also that line ends with a comma, but there should be a closing bracket.
#10
04/06/2010 (4:24 pm)
yesssssssssss

thank you very much... the getWord thing worked. also the code strip wasn't quite over just out of the page range

For anyone who would like the final code
if(!isObject(platformerAttack))
{
   %template = new BehaviorTemplate(platformerAttack);
   
   %template.friendlyName = "Platformer Attack"; 
   %template.behaviorType = "Input";
   %template.description  = "Sets the players attack";
   
   %template.addBehaviorField(Button, "Button to attack", keybind, "Space");
   %template.addBehaviorField(Length, "Length of the attack(pixels)", float, 30.0);
}

function platformerAttack::onBehaviorAdd(%this)
{   
   if(!isObject(moveMap))
      return;
   
   //if ($sword)
   //{
   moveMap.bindObj(getWord(%this.Button,0),getWord(%this.Button,1), "beginAttack", %this);
     
   %this.enableUpdateCallback();
   //}
}

function platformerAttack::beginAttack(%this, %val)
{
   echo("Hello");
   %start = %this.owner.getPosition();
   %xVel = %this.owner.getLinearVelocityX();
   
   if (%xVel >= 0)
   {
      %end = t2dVectorAdd( %start, %this.Length SPC 0);
   }
   else
   {
      %end = t2dVectorAdd( %start, -%this.Length SPC 0);
   }
   
   %hits = %this.owner.getSceneGraph().pickLine (%start, %end);
   
   for( %i = 0; %i < getWordCount(%hits); %i++)
   {
      %hitObject = getWord(%hits, %i);
      
      if (%hitObject.class $= "enemy")
      {
         %hitObject.die(%this);
      }
   }
}
#11
04/06/2010 (11:01 pm)
Nice :)

Quote:also the code strip wasn't quite over just out of the page range

I didn't see a scrollbar under your post so I assumed the end was really missing. Now I can see it and everything is ok.
#12
04/08/2010 (2:45 pm)
hmmmm it seems I was premature in my celebration...

I tried to move my attack behavior into the main project along with my enemy behavior. However upon doing so I found out that my attacks seemed to stop working. However, when i use my miniature testing project the behaviors... well... behave. As such I can't undertsand whats wrong.

if(!isObject(testEnemy))
{
   %template = new BehaviorTemplate(testEnemy);
   
   %template.friendlyName = "testEnemy"; 
   %template.behaviorType = "Test";
   %template.description  = "Behavior to test attack behavior";
   
   %template.addBehaviorField(minDist, "The left most distance", float, -60.0);
   %template.addBehaviorField(maxDist, "The right most distance", float, 100.0);
   %template.addBehaviorField(speed, "The enemies speed", float, 30.0);
}

function testEnemy::onBehaviorAdd(%this, %scenegraph)
{
   %isDead = false;
   %startX = %this.owner.getPositionX();
   
   %this.owner.setLinearVelocityX(%this.speed);
   %this.owner.enableUpdateCallback();
   %this.owner.setCollisionCallback(true);
}

function testEnemy::onUpdate(%this)
{
   if(!%isDead)
   {
   %pos = %this.owner.getPosition();
   %posX = getWord(%pos, 0);
   
   if (%posX > %startX + %this.maxDist)
   {
	   %this.owner.setLinearVelocityX(-%this.speed);
   }
   if (%posX <= %startX + %this.minDist)
   {
	   %this.owner.setLinearVelocityX(%this.speed);
   }
   }
}

function testEnemy::onCollision(%srcObj, %dstObj, %srcRef, %dstRef, %time, %normal, %contactCount, %contacts)
{
   if (%dstObj.class $= "playerChar")
   {
      %dstObj.kill();
   }
}
function testEnemy::die(%this)
{
   %isDead = true;
   %this.safeDelete();
}

this is my enemy Behavior and the attack behavior is the same as above. All the enemy classes are, enemy exactly as spelt in the attack behavior. Again any help is highly appreciated.

EDIT: okay so it seems the problem lies in that the attack doesn't actually call the .die() function anymore, can anyone explain why this might be?