MMORPG Tutorial article 2 RPG style targeting
by Dreamer · 04/14/2005 (2:58 pm) · 52 comments
Download Code File
This is a continuation of the Dream MMORPG tutorial, this part covers targeting and implements a basic targeting GUI.
If you haven't already done so, please do this tutorial first...
http://www.garagegames.com/index.php?sec=mg&mod=resource&page=view&qid=7514
I based my targeting setup on the Object Selection tutorial, of Dave Meyers, you will need to implement all of the code except for the change to allow for Highlighting via the showing of the bounding box.
The tutorial can be found here
www.garagegames.com/index.php?sec=mg&mod=resource&page=view&qid=7335
Pay special attention to the comments further down in that tutorial, where it is explained how to add in the ability to clear the selection, that part is also critical.
After you have all of that compiled and working successfully, add the following to your engine/game/fps
guiTargetHud.cc
Then add the following to your client/ui
TargetingGUI.gui
In client/scripts/playgui.cs
Finally in your server/scripts/commands.cs add the following
For right now the only part we need to worry about on the server commands is serverCmdTarget, this function will allow us to target ONLY targets from the PlayerData class, for our purposes there is no need to be able to target anything else.
Anyways thats it for targeting, in our next tutorial we will cover adding your first tradeskill, and begin making a Server Side Roll Based Melee
This is a continuation of the Dream MMORPG tutorial, this part covers targeting and implements a basic targeting GUI.
If you haven't already done so, please do this tutorial first...
http://www.garagegames.com/index.php?sec=mg&mod=resource&page=view&qid=7514
I based my targeting setup on the Object Selection tutorial, of Dave Meyers, you will need to implement all of the code except for the change to allow for Highlighting via the showing of the bounding box.
The tutorial can be found here
www.garagegames.com/index.php?sec=mg&mod=resource&page=view&qid=7335
Pay special attention to the comments further down in that tutorial, where it is explained how to add in the ability to clear the selection, that part is also critical.
After you have all of that compiled and working successfully, add the following to your engine/game/fps
guiTargetHud.cc
//-----------------------------------------------------------------------------
// Torque Game Engine
// Copyright (C) GarageGames.com, Inc.
//-----------------------------------------------------------------------------
#include "dgl/dgl.h"
#include "gui/guiControl.h"
#include "console/consoleTypes.h"
#include "game/gameConnection.h"
#include "game/shapeBase.h"
//-----------------------------------------------------------------------------
/// A basic health bar control.
/// This gui displays the damage value of the current PlayerObjectType
/// control object. The gui can be set to pulse if the health value
/// drops below a set value. This control only works if a server
/// connection exists and it's control object is a PlayerObjectType. If
/// either of these requirements is false, the control is not rendered.
class GuiTargetBarHud : public GuiControl
{
typedef GuiControl Parent;
bool mShowFrame;
bool mShowFill;
bool mDisplayEnergy;
bool mFlipped;
ColorF mFillColor;
ColorF mFrameColor;
ColorF mDamageFillColor;
S32 mPulseRate;
F32 mPulseThreshold;
F32 mValue;
public:
GuiTargetBarHud();
void onRender( Point2I, const RectI &);
static void initPersistFields();
DECLARE_CONOBJECT( GuiTargetBarHud );
};
//-----------------------------------------------------------------------------
IMPLEMENT_CONOBJECT( GuiTargetBarHud );
GuiTargetBarHud::GuiTargetBarHud()
{
mShowFrame = mShowFill = true;
mFlipped = mDisplayEnergy = false;
mFillColor.set(0, 0, 0, 0.5);
mFrameColor.set(0, 1, 0, 1);
mDamageFillColor.set(0, 1, 0, 1);
mPulseRate = 0;
mPulseThreshold = 0.3f;
mValue = 0.2f;
}
void GuiTargetBarHud::initPersistFields()
{
Parent::initPersistFields();
addGroup("Colors");
addField( "fillColor", TypeColorF, Offset( mFillColor, GuiTargetBarHud ) );
addField( "frameColor", TypeColorF, Offset( mFrameColor, GuiTargetBarHud ) );
addField( "damageFillColor", TypeColorF, Offset( mDamageFillColor, GuiTargetBarHud ) );
endGroup("Colors");
addGroup("Pulse");
addField( "pulseRate", TypeS32, Offset( mPulseRate, GuiTargetBarHud ) );
addField( "pulseThreshold", TypeF32, Offset( mPulseThreshold, GuiTargetBarHud ) );
endGroup("Pulse");
addGroup("Misc");
addField( "flipped", TypeBool, Offset( mFlipped, GuiTargetBarHud ) );
addField( "showFill", TypeBool, Offset( mShowFill, GuiTargetBarHud ) );
addField( "showFrame", TypeBool, Offset( mShowFrame, GuiTargetBarHud ) );
addField( "displayEnergy", TypeBool, Offset( mDisplayEnergy, GuiTargetBarHud ) );
endGroup("Misc");
}
//-----------------------------------------------------------------------------
/**
Gui onRender method.
Renders a health bar with filled background and border.
*/
void GuiTargetBarHud::onRender(Point2I offset, const RectI &updateRect)
{
// Must have a connection and player control object
GameConnection* conn = GameConnection::getServerConnection();
if (!conn || !conn->getSelectedObject())
return;
ShapeBase* control = conn->getSelectedObject();
if (!control || !(control->getType() & PlayerObjectType))
return;
if(mDisplayEnergy)
{
mValue = control->getEnergyValue();
}
else
{
// We'll just grab the damage right off the control object.
// Damage value 0 = no damage.
mValue = 1 - control->getDamageValue();
}
// Background first
if (mShowFill)
dglDrawRectFill(updateRect, mFillColor);
// Pulse the damage fill if it's below the threshold
if (mPulseRate != 0)
{
if (mValue < mPulseThreshold)
{
F32 time = Platform::getVirtualMilliseconds();
F32 alpha = mFmod(time,mPulseRate) / (mPulseRate / 2.0);
mDamageFillColor.alpha = (alpha > 1.0)? 2.0 - alpha: alpha;
}
else
mDamageFillColor.alpha = 1;
}
// Render damage fill %
RectI rect(updateRect);
if(mBounds.extent.x > mBounds.extent.y)
{
if(mFlipped)
{
S32 bottomX = rect.point.x + rect.extent.x;
rect.extent.x = (S32)(rect.extent.x * mValue);
rect.point.x = bottomX - rect.extent.x;
}
else
{
rect.extent.x = (S32)(rect.extent.x * mValue);
}
}
else
{
if(mFlipped)
{
rect.extent.y = (S32)(rect.extent.y * mValue);
}
else
{
S32 bottomY = rect.point.y + rect.extent.y;
rect.extent.y = (S32)(rect.extent.y * mValue);
rect.point.y = bottomY - rect.extent.y;
}
}
dglDrawRectFill(rect, mDamageFillColor);
// Border last
if (mShowFrame)
dglDrawRect(updateRect, mFrameColor);
}Then add the following to your client/ui
TargetingGUI.gui
//--- OBJECT WRITE BEGIN ---
new GuiControl(TargetGUI){
profile = "GuiModelessDialogProfile";
position = "500 0";
extent = "100 60";
new GuiBitmapBorderCtrl() {
profile = "ChatHudBorderProfile";
horizSizing = "right";
vertSizing = "bottom";
position = "500 0";
extent = "100 60";
minExtent = "8 8";
visible = "1";
new GuiTextCtrl(TargetText) {
profile = "GuiTextProfile";
horizSizing = "right";
vertSizing = "bottom";
position = "20 10";
extent = "8 18";
minExtent = "8 2";
visible = "1";
Text = $TargetName;
maxLength = "255";
};
new GuiTargetBarHud(TargetHealth) {
profile = "GuiDefaultProfile";
horizSizing = "right";
vertSizing = "bottom";
position = "10 30";
extent = "80 10";
minExtent = "8 2";
visible = "1";
fillColor = "0.000000 0.000000 0.000000 0.500000";
frameColor = "0.000000 1.000000 0.000000 0.000000";
damageFillColor = "0.800000 0.000000 0.000000 1.000000";
pulseRate = "0";
pulseThreshold = "0.3";
flipped = "0";
showFill = "1";
showFrame = "1";
displayEnergy = "0";
};
new GuiTargetBarHud(TargetEnergy) {
profile = "GuiDefaultProfile";
horizSizing = "right";
vertSizing = "bottom";
position = "10 40";
extent = "80 10";
minExtent = "8 2";
fillColor = "0.000000 0.000000 0.000000 0.500000";
frameColor = "0.000000 1.000000 0.000000 0.000000";
damageFillColor = "0.000000 0.000000 0.800000 1.000000";
pulseRate = "0";
pulseThreshold = "0.3";
flipped = "0";
showFill = "1";
showFrame = "1";
displayEnergy = "1";
};
};
};Now add this to your client/scripts/client_commands.csfunction ClientCmdUpdateTargetDialog(%var,%TargetName){
%var = detag(%var);
%TargetName = detag(%TargetName);
if(%var $="NewTarget"){
$TargetName = %TargetName;
Canvas.PushDialog(TargetGUI);
}else{
$TargetName = "";
Canvas.PopDialog(TargetGUI);
}
echo("Recieved command to open TargetGUI command was"SPC %var SPC"and TargetName is"SPC %TargetName);
TargetText.setText($TargetName);
}In client/scripts/playgui.cs
function PlayGui::onMouseDown(%this)
{
// mouseVec = vector from camera point to 3d mouse coords (normalized)
%mouseVec = %this.getMouse3DVec();
// cameraPoint = the world position of the camera
%cameraPoint = %this.getMouse3DPos();
commandToServer('Target', %mouseVec, %cameraPoint,'Player');
}Finally in your server/scripts/commands.cs add the following
//-----------------------------------------------------------------------------
// object selection additions
//-----------------------------------------------------------------------------
function serverCmdTarget(%client, %mouseVec, %cameraPoint,%TargType)
{
//Determine how far should the picking ray extend into the world?
%selectRange = 200;
// scale mouseVec to the range the player is able to select with mouse
%mouseScaled = VectorScale(%mouseVec, %selectRange);
// cameraPoint = the world position of the camera
// rangeEnd = camera point + length of selectable range
%rangeEnd = VectorAdd(%cameraPoint, %mouseScaled);
%TargType = detag(%TargType);
if(%TargType $= "Player"){
%searchMasks = $TypeMasks::PlayerObjectType;
}
// Search for objects within the range that fit the masks above. If we are
// in first person mode, we make sure player is not selectable by setting
// fourth parameter (exempt from collisions) when calling ContainerRayCast
%player = %client.player;
if ($firstPerson)
{
%scanTarg = ContainerRayCast (%cameraPoint, %rangeEnd, %searchMasks, %player);
}
else //3rd person - player is selectable in this case
{
%scanTarg = ContainerRayCast (%cameraPoint, %rangeEnd, %searchMasks);
}
// a target in range was found so select it
if (%scanTarg)
{
%targetObject = firstWord(%scanTarg);
%client.setSelectedObject(%targetObject);
CommandToClient(%client,'UpdateTargetDialog','NewTarget',%targetObject.getshapeName());
echo("Client has selected" SPC %scanTarg);
}else{
if(%client.getSelectedObject()){
%client.clearSelectedObject();
echo("Client has cleared selection");
CommandToClient(%client,'UpdateTargetDialog','ClearTarget');
}
}
}
function findObject(%client,%searchMasks,%distance,%LOS){
if(%LOS){
if(DoRaycast(%client,%distance,%searchMasks)){
return(1);
}else{
return(0);
}
}else{
if(DoRadiusSearch(%client,%distance,%searchMasks)){
return(1);
}else{
return(0);
}
}
}
function DoRaycast(%client,%distance,%searchMasks)
{
echo("We are doing raycast and player ="@%client.player);
%player = %client.player;
%eye = %player.getEyeVector();
%vec = vectorScale(%eye, %distance);
%startPoint = %player.getEyeTransform();
%endPoint = VectorAdd(%startPoint,%vec);
%object = ContainerRayCast (%startPoint, %endPoint, %searchMasks, %player);
echo( "\c1 /// RayCast Search /// " );
echo("\c1 Object = " SPC %object);
echo("\c1 Object Position = " SPC %object.getPosition());
echo("\c1 Object Id = " SPC %object.getId());
echo("\c1 Object Name = " SPC %object.getName());
echo( "\c1 /// --------------- /// " );
if(%object){
return(1);
}else{
return(0);
}
}
function DoRadiusSearch(%client,%distance,%searchMasks){
%player = %client.player;
%pos = %player.getPosition();
InitContainerRadiusSearch(%pos, %radius, %searchMasks);
while ((%targetObject = containerSearchNext()) != 0) {
%dist = containerSearchCurrRadiusDist();
%target = %targetObject.getTransform();
%id = %targetObject.getId();
%name = %targetObject.getName();
echo( "\c3 /// Container Search /// " );
echo( " Distans = " @ %dist);
echo( " Player Position = " @ %pos);
echo( " Target = " SPC %target);
echo( " Target Id = " SPC %id);
echo( " Target Name = " SPC %name);
echo( "\c3 /// --------------- /// " );
}
if(%targetObject){
return(1);
}else{
return(0);
}
}For right now the only part we need to worry about on the server commands is serverCmdTarget, this function will allow us to target ONLY targets from the PlayerData class, for our purposes there is no need to be able to target anything else.
Anyways thats it for targeting, in our next tutorial we will cover adding your first tradeskill, and begin making a Server Side Roll Based Melee
#3
:)
Hall Of Worlds, LLC
EdM|EGTGE
04/14/2005 (10:17 am)
Congrats! You've accomplished what no-one before has done (AFAIK). You've gotten all five slots on the 'most recent' resource.:)
Hall Of Worlds, LLCEdM|EGTGE
#4
Anyways these things were submitted over several days, but something happened that caused them to all que up and come out on the same day, (prolly my whining to GG that they hadn't been approved after almost 2 weeks) thereby making it look like I'm some kind of resource hog :(
Anyways, I'm slowing the pace a little and will only submit one or two per week, which judging from the approval rates I've had thus far means we should see tutorial 10 sometime in August :)
04/14/2005 (10:22 am)
Thanks... I think.Anyways these things were submitted over several days, but something happened that caused them to all que up and come out on the same day, (prolly my whining to GG that they hadn't been approved after almost 2 weeks) thereby making it look like I'm some kind of resource hog :(
Anyways, I'm slowing the pace a little and will only submit one or two per week, which judging from the approval rates I've had thus far means we should see tutorial 10 sometime in August :)
#5
edit: ur not a resource hog, ur a RESOURCE GOD! ^_^
04/14/2005 (7:09 pm)
Ahhh nooo lol submit em, some of us really need em, loledit: ur not a resource hog, ur a RESOURCE GOD! ^_^
#6
Thanks
04/16/2005 (4:20 pm)
im haveing trouble getting a Object Selection tut working, only one i can find is by David Myers, i tryed that tut and it is asking to place code after so and so, well the so and so code isant in my version or something so can you place a link to the one that you used?Thanks
#7
www.garagegames.com/index.php?sec=mg&mod=resource&page=view&qid=7335
04/16/2005 (9:15 pm)
Yes I am using Object Selection for v1.2 Onwardsby Dave Meyers.www.garagegames.com/index.php?sec=mg&mod=resource&page=view&qid=7335
#8
Thanks
04/17/2005 (7:09 pm)
Sorry for all the questions but is Object Selection required or can it be left out and just fix something like where you run around and hack and slash?Thanks
#9
Other than the exception stated above that entire tutorial is needed, including the changes made in the comments to clear selections and etc.
I do realize that particular tutorial is a little hard to follow, lemme see what I can do to make it easier.
*Update*
For those who are having trouble following along with the tutorial on object selection, I have zipped up my copies of all the relevant C++ code so now all you need to do is add these to your project and modify your scripts according to the tutorial.
04/18/2005 (8:20 am)
Yes object selection is required, it is the basis for almost every mod we do from here on out. That said, you do not need to make the change to shapebase which draws the bounding box around the selected object, if you choose not to.Other than the exception stated above that entire tutorial is needed, including the changes made in the comments to clear selections and etc.
I do realize that particular tutorial is a little hard to follow, lemme see what I can do to make it easier.
*Update*
For those who are having trouble following along with the tutorial on object selection, I have zipped up my copies of all the relevant C++ code so now all you need to do is add these to your project and modify your scripts according to the tutorial.
#10
04/18/2005 (5:15 pm)
o WOW, thanks man, im checking it out now :)
#11
also the reasion i could'int get this working earler was i had the lighting pack installed and it had takeing out some code that the other code referd to when installing and if you placed it where it should have been then you would get compile errors on the lighting pack code.
Thanks so much, I am loveing it :)
04/22/2005 (7:30 am)
cool got everything working so far but still have a question, do we need to add a keybinding to the targetgui or is there a way to have it showing in the playgui at all times?also the reasion i could'int get this working earler was i had the lighting pack installed and it had takeing out some code that the other code referd to when installing and if you placed it where it should have been then you would get compile errors on the lighting pack code.
Thanks so much, I am loveing it :)
#12
04/22/2005 (7:49 am)
@ Wayne, yes there is a way to do this w/o a keybinding however if you make the targetingGUI the default rather than the other you will need to fix your mousebindings so you have some way of looking left,right,up and down.
#13
having some problems with this. i got thru 1 and now i am on part 2 from this page i went thru the link above. finished that. i get when i click "M" cursor i click myself in TAB and see the bounding box i click dork and get same... sofar so good. now i add the stuff from this page and i see the target hud under the gui editor. but nothing when i target myself or the dork. also i could not get the crosshair to leave correctly not a big deal for now. i get zero errors in consol.log anyplace i could past code that might be the problem?
any help would be appreciated
BTW i even tried your zip and putting those files in and going thru the tuts to double check and still same thing no targethud showing up
05/03/2005 (9:00 pm)
Dreamer:having some problems with this. i got thru 1 and now i am on part 2 from this page i went thru the link above. finished that. i get when i click "M" cursor i click myself in TAB and see the bounding box i click dork and get same... sofar so good. now i add the stuff from this page and i see the target hud under the gui editor. but nothing when i target myself or the dork. also i could not get the crosshair to leave correctly not a big deal for now. i get zero errors in consol.log anyplace i could past code that might be the problem?
any help would be appreciated
BTW i even tried your zip and putting those files in and going thru the tuts to double check and still same thing no targethud showing up
#14
I usually move my field of view so the object is almost to the rightmost edge of the screen, and centered top to bottom in my view, I then click on the name of the object (It's guiShapeNameHUD), rather than on the object itself.
05/03/2005 (10:53 pm)
Targeting itself seems to be a bit tricky, what you have to do is make sure the object is NOT in the center of the screen or in any place on the screen where any huds will normally appear.I usually move my field of view so the object is almost to the rightmost edge of the screen, and centered top to bottom in my view, I then click on the name of the object (It's guiShapeNameHUD), rather than on the object itself.
#15
05/04/2005 (6:46 am)
thanks for righting back. i can target just fine me or dork.... but the gui for target "with health and such" is not coming up at all so after doing your stuff from this tutorial i see no difference between the Object selection in Torque (v1.2 onward) tutorial... and this one MMORPG Tutorial article 2 RPG style targeting. when i target myself or dork the TargetingGUI.gui... does not appear at all
#16
05/04/2005 (6:49 am)
Hmm would you mind doing a targeting scenario and sending me a copy of your console.log leading up to and immediately after having actually acquired the target? smorrey@gmail.com
#17
05/04/2005 (7:25 am)
k sent it off to you... thanks for looking into it
#18
05/04/2005 (7:34 am)
Not to be a pest or anything, but I haven't recieved it yet, Gmail is usually pretty quick, so can you please resend it?
#19
hmmm have ya recieved the 2nd attempt?
05/04/2005 (7:48 am)
attempt #2 think something wrong on this computer so i used my other computer see if that goes thruhmmm have ya recieved the 2nd attempt?
#20
Oh yeah, make sure as soon as the game loads and before you actually target anything to open a console window and type "trace(1);" without the quotes, this will give a much better idea of what went wrong.
05/04/2005 (8:49 am)
Nope, not at all, it would be much quicker if you just posted your entire console.log then deleted it when I've helped you to find the solution. Make sure to change your username and password in the log before posting it. Unless you want the whole world to see them :)Oh yeah, make sure as soon as the game loads and before you actually target anything to open a console window and type "trace(1);" without the quotes, this will give a much better idea of what went wrong.
Torque Owner Dreamer
Default Studio Name
http://www.garagegames.com/index.php?sec=mg&mod=resource&page=view&qid=7516